#MatrixVariable Spring 3.2 return Null - java

I'm using Spring 3.2.6 in order to learn the #MatrixVariable feature with a basic example.
I have coded this method to get the matrix variable from the URI :
#RequestMapping(value="/matrix/{paths}", method=RequestMethod.GET)
public ModelAndView MatrixVariableExample(#MatrixVariable Integer age){
ModelAndView mv = new ModelAndView("affichageMatrix");
mv.addObject("age", age);
return mv;
}
I use this URI : localhost:8080/SpringMVC-Maven/matrix/user;age=23
The value returned for the age variable is null, but I it should be 23

Enable Matrix Variables in spring config file:
<mvc:annotation-driven enable-matrix-variables="true"/>

Try to change your code like this:
#RequestMapping(value="/matrix/{paths}", method=RequestMethod.GET)
public ModelAndView MatrixVariableExample(#PathVariable String paths, #MatrixVariable Integer age){
System.out.println(paths); //or do something with it, at your choice
ModelAndView mv = new ModelAndView("affichageMatrix");
mv.addObject("age", age);
return mv;
}
And use URL:
http://localhost:8080/SpringMVC-Maven/matrix/user;age=23
Your variable paths should now contain string user, and age should be 23. I guess you're not allowed to miss path parameters if you have already parametrized your request mapping.

To use matrix variable you have to enable Spring MVC framework to read matrix variable in your application.
You can do it using either XML notation or by java configuration
XML configuration:
By adding below configuration in dispatcher-servlet.xml
<mvc:annotation-driven enable-matrix-variables="true"/>
Java Configuration:
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {AppConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] {"/*"};
}}
#Configuration
#EnableWebMvc
#ComponentScan(basePackages= {"com.springmvc.test"})
public class AppConfig implements WebMvcConfigurer {
#Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver resolver=new InternalResourceViewResolver();
resolver.setViewClass(JstlView.class);
resolver.setPrefix("/jsp/");
resolver.setSuffix(".jsp");
return resolver;
}
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper=new UrlPathHelper();
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}}

Related

Spring framework not decoding path variables with semicolon

In a Spring framework application I want to pass a URL encoded path variable value of ;,/?:#&=+$-_.!~*'()# to the following method:
#RequestMapping(value = "/{et}/{ei}/{ls}", method = RequestMethod.PATCH)
#ResponseBody
public JSONObject lk( #PathVariable("et") String et,
#PathVariable("ei") String ei,
#PathVariable("ls") LS ls,
HttpServletRequest request,
HttpServletResponse response)
throws UIServerException {
When I test it using the following curl command:
curl -s -X PATCH "http://example.com/etxx/%3B%2C%2F%3F%3A%40%26%3D%2B%24-_.%21~%2A%27%28%29%23/lsxx"
I can see that the path variable has not been decoded correctly in the debugger - the semicolon and colon from the encoded string are removed.
I've tried setting the following but with no luck:
final UrlPathHelper urlPathHelper = new UrlPathHelper();
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
Although not very sure but this is just a possibility. Can you try setting setRemoveSemicolonContent(false) at the RequestMappingHandlerMapping level and check if it works
#Configuration
public class WebConfig extends DelegatingWebMvcConfiguration {
#Override
#Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
final RequestMappingHandlerMapping requestMappingHandlerMapping = super.requestMappingHandlerMapping();
requestMappingHandlerMapping.setRemoveSemicolonContent(false);
return requestMappingHandlerMapping;
}
}
This worked for me:
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
final DefaultHttpFirewall firewall = new DefaultHttpFirewall();
firewall.setAllowUrlEncodedSlash(true);
return firewall;
}
#Override
public void configure(final WebSecurity web) throws Exception {
web.httpFirewall(allowUrlEncodedSlashHttpFirewall());
}
}
public class AppConfig extends WebMvcConfigurationSupport {
#Override
#Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
final RequestMappingHandlerMapping requestMappingHandlerMapping = super.requestMappingHandlerMapping();
requestMappingHandlerMapping.setUrlDecode(false);
return requestMappingHandlerMapping;
}
}
add security setting to allow encoded forward slashes
disable URL decoding in request mapping
(also had to fix in Nginx reverse proxy)

Controller doesn't work with spring

I use spring mvc with spring configuration (without xml). And it seems like IDEA doesn't go to controller code. Maybe somewhere path is incorrect so #RequestMapping doesn't work. But i can't understand where exactly.
Here is my Controller
#Controller
public class MainController {
#RequestMapping(value = "/" , method = RequestMethod.GET)
public String home() {
return "index";
}
#RequestMapping(value = "welcome", method = RequestMethod.GET)
public String welcome(Model m){
m.addAttribute("name","lol kkeke");
return "index2";
}
}
WebMvcConfig
#Configuration
#ComponentScan("com.chat")
#EnableWebMvc
public class WebMVCConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/scripts/**").addResourceLocations("/scripts/");
registry.addResourceHandler("/styles/**").addResourceLocations("/styles/");
registry.addResourceHandler("/images/**").addResourceLocations("/images/");
registry.addResourceHandler("/fonts/**").addResourceLocations("/fonts/");
registry.addResourceHandler("/pages/**").addResourceLocations("/views/");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("/index.jsp");
}
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
}
So.. I solved a problem. It was in Controller - path. My Idea automatically change path from com.chat.controller to c.c.controller. So i rebuild project structure to com.chat.controller.Controller.class; and com.chat.config.Configuration.class.
Also, i found the next article about similar trouble. May be it will help somebody! How do I map Spring MVC controller to a uri with and without trailing slash?

Troubles running spring mvc java based configuration in idea local tomcat

I created to simple spring mvc configuration using java based configuration:
Config file:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.kitchen")
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/kitchen/**").addResourceLocations("/kitchen/");
registry.addResourceHandler("/images/**").addResourceLocations("file:E:/Work/images/");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
Initializer:
public class WebMvcAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[0];
}
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{WebMvcConfiguration.class};
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
#Override
protected Filter[] getServletFilters() {
return new Filter[]{new CORSFilter()};
}
}
Controller:
#Controller
public class IndexController {
#RequestMapping(value = "/")
public String getIndexPage() {
return "kitchen/index.html";
}
}
All files are located in same package. But when I try to deploy in tomcat, nothing is deployed. I am not good in configurations so I would like to ask maybe I forgot something more? I do not want to use web.xml, just plain java configuration.
Also there could be problem creating modules and artifacts in in Idea IDE I moved not a lot of time ogo to it from eclipse. so here is everithing a little bit different. Here are my configurations of project modules and artifacts, can you please tell me what could be problems in my situation?
Screens:

getServletConfigClasses() vs getRootConfigClasses() when extending AbstractAnnotationConfigDispatcherServletInitializer

What is the difference between getServletConfigClasses() vs getRootConfigClasses() when extending AbstractAnnotationConfigDispatcherServletInitializer.
I've been reading a lot sources since this morning but I haven't get any clear understanding on the differences yet :
Please have look at these two configurations :
1).
public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { ConServlet.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
....
....
}
The ConServlet.class is refering to
#EnableWebMvc
#Configuration
#ComponentScan({ "com" })
#Import({ SecurityConfig.class })
public class ConServlet {
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/pages/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
2).
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class };
}
.....
}
the WebConfig.class is refering to
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "....." })
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
I see both ConServlet & WebConfig (more or less) doing the same things like initializating view :
But why :
ConServlet is returned in getRootConfigClasses()
while WebConfig is returned in getServletConfigClasses()
I read the documentation
both getRootConfigClasses() & getServletConfigClasses() is for
Specify #Configuration and/or #Component classes to be provided to..
(their differences )
the root application context for getRootConfigClasses()
the dispatcher servlet application context for getServletConfigClasses()
but why then ConServlet & WebConfig doing same things (like initizialising view), maybe I'm the one misunderstood it. What's are actually root context and dispatcher servlets (I know this one) in the simple term/example
Thank you!
A Bit on ApplicationContext Hierarchies
Spring's ApplicationContext provides the capability of loading multiple (hierarchical) contexts, allowing each to be focused on one particular layer, such as the web layer of an application or middle-tier services.
One of the canonical examples of using hierarchical ApplicationContext is when we have multiple DispatcherServlets in a web application and we're going to share some of the common beans such as datasources between them. This way, we can define a root ApplicationContext that contain all the common beans and multiple WebApplicationContexts that inherit the common beans from the root context.
In the Web MVC framework, each DispatcherServlet has its own WebApplicationContext, which inherits all the beans already defined in the root WebApplicationContext. These inherited beans can be overridden in the servlet-specific scope, and you can define new scope-specific beans local to a given Servlet instance.
Typical context hierarchy in Spring Web MVC (Spring Documentation)
If you're living in a single DispatherServlet world, it is also possible to have just one root context for this scenario:
Single root context in Spring Web MVC (Spring Documentation)
Talk is cheap, Show me the code!
Suppose we're developing a web application and we're going to use Spring MVC, Spring Security and Spring Data JPA. For this simple scenario, we would have at least three different config files. A WebConfig that contains all our web related configurations, such as ViewResolvers, Controllers, ArgumentResolvers, etc. Something like following:
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = "com.so.web")
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
final boolean DO_NOT_USE_SUFFIX_PATTERN_MATCHING = false;
configurer.setUseSuffixPatternMatch(DO_NOT_USE_SUFFIX_PATTERN_MATCHING);
}
}
Here I'm defining a ViewResolver to resolve my plain old jsps, poor life decisions, basically. We would need a RepositoryConfig, which contains all the data access facilities such as DataSource, EntityManagerFactory, TransactionManager, etc. It probably would be like following:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = "com.so.repository")
public class RepositoryConfig {
#Bean
public DataSource dataSource() { ... }
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() { ... }
#Bean
public PlatformTransactionManager transactionManager() { ... }
}
And a SecurityConfig which contains all the security related stuff!
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
#Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception { ... }
#Override
protected void configure(HttpSecurity http) throws Exception { ... }
}
For gluing all these together, we have two options. First, we can define a typical hierarchical ApplicationContext, by adding RepositoryConfig and SecurityConfig in root context and WebConfig in their child context:
public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RepositoryConfig.class, SecurityConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
Since we have a single DispatcherServlet here, we can add the WebConfig to the root context and make the servlet context empty:
public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RepositoryConfig.class, SecurityConfig.class, WebConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
Further Reading
Skaffman did a great job on explaining ApplicationContext hierarchies in this answer, which is highly recommended. Also, you can read Spring Documentation.
Root Config Classes are actually used to Create Beans which are Application Specific and which needs to be available for Filters (As Filters are not part of Servlet).
Servlet Config Classes are actually used to Create Beans which are DispatcherServlet specific such as ViewResolvers, ArgumentResolvers, Interceptor, etc.
Root Config Classes will be loaded first and then Servlet Config Classes will be loaded.
Root Config Classes will be the Parent Context and it will create a ApplicationContext instace. Where as Servlet Config Classes will be the Child Context of the Parent Context and it will create a WebApplicationContext instance.
In your ConServlet Configuration, You don't need to specify the #EnableWebMvc as well the InternalResourceViewResolver bean as they are only required at the WebConfig.

access static html page from jar file using spring

I want to call home.html file present in jar under /WEB-INF/lib using spring.
Below is configuration class
#Configuration
#ComponentScan("com.barclays.mobile.gateway.controller")
#EnableWebMvc
public class MvcConfig extends WebMvcConfigurerAdapter{
#Bean(name = "viewResolver")
public InternalResourceViewResolver getViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/");
viewResolver.setSuffix(".html");
return viewResolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/component/**").addResourceLocations("classpath:/app/component/*");
registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/app/assets/*");
registry.addResourceHandler("/home/**").addResourceLocations("classpath:/app/*");
}
}
Below is controller:
#Controller
public class StaffController {
#RequestMapping(value = "/home", method = RequestMethod.GET)
public String home() {
return "home";
}
}
Please suggest how to do this.?
remove / from /home, I guess that is the problem

Categories