In spring we can design rest web service like below.
#RestController
public class HelloController {
#RequestMapping(value = "/hello", method = RequestMethod.GET)
public String printWelcome(ModelMap model) {
model.addAttribute("message", "Hello");
return "hello";
}
}
When we do so, #RestController & #RequestMapping will internally manage request mapping part. So when I will hit url i.e. http://localhost:8080/hello it will point to printWelcome method.
I was looking into spring boot actuator source code. If we will use spring boot actuator in our application it will provide us some endpoints, which has exposed as rest APIs like health, metrics, info. So in my application if I am using spring boot actuator, when I will hit the url like "localhost:8080/health" I will get response.
So now my question is in spring boot actuator source code where this URLs get mapped. I have debugged source code of spring boot actuator, but not able to find out the root class of mapping of endpoints.
Can anyone please help ?
here it is , In AbstractEndpoint it says
/**
* Endpoint identifier. With HTTP monitoring the identifier of the endpoint is mapped
* to a URL (e.g. 'foo' is mapped to '/foo').
*/
If you see HealthEndPoint it extends AbstractEndpoint and does a super("health", false); , thats where it maps to "localhost:8080/health".
All spring-boot-actuator endpoints extends AbstractEndpoint (In Health endpoint case for example: class HealthEndpoint extends AbstractEndpoint<Health>) which construcor has the id of the Endpoint.
/**
* Endpoint identifier. With HTTP monitoring the identifier of the endpoint is mapped
* to a URL (e.g. 'foo' is mapped to '/foo').
*/
private String id;
Otherwise, it has an invoke method (from interface Endpoint) through it is invoked the endpoint.
/**
* Called to invoke the endpoint.
* #return the results of the invocation
*/
T invoke();
Finally, this endpoints are configured in the class EndpointAutoConfiguration as Bean:
#Bean
#ConditionalOnMissingBean
public HealthEndpoint healthEndpoint() {
return new HealthEndpoint(this.healthAggregator, this.healthIndicators);
}
Take a look this post where explains how to custom your endpoint:
http://blog.codeleak.pl/2014/10/spring-boot-actuator-custom-endpoint.html
Related
I have a spring cloud gateway application and what I want is like if there are two routes then on one route it should redirect to some external application but for other route it should forward the request to same app with a particular url.
-id: my_local_route
predicates:
- Path="/services/local"
uri: "/mylocal/services/local" //can we do something like that
Please note I want to create my rest services in same app as in spring cloud gateway. I understand it is not correct approach but for my knowledge I wanted to know whether it is possible or not.
If you have some rest APIs within your spring-cloud-gateway project, you don't need to explicitly put the routes for it.
So suppose you have following rest api in gateway project
#RestController
#RequestMapping("test")
class Controller{
#GetMapping("hello")
public String hello(){
return "hello";
}
}
and for external-url, you want to send some traffic to let's say https://httpbin.org. So in gateway application.yml could look something like this:
spring:
cloud:
gateway:
routes:
- id: httpbin-route
uri: https://httpbin.org
predicates:
- Path=/status/**
With this request like
http://localhost:8080/test/hello will be resolved by your rest controller
http://localhost:8080/status/200 will be redirected to httpbin site
If for some reason you have the same root path for both cases, the controller will have precedence.
If you have the same endpoint in gateway predicates and controller, by default controller will take precedence over predicates, if you want predicates to take precedence over controller, just create a BeanPostProcessor to adjust the order:
#Component
public class RequestMappingHandlerMappingBeanPostProcessor implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof RequestMappingHandlerMapping) {
((RequestMappingHandlerMapping) bean).setOrder(2); // After RoutePredicateHandlerMapping
}
return bean;
}
}
I have a Spring boot REST service (spring-boot-starter-parent:1.3.2) that exposes some endpoints using RestController defined methods. I am also using Spring security. Everything works fine until I try to define a controller method that is mapped to "/images". When I try to access this api path I get the following error. By debugging I can see that my controller handler is being mapped, but the preauthorize filter is not being called (it is called properly for other mappings). I have set the following properties, but with no change. How do I fix this so that I can use "/images"?
spring.resources.add-mappings=false
spring.mvc.static-path-pattern=/hide-me/**
Error:
"exception": "org.springframework.security.authentication.AuthenticationCredentialsNotFoundException",
"message": "An Authentication object was not found in the SecurityContext",
Code:
#RestController
#PreAuthorize(value = "hasAnyAuthority('SOMEUSER')")
public class ImageController {
...
#RequestMapping(value = { "/images/{imageId}" }, method = RequestMethod.GET)
#ResponseBody
public Image getImage(#PathVariable UUID imageId) {
return imageDataService.getImage(imageId);
}
...
If I change the mapping to the following then it works just fine.
#RequestMapping(value = { "/image/{imageId}" }, method = RequestMethod.GET)
#ResponseBody
public Image getImage(#PathVariable UUID imageId) {
return imageDataService.getImage(imageId);
}
I'm thinking that the config for static resources has a default entry that tells Spring security to ignore the "/images" path for the preauth filter. I'm debugging around trying to figure out where that might be overridden.
SpringBoot by default use some paths
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
"classpath:/META-INF/resources/", "classpath:/resources/",
"classpath:/static/", "classpath:/public/" };
https://spring.io/blog/2013/12/19/serving-static-web-content-with-spring-boot
And one of this paths is /images
Java Web Application. Spring Boot. Locating Images
Also you have the following restrictions when usind SpringSecurity
The basic features you get out of the box in a web application are:
An AuthenticationManager bean with in-memory store and a single user
(see SecurityProperties.User for the properties of the user). Ignored
(insecure) paths for common static resource locations (/css/,
/js/, /images/, /webjars/ and **/favicon.ico). HTTP Basic
security for all other endpoints. Security events published to
Spring’s ApplicationEventPublisher (successful and unsuccessful
authentication and access denied).
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/
Common low-level features (HSTS, XSS, CSRF, caching) provided by Spring Security are on by default.
You need to ensure, that security is done for every request. This can be done using the following SecurityConfiguration:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated();
}
}
I'm currently developing a Spring Boot application that exposes endpoints using #RestController and #RequestMapping annotations.
I recently discovered the concept of the projections as defined in Spring Data Rest (#Projection-annotated interfaces and #RepositoryRestResource-annotated JPA repositories) and I'd like to apply this concept to my existing services.
As I understand this post Spring Boot Projection with RestController, (please correct me if I'm wrong), #RestController and #RepositoryRestResource classes both define endpoints. So these annotations seem quite incompatible.
Is there a Spring component which can simply apply the projections concept to the #RestController endpoints ?
Is there a way to manually reroute requests from a endpoint to another ? (for example, using #RestController endpoints as some sort of proxy which performs controls or other operations before rerouting the request to the #RepositoryRestResource endpoints)
EDIT: I add a glimpse of the final code I'd like to have in the end.
#RestController
public class MyController {
#RequestMapping(value = "/elements/{id}", method = RequestMethod.GET)
public ResponseEntity<Element> getElements(
#PathVariable("id") Integer elementId,
#RequestParam("projection") String projection,
#RequestHeader(value = "someHeader") String header{
// [manual controls on the header then call to a service which returns the result]
}
}
#Entity
public class Element {
private Integer id;
private String shortField;
private String longField;
private List<SubElement> subElements;
// [Getters & setters]
}
#Projection(name = "light", types = {Element.class})
interface ElementLight {
public Integer getId();
public String getShortField();
}
If I call /elements/4, I'd get the complete Element having id = 4.
If I call /elements/4?projection=light, I'd get only the id and the short field of the Element having id = 4.
This answer gives some detail about how to create projection instances of your entities - https://stackoverflow.com/a/29386907/5371736
So depending on your projection parameter you could generate the given projections.
Hope this is what you are looking for.
I have been reading on Spring 3.2 lately and I am now trying the following code using Spring 2.5. From what I have read this should mean that it should map profile/tags/me. However it doesn't. It just throws a No mapping found for HTTP request with URI .... What is wrong with the code, or didn't Spring 2.5 work like it does in Spring 3?
Problem when using Spring 2.5
#Controller
#RequestMapping("/profile/tags")
public class ProfileController { ... }
And this is the method inside ProfileController class:
#RequestMapping(value = "/me", method = RequestMethod.GET)
public String show(#RequestParam final long id, final ModelMap model) { ... }
According to Spring documentation, I imagine you're missing the required configuration to receive the request parameter, if you mean to receive this request parameter:
#RequestMapping(value = "/me/{id}", method = RequestMethod.GET)
public String show(#RequestParam("id") final long id, final ModelMap model) { ... }
Or you should remove RequestParam.
Update for Spring 2.5
Additionally, since you're using Spring 2.5, make sure that you've configured your DispatcherServlet in the expected way; Sections 13.11, subsections 1, 2, and 3. In summary:
DispatcherServlet should be told to load annotated RequestMappings.
DispatcherServlet should be told to load Controller annotations.
Not sure but maybe you need to refine the paths you use for the request mappings.
Hope this helps.
in my exercise i have to develop a spring application which should be accessible through a WebGUI AND a REST service.
Now i browed through the examples of Spring MVC, there is this hello world tutorial on Spring MVC.
The controller looks like as follows:
#Controller
#RequestMapping("/welcome")
public class HelloController {
#RequestMapping(method = RequestMethod.GET)
public String printWelcome(ModelMap model) {
model.addAttribute("message", "Spring 3 MVC Hello World");
return "hello";
}
}
Then i looked through the Spring REST example which looks like this:
#Controller
#RequestMapping("/movie")
public class MovieController {
#RequestMapping(value = "/{name}", method = RequestMethod.GET)
public String getMovie(#PathVariable String name, ModelMap model) {
model.addAttribute("movie", name);
return "list";
}
#RequestMapping(value = "/", method = RequestMethod.GET)
public String getDefaultMovie(ModelMap model) {
model.addAttribute("movie", "this is default movie");
return "list";
}
}
Now I am wondering, how do these two examples (Spring-mvc and Spring-rest) differ?
They both use the same annotations and work similar. Aren't that both just REST examples?
How can I provide a Rest-Interface to a Spring-MVC application?
regards
In order to provide rest interface to Spring MVC application, you can apply #RequestMapping annotation with a path name to each of the methods in controller, this creates a unique URL path for each of the rest services you would like to provide.
Meaning, the rest services are nothing but the methods in Spring MVC controller with #RequestMapping annotation.
If you would like to learn how Spring MVC supports Rest Based services, the below link might help:
http://blog.springsource.org/2009/03/08/rest-in-spring-3-mvc/#features
Both samples are about Spring Web MVC.
You should pay more attention to definitions, like what is REST
https://en.wikipedia.org/wiki/Representational_state_transfer
Representational State Transfer is intended to evoke an image of how a
well-designed Web application behaves: presented with a network of Web
pages (a virtual state-machine), the user progresses through an
application by selecting links (state transitions), resulting in the
next page (representing the next state of the application) being
transferred to the user and rendered for their use.
Spring Web MVC greatly facilitates developing REST web APIs and that's it.
Rememeber #ResponseBody as return type on method is going to be REST.
ofcourse returned object can be negotiated with either JSON or XML.