Spring Mvc服务端验证&拦截器

目录

一、服务端校验

1、为什么要做服务端校验

2、使用JSR303工具类完成服务端校验

2.1   导入JSR303所需要的pom依赖

2.2  后端编码

 JSR303工具类

2.3前端编码

二、拦截器 

1、拦截器的介绍

2.拦截器与过滤器

2.1 什么是过滤器(Filter)

  2.2 拦截器与过滤器的区别 

3.应用场景

4、拦截器的编码演示

1、建立一个拦截器类并实现拦截器HandlerInterceptor接口

2、在Springmvc的配置文件中配置拦截器类

3、编写一个测试类测试方法 

前置处理返回false和ture的区别:

 5、拦截器链

5.1  再建立·一个·拦截器类 实现HandInterceptor接口

5.2  在SpringMvc配置文件中将两个拦截器类分别进行配置

5.3 执行顺序说明

 6、拦截器具体应用到登录权限控制

6.1  在配置文件中配置一个所有路径的拦截器

6.2 在登录功能的后端编码中进行判断是否拦截


一、服务端校验

1、为什么要做服务端校验

客户端校验的安全性低,用户在注册信息时很容易绕过校验,输入不合法的信息

2、使用JSR303工具类完成服务端校验

2.1   导入JSR303所需要的pom依赖


      org.hibernate
      hibernate-validator
      6.0.7.Final
    

2.2  后端编码

 JSR303工具类

JSR303工具类中包含了许多标签以及能够添加注解来指定实体类中的属性

Spring Mvc服务端验证&拦截器_第1张图片

 例如:

 @NotNull :作用于基本数据类型

 @NotEmpty    作用于集合

 @NotBlank    作用于字符串

 2.2.1  在model 实体类中添加校验注解

Spring Mvc服务端验证&拦截器_第2张图片

2.2.2 控制层

在控制层中加入了valid和BindingResult

valid和BindingResult

vaild:

是与实体类的服务端效验 注解配合使用的 

BindingResult:

存放所有违背效验的错误信息

  先判断是否存在错误信息,如果有就拿到错误信息的集合,定义一个map集合,遍历集合时将错误信息存在map集合里,传递到前端界面Spring Mvc服务端验证&拦截器_第3张图片

完整代码:

实体类

package com.zjy.model;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

public class Clazz {
    @NotNull(message = "cid不能为空")
    private Integer cid;

    @NotBlank(message = "班级名称不能为空")
    private String cname;

    @NotBlank(message = "教员老师不能为空")
    private String cteacher;

    private String pic;

    public Clazz(Integer cid, String cname, String cteacher, String pic) {
        this.cid = cid;
        this.cname = cname;
        this.cteacher = cteacher;
        this.pic = pic;
    }

    public Clazz() {
        super();
    }

    public Integer getCid() {
        return cid;
    }

    public void setCid(Integer cid) {
        this.cid = cid;
    }

    public String getCname() {
        return cname;
    }

    public void setCname(String cname) {
        this.cname = cname;
    }

    public String getCteacher() {
        return cteacher;
    }

    public void setCteacher(String cteacher) {
        this.cteacher = cteacher;
    }

    public String getPic() {
        return pic;
    }

    public void setPic(String pic) {
        this.pic = pic;
    }
}

控制层

package com.zjy.controller;

import com.zjy.biz.ClazzBiz;
import com.zjy.model.Clazz;
import com.zjy.util.ClazzDto;
import com.zjy.util.PageBean;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
@RequestMapping("/clz")
public class ClazzController {
    @Autowired
    private ClazzBiz clazzBiz;

    @RequestMapping("/list")
    public  String list(Clazz clazz, HttpServletRequest request){
        PageBean pageBean = new PageBean();
        pageBean.setRequest(request);
        List list = this.clazzBiz.listPager(clazz,pageBean);
        request.setAttribute("lst",list);
        request.setAttribute("pageBean",pageBean);
        return "clzList";
    }

    @RequestMapping("/toEdit")
    public  String toEdit(Clazz clazz, HttpServletRequest request){
        Integer cid = clazz.getCid();
        if(cid!=null){
            List lst = this.clazzBiz.listPager(clazz, null);
            request.setAttribute("b",lst.get(0));
        }
        return "clzEdit";
    }

    @RequestMapping("/add")
    public  String add(Clazz clazz, HttpServletRequest request){
        this.clazzBiz.insertSelective(clazz);
        return "redirect:/clz/list";
    }

    @RequestMapping("/del")
    public  String delete(Clazz clazz, HttpServletRequest request){
        this.clazzBiz.deleteByPrimaryKey(clazz.getCid());
        return "redirect:/clz/list";
    }

    @RequestMapping("/edit")
    public  String edit(Clazz clazz, HttpServletRequest request){
        this.clazzBiz.updateByPrimaryKeySelective(clazz);
        return "redirect:/clz/list";
    }

    //    文件上传
    @RequestMapping("/upload")
    public String upload(ClazzDto clazzDto){
        try {
            //前台上传的文件
            MultipartFile picFile = clazzDto.getPicFile();
            //实际应该配置到resource.properties中
            String diskPath="E:/temp/images/";//图片存放地址
            //http://localhost:8080/upload/mvc/...png
            String requestPath="/upload/mvc/";//数据库保存地址,也是访问地址

            //拿到上传文件的名字
            String filename = picFile.getOriginalFilename();
            FileUtils.copyInputStreamToFile(picFile.getInputStream(),new File(diskPath+filename));

            //将图片上传图片之后,并且将图片地址更新到数据库中
            Clazz clazz=new Clazz();
            clazz.setCid(clazzDto.getCid());
            clazz.setPic(requestPath+filename);

            this.clazzBiz.updateByPrimaryKeySelective(clazz);
        }catch (Exception e){
            e.printStackTrace();
        }
        return "redirect:/clz/list";
    }

    //文件下载
    @RequestMapping(value="/download")
    public ResponseEntity download(ClazzDto clazzDto){
        try {
            //1、点击下载传递文件的ID,通过文件的ID查询出文件的路径
            Clazz clazz = this.clazzBiz.selectByPrimaryKey(clazzDto.getCid());
            String pic=clazz.getPic();
            String diskPath = "E:/temp/images/";
            String requestPath = "/upload/mvc/";

            //2、通过文件的请求地址,转换成文件存放的硬盘地址
            String realPath = pic.replace(requestPath, diskPath);
            String fileName = realPath.substring(realPath.lastIndexOf("/")+1);

            // 3、将硬盘中文件下载下来——>固定代码
            File file=new File(realPath);
            HttpHeaders headers = new HttpHeaders();//http头信息
            String downloadFileName = new String(fileName.getBytes("UTF-8"),"iso-8859-1");//设置编码
            headers.setContentDispositionFormData("attachment", downloadFileName);
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            //MediaType:互联网媒介类型  contentType:具体请求中的媒体类型信息
            return new ResponseEntity(FileUtils.readFileToByteArray(file),headers, HttpStatus.OK);

        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Valid 是与实体类的服务端效验 注解配合使用的
     * BindingResult 存放所有违背效验的错误信息
     * @param clazz
     * @param result
     * @param req
     * @return
     */
    @RequestMapping("/valiAdd")
    public String valiAdd(@Valid Clazz clazz, BindingResult result, HttpServletRequest req){
            //如果服务端验证不通过,有错误
            if(result.hasErrors()){
                //服务端验证了实体类的多个属性,多个属性都没有验证通过
                List fieldErrors = result.getFieldErrors();
                Map map = new HashMap<>();
                for (FieldError fieldError : fieldErrors) {
                    //将多个属性的验证失败信息输送到控制台
                    System.out.println(fieldError.getField() + ":" + fieldError.getDefaultMessage());
                    map.put(fieldError.getField(),fieldError.getDefaultMessage());
             }
                 req.setAttribute("msg",map);
                 return "clzEdit";
            }else {
                this.clazzBiz.insertSelective(clazz);
            }
                return "redirect:/clz/list";
    }




}

2.3前端编码

主界面

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<%@ taglib uri="http://jsp.veryedu.cn" prefix="z"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>



    
    
    
    班级列表
    


新增
ID 名字 教师 图片 操作
${b.cid } ${b.cname } ${b.cteacher } 修改 删除 上传 下载

新增界面 

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>



    
    班级编辑界面


cid:${msg.cid}
cname:${msg.cname}
cteacher:${msg.cteacher}

实现效果:什么都不输入时,直接点提交,会显示在后端编写的注解信息

 

Spring Mvc服务端验证&拦截器_第4张图片

二、拦截器 

 1、拦截器的介绍

 SpringMVC的处理器拦截器,类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。(环绕通知)

  依赖于web框架,在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于
  web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个 
  controller生命周期之内可以多次调用。
 

2.拦截器与过滤器

2.1 什么是过滤器(Filter)

    
     
        依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例
    只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,比如:在过滤器中修改字符编码;
    在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等。
       
  

  2.2 拦截器与过滤器的区别 

        过滤器(filter):

    1) filter属于Servlet技术,只要是web工程都可以使用
    2) filter主要对所有请求过滤
    3) filter的执行时机早于Interceptor

    拦截器(interceptor)

    1) interceptor属于SpringMVC技术,必须要有SpringMVC环境才可以使用
    2) interceptor通常对处理器Controller进行拦截
    3) interceptor只能拦截dispatcherServlet处理的请求

 

3.应用场景

    1)日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。

    2)权限检查:如登录检测,进入处理器检测是否登录,如果没有直接返回到登录页面;

    3)性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);

    4)通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个Controller中的处理方法都需要的,我们就可以使用拦截器实现。

4、拦截器的编码演示

1、建立一个拦截器类并实现拦截器HandlerInterceptor接口

package com.zjy.ljq;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

public class OneInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //预处理
        System.out.println("【OneInterceptor】:preHandle...");
        StringBuffer url = request.getRequestURL();
        if (url.indexOf("/login") > 0 || url.indexOf("/logout") > 0) {
            return true;
        }
        // session判断 是否登录成功
        String uname = (String) request.getSession().getAttribute("uname");
        if (uname == null || "".equals(uname)) {
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        //后处理
        System.out.println("【OneInterceptor】:postHandle...");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //完成后执行
        System.out.println("【OneInterceptor】:afterCompletion...");
    }


}


2、在Springmvc的配置文件中配置拦截器类


        
    

3、编写一个测试类测试方法 

package com.zjy.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class HelloController {
    @RequestMapping("/hello")
    public String hello(){
        System.out.println("进入业务方法。。");
        return "index";
    }
}

 根据运行效果我们能得知拦截器类似Aop环绕通知先执行前处理,在执行业务方法,最后执行后处理

Spring Mvc服务端验证&拦截器_第5张图片

前置处理返回false和ture的区别:

false:只执行了预处理,当我们应用于用户登录信息时,如果用户填写信息错误或未填写就返回false拦截,不进入业务处理界面

true:执行前处理,在执行业务方法,最后执行后处理

 

 5、拦截器链

5.1  再建立·一个·拦截器类 实现HandInterceptor接口

package com.zjy.ljq;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

public class TwoInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("【TwoInterceptor】:preHandle...");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("【TwoInterceptor】:postHandle...");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("【TwoInterceptor】:afterCompletion...");
    }
}

5.2  在SpringMvc配置文件中将两个拦截器类分别进行配置


    
        
            
            
        
        
            
            
        
    

5.3 执行顺序说明

先执行拦截器一,在执行拦截器二,返回时先返回拦截器二、再返回一,就跟人进家门一样,先进大门,再进小门,离开时先从小门出来,再从大门出来。

Spring Mvc服务端验证&拦截器_第6张图片

 6、拦截器具体应用到登录权限控制

6.1  在配置文件中配置一个所有路径的拦截器

   
        
            
            
        

6.2 在登录功能的后端编码中进行判断是否拦截

package com.zjy.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;

@Controller
public class LoginController {
    @RequestMapping("/login")
    public String login(HttpServletRequest req){
        String uname = req.getParameter("uname");
        if ("zjy".equals(uname)){
            req.getSession().setAttribute("uname",uname);
        }
        return "index";
    }

    @RequestMapping("/logout")
    public String logout(HttpServletRequest req){
        req.getSession().invalidate();
        return "index";
    }
}

你可能感兴趣的:(spring,mvc,java)