目录
一、服务端校验
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 在登录功能的后端编码中进行判断是否拦截
客户端校验的安全性低,用户在注册信息时很容易绕过校验,输入不合法的信息
org.hibernate
hibernate-validator
6.0.7.Final
JSR303工具类中包含了许多标签以及能够添加注解来指定实体类中的属性
例如:
@NotNull :作用于基本数据类型
@NotEmpty 作用于集合
@NotBlank 作用于字符串
2.2.1 在model 实体类中添加校验注解
2.2.2 控制层
在控制层中加入了valid和BindingResult
valid和BindingResult
vaild:
是与实体类的服务端效验 注解配合使用的BindingResult:
存放所有违背效验的错误信息
先判断是否存在错误信息,如果有就拿到错误信息的集合,定义一个map集合,遍历集合时将错误信息存在map集合里,传递到前端界面
完整代码:
实体类
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";
}
}
主界面
<%@ 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"%>
班级编辑界面
实现效果:什么都不输入时,直接点提交,会显示在后端编写的注解信息
SpringMVC的处理器拦截器,类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。(环绕通知)
依赖于web框架,在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于
web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个
controller生命周期之内可以多次调用。
依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例
只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,比如:在过滤器中修改字符编码;
在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等。
过滤器(filter):
1) filter属于Servlet技术,只要是web工程都可以使用
2) filter主要对所有请求过滤
3) filter的执行时机早于Interceptor
拦截器(interceptor)
1) interceptor属于SpringMVC技术,必须要有SpringMVC环境才可以使用
2) interceptor通常对处理器Controller进行拦截
3) interceptor只能拦截dispatcherServlet处理的请求
1)日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。
2)权限检查:如登录检测,进入处理器检测是否登录,如果没有直接返回到登录页面;
3)性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);
4)通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个Controller中的处理方法都需要的,我们就可以使用拦截器实现。
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...");
}
}
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环绕通知先执行前处理,在执行业务方法,最后执行后处理
false:只执行了预处理,当我们应用于用户登录信息时,如果用户填写信息错误或未填写就返回false拦截,不进入业务处理界面
true:执行前处理,在执行业务方法,最后执行后处理
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...");
}
}
先执行拦截器一,在执行拦截器二,返回时先返回拦截器二、再返回一,就跟人进家门一样,先进大门,再进小门,离开时先从小门出来,再从大门出来。
’
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";
}
}