Springmvc之JSR303和拦截器

  • JSR303
  • 拦截器

1.JSR303

什么是JSR303

JSR是Java Specification Requests的缩写,意思是Java 规范提案。是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。任何人都可以提交JSR,以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。 JSR-303 是JAVA EE 6 中的一项子规范,叫做Bean Validation,Hibernate Validator 是 Bean Validation 的参考实现 . Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint(约束) 的实现,除此之外还有一些附加的 constraint。

> 验证数据是一项常见任务,它发生在从表示层到持久层的所有应用程序层中。通常在每一层都实现相同的验证逻辑,这既耗时又容易出错。为了避免重复这些验证,开发人员经常将验证逻辑直接捆绑到域模型中,将域类与验证代码混在一起,而验证代码实际上是关于类本身的元数据。

为什么要使用JSR303

前端不是已经校验过数据了吗?为什么我们还要做校验呢,直接用不就好了?草率了,假如说前端代码校验没写好又或者是对于会一点编程的人来说,直接绕过前端发请求(通过类似Postman这样的测试工具进行非常数据请求),把一些错误的参数传过来,你后端代码不就危险了嘛。

所以我们一般都是前端一套校验,后端在一套校验,这样安全性就能够大大得到提升了。

常用注解

注解名称    注解作用说明
@NotNull    主要用于对象的校验,校验对象不能为null,无法检查长度为0的字符串
@NotBlank    用于String类型参数校验,检查字符串不能为null且trim()之后的size>0
@NotEmpty    主要用于集合校验,校验集合不能为null且不能size>0,也可以用于String的校验
@Size    用于对象(Array,Collection,Map,String)长度是否在给定的范围之内
@Range    控制一个数值的范围
@Length    用于String对象的大小必须在指定的范围内
@Pattern    用于String对象是否符合正则表达式的规则
@Email    用于String对象是否符合邮箱格式
@Min    用于Number和String对象是否大等于指定的值
@Max    用于Number和String对象是否小等于指定的值
@AssertTrue    用于Boolean对象是否为true
@AssertFalse    用于Boolean对象是否为false

package com.zlj.web;

import com.zlj.biz.StuBiz;
import com.zlj.model.Stu;
import com.zlj.util.PageBean;
import com.zlj.util.PropertiesUtil;
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.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

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

/**
 * @author zlj
 * @create 2023-09-08 16:55
 */
@Controller
@RequestMapping("stu")
public class StuController {
    @Autowired
    private StuBiz stuBiz;

    //    增
    @RequestMapping("/add")
    public String add(Stu stu,HttpServletRequest request) {
        int i = stuBiz.insert(stu);
        return "redirect:list";
    }
    //    给数据添加服务端校验
    @RequestMapping("/valiAdd")
    public String valiAdd(@Validated Stu stu, 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("errorMap",map);
        }else {
            this.stuBiz.insertSelective(stu);
            return "redirect:list";
        }
        return "stu/edit";
    }

    //            删
    @RequestMapping("/del/{sid}")
    public String del(@PathVariable("sid") Integer sid) {
        stuBiz.deleteByPrimaryKey(sid);
        return "redirect:/stu/list";
    }

//        改
@RequestMapping("/edit")
public String edit(Stu stu) {
    stuBiz.updateByPrimaryKeySelective(stu);
    return "redirect:list";
}
//文件上传
    @RequestMapping("/upload")
    public String upload(Stu stu,MultipartFile xxx){
        try {
//    3.后端可以直接利用mutipartFile类,接受前端传递到后台的文件
//    4.将文件转成流,然后写到服务器(某一个硬盘)
//    上传的图片真实的地址
        String dir= PropertiesUtil.getValue("dir");
//        网络访问的地址
        String server=PropertiesUtil.getValue("server");;
        //文件名
        String filename=xxx.getOriginalFilename();
        System.out.println("文件名"+filename);
        System.out.println("文件类别"+xxx.getContentType());
        FileUtils.copyInputStreamToFile(xxx.getInputStream(),new File(dir+filename));
//      /upload/0703.png
        stu.setSpic(server+filename);
        stuBiz.updateByPrimaryKeySelective(stu);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return "redirect:list";
}


//                查
    @RequestMapping("/list")
    public String list(Stu stu, HttpServletRequest request) {
        //stu是用来接收前台传递后台的参数
        PageBean pageBean = new PageBean();
        pageBean.setRequest(request);
        List stus = stuBiz.ListPager(stu, pageBean);
        request.setAttribute("lst", stus);
        request.setAttribute("pageBean", pageBean);
//      WEB-INF/jsp/stu/list.jsp
        return "stu/list";

    }
//下载文件
    @RequestMapping(value="/download")
    public ResponseEntity download(Stu stu,HttpServletRequest req){

        try {
            //先根据文件id查询对应图片信息
            Stu stus = this.stuBiz.selectByPrimaryKey(stu.getSid());
            String diskPath = PropertiesUtil.getValue("dir");
            String reqPath = PropertiesUtil.getValue("server");
//            /upload/0703.png  -->D:/temp/upload/0703.png
            String realPath = stus.getSpic().replace(reqPath,diskPath);
            String fileName = realPath.substring(realPath.lastIndexOf("/")+1);
            //下载关键代码
            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;
    }
    //多文件上传
    @RequestMapping("/uploads")
    public String uploads(HttpServletRequest req, Stu stu, MultipartFile[] files){
        try {
            StringBuffer sb = new StringBuffer();
            for (MultipartFile file : files) {
                //思路:
                //1) 将上传图片保存到服务器中的指定位置
                String dir = PropertiesUtil.getValue("dir");
                String server = PropertiesUtil.getValue("server");
                String filename = file.getOriginalFilename();
                FileUtils.copyInputStreamToFile(file.getInputStream(),new File(dir+filename));
                sb.append(filename).append(",");
            }
            System.out.println(sb.toString());

        } catch (Exception e) {
            e.printStackTrace();
        }
        return "redirect:list";
    }



    //数据回显
    @RequestMapping("/preSave")
    public String preSave(Stu stu, Model model) {
        if (stu != null && stu.getSid() != null && stu.getSid() != 0) {
            Stu s = stuBiz.selectByPrimaryKey(stu.getSid());
            model.addAttribute("s", s);
        }
        return "stu/edit";
    }
}
<%@ page language="java" pageEncoding="UTF-8"%>
<%@include file="/common/header.jsp"%>



    
    博客的编辑界面


学生id:${errorMap.sid}
学生姓名:${errorMap.same}
学生年龄:${errorMap.sage}

Springmvc之JSR303和拦截器_第1张图片

2.拦截器

什么是拦截器

​SpringMVC的处理器拦截器,类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。依赖于web框架,在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。

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

拦截器与过滤器的区别

- 过滤器(filter)

  1.filter属于Servlet技术,只要是web工程都可以使用

  2.filter主要由于对所有请求过滤

  3.filter的执行时机早于Interceptor

- 拦截器(interceptor)

  1.interceptor属于SpringMVC技术,必须要有SpringMVC环境才可以使用

  2.interceptor通常由于对处理器Controller进行拦截

  3.interceptor只能拦截dispatcherServlet处理的请求

应用场景

- 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。
- 权限检查:如登录检测,进入处理器检测是否登录,如果没有直接返回到登录页面;
- 性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);
- 通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个Controller中的处理方法都需要的,我们就可以使用拦截器实现。

package com.zlj.interceptor;

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...");

        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...");
    }
}
package com.zlj.interceptor;

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...");
    }
}

 单拦截器,多拦截器配置如下,区别:单拦截器只会拦截一次多拦截器会拦截多次。

//spring-mvc.xml


   
    

    
    

    
    
        
        
        
        
    

    



    

    
    
        
        
        
        
        
        
    


    
        
    



















    
    

单拦截器控制台显示

kSpringmvc之JSR303和拦截器_第2张图片

多拦截器控制台显示

Springmvc之JSR303和拦截器_第3张图片

Springmvc之JSR303和拦截器_第4张图片

Springmvc之JSR303和拦截器_第5张图片

package com.zlj.web;

import com.zlj.biz.StuBiz;
import com.zlj.model.Stu;
import com.zlj.util.PageBean;
import com.zlj.util.PropertiesUtil;
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.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

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

/**
 * @author zlj
 * @create 2023-09-08 16:55
 */
@Controller
@RequestMapping("stu")
public class StuController {
    @Autowired
    private StuBiz stuBiz;

    //    增
    @RequestMapping("/add")
    public String add(Stu stu,HttpServletRequest request) {
        int i = stuBiz.insert(stu);
        return "redirect:list";
    }
    //    给数据添加服务端校验
    @RequestMapping("/vliAdd")
    public String vliAdd(@Validated Stu stu, 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("errorMap",map);
        }else {
            this.stuBiz.insertSelective(stu);
            return "redirect:list";
        }
        return "stu/edit";
    }

    //            删
    @RequestMapping("/del/{sid}")
    public String del(@PathVariable("sid") Integer sid) {
        stuBiz.deleteByPrimaryKey(sid);
        return "redirect:/stu/list";
    }

//        改
@RequestMapping("/edit")
public String edit(Stu stu) {
    stuBiz.updateByPrimaryKeySelective(stu);
    return "redirect:list";
}
//文件上传
    @RequestMapping("/upload")
    public String upload(Stu stu,MultipartFile xxx){
        try {
//    3.后端可以直接利用mutipartFile类,接受前端传递到后台的文件
//    4.将文件转成流,然后写到服务器(某一个硬盘)
//    上传的图片真实的地址
        String dir= PropertiesUtil.getValue("dir");
//        网络访问的地址
        String server=PropertiesUtil.getValue("server");;
        //文件名
        String filename=xxx.getOriginalFilename();
        System.out.println("文件名"+filename);
        System.out.println("文件类别"+xxx.getContentType());
        FileUtils.copyInputStreamToFile(xxx.getInputStream(),new File(dir+filename));
//      /upload/0703.png
        stu.setSpic(server+filename);
        stuBiz.updateByPrimaryKeySelective(stu);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return "redirect:list";
}


//                查
    @RequestMapping("/list")
    public String list(Stu stu, HttpServletRequest request) {
        //stu是用来接收前台传递后台的参数
        PageBean pageBean = new PageBean();
        pageBean.setRequest(request);
        List stus = stuBiz.ListPager(stu, pageBean);
        request.setAttribute("lst", stus);
        request.setAttribute("pageBean", pageBean);
//      WEB-INF/jsp/stu/list.jsp
        return "stu/list";

    }
//下载文件
    @RequestMapping(value="/download")
    public ResponseEntity download(Stu stu,HttpServletRequest req){

        try {
            //先根据文件id查询对应图片信息
            Stu stus = this.stuBiz.selectByPrimaryKey(stu.getSid());
            String diskPath = PropertiesUtil.getValue("dir");
            String reqPath = PropertiesUtil.getValue("server");
//            /upload/0703.png  -->D:/temp/upload/0703.png
            String realPath = stus.getSpic().replace(reqPath,diskPath);
            String fileName = realPath.substring(realPath.lastIndexOf("/")+1);
            //下载关键代码
            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;
    }
    //多文件上传
    @RequestMapping("/uploads")
    public String uploads(HttpServletRequest req, Stu stu, MultipartFile[] files){
        try {
            StringBuffer sb = new StringBuffer();
            for (MultipartFile file : files) {
                //思路:
                //1) 将上传图片保存到服务器中的指定位置
                String dir = PropertiesUtil.getValue("dir");
                String server = PropertiesUtil.getValue("server");
                String filename = file.getOriginalFilename();
                FileUtils.copyInputStreamToFile(file.getInputStream(),new File(dir+filename));
                sb.append(filename).append(",");
            }
            System.out.println(sb.toString());

        } catch (Exception e) {
            e.printStackTrace();
        }
        return "redirect:list";
    }



    //数据回显
    @RequestMapping("/preSave")
    public String preSave(Stu stu, Model model) {
        if (stu != null && stu.getSid() != null && stu.getSid() != 0) {
            Stu s = stuBiz.selectByPrimaryKey(stu.getSid());
            model.addAttribute("s", s);
        }
        return "stu/edit";
    }
}
//edit.jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<%@include file="/common/header.jsp"%>



    
    博客的编辑界面


学生id:${errorMap.sid}
学生姓名:${errorMap.same}
学生年龄:${errorMap.sage}

Springmvc之JSR303和拦截器_第6张图片 

package com.zlj.interceptor;

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

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 {
        System.out.println("【implements】:preHandle...");
        StringBuffer url = request.getRequestURL();
        if (url.indexOf("/login") > 0 || url.indexOf("/logout") > 0){
            //        如果是 登录、退出 中的一种
            return true;
        }
//            代表不是登录,也不是退出
//            除了登录、退出,其他操作都需要判断是否 session 登录成功过
        String name = (String) request.getSession().getAttribute("name");
        if (name == null || "".equals(name)){
            response.sendRedirect("/page/login");
            return false;
        }
        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 {

    }
}
package com.zlj.web;

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

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * @author zlj
 * @create 2023-09-12 17:47
 */
@Controller
public class loginController {
    @RequestMapping("/login")
    public String login(HttpServletRequest req){
        String name = req.getParameter("name");
        HttpSession session = req.getSession();
        if ("zs".equals(name)){
            session.setAttribute("name",name);
        }
        return "redirect:/stu/list";
    }

    @RequestMapping("/logout")
    public String logout(HttpServletRequest req){
        req.getSession().invalidate();
        return "redirect:/stu/list";
    }
}
//login.jsp
<%--
  Created by IntelliJ IDEA.
  User: 朱
  Date: 2023/9/12
  Time: 17:46
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title


登录

用户:

Springmvc之JSR303和拦截器_第7张图片

你可能感兴趣的:(状态模式)