目录
一、JSR303
①JSR303介绍
JSR303的作用其实就是类似于验证作用,只是和我们一般的不一样点在于,JSR303是基于服务端的验证,目的在于就是放置客户端的验证被绕过!
现在我们用一个例子:基于之前创建的CRUD的增加,实现JSR303验证,我们想要达到的效果就是我们在输入空的内容时,我们不能向数据库添加数据,并且给出相应的非空提示!
②实现非空验证
2.1导入POM依赖
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.7.Final</version>
</dependency>
2.2添加非空注释
这一步我们需要在对应的实体类判断的属性上方添加非空注释
@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;
}
}
2.3后端编码
既然是服务端的验证,那么和后端的方法判断就息息相关,我们就需要在后端进行判断,我们直接在Clazz的web层加入方法:
ClazzController:
@RequestMapping("/valiadd")
public String valiadd(HttpServletRequest req, @Validated Clazz clazz, BindingResult result){
if(result.hasErrors()){
List<FieldError> fieldErrors = result.getFieldErrors();
Map<String,Object> 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";
}
2.4前端编码
然后就是我们的前端的代码了,我们需要做的就是加入提示语句的位置放置,通过作用域的显示因为我们在后端进行了判断,如果非空的话就会将提示语句存入Session中。
jsp:
<body>
<form action="${pageContext.request.contextPath }/clz/${empty b ? 'valiadd' : 'edit'}" method="post">
id:<input type="text" name="cid" value="${b.cid }"><span style="color: red;">${eMap.cid}</span><br>
cname:<input type="text" name="cname" value="${b.cname }"><span style="color: red;">${eMap.cname}</span><br>
cteacher:<input type="text" name="cteacher" value="${b.cteacher }"><span style="color: red;">${eMap.cteacher}</span><br>
<input type="submit">
</form>
</body>
2.5效果显示:
二、拦截器
①什么是拦截器?
其实拦截器和过滤器是有点相似的只不过:
过滤器依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,比如:在过滤器中修改字符编码在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等。
②拦截器与过滤器的区别
过滤器(filter):
1) filter属于Servlet技术,只要是web工程都可以使用
2) filter主要对所有请求过滤
3) filter的执行时机早于Interceptor拦截器(interceptor)
1) interceptor属于SpringMVC技术,必须要有SpringMVC环境才可以使用
2) interceptor通常对处理器Controller进行拦截
3) interceptor只能拦截dispatcherServlet处理的请求
③案例实现拦截器
我们在这使用一个简单的案例来实现一下拦截器的功能,并且分析一下拦截器的使用
3.1创建一个web层用来跳转页面
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";
}
}
3.2创建拦截器对象,实现接口,实现接口方法
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则进行拦截,然后在第一个方法中进行添加逻辑语句进行我们的拦截判断。
3.3在SpringMVC配置文件中添加配置:
<mvc:interceptors>
<bean class="com.zq.ssm.interceptor.OneInterceptor"></bean>
</mvc:interceptors>
3.4运行结果查看拦截的逻辑顺序:
这时我们运行我的web层对应的界面向中央控制器发送请求,然后看一下控制台的打印结果:
我们发现我们在发送请求后,顺序就是:
进入拦截器第一个方法——>通过拦截则进入web层——>第二个方法——>第三个方法
④拦截器链
什么是拦截器链?大致的理解就是多重拦截,针对不同的请求进行层层拦截
比如这样的配置文件:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.zq.ssm.interceptor.OneInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/clz/**"/>
<bean class="com.zq.ssm.interceptor.TwoInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
这个配置就可以是对待请求是clz/**的进行双重拦截
第一个是无论什么请求都会进入到 OneInterceptor的拦截器
而第二个是只有以clz/开头的请求才会进入到TwoInterceptor的拦截器
然后当我们请求以clz/开头的请求时,他们的拦截顺序为:
⑤拦截器实际运用:必须登录才能进入主界面
我们将第一个拦截器进行修改作为我们判断我们的用户发送的请求是否是登录之后的,因为实际的项目开发中,这个拦截是必不可少的,我们想要展示主界面的东西那么就得登录,所以我们需要拦截器进行拦截判断。
5.1拦截器配置:
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.zq.ssm.interceptor.OneInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
5.2OneInterceptor业务编写
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...");
}
}
5.3请求业务(web)编写:
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";
}
}
5.4案例分析
这个案例就是拦截器的一个应用:
我们必须要先登录才能够进入到主界面list.jsp。否则我们直接请求主界面是不会显示主界面的内容的。接下来我们看一下效果输入:
http://localhost:8080/clz/list 不能访问,因为session被过滤掉
http://localhost:8080/login 不能访问,因为用户未成功登录被过滤掉
http://localhost:8080/login?uname=zs 可以访问
http://localhost:8080/logout 清除掉session