Java使用validation攔截非法提交的數(shù)據(jù)的方法實(shí)現(xiàn)
注意:本文使用的是Springboot 2.x版本,如果使用其他版本會(huì)略有差異,本文僅作拋轉(zhuǎn)引義,開發(fā)時(shí)需結(jié)合自己項(xiàng)目的實(shí)際情況來定。
一.引入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>二.提交數(shù)據(jù)的實(shí)體類添加驗(yàn)證規(guī)則的注解
需根據(jù)屬性的類型和業(yè)務(wù)規(guī)則添加相應(yīng)的注解
import lombok.Data;
import org.hibernate.validator.constraints.URL;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @author:
* @Desc:
* @create: 2025-04-14 10:32
**/
@Data
public class StoreDeviceDTO {
@NotNull(message = "storeId不能為空")
private Long storeId;
@NotBlank(message = "設(shè)備名稱不能為空")
private String deviceName;
@NotBlank(message = "設(shè)備圖片不能為空")
@URL(message = "設(shè)備圖片必須是一個(gè)合法的URL地址")
private String deviceImage;
}
三.在控制器方法上添加@Valid注解
@PostMapping("/addApply")
public AjaxResult add(@Valid @RequestBody StoreApplyDTO storeApplyDTO)
{
storeApplyService.saveStoreApply(storeApplyDTO);
return AjaxResult.success();
}如果傳的集合類型的數(shù)據(jù),則比較特殊,需要在控制器類名上加上@Validated注解,同時(shí)方法中也要加上上@Validated注解,正確的使用方式如下:
@RestController
@Validated
public class StoreDeviceController {
@Autowired
private IStoreDeviceService storeDevicesService;
@PostMapping("/saveDevices")
public AjaxResult saveDevices(@RequestBody @Validated List<@Valid StoreDeviceDTO> deviceDTOList) {
storeDevicesService.saveDevices(deviceDTOList);
return AjaxResult.success();
}
}其中@Valid和@Validated引用的包為:
import org.springframework.validation.annotation.Validated; import javax.validation.Valid;
為了給前端返回時(shí)是可讀性強(qiáng)的文字說明,而不是一堆英文說明,需要在全局異常處理類中添加如下代碼:
@RestControllerAdvice
public class GlobalExceptionHandler
{
/**
* 自定義驗(yàn)證異常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e)
{
//log.error(e.getMessage(), e);
String message = e.getBindingResult().getFieldError().getDefaultMessage();
return AjaxResult.error(message);
}
}第一個(gè)返回示例:
{
"msg": "門店id不能為空",
"code": 500
}第二個(gè)返回示例(可進(jìn)一步優(yōu)化):
{
"msg": "saveDevices.deviceDTOList[0].deviceName: 設(shè)備名稱不能為空, saveDevices.deviceDTOList[0].deviceImage: 設(shè)備圖片必須是一個(gè)合法的URL地址",
"code": 500
}拓展:分組校驗(yàn)
很多時(shí)候,有新增和修改操作,需進(jìn)行不同的驗(yàn)證,比如新增時(shí)無需帶id,而修改時(shí)必須帶id,此時(shí)可通過分組檢驗(yàn),以實(shí)現(xiàn)區(qū)別對(duì)接。下面是實(shí)現(xiàn)的過程:
1.創(chuàng)建新建和修改的分組interface
//新增
public interface AddGroup {
}
//修改
public interface UpdateGroup {
}2.請(qǐng)求體添加分組注解
import com.bbc.validate.group.AddGroup;
import com.bbc.validate.group.UpdateGroup;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.*;
import java.util.List;
/**
* @author:
* @Desc:
* @create: 2025-03-22 14:34
**/
@Data
@ApiModel(description = "認(rèn)證項(xiàng)目請(qǐng)求體")
public class CertificateDTO {
@ApiModelProperty("申請(qǐng)認(rèn)證ID")
@NotNull(message = "申請(qǐng)認(rèn)證ID不能為空",groups ={UpdateGroup.class})
private Long id;
@NotNull(message = "storeId不能為空",groups ={AddGroup.class,UpdateGroup.class})
private Long storeId;
@NotBlank(message = "認(rèn)證項(xiàng)目不能為空",groups ={AddGroup.class,UpdateGroup.class})
@ApiModelProperty("認(rèn)證項(xiàng)目")
private String project;
@NotNull(message = "請(qǐng)上傳證書材料", groups = {AddGroup.class})
@Size(min = 1, max = 9, message = "請(qǐng)上傳1-9張證書材料圖片", groups = {AddGroup.class, UpdateGroup.class})
@ApiModelProperty("認(rèn)證項(xiàng)目材料圖片(1-9張)")
private List<String> certificateMaterials;
@Size(max = 200, message = "認(rèn)證說明最多200個(gè)字符")
@ApiModelProperty("認(rèn)證說明/備注(最多200字)")
private String instructions;
}3.controller中的方法添加了分組
@ApiOperation("新增認(rèn)證管理")
@Log(title = "認(rèn)證管理", businessType = BusinessType.INSERT)
@PostMapping("/saveProject")
@RepeatSubmit(interval = 5000, message = "不允許重復(fù)提交,請(qǐng)稍候再試")
public AjaxResult add(@Validated(AddGroup.class) @RequestBody CertificateDTO certificateDTO)
{
certificateService.saveCertificateProject(certificateDTO);
return AjaxResult.success();
}
/**
* 修改認(rèn)證管理
*/
@ApiOperation("修改認(rèn)證管理")
@Log(title = "認(rèn)證管理", businessType = BusinessType.UPDATE)
@PutMapping("/editProject")
public AjaxResult edit(@Validated(UpdateGroup.class) @RequestBody CertificateDTO certicateDTO)
{
certificateService.updateCertificateProject(certicateDTO);
return AjaxResult.success();
}避坑指南:
如果DTO類某個(gè)屬性添加了分組校驗(yàn),但Controller方法未指定校驗(yàn)分組,會(huì)導(dǎo)致分組校驗(yàn)失效,沒有添加分組注解的基礎(chǔ)校驗(yàn)仍然有效。
情況說明:
1. 默認(rèn)行為
- 未指定分組:當(dāng)Controller方法沒有使用
@Validated指定分組時(shí),只會(huì)校驗(yàn)沒有分組的約束注解 - 有分組注解:帶有
groups屬性的校驗(yàn)注解將被跳過(因?yàn)闆]有添加@Validated注解)
2. 示例分析
public class CertificateDTO {
@NotEmpty(message = "證書材料不能為空", groups = {AddGroup.class}) // 有分組
private List<String> certificateMaterials;
@Size(max = 200) // 無分組
private String instructions;
}在Controller中:
@PostMapping
public void save(@RequestBody @Valid StoreCertificateDTO dto) {
// 只會(huì)校驗(yàn)instructions字段
// certificateMaterials不會(huì)被校驗(yàn),因?yàn)槲粗付ˋddGroup分組
}3. 解決方案
方案1:在Controller類上添加@Validated注解
@RestController
@Validated(AddGroup.class) // 指定默認(rèn)分組
public class CertificateController {
@PostMapping
public void save(@RequestBody @Valid CertificateDTO dto) {
// 現(xiàn)在會(huì)校驗(yàn)AddGroup分組和沒有分組的約束
}
}方案2:在方法參數(shù)上指定分組
@PostMapping
public void save(@RequestBody @Validated(AddGroup.class) StoreCertificateDTO dto) {
// 明確指定校驗(yàn)分組
}方案3:混合使用(推薦)
@RestController
@Validated // 類級(jí)別啟用校驗(yàn)
public class CertificateController {
@PostMapping("/add")
public void add(@RequestBody @Validated(AddGroup.class) StoreCertificateDTO dto) {
// 添加操作使用AddGroup分組
}
@PostMapping("/update")
public void update(@RequestBody @Validated(UpdateGroup.class) StoreCertificateDTO dto) {
// 更新操作使用UpdateGroup分組
}
}4. 重要注意事項(xiàng)
@Valid vs @Validated:
@Valid(JSR-303)不支持分組@Validated(Spring擴(kuò)展)支持分組
默認(rèn)校驗(yàn):
- 沒有分組的約束注解總是會(huì)被校驗(yàn)
- 有分組的約束只在指定對(duì)應(yīng)分組時(shí)才會(huì)校驗(yàn)
繼承關(guān)系:
- 分組可以繼承,父接口的分組會(huì)被子接口繼承
分組雖好,使用不當(dāng)可能會(huì)得不到預(yù)期的結(jié)果,那么什么情況下要分組,什么情況下不分組呢:
5. 使用建議
- 明確指定分組:重要的業(yè)務(wù)校驗(yàn)都應(yīng)該明確指定分組
- 分層設(shè)計(jì):
- 基礎(chǔ)校驗(yàn)(非空、格式等)可以不分組
- 業(yè)務(wù)規(guī)則校驗(yàn)使用分組
- 文檔注釋:在代碼中注明各分組的用途
- 測(cè)試覆蓋:編寫測(cè)試驗(yàn)證分組校驗(yàn)是否按預(yù)期工作
到此這篇關(guān)于Java使用validation攔截非法提交的數(shù)據(jù)的文章就介紹到這了,更多相關(guān)Java使用validation攔截非法提交內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Springboot項(xiàng)目javax.validation使用方法詳解
- java validation 后臺(tái)參數(shù)驗(yàn)證的使用詳解
- java使用Validation進(jìn)行數(shù)據(jù)校驗(yàn)的方式總結(jié)
- JAVA中通過Hibernate-Validation進(jìn)行參數(shù)驗(yàn)證
- JAVA中的字段校驗(yàn)(validation)
- 使用javax.validation.constraints對(duì)請(qǐng)求體進(jìn)行統(tǒng)一校驗(yàn)
- Java參數(shù)校驗(yàn)中validation和validator的區(qū)別詳解
- Java Validation Api實(shí)現(xiàn)原理解析
- Java Validation Api如何實(shí)現(xiàn)自定義注解
- Javax Validation自定義注解進(jìn)行身份證號(hào)校驗(yàn)
相關(guān)文章
springmvc處理模型數(shù)據(jù)ModelAndView過程詳解
這篇文章主要介紹了springmvc處理模型數(shù)據(jù)ModelAndView過程詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01
Java Spring 中的監(jiān)聽器Listener詳解與實(shí)戰(zhàn)教程
Spring 提供了多種監(jiān)聽器機(jī)制,可以用于監(jiān)聽?wèi)?yīng)用生命周期、會(huì)話生命周期和請(qǐng)求處理過程中的事件,這篇文章主要介紹了Java Spring 之監(jiān)聽器(Listener)詳解與實(shí)戰(zhàn),需要的朋友可以參考下2025-06-06
SpringBoot實(shí)現(xiàn)驗(yàn)證碼的案例分享
驗(yàn)證碼可以有效防止其他人對(duì)某一個(gè)特定的注冊(cè)用戶用特定的程序,破解方式進(jìn)行不斷的登錄嘗試,我們其實(shí)很經(jīng)常看到,登錄一些網(wǎng)站其實(shí)是需要驗(yàn)證碼的,所以本文給大家分享了SpringBoot實(shí)現(xiàn)驗(yàn)證碼的案例,需要的朋友可以參考下2024-11-11
Java之如何讀取Excel獲取真實(shí)行數(shù)
這篇文章主要介紹了Java之如何讀取Excel獲取真實(shí)行數(shù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。2023-06-06
Java調(diào)用第三方接口封裝實(shí)現(xiàn)
本文主要介紹了Java調(diào)用第三方接口封裝實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02

