How to define RequestMapping prioritization - java

I have a situation where I need the following RequestMapping:
#RequestMapping(value={"/{section}"})
...method implementation here...
#RequestMapping(value={"/support"})
...method implementation here...
There is an obvious conflict. My hope was that Spring would resolve this automatically and map /support to the second method, and everything else to the first, but it instead maps /support to the first method.
How can I tell Spring to allow an explicit RequestMapping to override a RequestMapping with a PathVariable in the same place?
Edit 2: It seems that it would work if the /support mapping came before the /{section} mapping. Unfortunately we have dozens of controllers containing numerous methods with RequestMapping. How can I make sure that the controller with the /{section} mapping is initialized last? Or would a pre-interceptor be the way to go?
Edit 1: This is simplified, I know that having those two RequestMapping alone wouldn't make much sense)

Using Spring you can extend the org.springframework.web.HttpRequestHandler to support your scenario.
Implement the method:
#Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}
Use it to analyze the incoming request, determine if the request url is part of your special subset of request url's and forward to the appropriate location.
Ex:
#Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/** You will want to check your array of values and have this data cached **/
if (urlPath.contains("/sectionName")) {
RequestDispatcher requestDispatcher = request.getRequestDispatcher("sections" + "/" + urlPath);
requestDispatcher.forward(request, response);
}
}
And setup your sections such as:
#RequestMapping(value={"/sections/{sectionName}"})
This will not interfere with any of your pre-existing controller mappings.

If 2 these methods are defined in 2 different controllers your problem is that you have 2 controllers mapped to same URL. You do not control the order of controllers initialization right now, so the order is random.
I think you need /support mapping to be initialized before /{section}.
To achieve this try to define that controller "section" depends on controller "support". If this will not help try to put both methods together to one controller and put method mapped to "support" before "section"
I this does not work here is other suggestion. What "section" is? If it can accept limited number of values it should be defined as enum. I believe that in this case everything will work as required if support and section methods are in one controller or in separate controllers.
Good luck.

This not seems to be a problem, this is a valid mapping. If you have a look to http://static.springsource.org/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping-uri-templates
In the section 16.3.2 Mapping Requests With #RequestMapping exists two methods doing exactly the same that you are trying.
To be sure that your classes are being compiled try to add a #RequestMapping("/someprefix") at class level to see if the URL is being exposed as you want.
I verify your example locally using the version 3.1.0.RELEASE and no issue were present.
As a workaround (and also to provide a well-understand REST URI add some context to your second mapping:
#RequestMapping(value={"client/support"}) // i.e: if you are working with clients
public ModelAndView getsupport(#PathVariable Long supportId){
// do your code here something here
}
Of course that this is valid if this is the unique controller present in the system, otherwise you must use RequestMapping at class level as I suggested above.
I hope this helps.

I am not seeing this behavior with Spring 3.1.2, it could potentially have been a bug with an older Spring version. Here is a gist which runs through without any issues for me - https://gist.github.com/3802254

Related

Is there a way to provide an attribute to all models in Spring?

Thymeleaf dropped template expressions like #session, #httpServletRequest etc. in Version 3.1 (https://www.thymeleaf.org/doc/articles/thymeleaf31whatsnew.html).
We used those a lot in relatively large applications. I wrote an interceptor to populate those attributes at every request since I don't want to add them in every Controller needed (like described in the migration guide).
Does anybody know a better way of achieving this?
This is already the best method to populate attributes at each request, compared to the earlier methods defined in the Spring framework documentations.
I learned that #ControllerAdvice can be used in this case (see https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc).
Classes annotated with #ControllerAdvice, can have methods annotated with #ModelAttribute to populate attributes over multiple Controllers (all of them if not specified otherwise).
In my case:
#ControllerAdvice
public class CommonDataAdvice {
#Autowired
private HttpServletRequest request;
#ModelAttribute("request")
public HttpServletRequest populateRequest(){
return request;
}
}

How to call a Servlet/Filter before a JSP is executed in CQ5?

In a Spring MVC application we have a Controller that would execute before calling the JSP. The Controller would prefetch some values from the database and set them in the model and forward the control to JSP.
How do I implement this feature in CQ 5? I want the SlingFilter to execute before the JSP is executed. And the JSP is not a page component but a component that appears in the side kick.
Note:
I can do this by writing my own SlingSerlvet that would prefetch my required values and use the RequestDispatcher to forward to the JSP.
But by this method I would have to go through a URL like "/bin/.*". And this is again at a page level I want this kind of functionality at component level.
So to answer your specific question, if you want a filter to be executed before a component is called you would create a filter that is listening to Component level filter scope.
See
http://sling.apache.org/documentation/the-sling-engine/filters.html
You would then have your filter change the incoming request to a SlingServletRequest and determine if the target resource is the one that you are looking for.
However this filter would be executed on every single component that is being included on a page. The reverse process of this that may be useful to you is the ResourceDecorator.
http://sling.apache.org/documentation/the-sling-engine/wrap-or-decorate-resources.html
These are executed when the resource is identified, prior to the servlet and filter calls, which would allow you to verify if a resource is a type that you are interested in, and then allows you to add additional information to the resource object.However this is, once again a service that would be applied to every resource that is identified.
However, if what you are looking for is a filter that is only executed for a specific path, then no. Sling doesn't do that. You mentioned Spring MVC and Spring MVC works on a completely different concept of MVC then what Slings version of MVC does.
EDIT
So in a traditional web app, the servlet would be at a fixed position and all filters are applied prior to the call to that servlet. In Sling you are dynamically wiring servlets together to generate the resulting page. So each time that you are in a servlet and call directly or indirectly the request dispatcher, it's executing the resolution process again and applying a series of filters again before the new servlet is executed.
To prevent a high level filter that needs to applied only to the main request being applied on every single internal dispatch, they came up with the idea of contexts, or chains of filters that are applied at different times and associated with different types of includes.
Here is a basic filter that will log a message when it's called. I did this from memory so you'll need to dink with it.
#SlingFilter(scope = SlingFilterScope.COMPONENT, order = Integer.MIN_VALUE)
public class SampleFilter implements Filter {
private static final Logger LOG = LoggerFactory.getLogger(SampleFilter.class);
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;
Resource res = slingRequest.getResource();
if (!(res == null || ResourceUtil.isNonExistingResource(res))) {
LOG.error("this servlet is called before resource {} at path {}", res.getName(),res.getPath());
}
chain.doFilter(request, response);
}
}
The important part of this is scope = SlingFilterScope.COMPONENT take a look at the page I had listed earlier and try out different combinations of slignfilterscope and you'll see how it's being applied at different times. scope = SlingFilterScope.REQUEST would be once at a top level on a per page basis.
JE Bailey's answer is correct as far as Filters are concerned, but I suspect your problem might be solved in a different way that better fits Sling's view of the world.
Sling promotes the use of OSGi services for business logic, and scripts should be a thin layer above that. Moving your logic to OSGi services and calling those from your scripts is the recommended way.
You might also have a look at Sling Models which can include processing steps (with #PostConstruct) before the rendering scripts kick in.
But by this method I would have to go through a URL like "/bin/.*".
You can also register a servlet against a resource type, as well as by path, e.g. (from the Sling documentation):
#SlingServlet(
resourceTypes = "sling/servlet/default",
selectors = "hello",
extensions = "html",
methods = "GET")
public class MyServlet extends SlingSafeMethodsServlet {
#Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
...
}
}
If you remove the "selectors", "extensions" and "methods" parameters on the annotation, this servlet would bind against all calls to sling/servlet/default without requiring binding against a set path.

Accessing HttpServletRequest object in a normal Java class from Spring

I have a normal Java class in a Spring MVC 3.06 web application.
In this class I would like to inject or get hold of the HttpServletRequest object in a method.
I know I can pass this around, but I was wondering how can I get hold of the request without passing it in to the method. Perhaps using annotations or similar?
Also, what are the "real" concerns with getting hold of the request this way, except some peoples opinions of it being ugly coding. I mean, is it unstable to access it this way?
Preferably non application server dependent way.
I have seen
(HttpServletRequest) RequestContextHolder.getRequestContext().getExternalContext().getNativeRequest()
but this doesn't seem to work for Spring MVC 3.06 . RequestContextHolder doesn't have the method getRequestContext().
Use
((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
I'm not sure where you got RequestContextHolder.getRequestContext(), that's completely wrong.
is it unstable to access it this way?
No, it's stable enough, assuming you're always running the code as part of an HttpServlet request thread. The main issue is that yes, it's ugly, and it makes your code hard to test. That is reason enough not to use it.
If you must use it, then decouple it from your code, e.g.
public void doSomething() {
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
doSomething(request);
}
void doSomething(HttpServletRequest request) {
// put your business logic here, and test this method
}
#Context HttpServletRequest httpServletRequest =null;
use this

How to use context.getNamedDispatcher with the Guice Servlet Extension

I am trying migrate a servlet-project to use Guice 3.0-rc2 (from maven central) and its servlet extension. I already migrated another project where I had the same problem:
Since Guice renders the web.xml basically useless, I have no idea where to define my servlets names. The codebase makes quite heavy use of ServletContext#getNamedDispatcher("name") and I would like to change as little as possible. The first codebase used getNamedDispatcher only once, so I was able work around that.
The Servlets in question are not listening to any path, so using getRequesetDispatcher won't do.
Does anyone have any suggestions?
One of the big things Guice tries to do is move away from using unreliable String identifiers to using actual Java types to do things. While guice-servlet managed servlets do have names (the toString() of the Key they are bound as), I don't think the ServletContext is aware of them.
One option that may work for you is to actually inject the servlet(s) you want to be able to pass requests to and do it directly yourself:
#Singleton
public class TestServlet extends HttpServlet {
private final TestServlet2 testServlet2;
#Inject public TestServlet(TestServlet2 testServlet2) {
this.testServlet2 = testServlet2;
}
#Override
protected void doGet(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse)
throws ServletException, IOException {
testServlet2.doGet(httpServletRequest, httpServletResponse);
}
}
For this to work, you do need to register the servlets in your ServletModule... I think you can serve("").with(TestServlet2.class) in order to not have it map to any URL.

How do I implement a front controller in Java?

I'm writing a very simple web framework using Java servlets for learning purposes. I've done this before in PHP, and it worked by consulting the request URI, then instantiating the appropriate class and method.
This worked fine in PHP, as one can do something like $c = new $x; $x->$y;. I'm unsure however of how to translate this to Java, or even if this is an appropriate way to go about it.
So far, I've tried:
Router router = new Router(request.getPathInfo());
String className = router.route(); //returns com.example.controller.Foo
Class c = Class.forName(className);
Object x = c.newInstance();
Foo y = (Foo) x;
y.doSomething();
This seems fine for a couple of routes, but doesn't seem like it would scale well, nor would it allow for sourcing routes from a configuration file.
How should I make it work?
Get hold of actions in a Map<String, Action> where the String key represents less or more a combination of request method and request pathinfo. I've posted similar answer before here: Java Front Controller
You can fill such a map either statically (hardcoding all actions) or dynamically (convention over configuration, looking up classes in a certain package, or scanning the entire classpath for classes with a certain annotation or implementing a certain interface).
And just stick to Servlet. The Filter isn't there for. At highest use it to forward the request to the controller Servlet. In the Servlet, just implement HttpServlet#service().
I would use a Servlet Filter as Front Controller. The router would connect paths with request dispatchers. In the doFilter method you would convert ServletRequest to HttpServletRequest, extract the request path and match it against the registered mappings. The result of this mapping is a request dispatcher you would dispatch the request with.
In pseudo code:
doFilter(ServletRequest request, ServletResponse response) {
httpServletRequest = (HttpServletRequest) request;
path = httpServletRequest.getRequestURI();
dispatcher = router.getTarget(path);
dispatcher.dispatch(request, response);
}
Depending on your need the default routing mechanism of the Servlet API could be sufficient.
Not quite sure what you're after but you might want to take a look at Java servlets. Granted many web frameworks are abstracted above plain servlets, but it's a jolly good place to start learning about Java web apps if you ask me (which indirectly you did ;) )
Download the Java servlet specification here: Java Servlet Spec - it's quite interesting.
How should you make it work? However you want it to. If you're just doing it for learning purposes, whatever you do will be fine.
I would suggest having all your actions implement the same interface though (maybe extend Servlet) so that you don't have to compile in all different classes.
Then you can essentially do what you're doing, except that your cast to Foo becomes a cast to Servlet and then you don't have to have a special case for all your different classes.
You can then also load up the routes from configuration (maybe an XML file).
Essentially what you're doing is implemented by the Struts 1 framework so it might be worthwhile reading up on that (it's open-source so you can also look at the source if you want).

Categories

Resources