Spring mvc:mapping path rules - spring

I need to map interceptor for all methods in annotated controller with #RequestMapping(value = "/client")
In mapping I have
<mvc:interceptor>
<mvc:mapping path="/app/client/*"/>
<bean class="com.cci.isa.web.CIPClientHandleInterceptor" />
</mvc:interceptor>
This interceptor called perfectly for urls like:
1. http://host/app/client/clientUpdateForm?clientId=305
But doesn't called for urls like:
2. http://host/app/client/clientUpdateForm/clientId_305 (with slash after method name)
How get it called for second variant?
Thanks a lot.

This question is too old, but maybe this helps somebody.
You should try removing /app, I think it's not necessary and perhaps this is causing the problem.
<mvc:mapping path="/client/**"/>

I think this will achieve what you would like:
<mvc:mapping path="/app/client/**/*"/>
The '/**' suggests any number of directories. When this is used in conjunction with '/*', you have something that looks at an arbitrary folder depth, with an arbitrary file name.

If your controller with
#RequestMapping(value = "/client")
Try
<mvc:mapping path="/client**"/>

Try the above suggestion but change the annotation to
#RequestMapping(value = "/client*")
Although I would use two methods for each of the two URI patterns and pass them to the one common method to do the "stuff"...
#RequestMapping(value = "/app/client/clientUpdateFormat/{clientId}", method = RequestMethod.GET)
public String doItOne(#PathVariable("clientId") String clientId) {
doItCommon(clientId);
and
#RequestMapping(value = "/app/client/clientUpdateFormat", method = RequestMethod.GET)
public String doItTwo(#RequestParam("clientId") String clientId) {
doItCommon(clientId);

My problem was, that we used custom RequestMappingHandlerMapping
<bean name="handlerMapping"
class="utils.web.versioning.MobileVersionRewritingMappingHandler">
<property name="order" value="0"/>
<property name="interceptors">
<list>
...
</list>
</property>
</bean>
XML or code config for CORS or any other MVC properties doesn't affect custom handler mappings.
I could specify cors config for custom handler mapping, but I prefer to remove legacy config and use this to configure interceptors:
<mvc:interceptors>
...
</mvc:interceptors>
Now cors is working and I'm using XML global cors configuration.

Related

RedirectView with dynamic parameter in url

So, in my controller I have a method with mapping #RequestMapping(value = "/profile-{id}/launch") and at the end of it I want to redirect the flow to other method within same controller with mapping #RequestMapping(value = "/profile-{id}/executions") ...
I am obligated to inject RedirectView bean with xml configuration. So I have something like
<bean name="redirect:executions" class="org.springframework.web.servlet.view.RedirectView">
<property name="url" value="#{resourceService.servletPath}/profile-{id}/executions" />
<property name="contextRelative" value="true" />
</bean>
but how am I going to target specific profile ID, since at the end of first method I have to write return "redirect:executions" cause I am targeting the name of the bean, and it cant be dynamic.
Or I target the url with something like return "redirect:/profile-"+someID+"/executions"

The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler

I wanted to use both annotation mapping and xml mapping in Spring MVC. My application-context.xml as follows:
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="personal/account/history">accountHistoryController</prop>
</props>
</property>
</bean>
<bean id="accountHistoryController" class="com.fg.banking.ib.controller.AccountHistoryController" />
<bean
class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<context:annotation-config />
<mvc:annotation-driven />
<context:component-scan base-package="com.fg.banking.ib.controller, com.fg.banking.ib.helper, com.fg.banking.corporate.controller" />
I am getting the following error when I try to access the url. I have configured the SimpleControllerHandlerAdapter as above.
javax.servlet.ServletException: No adapter for handler
[com.fg.banking.ib.controller.AccountHistoryController#218531e6]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler
org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter(DispatcherServlet.java:1128)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:903)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827)
What to do?
This error also occurs when you define a restController but forget to define the requestMapping.
#RestController
#RequestMapping("/api/orders") // <---- dont't forget the requestMapping
This problem occurred for me when I tried to define RestController path by using in this way:
#RestController("/test")
public class TestController {}
In the above section, the meaning of this declaration is different. Here actually "/test" is defined as bean name rather than path for the controller.
After defining the path in this way it worked for me:
#RestController
#RequestMapping("/test")
public class TestController {}
I resolved the issue. I forgot to add the #Controller annotation in controller class. There are fore we can use the both methods(annotation mapping & XML mapping) together in an application.
Try adding the following as a handler mapper(Worked for me):
<bean id="HandlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
Make sure you have implemented Controller in your controller classes and overrided handleRequest method.
Here our controller class should extends
import org.springframework.web.servlet.mvc.AbstractController;
public class AppController extends AbstractController{ }
Here we need to implement the abstract method as :
protected modelandview handleRequestInternal(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception { return null; }

Looking for a way to apply aspects to spring-mvc controller method

The original intention was to be able to configure filter mappings with annotations (i.e. #FilteredBy below) instead of adding filter mappings to the web.xml file. Something like:
#Controller
public class MyController {
#RequestMapping(value = "/special/page.html")
#FilteredBy("SpecialBean") // <-- *** desired ***
public String doSpecialStuff() {
return "special/page";
}
}
I see that Servlet 3.0 introduces #ServletFilter which can be applied any object method and the mappings are defined by #FilterMapping. However, I want invert the responsibility of the mapping to the controller method consuming the shared logic of my "SpecialBean".
Why not use your spring context xml. If you are using mvc:annotation you can try this.
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/filtered/page.htm" />
<bean class="com.yourinterceptor" />
</mvc:interceptor>
</mvc:interceptors>

Spring MVC #PathVariable with dot (.) is getting truncated

This is continuation of question
Spring MVC #PathVariable getting truncated
Spring forum states that it has fixed(3.2 version) as part of ContentNegotiationManager. see the below link.
https://jira.springsource.org/browse/SPR-6164
https://jira.springsource.org/browse/SPR-7632
In my application requestParameter with .com is truncated.
Could anyone explain me how to use this new feature? how is it configurable at xml?
Note: spring forum- #1
Spring MVC #PathVariable with dot (.) is getting truncated
As far as i know this issue appears only for the pathvariable at the end of the requestmapping.
We were able to solve that by defining the regex addon in the requestmapping.
/somepath/{variable:.+}
Spring considers that anything behind the last dot is a file extension such as .jsonor .xml and trucate it to retrieve your parameter.
So if you have /somepath/{variable} :
/somepath/param, /somepath/param.json, /somepath/param.xml or /somepath/param.anything will result in a param with value param
/somepath/param.value.json, /somepath/param.value.xml or /somepath/param.value.anything will result in a param with value param.value
if you change your mapping to /somepath/{variable:.+} as suggested, any dot, including the last one will be consider as part of your parameter :
/somepath/param will result in a param with value param
/somepath/param.json will result in a param with value param.json
/somepath/param.xml will result in a param with value param.xml
/somepath/param.anything will result in a param with value param.anything
/somepath/param.value.json will result in a param with value param.value.json
...
If you don't care of extension recognition, you can disable it by overriding mvc:annotation-driven automagic :
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="contentNegotiationManager" ref="contentNegotiationManager"/>
<property name="useSuffixPatternMatch" value="false"/>
</bean>
So, again, if you have /somepath/{variable} :
/somepath/param, /somepath/param.json, /somepath/param.xml or /somepath/param.anything will result in a param with value param
/somepath/param.value.json, /somepath/param.value.xml or /somepath/param.value.anything will result in a param with value param.value
note : the difference from the default config is visible only if you have a mapping like somepath/something.{variable}. see Resthub project issue
if you want to keep extension management, since Spring 3.2 you can also set the useRegisteredSuffixPatternMatch property of RequestMappingHandlerMapping bean in order to keep suffixPattern recognition activated but limited to registered extension.
Here you define only json and xml extensions :
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="contentNegotiationManager" ref="contentNegotiationManager"/>
<property name="useRegisteredSuffixPatternMatch" value="true"/>
</bean>
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false"/>
<property name="favorParameter" value="true"/>
<property name="mediaTypes">
<value>
json=application/json
xml=application/xml
</value>
</property>
</bean>
Note that mvc:annotation-driven accepts now a contentNegotiation option to provide a custom bean but the property of RequestMappingHandlerMapping has to be changed to true (default false) (cf. https://jira.springsource.org/browse/SPR-7632).
For that reason, you still have to override the all mvc:annotation-driven configuration. I opened a ticket to Spring to ask for a custom RequestMappingHandlerMapping : https://jira.springsource.org/browse/SPR-11253. Please vote if you are intereted in.
While overriding, be carreful to consider also custom Execution management overriding. Otherwise, all your custom Exception mappings will fail. You will have to reuse messageCoverters with a list bean :
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />
<util:list id="messageConverters">
<bean class="your.custom.message.converter.IfAny"></bean>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</util:list>
<bean name="exceptionHandlerExceptionResolver"
class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver">
<property name="order" value="0"/>
<property name="messageConverters" ref="messageConverters"/>
</bean>
<bean name="handlerAdapter"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="conversionService" ref="conversionService" />
<property name="validator" ref="validator" />
</bean>
</property>
<property name="messageConverters" ref="messageConverters"/>
</bean>
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
</bean>
I implemented, in the open source project Resthub that I am part of, a set of tests on these subjects : see https://github.com/resthub/resthub-spring-stack/pull/219/files & https://github.com/resthub/resthub-spring-stack/issues/217
Update for Spring 4: since 4.0.1 you can use PathMatchConfigurer (via your WebMvcConfigurer), e.g.
#Configuration
protected static class AllResources extends WebMvcConfigurerAdapter {
#Override
public void configurePathMatch(PathMatchConfigurer matcher) {
matcher.setUseRegisteredSuffixPatternMatch(true);
}
}
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
}
}
In xml, it would be (https://jira.spring.io/browse/SPR-10163):
<mvc:annotation-driven>
[...]
<mvc:path-matching registered-suffixes-only="true"/>
</mvc:annotation-driven>
In addition to Martin Frey's answer, this can also be fixed by adding a trailing slash in the RequestMapping value:
/path/{variable}/
Keep in mind that this fix does not support maintainability. It now requires all URI's to have a trailing slash - something that may not be apparent to API users / new developers. Because it's likely not all parameters may have a . in them, it may also create intermittent bugs
In Spring Boot Rest Controller, I have resolved these by following Steps:
RestController :
#GetMapping("/statusByEmail/{email:.+}/")
public String statusByEmail(#PathVariable(value = "email") String email){
//code
}
And From Rest Client:
Get http://mywebhook.com/statusByEmail/abc.test#gmail.com/
adding the ":.+" worked for me, but not until I removed outer curly brackets.
value = {"/username/{id:.+}"} didn't work
value = "/username/{id:.+}" works
Hope I helped someone :)
/somepath/{variable:.+} works in Java requestMapping tag.
Here's an approach that relies purely on java configuration:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
#Configuration
public class MvcConfig extends WebMvcConfigurationSupport{
#Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = super.requestMappingHandlerMapping();
handlerMapping.setUseSuffixPatternMatch(false);
handlerMapping.setUseTrailingSlashMatch(false);
return handlerMapping;
}
}
One pretty easy way to work around this issue is to append a trailing slash ...
e.g.:
use :
/somepath/filename.jpg/
instead of:
/somepath/filename.jpg
In Spring Boot, The Regular expression solve the problem like
#GetMapping("/path/{param1:.+}")
The complete solution including email addresses in path names for spring 4.2 is
<bean id="contentNegotiationManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false" />
<property name="favorParameter" value="true" />
<property name="mediaTypes">
<value>
json=application/json
xml=application/xml
</value>
</property>
</bean>
<mvc:annotation-driven
content-negotiation-manager="contentNegotiationManager">
<mvc:path-matching suffix-pattern="false" registered-suffixes-only="true" />
</mvc:annotation-driven>
Add this to the application-xml
If you are using Spring 3.2.x and <mvc:annotation-driven />, create this little BeanPostProcessor:
package spring;
public final class DoNotTruncateMyUrls implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof RequestMappingHandlerMapping) {
((RequestMappingHandlerMapping)bean).setUseSuffixPatternMatch(false);
}
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
Then put this in your MVC config xml:
<bean class="spring.DoNotTruncateMyUrls" />
Finally I found solution in Spring Docs:
To completely disable the use of file extensions, you must set both of the following:
useSuffixPatternMatching(false), see PathMatchConfigurer
favorPathExtension(false), see ContentNegotiationConfigurer
Adding this to my WebMvcConfigurerAdapter implementation solved the problem:
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
}
#Override
public void configurePathMatch(PathMatchConfigurer matcher) {
matcher.setUseSuffixPatternMatch(false);
}
For me the
#GetMapping(path = "/a/{variableName:.+}")
does work but only if you also encode the "dot" in your request url as "%2E" then it works. But requires URL's to all be that...which is not a "standard" encoding, though valid. Feels like something of a bug :|
The other work around, similar to the "trailing slash" way is to move the variable that will have the dot "inline" ex:
#GetMapping(path = "/{variableName}/a")
now all dots will be preserved, no modifications needed.
If you write both back and frontend, another simple solution is to attach a "/" at the end of the URL at front. If so, you don't need to change your backend...
somepath/myemail#gmail.com/
Be happy!
As of Spring 5.2.4 (Spring Boot v2.2.6.RELEASE)
PathMatchConfigurer.setUseSuffixPatternMatch and ContentNegotiationConfigurer.favorPathExtension have been deprecated ( https://spring.io/blog/2020/03/24/spring-framework-5-2-5-available-now and https://github.com/spring-projects/spring-framework/issues/24179).
The real problem is that the client requests a specific media type (like .com) and Spring added all those media types by default. In most cases your REST controller will only produce JSON so it will not support the requested output format (.com).
To overcome this issue you should be all good by updating your rest controller (or specific method) to support the 'ouput' format (#RequestMapping(produces = MediaType.ALL_VALUE)) and of course allow characters like a dot ({username:.+}).
Example:
#RequestMapping(value = USERNAME, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public class UsernameAPI {
private final UsernameService service;
#GetMapping(value = "/{username:.+}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.ALL_VALUE)
public ResponseEntity isUsernameAlreadyInUse(#PathVariable(value = "username") #Valid #Size(max = 255) String username) {
log.debug("Check if username already exists");
if (service.doesUsernameExist(username)) {
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
return ResponseEntity.notFound().build();
}
}
Spring 5.3 and above will only match registered suffixes (media types).
If you are using Spring 3.2+ then below solution will help. This will handle all urls so definitely better than applying regex pattern in the request URI mapping to allow . like /somepath/{variable:.+}
Define a bean in the xml file
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="useSuffixPatternMatch" value="false"/>
<property name="useRegisteredSuffixPatternMatch" value="true"/>
</bean>
The flags usage can be found on the documentation. I am putting snipped to explain
exlanation of useRegisteredSuffixPatternMatch is said to be resolving the issue. From the java doc in the class
If enabled, a controller method mapped to "/users" also matches to
"/users.json" assuming ".json" is a file extension registered with the
provided {#link #setContentNegotiationManager(ContentNegotiationManager)
contentNegotiationManager}. This can be useful for allowing only specific
URL extensions to be used as well as in cases where a "." in the URL path
can lead to ambiguous interpretation of path variable content, (e.g. given
"/users/{user}" and incoming URLs such as "/users/john.j.joe" and
"/users/john.j.joe.json").
Simple Solution Fix: adding a regex {q:.+} in the #RequestMapping
#RequestMapping("medici/james/Site")
public class WebSiteController {
#RequestMapping(value = "/{site:.+}", method = RequestMethod.GET)
public ModelAndView display(#PathVariable("site") String site) {
return getModelAndView(site, "web site");
}
}
Now, for input /site/jamesmedice.com, “site” will display the correct james'site

Can I combine #controller and XML bean mapping in spring?

I currently have a #Controller declared in spring and have a bunch of mappings done like so:
#RequestMapping(value = "foo", method = RequestMethod.GET)
public ModelAndView foo() {
ModelAndView mav = new ModelAndView(
"myjsp");
return mav;
}
However every time I want to add a simple JSP mapping I need to recompile and build a new war and deploy.
This isnt so bad except sometimes other members of the team have requests and it would be easier if they can just go into the test env and create the mapping themselves without having to recompile.
I know that you can do similar mapping using xml but can I do this at the same time that I have the #Controller defined?
Like in the example above how could I define that mapping in XML rather than in java?
or say I needed foo2 to map to myjsp2.jsp
I am using spring MVC 3.2
Look into BeanNameUrlHandlerMapping which allows you specify url patterns for controllers in your configuration. Documentation
Example
<beans>
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean name="/editaccount.form" class="org.springframework.web.servlet.mvc.SimpleFormController">
<property name="formView" value="account"/>
<property name="successView" value="account-created"/>
<property name="commandName" value="account"/>
<property name="commandClass" value="samples.Account"/>
</bean>
<beans>

Resources