拦截器

147 阅读5分钟

拦截器

springBoot中使用拦截器

spring MVC的拦截器(Interceptor)与java Servlet的过滤器(Filter)类似,它主要用于拦截用户的请求并作出相应的处理,通常应用于权限验证、记录请求信息的日志、判断用户是否登录等功能。

spring mvc 中自定义拦截器,可以通过实现HandlerInterceptor接口来定义,重点重写prehandle()方法

prehandle():这个方法在业务处理器处理请求之前被调用,可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否继续进行下去。该方法的返回值是布尔值Boolean类型的,当它返回为false时,表示请求结束,后续的interceptor和controller都不会执行;当返回为true时就会继续调用下一个interceptor的prehandle方法,如果已经是最后一个interceptor的时候就会调用当前请求的controller方法。

定义拦截器

package com.project.intercepetor;
​
import org.springframework.web.servlet.HandlerInterceptor;
​
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
​
/**
 * 登录拦截器
 */public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//        得到登录用户
        Object obj=request.getSession().getAttribute("loginUser");
        if (obj==null){//没有登录,回到登录页面
            response.sendRedirect("/login.html?errorInfo=noland");
            //没有通过,不能继续访问目标资源
            return false;
        }
        //通过拦截器,继续访问目标资源
        return true;
    }
}

注册拦截器

拦截器定义后,必须完成注册,才能被springMVC容器所识别。在注册时,需要指定拦截范围。

package com.project.config;
​
import com.project.intercepetor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
​
@Configuration//声明是一个配置类public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())//注册拦截器
                .addPathPatterns("/index.html");//定义拦截范围(受限资源)
    }
}

路径映射

registry.addInterceptor(new LoginInterceptor())//注册拦截器
        .addPathPatterns("/dept/*");

拦截所有

registry.addInterceptor(new LoginInterceptor())//注册拦截器
        .addPathPatterns("/**");

文件上传

表单上传

文件上传是将客户本地的文字、图片、视频扽上传给web服务器。

文件上传,要求客户端必须以post方式提交,并在表单中添加enctype="multipart/form-data"属性。

客户端

<form action="/user/add" method="post" enctype="multipart/form-data">
    用户名:<input type="text" id="userName" name="userName"><br>
    头像:<input type="file" name="face"><br>
    <input type="submit" value="提交">
</form>

在application.yml文件中添加上传文件大小的限制

spring:
  servlet:
    multipart:
      maxFileSize: 20MB
      maxRequestSize: 100MB

在服务器端controller中接收上传文件

@RequestMapping("add")
//"face"是表单的name值
public String add(String userName, @RequestParam("face") MultipartFile mf) throws IOException {
    //表示得到客户端上传文件的文件名
    String fileName=mf.getOriginalFilename();
    //将上传文件的二进制数据保存到服务器本地文件
    mf.transferTo(new File("E:\program\javaPhaseTwo\week06\day03\Interceptor\src\main\resources\static\userface\"+fileName));
    return "ok";
}

在配置类(config)当中注册上传文件的路径的映射

 @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
//        http://localhost:8088/face/55.webp
//        face是一个请求路径
        registry.addResourceHandler("/face/**")
                .addResourceLocations("file:E:\program\javaPhaseTwo\week06\day03\Interceptor\src\main\resources\static\userface\");
    }

ajax上传文件

用户名:<input type="text" id="userName"><br>
<img src="" id="facePic" width="200" height="200">
头像:<input type="file" id="faceImg" onchange="fileChange()"><br>
<input type="button" value="添加" onclick="addUser()">
function addUser(){
    //创建上传文件的对象
    let formObj=new FormData();
    //添加表单数据
    formObj.append("userName",$("userName").value);
    formObj.append("face",$("faceImg").files[0]);
    //设置请求头
    let config = {
        headers: {'Content-Type': 'multipart/form-data' }
    }
    axios.post("/user/add",formObj,config).then(resp=>{
        if (resp.data == "ok"){
            alert("添加成功")
        }
    })
​
}
function fileChange(){
    var reader=new FileReader();
    reader.readAsDataURL($("faceImg").files[0]);
    reader.onload=function (ev){
        $("facePic").src=ev.target.result;
    }
}

数据验证

数据校验在WEB应用里是非常重要的功能,可以避免因为客户端非法数据的录入,导致的服务器类型转换异常,以及非法数据的数据保存。

数据校验分为客户端校验和服务器校验。

客户端校验

客户端校验是指,通过JavaScript脚本语言对提交服务器表单数据进行校验。校验通过以后,再将表单提交给服务器。

客户端校验的优点是直观,可以在不访问服务器的情况下,直接对非法数据的错误信息直接在页面上显示出来。

客户端校验的缺点是并不安全,因为客户端校验需要依赖于浏览器和JavaScript。横夺时候,可以绕过浏览器和JavaScript,直接访问服务器。

服务器校验

服务器校验是指,在服务器接收到客户端提交的表单数据后,在访问业务组件之前,进行的数据验证。验证通过,则访问业务组件,否则,给客户端发错误提示。

服务器校验优点是比较安全,是客户端数据访问业务组件的最后一道屏障。

服务器校验的缺点是执行效率相对较低。多了访问服务器的步骤,校验由服务器完成,所以,服务器压力要大一些。

spring MVC服务器校验

springMVC拥有自己独立的数据校验框架,同时支持JSR 303标准的校验框架。Hibernate Validator 是JSR 303的一个参考实现。

导入依赖

<dependencies>
    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>6.1.5.Final</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish</groupId>
        <artifactId>javax.el</artifactId>
        <version>3.0.1-b11</version>
    </dependency>
</dependencies>

在实体类属性中定义校验规则

@NotBlank 判断字符串是否为null或者空串(去掉首尾空格)

@Max 判断数值的最大值

@Min判断数值的最小值

@Email判断邮箱是否合法

@Pattern(regexp =“\d+”)判断是否匹配指定正则表达式,

每个校验规则都有message属性,用于自定义错误提示信息

在实体类属性中添加校验属性

 /**姓名*/
    @NotBlank(message = "姓名必须填写")
    @Pattern(regexp = "[a-zA-Z\u4e00-\u9fa5]{2,}",message = "姓名必须为两个以上的汉字或字母")
    private String name;
    /**电话*/
    @Pattern(regexp = "1[35789]\d{9}",message = "电话必须以13、15、17、18、19开始的11位数")
    private String phone;
    /**工资*/
    @NotBlank(message = "工资必须填写")
    @Max(value = 100000,message = "工资不能高于100000")
    @Min(value = 1800,message = "工资不能低于1800")
    private Integer money;

应用控制器方法

controller

//    BindingResult br 用于存放校验失败信息
//    @Valid 表示需将提交的数据进行校验
    @RequestMapping("add")
    public String add(@Valid EmployeeBean employeeBean, BindingResult br) throws JsonProcessingException {
       if (br.hasErrors()){//判断是否有验证失败的信息, 有为true,没有false
           //得到校验失败的集合
           List<FieldError> errorList=br.getFieldErrors();
//           将校验失败集合转化为json字符串发送给客户端
           ObjectMapper om=new ObjectMapper();
           String errorInfo=om.writeValueAsString(errorList);
           return errorInfo;
       }

html

姓名:<input type="text" id="nameTxt"><span id="nameSpan" class="errorSpan"></span><br>
电话:<input type="text" id="phoneTxt"><span id="phoneSpan" class="errorSpan"></span><br>
工资:<input type="text" id="moneyTxt"><span id="moneySpan" class="errorSpan"></span><br>

js

}).then(resp=>{
    var info=resp.data;
    // alert(JSON.stringify(info))
    if (info=="ok"){
        location.href="main.html";
    }else {
        info.forEach(n=>{
            $(n.field+"Span").innerHTML=n.defaultMessage;
        });
    }
})