回顾原生的Web应用
DispatcherServlet
-
ContextLoaderListener做了什么
-
DispatcherServlet创建一个子容器
-
HandlerMapping(处理器映射器)
-
HandlerAdapter(处理器适配器)
-
ViewResolver(视图解析器)
-
HandlerExceptionResolver(异常拦截器)
-
LocaleResolver(客户端地区解析)
-
ThemeResolver(切换主题)
-
MultipartResolver(多部件上传)
-
本章节总结
SpringMvc中的注解
控制器相关
参数映射
-
@PathVariable将url绑定到参数
-
参数映射的限制
-
@MatrixVariable矩阵变量
-
@RequestParam参数别名
-
@RequestHeader绑定请求头到参数
-
@CookieValue绑定cookie到参数
-
可自动加入ModelAndView的参数
-
@ModelAttribute(坑深尽量不要用)
回顾原生的Servlet
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <!-- 全局的配置参数,listener filter servlet 都可以获取参数 可以定义多个 --> <context-param> <param-name>Encoding</param-name> <param-value>UTF-8</param-value> </context-param> <!-- 过滤器 可以定义多个--> <filter> <filter-name>filter1</filter-name> <filter-class>filter.MyFilter</filter-class> </filter> <filter-mapping> <filter-name>filter1</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 监听器可以定义多个 --> <listener> <listener-class>listener.MyListener</listener-class> </listener> <!-- servlet可以定义多个 --> <servlet> <servlet-name>success</servlet-name> <servlet-class>servlet.UserServlet</servlet-class> <init-param> <param-name>key1</param-name> <param-value>value1</param-value> </init-param> <!-- 初始化加载顺序,会调用servlet的init方法 --> <load-on-startup>2</load-on-startup> </servlet> <servlet> <servlet-name>success2</servlet-name> <servlet-class>servlet.UserServlet2</servlet-class> <init-param> <param-name>key1</param-name> <param-value>value1</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <!-- servlet映射,跟每一个Servlet对应 --> <servlet-mapping> <servlet-name>success</servlet-name> <url-pattern>/success</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>success2</servlet-name> <url-pattern>/success2</url-pattern> </servlet-mapping> </web-app>
全局参数
web容器启动后,会创建一个ServletContext上下文对象,在web.xml中配置<context-param>会被上下文对象存储,任何可以获取ServletContext上下文的地方都可以调用getInitParameter("key");获取初始化参数,属于全局范围。
listener
package listener; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; public class MyListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent servletContextEvent) { System.out.println("glistener1 init"); ServletContext servletContext = servletContextEvent.getServletContext(); String value = servletContext.getInitParameter("Encoding"); System.out.println("当前设置编码" + value); } @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { System.out.println("listener1 dest"); } }
listener监听器分为三类,分别监听ServletContext域,HttpSession域,ServletRequest域。每一类又分成监听域对象的创建、销毁和域对象内的属性的变化。在web.xml中可以定义多个监听器。同类型的监听器按照加载顺序执行。
以上代码片段创建了一个servletContextListener用来监听Servlet上下文的创建和销毁。
filter
package filter;/* * @auther 顶风少年 * @mail dfsn19970313@foxmail.com * @date 2020-02-06 17:35 * @notify * @version 1.0 */ import javax.servlet.*; import java.io.IOException; public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("filter1 init"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { ServletContext servletContext = servletRequest.getServletContext(); String encoding = servletContext.getInitParameter("Encoding"); servletRequest.setCharacterEncoding(encoding); filterChain.doFilter(servletRequest,servletResponse); } @Override public void destroy() { System.out.println("filter1 destory"); } }
filter过滤器,在xml中通过<filter>和<filter-mapping>定义,两个为一组在mapping中定义要过滤的路径,匹配路径的都会进入filter。在filter类中有三个方法。分别是初始化(init),销毁(destroy)。doFilter,每一个匹配路径符合的都会进入doFilter(),如果方法内部业务逻辑正确,则可以使用FilterChain.doFilter(req,resp);表示放行。多个filter会组成过滤器链,当一个第一个放行后,则进入第二个。全部通过则会到达servlet,一个不通过,则不通过。
servlet
package servlet;/* * @auther 顶风少年 * @mail dfsn19970313@foxmail.com * @date 2020-02-06 12:33 * @notify * @version 1.0 */ import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.Enumeration; public class UserServlet extends HttpServlet { @Override public void init() throws ServletException { System.out.println("servlet1"); super.init(); } @Override public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8"); PrintWriter out = resp.getWriter(); out.println("success"); out.close(); } }
servlet服务,同样的在web.xml中通过<servlet>和<servlet-mapping>,每一个servletClass需要实现HttpServlet,类HttpServlet默认实现了各种请求方式的实现。我们需要根据自身需要覆盖对应的请求方式。配置<load-on-startup>1</load-on-startup>代表该Servlet的加载顺序,ServletContext创建后,会对设置了该标签的Servlet进行初始化,负值不初始化,值越小越先被初始化。所谓初始化就是调用Servlet的init()
DispatcherServlet
ContextLoaderListener做了什么
在这里我们跟踪源码,主要找到listener创建ApplicationContext和创建过程中在哪里加载的配置文件。
<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationconfig.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
首先我们在web.xml配置了一个监听器ContextLoaderListener,另外配置了全局参数contextConfigLocation
public class ContextLoaderListener extends ContextLoader implements ServletContextListener { public ContextLoaderListener() { } public ContextLoaderListener(WebApplicationContext context) { super(context); } public void contextInitialized(ServletContextEvent event) { this.initWebApplicationContext(event.getServletContext()); } public void contextDestroyed(ServletContextEvent event) { this.closeWebApplicationContext(event.getServletContext()); ContextCleanupListener.cleanupAttributes(event.getServletContext()); } }
在全局配置参数的value中我指向了一个Spring配置文件,并且添加了一个bean。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="pojo.Person" id="person"></bean> </beans>
该ContextLoaderListener实现了ServletContextListener,那他的功能就是监听ServletContext创建和销毁。其次,它继承了ContextLoader,该类是Spring的类。我们先来看看contextInitialized()方法在ServletContext创建时都做了什么。
DispatcherServlet创建一个子容器
<servlet> <servlet-name>app</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>app</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <context:component-scan base-package="com.datang"/> </beans>
在这里我们跟踪源码,查看DispatcherServlet创建子容器的,和加载配置文件的源码。前边我们说过,Servlet初始化会调用init()方法。而DispatcherServlet也继承自HttpServlet。
HandlerMapping
HandlerMapping的作用就是解析请求链接,然后根据请求链接找到执行这个请求的类(HandlerMapping所说的handler,也就是我们写的Controller或是Action)。
BeanNameUrlHandlerMapping
BeanNameUrlHandlerMapping处理器映射器,处理器必须实现Controller接口,并且将该类配置成bean,bean的id需要是/开头,标识它是一个处理器。
package com.datang.controller;/* * @auther 顶风少年 * @mail dfsn19970313@foxmail.com * @date 2020-02-07 17:44 * @notify * @version 1.0 */ import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class BeanNameUrlHandlerMappingController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { System.out.println("我是根据BeanNameUrlHandlerMapping找到的controller,但是显然的,我是错误的,因为我返回的是null"); return null; } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean id="/beannameurlhandlermappingcontroller" class="com.datang.controller.BeanNameUrlHandlerMappingController"></bean> <context:component-scan base-package="com.datang"/> </beans>
RequestMappingHandlerMapping
RequestMappingHandlerMapping处理器映射器,需要使用@Controller注册bean然后对方法上带有@RequestMapping注解的方法,注册为处理器映射器。
package com.datang.controller;/* * @auther 顶风少年 * @mail dfsn19970313@foxmail.com * @date 2020-02-07 18:04 * @notify * @version 1.0 */ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; @Controller public class RequestMappingHandlerMappingController { @RequestMapping(value = "requestmappinghandlermappingcontroller",method = RequestMethod.GET) public ModelAndView handler() { System.out.println("我是根据RequestMappingHandlerMapping找到的controller,但是显然的,我是错误的,因为我返回的是null"); return null; } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 根据beanName找到处理器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean id="/beannameurlhandlermappingcontroller" class="com.datang.controller.BeanNameUrlHandlerMappingController"></bean> <!-- 根据@RequestMapping 找到处理器--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <context:component-scan base-package="com.datang"/> </beans>
HandlerAdapter
HandlerAdapter的作用是,执行handlerMapping找到的处理器。处理器有多种,显然的每一种的处理器所执行的方法都不一样。比如上边的两种,继承自Controller的处理器方法固定的是handleRequest()而使用@RequestMapping注解的则方法名不同。所以处理器适配器的存在是有必要的。
SimpleControllerHandlerAdapter
SimpleControllerHandlerAdapter这个处理器适配器是配合BeanNameUrlHandlerMapping处理器映射器使用的。定义了SimpleControllerHandlerAdapter便不会有其他的适配器。这里请求beannameurlhandlermappingcontroller会成功,但是请求requestmappinghandlermappingcontroller是不成功的。<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 根据beanName找到处理器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean id="/beannameurlhandlermappingcontroller" class="com.datang.controller.BeanNameUrlHandlerMappingController"></bean> <!-- 根据@RequestMapping 找到处理器--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!-- 配合BeanNameUrlHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <context:component-scan base-package="com.datang"/> </beans>
RequestMappingHandlerAdapter
RequestMappingHandlerAdapter这个处理器适配器是配合RequestMappingHandlerMapping处理器映射器使用的。这次就可以正确访问requestmappinghandlermappingcontroller。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 根据beanName找到处理器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean id="/beannameurlhandlermappingcontroller" class="com.datang.controller.BeanNameUrlHandlerMappingController"></bean> <!-- 根据@RequestMapping 找到处理器--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!-- 配合BeanNameUrlHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!-- 配合RequestMappingHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> <context:component-scan base-package="com.datang"/> </beans>
ViewResolver
InternalResourceViewResolver
根据Controller返回的逻辑视图名,寻找物理视图。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 根据beanName找到处理器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean id="/beannameurlhandlermappingcontroller" class="com.datang.controller.BeanNameUrlHandlerMappingController"></bean> <!-- 根据@RequestMapping 找到处理器--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!-- 配合BeanNameUrlHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!-- 配合RequestMappingHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> <!-- 视图解析器,配置视图的前缀和后缀 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsps/"/> <property name="suffix" value=".jsp"/> </bean> <context:component-scan base-package="com.datang"/> </beans>
package com.datang.controller;/* * @auther 顶风少年 * @mail dfsn19970313@foxmail.com * @date 2020-02-07 21:09 * @notify * @version 1.0 */ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; @Controller public class ReturnJsp { @RequestMapping(value = "returnjsp", method = RequestMethod.GET) public String handler() { return "page1"; } }
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>我是page1</h1> </body> </html>
定义多个视图解析器(源码解析)
我们可以定义多个视图解析器,属性order规定视图解析器的优先级。DispatcherServlet试图从所有的视图解析器中匹配视图,如果匹配成功则不继续匹配。那么就让我们来碰碰壁吧。可以看出第二个路径出错了,问题就在于,它好像根本没有走我们的第二个视图解析器呀!看源码吧。(不想看源码,直接看解决办法。)
package com.datang.controller;/* * @auther 顶风少年 * @mail dfsn19970313@foxmail.com * @date 2020-02-07 21:09 * @notify * @version 1.0 */ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.view.InternalResourceView; @Controller public class ReturnJsp { @RequestMapping(value = "returnjsp", method = RequestMethod.GET) public String handler() { return "page1"; } @RequestMapping(value = "returnjsp2", method = RequestMethod.GET) public String handler2() { return "page2"; } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 根据beanName找到处理器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean id="/beannameurlhandlermappingcontroller" class="com.datang.controller.BeanNameUrlHandlerMappingController"></bean> <!-- 根据@RequestMapping 找到处理器--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!-- 配合BeanNameUrlHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!-- 配合RequestMappingHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> <!-- 视图解析器,配置视图的前缀和后缀 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsps/"/> <property name="suffix" value=".jsp"/> <property name="order" value="1"/> </bean> <!-- 第二个视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsps2/"/> <property name="suffix" value=".jsp"/> <property name="order" value="2"/> </bean> <context:component-scan base-package="com.datang"/> </beans>
入口类,就从DispatcherServlet开始(因为我已经debug了好久才找到从这么看最直观!!!)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 根据beanName找到处理器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean id="/beannameurlhandlermappingcontroller" class="com.datang.controller.BeanNameUrlHandlerMappingController"></bean> <!-- 根据@RequestMapping 找到处理器--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!-- 配合BeanNameUrlHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!-- 配合RequestMappingHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> <!-- 视图解析器,配置视图的前缀和后缀 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 使用自己的viewClass --> <property name="viewClass" value="com.datang.view.MyInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsps/"/> <property name="suffix" value=".jsp"/> <property name="order" value="1"/> </bean> <!-- 第二个视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 使用自己的viewClass --> <property name="viewClass" value="com.datang.view.MyInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsps2/"/> <property name="suffix" value=".jsp"/> <property name="order" value="2"/> </bean> <context:component-scan base-package="com.datang"/> </beans>
package com.datang.view;/* * @auther 顶风少年 * @mail dfsn19970313@foxmail.com * @date 2020-02-08 14:49 * @notify * @version 1.0 */ import org.springframework.web.servlet.view.InternalResourceView; import java.io.File; import java.util.Locale; public class MyInternalResourceView extends InternalResourceView { @Override public boolean checkResource(Locale locale) throws Exception { //这里,super.getUrl就是prefix+viewName+suffix File file = new File(this.getServletContext().getRealPath("/") + super.getUrl()); // 判断该页面是否存在 return file.exists(); } }
转发重定向
//转发到returnjsp @RequestMapping(value = "returnjsp3", method = RequestMethod.GET) public String handler3() { return "forward:returnjsp"; } //重定向到returnjsp @RequestMapping(value = "returnjsp4", method = RequestMethod.GET) public String handler4() { return "redirect:returnjsp"; }
ResourceBundleViewResolver
Controller中返回ModelAndView,设置view的名称。ResourceBundleViewResolver根据view名称查询views下的路径配置。
@RequestMapping(value = "returnjsp9", method = RequestMethod.GET) public ModelAndView handler9() { return new ModelAndView("user1"); }
user1.(class)=org.springframework.web.servlet.view.InternalResourceView user1.url=/WEB-INF/jsps/page3.jsp
<!-- 根据view名称匹配资源路径 --> <bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver"> <property name="order" value="3"/> <property name="basename" value="views"/> </bean>
HandlerExceptionResolver
handlerExcetpionResolver用于处理异常,可以同时注入多个异常处理方案,指定order属性,值越小,优先级越高。
SimpleMappingExceptionResolver
SimpleMappingExceptionResolver会拦截住controller中抛出的异常,分发到对应的异常页面,并且向异常页面传递异常信息。注意了!如果是页面找不到的异常不会被拦截。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 根据beanName找到处理器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean id="/beannameurlhandlermappingcontroller" class="com.datang.controller.BeanNameUrlHandlerMappingController"></bean> <!-- 根据@RequestMapping 找到处理器--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!-- 配合BeanNameUrlHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!-- 配合RequestMappingHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> <!-- 视图解析器,配置视图的前缀和后缀 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 使用自己的viewClass --> <property name="viewClass" value="com.datang.view.MyInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsps/"/> <property name="suffix" value=".jsp"/> <property name="order" value="1"/> </bean> <!-- 第二个视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 使用自己的viewClass --> <property name="viewClass" value="com.datang.view.MyInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsps2/"/> <property name="suffix" value=".jsp"/> <property name="order" value="2"/> </bean> <!-- SimpleMappingExceptionResolver --> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 为所有的异常定义默认的异常处理页面,exceptionMappings未定义的异常使用本默认配置 --> <property name="defaultErrorView" value="error"></property> <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception --> <property name="exceptionAttribute" value="ex"></property> <!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常页文件名作为值, 将不同的异常映射到不同的页面上。 --> <property name="exceptionMappings"> <props> <prop key="java.io.IOException">ioerror</prop> </props> </property> <!-- 返回状态码 --> <property name="defaultStatusCode" value="250"/> </bean> <context:component-scan base-package="com.datang"/> </beans>
//数学异常 @RequestMapping(value = "returnjsp5", method = RequestMethod.GET) public String handler5() { int i = 1 / 0; return "xixi"; } //IO异常 @RequestMapping(value = "returnjsp6", method = RequestMethod.GET) public String handler6() throws IOException { FileInputStream fileInputStream = new FileInputStream(""); return "xixi"; } //找不到页面 @RequestMapping(value = "returnjsp7", method = RequestMethod.GET) public String handler7() { return "xixi"; }
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>SimpleMappingExceptionResolver的异常页面${requestScope.ex}</h1> </body> </html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>SimpleMappingExceptionResolver的IO异常页面${requestScope.ex}</h1> </body> </html>
ResponseStatusExceptionResolver
ResponseStatusExceptionResolver拦截使用了@ResponseStatus的自定义异常。在自定义异常中,可以规定返回状态,错误原因。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 根据beanName找到处理器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean id="/beannameurlhandlermappingcontroller" class="com.datang.controller.BeanNameUrlHandlerMappingController"></bean> <!-- 根据@RequestMapping 找到处理器--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!-- 配合BeanNameUrlHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!-- 配合RequestMappingHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> <!-- 视图解析器,配置视图的前缀和后缀 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 使用自己的viewClass --> <property name="viewClass" value="com.datang.view.MyInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsps/"/> <property name="suffix" value=".jsp"/> <property name="order" value="1"/> </bean> <!-- 第二个视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 使用自己的viewClass --> <property name="viewClass" value="com.datang.view.MyInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsps2/"/> <property name="suffix" value=".jsp"/> <property name="order" value="2"/> </bean> <!-- ResponseStatusExceptionResolver --> <bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver"> <!-- 优先级--> <property name="order" value="1"/> </bean> <!-- SimpleMappingExceptionResolver --> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 优先级--> <property name="order" value="2"/> <!-- 为所有的异常定义默认的异常处理页面,exceptionMappings未定义的异常使用本默认配置 --> <property name="defaultErrorView" value="error"></property> <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception --> <property name="exceptionAttribute" value="ex"></property> <!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常页文件名作为值, 将不同的异常映射到不同的页面上。 --> <property name="exceptionMappings"> <props> <prop key="java.io.IOException">ioerror</prop> </props> </property> <!-- 返回状态码 --> <property name="defaultStatusCode" value="250"/> </bean> <context:component-scan base-package="com.datang"/> </beans>
//ResponseStatusExceptionResolver @RequestMapping(value = "returnjsp8", method = RequestMethod.GET) public String handler8() { throw new MyException1(); }
package com.datang.exception;/* * @auther 顶风少年 * @mail dfsn19970313@foxmail.com * @date 2020-02-09 13:31 * @notify * @version 1.0 */ import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(value = HttpStatus.FORBIDDEN,reason = "我就是测试下异常,没别的意思") public class MyException1 extends RuntimeException { }
ExceptionHandlerExceptionResolver
ExceptionHandlerExceptionResolver用于全局处理异常,将异常放到一个被@ControllerAdvice注释的类上,该类的每个带有@ExceptionHandler的方法都关联一个异常类,其他Controller中抛出的异常如果匹配则走该异常处理。别标注@ExceptionHandler的方法如果在@Controller中,表示该异常处只在本类中有效。
package com.datang.exception;/* * @auther 顶风少年 * @mail dfsn19970313@foxmail.com * @date 2020-02-09 13:31 * @notify * @version 1.0 */ import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import java.io.IOException; @ControllerAdvice public class MyException2 { @ExceptionHandler({NullPointerException.class}) public String exception(NullPointerException e) { System.out.println(e.getMessage()); e.printStackTrace(); return "空指针异常了"; } }
//ResponseStatusExceptionResolver @RequestMapping(value = "returnjsp8", method = RequestMethod.GET) public String handler8() { throw new NullPointerException(); }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 根据beanName找到处理器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean id="/beannameurlhandlermappingcontroller" class="com.datang.controller.BeanNameUrlHandlerMappingController"></bean> <!-- 根据@RequestMapping 找到处理器--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!-- 配合BeanNameUrlHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!-- 配合RequestMappingHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> <!-- 视图解析器,配置视图的前缀和后缀 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 使用自己的viewClass --> <property name="viewClass" value="com.datang.view.MyInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsps/"/> <property name="suffix" value=".jsp"/> <property name="order" value="1"/> </bean> <!-- 第二个视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 使用自己的viewClass --> <property name="viewClass" value="com.datang.view.MyInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsps2/"/> <property name="suffix" value=".jsp"/> <property name="order" value="2"/> </bean> <!-- ExceptionHandlerExceptionResolver --> <bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"> <!-- 优先级--> <property name="order" value="0"/> </bean> <!-- ResponseStatusExceptionResolver --> <bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver"> <!-- 优先级--> <property name="order" value="1"/> </bean> <!-- SimpleMappingExceptionResolver --> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 优先级--> <property name="order" value="2"/> <!-- 为所有的异常定义默认的异常处理页面,exceptionMappings未定义的异常使用本默认配置 --> <property name="defaultErrorView" value="error"></property> <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception --> <property name="exceptionAttribute" value="ex"></property> <!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常页文件名作为值, 将不同的异常映射到不同的页面上。 --> <property name="exceptionMappings"> <props> <prop key="java.io.IOException">ioerror</prop> </props> </property> <!-- 返回状态码 --> <property name="defaultStatusCode" value="250"/> </bean> <context:component-scan base-package="com.datang"/> </beans>
LocaleResolver
LocaleResolver,获取客户端时区和地区。
@RequestMapping(value = "returnjsp10", method = RequestMethod.GET) public String handler10(Locale locale) { return "page1"; }
<bean class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver"></bean>
CookieLocaleResolver
先访问returnjsp11设置cookie,注意cookie的key需要和xml中设置一样,值的格式也是固定的,前半部分是地区,这个地区不能瞎搞,必须是Locale枚举类定义好的值,而后半部分也是固定的,我就知道一个GMT+8东八区。。如果不要时区,则/不要后边也不要。这里有一点特别需要注意!CookieLocaleResolver的id必须设置,值必须是localeResolver。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 映射器 根据beanName找到处理器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean id="/beannameurlhandlermappingcontroller" class="com.datang.controller.BeanNameUrlHandlerMappingController"></bean> <!-- 映射器 根据@RequestMapping 找到处理器--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!-- 处理器适配器 配合BeanNameUrlHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!-- 处理器适配器 配合RequestMappingHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> <!-- 视图解析器,配置视图的前缀和后缀 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 使用自己的viewClass --> <property name="viewClass" value="com.datang.view.MyInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsps/"/> <property name="suffix" value=".jsp"/> <property name="order" value="1"/> </bean> <!-- 第二个视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 使用自己的viewClass --> <property name="viewClass" value="com.datang.view.MyInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsps2/"/> <property name="suffix" value=".jsp"/> <property name="order" value="2"/> </bean> <!-- 根据view名称匹配资源路径 --> <bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver"> <property name="order" value="3"/> <property name="basename" value="views"/> </bean> <!-- ExceptionHandlerExceptionResolver 配合@ControllerAdvice和@ExceptionHandler使用 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"> <!-- 优先级--> <property name="order" value="0"/> </bean> <!-- ResponseStatusExceptionResolver 配合@ResponseStatus使用 --> <bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver"> <!-- 优先级--> <property name="order" value="1"/> </bean> <!-- SimpleMappingExceptionResolver 规定异常页面--> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 优先级--> <property name="order" value="2"/> <!-- 为所有的异常定义默认的异常处理页面,exceptionMappings未定义的异常使用本默认配置 --> <property name="defaultErrorView" value="error"></property> <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception --> <property name="exceptionAttribute" value="ex"></property> <!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常页文件名作为值, 将不同的异常映射到不同的页面上。 --> <property name="exceptionMappings"> <props> <prop key="java.io.IOException">ioerror</prop> </props> </property> <!-- 返回状态码 --> <property name="defaultStatusCode" value="250"/> </bean> <!-- 从cookie中读取cookieName的对应值。 --> <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver"> <property name="cookieName" value="localeCoolie"/> </bean> <bean class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver"></bean> <context:component-scan base-package="com.datang"/> </beans>
@RequestMapping(value = "returnjsp10", method = RequestMethod.GET) public String handler10(Locale locale, TimeZone timeZone) { return "page1"; } @RequestMapping(value = "returnjsp11", method = RequestMethod.GET) public String handler11(HttpServletResponse httpResponse) { Cookie cookie = new Cookie("localeCoolie", "en_US/GMT+8"); cookie.setMaxAge(120); httpResponse.addCookie(cookie); return "page1"; }
SessionLocaleResolver
和cookie的用法类似,但是细节上有很大的差别。localeAttributeName和timeZoneAttributeName分别设置两个session的key,注意,值必须是对象。不能是字符串。这里被坑惨了。<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 映射器 根据beanName找到处理器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean id="/beannameurlhandlermappingcontroller" class="com.datang.controller.BeanNameUrlHandlerMappingController"></bean> <!-- 映射器 根据@RequestMapping 找到处理器--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!-- 处理器适配器 配合BeanNameUrlHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!-- 处理器适配器 配合RequestMappingHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> <!-- 视图解析器,配置视图的前缀和后缀 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 使用自己的viewClass --> <property name="viewClass" value="com.datang.view.MyInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsps/"/> <property name="suffix" value=".jsp"/> <property name="order" value="1"/> </bean> <!-- 第二个视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 使用自己的viewClass --> <property name="viewClass" value="com.datang.view.MyInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsps2/"/> <property name="suffix" value=".jsp"/> <property name="order" value="2"/> </bean> <!-- 根据view名称匹配资源路径 --> <bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver"> <property name="order" value="3"/> <property name="basename" value="views"/> </bean> <!-- ExceptionHandlerExceptionResolver 配合@ControllerAdvice和@ExceptionHandler使用 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"> <!-- 优先级--> <property name="order" value="0"/> </bean> <!-- ResponseStatusExceptionResolver 配合@ResponseStatus使用 --> <bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver"> <!-- 优先级--> <property name="order" value="1"/> </bean> <!-- SimpleMappingExceptionResolver 规定异常页面--> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 优先级--> <property name="order" value="2"/> <!-- 为所有的异常定义默认的异常处理页面,exceptionMappings未定义的异常使用本默认配置 --> <property name="defaultErrorView" value="error"></property> <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception --> <property name="exceptionAttribute" value="ex"></property> <!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常页文件名作为值, 将不同的异常映射到不同的页面上。 --> <property name="exceptionMappings"> <props> <prop key="java.io.IOException">ioerror</prop> </props> </property> <!-- 返回状态码 --> <property name="defaultStatusCode" value="250"/> </bean> <!-- 从cookie中读取cookieName的对应值。 --> <!-- <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">--> <!-- <property name="cookieName" value="localeCoolie"/>--> <!-- </bean>--> <!-- 从客户端的accept中获取地区 --> <bean class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver"></bean> <!-- 从session中获取时区和地区 --> <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"> <property name="localeAttributeName" value="sessionLocale"/> <property name="timeZoneAttributeName" value="sessionZone"/> </bean> <context:component-scan base-package="com.datang"/> </beans>
@RequestMapping(value = "returnjsp12", method = RequestMethod.GET) public String handler12(HttpServletRequest request) { HttpSession session = request.getSession(); Locale locale = new Locale("en_US"); session.setAttribute("sessionLocale",locale); //session.setAttribute("sessionLocale","en_US"); TimeZone timeZone = new SimpleTimeZone(8,"GMT"); session.setAttribute("sessionZone",timeZone); //session.setAttribute("sessionZone","GMT+8"); return "page1"; }
@RequestMapping(value = "returnjsp10", method = RequestMethod.GET) public String handler10(Locale locale, TimeZone timeZone) { return "page1"; }
ResourceBundleViewResolver和LocaleResolver配合做国际化
LocaleResolver前边我们说过,根据视图名字,从配置文件中找到对应的视图路径。做国际化也很简单,除了视图我们在设置一个模型,模型设置Locale,而Locale就是从参数,也就是ResourceBundleViewResolver获取。然后根据不同的地区,设置多个配置文件。下边代码片段,为了省事我用的AcceptHeaderLocaleResolver从请求头获取地区信息。
// ResourceBundleViewResolver配合时区,做国际化 @RequestMapping(value = "returnjsp13", method = RequestMethod.GET) public ModelAndView handler13(Locale locale) { ModelAndView modelAndView = new ModelAndView("user2"); modelAndView.addObject("locale", locale); return modelAndView; }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 映射器 根据beanName找到处理器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean id="/beannameurlhandlermappingcontroller" class="com.datang.controller.BeanNameUrlHandlerMappingController"></bean> <!-- 映射器 根据@RequestMapping 找到处理器--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!-- 处理器适配器 配合BeanNameUrlHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!-- 处理器适配器 配合RequestMappingHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> <!-- 视图解析器,配置视图的前缀和后缀 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 使用自己的viewClass --> <property name="viewClass" value="com.datang.view.MyInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsps/"/> <property name="suffix" value=".jsp"/> <property name="order" value="1"/> </bean> <!-- 第二个视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 使用自己的viewClass --> <property name="viewClass" value="com.datang.view.MyInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsps2/"/> <property name="suffix" value=".jsp"/> <property name="order" value="2"/> </bean> <!-- 根据view名称匹配资源路径 --> <bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver"> <property name="order" value="3"/> <property name="basename" value="views"/> </bean> <!-- ExceptionHandlerExceptionResolver 配合@ControllerAdvice和@ExceptionHandler使用 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"> <!-- 优先级--> <property name="order" value="0"/> </bean> <!-- ResponseStatusExceptionResolver 配合@ResponseStatus使用 --> <bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver"> <!-- 优先级--> <property name="order" value="1"/> </bean> <!-- SimpleMappingExceptionResolver 规定异常页面--> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 优先级--> <property name="order" value="2"/> <!-- 为所有的异常定义默认的异常处理页面,exceptionMappings未定义的异常使用本默认配置 --> <property name="defaultErrorView" value="error"></property> <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception --> <property name="exceptionAttribute" value="ex"></property> <!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常页文件名作为值, 将不同的异常映射到不同的页面上。 --> <property name="exceptionMappings"> <props> <prop key="java.io.IOException">ioerror</prop> </props> </property> <!-- 返回状态码 --> <property name="defaultStatusCode" value="250"/> </bean> <!-- 从cookie中读取cookieName的对应值。 --> <!-- <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">--> <!-- <property name="cookieName" value="localeCoolie"/>--> <!-- </bean>--> <!-- 从客户端的accept中获取地区 --> <bean class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver"></bean> <!-- 从session中获取时区和地区 --> <!-- <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">--> <!-- <property name="localeAttributeName" value="sessionLocale"/>--> <!-- <property name="timeZoneAttributeName" value="sessionZone"/>--> <!-- </bean>--> <context:component-scan base-package="com.datang"/> </beans>
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>我是外国版本</h1> </body> </html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>我是中国版本</h1> </body> </html>
ThemeResolver
ThemeResolver对主题做切换。
CookieThemeResolver
通过cookie切换主题。ResourceBundleThemeSource设置主题文件所在文件夹,注意文件夹一定要在classe下。basenamePrefix需要带 . 不带会报错的。CookieThemeResolver通过cookie设置主题文件。从cookieName这个cookie
中取主题文件名,如果没有对应的cookie则主题文件名为defaultThemeName的值。在jsp中必须引入spring标签库。然后使用正确的格式找配置参数。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 映射器 根据beanName找到处理器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean id="/beannameurlhandlermappingcontroller" class="com.datang.controller.BeanNameUrlHandlerMappingController"></bean> <!-- 映射器 根据@RequestMapping 找到处理器--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!-- 处理器适配器 配合BeanNameUrlHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!-- 处理器适配器 配合RequestMappingHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> <!-- 视图解析器,配置视图的前缀和后缀 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 使用自己的viewClass --> <property name="viewClass" value="com.datang.view.MyInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsps/"/> <property name="suffix" value=".jsp"/> <property name="order" value="1"/> </bean> <!-- 第二个视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 使用自己的viewClass --> <property name="viewClass" value="com.datang.view.MyInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsps2/"/> <property name="suffix" value=".jsp"/> <property name="order" value="2"/> </bean> <!-- 根据view名称匹配资源路径 --> <bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver"> <property name="order" value="3"/> <property name="basename" value="views"/> </bean> <!-- ExceptionHandlerExceptionResolver 配合@ControllerAdvice和@ExceptionHandler使用 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"> <!-- 优先级--> <property name="order" value="0"/> </bean> <!-- ResponseStatusExceptionResolver 配合@ResponseStatus使用 --> <bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver"> <!-- 优先级--> <property name="order" value="1"/> </bean> <!-- SimpleMappingExceptionResolver 规定异常页面--> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 优先级--> <property name="order" value="2"/> <!-- 为所有的异常定义默认的异常处理页面,exceptionMappings未定义的异常使用本默认配置 --> <property name="defaultErrorView" value="error"></property> <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception --> <property name="exceptionAttribute" value="ex"></property> <!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常页文件名作为值, 将不同的异常映射到不同的页面上。 --> <property name="exceptionMappings"> <props> <prop key="java.io.IOException">ioerror</prop> </props> </property> <!-- 返回状态码 --> <property name="defaultStatusCode" value="250"/> </bean> <!-- 从cookie中读取cookieName的对应值。--> <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver"> <property name="cookieName" value="localeCoolie"/> </bean> <!-- 从客户端的accept中获取地区 --> <bean class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver"></bean> <!-- 从session中获取时区和地区 --> <!-- <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">--> <!-- <property name="localeAttributeName" value="sessionLocale"/>--> <!-- <property name="timeZoneAttributeName" value="sessionZone"/>--> <!-- </bean>--> <!-- cookie设置css样式 --> <bean id="themeResolver" class="org.springframework.web.servlet.theme.CookieThemeResolver"> <property name="defaultThemeName" value="theme1"/> <property name="cookieName" value="theme"/> </bean> <!-- 样式路径 --> <bean id="themeSource" class="org.springframework.ui.context.support.ResourceBundleThemeSource"> <property name="basenamePrefix" value="theme."/> </bean> <context:component-scan base-package="com.datang"/> </beans>
//设置主题 theme1 theme2 en_US zh_CN @RequestMapping(value = "returnjsp14", method = RequestMethod.GET) public String handler14(String t, String l, HttpServletResponse httpResponse) { //在本类设置cookie Cookie cookie = new Cookie("theme", t); cookie.setMaxAge(120); httpResponse.addCookie(cookie); if (l != null && !l.equals("")) { Cookie cookie2 = new Cookie("localeCoolie", l); cookie2.setMaxAge(120); httpResponse.addCookie(cookie2); } return "page1"; } //设置主题 @RequestMapping(value = "returnjsp15", method = RequestMethod.GET) public String handler15() { return "page6"; }
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <span style="color:<spring:theme code='color'/>">我是什么颜色</span> </body> </html>
# theme1.properties
color=red
# theme2.properties
color=deeppink
使用CookieThemeResolver做国际化主题
做国际化很简单,只要我们使用CookieLocaleResolver引入CookieLocale,设置对应地区Locale。同时的,要引入对应的国家化配置文件。
# theme1_en_US
color=green
# theme1_zh_CN
color=blue
# theme2_en_US
color=aquamarine
# theme2_zh_CN
color=chartreuse
MultipartResolver
MultipartResolver负责文件上传。
CommonsMultipartResolver
CommonsMultipartResolver基于Commons FileUpload需要引入对应jar包。
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 映射器 根据beanName找到处理器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean id="/beannameurlhandlermappingcontroller" class="com.datang.controller.BeanNameUrlHandlerMappingController"></bean> <!-- 映射器 根据@RequestMapping 找到处理器--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!-- 处理器适配器 配合BeanNameUrlHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!-- 处理器适配器 配合RequestMappingHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> <!-- 视图解析器,配置视图的前缀和后缀 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 使用自己的viewClass --> <property name="viewClass" value="com.datang.view.MyInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsps/"/> <property name="suffix" value=".jsp"/> <property name="order" value="1"/> </bean> <!-- 第二个视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 使用自己的viewClass --> <property name="viewClass" value="com.datang.view.MyInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsps2/"/> <property name="suffix" value=".jsp"/> <property name="order" value="2"/> </bean> <!-- 根据view名称匹配资源路径 --> <bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver"> <property name="order" value="3"/> <property name="basename" value="views"/> </bean> <!-- ExceptionHandlerExceptionResolver 配合@ControllerAdvice和@ExceptionHandler使用 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"> <!-- 优先级--> <property name="order" value="0"/> </bean> <!-- ResponseStatusExceptionResolver 配合@ResponseStatus使用 --> <bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver"> <!-- 优先级--> <property name="order" value="1"/> </bean> <!-- SimpleMappingExceptionResolver 规定异常页面--> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 优先级--> <property name="order" value="2"/> <!-- 为所有的异常定义默认的异常处理页面,exceptionMappings未定义的异常使用本默认配置 --> <property name="defaultErrorView" value="error"></property> <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception --> <property name="exceptionAttribute" value="ex"></property> <!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常页文件名作为值, 将不同的异常映射到不同的页面上。 --> <property name="exceptionMappings"> <props> <prop key="java.io.IOException">ioerror</prop> </props> </property> <!-- 返回状态码 --> <property name="defaultStatusCode" value="250"/> </bean> <!-- 从cookie中读取cookieName的对应值。--> <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver"> <property name="cookieName" value="localeCoolie"/> </bean> <!-- 从客户端的accept中获取地区 --> <bean class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver"></bean> <!-- 从session中获取时区和地区 --> <!-- <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">--> <!-- <property name="localeAttributeName" value="sessionLocale"/>--> <!-- <property name="timeZoneAttributeName" value="sessionZone"/>--> <!-- </bean>--> <!-- cookie设置css样式 --> <bean id="themeResolver" class="org.springframework.web.servlet.theme.CookieThemeResolver"> <property name="defaultThemeName" value="theme1"/> <property name="cookieName" value="theme"/> </bean> <!-- 样式路径 --> <bean id="themeSource" class="org.springframework.ui.context.support.ResourceBundleThemeSource"> <property name="basenamePrefix" value="theme."/> </bean> <!-- 文件上传 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean> <context:component-scan base-package="com.datang"/> </beans>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <form enctype="multipart/form-data" action="returnjsp17" method="post"> <input type="file" name="file"> <input type="submit" value="提交"> </form> </body> </html>
//返回一个带上传组件的视图 @RequestMapping(value = "returnjsp16", method = RequestMethod.GET) public String handler16() { return "page7"; } @RequestMapping(value = "returnjsp17", method = RequestMethod.POST) public String handler17(MultipartFile file) { return "page1"; }
本章节总结
这一个章节围绕DispatcherServlet这个类。DispatcherServlet是一个被Spring包装好的Servlet,它把全部的请求都接收到DispatcherServlet,然后通过HandlerMapping(处理器映射器)去寻找对应的controller,当寻找到controller后,不会直接执行而是寻找能够处理controller的HandlerAdapter(处理器适配器),通过HandlerAdapter去执行controller,执行完毕后,拿到ModelAndView并且返回一个ViewResolver(视图解析器),ModelAndView负责将View的逻辑视图找到对应的物理视图,并将Model填充到View中,并返回。如果在Controller处理过程中出现错误,则交给HandlerExceptionResolver(异常解析器)处理。除此之外SpringMvc对处理国际化也有对应的方式。LocaleResolver(地区转换器)通过请求头或cookie或session获取客户端地区和时区,在配合ViewResolver找到对应地区的视图。ThemeResolver(主题解析器)可以根据不同的选择或者地区给页面渲染不同的主题。最后在处理多部件参数时使用MultipartResolver有效的将请求中的文件参数绑定到controller的参数上。其实在默认情况下,如果我们不知道选择什么样的配置,也完全不必担心。SpringMvc默认的会加载默认配置。
SpringMvc中的注解
控制器相关
@Controller
使用@Controller的注解的类不需要实现Controller接口便可成为处理器类。注意不能使用@Component代替。
@RequestMapping
RequestMappingHandlerMapping会找到所有被@RequestMapping注解的方法,匹配映射。也可以注解到类上会拼接映射路劲。
@ResponseBody
使用该注解意味着直接将返回值填充到Response的响应体中,因此被@ResponseBody注解的方法,不会再走视图解析器。
package com.datang.controller;/* * @auther 顶风少年 * @mail dfsn19970313@foxmail.com * @date 2020-02-11 09:41 * @notify * @version 1.0 */ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; @Controller @RequestMapping(value = "anno/") public class Anno { @RequestMapping(value = "g1",method = RequestMethod.GET) @ResponseBody public String get1(){ return "haha"; } }
@RestController
@Controller和@ResponseBody的结合体。被@RestController注释的类是处理器类,类中的方法如果是处理器方法则返回值都直接填充到Response响应体中。
package com.datang.controller;/* * @auther 顶风少年 * @mail dfsn19970313@foxmail.com * @date 2020-02-11 09:41 * @notify * @version 1.0 */ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping(value = "rest/") public class RestAnno { @RequestMapping(value = "g1",method = RequestMethod.GET) public String get1(){ return "haha"; } }
@RequestMapping的变体
把RequestMapping加到方法上需要method参数对请求进行筛选的操作是必要的。于是Spring扩展了一下注解专门针对不同的请求方式设计不同的注解。在这些注解上我们依然可以对headers等其他的条件进行筛选。
@GetMappinig
//使用@GetMapping标识该方法只接受Get请求 @GetMapping(value = "g2") public String get2() { return "g2"; }
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
参数映射
@PathVariable将url绑定到参数
这种方法准确来说,是将url绑定到参数,所以参数名必须要和{path}一样
//将路径映射到参数上 @GetMapping(value = "g3{p1}/{p2}") public String get3(@PathVariable String p1, @PathVariable String p2) { return p1 + p2; }
参数映射的限制
在使用@RequestMapping或者其他变体时,我们指定method参数,标识只接收对应方法的请求。这个注解还有其他的映射限制参数。
consumes
接收指定参数类型的请求。一下代码片段只接收参数类型是text/xml或者text/plain
//将路径映射到参数上 @GetMapping(value = "g4",consumes = {"text/xml","text/plain"}) public String get4() { return "g4"; }
produces
一下代码片段标识服务端返回的数据格式是application/json而客户端只接收text/html所以是错误的。
//只接受客户端要求的返回值类型包含application/json @GetMapping(value = "g5",produces = {"application/json"}) public String get5() { return "g5"; }
params
要求请求中必须指定某个参数,或某个参数的值必须匹配。
//要求客户端必须要参数 a,参数b的值必须是100 @GetMapping(value = "g6", params = {"a", "b=100"}) public String get6(String a, Integer b) { return "g6"; }
headers
要求客户端请求必须有指定的请求头,或请求头的值必须符合
@MatrixVariable矩阵变量
矩阵变量也是从url中获取参数,但是有几个条件必须满足。1、必须使用@PathVariable 2、必须使用@MatrixVariable 3、RequestMappingHandlerMapping的removeSemicolonContent必须是false
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 映射器 根据beanName找到处理器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean id="/beannameurlhandlermappingcontroller" class="com.datang.controller.BeanNameUrlHandlerMappingController"></bean> <!-- 映射器 根据@RequestMapping 找到处理器--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"> <property name="removeSemicolonContent" value="false"/> </bean> <!-- 处理器适配器 配合BeanNameUrlHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!-- 处理器适配器 配合RequestMappingHandlerMapping使用 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> <!-- 视图解析器,配置视图的前缀和后缀 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 使用自己的viewClass --> <property name="viewClass" value="com.datang.view.MyInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsps/"/> <property name="suffix" value=".jsp"/> <property name="order" value="1"/> </bean> <!-- 第二个视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 使用自己的viewClass --> <property name="viewClass" value="com.datang.view.MyInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsps2/"/> <property name="suffix" value=".jsp"/> <property name="order" value="2"/> </bean> <!-- 根据view名称匹配资源路径 --> <bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver"> <property name="order" value="3"/> <property name="basename" value="views"/> </bean> <!-- ExceptionHandlerExceptionResolver 配合@ControllerAdvice和@ExceptionHandler使用 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"> <!-- 优先级--> <property name="order" value="0"/> </bean> <!-- ResponseStatusExceptionResolver 配合@ResponseStatus使用 --> <bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver"> <!-- 优先级--> <property name="order" value="1"/> </bean> <!-- SimpleMappingExceptionResolver 规定异常页面--> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 优先级--> <property name="order" value="2"/> <!-- 为所有的异常定义默认的异常处理页面,exceptionMappings未定义的异常使用本默认配置 --> <property name="defaultErrorView" value="error"></property> <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception --> <property name="exceptionAttribute" value="ex"></property> <!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常页文件名作为值, 将不同的异常映射到不同的页面上。 --> <property name="exceptionMappings"> <props> <prop key="java.io.IOException">ioerror</prop> </props> </property> <!-- 返回状态码 --> <property name="defaultStatusCode" value="250"/> </bean> <!-- 从cookie中读取cookieName的对应值。--> <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver"> <property name="cookieName" value="localeCoolie"/> </bean> <!-- 从客户端的accept中获取地区 --> <bean class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver"></bean> <!-- 从session中获取时区和地区 --> <!-- <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">--> <!-- <property name="localeAttributeName" value="sessionLocale"/>--> <!-- <property name="timeZoneAttributeName" value="sessionZone"/>--> <!-- </bean>--> <!-- cookie设置css样式 --> <bean id="themeResolver" class="org.springframework.web.servlet.theme.CookieThemeResolver"> <property name="defaultThemeName" value="theme1"/> <property name="cookieName" value="theme"/> </bean> <!-- 样式路径 --> <bean id="themeSource" class="org.springframework.ui.context.support.ResourceBundleThemeSource"> <property name="basenamePrefix" value="theme."/> </bean> <!-- 文件上传 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean> <context:component-scan base-package="com.datang"/> </beans>
//矩阵变量,defaultValue可设置默认值 @GetMapping(value = "g8/{a}") public String get8(@PathVariable String a, @MatrixVariable(defaultValue = "bbbb") String b, @MatrixVariable List c) { return a + b + c.toString(); }
@RequestParam参数别名
请求中的参数名和方法参数不一致时,可以使用@RequestParam。注意使用该注解的参数默认是必须的,否则报错。可以使用required = false
//参数别名映射。required设置是否是必须的参数 @GetMapping(value = "g9") public String get9(@RequestParam(value = "v2",required = false) String v1) { return v1; }
@RequestHeader绑定请求头到参数
//请求头映射成参数。value代表要映射的head,如果head为空则报错,但是可以设置required或着defaultValue参数。 //如果参数类型是Map则会把所有的head全部映射到map中 @GetMapping(value = "g10") public String get10(@RequestHeader(value = "head1") String head1, @RequestHeader(value = "head2", required = false) String head2, @RequestHeader(value = "head3", defaultValue = "head333") String head3, @RequestHeader Map heads) { return "requestHeader"; }
@CookieValue绑定cookie到参数
//获取cookie映射到参数。required设置是否是必须的参数。 // defaultValue如果没有对应cookie则选择默认的 @GetMapping(value = "g11") public String get10(@CookieValue(value = "JSESSIONID") String sessionId, @CookieValue(value = "a", defaultValue = "aaa") String a, @CookieValue(value = "b", required = false) String c) { return sessionId; }
可自动加入ModelAndView的
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <div> ${k1} ${k2} ${k3} ${k4} </div> </body> </html>
package com.datang.controller;/* * @auther 顶风少年 * @mail dfsn19970313@foxmail.com * @date 2020-02-11 17:56 * @notify * @version 1.0 */ import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.ui.ModelMap; import org.springframework.validation.support.BindingAwareConcurrentModel; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import java.util.HashMap; import java.util.Map; @Controller @RequestMapping(value = "moa/") public class ModelAttributeD { //通常的我们返回ModelAndView,addObject()则相当于request.addAttribute("",""); @GetMapping("g1") public ModelAndView g1() { ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("k1", "v1"); modelAndView.setViewName("page8"); return modelAndView; } }
/* 除此之外我们还可以在参数中携带 Model , Map ModelMap 这三个参数也可以自动的封装到request中。注意,只能是在参数中。 如果是局部变量则不会自动封装。*/ @RequestMapping(value = "g2") public ModelAndView g1(Model model, Map map, ModelMap modelMap) { // Model model, Map map, ModelMap modelMap ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("k1", "v1"); modelAndView.setViewName("page8"); // Model model = new BindingAwareConcurrentModel(); model.addAttribute("k2", "v2"); // Map map = new HashMap(); map.put("k3", "v3"); // ModelMap modelMap = new ModelMap(); modelMap.addAttribute("k4", "v4"); return modelAndView; }
/* 如果返回值是String,并且没有使用@ResponseBody也会填充 这三个参数,但是ModeleAndView则不会自动填充*/ @RequestMapping(value = "g3") public String g3(ModelAndView modelAndView, Model model, Map map, ModelMap modelMap) { modelAndView.addObject("k1", "v1"); modelAndView.setViewName("page8"); model.addAttribute("k2", "v2"); map.put("k3", "v3"); modelMap.addAttribute("k4", "v4"); return "page8"; }
@ModelAttribute
@ModelAttribute添加到方法上,充当前置Controller
被@ModelAttribute注释的方法,没有返回值。它会在每一个controller处理前先执行。如果参数中有Model,Map,modelMap。则会自动填充到所有的Controller中的Model中。
@ModelAttribute public void m1(Model model, Map map, ModelMap modelMap) { model.addAttribute("m1", "v1"); map.put("m2", "v2"); modelMap.put("m3", "v3"); } @GetMapping(value = "g4") public String g4() { return "page9"; }
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<div>
${m1} ${m2} ${m3}
</div>
</body>
</html>
@ModelAttribute添加到方法上,返回对象
@ModelAttribute注释的方法返回一个具体的对象,虽然未显示的指定model的Key,则默认的将其类型小写作为model的Key
@ModelAttribute public String m2(){ return "m4"; } @GetMapping(value = "g4") public String g4() { return "page9"; }
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <div> ${m1} ${m2} ${m3} ${string} </div> </body> </html>
@ModelAttribute添加到方法上,返回对象,设置value属性
通过设置Value属性,指定返回值得Key。
@ModelAttribute(value = "m5") public String m3(){ return "v5"; } @GetMapping(value = "g4") public String g4() { return "page9"; }
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <div> ${m1} ${m2} ${m3} ${string} ${m5} </div> </body> </html>
@ModelAttribute和@GetMapping(包括其他Method的Mapping)一块使用
这种使用方法最难理解,坑也最多。先看第一个代码片段,这个的mapping的值,其实是视图的名字。而@ModelAttribute的value则是model的Key。
package com.datang.controller;/* * @auther 顶风少年 * @mail dfsn19970313@foxmail.com * @date 2020-02-11 17:56 * @notify * @version 1.0 */ import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import java.util.Map; @Controller public class ModelAttributeD2 { @ModelAttribute(value = "m1") @GetMapping(value = "page10") public String g5() { return "v1"; } }
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <div> ${m1} </div> </body> </html>
如果是多层路径则会报错,明显的,它说找不到view。
@Controller
@RequestMapping("/test")
public class ModelAttributeD2 {
@ModelAttribute(value = "m1")
@GetMapping(value = "page10")
public String g5() {
return "v1";
}
}
同时其他的@ModelAttribute也会生效。
package com.datang.controller;/* * @auther 顶风少年 * @mail dfsn19970313@foxmail.com * @date 2020-02-11 17:56 * @notify * @version 1.0 */ import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import java.util.Map; @Controller //@RequestMapping("/test") public class ModelAttributeD2 { @ModelAttribute public void m1(Model model){ model.addAttribute("m2","v2"); } @ModelAttribute(value = "m1") @GetMapping(value = "page10") public String g5() { return "v1"; } }
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <div> ${m1} ${m2} </div> </body> </html>
@ModelAttribute注释参数,获取其他ModelAttribute的值
以下代码片段,我们获取了m1()方法的model。此时就算我们通过请求参数设置属性也不会自动绑定。
package com.datang.controller;/* * @auther 顶风少年 * @mail dfsn19970313@foxmail.com * @date 2020-02-11 17:56 * @notify * @version 1.0 */ import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import java.util.Map; @Controller //@RequestMapping("/test") public class ModelAttributeD2 { @ModelAttribute public void m1(Model model) { model.addAttribute("m2", "v2"); } @GetMapping(value = "g4") public String g4() { return "page9"; } @ModelAttribute(value = "m1") @GetMapping(value = "page10") public String g5() { return "v1"; } @ResponseBody @GetMapping(value = "g5") public String g6(@ModelAttribute("m2") String m2) { return m2; } }
@ModelAttribute注释返回值
最坑的用法,首先@GetMapping的作用还是设置视图,那问题就出现了,我们已经有一个方法的@GetMapping是page10了,尽管它俩都是指向的视图,还是会报错。所以我这另外开了一个视图。
注解到返回值,就是将返回值填充到Model中,key为value的值。
package com.datang.controller;/*
* @auther 顶风少年
* @mail dfsn19970313@foxmail.com
* @date 2020-02-11 17:56
* @notify
* @version 1.0
*/
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import java.util.Map;
@Controller
//@RequestMapping("/test")
public class ModelAttributeD2 {
@ModelAttribute
public void m1(Model model) {
model.addAttribute("m2", "v2");
}
@GetMapping(value = "g4")
public String g4() {
return "page9";
}
@ModelAttribute(value = "m1")
@GetMapping(value = "page10")
public String g5() {
return "v1";
}
@ResponseBody
@GetMapping(value = "g5")
public String g6(@ModelAttribute("m2") String m2) {
return m2;
}
@GetMapping(value = "page11")
public @ModelAttribute(value = "m3") String g7() {
return "haha";
}
}
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <div> ${m3} </div> </body> </html>