SpringMVC中的JSR303與攔截器的使用方法
一,JSR303的概念
JSR303是Java中的一個標(biāo)準(zhǔn),用于驗(yàn)證和校驗(yàn)JavaBean對象的屬性的合法性。它提供了一組用于定義驗(yàn)證規(guī)則的注解,如@NotNull、@Min、@Max等。在Spring MVC中,可以使用JSR303注解對請求參數(shù)進(jìn)行校驗(yàn)。
1.2 為什么要使用JSR303?(更加理解)
前端不是已經(jīng)校驗(yàn)過數(shù)據(jù)了嗎?為什么我們還要做校驗(yàn)?zāi)?,直接用不就好了?草率了,假如說前端代碼校驗(yàn)沒寫好又或者是對于會一點(diǎn)編程的人來說,直接繞過前端發(fā)請求(通過類似Postman這樣的測試工具進(jìn)行非常數(shù)據(jù)請求),把一些錯誤的參數(shù)傳過來,你后端代碼不就危險了嘛
所以我們一般都是前端一套校驗(yàn),后端在一套校驗(yàn),這樣安全性就能夠大大得到提升了。
1.3 常用的注解
在上面JSR303的概念中也指到了一些注解,以下是注解的詳細(xì)概述
| 注解 | 說明 |
|---|---|
| @Null | 用于驗(yàn)證對象為null |
| @NotNull | 用于對象不能為null,無法查檢長度為0的字符串 |
| @NotBlank | 只用于String類型上,不能為null且trim()之后的size>0 |
| @NotEmpty | 用于集合類、String類不能為null,且size>0。但是帶有空格的字符串校驗(yàn)不出來 |
| @Size | 用于對象(Array,Collection,Map,String)長度是否在給定的范圍之內(nèi) |
| @Length | 用于String對象的大小必須在指定的范圍內(nèi) |
| @Pattern | 用于String對象是否符合正則表達(dá)式的規(guī)則 |
| 用于String對象是否符合郵箱格式 | |
| @Min | 用于Number和String對象是否大等于指定的值 |
| @Max | 用于Number和String對象是否小等于指定的值 |
| @AssertTrue | 用于Boolean對象是否為true |
| @AssertFalse | 用于Boolean對象是否為false |
1.4 @Validated與@Valid區(qū)別
@Validated:
Spring提供的
支持分組校驗(yàn)
可以用在類型、方法和方法參數(shù)上。但是不能用在成員屬性(字段)上
由于無法加在成員屬性(字段)上,所以無法單獨(dú)完成級聯(lián)校驗(yàn),需要配合@Valid
@Valid:
JDK提供的(標(biāo)準(zhǔn)JSR-303規(guī)范)
不支持分組校驗(yàn)
可以用在方法、構(gòu)造函數(shù)、方法參數(shù)和成員屬性(字段)上
可以加在成員屬性(字段)上,能夠獨(dú)自完成級聯(lián)校驗(yàn)
二,JSR303使用
2.1 導(dǎo)入pom.xml依賴
<!-- JSR303 -->
<hibernate.validator.version>6.0.7.Final</hibernate.validator.version>
<!-- JSR303 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate.validator.version}</version>
</dependency>2.2 配置校驗(yàn)規(guī)則
package com.Bingzy.model;
import lombok.ToString;
import org.hibernate.validator.constraints.NotBlank;
@ToString
public class Tbook {
@ToString
public class Clazz {
@NotNull(message = "書籍編號不能為空")
protected Integer bid;
@NotBlank(message = "書籍名不能為空")
protected String bname;
@NotBlank(message = "書籍價格不能為空")
protected Float price;
public Clazz(String bid, String bname, Float price) {
this.bid = bid;
this.bname = bname;
this.price = price;
}
public String getBid() {
return bid;
}
public void setBid(String bid) {
this.bid = bid;
}
public String getBname() {
return bname;
}
public void setBname(String bname) {
this.bname = bname;
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
this.price = price;
}
@Override
public String toString() {
return "Clazz{" +
"bid='" + bid + '\'' +
", bname='" + bname + '\'' +
", price=" + price +
'}';
}
}
}2.3 入門案例
在請求處理方法中,使用@Validated或@Valid注解要驗(yàn)證的對象,并根據(jù)BindingResult判斷校驗(yàn)是否通過。
// 給數(shù)據(jù)添加服務(wù)端校驗(yàn)
@RequestMapping("/valiAdd")
public String valiAdd(@Validated Tbook tbook,
BindingResult result,
HttpServletRequest req){
// 如果服務(wù)端驗(yàn)證不通過,有錯誤
if(result.hasErrors()){
// 服務(wù)端驗(yàn)證了實(shí)體類的多個屬性,多個屬性都沒有驗(yàn)證通過
List<FieldError> fieldErrors = result.getFieldErrors();
Map<String,Object> map = new HashMap<>();
for (FieldError fieldError : fieldErrors) {
// 將多個屬性的驗(yàn)證失敗信息輸送到控制臺
System.out.println(fieldError.getField() + ":" + fieldError.getDefaultMessage());
map.put(fieldError.getField(),fieldError.getDefaultMessage());
}
req.setAttribute("errorMap",map);
}else {
this.tbookBiz.insertSelective(tbook);
return "redirect:list";
}
return "book/edit";
}edit.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>博客的編輯界面</title>
</head>
<body>
<center>
編輯界面
<form action="${pageContext.request.contextPath }/${empty b ? 'book/valiAdd' : 'book/edit'}" method="post"><br>
書籍id:<input type="text" name="bid" value="${b.bid }"><span style="color: red">${errorMap.bid}</span><br>
書籍名稱:<input type="text" name="bname" value="${b.bname }"><span style="color: red">${errorMap.bname}</span><br>
書籍價格:<input type="text" name="price" value="${b.price }"><span style="color: red">${errorMap.price}</span><br>
<input type="submit">
</form>
</center>
</body>
</html>運(yùn)行結(jié)果:
點(diǎn)擊新增或修改,進(jìn)入頁面后點(diǎn)擊提交顯示相對應(yīng)的提示語句

三,攔截器
3.1 什么是攔截器?
Spring MVC攔截器是Spring框架中的一個組件,用于攔截請求并在請求處理之前或之后執(zhí)行一些額外的操作。它可以用于實(shí)現(xiàn)一些通用的、與業(yè)務(wù)無關(guān)的功能,如日志記錄、權(quán)限驗(yàn)證、異常處理、跨域請求處理等。
攔截器在請求到達(dá)DispatcherServlet之后,但在具體的Controller方法執(zhí)行之前,提供了一個攔截點(diǎn),可以對請求進(jìn)行處理和干預(yù)。攔截器可以攔截請求、響應(yīng)或會話的各個階段,并在每個階段執(zhí)行預(yù)定義的操作。
3.2 什么是過濾器
依賴于servlet容器。在實(shí)現(xiàn)上基于函數(shù)回調(diào),可以對幾乎所有請求進(jìn)行過濾,但是缺點(diǎn)是一個過濾器實(shí)例只能在容器初始化時調(diào)用一次。使用過濾器的目的是用來做一些過濾操作,比如:在過濾器中修改字符編碼;在過濾器中修改HttpServletRequest的一些參數(shù),包括:過濾低俗文字、危險字符等
3.3 攔截器與過濾器的區(qū)別?
過濾器(filter)
1.filter屬于Servlet技術(shù),只要是web工程都可以使用
2.filter主要由于對所有請求過濾
3.filter的執(zhí)行時機(jī)早于Interceptor
攔截器(interceptor)
1.interceptor屬于SpringMVC技術(shù),必須要有SpringMVC環(huán)境才可以使用
2.interceptor通常由于對處理器Controller進(jìn)行攔截
3.interceptor只能攔截dispatcherServlet處理的請求
3.4 應(yīng)用場景
日志記錄:記錄請求信息的日志,以便進(jìn)行信息監(jiān)控、信息統(tǒng)計、計算PV(Page View)等。
權(quán)限檢查:如登錄檢測,進(jìn)入處理器檢測是否登錄,如果沒有直接返回到登錄頁面;
性能監(jiān)控:有時候系統(tǒng)在某段時間莫名其妙的慢,可以通過攔截器在進(jìn)入處理器之前記錄開始時間,在處理完后記錄結(jié)束時間,從而得到該請求的處理時間(如果有反向代理,如apache可以自動記錄);
通用行為:讀取cookie得到用戶信息并將用戶對象放入請求,從而方便后續(xù)流程使用,還有如提取Locale、Theme信息等,只要是多個Controller中的處理方法都需要的,我們就可以使用攔截器實(shí)現(xiàn)
四,攔截器快速入門
定義一個包并創(chuàng)建OneInterceptor類
攔截器(interceptor):
package com.Bingzy.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...");
}
}spring-mvc.xml配置自定義攔截器
<mvc:interceptors>
<bean class="com.Bingzy.interceptor.OneInterceptor"></bean>
</mvc:interceptors>在攔截器(interceptor)中的preHandle()方法中的返回值為true未攔截的情況:

在攔截器(interceptor)中的preHandle()方法中的返回值為false攔截的情況:
注意:攔截器會根據(jù)preHandle()方法返回值進(jìn)行攔截判斷,返回了一個true值。這個返回值表示該攔截器已經(jīng)處理了當(dāng)前的請求,并且可以繼續(xù)向下傳遞請求。如果返回false,則表示該攔截器不處理當(dāng)前請求,請求將被終止
4.1 攔截器原理圖

preHandle:用于對攔截到的請求進(jìn)行預(yù)處理,方法接收布爾(true,false)類型的返回值,返回true:放行,false:不放行。
執(zhí)行時機(jī):在處理器方法執(zhí)行前執(zhí)行
方法參數(shù)
參數(shù) 說明 request 請求對象 response 響應(yīng)對象 handler 攔截到的方法處理 postHandle:用于對攔截到的請求進(jìn)行后處理,可以在方法中對模型數(shù)據(jù)和視圖進(jìn)行修改
執(zhí)行時機(jī):在處理器的方法執(zhí)行后,視圖渲染之前
方法參數(shù)
參數(shù) 說明 request 請求對象 response 響應(yīng)對象 handler 攔截到的處理器方法 ModelAndView 處理器方法返回的模型和視圖對象,可以在方法中修改模型和視圖 afterCompletion:用于在整個流程完成之后進(jìn)行最后的處理,如果請求流程中有異常,可以在方法中獲取對象
執(zhí)行時機(jī):視圖渲染完成后(整個流程結(jié)束之后)
方法參數(shù)
參數(shù) 說明 request 請求參數(shù) response 響應(yīng)對象 handler 攔截到的處理器方法 ex 異常對象
4.2 攔截器鏈
如果多個攔截器能夠?qū)ο嗤恼埱筮M(jìn)行攔截,則多個攔截器會形成一個攔截器鏈,主要理解攔截器鏈中各個攔截器的執(zhí)行順序。攔截器鏈中多個攔截器的執(zhí)行順序,根攔截器的配置順序有關(guān),先配置的先執(zhí)行
攔截器(interceptor)
package com.Bingzy.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配置自定義攔截器
<mvc:interceptors>
<!--2) 多攔截器(攔截器鏈)-->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.Bingzy.interceptor.OneInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/book/**"/>
<bean class="com.Bingzy.interceptor.TwoInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>運(yùn)行展示:

五,用戶登錄權(quán)限案例
登入攔截器(interceptor):
package com.Bingzy.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
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 bname = (String) request.getSession().getAttribute("bname");
if (bname == null || "".equals(bname)){
response.sendRedirect("/page/book/login");
return false;
}
return true;
}
}spring-mvc.xml配置自定義登入攔截器
<mvc:interceptors>
<bean class="com.Bingzy.interceptor.LoginInterceptor"></bean>
</mvc:interceptors>Controller層(web):
package com.Bingzy.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@Controller
public class LoginController {
@RequestMapping("/login")
public String login(HttpServletRequest req){
String bname = req.getParameter("bname");
HttpSession session = req.getSession();
if ("zs".equals(bname)){
session.setAttribute("bname",bname);
}
return "redirect:/book/list";
}
@RequestMapping("/logout")
public String logout(HttpServletRequest req){
req.getSession().invalidate();
return "redirect:/book/list";
}
}login.jsp:
簡單的測試布局,可自行布局

測試結(jié)果:

總結(jié):
如果用戶發(fā)送URL中的后綴包含"/login"或"/logout",則表示當(dāng)前請求是登錄或退出操作,直接返回true表示繼續(xù)處理請求,后端進(jìn)行判斷“uname”是否為“zs”,如果不是zs則域?qū)ο蟛粫4?,從而到攔截器判斷域?qū)ο鬄榭談t會重定向到登良頁面,如果不為空就執(zhí)行后端返回的字符串到視圖解析器解析跳轉(zhuǎn)指定頁面
到此這篇關(guān)于SpringMVC中的JSR303與攔截器的使用方法的文章就介紹到這了,更多相關(guān)SpringMVC JSR303與攔截器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Springboot集成JSR303參數(shù)校驗(yàn)的方法實(shí)現(xiàn)
- Spring Boot利用JSR303實(shí)現(xiàn)參數(shù)驗(yàn)證的方法實(shí)例
- SpringBoot結(jié)合JSR303對前端數(shù)據(jù)進(jìn)行校驗(yàn)的示例代碼
- SpringBoot使用jsr303校驗(yàn)的實(shí)現(xiàn)
- Spring中使用JSR303請求約束判空的實(shí)現(xiàn)
- SpringBoot后端進(jìn)行數(shù)據(jù)校驗(yàn)JSR303的使用詳解
- springboot接口參數(shù)校驗(yàn)JSR303的實(shí)現(xiàn)
- springboot整合JSR303參數(shù)校驗(yàn)與全局異常處理的方法
- springboot整合JSR303校驗(yàn)功能實(shí)現(xiàn)代碼
相關(guān)文章
Java微信掃碼登錄功能并實(shí)現(xiàn)認(rèn)證授權(quán)全過程
這篇文章主要給大家介紹了關(guān)于Java微信掃碼登錄功能并實(shí)現(xiàn)認(rèn)證授權(quán)的相關(guān)資料,要在Java中實(shí)現(xiàn)微信掃碼登錄,您可以按照以下步驟進(jìn)行操作,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10
java批量采集豌豆莢網(wǎng)站Android應(yīng)用圖標(biāo)和包名
這篇文章主要介紹了java批量采集豌豆莢網(wǎng)站Android應(yīng)用圖標(biāo)和包名,主要用在做主題時替換這些常見應(yīng)用的圖片,需要的朋友可以參考下2014-06-06
Java實(shí)現(xiàn)規(guī)則幾何圖形的繪制與周長面積計算詳解
隨著計算機(jī)的發(fā)展,人們對圖形的計算要求會越來越高。在各行各業(yè)中的計算人員會對圖形的計算要有便利的要求,規(guī)則幾何圖形問題求解程序應(yīng)運(yùn)而生!本文將用Java編寫一個程序,可以實(shí)現(xiàn)規(guī)則幾何圖形的繪制與周長面積計算,感興趣的可以了解一下2022-07-07
springcloud中RabbitMQ死信隊列與延遲交換機(jī)實(shí)現(xiàn)方法
死信隊列是消息隊列中非常重要的概念,同時我們需要業(yè)務(wù)場景中都需要延遲發(fā)送的概念,比如12306中的30分鐘后未支付訂單取消,那么本期,我們就來講解死信隊列,以及如何通過延遲交換機(jī)來實(shí)現(xiàn)延遲發(fā)送的需求,感興趣的朋友一起看看吧2022-05-05
spring boot實(shí)現(xiàn)在request里解密參數(shù)返回
這篇文章主要介紹了Spring Boot實(shí)現(xiàn)在request里解密參數(shù)返回操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
SpringBoot整合Elasticsearch?8.x的實(shí)戰(zhàn)總結(jié)(附完整示例)
Elasticsearch(簡稱 ES)是當(dāng)前最流行的分布式搜索引擎,具備強(qiáng)大的全文檢索與數(shù)據(jù)分析能力,本文基于官方文檔與實(shí)戰(zhàn)經(jīng)驗(yàn),系統(tǒng)總結(jié) ?Spring Boot 整合 Elasticsearch 8.x 的核心要點(diǎn)、版本選型和三種主流實(shí)現(xiàn)方式,感興趣的小伙伴可以了解下2026-03-03

