SpringMVC对web层的支持笔记整理

目录

1. 什么是MVC

MVC是web层的一种设计模式 , 全称为 Model View Controller

  • Model : 数据模型 (接收和响应的数据 , 可以理解为对应的实体类)
  • View : 视图 , jsp和html也属于一种试图 , 用于数据的展示
  • Controller : 控制器 , 用于数据模型和试图的中转位置

2. SpringMVC概述

2.1. SpringMVC简单介绍

Spring Web MVC是基于Servlet API构建的原始Web框架 , 并从一开始就包含在Spring Framework中 , 正式名称"Sprnig Web MVC"来自其源模块spring-webmvc的名称 , 但它通常被成为"Spring MVC"

简而言之 , SpringMVC对Servlet进行封装 , 避免了繁琐的获取表单参数 , 多余的servlet服务类等代码

2.2. Spring对web层的支持

  • spring对web层的支持需要用到2个包 :
    • spring-web : spring对web层的支持包
    • spring-webmvc : springwebmvc的框架包
  • spring对web层的支持提供的技术 :
    • spring webmvc : springmvc框架
    • spring webFlux : spring webFluex框架
    • 这两个框架的作用一样 , 只是写法不同

3. SpringMVC的基本使用

3.1. 创建web工程

不做演示

3.2. 导入jar包

4个核心包 + 1个日志包 + spring-web + spring-webmvc + spring-aop 共计8个包

3.3. 创建并定义springmvc配置文件

	<!--    配置处理器映射器-->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

    <!--    处理器适配器-->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

    <!--    视图解析器-->
    <bean id="resourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--        配置前置-->
        <property name="prefix" value="/WEB-INF/pages/"/>
        <!--        配置后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--    配置自定义类 , 将ControllerTest交给Spring管理 , 并加入容器-->
    <bean name="/test" class="com.springMVCTest.controller.ControllerTest"/>
</beans>

3.4. 创建Controller

public class ControllerTest implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("success");
        return modelAndView;
    }
}

3.5. 编写一个页面

<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>成功</h1>
</body>
</html>

3.6. 配置web.xml

    <!--    配置核心控制器 加载springmvc的配置文件-->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <!--初始化参数加载配置文件
			key的写法是固定的必须是contextConfigLocation , 不能写其他-->
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springMVC-config.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

4. SpringMVC的执行流程

流程一共分为2大阶段

  1. Tomcat启动阶段
    1. Tomcat启动并加载web.xml
    2. web.xml配置了一个servlet
      1. 如果servlet中的<load-on-startup>1</load-on-startup>指定为1 , 则在Tomcat启动时Servlet直接实例化并且初始化方法将会执行
    3. servlet只要初始化就会加载springmvc的配置文件
    4. springmvc配置文件加载 , 会将配置的4个bean标签对应的对象实例化好并放到容器中
  2. 浏览器访问阶段
    1. 浏览器访问http://localhost:8080/test通过域名端口找到了本机域名端口
    2. 然后通过/test访问 , 因为<url-pattern>/</url-pattern>参数配置为/ , 此时请求会到达DispatcherServlet , 说明请求到达了springmvc
    3. 通过/test , 就可以从容器中获取对应的Controller , 直接执行controller方法
    4. 返回内容给浏览器显示

图解 :

![QQ图片20200207015036](C:\Users\JAVASM\Desktop\SpringMVC笔记整理 .assets\QQ图片20200207015036.png)

5. SpringMVC的内部流程

流程文字解释 :

  1. 请求/test到达了DispatcherServlet
  2. DispatcherServlet 会携带请求找到处理器映射器BeanNameUrlHandlerMapping , 通过URL当做Bean的name属性值从容器中找到ControllerTest
  3. 处理器映射器BeanNameUrlHandlerMapping 找到之后 , 将找到的结果返回给DispatcherServlet `
  4. DispatcherServlet把执行的内容给处理器适配器SimpleControllerHandlerAdapter , 处理器适配器去调用对应的controller方法 , 获得ModelAndView
  5. 处理器适配器SimpleControllerHandlerAdapter 拿到ModelAndView之后 , 把结果给了DispatcherServlet
  6. 处理器适配器DispatcherServlet 拿到返回的结果之后 , 将结果给视图解析器InternalResourceViewResolver拼接视图的前后缀 , 然后就拿到了真实的视图地址
  7. 把地址返回给DispatcherServlet , DispatcherServlet 拿到真正视图地址 , 返回的Model给模版引擎
  8. 使用模版引擎技术渲染页面 , 并返回给前端

图解 :

![springmvc执行流程原理](C:\Users\JAVASM\Desktop\SpringMVC笔记整理 .assets\springmvc执行流程原理.jpg)

了解不同的写法使用不同的处理器映射器和不同的处理器适配器

  • 总结 :
    • dispatcherServlet : 是一个中转站 , 所有的功能都需要dispatcherServlet 做中转 , 这个servlet不能少 , dispatcherServlet 是springmvc的核心核心控制器
    • 处理器映射器 : 通过请求才能找到对应的bean
    • 处理器适配器 : 主要执行对应bean的方法
    • 试图解析器 : 拼接前后缀 , 找到视图的真实地址
    • jsp : 是一个模版引擎 , 是渲染数据使用的 使用EL表达 jstl标签

6. 实现一个类中不同的请求做不同的事

问题 : 定义的Controller因为只有一个实现 , 因此一个controller只能做一件事 , 并且每次都需要配置Bean

解决 : 通过包扫描和注解的方式完成一个类中 , 不同的请求做不同的事情

6.1. 编写Controller

  • 使用包扫描的方式将Controller添加入容器 , 需要在类上添加注解@Controller这样aop扫描会将当前类作为controller加入容器
  • 注意 : @Controller@Component的一个延伸 , 当类作为Controller时不能使用@Component , 否则会报错
//@Component 使用Component注解将本类加入容器中 ,
//在web层中又一个Component注解的延伸 : @Controller
//@Controller可以通过aop扫描将当做一个controller
//注意 : 在web层只能使用@Controller不能使用@Component否则会报错
//使用@Controller需要配置包扫描
@Controller
public class ControllerTest2 {

    //GetMapping注解 : 此方法只接受get请求
    //注解参数 : 表示请求路径
  
    //登陆操作
    @GetMapping("login")
    private ModelAndView login() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("msg", "登录成功");
        modelAndView.setViewName("success");
        return modelAndView;
    }

    //注册操作
    @GetMapping("register")
    private ModelAndView register() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("msg", "注册成功");
        modelAndView.setViewName("success");
        return modelAndView;
    }
}

6.2. 编写配置文件

    <!--    配置包扫描-->
    <context:component-scan base-package="com.springMVCTest.controller"/>

    <!--处理器映射器 根据请求路径去找到对应的映射-->
     <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
    <!--处理器适配器 根据请求路径-->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>

    <!--    视图解析器-->
    <bean id="resourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--        配置前置-->
        <property name="prefix" value="/WEB-INF/pages/"/>
        <!--        配置后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>

6.3. 配置优化

开启mvc注解驱动

    <!--    配置包扫描-->
    <context:component-scan base-package="com.springMVCTest.controller"/>


    <!--    使用这个标签替代处理器映射器和处理器适配器-->
    <mvc:annotation-driven/>

    <!--    视图解析器-->
    <bean id="resourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--        配置前置-->
        <property name="prefix" value="/WEB-INF/pages/"/>
        <!--        配置后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>

7. springMVC请求接收

常用的http请求

  • get : get请求 springMVC中对应的是 @GetMapping
  • post : post请求 springMVC中对应的是 @PostMapping
  • delete : delet请求 springMVC中对应的是 @DeleteMapping
  • put : put请求 springMVC中对应的是 @PutMapping
  • @RequestMapping : 默认情况下可以用于任何请求方式

8. 参数的接收与封装

SpringMVC接受参数的方式 :

  1. key=value方式
  2. json方式
  3. 文件接收

8.1. key=value形式接收参数

只要参数的接受方式是以key=value的形式接收 , 那么所有的请求方法都可以按如下方法使用

注意 : 表单的name属性就是请求参数的可以 , 需要和方法方法的参数名一致 , 此时会自动将数据封装上

8.1.1. 基本数据类型和字符串

collector :

    @GetMapping("basicParam")
    public ModelAndView basicParam(int age, String name) {
        System.out.println(age);
        System.out.println(name);
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("success");
        return modelAndView;
    }

jsp :

<h2>key = value 基本类型和字符串的接收</h2>
<form action="/basicParam">
    年龄 <input type="text" name="age"><br>
    姓名 <input type="text" name="name">
    <input type="submit" value="提交">
</form>

8.1.2. 数组

collector :

    @GetMapping("arrayParam")
    public ModelAndView arrayParam(String[] check) {
        System.out.println(Arrays.toString(check));
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("success");
        return modelAndView;
    }

jsp :

<h2>key = value 基本类型和字符串的接收</h2>
<form action="/arrayParam">
    选择 :
    <input type="checkbox" name="check" value="A">A
    <input type="checkbox" name="check" value="B">B
    <input type="checkbox" name="check" value="C">C<br>
    <input type="submit" value="提交">
</form>

8.1.3. 对象类型

注意 : 使用对象类型接收数据 , 表单的name属性要和实体类中的属性名一致 , 和controller方法的接受对象名没有关系

创建对象 :

public class User {
    private String name;
    private int age;
    private String sex;
    private String address;


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

controller :

    @GetMapping("objectParam")
    public ModelAndView objectParam(User user) {
        System.out.println(user);
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("success");
        return modelAndView;
    }

jsp :

<h2>key = value 对象接收</h2>
<form action="/objectParam">
    <!--name属性的值要与实体类的属性值相同-->
    姓名<input type="text" name="name"/><br>
    性别<input type="text" name="sex"/><br>
    年龄<input type="text" name="age"/><br>
    地址<input type="text" name="address"/><br>
    <input type="submit" value="提交">
</form>

8.1.4. 包装类类型 ( 不重要 )

包装类 :

public class UserExt {
    private User user;

    private List<User> list;

    private Map<String, User> map;

    public Map<String, String> getMap() {
        return map;
    }

    public void setMap(Map<String, User> map) {
        this.map = map;
    }

    public List<User> getList() {
        return list;
    }

    public void setList(List<User> list) {
        this.list = list;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public String toString() {
        return "UserExt{" +
                "user=" + user +
                ", list=" + list +
                ", map=" + map +
                '}';
    }
}

controller :

    @GetMapping("extParam")
    public ModelAndView extParam(UserExt userExt) {
        System.out.println(userExt);
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("success");
        return modelAndView;
    }

jsp :

<h2>key = value 包装类接收</h2>
<form action="/objectParam">
    姓名<input type="text" name="user.name"/><br>
    性别<input type="text" name="user.sex"/><br>
    年龄<input type="text" name="user.age"/><br>
    地址<input type="text" name="user.address"/><br>
    <input type="submit" value="提交">
</form>

8.1.5. List集合类型 ( 不重要 )

controller :

    @GetMapping("listParam")
    public ModelAndView listParam(UserExt userExt) {
        userExt.getList().forEach(user -> System.out.println(user));
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("success");
        return modelAndView;
    }

jsp :

<h2>key = value list接收</h2>
<form action="/objectParam">
    <input type="text" name="list[0].name"/><br>
    <input type="text" name="list[0].age"/><br>
    <input type="text" name="list[1].name"/><br>
    <input type="text" name="list[1].age"/><br>
    <input type="text" name="list[2].name"/><br>
    <input type="text" name="list[2].age"/><br>
    <input type="text" name="list[3].name"/><br>
    <input type="text" name="list[3].age"/><br>
    <input type="submit" value="提交">
</form>

8.1.6. Map集合类型 ( 不重要 )

controller :

    @GetMapping("mapParam")
    public ModelAndView mapParam(UserExt userExt) {
        System.out.println(userExt.getMap());
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("success");
        return modelAndView;
    }

jsp :

<h2>key = value map接收</h2>
<form action="/objectParam">
    <input type="text" name="map['a']"/><br>
    <input type="text" name="map['b']"/><br>
    <input type="text" name="map['c']"/><br>
    <input type="text" name="map['d']"/><br>
    <input type="submit" value="提交">
</form>

8.2. JSON格式字符串

  • JSON格式接收请求一般用于Post请求和Put请求 , 因为传递的josn格式是一个字符串 , 需要放到请求体中 , 供java代码直接使用对象接收
  • 后端获取到json字符串需要通过@RequestBody从请求体中获取json格式字符串封装到对象内
  • 将json字符串转换为对象 , 需要依赖于第三方的json和对象转换包
    • 第三方转换包有 : json-lib(已淘汰) fastJson jackson gson json-b
  • springMVC默认支持jsckson , 如果是jackson不需要任何配置 , 导入包即可 , 如果不是jackson需要配置
  • JSON格式传递参数不会乱码
@Controller
public class JSONStringReceiveController {
  
    @PostMapping("receiveJson")//@RequestBody 表示从请求体中获取json格式字符串封装到对象内
    public ModelAndView receiveJson(@RequestBody String strJson) throws IOException {
        //获取的字符串无法直接转换为对象 , 需要依赖于第三方的json和对象转换包
        //springmvc默认支持jackson , 如果使用jackson转换对象 , 不需要任何配置
        ObjectMapper objectMapper = new ObjectMapper();
        User user = objectMapper.readValue(strJson, User.class);
        System.out.println(user);
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("success");
        return modelAndView;
    }
  
}

//==============使用jackson自动将json封装为对象===========
@Controller
public class JSONStringReceiveController2 {
  
    @PostMapping("receiveJson")//@RequestBody 表示从请求体中获取json格式字符串封装到对象内
    public ModelAndView receiveJson(@RequestBody User user) throws IOException {
        //获取的字符串无法直接转换为对象 , 需要依赖于第三方的json和对象转换包
        //springmvc默认支持jackson , 如果使用jackson转换对象 , 不需要任何配置
        //ObjectMapper objectMapper = new ObjectMapper();
        //User user = objectMapper.readValue(strJson, User.class);
        System.out.println(user);
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("success");
        return modelAndView;
    }
  
}

8.3. Rest方式接收参数

9. 乱码问题

9.1. get请求接收汉字参数乱码

  • get请求在Tomcat8以上没有乱码问题 , 如果使用Tomcat7会有乱码

  • 根据String的构造方法

    String s = new String(username.getBytes("ISO-8859-1"),"utf-8")
    
  • 修改配置文件

    /**
     修改 Tomcat中的config目录下 server.xml
     添加  URIEncoding="utf-8"
    
     注意点:如果有 useBodyEncodingForURI="true" 就删除
    
     例如:
         <Connector port="8080" protocol="HTTP/1.1"
            connectionTimeout="20000"
            redirectPort="8443"
            disableUploadTimeout="true"
            executor="tomcatThreadPool"
            URIEncoding="utf-8"/>
    
     */
    

9.2.post请求接收汉字参数乱码

  • 解决方式
    • 和get方法一样 , 使用String的构造函数解决 ( 了解即可 )
    • 使用Spring提供的过滤器一次性解决
<!--    使用spring提供的编码过滤器解决post请求的乱码问题-->
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>characterEncodingFilter</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

提问 : post一定会出现乱码么?

不一定会 , 需要根据post请求的位置判断 ,
**如果post请求的位置在请求体中 ( 参数不拼接到url后面 ) 会出现乱码 , **
如果在请求头中 ( 参数拼接到url后面 ) 不会出现乱码

10. 获取ServletAPI

想要得到最原始的HttpservletRequestHttpServletResponse直接在方法里写形参即可 ,

然后就可在代码中使用

    @GetMapping("returnView")
    public String returnView(HttpServletRequest request) {
		//可以拿对象随意操作
        request.setAttribute("msg", "request内数据");
        return "success";
    }

11. Controller的返回值

11.1. ModelAndView作为返回值

    /*
     * 返回值ModelAndView
     * 携带数据返回视图(JSP页面)
     * 在JSP页面可以用EL表达式输出
     * 默认请求是转发
     * */
    @GetMapping("ReturnModelAndView")
    public ModelAndView ReturnModelAndView() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("msg", "ModelAndView携带的数据");
        modelAndView.setViewName("success");
        return modelAndView;
    }

11.2. 字符串作为返回值

返回值是字符串共有3中用法 :

  1. 返回视图
    • 返回的字符串携带数据的方式
      1. 放到域中 , 所有域都可以
      2. 放到Model中 , 本质也是放到域中
      3. 放到Map中 , 本质也是放到域中
  2. 返回字符串本身
    • 返回字符串本身有可能产生乱码 , @GetMapping等注解的produces属性可以设置返回值的样式和编码格式
      • produces = "text/html;charset=utf-8" 可以识别html标签
      • produces = "application/json;charset=utf-8"可以识别json
      • produces = "charset=utf-8"设置编码格式
    • @ResponseBody : 通过HttpServletResponse输出数据 , 数据的返回值以响应体返回给页面 , 而不是页面
  3. 转发或重定向
    • 返回字符串做转发 : forward: + 转发的地址 , 注意加"/"
    • 返回字符串做重定向 : redirect + 转发的地址 , 注意加"/"

11.2.1. 返回字符串作为 : 视图

返回视图同时携带数据 :

    //返回视图-HttpServletRequest
    @GetMapping("returnView1")
    public String returnView1(HttpServletRequest request) {

        request.setAttribute("msg", "request内数据");
        return "success";
  
    }

    //返回视图-Model
    @GetMapping("returnView2")
    public String returnView2(Model model) {

        model.addAttribute("msg", "model内数据");
        return "success";
  
    }

    //返回视图-Map
    @GetMapping("returnView3")
    public String returnView3(Map<String, String> map) {

        map.put("msg", "map内数据");
        return "success";
  
    }

11.2.2. 返回字符串作为 : 字符串

    /*
	* 返回字符串本身
    * GetMapping注解的produces属性可以设置返回值的样式 ,
    * text/html可以识别html标签 ,
    * application/json可以识别json,
    * charset=utf-8设置编码格式
    * @ResponseBody : 通过HttpServletResponse输出数据 , 数据的返回值以相应体返回给页面 , 而不是页面
    */
    @GetMapping(value = "returnStringSlf", produces = "text/html;charset=utf-8")
    @ResponseBody  //数据的返回值以相应体返回给页面 , 而不是页面
    public String returnStringSlf() {
        //可以返回中文 , 但是会乱码 , 需要在produce属性中添加charset=utf-8
        //String json="{\"name\":\"aa\",\"age\":\"10\"}";
        //以json格式返回字符串 , 需要在produce属性中添加application/json
        //return json;
  
        //直接返回字符串success
        return "success";
    }

统一设置避免乱码 :

<mvc:annotation-driven>  
    <mvc:message-converters>  
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">  
            <property name="supportedMediaTypes">  
                <list>  
                    <span style="white-space:pre"></span>
                    <value>text/html;charset=UTF-8</value>  
                    <value>application/json;charset=UTF-8</value>  
                    <value>*/*;charset=UTF-8</value>  
                </list>  
            </property>  
  
        </bean>  
    </mvc:message-converters>  
</mvc:annotation-driven>  

11.2.3. 返回字符串作为 : 转发或重定向

    //返回字符串做转发 : forward: + 转发的地址 , 注意加"/"
    @GetMapping(value = "returnStrForwardOrRedirect1")
    public String returnStrForwardOrRedirect1() {
        //请求转发到returnStringSlf , 转发 : 不改变地址栏 , 服务器内部行为
        return "forward:/returnStringSlf";
    }


    //返回字符串做重定向 : redirect: + 转发的地址 , 注意加"/"
    @GetMapping(value = "returnStrForwardOrRedirect2")
    public String returnStrForwardOrRedirect2() {
        //页面重定向至returnStringSlf , 重定向 : 改变地址栏 , 浏览器行为
        return "redirect:/returnStringSlf";
    }

11.3. 返回void ( 无返回值 )

    /*
    * 返回void
    * 默认找的是以请求路径为视图名称的jsp页面
    * */
    @GetMapping("returnVoidController")
    public void returnVoidController(){
        System.out.println("xxxxx");
    }

11.4. 返回对象

  • springMVC能够将对象转换为json但是需要依赖Jackson
  • @ResponseBody : 把处理器对象转换为json后 , 返回给浏览器 , 位置位于方法的定义上面
    /*
    * 处理器方法返回一个user , 通过框架转为json , 响应请求
    * @ResponseBody
    * 作用 : 把处理器方法返回对象转为json后 , 通过HttpServletResponse输出给浏览器
    * 位置在方法的定义上面 , 和其他注解没有先后顺序
    * */
    @GetMapping("returnUser")
    @ResponseBody
    public User returnUser() {
        User user = new User();
        user.setName("aaa");
        user.setAge(10);
        return user;//会被框架转换为json
    }

返回对象框架的处理流程 ( 了解 ) :

  1. 框架会把返回User类型 , 调用框架中的ArrayList<HttpMessageConverter>中每个类的canWrite()方法 , 检查哪个HttpMessageConverter接口的实现类能够处理User类型的数据 , 最终找到MappingJacksong2HttpMessageConverter
  2. 框架会调用实现类的write()方法 , MappingJacksong2HttpMessageConverterwrite()方法 , 将User对象转为Json , 调用Jackson的ObjcetMapper实现转为json
  3. 框架会调用@ResponseBody把2的结果数据输出到浏览器 , ajax请求处理完成

11.5. 返回ResponseEntity

ResponseEntity使用泛型 , 说明任何类型都可以包含在ResponseEntity中返回

ResponseEntity默认直接就是json , 但是需要Jackson支持

注意 : 如果直接返回对象 , 想要返回json格式字符串 , 有2种选择

  1. 方法直接返回对象 , 此时需要注解@ResponseBody , 需要添加jackson支持
  2. 方法返回ResponseEntity , 把需要返回的对象放到ResponseEntity中 , 此时不需要添加@ResponseBody , 需要添加jackson支持
    /*
    * 返回ResponseEntity
    *   ResponseEntity使用泛型 , 说明任何类型都可以包含在ResponseEntity中返回
    *   默认直接就是json格式 , 但是需要jackson支持
    * 
    * 注意 : 如果直接返回对象 , 想要返回json格式字符串的话 , 有2种选择
    * 1. 直接返回对象 , 需要@ResponseBody并添加jackson支持
    * 2. 返回ResponseEntity , 把要返回的对象放到ResponseEntity中 , 不需要添加@ResponseBody , 需要添加jackson
    * */
    @GetMapping("returnEntity")
    public ResponseEntity returnEntity() {
        User user = new User();
        user.setAge(11);
        user.setName("aa");
        return ResponseEntity.ok(user);
    }

12. Rest风格

Rest风格规范 :

  • 对于请求方式规范 , 不同的操作使用不同的请求方式
    • get : 一般是获取数据
    • post : 登陆和添加数据
    • put : 一般是修改
    • delete : 删除操作
  • 对于不同的状态码的规范
    • 状态码
    • 相应信息
    • 结果集
  • 参数接收/请求路径
    • 将参数拼接在了URL中 , 参数成为了请求路径的一部分

12.1. Rest风格参数获取

获取路径中的参数值使用@PathVariable , 如果名字一样直接获取即可 , 没有先后顺序 , 如果参数名和路径名不一致 , 需要通过@PathVariable的参数指定获取路径上的值 , 也不分先后顺序

    @GetMapping("/restPath/{name}/{age}")
    public void restPath(@PathVariable String name, @PathVariable int age) {
        System.out.println(name);
        System.out.println(age);

    }
    @GetMapping("/restPath/{name}/{age}")
    public void restPath(@PathVariable("name") String username, @PathVariable("age") int userage) {
        System.out.println(name);
        System.out.println(age);

    }

13. 文件上传

目前市场流行的文件上传分为2中 :

  • 提交表单(包含异步)
  • Base64格式

13.1.java代码编写方式

  • 提交表单上传
    • Servlet3.0 之前原始的写法
    • Servlet3.0 之后part的写法
    • fileupload.jar + commons.io.jar的写法
    • fileupload.jar + commons.io.jar继承SpringMVC的写法
  • Base64上传
    • 写法很单一

13.2. 提交变单上传的三要素

  • post请求
  • 有一个input type=file标签
  • enctype=multipart/form-data

13.3. part方式上传文件

这种方式 不需要导入任何包 , 也不要配置任何视图解析器

  • 编写Controller

        @PostMapping("uploadController")
        @ResponseBody
        public String upload(HttpServletRequest request) throws IOException, ServletException {
            //从前端读取文件
            Part pic = request.getPart("pic");
            //找到写的位置
            String realPath = request.getServletContext().getRealPath("/uploads/");
            File file = new File(realPath);
            //如果位置不存在则创建
            if (!file.exists()) {
                file.mkdirs();
            }
            //文件写入
            pic.write(realPath + pic.getSubmittedFileName());
            return "http://localhonst:8080/uploads/" + pic.getSubmittedFileName();
        }
    }
    
  • 编写前端页页面

    <form action="/upLoadServlet" enctype="multipart/form-data" method="post">
        <input type="file" name="pic">
        <input type="submit" value="上传">
    </form>
    
  • 添加配置信息

    <!--        开启springmvc part方式文件上传-->
            <multipart-config/>
    
    <!-- 也可以写的更详细些 : -->
           <!--可以直接复制  单位byte-->
            <multipart-config>
                <max-file-size>20848820</max-file-size>
                <max-request-size>418018841</max-request-size>
                <file-size-threshold>1048576</file-size-threshold>
            </multipart-config>
    

13.4. 上传文件重名处理

  • 为了防止图片重名 , 可以对上传的文件进行重命名
  • 重命名的方式 :
    • UUID
    • 时间戳
      • 毫秒值
      • 纳秒值
    • 建立多个文件夹

13.4.1. 使用UUID重命名文件

  1. 先获取文件后缀名
  2. 生成一个uuid
  3. 拼接uuid和后缀名 , 获取新文件名
  4. 文件写入

代码 :

@Controller
public class SpringUpLoadController {
    @PostMapping("uploadController")
    @ResponseBody
    public String upload(HttpServletRequest request) throws IOException, ServletException {
        //从前端读取文件
        Part pic = request.getPart("pic");
        //找到写的位置
        String realPath = request.getServletContext().getRealPath("/uploads/");
        File file = new File(realPath);
        //如果位置不存在则创建
        if (!file.exists()) {
            file.mkdirs();
        }

        //声明一个uuid
        String uuid = UUID.randomUUID().toString();
        //获得文件后缀名
        String ext = StringUtils.getFilenameExtension(pic.getSubmittedFileName());
        //拼接uuid和文件后缀名 , 生成新的文件名
        String fileName = uuid + "." + ext;
        //文件写入
        pic.write(realPath + fileName);
  
        return "http://localhonst:8080/uploads/" + pic.getSubmittedFileName();
    }

13.4.2. 使用毫秒值 , 纳秒值重命名文件

@Controller
public class SpringUpLoadController {
    @PostMapping("uploadController")
    @ResponseBody
    public String upload(HttpServletRequest request) throws IOException, ServletException {
        //从前端读取文件
        Part pic = request.getPart("pic");
        //找到写的位置
        String realPath = request.getServletContext().getRealPath("/uploads/");
        File file = new File(realPath);
        //如果位置不存在则创建
        if (!file.exists()) {
            file.mkdirs();
        }

        //获取毫秒值
        long id = System.currentTimeMillis();
        //获取纳秒值
        //long id = System.nanoTime();
        //获得文件后缀名
        String ext = StringUtils.getFilenameExtension(pic.getSubmittedFileName());
        //文件写入
        pic.write(realPath );

        return "http://localhonst:8080/uploads/" + pic.getSubmittedFileName();
    }

13.5. 目录打散

目录打散 : 创建多个目录分别存储文件

    @PostMapping("uploadController2")
    @ResponseBody
    public String upload2(HttpServletRequest request) throws IOException, ServletException {
        //从前端读取文件
        Part pic = request.getPart("pic");
        //找到写的位置
        String realPath = request.getServletContext().getRealPath("/");
        //声明一个uuid
        String uuid = UUID.randomUUID().toString();
        //获得文件后缀名
        String ext = StringUtils.getFilenameExtension(pic.getSubmittedFileName());
        //获取uuid的哈希值
        int hashCode = uuid.hashCode();
        //根据哈希值获取第一个文件夹的名字
        int dir1 = hashCode & 0xf; //0--15
        //获取第二个文件夹的名字
        int dir2 = dir1 >> 4;  //0-15
        //设置文件最终保存地址
        String finalFilePath = realPath + "/" + dir1 + "/" + dir2 + "/";
        //获取文件夹 , 文件夹不存在则创建
        File file = new File(finalFilePath);
        if (!file.exists())
            file.mkdirs();
        //拼接uuid和文件后缀名 , 生成新的文件名
        String fileName = uuid + "." + ext;
        //文件写入
        pic.write(finalFilePath + fileName);

        return "http://localhonst:8080/uploads/" + dir1 + "/" + dir2 + "/" + fileName;
    }

13.6. 多文件上传

controller :

    @PostMapping("uploadController3")
    @ResponseBody
    public String upload3(HttpServletRequest request) throws IOException, ServletException {
        //从前端读取文件
        Collection<Part> parts = request.getParts();
        parts.forEach(part -> {
            //找到写的位置
            String realPath = request.getServletContext().getRealPath("/");
            //声明一个uuid
            String uuid = UUID.randomUUID().toString();
            //获得文件后缀名
            String ext = StringUtils.getFilenameExtension(part.getSubmittedFileName());
            //获取uuid的哈希值
            int hashCode = uuid.hashCode();
            //根据哈希值获取第一个文件夹的名字
            int dir1 = hashCode & 0xf; //0--15
            //获取第二个文件夹的名字
            int dir2 = dir1 >> 4;  //0-15
            try {
                part.write(realPath + uuid + "." + ext);
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        return null;
    }

jsp :

<form action="/upLoadServlet" enctype="multipart/form-data" method="post">
    <input type="file" name="pic" multiple>
    <input type="submit" value="上传">
</form>

13.7. springMVC方式上传文件

这种方式相较之前比较麻烦 , 需要导包和配置多媒体视图解析器

  • 导入jar包

    导入common-fileupload.jar commons-io

  • 编写Controller

    在方法的形式参数位置 , 定义一个MultipartFile 参数名称和前端传递的input标签的name属性值一致

    @Controller
    public class SpringUpLoadController {
    
        @PostMapping("uploadByIO")
        public String uploadByIO(HttpServletRequest request, MultipartFile pic) throws IOException {
            String realPath = request.getServletContext().getRealPath("/file/");
            File file = new File(realPath);
            if (!file.exists())
                file.mkdirs();
            String uuid = UUID.randomUUID().toString();
            String filenameExtension = StringUtils.getFilenameExtension(pic.getOriginalFilename());
            String filePath = realPath + uuid + "." + filenameExtension;
    
            pic.transferTo(new File(filePath));
    
            return "success";
        }
    
  • 编写前端

    <form action="/uploadByIO" enctype="multipart/form-data" method="post">
        <input type="file" name="pic" >
        <input type="submit" value="上传">
    </form>
    
  • 配置多媒体视图解析器

    <!--    配置多媒体试图解析器-->
        <bean id="commonsMultipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
    
    

14. 文件下载

14.1. 文件下载方式一 ( 不建议使用 )

直接将连接传给前端 ( 不建议使用 ) , 如果浏览器可以解析则直接浏览 , 不能解析则直接下载

弊端 : 不能计算下载次数 , 对于那些不懂电脑的人 , 不直到使用Ctrl+s或右键另存为

演示 :

添加需要下载的文件 :

在web下创建文件夹 , 在文件夹下存放需要下载的文件

直接使用资源路径去下载 :

<h2>下载</h2>
  <a href="/download/a.txt">下载a</a>
  <a href="/download/b.txt">下载b</a>
  <a href="/download/c.txt">下载c</a>

修改springmvc配置文件 :

    <!--开启静态资源-->
    <mvc:default-servlet-handler/>

14.2.文件下载方式二

直接下载文件 , 不需要浏览器解析

好处 : 任何文件下载都可以通过弹窗保存 , 可以统计下载次数

文件下载过程中 , java程序的功能 :

  1. 从文件存储位置读取文件
  2. 把读取的文件写到浏览器

controller :

    @GetMapping("download")
    public ResponseEntity<byte[]> download(HttpServletRequest request) throws IOException {
        //从文件夹读取文件
        String filePath = request.getServletContext().getRealPath("/download/a.txt");
        FileInputStream fileInputStream = new FileInputStream(filePath);
        byte[] bytes = new byte[fileInputStream.available()];
        fileInputStream.read(bytes);

        //写文件
        //调起浏览器下载功能 (通过响应头告知浏览器这个请求是一个下载)

        //1. 设置请求头
        HttpHeaders httpHeaders = new HttpHeaders();
        //httpHeaders第一个可以随意设置 , 不管设置什么最后对会变为"attachment"
        //第二个参数设置文件名 , 有时候会出现乱码 , 就需要设置URLEncoder.encode("文件名","编码格式") 解决乱码
        httpHeaders.setContentDispositionFormData("attachment", URLEncoder.encode("a.txt","utf-8"));

        //通过ResponseEntity设置响应头并返回数据 第一参数为返回数据 , 第二个参数为响应头 , 第三个参数为响应状态码
        ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(bytes, httpHeaders, HttpStatus.OK);

        return responseEntity;
    }

jsp :

<h2>下载</h2>
  <a href="/download">下载a</a>

15. SpringMVC类型转换问题

15.1. Date类型

15.1.1. 型以key=value形式传参

  • 第一种方式 :

    @DateTimeFormat(pattern = "yyyy-MM-dd") : 可用于方法形参的位置 , 目的是解决key=value参数形式Date日期格式转换

    参数是Date类型则在参数前添加注解@DateTimeFormat(pattern = "yyyy-MM-dd")

        @GetMapping("dataFormat")
        public String dataFormat(String name, @DateTimeFormat(pattern = "yyyy-MM-dd") Date date) {
            System.out.println(date);
            return "success";
        }
    

    参数是对象 :

    在对象对应的参数上写注解@DateTimeFormat(pattern = "yyyy-MM-dd")

    public class User {
        private String name;
    
        @DateTimeFormat(pattern = "yyyy-MM-dd")
        private Date date;
    
        //get set tosring
    }
    
  • 第二种方式 :

    自定义类型转换器convert :

    1. 自定义一个类实现Convert接口 , 重写方法
    2. 配置自定义类

    自定义Convert :

    import org.springframework.core.convert.converter.Converter;
    
    //converter的2个泛型表示从a泛型到b泛型
    public class TimeConvert implements Converter<String, Date> {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
    
        @Override
        //s是前端传来日期格式的字符串
        public Date convert(String s) {
            Date date = null;
            try {
                date = simpleDateFormat.parse(s);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return date;
        }
    
    }
    

    配置自定义类 :

      <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
            <property name="converters">
                <set>
                    <bean class="自定义的convert地址"/>
                </set>
            </property>
        </bean>
    
    <!--    注解驱动 conversion-service="conversionService"设置全局-->
        <mvc:annotation-driven conversion-service="conversionService"/>
    

15.1.2. 以json形式传参

如果传递的是一个json , @DateTimeFormat处理方式失效

处理json默认使用jackson , 只需要导入jar包即可 , 默认的接收格式为yyyy-MM-dd , 用此格式不需要添加注解 , 使用其他格式需要添加注解

自定义格式一 :

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date date;

自定义格式二 :

    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper" ref="objectMapper"/>
            </bean>

        </mvc:message-converters>
    </mvc:annotation-driven>

    <bean id="objectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"
          p:indentOutput="true"
          p:simpleDateFormat="自定义格式"
      />

15.2. LocalDateTime类型

15.2.1. 以key=vlaue形式传参

  • 第一种方式 :

    在对应的参数上添加注释@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")可以自动转换格式

    public class User {
        private String name;
    
        //必须加上HH:mm:ss否则会报错
        @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        private LocalDateTime localDateTime;
    

    //get set tostrign

- 第二种方式 :

  自定义类型转换器convert

  convert :

  ```java
  public class LocalDateTimeConvert implements Converter<String, LocalDateTime> {

      @Override
      public LocalDateTime convert(String s) {
          LocalDateTime parse = LocalDateTime.parse(s, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
          return parse;
      }
  }

配置文件 :

      <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
          <property name="converters">
              <set>
                  <bean class="com.test.convert.LocalDateTimeConvert"/>
              </set>
          </property>
      </bean>

      <mvc:annotation-driven conversion-service="conversionService"/>

15.2.2. 以json形式传参

默认情况下 , 使用JsonFormate注解 , 封装报错 , 返回的内容指定的格式也失效

注意 : 如果使用java8的日期格式 , 需要添加一个jackson的支持包 jsr310

导入jsr310之后 , 不需要做任何配置 , 只写使用@JsonFormate注解 , 接收和响应都会按照指定的格式生效

public class User {
    private String name;

    //必须加上HH:mm:ss否则会报错
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime localDateTime;


	//get set tostrign

16. 静态资源拦截

SpringMVC默认对静态资源有拦截 ( html css js 图片 字体 多媒体 图标…)

<url-pattern></url-pattern>标签中设置值来实现拦截

<url-pattern> </url-pattern>取值 :

  • / : 拦截所有静态资源 , jsp除外
  • /* : 拦截所有静态资源 , 包括jsp

16.1. 静态资源拦截的解决方式

16.1.1. 使请求不进入SpringMVC ( 不用 )

SpingMVC默认对静态资源有拦截 , 那么只要不让静态资源进入SpringMVC即可越过拦截

由于这种情况jsp页面没有经过SpringMVC , 所以jsp页面不被渲染

因为这种方式不满足Rest风格API所以不用

实现方式 : 让所有有规律的请求进入SpingMVC

举例 :

    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

16.1.2.配置静态资源映射

配置静态资源映射 , 即告诉SpringMVC哪些请求需要到什么地方找

实现方式 : 在SpringMVC配置文件中配置静态资源映射

注意 : 如果使用4.2.5版本的springmvc则必须在请求匹配前加/ , 资源位置后加/

举例 :

<!--    mapping : 请求匹配 , 支持通配符-->
<!--    location : 资源的位置-->
<!--    通配符* : 一级路径-->
<!--    通配符** : 多级路径-->
    <mvc:resources mapping="/test1.html" location="/"/>
    <mvc:resources mapping="/css/**" location="/css/"/>

16.1.3. 放行所有静态资源

一个标签解决所有问题 , 建议使用

开发时如果使用就用这种方式 , 或者根本不使用

举例 :

    <mvc:default-servlet-handler/>

17. 异常处理

编写程序的过程中 :

dao操作数据库时可能出现异常 , 此时异常抛出 ,
service处理dao层的异常 , service层本身也可能出现异常 , service把所有的异常抛出
contorller需要处理dao层异常 , service层异常 , 本身也可能有异常

contorller是用SpringMVC编写的 , 所以异常处理是SpringMVC的异常处理

SpringMVC异常处理有2中方式 :

  • 抛出 : 交由JVM处理 , 也就是控制台报错 , 出现报错页面
  • 处理异常 :
    • 返回一个固定页面 ( 服务器繁忙 )
    • 返回页面 , 携带数据 ( 需要使用JSP或HTML+其他模版引擎)
    • 定制json格式字符串 ( 需要掌握 )
    • 提示 : 只要页面不是jsp或者html+模版引擎 , 则第一二中方式无法使用
    • 如果是前后端分离项目或前后端不分离使用ajax异步请求的 , 此时需要使用自定义异常返回json状态码 , 并且为了满足Rest封装 , 错误信息应该包含 : status message

17.1. 处理异常 : 返回固定页面

当出现异常时 , 直接返回一个固定的页面 , 如果需要展示错误信息比较复杂

web.xml配置文件 :

<error-page>
    <location>/error.html</location>
</error-page>

17.2. 处理异常 : 返回页面并携带数据

携带数据到达视图 , 渲染展示 :

  • 好处 : 可以显示不同的错误信息
  • 坏处 : 页面目前来讲只是能使用jsp页面 , 并且需要配置视图解析器

springMVC :

    <!--    视图解析器-->
    <bean id="resourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--        配置前置-->
        <property name="prefix" value="/WEB-INF/pages/"/>
        <!--        配置后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>

handler :

//记得配置扫描器
@Component
public class ExceptionHandler implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        String message = e.getMessage();
//        httpServletRequest.setAttribute("msg", message);
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("msg", message);
        modelAndView.setViewName("error");
        return modelAndView;
    }
}

17.3. 处理异常 : 自定义异常

处理方法 :

  1. 添加controllerAdvice给所有controller添加功能
  2. 只要controller抛出MyException异常 , 则进入ControllerAdvice

自定义应用场景 : 明白controller要抛出的异常 , 但是又无法处理 ( 编译器异常 )

问题 : 运行过程中出现的未被提前处理的异常( 空指针 索引操作 类型转换错误等 )怎么处理?

自定义枚举类型保存返回异常状态和信息 :

public enum MyStatus {
    USERNAME_ERROR(4000, "用户名错误"),
    PASSWORD_ERROR(4001,"密码错误")
    ;
    private int status;
    private String message;

    MyStatus(int status, String message) {
        this.status = status;
        this.message = message;
    }

    //get set tostring
}

自定义异常抛出信息为枚举类 :

public class MyException extends RuntimeException {
    private MyStatus myStatus;

    public MyException(MyStatus myStatus) {
        this.myStatus = myStatus;
    }

    public MyStatus getMyStatus() {
        return myStatus;
    }

    public void setMyStatus(MyStatus myStatus) {
        this.myStatus = myStatus;
    }
}

编写ControllerAdvice , 给所有controller添加功能

@ControllerAdvice//给controller层添加功能 , 所有controller出现的问题都会进入这里
public class TestHandler {

    //@ResponseBody
    //使用responseEntity返回json数据 , 或者使用@ResponseBody注解 , 记得导如jackson包 , 否则无法使用
    //controller层如果出现异常 并且异常是MyException异常 , 此时会执行这个方法 , 并用形参接收异常
    @ExceptionHandler(MyException.class)
    public ResponseEntity<Map<String, Object>> handlerMyException(MyException e) {
        MyStatus myStatus = e.getMyStatus();
        Map<String, Object> map = new HashMap<>();
        map.put("status", myStatus.getStatus());
        map.put("message", myStatus.getMessage());
        return ResponseEntity.ok(map);

    }
}

测试 :

    @ResponseBody
    @GetMapping("exception1")
    public String exception1() {
        System.out.println("test");
        throw new MyException(MyStatus.USERNAME_ERROR);
    }

17.4. 异常处理 : 其他异常

程序运行过程中 , 根本不知道那里出现了异常 , 也不知道出现了什么异常 , 必须要找到这个异常的父类 : Throwable

当与自定义异常同时存在时 , 如果满足自定义异常则使用自定义异常的ControllerAdvice , 否则使用这个ControllerAdvice

自定义枚举类保存返回异常信息 :

public enum MyStatus {
    USERNAME_ERROR(4000, "用户名错误"),
    PASSWORD_ERROR(4001,"密码错误"),
    UNKNOW_ERROR(4004,"未知错误")
    ;
    private int status;
    private String message;

    MyStatus(int status, String message) {
        this.status = status;
        this.message = message;
    }

    //get set tostring
}

编写ControllerAdvice , 给所有controller添加功能 :

@ControllerAdvice//给controller层添加功能 , 所有controller出现的问题都会进入这里
public class TestHandler {

    //@ResponseBody
    //使用responseEntity返回json数据 , 或者使用@ResponseBody注解 , 记得导如jackson包 , 否则无法使用
    //controller层如果出现异常 并且异常是Throwable的子类 , 此时会执行这个方法 , 并用形参接收异常
    @ExceptionHandler(Throwable.class)
    public ResponseEntity<Map<String, Object>> handlerMyException(Throwable t) {
        MyStatus myStatus = Mystatus.UNKNOW_ERROR();
        Map<String, Object> map = new HashMap<>();
        if(!StringUtils.isEmpty(t.getMessage)){
            map.put("message", t.getMessage());
        }else{
         	map.put("message",myStatus.getStatus());   
        }   
        map.put("status", myStatus.getMessage());
        return ResponseEntity.ok(map);
    }
}

测试 :

	@ResponseBody
    @GetMapping("exception2")
    public String exception2() {
        int i = 1 / 0;
        return "success";
    }

    @ResponseBody
    @GetMapping("exception3")
    public String exception3() {
        List list = null;
        list.add("aa");
        return "success";

    }

    @ResponseBody
    @GetMapping("exception4")
    public String exception4() {
        List list = null;
        list.get(1);
        return "success";

    }

    @ResponseBody
    @GetMapping("exception5")
    public String exception5() {
        String str = "a";
        Integer integer = Integer.valueOf(str);
        return "success";

    }

18. SpringMVC的拦截器

拦截器Filter是Servlet的三大技术之一

SpringMVC也提供了拦截器功能interceptor

二者功能都是拦截请求 , 过滤请求的

SpringMVC拦截器的创建流程 :

  1. 定义一个类实现拦截器接口
  2. 重写方法 , 是否继续执行要看返回值是true还是false
  3. 在SpringMVC配置文件中配置拦截器

拦截器代码 :

public class TestInterceptor implements HandlerInterceptor {

    //执行目标方法之前执行
    //返回true表示请求会向下执行 , 返回false表示请求不会向下执行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //登陆判断
        //从session中获取user对象 , 如果对象为空则页面重定向 , 否则
        Object user = request.getSession().getAttribute("user");
        if (user == null) {
            //重定向
            return false;
        } else
            return true;
    }

    //方法执行后 , 返回视图前执行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    //请求完成后执行 , 视图返回后执行 ( 仅限于试图解析器 )
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

配置文件 :

    <!--    配置拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--需要拦截取得地址 /**表示所有地址 /*表示所有的一级请求-->
            <mvc:mapping path="/**"/>
            <!--设置不拦截的请求-->
            <mvc:exclude-mapping path="/login"/>
            <bean class="com.test.interceptor.TestInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
posted @ 2021-06-02 23:15  小_Leo  阅读(243)  评论(0)    收藏  举报