Objective
The Spring MVC framework is believed to be familiar to many people, and the information on this is a huge search. But the feeling speaks is not very meticulous, lets many beginners all foggy. I have done so, I have studied it before, but I don't have to find it again after some time. So I decided to write it down for later use.
This series is based on spring-4.3.1, the configuration method is all based on java-based mode
From the configuration
First, the Configuration code:
@EnableWebMvc@Configuration Public class mvcconfig extends webmvcconfigureradapter { @Override Public void configuredefaultservlethandling(Defaultservlethandlerconfigurer Configurer) {configurer.enable (); }@Override Public void configureviewresolvers(Viewresolverregistry Registry) {registry.jsp ("/web-inf/jsp/",". JSP"); Registry.enablecontentnegotiation (NewMappingjackson2jsonview ()); }@Override Public void configurecontentnegotiation(Contentnegotiationconfigurer Configurer) {Configurer.favorpathextension (true). Ignoreacceptheader (true). ParameterName ("mediatype"). Defaultcontenttype (mediatype.text_html). MediaType ("HTML", mediatype.text_html). MediaType ("JSON", Mediatype.application_json); }@Bean(name ="Multipartresolver")//File Upload bean PublicCommonsmultipartresolverCommonsmultipartresolver() {return NewCommonsmultipartresolver (); }}
The spring MVC configuration based on the java-based approach requires the creation of a configuration class and implementation WebMvcConfigurer
interface, which WebMvcConfigurerAdapter
is a simple abstraction of the WebMvcConfigurer
interface (with some default implementations added), so the configuration code above chooses to inherit directly WebMvcConfigurerAdapter
. Then implement the specific methods in the interface according to the needs of the project, and finally note that you want to label them on the configuration class @EnableWebMvc
.
Someone here might ask, how do I know what to implement? How exactly should I match? What are the processing processes between them? OK, don't worry, we'll step by step.
First, we need to know WebMvcConfigurer
what callback methods are available on the interface.
Webmvcconfigurer
PackageOrg.springframework.web.servlet.config.annotation;/** * For reasons, we will introduce only some of the methods commonly used by spring MVC * * Public interface webmvcconfigurer { voidAddformatters (Formatterregistry Registry);voidConfiguremessageconverters (listvoidExtendmessageconverters (list/ * Some options for configuring content adjudication * / voidConfigurecontentnegotiation (Contentnegotiationconfigurer configurer);voidConfigureasyncsupport (Asyncsupportconfigurer configurer);/ * @since 4.0.3 * / voidConfigurepathmatch (Pathmatchconfigurer configurer);/ * Parameter Resolution * / voidAddargumentresolvers (list/ * Return value Resolution * / voidAddreturnvaluehandlers (list/ * Exception handling * / voidConfigurehandlerexceptionresolvers (listvoidExtendhandlerexceptionresolvers (listvoidAddinterceptors (Interceptorregistry Registry); Messagecodesresolver Getmessagecodesresolver ();voidAddviewcontrollers (Viewcontrollerregistry Registry);/** * Here Configure the View resolver */ voidConfigureviewresolvers (Viewresolverregistry Registry);/** * Static resource processing * / voidAddresourcehandlers (Resourcehandlerregistry Registry);voidConfiguredefaultservlethandling (Defaultservlethandlerconfigurer configurer);voidAddcorsmappings (Corsregistry registry);}
Here are a few common ways to focus on the following:
void configureViewResolvers(ViewResolverRegistry registry);void configureContentNegotiation(ContentNegotiationConfigurer configurer);void addViewControllers(ViewControllerRegistry registry);void addResourceHandlers(ResourceHandlerRegistry registry);void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer);
1. Configureviewresolvers (Viewresolverregistry Registry)
From the method name we can see that this method is used to configure the view parser, the parameter of the method ViewResolverRegistry
is a registrar, used to register you want to customize the view parser and so on. ViewResolverRegistry
a few common methods:
1). Enablecontentnegotiation
/** 启用内容裁决视图解析器*/publicvoidenableContentNegotiation(View... defaultViews) { initContentNegotiatingViewResolver(defaultViews); }
This method creates a content adjudication parser that ContentNegotiatingViewResolver
does not parse the specific view, but manages all the view parsers that you register, all of which are parsed first, and then determined by which parser to use. The specific mapping rules are determined based on the requested media types.
2). urlbasedviewresolverregistration
publicjsp(String prefix, String suffix) { new InternalResourceViewResolver(); resolver.setPrefix(prefix); resolver.setSuffix(suffix); this.viewResolvers.add(resolver); returnnew UrlBasedViewResolverRegistration(resolver); }
The method registers an internal resource View parser that InternalResourceViewResolver
is apparently accessed by all JSPs that it parses. The method parameter is used to specify the prefix and file suffix of the path, such as:
registry.jsp("/WEB-INF/jsp/"".jsp");
For the above configuration, if the returned view name is example, it will be returned /WEB-INF/jsp/example.jsp
to the front end and the report 404 cannot be found.
3). Beanname
publicvoidbeanName() { new BeanNameViewResolver(); this.viewResolvers.add(resolver); }
This method registers a BeanNameViewResolver
view resolver, what does this parser do? It mainly resolves the view name to the corresponding bean. What do you mean? If the returned view name is example, will it find a bean called example in the spring container, and the bean is of type view.class? If so, return this bean.
4). Viewresolver
publicvoidviewResolver(ViewResolver viewResolver) { ifinstanceof ContentNegotiatingViewResolver) { thrownew BeanInitializationException( "addViewResolver cannot be used to configure a ContentNegotiatingViewResolver. Please use the method enableContentNegotiation instead."); } this.viewResolvers.add(viewResolver); }
This method must be known by the name, it is used to register a variety of view parsers, including their own definition.
2. Configurecontentnegotiation (Contentnegotiationconfigurer configurer)
In the previous section we talked about the configureViewResolvers
method, if we enabled the Content award parser in this method, then configureContentNegotiation(ContentNegotiationConfigurer configurer)
this method is specifically used to configure some parameters of the Content award. This is relatively straightforward, and we can look at it directly from an example:
public void Configurecontentnegotiation (Contentnegotiationconfigurer configurer) {/ * Whether media type is determined by requesting the extension of the URL * /Configurer. Favorpathextension(true)/ * Do not check the Accept request header * / . Ignoreacceptheader(true). ParameterName("mediatype")/ * Set the default media yype * / . Defaultcontenttype(mediatype. TEXT_html)/ * request to end with. HTML will be treated as mediatype.text_html*/ . MediaType("HTML", mediatype. TEXT_html)/ * requests that end with. JSON will be treated as mediatype.application_json*/ . MediaType("JSON", mediatype. Application_json);}
Here we can give an example to further familiarize ourselves with the above knowledge, if our MVC configuration is as follows:
@EnableWebMvc @Configuration Public class mvcconfig extends webmvcconfigureradapter { @Override Public void configureviewresolvers(Viewresolverregistry Registry) {registry.jsp ("/web-inf/jsp/",". JSP"); Registry.enablecontentnegotiation (NewMappingjackson2jsonview ()); }@Override Public void configurecontentnegotiation(Contentnegotiationconfigurer Configurer) {Configurer.favorpathextension (true). Ignoreacceptheader (true). ParameterName ("mediatype"). Defaultcontenttype (mediatype.text_html). MediaType ("HTML", mediatype.text_html). MediaType ("JSON", Mediatype.application_json); } }
The controller's code is as follows:
@Controller publicclass ExampleController { @RequestMapping("/example1") publicexample1() { new HashMap(); map.put("1""a"); map.put("2""b"); returnnew ModelAndView("example1", map); } }
Create a example1.jsp file in the web-inf/jsp directory, free of content. Now launch Tomcat, enter the following link in the browser: Http://localhost:8080/example1.json, the browser returns as follows:
In the browser input http://localhost:8080/example1 or http://localhost:8080/example1.html, return as follows:
Obviously, two times a different view parser is used, so what happens at the bottom? In the configuration we have two view resolvers registered:ContentNegotiatingViewResolver
AndInternalResourceViewResolver
, there is also a default view:MappingJackson2JsonView
。 When the controller finishes executing, it returns a Modelandview with the name example1 of the view. Return first will be given toContentNegotiatingViewResolver
For view resolution processing, andContentNegotiatingViewResolver
The view name example1 is given to all the viewresolver it holds to try to parse (only in this instanceInternalResourceViewResolver
), and then according to the requested mediatype, thenexample1.mediaType
(This is Example1.json and example1.html) as the view name for all the view resolvers to parse again, after two steps to resolve, you will get a bunch of candidatesList<View>
Plus the defaultMappingJackson2JsonView
, and finally based on the requested media type from the candidateList<View>
Select an optimal return, and the view is resolved. Now you can understand why the request link in the example above is added.json
And not.json
The results will be different. When added.json
Indicates that the requested media type is Mediatype.application_json, while theInternalResourceViewResolver
The contenttype of the parsed view is inconsistent with theMappingJackson2JsonView
ContentType match, so I chose theMappingJackson2JsonView
Returned as a view. When not added.json
When requested, the default media type is mediatype.text_html, so you use theInternalResourceViewResolver
The parsed view is returned as a value. I want to see here that you can already customize the view in general.
3. Addviewcontrollers (Viewcontrollerregistry Registry)
This method can easily implement a request-to-view mapping without writing a controller, for example:
@Override publicvoidaddViewControllers(ViewControllerRegistry registry){ registry.addViewController("/login").setViewName("login");
This is a direct return to the login page when accessing ${domain}/login.
4. Addresourcehandlers (Resourcehandlerregistry Registry)
This method is used specifically to register a handler to handle static resources, such as: Pictures, js,css, and so on. Example:
@Override publicvoidaddResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resource/**").addResourceLocations("/WEB-INF/static/"); }
When you request Http://localhost:8083/resource/1.png, you will return the/web-inf/static/1.png. Note : The static resources here are placed in the web-inf directory.
5. Configuredefaultservlethandling (Defaultservlethandlerconfigurer configurer)
Usage:
@Override public void Configuredefaultservlethandling (Defaultservlethandlerconfigurer configurer) {configurer.enable (); }
A default handler is registered: DefaultServletHttpRequestHandler
This handler is also used to handle static files, and it attempts to map /*
. When the Dispatcherservelt is mapped /
( /
and /*
is differentiated) and no appropriate handler is found to handle the request, it is handed over DefaultServletHttpRequestHandler
. Note : The static resources here are placed under the WEB root directory, not under web-inf .
Perhaps the description here is a bit difficult to understand (I feel the same), so simply give an example, for example: in the webroot directory There is a picture: 1.png
We know the Servelt specification in the Web root directory (webroot) files can be directly accessed, But because the DispatcherServlet
mapping path is configured: /
it intercepts almost all of the requests, resulting in 1.png
a lack of access, and registering one DefaultServletHttpRequestHandler
can solve the problem. In fact, it can be understood that DispatcherServlet
a feature that has been destroyed Servlet
(the file under the root directory can be accessed directly) DefaultServletHttpRequestHandler
is helpful to return to this feature.
Off Topic
Q: /
/*
What's the difference?
A: /
all URLs except JSPs are intercepted and /*
all URLs, including JSPs, are blocked. For example: Under Webroot There is a test.jsp, when DispatcherServlet
configuring the map /
, the browser input: http://localhost:8083/test.jsp This JSP is directly accessible, and does not pass DispatcherServlet
, and when DispatcherServlet
When the mapping is configured /*
, the request is DispatcherServlet
intercepted.
A schematic analysis of the Spring MVC request processing process (a)