SpringMVC

什么是MVC

模型-视图-控制器(MVC)是一个众所周知的以设计界面应用程序为基础的设计思想。它主要通过分离模型、视图及控制器在应用程序中的角色将业务逻辑从界面中解耦。通常,模型负责封装应用程序数据在视图层展示。视图仅仅只是展示这些数据,不包含任何业务逻辑。控制器负责接收来自用户的请求,并调用后台服务(service或者dao)来处理业务逻辑。处理后,后台业务层可能会返回了一些数据在视图层展示。控制器收集这些数据及准备模型在视图层展示。MVC模式的核心思想是将业务逻辑从界面中分离出来,允许它们单独改变而不会相互影响。

SpringMVC是什么

Spring MVC是Spring家族中的一个web成员, 它是一种基于Java的实现了Web MVC设计思想的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,Spring MVC也是要简化我们日常Web开发的。

Spring MVC是服务到工作者思想的实现。前端控制器是DispatcherServlet;应用控制器拆为处理器映射器(Handler Mapping)进行处理器管理和视图解析器(View Resolver)进行视图管理;支持本地化/国际化(Locale)解析及文件上传等;提供了非常灵活的数据验证、格式化和数据绑定机制;提供了强大的约定大于配置(惯例优先原则)的契约式编程支持。

SpringMvc 环境搭建与测试

开发环境

Idea + Maven + Jdk1.8 +Jetty

pom.xml 坐标添加

  1. <properties>
  2. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  3. <maven.compiler.source>1.8</maven.compiler.source>
  4. <maven.compiler.target>1.8</maven.compiler.target>
  5. </properties>
  6. <dependencies>
  7. <!-- spring web -->
  8. <dependency>
  9. <groupId>org.springframework</groupId>
  10. <artifactId>spring-web</artifactId>
  11. <version>4.3.2.RELEASE</version>
  12. </dependency>
  13. <!-- spring mvc -->
  14. <dependency>
  15. <groupId>org.springframework</groupId>
  16. <artifactId>spring-webmvc</artifactId>
  17. <version>4.3.2.RELEASE</version>
  18. </dependency>
  19. <!-- web servlet -->
  20. <dependency>
  21. <groupId>javax.servlet</groupId>
  22. <artifactId>javax.servlet-api</artifactId>
  23. <version>3.0.1</version>
  24. </dependency>
  25. </dependencies>
  26. <build>
  27. <plugins>
  28. <!-- 编译环境插件 -->
  29. <plugin>
  30. <groupId>org.apache.maven.plugins</groupId>
  31. <artifactId>maven-compiler-plugin</artifactId>
  32. <version>2.3.2</version>
  33. <configuration>
  34. <source>1.8</source>
  35. <target>1.8</target>
  36. <encoding>UTF-8</encoding>
  37. </configuration>
  38. </plugin>
  39. <plugin>
  40. <groupId>org.mortbay.jetty</groupId>
  41. <artifactId>maven-jetty-plugin</artifactId>
  42. <version>6.1.25</version>
  43. <configuration>
  44. <scanIntervalSeconds>10</scanIntervalSeconds>
  45. <contextPath>/springmvc01</contextPath>
  46. </configuration>
  47. </plugin>
  48. </plugins>
  49. </build>

配置web.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app id="WebApp_ID" version="3.0"
  3. xmlns="http://java.sun.com/xml/ns/javaee"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
  6. http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  7. <!-- 编码过滤 utf-8 -->
  8. <filter>
  9. <description>char encoding filter</description>
  10. <filter-name>encodingFilter</filter-name>
  11. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  12. <init-param>
  13. <param-name>encoding</param-name>
  14. <param-value>UTF-8</param-value>
  15. </init-param>
  16. </filter>
  17. <filter-mapping>
  18. <filter-name>encodingFilter</filter-name>
  19. <url-pattern>/*</url-pattern>
  20. </filter-mapping>
  21. <!-- servlet请求分发器 -->
  22. <servlet>
  23. <servlet-name>springMvc</servlet-name>
  24. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  25. <init-param>
  26. <param-name>contextConfigLocation</param-name>
  27. <param-value>classpath:servlet-context.xml</param-value>
  28. </init-param>
  29. <!-- 表示启动容器时初始化该Servlet -->
  30. <load-on-startup>1</load-on-startup>
  31. </servlet>
  32. <servlet-mapping>
  33. <servlet-name>springMvc</servlet-name>
  34. <!-- 这是拦截请求, /代表拦截所有请求,拦截所有.do请求 -->
  35. <url-pattern>*.do</url-pattern>
  36. </servlet-mapping>
  37. </web-app>

要想启动我们的springMvc 环境,目前对于mvc 框架的配置还未进行。以上在web.xml中引用了servlet-context.xml 文件

servlet-context.xml 配置

  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns:mvc="http://www.springframework.org/schema/mvc"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="
  6. http://www.springframework.org/schema/mvc
  7. http://www.springframework.org/schema/mvc/spring-mvc.xsd
  8. http://www.springframework.org/schema/beans
  9. http://www.springframework.org/schema/beans/spring-beans.xsd
  10. http://www.springframework.org/schema/context
  11. http://www.springframework.org/schema/context/spring-context.xsd">
  12. <context:component-scan base-package="com.xxxx.springmvc.controller"></context:component-scan>
  13. <mvc:annotation-driven/>
  14. <!--配置视图解析器 默认的视图解析器- -->
  15. <bean id="defaultViewResolver"
  16. class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  17. <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
  18. <property name="contentType" value="text/html" />
  19. <property name="prefix" value="/WEB-INF/jsp/" />
  20. <property name="suffix" value=".jsp" />
  21. </bean>
  22. </beans>

页面控制器的编写

  1. @Controller
  2. public class HelloController {
  3. /**
  4. * 请求映射地址 /hello.do
  5. * @return
  6. */
  7. @RequestMapping(value={"/hello","asdasdas","asfs"})
  8. public ModelAndView hello(){
  9. ModelAndView mv=new ModelAndView();
  10. mv.addObject("hello", "hello spring mvc");
  11. mv.setViewName("hello");
  12. return mv;
  13. }
  14. }

添加视图页面

在WEB-INF 下新建jsp文件夹 ,并在文件加下新建hello.jsp

  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  2. <%
  3. String path = request.getContextPath();
  4. String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
  5. %>
  6. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  7. <html>
  8. <head>
  9. <base href="<%=basePath%>">
  10. <title>My JSP 'hello.jsp' starting page</title>
  11. <meta http-equiv="pragma" content="no-cache">
  12. <meta http-equiv="cache-control" content="no-cache">
  13. <meta http-equiv="expires" content="0">
  14. <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
  15. <meta http-equiv="description" content="This is my page">
  16. </head>
  17. <body>
  18. <!-- el表达式接收参数值 -->
  19. ${hello}
  20. </body>
  21. </html>

启动项目,在浏览器访问 => 地址 http://localhost:8080/springmvc01/hello.do

至此,springmvc 环境搭建完毕

URL地址映射配置 & 参数绑定

URL 映射地址配置之@RequestMapping

在类前面定义,则将url和类绑定,在方法前面定义,则将url和类的方法绑定

  1. //url: http://localhost:8080/springmvc01/hello2/test01.do
  2. @RequestMapping("test01")
  3. public ModelAndView test01(){
  4. ModelAndView mv=new ModelAndView();
  5. mv.setViewName("hello");
  6. mv.addObject("hello", "hello test01");
  7. return mv;
  8. }
  9. //url: http://localhost:8080/springmvc01/hello2.do?test02
  10. @RequestMapping(params="test02")
  11. public ModelAndView test02(){
  12. ModelAndView mv=new ModelAndView();
  13. mv.setViewName("hello");
  14. mv.addObject("hello", "hello test02");
  15. return mv;
  16. }
  17. //url: http://localhost:8080/springmvc01/hello2/test03.do
  18. @RequestMapping("test03")
  19. public String test03(Model model){
  20. model.addAttribute("hello", "hello test03");
  21. return "hello";
  22. }
  23. //url: http://localhost:8080/springmvc01/hello2/test04.do
  24. @RequestMapping("test04")
  25. public String test04(ModelMap modelMap){
  26. modelMap.addAttribute("hello", "hello test04");
  27. return "hello";
  28. }
  29. //url: http://localhost:8080/springmvc01/hello2/test05.do
  30. @SuppressWarnings("unchecked")
  31. @RequestMapping("test05")
  32. public String test05(Map model){
  33. model.put("hello", "hello test05 ");
  34. return "hello";
  35. }

参数绑定

请求参数到处理器功能处理方法的方法参数上的绑定,对于参数绑定非常灵活

基本数据类型、字符串数据绑定
  1. /**
  2. * 简单数据类型 值必须存在 不传可以通过默认值代替
  3. */
  4. @RequestMapping("data1")
  5. public void data1(@RequestParam(defaultValue="10",name="age")int age,
  6. @RequestParam(defaultValue="1",name="flag")boolean flag,
  7. @RequestParam(defaultValue="100",name="s")double s){
  8. System.err.println("age:"+age+":flag:"+flag+":s:"+s);
  9. }
  10. /**
  11. * 包装类型 值可以为空
  12. */
  13. @RequestMapping("data2")
  14. public void data2(Integer age,Double s){
  15. System.err.println("age:"+age+":s:"+s);
  16. }
  17. /**
  18. * 字符串注入
  19. * @param str
  20. */
  21. @RequestMapping("data3")
  22. public void data3(String str){
  23. System.err.println("str:"+str);
  24. }

数组类型
  1. @RequestMapping("/dataTest3")
  2. public void getParamsData3(@RequestParam(value="ids")String[] ids){
  3. for(String id:ids){
  4. System.out.println(id+"---");
  5. }
  6. }

vo 类型
  1. @RequestMapping("/dataTest4")
  2. public void getParamsData4(User user){
  3. System.out.println(user);
  4. }

list 类型

此时user 实体需要定义list 属性

  1. public class User {
  2. private int id;
  3. private String userName;
  4. private String userPwd;
  5. private List<Phone> phones=new ArrayList<Phone>();
  6. public List<Phone> getPhones() {
  7. return phones;
  8. }
  9. public void setPhones(List<Phone> phones) {
  10. this.phones = phones;
  11. }
  12. public int getId() {
  13. return id;
  14. }
  15. public void setId(int id) {
  16. this.id = id;
  17. }
  18. public String getUserName() {
  19. return userName;
  20. }
  21. public void setUserName(String userName) {
  22. this.userName = userName;
  23. }
  24. public String getUserPwd() {
  25. return userPwd;
  26. }
  27. public void setUserPwd(String userPwd) {
  28. this.userPwd = userPwd;
  29. }
  30. @Override
  31. public String toString() {
  32. return "User [id=" + id + ", userName=" + userName + ", userPwd="
  33. + userPwd + ", phones=" + phones + "]";
  34. }
  35. }

Phone实体

  1. public class Phone {
  2. private String num;
  3. public String getNum() {
  4. return num;
  5. }
  6. public void setNum(String num) {
  7. this.num = num;
  8. }
  9. @Override
  10. public String toString() {
  11. return "Phone [num=" + num + "]";
  12. }
  13. }

Jsp 页面定义

  1. <form action="dataTest5.do" method="post">
  2. <input name="phones[0].num" value="123456" />
  3. <input name="phones[1].num" value="4576" />
  4. <button type="submit"> 提交</button>
  5. </form>

Controller 方法

  1. @RequestMapping("/dataTest5")
  2. public void getParamsData5(User user){
  3. System.out.println(user);
  4. }

Set 类型
  1. SetList类似,也需要绑定在对象上,而不能直接写在Controller方法的参数中。但是,绑定Set数据时,必须先在Set对象中add相应的数量的模型对象。
  1. public class User {
  2. private int id;
  3. private String userName;
  4. private String userPwd;
  5. private Set<Phone> phones=new HashSet<Phone>();
  6. public User() {
  7. phones.add(new Phone());
  8. phones.add(new Phone());
  9. phones.add(new Phone());
  10. }
  11. /*public List<Phone> getPhones() {
  12. return phones;
  13. }
  14. public void setPhones(List<Phone> phones) {
  15. this.phones = phones;
  16. }*/
  17. public int getId() {
  18. return id;
  19. }
  20. public void setId(int id) {
  21. this.id = id;
  22. }
  23. public String getUserName() {
  24. return userName;
  25. }
  26. public void setUserName(String userName) {
  27. this.userName = userName;
  28. }
  29. public String getUserPwd() {
  30. return userPwd;
  31. }
  32. public void setUserPwd(String userPwd) {
  33. this.userPwd = userPwd;
  34. }
  35. public Set<Phone> getPhones() {
  36. return phones;
  37. }
  38. public void setPhones(Set<Phone> phones) {
  39. this.phones = phones;
  40. }
  41. }

Controller 方法:

  1. @RequestMapping("/dataTest6")
  2. public void getParamsData6(User user){
  3. System.out.println(user);
  4. }

表单页面

  1. <form action="dataTest6.do" method="post">
  2. <input name="phones[0].num" value="123456" />
  3. <input name="phones[1].num" value="4576" />
  4. <input name="phones[2].num" value="4576" />
  5. <button type="submit"> 提交</button>
  6. </form>

Map 类型数据

Map最为灵活,它也需要绑定在对象上,而不能直接写在Controller方法的参数中。

  1. public class User {
  2. private int id;
  3. private String userName;
  4. private String userPwd;
  5. private Set<Phone> phones=new HashSet<Phone>();
  6. private Map<String, Phone> map=new HashMap<String, Phone>();
  7. //private List<Phone> phones=new ArrayList<Phone>();
  8. public User() {
  9. phones.add(new Phone());
  10. phones.add(new Phone());
  11. phones.add(new Phone());
  12. }
  13. /*public List<Phone> getPhones() {
  14. return phones;
  15. }
  16. public void setPhones(List<Phone> phones) {
  17. this.phones = phones;
  18. }*/
  19. public int getId() {
  20. return id;
  21. }
  22. public void setId(int id) {
  23. this.id = id;
  24. }
  25. public String getUserName() {
  26. return userName;
  27. }
  28. public void setUserName(String userName) {
  29. this.userName = userName;
  30. }
  31. public String getUserPwd() {
  32. return userPwd;
  33. }
  34. public void setUserPwd(String userPwd) {
  35. this.userPwd = userPwd;
  36. }
  37. public Set<Phone> getPhones() {
  38. return phones;
  39. }
  40. public void setPhones(Set<Phone> phones) {
  41. this.phones = phones;
  42. }
  43. public Map<String, Phone> getMap() {
  44. return map;
  45. }
  46. public void setMap(Map<String, Phone> map) {
  47. this.map = map;
  48. }
  49. }

Controller 方法

  1. @RequestMapping("/dataTest7")
  2. public void getParamsData7(User user){
  3. Set<Entry<String, Phone>> set=user.getMap().entrySet();
  4. for(Entry<String, Phone> entry:set){
  5. System.out.println(entry.getKey()+"--"+entry.getValue().getNum());
  6. }
  7. }

表单页面

  1. <form action="dataTest7.do" method="post">
  2. <input name="map['1'].num" value="123456" />
  3. <input name="map['2'].num" value="4576" />
  4. <input name="map['3'].num" value="4576" />
  5. <button type="submit"> 提交</button>
  6. </form>

请求转发与重定向的问题

SpringMvc 默认采用服务器内部转发的形式展示页面信息。同样也支持重定向页面。

转发与重定向代码实现

  1. /**
  2. * 重定向到 jsp 中文会出现乱码
  3. */
  4. @RequestMapping("/queryView1")
  5. public String queryView1(){
  6. return "redirect:v1.jsp?a=admin&b=123456";
  7. }
  8. /**
  9. * 重定向到 jsp 中文乱码解决
  10. */
  11. @RequestMapping("/queryView3")
  12. public String queryView3(RedirectAttributes attr){
  13. attr.addAttribute("a", "admin");
  14. attr.addAttribute("b", "奥利给");
  15. return "redirect:v1.jsp";
  16. }
  17. /**
  18. * 重定向到 jsp ModelAndView1
  19. */
  20. @RequestMapping("/queryView4")
  21. public ModelAndView queryView4(RedirectAttributes attr){
  22. ModelAndView mv=new ModelAndView();
  23. attr.addAttribute("a", "admin");
  24. attr.addAttribute("b", "奥利给");
  25. mv.setViewName("redirect:v1.jsp");
  26. return mv;
  27. }
  28. /**
  29. * 重定向到 jsp ModelAndView2 mv 携带参数
  30. */
  31. @RequestMapping("/queryView5")
  32. public ModelAndView queryView5(){
  33. ModelAndView mv=new ModelAndView();
  34. mv.setViewName("redirect:v1.jsp");
  35. mv.addObject("a", "admin");
  36. mv.addObject("b", "奥利给");
  37. System.out.println("重定向。。。");
  38. return mv;
  39. }
  40. /**
  41. * 重定向到Controller 并传递参数
  42. */
  43. @RequestMapping("/queryView6")
  44. public String queryView6(RedirectAttributes attr){
  45. attr.addAttribute("a", "admin");
  46. attr.addAttribute("b", "奥利给");
  47. return "redirect:/user/queryUserById.do";
  48. }
  49. /**
  50. * 重定向到Controller modelandview
  51. * @return
  52. */
  53. @RequestMapping("/queryView7")
  54. public ModelAndView queryView7(){
  55. ModelAndView mv=new ModelAndView();
  56. mv.setViewName("redirect:/user/queryUserById.do");
  57. mv.addObject("a", "admin");
  58. mv.addObject("b", "奥利给");
  59. return mv;
  60. }
  61. 重定向页面值获取 ${param.a}|||${param.b}
  62. /**
  63. * 转发到视图
  64. */
  65. @RequestMapping("/queryView8")
  66. public ModelAndView queryView8(){
  67. ModelAndView mv=new ModelAndView();
  68. mv.setViewName("v1");
  69. mv.addObject("a", "admin");
  70. mv.addObject("b", "奥利给");
  71. return mv;
  72. }
  73. /**
  74. * 转发到controller
  75. */
  76. @RequestMapping("/queryView9")
  77. public ModelAndView queryView9(HttpServletRequest request){
  78. ModelAndView mv=new ModelAndView();
  79. mv.setViewName("forward:user/queryUserById2.do?a=admin&b=奥利给");
  80. return mv;
  81. }
  82. 页面值获取 ${a}||${b}

SpringMvc 之Json数据开发

基本概念

Json在企业开发中已经作为通用的接口参数类型,在页面(客户端)解析很方便。SpringMvc 对于json 提供了良好的支持,这里需要修改相关配置,添加json数据支持功能

@ResponseBody

该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用(通常用于ajax 请求)

@RequestBody

该注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上 ,再把HttpMessageConverter返回的对象数据绑定到 controller中方法的参数上

使用配置

pom.xml 添加json相关坐标
  1. <!-- 添加json 依赖jar包 -->
  2. <dependency>
  3. <groupId>com.fasterxml.jackson.core</groupId>
  4. <artifactId>jackson-core</artifactId>
  5. <version>2.7.0</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>com.fasterxml.jackson.core</groupId>
  9. <artifactId>jackson-databind</artifactId>
  10. <version>2.7.0</version>
  11. </dependency>
  12. <dependency>
  13. <groupId>com.fasterxml.jackson.core</groupId>
  14. <artifactId>jackson-annotations</artifactId>
  15. <version>2.7.0</version>
  16. </dependency>

修改servlet-context.xml
  1. <!-- mvc 请求映射 处理器与适配器配置 -->
  2. <mvc:annotation-driven>
  3. <mvc:message-converters>
  4. <bean class="org.springframework.http.converter.StringHttpMessageConverter" />
  5. <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
  6. </mvc:message-converters>
  7. </mvc:annotation-driven>

注解使用
  1. /**
  2. *
  3. * @author Administrator
  4. * json 数据操作
  5. */
  6. @Controller
  7. @RequestMapping("/user")
  8. public class UserLoginController {
  9. @RequestMapping("/addUser")
  10. @ResponseBody
  11. public User addUser(@RequestBody User user){
  12. System.out.println(user);
  13. return user;
  14. }
  15. @RequestMapping("/getUser")
  16. @ResponseBody
  17. public User getUser(User user){
  18. System.out.println(user);
  19. return user;
  20. }
  21. }

拦截器

基本概念

  1. SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理。比如通过它来进行权限验证,或者是来判断用户是否登陆等操作。对于springmvc拦截器的定义方式有两种方式:

实现接口:org.springframework.web.servlet.HandlerInterceptor

继承适配器org.springframework.web.servlet.handler.HandlerInterceptorAdapter

拦截器实现

实现HandlerInterceptor 接口

  • 接口实现类
  1. public class MyInterceptor1 implements HandlerInterceptor{
  2. /**
  3. * preHandle 在请求方法拦截前执行
  4. * 返回true 代表对当前请求进行放行处理
  5. */
  6. @Override
  7. public boolean preHandle(HttpServletRequest request,
  8. HttpServletResponse response, Object handler) throws Exception {
  9. System.out.println("handler方法之前执行MyInterceptor1-->preHandle方法...");
  10. return true; //继续执行action
  11. }
  12. /**
  13. * 请求执行后,生成视图前执行
  14. */
  15. @Override
  16. public void postHandle(HttpServletRequest request,
  17. HttpServletResponse response, Object handler,
  18. ModelAndView modelAndView) throws Exception {
  19. System.out.println("handler方法之后,生成视图之前执行MyInterceptor1-->postHandle方法...");
  20. }
  21. /**
  22. * 在请求方法执行后进行拦截
  23. */
  24. @Override
  25. public void afterCompletion(HttpServletRequest request,
  26. HttpServletResponse response, Object handler, Exception ex)
  27. throws Exception {
  28. System.out.println("handler方法执行完毕,生成视图后执行MyInterceptor1-->afterCompletion...");
  29. }
  30. }
  • 生效拦截器xml配置
  1. <!--配置方式一-->
  2. <mvc:interceptors>
  3. <!-- 使用bean定义一个Interceptor
  4. 直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求 -->
  5. <bean class="com.xxxx.springmvc.interceptors.MyInterceptor1" />
  6. </mvc:interceptors>
  1. <!--配置方式二-->
  2. <mvc:interceptors>
  3. <!-- 定义在 mvc:interceptor 下面 拦截所有test地址开头的请求-->
  4. <mvc:interceptor>
  5. <mvc:mapping path="/test/*.do" />
  6. <bean class="com.xxxx.springmvc.interceptors.MyInterceptor1" />
  7. </mvc:interceptor>
  8. </mvc:interceptors>

继承HandlerInterceptorAdapter

  1. 实际上最终还是HandlerInterceptor接口实现。
  • 子类实现类
  1. public class MyInterceptor2 extends HandlerInterceptorAdapter{
  2. /**
  3. * 重写preHandle 请求执行前执行
  4. */
  5. @Override
  6. public boolean preHandle(HttpServletRequest request,
  7. HttpServletResponse response, Object handler) throws Exception {
  8. System.out.println("handler方法之前执行MyInterceptor2-->preHandle方法...");
  9. return true;
  10. }
  11. }
  • 生效拦截器xml配置
  1. <!--配置方式二-->
  2. <mvc:interceptors>
  3. <!-- 定义在 mvc:interceptor 下面 拦截所有test地址开头的请求-->
  4. <mvc:interceptor>
  5. <mvc:mapping path="/test/*.do" />
  6. <bean class="com.xxxx.springmvc.interceptors.MyInterceptor2" />
  7. </mvc:interceptor>
  8. </mvc:interceptors>

多个拦截器实现

SpringMvc 框架支持多个拦截器配置,从而构成拦截器链,对客户端请求进行多次拦截操作。

  • 拦截器代码实现

这里参考MyInterceptor1、MyInterceptor2代码

  • 生效拦截器xml配置
  1. <mvc:interceptors>
  2. <mvc:interceptor>
  3. <!-- 拦截所有请求 -->
  4. <mvc:mapping path="/**" />
  5. <bean class="com.xxxx.springmvc.interceptors.MyInterceptor" />
  6. </mvc:interceptor>
  7. <mvc:interceptor>
  8. <!-- 拦截所有请求 -->
  9. <mvc:mapping path="/**" />
  10. <bean class="com.xxxx.springmvc.interceptors.MyInterceptor2" />
  11. </mvc:interceptor>
  12. </mvc:interceptors>

拦截器应用-非法请求拦截处理

使用拦截器完成用户是否登录请求验证功能

用户控制器-UserController定义

  1. /**
  2. *
  3. * @author Administrator
  4. * 模拟 用户操作
  5. */
  6. @Controller
  7. @RequestMapping("/user")
  8. public class UserController {
  9. @RequestMapping("/userLogin")
  10. public ModelAndView userLogin(HttpServletRequest request){
  11. ModelAndView mv=new ModelAndView();
  12. User user=new User();
  13. user.setUserName("admin");
  14. user.setUserPwd("123456");
  15. request.getSession().setAttribute("user", user);
  16. mv.setViewName("success");
  17. return mv;
  18. }
  19. @RequestMapping("/addUser")
  20. public ModelAndView addUser(){
  21. System.out.println("添加用户记录。。。");
  22. ModelAndView mv=new ModelAndView();
  23. mv.setViewName("success");
  24. return mv;
  25. }
  26. @RequestMapping("/delUser")
  27. public ModelAndView delUser(){
  28. ModelAndView mv=new ModelAndView();
  29. mv.setViewName("success");
  30. return mv;
  31. }
  32. @RequestMapping("/updateUser")
  33. public ModelAndView updateUser(){
  34. ModelAndView mv=new ModelAndView();
  35. mv.setViewName("success");
  36. return mv;
  37. }
  38. }

非法请求拦截器定义

  1. public class LoginInterceptor extends HandlerInterceptorAdapter{
  2. /**
  3. * 方法拦截前执行
  4. */
  5. @Override
  6. public boolean preHandle(HttpServletRequest request,
  7. HttpServletResponse response, Object handler) throws Exception {
  8. User user= (User) request.getSession().getAttribute("user");
  9. /**
  10. * 判断session user 是否为空
  11. */
  12. if(null==user){
  13. response.sendRedirect(request.getContextPath()+"/login.jsp");
  14. return false;
  15. }
  16. return true;
  17. }
  18. }

拦截器生效配置

  1. <!-- 拦截所有请求 -->
  2. <mvc:interceptors>
  3. <mvc:interceptor>
  4. <mvc:mapping path="/**" />
  5. <!--放行用户登录请求-->
  6. <mvc:exclude-mapping path="/user/userLogin"/>
  7. <bean class="com.xxxx.springmvc.interceptors.LoginInterceptor" />
  8. </mvc:interceptor>
  9. </mvc:interceptors>

RestFul URL

基本概念

  1. 模型-视图-控制器(MVC)是一个众所周知的以设计界面应用程序为基础的设计思想。
  2. Restful风格的API是一种软件架构风格,设计风格而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
  3. Restful风格中,用户请求的url使用同一个url而用请求方式:getpostdeleteput...等方式对请求的处理方法进行区分,这样可以在前后台分离式的开发中使得前端开发人员不会对请求的资源地址产生混淆和大量的检查方法名的麻烦,形成一个统一的接口。

在Restful风格中,现有规定如下:

  • GET(SELECT):从服务器查询,可以在服务器通过请求的参数区分查询的方式。

  • POST(CREATE):在服务器端新建一个资源,调用insert操作。

  • PUT(UPDATE):在服务器端更新资源,调用update操作。

  • PATCH(UPDATE):在服务器端更新资源(客户端提供改变的属性)。(目前jdk7未实现,tomcat7不支持)。

  • DELETE(DELETE):从服务器端删除资源,调用delete语句。

Spring Mvc 支持RestFul URL 风格设计

案例:如何在java构造没有扩展名的RESTful url,如 /forms/1?

SpringMvc是通过@RequestMapping @PathVariable annotation提供的,通过如@RequestMapping(value=”/blog /{id}”,method=RequestMethod.DELETE)即可处理/blog/1 的delete请求.

RestFul Url 映射地址配置实现

Get 请求配置

  1. /**
  2. *restful-->get 请求 执行查询操作
  3. * @param id
  4. * @return
  5. */
  6. @GetMapping("account/{id}")
  7. @ResponseBody
  8. public Account queryAccountById(@PathVariable Integer id){
  9. return accountService.selectById(id);
  10. }

Post请求配置

  1. /* restful-->post请求执行添加操作
  2. * @return
  3. */
  4. @PostMapping("account")
  5. @ResponseBody
  6. public Map<String,Object> saveAccount(@RequestBody Account account){
  7. int result = accountService.saveAccount(account);
  8. Map<String,Object> map=new HashMap<String,Object>();
  9. map.put("msg","success");
  10. map.put("code",200);
  11. if(result==0){
  12. map.put("msg","error");
  13. map.put("code",500);
  14. }
  15. return map;
  16. }

Put请求配置

  1. /* restful-->put 请求执行更新操作
  2. * @param id
  3. * @param account
  4. * @return
  5. */
  6. @PutMapping("account")
  7. @ResponseBody
  8. public Map<String,Object> updateAccount(@RequestBody Account account){
  9. int result = accountService.updateAccount(account);
  10. Map<String,Object> map=new HashMap<String,Object>();
  11. map.put("msg","success");
  12. map.put("code",200);
  13. if(result==0){
  14. map.put("msg","error");
  15. map.put("code",500);
  16. }
  17. return map;
  18. }

Delete请求配置

  1. /* restful-->delete 请求 执行删除操作
  2. * @param id
  3. * @return
  4. */
  5. @DeleteMapping("account/{id}")
  6. @ResponseBody
  7. public Map<String,Object> deleteAccount(@PathVariable Integer id){
  8. int result = accountService.delAccount(id);
  9. Map<String,Object> map=new HashMap<String,Object>();
  10. map.put("msg","success");
  11. map.put("code",200);
  12. if(result==0){
  13. map.put("msg","error");
  14. map.put("code",500);
  15. }
  16. return map;
  17. }

SpringMVC 全局异常统一处理

全局异常概念

  1. JavaEE 项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的、不可预知的异常需要处理。每个过程都单独处理异常,系统的代码耦合度高,工作量大且不好统一,维护的工作量也很大。
  2. SpringMvc 对于异常处理这块提供了支持,通过 SpringMvc 提供的全局异常处理机制,能够将所有类型的异常处理从各处理过程解耦出来,这样既保证了相关处理过程的功能较单一,也实现了异常信息的统一处理和维护。

全局异常实现方式Spring MVC 处理异常有 3 种方式

  1. 使用 Spring MVC 提供的简单异常处理器 SimpleMappingExceptionResolver;
  2. 实现 Spring 的异常处理接口 HandlerExceptionResolver 自定义自己的异常处理器;
  3. 使用@ExceptionHandler 注解实现异常处理;

异常处理实现

全局异常处理方式一

配置 SimpleMappingExceptionResolver 对象

  1. <bean
  2. class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
  3. <property name="defaultErrorView" value="error"></property>
  4. <property name="exceptionAttribute" value="ex"></property>
  5. <property name="exceptionMappings">
  6. <props>
  7. <prop key="com.xxxx.ssm.exception.BusinessException">error</prop>
  8. <prop key="com.xxxx.ssm.exception.ParamsException">error</prop>
  9. </props>
  10. </property>
  11. </bean>
  1. 使用 SimpleMappingExceptionResolver 进行异常处理,具有集成简单、有良好的扩展性、对已有代码没有入侵性等优点,但该方法仅能获取到异常信息,若在出现异常时,对需要获取除异常以外的数据的情况不适用。

全局异常处理方式二(推荐)

实现 HandlerExceptionResolver 接口

  1. public class MyExceptionHandler implements HandlerExceptionResolver {
  2. @Override
  3. public ModelAndView resolveException(HttpServletRequest request,
  4. HttpServletResponse response, Object handler, Exception ex) {
  5. Map<String,Object> map=new HashMap<String, Object>();
  6. map.put("ex", ex);
  7. ModelAndView mv=null;
  8. if(ex instanceof ParamsException){
  9. return new ModelAndView("error_param", map);
  10. }
  11. if(ex instanceof BusinessException){
  12. return new ModelAndView("error_business", map);
  13. }
  14. return new ModelAndView("error", map);
  15. }
  16. }
  1. 使用实现 HandlerExceptionResolver 接口的异常处理器进行异常处理,具有集成简单、有良好的扩展性、对已有代码没有入侵性等优点,同时,在异常处理时能获取导致出现异常的对象,有利于提供更详细的异常处理信息。

全局异常处理方式三

页面处理器继承 BaseController

  1. public class BaseController {
  2. @ExceptionHandler
  3. public String exc(HttpServletRequest request,HttpServletResponse
  4. response,Exception ex){
  5. request.setAttribute("ex", ex);
  6. if(ex instanceof ParamsException){
  7. return "error_param";
  8. }
  9. if(ex instanceof BusinessException){
  10. return "error_business";
  11. }
  12. return "error";
  13. }
  14. }
  1. 使用[@ExceptionHandler ](/ExceptionHandler ) 注解实现异常处理,具有集成简单、有扩展性好(只需要将要异常处理的 Controller 类继承于 BaseController 即可)、不需要附加Spring 配置等优点,但该方法对已有代码存在入侵性(需要修改已有代码,使相关类继承于 BaseController),在异常处理时不能获取除异常以外的数据。

未捕获异常的处理

  1. 对于 Unchecked Exception 而言,由于代码不强制捕获,往往被忽略,如果运行期产生了Unchecked Exception,而代码中又没有进行相应的捕获和处理,则我们可能不得不面对尴尬的 404 500……等服务器内部错误提示页面。
  2. 此时需要一个全面而有效的异常处理机制。目前大多数服务器也都支持在 Web.xml 中通过(Websphere/Weblogic)或者(Tomcat)节点配置特定异常情况的显示页面。修改 web.xml 文件,增加以下内容:
  1. <!-- 出错页面定义 -->
  2. <error-page>
  3. <exception-type>java.lang.Throwable</exception-type>
  4. <location>/500.jsp</location>
  5. </error-page>
  6. <error-page>
  7. <error-code>500</error-code>
  8. <location>/500.jsp</location>
  9. </error-page>
  10. <error-page>
  11. <error-code>404</error-code>
  12. <location>/404.jsp</location>
  13. </error-page>