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

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 Boot 中使用 @Autowired和 @Bean注解的示例详解

《在SpringBoot中使用@Autowired和@Bean注解的示例详解》本文通过一个示例演示了如何在SpringBoot中使用@Autowired和@Bean注解进行依赖注入和Bean... 目录在 Spring Boot 中使用 @Autowired 和 @Bean 注解示例背景1. 定义 Stud

Spring排序机制之接口与注解的使用方法

《Spring排序机制之接口与注解的使用方法》本文介绍了Spring中多种排序机制,包括Ordered接口、PriorityOrdered接口、@Order注解和@Priority注解,提供了详细示例... 目录一、Spring 排序的需求场景二、Spring 中的排序机制1、Ordered 接口2、Pri

Idea实现接口的方法上无法添加@Override注解的解决方案

《Idea实现接口的方法上无法添加@Override注解的解决方案》文章介绍了在IDEA中实现接口方法时无法添加@Override注解的问题及其解决方法,主要步骤包括更改项目结构中的Languagel... 目录Idea实现接China编程口的方法上无法添加@javascriptOverride注解错误原因解决方

Java通过反射获取方法参数名的方式小结

《Java通过反射获取方法参数名的方式小结》这篇文章主要为大家详细介绍了Java如何通过反射获取方法参数名的方式,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、前言2、解决方式方式2.1: 添加编译参数配置 -parameters方式2.2: 使用Spring的内部工具类 -

Java中基于注解的代码生成工具MapStruct映射使用详解

《Java中基于注解的代码生成工具MapStruct映射使用详解》MapStruct作为一个基于注解的代码生成工具,为我们提供了一种更加优雅、高效的解决方案,本文主要为大家介绍了它的具体使用,感兴趣... 目录介绍优缺点优点缺点核心注解及详细使用语法说明@Mapper@Mapping@Mappings@Co

Java中注解与元数据示例详解

《Java中注解与元数据示例详解》Java注解和元数据是编程中重要的概念,用于描述程序元素的属性和用途,:本文主要介绍Java中注解与元数据的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参... 目录一、引言二、元数据的概念2.1 定义2.2 作用三、Java 注解的基础3.1 注解的定义3.2 内

Python调用另一个py文件并传递参数常见的方法及其应用场景

《Python调用另一个py文件并传递参数常见的方法及其应用场景》:本文主要介绍在Python中调用另一个py文件并传递参数的几种常见方法,包括使用import语句、exec函数、subproce... 目录前言1. 使用import语句1.1 基本用法1.2 导入特定函数1.3 处理文件路径2. 使用ex

MySQL中时区参数time_zone解读

《MySQL中时区参数time_zone解读》MySQL时区参数time_zone用于控制系统函数和字段的DEFAULTCURRENT_TIMESTAMP属性,修改时区可能会影响timestamp类型... 目录前言1.时区参数影响2.如何设置3.字段类型选择总结前言mysql 时区参数 time_zon

Spring常见错误之Web嵌套对象校验失效解决办法

《Spring常见错误之Web嵌套对象校验失效解决办法》:本文主要介绍Spring常见错误之Web嵌套对象校验失效解决的相关资料,通过在Phone对象上添加@Valid注解,问题得以解决,需要的朋... 目录问题复现案例解析问题修正总结  问题复现当开发一个学籍管理系统时,我们会提供了一个 API 接口去

Python如何使用seleniumwire接管Chrome查看控制台中参数

《Python如何使用seleniumwire接管Chrome查看控制台中参数》文章介绍了如何使用Python的seleniumwire库来接管Chrome浏览器,并通过控制台查看接口参数,本文给大家... 1、cmd打开控制台,启动谷歌并制定端口号,找不到文件的加环境变量chrome.exe --rem