Spring MVC 3 controller request handler common - java

I have a controller that handles few requests that have to be checked for existence of the same cookie value. This means that in each request handler I have to perform the same check.
#Controller
public class MyController {
#RequestMapping("/Path")
public String Handler1(#CookieValue(required = false, value = "Cookie") String cookie) {
if (cookie != null) {
handleNoCookie();
}
handleRequest1();
}
#RequestMapping("/AnotherPath")
public String Handler2(#CookieValue(required = false, value = "Cookie") String cookie) {
if (cookie != null) {
handleNoCookie();
}
handleRequest2();
}
and so on...
}
Is there a way to extract the duplicated check this into some method that will do the check before the actual handler executes?
Thanks.

You could use an interceptor to ... "intercept" requests and process your logic if the cookie isn't there. You can make it fire before the controller is hit via the preHandle method.
API: HandlerInterceptor

If there are a large number of Handler methods, you could look into Spring's AOP to implement the cookie check advice for all the methods.
http://static.springsource.org/spring/docs/2.5.x/reference/aop.html

AOP interceptor suggested in other answers is an configurational overkill.
Similar functionality can be achieved using #ModelAttribute annotation. It is available since Spring 2.5. Methods annotated using #ModelAttribute must generate parameters for the view model. These methods are called before every method annotated using #RequestMapping.
It seems to be working if the annotated method returns nothing (void-method). In this case it works as some imaginary "BeforeEveryRequest" annotation. It looks like this:
#ModelAttribute
public void tagController(HttpServletRequest request) {
request.setAttribute(VERSION_PARAMETER, version());
}
UPDATE:
There is a small side effect. It adds a dummi value to the model. Key is a string "void" and the value is null.

Related

How to get URI value coming from HTML to Variable in Spring (There are multiple Links associated with corresponding method)

I have multiple links in my HTML, which are referring to URI in Controller Class,
How can I get this URI in some variable which can be used further, at last, I want to store these URI in DB.
HTML Code :
<td>Win Report</td>
<td>Win Report</td>
Spring Controller Class :
#RequestMapping(value = "/ui/report/win", method = RequestMethod.GET)
public String winReport() {
return "win_report";
}
#RequestMapping(value = "/ui/report/niw", method = RequestMethod.GET)
public String niwReport() {
return "niw_report";
}
You can use the below solution to retrieve the page Url as well as avoid using repetitive method calls.
You can use a Spring Boot HandlerInterceptor, here's a brief description of the same :
Handler interceptors are used when you want to apply specific
functionality to certain or all requests.
Handler Interceptors should implement the interface HandlerInterceptor. HandlerInterceptor can be used to avoid repetitive handler code.
We can use HandlerInterceptor for different purposes like authorization checks, locale checks, logging, creating common application parameters etc.
HandlerInterceptor works similar to the servlet filter. But in some cases filters are more powerful than HandlerInterceptor.
In Spring-MVC the HandlerInterceptor is configured in spring application context xml file or by Java configuration.
HandlerInterceptor has three methods.
preHandle( ) : It is executed before actual handler is executed.
postHandle( ) : It is executed after handler is executed.
afterCompletion( ) : It is executed after the complete request is finished.
For more details, you can use an example from the below link
https://www.tuturself.com/posts/view?menuId=3&postId=1071
You can get the entire sample project which can help you with the setup at
https://github.com/ninja-panda
To get the request url you can do the following:
#RequestMapping(value = "/ui/report/win", method = RequestMethod.GET)
public String winReport(HttpServletRequest request){
String request = request.getRequestURI();
// do somehting here
return "win_report"
}
Spring will automatically inject the HttpServletRequest.
Update:
If your want get the urls for all of your methods in your controller, you can go with RequestMappingHandlerMapping:
private final RequestMappingHandlerMapping handlerMapping;
#Autowired
public YourController(RequestMappingHandlerMapping handlerMapping) {
this.handlerMapping = handlerMapping;
}
With handlerMapping.getHandlerMethods(), you can access all mappings decleared in your controller. With reflection and getMappingAnnotation, you can then read the value of each RequestMapping annotation.
You can try the getServletPath() like following:
#RequestMapping(value = "/ui/report/win", method = RequestMethod.GET)
public String winReport(HttpServletRequest request){
String mapping = request.getServletPath();
// do somehting here
System.out.println(mapping); // Will print /ui/report/win
return "win_report"
}

How can I specify method with an parameterized annotation and its value with #Pointcut

Background:
I am developing an web application with Spring MVC.
I want to make an aspect that is executed on POST requests and not executed on GET requests, because I want to inject the logic that prevent POST requests which are sent before completion of HTML rendering.
#RequestMapping(value = "/aaa", method = RequestMethod.POST)
public String methodForPost(AnDto dto, Model model) {
// the aspect should be executed on this method
}
#RequestMapping(value = "/bbb", method = RequestMethod.GET)
public String methodForGET(AnDto dto, Model model) {
// the aspect shouldn't be executed on this method
}
Question:
How can I specify method with an parameterized annotation and its value with #Pointcut ?
How can I specify method with an parameterized annotation and its value in <aop:pointcut> in Spring applicationContext.xml?
#Around(value="#annotation(RequestMapping)")
public Object display(ProceedingJoinPoint joinPoint, RequestMapping requestMapping ) throws Throwable {
// You have access to requestMapping. From which you can get whether its get or post and decide to proceed or not.
}
More info http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-ataspectj-advice-params-passing
You might have to extend this to intercept only for Requestmapping's in your package. Because this intercepts every RequestMappig you might have in your project including one used by the libraries which you might be using, which is a burden.

Spring Security + MVC : same #RequestMapping, different #Secured

Let say we have an API endpoint configured using Spring MVC and Spring Security. We would like to be able to handle pairs of #RequestMapping and #Secured annotations where the only #Secured annotation values differ from pair to pair. This way, we would be able to return a different response body depending on security rules for the same request.
This may allow our code to be more maintainable by avoiding to check for security rules directly into the method body.
With a not working example, here is what we would like to do :
#Controller
#RequestMapping("/api")
public class Controller {
#Secured ({"ROLE_A"})
#RequestMapping(value="{uid}", method=RequestMethod.GET)
#ResponseBody
public Response getSomething(#PathVariable("uid") String uid) {
// Returns something for users having ROLE_A
}
#Secured ({"ROLE_B"})
#RequestMapping(value="{uid}", method=RequestMethod.GET)
#ResponseBody
public Response getSomethingDifferent(#PathVariable("uid") String uid) {
// Returns something different for users having ROLE_B
}
}
How can we achieve this ?
And if this can be done: How the priority should be managed for a user who has both ROLE_A and ROLE_B ?
Assuming you are using Spring 3.1 (or up) together with the RequestMappingHandlerMapping (and RequestMappingHandlerAdapter) you can extend the request mapping mechanism. You can do this by creating your own implementation of the RequestCondition interface and extend the RequestMappingHandlerMapping to construct this based on the #Secured annotation on your method.
You would need to override the 'getCustomMethodCondition' method on the RequestMappingHandlerMapping and based on the Method and the existence of the #Secured annotation construct your custom implementation of the RequestCondition. All that information is then taken into account when matching incoming requests to methods.
Related answers (although not specific for #Secured annotations but the mechanism is the same) is also to be found here or here
I don't think you can do this in spring-mvc, since both routes have exactly the same #RequestMapping (#Secured) is not taken into account by the route engine of spring-mvc. The easiest solution would be to do this:
#Secured ({"ROLE_A", "ROLE_B"})
#RequestMapping(value="{uid}", method=RequestMethod.GET)
#ResponseBody
public Response getSomething(#PathVariable("uid") String uid, Principal p) {
// Principal p gets injected by spring
// and you need to cast it to check access roles.
if (/* p.hasRole("ROLE_A") */) {
return "responseForA";
} else if (/* p.hasRole("ROLE_B") */) {
return "responseForB";
} else {
// This is not really needed since #Secured guarantees that you don't get other role.
return 403;
}
}
However, I would change your design, since the response is different per role, why not have 2 separate request mappings with slightly different URLs? If at some point you have users with role A and B at the same time, you can't let the user choose what response to get (think, for example, of the public and private profiles of LinkedIn)

How to pre-process the request body in Spring before passing it to the a Controller?

I am implementing a RESTful service and I would like to validate the XML against an XSD in an interceptor before passing it on the a CastorUnmarshaller.
Though, in the WebRequestInterceptor I have to read the request body which can only be read once so the unmarshaller cannot read it. Is there a way of doing it?
I know that I can do both the validation and the unmarshalling manually in the Controller, but I would like to use the #RequestBody <DomainObject> way to unmarhall it.
Alternatively, as another solution, is there a way to tell the CastorUnmarshaller to validate it against the xsd?
Quite a long time passed, but someone else might benefit from this:
You can define an #Around aspect and intercept the incoming requests and their respective bodies as follows:
#Aspect
#Component
public class RequestResponseLoggingAdvice {
private static final Logger logger = LoggerFactory.getLogger(RequestResponseLoggingAdvice.class);
#Pointcut("within(#org.springframework.web.bind.annotation.RestController*)")
public void restcontroller() {}
#Pointcut("#annotation(org.springframework.web.bind.annotation.PostMapping)")
public void postmapping() {}
#Around("restcontroller() && postmapping() && args(.., #RequestBody body, request)")
public Object logPostMethods(ProceedingJoinPoint joinPoint, Object body, HttpServletRequest request) throws Throwable {
logger.debug(request.toString()); // You may log request parameters here.
logger.debug(body.toString()); // You may do some reflection here
Object result;
try {
result = joinPoint.proceed();
logger.debug(result.toString());
} catch(Throwable t) {}
}
}
Please note that your REST controller methods have to have suitable signatures for the above aspect can hook in. A sample one could be as follows:
#PostMapping
public SampleDTO saveSample(#RequestBody Sample sample, HttpServletRequest request) {
//.....
}
You can probably attach a #Before aspect (spring AOP). There you can get the same request body parameter as passed to the controller method.
Another option is to wrap the request into one that supports reading the body multiple times (by caching it the first time)
A filter can also be used to validate the XML passed.
org.springframework.oxm.castor.CastorMarshaller has a validating property to enable validation on in- and out-going documents.
But enabling it in Spring-MVC's default marshaller must be solved.

How to implement Spring's 3.1 MvcAnnotationDriven?

This is the code example from Spring 3.1 Spring Source Blog: From XML to #Configuration I'm trying to implement in my application (which was done in Spring 2.0 not by me so it's lot of learning).
#FeatureConfiguration
class MvcFeatures {
#Feature
public MvcAnnotationDriven annotationDriven(ConversionService conversionService) {
return new MvcAnnotationDriven().conversionService(conversionService)
.argumentResolvers(new CustomArgumentResolver());
}
// ...
}
However, I can't understand the point of .argumentResolvers(new CustomArgumentResolver()) and their CustomArgumentResolver looks like bellow. What's the point of it?
public class CustomArgumentResolver implements WebArgumentResolver {
#Override
public Object resolveArgument(MethodParameter param, NativeWebRequest request) throws Exception {
RequestAttribute attr = param.getParameterAnnotation(RequestAttribute.class);
if (attr != null) {
return request.getAttribute(attr.value(), WebRequest.SCOPE_REQUEST);
} else {
return WebArgumentResolver.UNRESOLVED;
}
}
}
To add to #GaryF's answer, and to clarify some points, Spring 2.5 introduced annotated controllers, which replaced the old interface-style controllers of Spring 2.0. These new controllers have methods with no fixed parameters - the method declares the parameters that it needs to do its job, and nothing more.
For example, say a controller method needed one thing to do its job - a request parameter that contains the ID of an object from the database. In Spring 2.0, you would need to implement something like AbstractController.handleRequestInternal(), e.g
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) {
String id = request.getParameter("id");
MyThing obj = getObjById(id);
//... do stuff and return ModelAndView
}
Spring 2.5 made that easier:
#RequestMapping
public ModelAndView handle(String id) {
MyThing obj = getObjById(id);
//... do stuff and return ModelAndView
}
Here, we only declare parameters for the stuff we need.
So far so good, but this is where a custom WebArgumentResolver comes in. Say I want to remove the getObjById from my controller altogether, because maybe I think it clutters up the code, and maybe it's used across many other controller methods. Instead, I want to do this:
#RequestMapping
public ModelAndView handle(MyThing id) {
//... do stuff and return ModelAndView
}
It's even simpler, and has a bare minimum of boilerplate code. A custom WebArgumentResolver can be registered with the app-context which recognises parameters of type MyThing, and knows how to extract the information from the request. Spring invokes that resolver, and passes the result to the controller method.
Custom resolvers aren't commonly used, but can be very handy in the right situation.
The example in your question uses CustomArgumentResolver to resolve the example's custom RequestAttribute class. The resolver pulls out request attributes and binds them to RequestAttribute objects, so that they can be declared as controller method parameters.
WebArgumentResolvers are a way for you to specify how the parameters of MVC-mapped methods should be resolved. If you'd like to use a custom object as a parameter for an MVC-mapped method, Spring tries to figure out how make sense of it in it's own way. Typically this would happen through binding, where some http parameters you submit match up with the fields of the object and Spring matches them up and creates a new object for you.
If you ever have a situation where the submitted parameters don't match up quite so neatly with your method parameters, WebArgumentResolvers are there to fill in the gap: you provide custom logic so Spring doesn't have to figure it out.
In your example, param is one such parameter to be matched up. This piece of custom code first checks if the parameter has an #RequestAttribute annotation. If it does, then the custom code pulls the value from that object and looks it up as an attribute on the http request, returning it. It it does not have that annotation, then the method returns the UNRESOLVED value, which simply indicates that this WebArgumentResolver doesn't know anything about this particular parameter and Spring should try a different method (such as binding).

Categories

Resources