Spring Controller Request Mapping Does Not Work Correctly - java

I have a simple request mapping that opens up an html file residing in static folder. It works correctly when the request mapping is a one part request like '/town' but does not works (returns 404) on urls like '/visual/town'. When I debug, the program falls to the desired place though. It just cannot recognise the file that it points to when the mapping constitutes of two or more parts. This doesn't makes sense to me at all.
This one works :
#Controller("VisualHomeController")
public class HomeController {
#RequestMapping(value = "/town")
public String emergentTown() {
return "static/visual/emergent_town.html";
}
}
This one does not :
#Controller("VisualHomeController")
public class HomeController {
#RequestMapping(value = "/visual/town")
public String emergentTown() {
return "static/visual/emergent_town.html";
}
}
And here is my servlet mapping, It seems that the problem arises here :
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

So, I figured out that the problem is with the servlet mapping.
I needed to add another servlet mapping for the first part of my additional controller which is /visual as :
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>/visual/*</url-pattern>
</servlet-mapping>
Then it worked. So whenever you want to have requests like /.../new_page you need to define the ... as servlet mappings. Note that changing the main servlet mapping to /* is not enough for this purpose.
Note : It still doesn't make sense that why the program falls into the return ... when debugging. I mean, if one more servlet mapping is needed, how front controller can route the request to that method? And while doing so why it can not resolve the view?

Related

Spring 4 RestController Dispatcher url-pattern

I have an annotated rest controller, like the one below. I'm able to get the services to host fine, but only if I configure the full path for each individual service in web.xml:
#RestController
#RequestMapping("/service/")
public class StuffRestController
{
#RequestMapping("/getStuffList")
public List<Stuff> getStuffList() {
... make stuff ...
return stuffList;
}
... many other similar services ...
}
This is really the only spring resource in my application; although, we are using spring security.
The below are the only lines spring4-servlet.xml:
<mvc:annotation-driven />
<context:component-scan base-package="com.me.stuff.presentation.controller" />
<context:component-scan base-package="com.me.stuff.security" />
The StuffRestController class resides in the "...controller" package.
web.xml:
<servlet>
<servlet-name>spring4</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring4-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring4</servlet-name>
<url-pattern>/service/getStuffList</url-pattern>
</servlet-mapping>
All of the above actually all works fine and dandy, but there are 30 other services in this controller and I would rather not make a new servlet mapping for every method. The issue occurs when I attempt to "wildcard" the mapping. I've tried /service/, /service, and /service/*. And many other combinations.
Most all simply don't map properly, and I receive 404 errors. If I use /service/* it will engage the dispatcher servlet when /service/getStuffList is called, but it responds with:
WARNING: No mapping found for HTTP request with URI [/myapp/service/getStuffList] in DispatcherServlet with name 'spring4'
I'm sure this is something simple with how URL mappings are created, but it is eluding me.
The issue is you've included the path: /service/getStuffList in both your DispatcherServlet and the #RestController request mapping. So to access the rest controller method, you've to hit the following URL:
{contextPath}/service/getStuffList/service/getStuffList
So, either change the dispatcher servlet url-pattern to /, so it will handle every request coming to your application, and then based on path after myApp, will redirect to appropriate controller. Or, set the RestController mapping to /*. You should prefer the former approach.
If you want to have your servlet handle request coming at /service, then change the url-pattern to /service/*. But then you've to remove all the request mapping from class level. Else at current scenario, you've to hit the following url:
{contextPath}/service/service/getStuffList
However, if you want to include the dispatcher servlet url-pattern in path resolution (i.e., you want to map the class at /service and also map servlet to that path), you can set alwaysUseFullPath property to true of URL handler mapping. For that, add the following to your spring context xml file:
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name = "alwaysUseFullPath" value = "true" />
</bean>

Spring MVC request mapping conflict

I'm having an issue regarding #RequestMapping on classes. Say I have these two controllers:
#Controller
#RequestMapping(value="/controller1")
public class Controller1 {
#RequestMapping(value="/method11.do")
public #ResponseBody method11(){
//...
}
#RequestMapping(value="/method12.do")
public ModelAndView method12(){
//This method redirects me to another jsp where I'll call Controller2 methods
return new ModelAndView("test");
}
}
#Controller
#RequestMapping(value="/controller2")
public class Controller2 {
#RequestMapping(value="/method21.do")
public #ResponseBody method21(){
//...
}
}
When I first call via AJAX method11, it works fine, the url generated is http://mydomain/myapp/controller1/method11.do
Then, I call method12 and get redirected to test.jsp, and from there, I call to method21, and here is the problem, the url generated is not the expected http://mydomain/myapp/controller2/method21.do, but something else, depending on how I make the AJAX call:
url:'controller2/method21' --> http://mydomain/myapp/controller1/controller2/method21.do
url:'/controller2/method21' --> http://mydomain/controller2/method21.do
So, in what way should I make the calls so that they always start at http://mydomain/myapp/...?
I believe I could just use url:'/myapp/controller2/method21.do', but I guess there should be a more generic way in which I don't have to use 'myapp' on every call.
This is my web.xml:
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
You should make the client aware of the proper URL by retrieving the context root within your script using JSP EL.
In JSP
<script>var ctx = "${pageContext.request.contextPath}"</script>
You can then use ctx as a prefix to the URLs constructed via Javascript.
var url = ctx + "/rest_of_url"
On the server side, you can use:
${pageContext.request.contextPath} or JSTL has a tag, <c:url> which will append your context root.

Spring MVC and RequestMapping with filter

I am having a problem with url mappings and thought somebody might help me :-)
My Spring MVC application has a dispatcherServler's mapping as follows:
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
Then I have a controller servlet with a method annotated like this:
MyServlet {
....myMethod
#RequestMapping(value = "/qwert/request", method = RequestMethod.POST)
To conclude I have a DelegatingFilterProxy with a mapping:
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/qwert/request</url-pattern>
</filter-mapping>
whose target is to intercept all requests directed to the aforementioned MyServlet's method.
The application is working fine for the typical request localhost:port/MyApp/qwert/request which means that the filter is intercepting requests and doing its business.
The problems is that a request like this localhost:port/MyApp/qwert/request.do is getting directly into the Servlet (MyServlet) method without passing through the Filter. My #RequestMapping is not /qwert/request.do, how can the request end up arriving in the servlet?
Does anyone have any idea how to solve this without changing my dispatcherServlet mapping to something like *.do and making other changes accordingly.
I would like my application to serve requests under localhost:port/MyApp/qwert/request and not localhost:port/MyApp/qwert/request.whatever and I cannot change the filter mapping to /* since there are other methods that do not require the filter intervention.
Thanks
Update 1:
Yes, I tried to introduce a filter's url-pattern like /qwert/request.* but in that case the filter does not intercept any request. Neither localhost:port/MyApp/qwert/request nor localhost:port/MyApp/qwert/request.whatever (being the first one the one normal callers should be using)
Solution
At the end I found what the problem was, #Jhonathan pointed me in the right direction
I had to define a RequestMappingHandlerMapping instead of a DefaultAnnotationHandlerMapping
#Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping mapping = new RequestMappingHandlerMapping();
// no dot like names will be matched
mapping.setUseSuffixPatternMatch(false);
// no trailing slash will be matched
mapping.setUseTrailingSlashMatch(false);
return mapping;
}
That did the trick and I can now see internally that the pattern does not mach "wrong" requests like the ones I mentioned at the beginning.
Thank you all
First Question
My #RequestMapping is not /qwert/request.do, how can the request end up arriving in the servlet?
Spring by default take
/qwert/request.do
/qwert/request.whatever
/qwert/request.*
like
/qwert/request
therefore your #RequestMapping(value = "/qwert/request", method = RequestMethod.POST)take request. Change in your
DefaultAnnotationHandlerMapping for change this default option:
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="useDefaultSuffixPattern" value="false" />
</bean>
From Spring Source:
setUseDefaultSuffixPattern
public void setUseDefaultSuffixPattern(boolean useDefaultSuffixPattern)
Set whether to register paths using the default suffix pattern as well: i.e. whether "/users" should be registered as "/users." and "/users/" too.
Default is "true". Turn this convention off if you intend to interpret your #RequestMapping paths strictly.
Note that paths which include a ".xxx" suffix or end with "/" already will not be transformed using the default suffix pattern in any case.*

Spring and returning protected resources

I have a pretty standard Spring 3.0.7 web app
The structure is like this
WebContent/
resources/
myStaticConent/
WEB-INF/
views/
myProtectedContent/
I am using the <mvc:resources> configuration for the static content and my controllers get views using the InternalViewResolver from WEB-INF/views
Now I have a requirement to return non-JSP content ( JPGs,PNGs,HTML,etc ) from a protected directory in WEB-INF
So a user might enter a URL like http:myWebApp/myProtectedContent and hit my protected content controller.
#Controller
public class HelloWorldController {
#RequestMapping(value="/myProtectedContent")
public String index() {
return "myjpg.jpg";
}
}
Essentially I want to conditionally serve a file just like I would a view. Anyone know how this can be done ?
I looked at some of the other methods here, Streaming using Inputstream seems overkill for files that are essentially static. Can I register another "view" type ? I need this to appear l( from the web browser side ) like a standard http request response ( like the current view implementation).
I would really like to avoid inventing my own file handling methods unless there is some reason why using the file access methods are better then Springs "other" view resolvers like ResourceBundleResolver
So the requirement is
Conditionally respond to a http request with variable file type (jpg,png,html) from inside WEB-INF without wrapping in a jsp or having the file interpreted by the JSTL view. The names of the files are known and static. The controller will determine the file name based on its own business logic.
You can reproduce the behavior of the underlying implementation of <mvc:resources/> which is org.springframework.web.servlet.resource.ResourceHttpRequestHandler, which essentially streams out the content of the static files - You can like ResourceHttpRequestHandler, extend from org.springframework.web.servlet.support.WebContentGenerator which has extensive support for sending last-modified and caching related headers, and finally to stream the content also there is a utility that Spring provides:
org.springframework.util.FileCopyUtils.copy(resource.getInputStream(), response.getOutputStream());
Updated:
#Controller
public class HelloWorldController implements ApplicationContextAware {
ApplicatonContext ctx = ...;
#RequestMapping(value="/myProtectedContent")
public void index(HttpServletRequest req, HttpServletResponse res) {
Resource resource = ctx.getResource("classpath:staticpath/myjpg.jpg");
FileCopyUtils.copy(resource.getInputStream(), response.getOutputStream());
}
}
Something you can do is to map a new servlet to the path you want to be protected and handle the request the way you want.
For example, in web.xml:
<servlet>
<servlet-name>protServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/protServlet-context.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>protServlet</servlet-name>
<url-pattern>/myProtectedContent</url-pattern>
</servlet-mapping>
This way, you map a new servlet (DispatcherServlet) for URLs that are protected content.
The load-on-startup value equals 2 is due if you already have a DispatcherServlet with this field value equals 1.

GWT + GAE Servlet URL and Servlet Mapping

http://127.0.0.1:8888/socialnetwork/contactsService
That's the current URL for one of my servlets. My question is, how do I change it?
In my web.xml file, altering
<servlet-mapping>
<servlet-name>contactsServiceServlet</servlet-name>
<url-pattern>/socialnetwork/contactsService</url-pattern>
</servlet-mapping>
to
<servlet-mapping>
<servlet-name>contactsServiceServlet</servlet-name>
<url-pattern>/a/contactsService</url-pattern>
</servlet-mapping>
Makes absolutely NO difference to the URL it requests when I make an RPC-call to the servlet.
Once you have done the above you need to change where you invoke (Which is described in the Annotation below) as in...
// The RemoteServiceRelativePath annotation automatically calls setServiceEntryPoint()
#RemoteServiceRelativePath("email")
public interface MyEmailService extends RemoteService {
void emptyMyInbox(String username, String password);
}
See http://google-web-toolkit.googlecode.com/svn/javadoc/1.6/com/google/gwt/user/client/rpc/RemoteServiceRelativePath.html

Categories