目录
一、JSR303
1.1 JSR303的简介
1.2 JSR303实现判空校验
二、拦截器
2.1 什么是拦截器?
2.2 建立一个拦截器
2.2.1 配置拦截器
2.2.2 拦截器方法的执行顺序
2.3 建立拦截器链
2.3.1 配置拦截器链
2.3.2 拦截器链方法的执行顺序
2.4 利用拦截器实现登录权限控制
2.4.1 编写LoginController
2.4.2 登录页面
2.4.3 编写拦截器
2.4.4 配置拦截器
什么是JSR303?
JSR303是一个:{---服务端校验---}
它的作用:
解决了越过表单验证{客户端},直接访问页面的问题;
我们通过上机实操来认识一下JSR303,实现的一些步骤:
① 导入pom依赖
org.hibernate
hibernate-validator
6.0.7.Final
② 在待校验的数据库列段对应的实体类属性打上校验标签:非空校验
三种注解验证:
* @NotNull:作用于基本数据类型
* @NotEmpty:作用于集合
* @NotBlank:作用于字符串
实体类:Clazz.java
package com.leaf.ssm.model;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* @NotNull:作用于基本数据类型
* @NotEmpty:作用于集合
* @NotBlank:作用于字符串
*/
public class Clazz {
@NotNull(message = "cid不能为空")
protected Integer cid;
@NotBlank(message = "班级名称不能为空")
protected String cname;
@NotBlank(message = "教员老师不能为空")
protected String cteacher;
protected 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;
}
}
③ 在controller层方法上添加@Valid注解配合前面的校验标签;
添加BindingResult,此对象包含所有校验为通过的错误信息;
④ 将所有的错误信息以Map集合的方式保存,并且传递到前台页面展示。
总的来说就是编写一个用来校验的方法:
valiAdd(@Valid Clazz clazz, BindingResult bindingResult,HttpServletRequest request)
/**
* 校验的方法(演示校验注解)
* @Valid:是与实体类中的服务端校验注解配合使用的
* BindingResult:存放了所有违背校验的错误信息
* @param clazz
* @param bindingResult
* @return
*/
@RequestMapping("/valiAdd")
public String valiAdd(@Valid Clazz clazz, BindingResult bindingResult,HttpServletRequest request){
if(bindingResult.hasErrors()){//违背了规则
HashMap msg = new HashMap();
//拿到所有错误
List fieldErrors = bindingResult.getFieldErrors();
for (FieldError fieldError : fieldErrors) {
//cid:cid不能为空
System.out.println(fieldError.getField() + ":" + fieldError.getDefaultMessage());
//msg.put(cid, cid不能为空);
msg.put(fieldError.getField(),fieldError.getDefaultMessage());
}
//如果出现了错误,应该将提示语显示在表单提示元素后方
request.setAttribute("msg",msg);
return "clzEdit";
}else{//没有违背
this.clazzBiz.insertSelective(clazz);
}
return "redirect:/clz/list";
}
接下来就让我们来测试一下是否成功校验啦:
新增:
校验成功~
拦截器的初步认知:
① SpringMVC的处理器拦截器,依赖于web框架,在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。
② 一个拦截器实例在一个controller生命周期之内可以多次调用。
拦截器的三个特点:
1) interceptor属于SpringMVC技术,必须要有SpringMVC环境才可以使用
2) interceptor通常对处理器Controller进行拦截
3) interceptor只能拦截dispatcherServlet处理的请求
我们还是一样,通过上机实践、测试,才能去认识并掌握这些技术;
我们先写一个可以访问的方法层:HelloController
package com.leaf.ssm.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 测试
* @author Leaf
* @site 2977819715
* @company 玉渊工作室
* @create 2022-08-20 1:35
*/
@Controller
public class HelloController {
@RequestMapping("hello")
public String hello(){
System.out.println("进入业务方法...");
return "index";
}
}
建立一个拦截器:OneHandlerInterceptor.java
package com.leaf.ssm.intercept;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Leaf
* @site 2977819715
* @company 玉渊工作室
* @create 2022-08-20 1:27
*/
public class OneHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//预处理
System.out.println("[OneHandlerInterceptor] . preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//后处理
System.out.println("[OneHandlerInterceptor] . postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//完成后处理
System.out.println("[OneHandlerInterceptor] . afterCompletion");
}
}
我们需要在springmvc的框架配置文件中配置上我们写的拦截器;
然后我们直接运行测试访问:http://localhost:8080/hello
通过运行结果我们得到几个关于拦截器的结论:
我们拦截器实现的三个方法以及执行顺序分别是:
预处理: [OneHandlerInterceptor] . preHandle
业务方法:进入业务方法...
后处理: [OneHandlerInterceptor] . postHandle
完成后: [OneHandlerInterceptor] . afterCompletion
并且,预处理方法里返回的true或者false就代表能不能继续跳转页面执行;
接着我们来看看拦截器链的概念:
拦截器链的概念:
如果多个拦截器能够对相同的请求进行拦截,则多个拦截器会形成一个拦截器链;
主要理解拦截器链中各个拦截器的执行顺序。
拦截器链中多个拦截器的执行顺序跟拦截器的配置顺序有关,先配置的先执行。
我们再次建立一个拦截器:TwoHandlerInterceptor.java
package com.leaf.ssm.intercept;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Leaf
* @site 2977819715
* @company 玉渊工作室
* @create 2022-08-20 1:27
*/
public class TwoHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//预处理
System.out.println("[TwoHandlerInterceptor] . preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//后处理
System.out.println("[TwoHandlerInterceptor] . postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//完成后处理
System.out.println("[TwoHandlerInterceptor] . afterCompletion");
}
}
这里就要注意,已经有两个拦截器了,配置就也有所不一样了;
然后我们还是运行一下测试:http://localhost:8080/hello
不一样的还有它们的执行顺序,前面关于拦截链的一些介绍已经说明了,需要理解它的执行顺序,这里Leaf特意花了一张运行图,配合文字,希望对大家有帮助。
拦截器链的执行顺序:
先进第一个拦截器--->第二个拦截器--->...
① [OneHandlerInterceptor] . preHandle
② [TwoHandlerInterceptor] . preHandle
③ 业务方法
④ [TwoHandlerInterceptor] . postHandle
⑤ [OneHandlerInterceptor] . postHandle
⑥ [TwoHandlerInterceptor] . afterComplation
⑦ [OneHandlerInterceptor] . afterComplation
OK,上面的都是关于拦截器的理论知识以及一些打印的小测试,下面,我们就通过实际上的案例对拦截器进行使用!
LoginController.java
package com.leaf.ssm.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
/**
* @author Leaf
* @site 2977819715
* @company 玉渊工作室
* @create 2022-08-20 2:25
*/
@Controller
public class LoginController {
/**
* 登录方法
* @param request
* @return
*/
@RequestMapping("/login")
public String login(HttpServletRequest request){
//登录成功需要保存用户信息
String uname = request.getParameter("uname");
if("Leaf".equals(uname)){
request.getSession().setAttribute("uname",uname);
}
return "index";
}
@RequestMapping("/logout")
public String logout(HttpServletRequest request){
request.getSession().invalidate();
return "index";
}
}
就随便建立一个登录页面就行了:login.jsp
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2022/8/20
Time: 2:30
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
登录页面
登录页面
这一步很重要,仔细看看代码,都有部分注释;
OneHandlerInterceptor.java
package com.leaf.ssm.intercept;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Leaf
* @site 2977819715
* @company 玉渊工作室
* @create 2022-08-20 1:27
*/
public class OneHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//预处理
System.out.println("[OneHandlerInterceptor] . preHandle");
//拿到请求路径
String url = request.getRequestURL().toString();
//如果是 login/logout 访问,不拦截,直接放行。
if (url.indexOf("/login") > 0 || url.indexOf("/logout") > 0){
return true;
}
//对于请求业务方法,只有登录过,也就是存在session的数据,才能访问;
String uname = (String) request.getSession().getAttribute("uname");
if(uname == null || "".equals(uname)){
//没有登录,跳回登录页面。
response.sendRedirect("/login.jsp");
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//后处理
System.out.println("[OneHandlerInterceptor] . postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//完成后处理
System.out.println("[OneHandlerInterceptor] . afterCompletion");
}
}
这里注意了,由于是做登录的校验,拦截器,自然要拦截所有请求;
这里直接放上案例用的整个springmvc的框架配置文件吧!
springmvc-servlet.xml
最后就让我们一起来测试一下吧,我们的登录信息是定死的Leaf,开始登录测试: