目录
一、JSR303
二、拦截器
JSR303的作用其实就是类似于验证作用,只是和我们一般的不一样点在于,JSR303是基于服务端的验证,目的在于就是放置客户端的验证被绕过!
现在我们用一个例子:基于之前创建的CRUD的增加,实现JSR303验证,我们想要达到的效果就是我们在输入空的内容时,我们不能向数据库添加数据,并且给出相应的非空提示!
org.hibernate
hibernate-validator
6.0.7.Final
这一步我们需要在对应的实体类判断的属性上方添加非空注释
@NotNull(message = "提示语句")
比如我们举例的例子Clazz对应的属性加上注释
package com.zq.ssm.model;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @NotNull :作用于基本数据类型
* @NotEmpty 作用于集合
* @NotBlank 作用于字符串
*/
public class Clazz {
@NotNull(message = "班级id不能为空")
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;
}
}
既然是服务端的验证,那么和后端的方法判断就息息相关,我们就需要在后端进行判断,我们直接在Clazz的web层加入方法:
ClazzController:
@RequestMapping("/valiadd")
public String valiadd(HttpServletRequest req, @Validated Clazz clazz, BindingResult result){
if(result.hasErrors()){
List fieldErrors = result.getFieldErrors();
Map map = new HashMap<>();
for (FieldError fieldError : fieldErrors) {
map.put(fieldError.getField(),fieldError.getDefaultMessage());
System.out.println(fieldError.getField());
}
req.setAttribute("eMap",map);
}else{
this.clazzBiz.insertSelective(clazz);
return "redirect:/clz/list";
}
return "clzEdit";
}
然后就是我们的前端的代码了,我们需要做的就是加入提示语句的位置放置,通过作用域的显示因为我们在后端进行了判断,如果非空的话就会将提示语句存入Session中。
jsp:
其实拦截器和过滤器是有点相似的只不过:
过滤器依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,比如:在过滤器中修改字符编码在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等。
过滤器(filter):
1) filter属于Servlet技术,只要是web工程都可以使用
2) filter主要对所有请求过滤
3) filter的执行时机早于Interceptor拦截器(interceptor)
1) interceptor属于SpringMVC技术,必须要有SpringMVC环境才可以使用
2) interceptor通常对处理器Controller进行拦截
3) interceptor只能拦截dispatcherServlet处理的请求
我们在这使用一个简单的案例来实现一下拦截器的功能,并且分析一下拦截器的使用
package com.zq.ssm.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author张强
* @site www.zq.com
* @create 2022-08-19 19:49
*/
@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello(){
System.out.println("进入了web层");
return "index";
}
}
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...");
}
}
在这里就是主要是第一个方法,返回值为true则代表通过拦截,为false则进行拦截,然后在第一个方法中进行添加逻辑语句进行我们的拦截判断。
这时我们运行我的web层对应的界面向中央控制器发送请求,然后看一下控制台的打印结果:
我们发现我们在发送请求后,顺序就是:
进入拦截器第一个方法——>通过拦截则进入web层——>第二个方法——>第三个方法
什么是拦截器链?大致的理解就是多重拦截,针对不同的请求进行层层拦截
比如这样的配置文件:
这个配置就可以是对待请求是clz/**的进行双重拦截
第一个是无论什么请求都会进入到 OneInterceptor的拦截器
而第二个是只有以clz/开头的请求才会进入到TwoInterceptor的拦截器
然后当我们请求以clz/开头的请求时,他们的拦截顺序为:
我们将第一个拦截器进行修改作为我们判断我们的用户发送的请求是否是登录之后的,因为实际的项目开发中,这个拦截是必不可少的,我们想要展示主界面的东西那么就得登录,所以我们需要拦截器进行拦截判断。
package com.zq.ssm.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author张强
* @site www.zq.com
* @create 2022-08-19 19:51
*/
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.zq.ssm.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* @author张强
* @site www.zq.com
* @create 2022-08-19 20:05
*/
@Controller
public class LoginController {
@RequestMapping("/login")
public String login(HttpServletRequest req){
String uname = req.getParameter("uname");
HttpSession session = req.getSession();
if ("zs".equals(uname)){
session.setAttribute("uname",uname);
}
return "redirect:/clz/list";
}
@RequestMapping("/logout")
public String logout(HttpServletRequest req){
req.getSession().invalidate();
return "redirect:/clz/list";
}
}
这个案例就是拦截器的一个应用:
我们必须要先登录才能够进入到主界面list.jsp。否则我们直接请求主界面是不会显示主界面的内容的。接下来我们看一下效果输入:
http://localhost:8080/clz/list 不能访问,因为session被过滤掉
http://localhost:8080/login 不能访问,因为用户未成功登录被过滤掉
http://localhost:8080/login?uname=zs 可以访问
http://localhost:8080/logout 清除掉session