注解+反射 参数校验更加简洁

2024-06-24 01:08

本文主要是介绍注解+反射 参数校验更加简洁,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

背景

做RPC接口的时候 我们需要对一些字段做非空校验 在字段很多的情况下 如果一个一个的用if判断 代码会很恶心 所以我们需要有一种便捷的方式去实现这个功能 比如使用注解+反射的方式

怎么做?

首先定义注解
非空注解:

package com.api.annotation;import java.lang.annotation.*;/*** 非空校验注解*/@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NotNull {String message() default "";
}

数值注解:

package com.api.annotation;import java.lang.annotation.*;/*** 数字类型校验注解*/@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Number {String message() default "";
}

日期注解:

package com.api.annotation;import java.lang.annotation.*;/*** 日期格式校验注解*/@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Date {String message() default "";String format() default "yyyy-MM-dd HH:mm:ss";
}

接下来定义一下校验的返回值

public class BaseResultInfo {/*** 响应码*/protected int code = 200;/*** 响应消息*/protected String msg = "OK";public int getCode() {return code;}public void setCode(int code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}

再定义一个返回码的枚举:

public enum ResultCodeEnum {SUCCESS(200,"成功"),PARAM_ERROR(1,"参数异常!!"),SYSTEM_ERROR(2,"系统异常!");ResultCodeEnum(int code, String msg) {this.code = code;this.msg = msg;}/*** 返回code*/private int code;/*** 错误消息*/private String msg;public int getCode() {return code;}public void setCode(int code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}
}

接下来定义一个基类 包含一个校验方法 通过反射来对字段进行校验

@Service
public class BaseService {/*** 验证某个bean的参数** @param object 被校验的参数*//*** 验证某个bean的参数* @param object        校验bean对象* @param resultInfo    校验结果* @param <T>* @return* @throws Exception*/public <T> BaseResultInfo validate(T object, BaseResultInfo resultInfo) throws Exception {if(object == null){resultInfo.setCode(ResultCodeEnum.PARAM_ERROR.getCode());resultInfo.setMsg("入参对象不能为null");return resultInfo;}//获取object的类型Class<? extends Object> clazz = object.getClass();//获取该类型声明的成员Field[] fields = clazz.getDeclaredFields();//遍历属性for (Field field : fields) {//对于private私有化的成员变量,通过setAccessible来修改器访问权限field.setAccessible(true);if(!validate(field, object, resultInfo)){return resultInfo;};//重新设置会私有权限field.setAccessible(false);}return resultInfo;}/*** 校验bean对象注解* @param field* @param object* @param resultInfo* @throws Exception*/private <T> boolean validate(Field field, T object, BaseResultInfo resultInfo) throws Exception {if(field.isAnnotationPresent(NotNull.class)){NotNull annotation = field.getAnnotation(NotNull.class);if(field.get(object) == null || StringUtils.isBlank(field.get(object).toString())){resultInfo.setCode(ResultCodeEnum.PARAM_ERROR.getCode());resultInfo.setMsg(StringUtils.isEmpty(annotation.message()) ? field.getName()+"不可为空" : annotation.message() );return false;}}if(field.isAnnotationPresent(Date.class)){Date annotation = field.getAnnotation(Date.class);SimpleDateFormat format = new SimpleDateFormat(annotation.format());try {if(field.get(object) != null){format.parse(field.get(object).toString());}} catch (ParseException e) {resultInfo.setCode(ResultCodeEnum.PARAM_ERROR.getCode());resultInfo.setMsg(annotation.message());return false;}}if(field.isAnnotationPresent(Number.class)){Number annotation = field.getAnnotation(Number.class);if(field.get(object) != null){try{new BigDecimal(field.get(object).toString());}catch (Exception e){resultInfo.setCode(ResultCodeEnum.PARAM_ERROR.getCode());resultInfo.setMsg(StringUtils.isEmpty(annotation.message()) ? field.getName()+"必须是数值" : annotation.message() );return false;}}}return true;}}

准备工作做好了 接下来看下怎么用
随便定义一个方法的入参,对于thrift等接口,数值类型如果使用double会丢失精度,而且也不支持date类型,所以我们一般都是使用String类型(这里仅仅是参考 没有加thrift的相关注解)

import com.api.annotation.Date;
import com.api.annotation.NotNull;
import com.api.annotation.Number;public class ApplyRequest {@NotNullprivate String applyNum;@NotNull(message = "描述不可以为空")private String description;@Numberprivate String amount;@Date(format = "yyyy-MM")private String periodDate;@Dateprivate String creationDate;public String getApplyNum() {return applyNum;}public void setApplyNum(String applyNum) {this.applyNum = applyNum;}public String getAmount() {return amount;}public void setAmount(String amount) {this.amount = amount;}public String getPeriodDate() {return periodDate;}public void setPeriodDate(String periodDate) {this.periodDate = periodDate;}public String getCreationDate() {return creationDate;}public void setCreationDate(String creationDate) {this.creationDate = creationDate;}
}

然后我们只需要让接口的实现类继承BaseService类,然后在方法内部调用父类的validate方法即可进行参数的一些基础校验

这篇关于注解+反射 参数校验更加简洁的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/1088765

相关文章

Spring Security方法级安全控制@PreAuthorize注解的灵活运用小结

《SpringSecurity方法级安全控制@PreAuthorize注解的灵活运用小结》本文将带着大家讲解@PreAuthorize注解的核心原理、SpEL表达式机制,并通过的示例代码演示如... 目录1. 前言2. @PreAuthorize 注解简介3. @PreAuthorize 核心原理解析拦截与

SpringCloud动态配置注解@RefreshScope与@Component的深度解析

《SpringCloud动态配置注解@RefreshScope与@Component的深度解析》在现代微服务架构中,动态配置管理是一个关键需求,本文将为大家介绍SpringCloud中相关的注解@Re... 目录引言1. @RefreshScope 的作用与原理1.1 什么是 @RefreshScope1.

Java进行文件格式校验的方案详解

《Java进行文件格式校验的方案详解》这篇文章主要为大家详细介绍了Java中进行文件格式校验的相关方案,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、背景异常现象原因排查用户的无心之过二、解决方案Magandroidic Number判断主流检测库对比Tika的使用区分zip

java中反射(Reflection)机制举例详解

《java中反射(Reflection)机制举例详解》Java中的反射机制是指Java程序在运行期间可以获取到一个对象的全部信息,:本文主要介绍java中反射(Reflection)机制的相关资料... 目录一、什么是反射?二、反射的用途三、获取Class对象四、Class类型的对象使用场景1五、Class

Spring事务中@Transactional注解不生效的原因分析与解决

《Spring事务中@Transactional注解不生效的原因分析与解决》在Spring框架中,@Transactional注解是管理数据库事务的核心方式,本文将深入分析事务自调用的底层原理,解释为... 目录1. 引言2. 事务自调用问题重现2.1 示例代码2.2 问题现象3. 为什么事务自调用会失效3

Java常用注解扩展对比举例详解

《Java常用注解扩展对比举例详解》:本文主要介绍Java常用注解扩展对比的相关资料,提供了丰富的代码示例,并总结了最佳实践建议,帮助开发者更好地理解和应用这些注解,需要的朋友可以参考下... 目录一、@Controller 与 @RestController 对比二、使用 @Data 与 不使用 @Dat

一文带你了解SpringBoot中启动参数的各种用法

《一文带你了解SpringBoot中启动参数的各种用法》在使用SpringBoot开发应用时,我们通常需要根据不同的环境或特定需求调整启动参数,那么,SpringBoot提供了哪些方式来配置这些启动参... 目录一、启动参数的常见传递方式二、通过命令行参数传递启动参数三、使用 application.pro

基于@RequestParam注解之Spring MVC参数绑定的利器

《基于@RequestParam注解之SpringMVC参数绑定的利器》:本文主要介绍基于@RequestParam注解之SpringMVC参数绑定的利器,具有很好的参考价值,希望对大家有所帮助... 目录@RequestParam注解:Spring MVC参数绑定的利器什么是@RequestParam?@

Spring 中使用反射创建 Bean 实例的几种方式

《Spring中使用反射创建Bean实例的几种方式》文章介绍了在Spring框架中如何使用反射来创建Bean实例,包括使用Class.newInstance()、Constructor.newI... 目录1. 使用 Class.newInstance() (仅限无参构造函数):2. 使用 Construc

SpringBoot接收JSON类型的参数方式

《SpringBoot接收JSON类型的参数方式》:本文主要介绍SpringBoot接收JSON类型的参数方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、jsON二、代码准备三、Apifox操作总结一、JSON在学习前端技术时,我们有讲到过JSON,而在