SpringMVC学习笔记

SpringMVC

简介:

springMVC是一个web层mvc框架 , 何谓MVC?

model 模型

view 视图

controller 控制器

这是一种设计模式,将责任进行拆分 , 不同的组件负责不同的事情

好处:

  • 结构清晰
  • 更好维护( Old : 大量使用jsp的年代 , 只应该负责显示就行了)

坏处:

  • 更加复杂了

入门体验

  1. 创建一个web项目
  2. 编写web.xml,在其中注册一个特殊的servlet , 前端控制器
  3. 编写一个springmvc的配置文件
    • 注册一个视图的解析器
  4. 编写一个控制器
  5. 编写一个结果页面

注解开发模式

​ 基本上实现接口的方式已经是过去式了 , 采用注解开发很简单

  • 基本注解

    • @Controller
    • @RequestMapping
  • 开发步骤

    1. 记得配置一下基础扫描的包 , 这样配置的注解才会生效
    2. 在指定的类上面添加@Controller注解
    3. 添加@RequestMapping注解 ---- 类似于前面的controller的那个名字(不同的requestHandler处理)

    当我们写上@Controller之后 , 就标记他为spring的一个组件,并且是控制器的组件 , 此时我们handlermapping会去扫描寻找扫描寻找Controller是否与之匹配 ,通过发现匹配就把这里处理的工作交给他.

    • 匹配的规则又是什么呢?

      具体的匹配就是通过请求的路径进行匹配的

      @RequestMapping(URI)

      此时就是通过这个URI进行匹配

      @RequestMapping

      可以写在类上

      可以写在方法上(推荐使用二者结合方式)

      @Controller
      @RequestMapping("/orders")
      public class OrderController {
      
          @RequestMapping("/addOrder")
          //这里的返回值为String,String就是逻辑的视图名称
          public String orderAdd(Model model){
      
              List<Order> orders = new ArrayList<>();
      
              Order order = new Order("1","平底锅",2432.1);
              Order order2 = new Order("2","大锄头",3306.0);
      
              orders.add(order);
              orders.add(order2);
              model.addAttribute("orders",orders);
      
              return "order";
          }
      }
      

转发与重定向

forward和redirect的区别是什么?

https://blog.csdn.net/weixin_37766296/article/details/80375106

  • 一、从地址栏显示来说:
    • forword是服务器内部的重定向,服务器直接访问目标地址的 url网址,把里面的东西读取出来,但是客户端并不知道,因此用forward的话,客户端浏览器的网址是不会发生变化的
    • redirect是服务器根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,所以地址栏显示的是新的地址
  • 二、从数据共享来说:
    • 由于在整个定向的过程中用的是同一个request,因此forward会将request的信息带到被重定向的jsp或者servlet中使用。即可以共享数据
    • redirect不能共享
  • 三、从运用的地方来说
    • forword 一般用于用户登录的时候,根据角色转发到相应的模块
    • redirect一般用于用户注销登录时返回主页面或者跳转到其他网站
  • 四、从效率来说:
    • forword效率高,而redirect效率低
  • 五、从本质来说:
    • forword转发是服务器上的行为,而redirect重定向是客户端的行为
  • 六、 从请求的次数来说:
    • forword只有一次请求;而redirect有两次请求
  • 转发到页面 : 默认到选项
  • 重定向到页面 : redirect:path
  • 转发到另外一个控制器 : forward:path

重定向到jsp

    @RequestMapping("/request3")
    public String request3(HttpSession session){

        session.setAttribute("session","神庙逃亡,你妹呀,好想睡觉");
        return "redirect:/jsp/redirect.jsp";
    }

重定向到Controller

    @RequestMapping("/request")
    public String webrequest(Model model){

        model.addAttribute("boy","boytest");

        return "redirect:/web/request";
    }

关于SpringMVC访问web元素

  • request

  • session

  • application

    可以通过模拟的对象完成操作,也可以使用元素的ServletAPI完成 , 直接在方法当中入参即可.

注解详解

RequestMapping

  • value写的是路径 , 是一个数组形式 , 可以匹配多个路径
  • path 是value的别名 , 所以二者人选其一 , 他们的作用是一样的
  • method 是可以指定访问的请求的类型 , 比如get post 它也可以写成一个数组的形式.

  • params 可以指定参数,你还可以限定参数的特征 , 必须对于某个值 , 不等于某个值也行
  • headers 能够影响浏览器的行为
  • consumers 消费者 , 媒体类型 , 可以限定必须为application / json;charset=UTF-8
  • produces 产生的响应的类型

关于请求路径的问题

springmvc 支持 ant 风格

  • localhost/web/m2==?== 任意的字符 , 斜杠除外
  • localhost/web/m1==*== 0-n个字符 , 任意个字符都可以 , 斜杠除外
  • localhost/web/m1/** 支持任意层路径 /m1** 这样的效果等同于m1后面的任意多个字符

@Getmapping 与 @Postmapping…

  • getmapping :限定了只支持get请求
  • postMapping : 限定了只支持post请求

对于非get post请求的支持

对于非get post请求的支持 , 需要有额外的内容添加 , 要增加一个过滤器来额外处理

  • 过滤器

  • 返回的不再是页面而是数据

        <!--注册一个支持所有http请求类型的过滤器-->
        <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>
    
  • 表单提交里面还有添加一个隐藏的参数

    name = “_method” value = “DELETE”

@Responsebody

  • 返回数据的 , 一般情况下返回json格式

    //@Controller
    @RestController // == @Controller+@ResponseBody  当整个Controller都是用于返回json的时候使用
    @RequestMapping("/json")
    public class JsonController {
    
        @RequestMapping("/m1")
        //    @ResponseBody
        public Order m1() {
    
            Order order = new Order("1", "leike", 12.3);
    
            return order;
        }}
    

@ModelAttribute

  • 使用方式一 如果某些对象从头到尾每次请求当中都要存在 , 不消失 , 就适合这么用.

    @Controller
    @RequestMapping("/user")
    public class UserController2 {
    
        // 在controller里面的任意一个处理具体方法之前都会执行
        @ModelAttribute
        public User init(){
            System.out.println("进入init...");
            User u = new User();
            u.setName("王菲");
            return u;
        }
    
        @RequestMapping("/login")
        public String login(Model model){
            System.out.println(model.containsAttribute("u"));
            System.out.println(model.containsAttribute("user"));
            System.out.println(model.containsAttribute("2345632"));
            return "/msg";
        }
    
    }
    
  • 使用方式二

        @ModelAttribute
        public void init(Model model){
            System.out.println("进入init...");
            User u = new User();
            u.setName("王菲");
            model.addAttribute("user",u);
        }
    
  • 使用方式三 如果没有传递这个model过来 , name方法上加了@Modelattribute的 为你提供 , 如果你传了则用传过来的值

        @ModelAttribute
        public void init(Model model){
            System.out.println("进入init...");
            User u = new User();
            u.setName("王菲");
            model.addAttribute("user",u);
        }
        @RequestMapping("/login")
        public String login(@ModelAttribute("user") User user){
            System.out.println(user);
    //        System.out.println(model.containsAttribute("u"));
    //        System.out.println(model.containsAttribute("user"));
    //        System.out.println(model.containsAttribute("2345632"));
            return "/msg";
        }
    

@SessionAttributes

  • 这个用在类上面 , 他会将模型自动填充到会话里面去

@SessionAttribute

  • 要求当前这次访问当中的会话里面必须要有某个对象

@RequestParam

@RequestBody

  • json数据 , 不是通过form表单传递

  • ajax({

    ​ data :

    })

@InitBinder

数据转换 , 将日期转换处理

@PathVariable

  • restful风格
  • 详情参考罗伊菲尔丁在他的博士论文.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZfRDyvJu-1571293750752)(C:\Users\leike\Documents\我的md笔记\images\PathVariable方式请求.png)]

@RestController–返回json数据时候用

  • 相当于于@Controller+@ResponseBody

关于静态资源访问的问题

由于我们的servlet设置乐URL匹配方式为 / 所以 , 他将我们的静态资源也当做了一个后台的请求

比如http://localhost:8080/springMVC/static/css/index.css

  • 它尝试去匹配一个static/css/index.css的Controller的RequestMapping的组合 , 因为没有 , 所以404 .
  • 解决方式很多 , 最简单的 , 让springmvc单独处理 , 将这些交给容器的默认servlet处理 , 就不让DispatcherServlet来处理.

解决方式一 在springMVC配置文件中加入

<!--默认的servlet处理者
    只加这个的话相当于全部让他处理了-->
<mvc:default-servlet-handler/>
<!-- 为了让controller生效,要加这个注解驱动-->
<mvc:annotation-driven/>

解决方式二 通过映射关系描述 , 一 一 对编写规则

<mvc:resources mapping="/static/css/*" location="/static/css/"/>
<!-- 为了让controller生效,要加这个注解驱动-->
<mvc:annotation-driven/>

解决方式三 自行在web.xml定义映射规则

关于post请求中文乱码问题解决

添加一个过滤器即可 , springMVC提供了一个非常好的字符编码过滤器 , 所以我们注册即可(建议放在所有过滤器最前面) .

<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>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

关于form表单提交数据的方式

方式一 通过属性名字进行绑定

  • 通过属性的名称就行绑定 , 可以完成数据传递 .

  • 页面当中表单元素的name值要和后台的形参名字保持一致 .

  • 如果有多个 , 多个形参按名字绑定即可 , 当传入的值较多的时候.

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>user_put</title>
    </head>
    <body>
        <form action="${ctx}/user/put/" method="post">
            <input type="hidden" name="_method" value="put">
            <input type="text" name="name">
            <br>
            <input type="password" name="password">
            <input type="submit" value="提交">
        </form>
    </body>
    </html>
    
    @Controller
    @RequestMapping("/user")
    public class UserController {
    
        @PutMapping("/put")
        //需要额外的json包支持
        @ResponseBody
        public String put(String name,String password){
    
            System.out.println(name+"   "+psword);
    //        Map<String, String> map = new HashMap<>();
    //        map.put("msg","ok");
    
            return "ok";
        }
    }
    

方式二 利用@RequestParam

  • jsp页面不变

  • 后台

    @Controller
    @RequestMapping("/user")
    public class UserController {
    
        @PutMapping("/put")
        //需要额外的json包支持
        @ResponseBody
        public String put(@RequestParam("name") String name,@RequestParam("password") String psword){
    
            System.out.println(name+"   "+psword);
    //        Map<String, String> map = new HashMap<>();
    //        map.put("msg","ok");
    
            return "ok";
        }
    }
    

方式三 直接使用pojo形式传递

  • jsp页面不变

  • 后台

        @PutMapping("/put1")
        //需要额外的json包支持
        @ResponseBody
        public String put(User user){
    
            System.out.println(user);
    //        Map<String, String> map = new HashMap<>();
    //        map.put("msg","ok");
            return "ok";
        }
    

方式四 – 关于form表单提交日期格式数据问题的处理

  1. 处理日期 ( 没有时间 )

    @InitBinder("user")
    public void init(WebDataBinder dataBinder) {
        //这里指定什么格式 , 前台就只能传什么格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        sdf.setLenient(false);
        dataBinder.registerCustomEditor(Date.class, new CustomDateEditor(sdf, false));
    }
    @PutMapping("/put2")
    //需要额外的json包支持
    @ResponseBody
    public String put2(@ModelAttribute("user") User user) {
        System.out.println(user);
        return "ok";
    }
    //通过initBinder指定了user名字和modelAttribute里面user绑定
    
  2. 不指定名字,根据数据类型一样可以分析解析转换成功

  3. 在属性上面添加注解

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

json数据交互

额外依赖

    <!--json依赖-->
    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.9.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.9</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.9.9</version>
    </dependency>
<!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib -->
<dependency>
    <groupId>net.sf.json-lib</groupId>
    <artifactId>json-lib</artifactId>
    <version>2.4</version>
    <classifier>jdk15</classifier>
</dependency>
<!--添加处理json为javabean-->
<!-- https://mvnrepository.com/artifact/org.codehaus.jackson/jackson-core-asl -->
<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-core-asl</artifactId>
    <version>1.9.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.codehaus.jackson/jackson-mapper-asl -->
<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-mapper-asl</artifactId>
    <version>1.9.13</version>
</dependency>
<!--添加处理json为javabean ==end== -->

另外记得添加

	<!--激活springmvc消息转换功能-->
    <mvc:annotation-driven/>

JSON数据返回前台以及如何解析

Json后台返回
  • 返回POJO

    @RequestMapping("/m1")
    //    @ResponseBody
    public Order m1(){
    
        Order order = new Order("1", "leike", 12.3);
    
        return order;
    }
    
    
  • 返回Map

    @RequestMapping("/m2")
    //    @ResponseBody
    public Map<String,Object> m2(){
    
        Map<String, Object> map = new HashMap<>();
        Order order = new Order("1", "lk", 12.3);
        Order order1 = new Order("2", "lk2", 12.3);
        Order order2 = new Order("3", "lk3", 12.3);
    
        map.put("1",order);
        map.put("2",order1);
        map.put("3",order2);
    
        return map;
    }
    
    
  • 返回List

    @RequestMapping("/m3")
    //    @ResponseBody
    public List<Order> m3(){
    
        List<Order> list = new ArrayList<>();
        Order order = new Order("1", "lk", 12.3);
        Order order1 = new Order("2", "lk2", 12.3);
        Order order2 = new Order("3", "lk3", 12.3);
    
        list.add(order);
        list.add(order1);
        list.add(order2);
        return list;
    }
    
    
  • 返回数组

    @RequestMapping("/m4")
    //    @ResponseBody
    public Order[] m4() {
    
        Order[] list = {new Order("1", "lk", 12.3),
                        new Order("2", "lk2", 12.3),
                        new Order("3", "lk3", 12.3)};
    
        return list;
    }
    
    
Json前台解析
  • 解析返回的pojo

    $('#b1').click(function () {
        $.ajax({
            url:'${ctx}/json/m1',
            type:'post',
            success:function (data) {
                alert(data.name);
                alert(data.id);
                alert(data.price);
            }
        })
    })
    
    
  • 解析返回的Map

    同上

  • 解析返回的List

    $('#b3').click(function () {
        $.ajax({
            url: '${ctx}/json/m3',
            type: 'post',
            success: function (data) {
                for (var i = 0; i < data.length; i++) {
                    alert(data[i].name);
                }
            }
        })
    })
    
    
  • 解析数组

    同上

JSON数据如何使用Ajax提交到后台,后台如何解析

  • 设置请求格式为json
contentType:"application/json;charset=utf-8"

  • 前台写法 – 发送一个pojo

    $(function () {
        $('#b').click(function () {
            var obj={
                id:'1',
                name:'爷们',
                price:'22.1'
            }
            $.ajax({
                url:'${ctx}/json2/add',
                type:'post',
                contentType: "application/json",
                data:JSON.stringify(obj),
                succese:function (data) {
                    alert(data);
                }
            })
        })
    })
    
    
  • 后台写法

    @Controller
    @RequestMapping("/json2")
    public class JsonController2 {
    
        @RequestMapping("/add")
        @ResponseBody
        public String add(@RequestBody Order order){
            System.out.println(order);
            return "ok";
        }
    }
    
    

    ps : 一定要记得添加@requestBody,否则无法解析

  • 发送一组pojo

    • 前台

      $('#b2').click(function () {
          var obj1={
          id:'1',
              name:'爷们',
          price:'22.1'
          }
          var obj2={
              id:'2',
          name:'爷们2',
              price:'22.13'
          }
          var arr = new Array();
          arr.push(obj1);
          arr.push(obj2);
          $.ajax({
              url:'${ctx}/json2/addList',
              type:'post',
              contentType: "application/json",
              data:JSON.stringify(arr),
              success:function (data) {
                  if (data.code == 2000){
                      alert("成功了");
                  }
              }
          })
      })
      
      
    • 后台

      @RequestMapping("/addList")
      @ResponseBody
      public Map<String,Integer> addList(@RequestBody List<Order> orders){
          System.out.println(orders);
          Map<String,Integer> map = new HashMap<>();
          map.put("code",2000);
          return map;
      }
      
      

xml数据交互

对于很多第三方开发 , 还是有很多会采用xml作为数据交互 , 比如微信.

  1. 添加额外的依赖

    <dependency>
       <groupId>com.fasterxml.jackson.dataformat</groupId>
        <artifactId>jackson-dataformat-xml</artifactId>
        <version>2.9.9</version>
    </dependency>
    
    
  2. 方法返回数据类型定义

    //描述生产的类型 , 返回类型的描述 , 返回什么数据
    @RequestMapping(value = "/m1",produces = {MediaType.APPLICATION_XML_VALUE})
    @ResponseBody
    public User m1(){
        // 希望springmvc将数据转换为xml形式user
        User user = new User("好","11",null);
    
        return user;
    }
    
    

文件上传

apache 上传组件方案—单文件上传

  • 添加依赖

    <!--文件上传依赖-->
    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.3.3</version>
    </dependency>
    
    
  • 在springmvc中注册一个文件上传解析器

    <!--文件上传解析器,
            id必须是multipartResolver原因是源码写死为这个名字-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--定义最大长度的大小 总的  单位为  bytes-->
        <property name="maxUploadSize" value="10241024"/>
        <!--指定上传编码-->
        <property name="defaultEncoding" value="UTF-8"/>
        <!--指定单个文件最大上传大小-->
        <property name="maxUploadSizePerFile" value="2000000"/>
    </bean>
    
    
  • 准备一个上传的页面

    <form action="${ctx}/file/upload" method="post" enctype="multipart/form-data">
        文件:<input type="file" name="file">
        <br>
            <input type="submit" value="提交">
    </form>
    
    
  • 后台处理程序

    //入参就可以代表上传的文件
    @RequestMapping("/upload")
    public String upload(@RequestParam("file") MultipartFile multipartFile, Model model) {
        /**
             * 1.传到那里去
             * 2. 传什么东西
             * 3. 传的细节
             */
        // 1.不为空才上传
        if (!multipartFile.isEmpty()) {
            //2.获取原始的文件名
            String originalFilename1 = multipartFile.getOriginalFilename();
            //3. 先截取源文件的文件名前缀 , 不带后缀
            String fileNamePrefix = originalFilename1.substring(0, originalFilename1.lastIndexOf("."));
            //4. 加工处理文件名 , 将原文件名+时间戳
            String newfileNamePrefix = fileNamePrefix+new Date().getTime();
            System.out.println(new Date().getTime());
            //5. 得到新文件名
            String newFilename = newfileNamePrefix+originalFilename1.substring(originalFilename1.lastIndexOf('.'));
            //6. 构建文件对象
            File file = new File(uploadPath + newFilename);
            //7.上传
            try {
                multipartFile.transferTo(file);
                model.addAttribute("fileName",newFilename);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return "file/uploadSuc";
    }
    
    

多文件上传

  • 配置同上

  • 前台

    多些几个<input>就完事
    
    
  • 后台

    把MultipartFile换成MultipartFile[]
    遍历这个数组
    完事
    
    

文件下载

@Controller
@RequestMapping("/download")
public class DownloadController {

    private static String parentPath = "D:"+ File.separator;

    @RequestMapping("/down")
    @ResponseBody
    public String down(HttpServletResponse response){
        //        response.setCharacterEncoding("UTF-8");
        //通过输出流写到客户端 , 浏览器
        // 1 获取我就爱你下载名
        String filename = "夜景.jpg";
        // 2 构建一个文件对象,通过Paths工具类获取一个Path对象
        Path path = Paths.get(parentPath, filename);
        // 3 判断它是否存在
        if (Files.exists(path)){
            //存在则开始下载
            //通过response设定他的响应的类型
            // 4 获取文件的后缀
            String fileSuffix = filename.substring(filename.lastIndexOf(".")+1);
            // 5 设置contenType , 只有指定它才能去下载
            response.setContentType("application/"+fileSuffix);
            // ISO8859-1
            try {
                response.addHeader("Content-Disposition","attachment; filename="+new String(filename.getBytes("UTF-8"),"ISO8859-1"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            // 6 通过Path写出去 -- end
            try {
                Files.copy(path,response.getOutputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else {
            return "未找到资源文件";
        }
        return "ok";
    }
}

拦截器

  • springmvc提供了拦截器 , 类似于过滤器 , 他将在我们的请求距离处理之前先做检查 , 有权决定 , 接下来是否继续 , 对我们的请求进行加工,

  • 可以设计多个拦截器

  • 通过实现HandlerInterceptor , 这是一个接口

    定义了非常重要的三个方法

    • 前置处理
    • 后置处理
    • 完成处理

案例一

拦截器实现方法耗时统计与警告.

后台代码

package com.leike.interceptors;

import org.apache.log4j.Logger;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * @description:
 * @author: leike
 * @date: 2019-07-22 18:52
 */

/**
 * 方法耗时统计拦截器
 */
public class MethodTimerInterceptor implements HandlerInterceptor {

    private static final Logger LOGGER = Logger.getLogger(MethodTimerInterceptor.class);


    //前置功能 , 开始 - 结束 , 两个点减法得到耗时
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1 定义开始时间
        long start = System.currentTimeMillis();
        //2 将其存到请求域当中
        request.setAttribute("start",start);
        // 返回true , 才会找到下一个拦截器 , 如果没有下一个拦截器 , 则去Controller
        LOGGER.info(request.getRequestURI()+",请求到达");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 1取出start
        long start = (long) request.getAttribute("start");
        // 2得到end
        long end = System.currentTimeMillis();
        // 3记录一下耗时
        long spendTime = end - start;
        if (spendTime >= 1000){
            LOGGER.warn("方法耗时严重 , 请及时处理,耗时: "+spendTime+"毫秒");
        }else {
            LOGGER.info("方法耗时:"+spendTime+"毫秒,速度正常");
        }

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}


springmvc的配置

<mvc:interceptors>
    <mvc:interceptor>
        <!--
                /* 的写法只能拦截/name的方法 , 只能由一层 , 不是多层拦截
            -->
        <mvc:mapping path="/**/*"/>
        <bean class="com.leike.interceptors.MethodTimerInterceptor">
        </bean>
    </mvc:interceptor>
</mvc:interceptors>

案例二

会话拦截器 , 做用户检查

后台代码

package com.leike.interceptors;

/**
 * @description:
 * @author: leike
 * @date: 2019-07-22 21:34
 */

import com.leike.pojo.Use;
import org.apache.log4j.Logger;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 会话拦截器
 */
public class SessionInterceptor implements HandlerInterceptor {

    private static final Logger LOGGER = Logger.getLogger(SessionAttributes.class);


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object use = request.getSession().getAttribute("SESSION_USER");
        if (use == null){
            LOGGER.warn("你不具备权限 , 请先登录");
            return false;
        }
        if (use instanceof Use){
            Use u = (Use) use;
            u.setPwd(null);
            request.getSession().setAttribute("SESSION_USER",u);
            LOGGER.info(u.getName()+"处于登录状态 , 可以执行操作");
            return true;
        }else {
            LOGGER.warn("请不要搞事 , 请先登录");
            return false;
        }

    }

    @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 {

    }

}

springmvc配置

<mvc:interceptor>
    <!--
                只想拦截/user/**/*
                还需要开放登录权限
            -->
    <mvc:mapping path="/**/*"/>
    <!--排除登录的这个URI-->
    <mvc:exclude-mapping path="/use/login"/>
    <bean class="com.leike.interceptors.SessionInterceptor">
    </bean>
</mvc:interceptor>

将其配置在mvc:interceptors节点之下即可

拦截器执行器顺序的问题

  • 如果有n个拦截器 , 并且都能拦截到某个URL的时候 , 执行顺序问题.

  • 在springmvc当中拦截器定义的顺序是有关系的 , 配在前面的优先拦截,按照顺序来.

    i1

    i2

    i3

    前置处理 i1>i2>i3

    后置处理 i3>i2>i1

拦截器与过滤器的比较

  • 相似点

    都有优先处理请求的权利 , 可以决定是否将请求转移到实际处理的控制器处 , 都可以对请求或者会话当中数据进行加工

  • 不同点

    • 拦截器可以做前置处理 , 也可以做后置处理 , 还可以完成后处理 , 控制的更细一些,过滤器只负责前面的行为而已
    • 过滤器优先执行 .
    • 过滤器是servlet规范里面的组件.
    • 拦截器都是框架自己额外添加的组件.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值