spring数据验证
一般情况下,我们并不推荐在服务端做基础的数据校验,因为这有一个很主要的问题:它加重了服务器的负载,如果并发多,这种负载就更加明显。
如果我们跟踪一个简单的Controller方法执行过程,就会发现Spring的一个http请求所需要执行的代码实在太多了。
因为这种特性,所以spring很适合用于开发一些对实时性要求不太高,单实例并发不太高的系统,或者说它适合用于开发运行于资源比较充裕的环境。
spring后续应该允许工程师做更灵活的配置--允许不加载一些不需要的,不必要的。 虽然现在已经部分有了,但是还不太够,因为它现在实在有点庞杂了。
不过既然有这个功能,也不妨用用,例如如果前端不是那么给力的情况下,可以把一些压力负载在后端上。
又或者把大部分的业务逻辑就放在后端,前端存粹就是展示而已,这样即使更换前端代码,耗费在前端的时间也比较少。
网络上有许多例子,本文仅仅是为了做个笔记,我本人并不推荐这种做法--在服务端做一些简单的数据校验。
本文例子参考了 https://blog.csdn.net/weixin_44953227/article/details/121841128
以下是本人的例子。
运行环境:springboot-2.6.7,jdk17,windows11.
验证类-ValidMessage
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import study.config.anno.ValidIsPositive; public class ValidMessage implements ConstraintValidator<ValidIsPositive, String> { @Override public boolean isValid(String value, ConstraintValidatorContext context) { if(value==null || value.trim().equals("")) { return true; } String message=value.trim(); if (message.contains("混吃等死") || message.contains("得过且过")) { return false; } return true; } }
注解-ValidIsPositive
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.validation.Constraint; import javax.validation.Payload; import study.config.validate.ValidMessage; /** * 验证消息是否积极 * @author lzfto * */ @Target({ ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = {ValidMessage.class}) @Documented public @interface ValidIsPositive { String message() default ""; Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default { }; }
待验证对象-SaleInfo
public class SaleInfo { private Integer id; @NotNull(message = "名称不能为空") private String name; @DecimalMax(message = "不能大于10000", value = "10000") private BigDecimal qty; private BigDecimal price; private BigDecimal totalAmount; @ValidIsPositive(message="请拼搏") private String comments; private Date addTime; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public BigDecimal getQty() { return qty; } public void setQty(BigDecimal qty) { this.qty = qty; } public BigDecimal getTotalAmount() { return totalAmount; } public void setTotalAmount(BigDecimal totalAmount) { this.totalAmount = totalAmount; } public Date getAddTime() { return addTime; } public void setAddTime(Date addTime) { this.addTime = addTime; } public BigDecimal getPrice() { return price; } public void setPrice(BigDecimal price) { this.price = price; } public String getComments() { return comments; } public void setComments(String comments) { this.comments = comments; } }
控制器方法
@RequestMapping("/spring/tran/") @Controller public class SpringTranController { @Autowired private SaleMainService saleMainService; @RequestMapping("/addSaleInfo") @ResponseBody public Object addSaleInfo(@RequestBody @Valid SaleInfo saleInfo, Errors errors) { if (errors.getAllErrors().size() > 0) { return ValidUtils.getValidMapInfo(errors); } try { if (saleInfo.getTotalAmount()==null) { saleInfo.setTotalAmount(saleInfo.getQty().multiply(saleInfo.getPrice())); } return saleMainService.sale(saleInfo); } catch (InvalidDataException e) { return PublicReturn.getUnSuccessful(e.getMessage()); } catch (Exception e) { return PublicReturn.getUnSuccessful(e.getMessage()); } } }
js-测试代码
var settings = { "url": "http://localhost:9999/spring/tran/addSaleInfo", "method": "GET", "timeout": 0, "headers": { "Content-Type": "application/json" }, "data": JSON.stringify({ "name": "大米", "qty": 10000.1, "price": 1000, "comments": "混吃等死" }), }; $.ajax(settings).done(function (response) { console.log(response); });
返回的结果:
{
"comments": "请拼搏",
"qty": "不能大于10000"
}