SpringMvc
SpringMvc是Spring的一个后续产品,是Spring的一个子项目
SpringMvc是Spring为表述层开发提供的一整套完备的解决方案
创建SpringMvc项目
创建maven下的web项目
参考:https://blog.csdn.net/weixin_42222334/article/details/80362126
导入依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.15</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.10</version> </dependency>
|
配置web.xml文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <!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> <servlet> <servlet-name>SpringMvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springMVC.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>SpringMvc</servlet-name>
<url-pattern>/</url-pattern> </servlet-mapping> </web-app>
|
配置springMVC.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com"/> <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver"> <property name="order" value="1"/> <property name="characterEncoding" value="UTF-8"/> <property name="templateEngine"> <bean class="org.thymeleaf.spring5.SpringTemplateEngine"> <property name="templateResolver"> <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver"> <property name="prefix" value="/WEB-INF/templates/"/> <property name="suffix" value=".html"/> <property name="templateMode" value="HTML5"/> <property name="characterEncoding" value="UTF-8"/> </bean> </property> </bean> </property> </bean> </beans>
|
扩展:过滤器、拦截器、aop 顺序
由于SpringMVC的前端控制器是DispatherServlet所以有必要了解一下过滤器、拦截器、aop 的执行顺序
filter—>Interceptor—->@Aspect –>Interceptor
SpringMVC的请求
@RequestMapping
@RequestMapping注解的作用就是将请求和处理请求的控制器方法关联起来,建立映射关系
- 标识一个类:设置请求的请求路径的初始信息
- 标识一个方法:设置映射请求请求路径的具体信息
1 2 3 4 5 6 7 8 9 10
| @Controller @RequestMapping(value="/test") public class controller { @RequestMapping(value="index") public String index(){ return "index"; } }
|
浏览器发送请求,若请求地址符合前端控制器的url-pattern,该请求就会被前端控制器DispatcherServlet处理。前端控制器会读取SpringMvc的核心配置文件,通过扫描组件会找到控制器,将请求地址和控制器中@RequestMapping注解的value属性值进行匹配,若匹配成功,该注解所标识的控制器方法就是处理请求的方法。处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会被视图解析器解析,通过Thymeleaf(也可以使用其他的视图解析器)对视图进行渲染,最终转发到视图所对应页面
@RequestMapping中的value属性
@RequestMapping注解的value属性是一个字符串类型的数组,表示该请求映射能够匹配多个请求地址所对应的请求
@RequestMapping注解的value属性必须设置
1 2 3 4 5
| @RequestMapping(value={"index","test"}) public String index(){ return "index"; }
|
@RequestMapping中的method属性
@RequestMapping中的method属性通过请求的请求方式(get/post匹配请求映射)
@RequestMapping中的method属性是一个RequestMethod类型的数组,表示该请求映射能够匹配多种请求方式的请求
1 2 3 4 5
| @RequestMapping(value="index",method=RequestMethod.GET) public String index(){ return "index"; }
|
@RequestMapping的派生注解
@GetMapping
@PostMapping
…
@RequestMapping中的params属性
@RequestMapping中的params属性通过请求的请求参数匹配请求映射
@RequestMapping中的params属性是一个字符串的数组,可以通过四种表达式设置请求参数和请求映射的匹配关系
1 2 3 4
| "param":要求请求映射所匹配的请求必须携带param请求参数 "param":要求请求映射所匹配的请求必须不能携带param请求参数 "param=value":要求请求映射所匹配的请求必须携带param请求参数且param=value" param!=value":要求请求映射所匹配的请求必须携带param请求参数但是param!=value
|
1 2 3 4 5
| @RequestMapping(value="index",param={"usename","!abc"}) public String index(){ return "index"; }
|
SpringMVC支持ant风格的路径
?:表示任意的单个字符
*:表示任意的0个或多个字符
**:表示任意的一层或多层目录
SpringMVC获取请求参数
可以使用servletAPI获取参数,但基本不使用
当发送的参数名与@RequestMapping标识方法中参数名一致时,会自动匹配
1 2 3 4
| @RequestMapping(value="index") public String index(String username, String password){ return "index"; }
|
当有多个请求参数名一样时,如: …?hobby=a&hobby=b
1 2 3 4 5 6 7 8 9 10
| @RequestMapping(value="index") public String index(String hobby){ return "index"; }
@RequestMapping(value="index") public String index(String[] hobby){ return "index"; }
|
@RequestParam()
1 2 3 4 5 6 7 8 9 10 11
| @RequestMapping(value="index") public String index( @RequestParam("user_name") String username, String password){ return "index"; }
@RequestParam()将请求参数和方法参数映射起来,属性: required 是否必须带有这个请求参数 defaultValue 不管required属性值为true或false,当value所指定的请求参数没有传输或传输的值为“”时,则使用默认值
|
@RequestHeader
1 2 3 4 5 6 7 8 9 10 11
| @RequestMapping(value="index") public String index( String username, String password, @RequestHeader("Host") String host){ return "index"; }
@RequestHeader()会从请求头中取出对应的字段赋值给参数,属性: required 是否必须带有这个请求参数 defaultValue 不管required属性值为true或false,当value所指定的请求参数没有传输或传输的值为“”时,则使用默认值
|
@CookieValue
与前面的使用方法一样
通过POJO获取请求参数
可以在控制器方法的形参位置设置一个实体类类型的形参,此时若浏览器传输的请求参数的参数名和实体类中的属性名一致,那么请求参数就会为此属性赋值
1 2 3 4
| <form th:action="@{/test}" method="post"> <input type="text" name="username"/> <input type="password" name="password"/> </form>
|
1 2 3 4 5 6 7 8 9 10 11 12
| public class User{ public String username; public String password; ... }
@RequestMapping("index") public String index(User user){ System.out.println(user.getUsername() + user.getPassword); return "index"; }
|
解决中文乱码问题
在web.xml文件中添加字符编码过滤器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceResponseEncoding</param-name> <param-value>true</param-value> </init-param> </filter>
<filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
|
域对象共享数据
使用servletAPI向request域对象共享数据
可以使用servletAPI向域对象中存放数据,但基本不使用
1 2 3 4 5
| @RequestMapping("index") public String index(HttpServletRequest request){ request.setAttribute("test","testString"); return "index"; }
|
使用ModelAndView向request域对象共享数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @RequestMapping("index") public ModelAndView index(){
ModelAndView mv = new ModelAndView(); mv.addObject("hello","world"); mv.setViewName("index"); return mv; }
|
使用Model向request域对象共享数据
1 2 3 4 5
| @RequestMapping("index") public String index(Model m){ m.addAttribute("hello","world"); return "index"; }
|
使用Map向request域对象共享数据
1 2 3 4 5
| @RequestMapping("index") public String index(Map<String,Object> map){ map.put("hello","world"); return "index"; }
|
使用ModelMap向request域对象共享数据
1 2 3 4 5
| @RequestMapping("index") public String index(ModelMap mm){ mm.addAttribute("hello","world"); return "index"; }
|
向session域中共享数据
1 2 3 4 5
| @RequestMapping("index") public String index(HttpSession session){ session.setAttribute("hello","world"); return "index"; }
|
向application域共享数据
1 2 3 4 5 6
| @RequestMapping("index") public String index(HttpSession session){ ServletContext application = session.getServletContext(); application.setAttribute("hello","world"); return "index"; }
|
SpringMVC的视图
自定义视图解析器
当控制器方法中设置的视图名没有任何前缀时,此时的视图名称会被SpringMVC配置文件中所配置的视图解析器解析,视图名称拼接视图前缀和视图后缀所得到的最终路径,会通过转发的方式实现跳转
转发视图
SpringMVC中默认的转发视图是InternalResourceView
创建转发视图的情况:
当控制器方法中所设置的视图名称以 “forward:” 为前缀时,创建InternalResourceView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀 “forward:” 去掉,剩余部分作为最终路径通过转发的方式实现跳转(只能跳转@RequestMapping映射过的视图)
例如 “forward:/“,”forward:/employee”
1 2 3 4
| @RequestMapping("index") public String index(){ return "forward:/index"; }
|
重定向视图
SpringMVC中默认的重定向视图是RedirectView
当控制器方法中所设置的视图名称以 “redirect:” 为前缀时,创建RedirectView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀 “redirect:” 去掉,剩余部分作为最终路径通过重定向的方式实现跳转(只能跳转@RequestMapping映射过的视图)
例如 “redirect:/“,”redirect:/employee”
1 2 3 4
| @RequestMapping("index") public String index(){ return "redirect:/index"; }
|
视图控制器 view-controller
当控制器方法中,仅仅用来实现页面跳转(即不做任何其他的操作,只是页面跳转),即只需要设置视图名称时,可以将处理器方法使用view-controller标签进行表示
使用场景:
spring文档里建议并将其做为最佳实践将所有的jsp页面放到WEB-INF下,不让直接访问,那么我们只能通过controller来访问jsp页面了,但是我们总不能为每个页面都写一个controller吧,那样太麻烦了,所以mvc:view-controller就是处理这个场景的一个shortcut(快捷方式)。
配置view-controller后所有映射都会失效
原因:如果没有mvc:annotation-driven,那么所有的@Controller注解可能就没有解析,所有当有请求时候都没有匹配的处理请求类,就都去mvc:default-servlet-handler即default servlet处理了。
<mvc:annotation-driven />的作用
InternalResourceViewResolver控制器
springMCV.xml
1 2 3 4
| <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/templates/"/> <property name="suffix" value=".jsp"/> </bean>
|
RESTFul简介
REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移。 它首次出现在2000年Roy Fielding的博士论文中,Roy Fielding是HTTP规范的主要编写者之一。 他在论文中提到:”我这篇文章的写作目的,就是想在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强、性能好、适宜通信的架构。REST指的是一组架构约束条件和原则。” 如果一个架构符合REST的约束条件和原则,我们就称它为RESTful架构。
REST本身并没有创造新的技术、组件或服务,而隐藏在RESTful背后的理念就是使用Web的现有特征和能力, 更好地使用现有Web标准中的一些准则和约束。虽然REST本身受Web技术的影响很深, 但是理论上REST架构风格并不是绑定在HTTP上,只不过目前HTTP是唯一与REST相关的实例。
参考:菜鸟教程
RESTFul的实现
具体来说就是HTTP协议里的四个表示操作方式的动词:GET、POST、PUT、DELETE
- GET:用于获取资源
- POST:用于新建资源
- PUT:用于更新资源
- DELETE:用于删除资源
REST风格提倡URL地址使用统一的风格设计,从前到后各个单词使用斜杠分开,不使用问号键值对方式携带请求参数,而是将要发送给服务器的数据作为URL地址的一部分,以保证整体风格的一致性
操作 |
传统方式 |
REST风格 |
查询 |
getUserById?id=1 |
user/1——>GET |
保存 |
saveUser |
user——>POST |
删除 |
deleteUser?id=1 |
user/1——>DELETE |
更新 |
updateUser |
user——>PUT |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @RequestMapping(value="/user/{id}", method=RequestMethod.GET) public String getUserById(){ ... }
@RequestMapping(value="/user", method=RequestMethod.POST) public String saveUser(String username,String password){ ... }
@RequestMapping(value="/user/{id}", method=RequestMethod.DELETE) public String deleteUser(){ ... }
@RequestMapping(value="/user", method=RequestMethod.PUT) public String updateUser(String username,String password){ ... }
|
PUT、DELETE请求方式存在浏览器兼容问题
浏览器确实支持PUT和DELETE,但是HTML不支持。
这是因为HTML 4.01和最终的W3C HTML 5.0规范都说它们的form元素应允许的唯一HTTP方法是GET和POST。
在HTML 5的开发过程中对此进行了很多讨论,有一次他们将它们添加到HTML 5中,然后再次删除。之所以从HTML5规范中删除其他方法,是因为HTML 4级浏览器永远无法支持它们(在制作时不属于HTML)。
解决:在web.xml文件中配置HiddenHttpMethodFilter过滤器
注:同时编码过滤器必须放在HiddenHttpMethodFilter过滤器之前
1 2 3 4 5 6 7 8 9
| <filter> <filter-name>HiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
|
扩展问题:DispatcherServlet是访问不到静态资源的,当DispatcherServlet访问不到时,应该让Tomcat配置的DefaultServlet去访问静态资源,因此需要配置mvc:default-servlet-handler标签,由于配置mvc:default-servlet-handler标签后也会导致映射路径失效,所以也需要配置mvc:annotation-driven标签
如果配置了DispatcherServlet,那么所有的请求都会被拦截,包括静态资源。
- ‘/‘ 将会替换掉容器的default servlet, 将会处理所有其他handler(Servlet)都不处理的访问请求.
- 如果web.xml没有配置其他特殊路径的servlet, 基本上所有的请求都交由DispatcherServlet处理.
- 将不会再访问容器中原始默认的servlet(你对静态资源的访问就是通过容器默认servlet处理的),故而静态资源将不可访问!
1 2 3 4
| <mvc:default-servlet-handler/>
<mvc:annotation-driven/>
|
刨根问底一下 为什么加入两个注解就没有问题了呢?
首先是两个注解都不加,此时HandlerMappings中的AnnotationHandlerMapping中存储这Controller和url的映射关系,由于我们没有编写Controller去处理js html等静态资源,所以此时的状态是动态资源可以访问,静态资源不可访问。
其次是只加上default-servlet-handler,发现处理Controller的AnnotationHandler不见了,取而代之的是SimpleURLHandlerMapping,该Handler种的handlerMap非常简单只有一个/** 即无论什么请求都直接去当前webapp下去找。这样配置静态资源肯定是可以访问的,因为它的作用和不使用SpringMVC中的DIsplacedServlet直接使用Tomcat一样。但由于AnnotationHandler的缺失,导致Controller这种基于注解配置处理请求的方法无法访问,所以这种配置下的状态是静态资源可以访问,动态资源不可以访问。
最后当把两个注解都加上的时候,不仅有处理静态资源的SimpleUrlHandlerMapping,还多了一个优先级最高的RequestMapping,点开详情信息发现我们配置的Controller都在里面。这就是我们要的效果:
对于每一个非jsp请求都会被DispatchServlet拦下,然后交给优先级最高的RequestMapping处理。RequestMapping遍历自己的Mappings,如果这个请求是一个动态请求,那么一定可以找到对应的Controller,Controller处理并返回;如果该请求是一个针对静态资源文件的,RequestMapping无能为力,他会按照优先级交给后续HandlerMapping如没啥用的BeanNameUrlHandlerMapping,以及放在最后用来兜底的SimpleUrlHandlerMapping,当SimpleUrlHandlerMapping拿到一个针对静态资源的请求后,会在/**目录下找到静态资源并返回。
转载自原创博主
HttpMessageConverter
HttpMessageConverter,报文信息转换器,将请求报文转换为Java对象,或将Java对象转换为响应报文
HttpMessageConverter提供了两个注解和两个类型:@RequestBody,@ResponseBody,RequestEntity,ResponseEntity
@RequestBody
@RequestBody可以获取请求体,需要在控制器方法设置一个形参,使用@RequestBody进行标识,当前请求的请求体就会为当前注解所标识的形参赋值
1 2 3 4 5
| @RequestMapping("/test") public String deleteUser(@RequestBody String requestBody){ System.out.println(requestBody); ... }
|
1 2 3 4 5
| <form th:action="@{/user/test}" method="post"> 用户名:<input type="text" name="username"> 密码:<input type="password" name="password"> <input type="submit" value="提交"> </form>
|
结果:
1
| username="..."&password="..."
|
RequestEntity
RequestEntity封装请求报文的一种类型,需要在控制器方法的形参中设置该类型的形参,当前请求的请求报文就会赋值给该形参,可通过getHeaders()获得请求头信息,通过getBody()获取请求体信息
1 2 3 4 5 6
| @RequestMapping("/test") public String deleteUser(RequestEntity<String> requestEntity){ System.out.println(requestEntity.getHeaders()); System.out.println(requestEntity.getBody()); ... }
|
@ResponseBody
@ResponseBody用于标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应到浏览器
1 2 3 4 5
| @RequestMapping("/test") @ResponseBody public String deleteUser(){ return "成功!"; }
|
结果:浏览器页面显式 成功!
处理 json
1、导入依赖
2、在SpringMVC核心配置文件中开启mvc的注解驱动
1
| <mvc:annotation-driven/>
|
3、在处理器方法上使用@ResponseBody注解进行标识
4、将Java对象直接作为控制器方法的返回值返回时,就会自动转换为json格式字符串
ResponseEntity
ResponseEntity用于控制器方法的返回值类型,该控制器的返回值就是响应到浏览器的响应报文
@RestController注解
@RestController注解是SpringMVC提供的一个复合注解,标识在控制器的类上,就相当于为类添加了@Controller注解,并且为其中的每个方法添加了@ResponseBody
文件上传和下载
下载
利用ResponseEntity实现下载功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @RequestMapping("download") public ResponseEntity<byte[]> test(HttpSession session) throws IOException { ServletContext servletcontext = session.getServletContext (); String realpath = servletcontext. getRealPath("/static/img/1.jpg"); InputStream is = new FileInputStream(realpath); byte[] bytes = new byte[is.available()]; is.read(bytes); MultiValueMap<String,String> headers = new HttpHeaders(); headers.add("content-Disposition","attachment;filename=1.jpg"); HttpStatus statuscode = HttpStatus.OK; ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes,headers,statuscode) ; return responseEntity; }
|
上传
添加依赖:
1 2 3 4 5
| <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</ artifactId> <version>1.3.1</version> </dependency>
|
html:
1 2 3 4 5
| <form th:action="@{/up}" method="post" enctype="multipart/form-data"> 头像:<input type="file" name="photo"><br> <input type="submit" value=”上传> </form>
|
在SpringMVC核心配置文件中配置文件上传解析器
1 2 3
|
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| @RequestMapping("up") public String test(MultipartFile photo,HttpSession session) throws IOException{ String fileName = photo.getOriginalFilename(); ServletContext servletContext = session.getServletContext(); String photoPath = servletContext.getRealPath("photo"); File file = new File(photoPath); if (!file.exists()){ file.mkdir(); } String filePath = photoPath + File.separator + fileName; photo.transferTo(new File(filePath)); return "success"; }
|
最终上传到这个文件夹:
拦截器
SpringMVC中的拦截器用于拦截控制器方法的执行
SpringMVC中的拦截器需要实现HandlerInterceptor或者继承HandlerInterceptorAdapter类
SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置
拦截器的配置
1 2 3 4
| <mvc:interceptors> <bean class="com.interceptors.Interceptor"/> </mvc:interceptors>
|
实现拦截器
拦截器三个方法执行时机
- 控制器方法执行之前
- 控制器方法执行之后
- 渲染视图完毕之后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class Interceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true
; }
@Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); }
@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { HandlerInterceptor.super.afterCompletion(request, response, handler, ex); } }
|
关于preHandle放行可以在DispatcherServlet源码中看见如下代码
进入applyPreHandle方法中可以看见若拦截器的preHandle方法返回true则这个方法返回true,结合DispatcherServlet的源码可知 if 代码块中的return不会执行,可以继续往下走
拦截指定路径
1 2 3 4 5 6 7 8
| <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <mvc:exclude-mapping path="/"/> <bean class="com.interceptors.Interceptor"/> </mvc:interceptor> </mvc:interceptors>
|
多个拦截器的执行顺序
若每个拦截器的preHandle()都返回true
- 则此时拦截器的执行顺序与拦截器在SpringMVC配置文件中的配置顺序有关
- preHandle()会按照配置的顺序执行,而postHandle()和afterComplation()会按照配置的反序执行()
若某个拦截器的preHandle()返回了false
- preHandle()返回false和它之前的拦截器的preHandle()都会执行,postHandle()都不执行,返回false的拦截器之前的拦截器的afterComplation()会执行
异常处理器
SpringMVC提供了一个处理控制器方法执行过程中出现的异常的接口:HandlerExceptionResolver
HandlerExceptionResolver接口的实现类有:DefaultHandlerExceptionResolver和SimpleMappingExceptionResolver
使用自定义异常理器
SpringMVC提供了自定义的异常处理器SimpleMappingExceptionResolver
基于配置的异常处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props>
<prop key="异常全类名">新的视图名称</prop> </props> </property> <property name="exceptionAttribute" value="键名"/> </bean>
|
基于注解的异常处理
1 2 3 4 5 6 7 8 9 10 11 12
| @ControllerAdvice public class ExceptionController { @ExceptionHandler(ArithmeticException.class); public ModelAndView testException(Exception ex){ ModelAndView mv = new ModelAndView(); mv.addObject("Exception",ex); ... } }
|
注解配置SpringMVC
使用配置类和注解代替web.xml和SpringMVC配置文件的功能
创建初始化类,代替web.xml
在Servlet3.0环境中,容器会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类,如果找到的话就用它来配置Servlet容器。
Spring提供了这个接口的实现,名为SpringServletContainerInitializer,这个类反过来又会查找实现WebApplicationInitializer的类并将配置的任务交给它们来完成。Spring3.2引入了一个便利的
WebApplicationInitializer基础实现,名为AbstractAnnotationConfigDispatcherServletinitializer,当我们的类扩展了AbstractAnnotationConfigDispatcherServletlnitializer并将其部署到Servlet3.0容器的时候,容器会自动发现它,并用它来配置Servlet上下文。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| public class webInit extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; }
@Override protected Class<?>[] getServletConfigClasses() { return new Class[]{WebConfig.class}; }
@Override protected String[] getServletMappings() { return new String[]{"/"}; }
@Override protected Filter[] getServletFilters() { CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); characterEncodingFilter.setEncoding("utf-8"); characterEncodingFilter.setForceResponseEncoding(true); HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
return new Filter[]{characterEncodingFilter,hiddenHttpMethodFilter}; } }
|
getRootConfigClasses、getServletConfigClasses、getServletMappings是必须的以外,还可以重写其他的方法
完成后项目结构如下图
SpringConfig类
1 2 3 4 5 6 7 8
| @Configuration
@ComponentScan
@EnableWebMvc public class SpringConfig { }
|
Webconfig类
总体:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| @Configuration
@ComponentScan("com")
@EnableWebMvc public class WebConfig implements WebMvcConfigurer { @Bean public ITemplateResolver templateResolver(){ WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext(); ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver( webApplicationContext.getServletContext() ); templateResolver.setPrefix("/WEB-INF/templates"); templateResolver.setSuffix(".html"); templateResolver.setCharacterEncoding("UTF-8"); templateResolver.setTemplateMode(TemplateMode.HTML); return templateResolver; }
@Bean public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver){ SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(templateResolver); return templateEngine; }
@Bean public ViewResolver viewResolver(SpringTemplateEngine templateEngine){ ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); viewResolver.setCharacterEncoding("UTF-8"); viewResolver.setTemplateEngine(templateEngine); return viewResolver; }
@Bean public MultipartResolver multipartResolver(){ CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(); return commonsMultipartResolver; }
@Override public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) { SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver(); Properties prop = new Properties(); prop.setProperty("java.lang.Exception","exception"); exceptionResolver.setExceptionMappings(prop); exceptionResolver.setExceptionAttribute("exception"); resolvers.add(exceptionResolver); }
@Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); }
@Override public void addInterceptors(InterceptorRegistry registry) { Interceptor interceptor = new Interceptor(); registry.addInterceptor(interceptor).excludePathPatterns("/**"); }
@Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/hello").setViewName("hello"); } }
|
配置视图解析器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| @Bean public ITemplateResolver templateResolver(){ WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext(); ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver( webApplicationContext.getServletContext() ); templateResolver.setPrefix("/WEB-INF/templates"); templateResolver.setSuffix(".html"); templateResolver.setCharacterEncoding("UTF-8"); templateResolver.setTemplateMode(TemplateMode.HTML); return templateResolver; }
@Bean public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver){ SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(templateResolver); return templateEngine; }
@Bean public ViewResolver viewResolver(SpringTemplateEngine templateEngine){ ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); viewResolver.setCharacterEncoding("UTF-8"); viewResolver.setTemplateEngine(templateEngine); return viewResolver; }
|
配置文件上传解析器
1 2 3 4 5 6
| @Bean public MultipartResolver multipartResolver(){ CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(); return commonsMultipartResolver; }
|
配置异常处理解析器
1 2 3 4 5 6 7 8 9 10 11 12
| @Override public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) { SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver(); Properties prop = new Properties(); prop.setProperty("java.lang.Exception","exception"); exceptionResolver.setExceptionMappings(prop); exceptionResolver.setExceptionAttribute("exception"); resolvers.add(exceptionResolver); }
|
配置default-servlet-handler
1 2 3 4 5
| @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); }
|
配置拦截器
1 2 3 4 5 6 7
| @Override public void addInterceptors(InterceptorRegistry registry) { Interceptor interceptor = new Interceptor(); registry.addInterceptor(interceptor).excludePathPatterns("/**"); }
|
配置view-controller
1 2 3 4 5
| @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/hello").setViewName("hello"); }
|