Spring boot通过切面,实现超灵活的注解式数据校验过程
作者:Balalalalalalalala 发布时间:2022-11-29 07:40:08
目录
通过切面,实现超灵活的注解式数据校验
Spring MVC的校验方式
通过切面实现自己的注解式数据校验
Spring boot aop注解数据权限校验
注解类
AOP切面
使用
通过切面,实现超灵活的注解式数据校验
在企业系统的开发中,用户表单输入的场景是会经常遇见的,如何让数据校验脱离于业务代码逻辑,谁也不想在逻辑代码里对字段逐一判断。。。。
Spring MVC的校验方式
在使用Spring MVC时的时候,直接使用hibernate-validator的注解,如下:
public class User {
private Long id;
@NotBlank(message = "name不能为空")
@Size(min = 5, max = 10, message = "字符在5到10个")
private String name;
private String des;
@NotNull
@Max(value = 3, message = "type 参数错误")
@Min(value = 0, message = "type 参数错误")
private Integer type;
@Min(value = 0, message = "参数错误, limit必须大于或等于0")
private int limit;
@Pattern(regexp = "^(true|false)$", message = "参数错误, 参数isActive只能是true或者false")
private String flag;
// setters and getters
然后将User对象作为Controller的参数,交给Spring MVC去帮你校验。
通过切面实现自己的注解式数据校验
这是一个SOA的微服务应用,没有controller和Spring MVC,当然也没有所谓的容器(Tomcat、Jetty),对于来自于client的调用,也要进行参数校验。继续基于hibernate-validator,
参看validator的官方文档
引入依赖:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator-cdi</artifactId>
<version>5.4.1.Final</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.1-b08</version>
</dependency>
这里需要引入spring boot和aop的一些知识点,自行去网上google吧。我直接上代码了,谁叫我是代码的搬运工。
定义一个切面:
@Aspect //一个切面
@Configuration // spring boot 配置类
public class RequestParamValidAspect {
private final ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
private final ExecutableValidator methodValidator = factory.getValidator().forExecutables();
private final Validator beanValidator = factory.getValidator();
private <T> Set<ConstraintViolation<T>> validMethodParams(T obj, Method method, Object [] params){
return methodValidator.validateParameters(obj, method, params);
}
private <T> Set<ConstraintViolation<T>> validBeanParams(T bean) {
return beanValidator.validate(bean);
}
@Pointcut("execution(* com.jiaobuchong.commodity.service.*.*(..))")
public void soaServiceBefore(){}
/* * 通过连接点切入 */
@Before("soaServiceBefore()")
public void twiceAsOld1(JoinPoint point) {
// 获得切入目标对象
Object target = point.getThis();
// 获得切入方法参数
Object [] args = point.getArgs();
// 获得切入的方法
Method method = ((MethodSignature)point.getSignature()).getMethod();
// 校验以基本数据类型 为方法参数的
Set<ConstraintViolation<Object>> validResult = validMethodParams(target, method, args);
Iterator<ConstraintViolation<Object>> violationIterator = validResult.iterator();
while (violationIterator.hasNext()) {
// 此处可以抛个异常提示用户参数输入格式不正确
System.out.println("method check---------" + violationIterator.next().getMessage());
}
// 校验以java bean对象 为方法参数的
for (Object bean : args) {
if (null != bean) {
validResult = validBeanParams(bean);
violationIterator = validResult.iterator();
while (violationIterator.hasNext()) {
// 此处可以抛个异常提示用户参数输入格式不正确
System.out.println("bean check-------" + violationIterator.next().getMessage());
}
}
}
}
}
具体的Service
// DemoService.java
public interface DemoService {
void one(@NotNull(message = "不能为null") Integer a, @NotBlank String b);
void two(@NotNull(message = "paramsVo不能为null") ParamsVo paramsVo,
@NotNull(message = "go不能为null") String go);
}
// ParamsVo.java
public class ParamsVo {
@NotBlank(message = "不能为空")
private String name;
@NotBlank
@Length(min = 2, max = 20, message = "不可以为空,最多20个字")
private String desc;
@NotNull
@Valid // 需要加上@Valid注解,不然不会校验到Img对象
private List<Img> imgList;
@NotNull(message = "length不能为null")
@Range(min = 3, max = 100, message = "长度范围3-100")
private Integer length;
// omitted other code
}
public class Img {
@NotNull(message = "img id 不能为null")
private Long id;
@NotBlank(message = "img name 不能为空")
private String name;
// omitted other code
}
运行DemoService:
@Autowired
private DemoService demoService;
@Test
public void testGo() {
demoService.one(null, "");
ParamsVo paramsVo = new ParamsVo();
List<Img> list = new ArrayList<>();
Img img = new Img();
list.add(img);
paramsVo.setImgList(list);
paramsVo.setDesc("你");
paramsVo.setLength(1);
demoService.two(paramsVo, null);
}
运行结果:
method check———不能为空
method check———不能为null
method check———go不能为null
bean check——-img name 不能为空
bean check——-不能为空
bean check——-深度范围3-100
bean check——-img id 不能为null
bean check——-不可以为空,最多20个字
这样比Spring MVC的校验功能还强大了,
// Spring MVC中对下面这样的校验是没有作用的
void one(@NotNull(message = "不能为null") Integer a, @NotBlank String b);
经过一番改造后,啥都支持了。而且独立于业务逻辑,维护和新增校验都很方便,代码量也变少了!
Spring boot aop注解数据权限校验
注解类
@Retention(RetentionPolicy.RUNTIME)
public @interface DataAuthValid
{
//位置
public int index() default 0;
//字段 id
//public String id() default "id";
//字段 id
public String orgId() default "org_id";
//mapper
@SuppressWarnings("rawtypes")
public Class<? extends Mapper> mapper();
}
AOP切面
@Aspect
@Component
@Order(1)
public class DataAuthAop {
private static String types = "java.lang.String,java.lang.Long,long";
@Before("@annotation(dataAuth)")
public void beforeMethod(JoinPoint point,DataAuthValid dataAuth) throws Exception {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
Map<String, Object> payloadMap = (Map<String, Object>) request.getAttribute("payloadMap");
Long companyid = Long.parseLong(payloadMap.get("companyid")+"");
if(companyid != 1) {
Object[] args = point.getArgs();
Object obj = args[dataAuth.index()];
String ids = null;
String typeName = obj.getClass().getTypeName();
if(types.contains(typeName)) {
ids = obj + "";
}else {
Field[] fields = obj.getClass().getDeclaredFields();
for (Field f : fields) {
f.setAccessible(true);
if("id".equals(f.getName())) {
Long id = (Long) f.get(obj);
ids = id + "";
}
}
}
String[] idArr = ids.split(",");
for (String id : idArr) {
Class cla = dataAuth.mapper();
Mapper mapper = (Mapper) SpringBeanFactoryUtils.getApplicationContext().getBean(cla);
Object object = mapper.selectByPrimaryKey(Long.valueOf(id));
Field field = obj.getClass().getDeclaredField(dataAuth.orgId());
field.setAccessible(true);
Long orgId = (Long)field.get(obj);
if(!companyid.equals(orgId)) {
throw new RuntimeException();
}
}
}
}
}
使用
来源:https://blog.csdn.net/jiaobuchong/article/details/74094155


猜你喜欢
- 递归三要素:1、明确递归终止条件;2、给出递归终止时的处理办法;3、提取重复的逻辑,缩小问题规模。1、1+2+3+…+nimport jav
- 单例模式算是设计模式中最容易理解,也是最容易手写代码的模式,但是其中涉及的知识点却一点也不少,所以经常作为面试题来考。一般单例都是五种写法:
- 本文讲述了在Java中如何创建和结束线程的最基本方法,只针对于Java初学者。一些高级知识如线程同步、调度、线程池等内容将会在后续章节中逐步
- Java ThreadPoolExecutor的参数深入理解一、使用Executors创建线程池 &nb
- 最近项目上用就hibernate+spring data jpa,一开始感觉还不错,但是随着对业务的复杂,要求处理一些复杂的sql,就顺便研
- 因为线程重用导致的信息错乱的bugThreadLocal一般用于线程间的数据隔离,通过将数据缓存在ThreadLocal中,可以极大的提升性
- 方法一第一步:添加引用using System.Printing;第二步:代码public static List<string>
- 引言上一个专题已经和大家分享了我理解的——C#中为什么需要委托,专题中简单介绍了下委托是什么以及委托简单的应用的,在这个专题中将对委托做进一
- 第一步:官网(或跟硬件开发WMI的人沟通你需要的接口和参数定义,如果是和硬件开发的人协定WMI接口,直接看第二步)查找你需要的WMI信息;举
- 前言在实际开发中,大多数情况下都需要对 SQL 传入参数以获得想要的结果集,传入的情况分为两种情况:1、SQL语句的拼接,比如表名、like
- 本文实例展示了DevExpress获取TreeList可视区域节点集合的实现方法,是比较有实用价值的技巧。分享给大家供大家参考。具体实现方法
- 一、JDBC概述1、数据的持久化持久化(persistence):把数据保存到可掉电式存储设备中以供之后使用。大多数情况下,特别是企业级应用
- mybatis多个区间处理如图:要实现车辆数不同区间查询条件思路a.前端传数组,数组里面放"1-5"String类型值
- 本文实例为大家分享了OpenGL绘制三次Bezier曲线的具体代码,供大家参考,具体内容如下计算公式:运行结果:代码如下:#include&
- 一、背景项目中肯定会遇到异步调用其他方法的场景,比如有个计算过程,需要计算很多个指标的值,但是每个指标计算的效率快慢不同,如果采用同步执行的
- 这个功能,大家也都可以去百度以下,千篇一律都自己写的(抄的)封装好的公共类,此处还是得膜拜下原创的大佬,可以花时间去搞这个,我看着都头皮发麻
- 今天讲解一下Fragment的控制,主要是切换View和页面替换等操作。还有就是如何获取Fragment的管理对象,以及与Activity的
- 本文较为详细的分析了Java反射机制。分享给大家供大家参考,具体如下:一、预先需要掌握的知识(java虚拟机) java虚拟机的方法区:ja
- 1. 概述官方JavaDocsApi:javax.swing.JCheckBoxJCheckBox,复选框。JCheckBox 常用构造方法
- ReferenceWhy using finalizers is a bad idea当在一个类中使用了另外一个实现了IDisposable