Springboot 使用自定义注解结合AOP方式校验接口参数

简介: Springboot 使用自定义注解结合AOP方式校验接口参数
aspectjrt
1.8.9
com.alibaba
fastjson
1.2.58
org.springframework.boot
spring-boot-starter-web
新建自定义注解,ParamCheck.java :
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
• @Author : JCccc
• @CreateTime : 2020/5/14
• @Description :
**/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface ParamCheck {
/**
• 是否非空,默认不能为空
*/
boolean notNull() default true;
/**
• 默认值
• @return
*/
String defaultValue() default “”;
}

简单描述:

ElementType.PARAMETER 使用于参数
boolean notNull() default true; 要求参数不为空,默认开启,可以自己传
String defaultValue() default “”; 默认值,默认设置 “”,可以自己传
接下来新建 参数校验的AOP实现类,ParamValidAop.java:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
/**
• @Author : JCccc
• @CreateTime : 2020/5/14
• @Description :
**/
@Component
@Aspect
public class ParamValidAop {
/**
• 定义有一个切入点,范围为web包下的类
*/
@Pointcut(“execution(public * com.bsapple.vshop.controller….(…))”)
public void checkParam() {
}
@Before(“checkParam()”)
public void doBefore(JoinPoint joinPoint) {
}
/**
• 检查参数是否为空
*/
@Around(“checkParam()”)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
MethodSignature signature = ((MethodSignature) pjp.getSignature());
//得到拦截的方法
Method method = signature.getMethod();
//获取方法参数注解,返回二维数组是因为某些参数可能存在多个注解
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
if (parameterAnnotations == null || parameterAnnotations.length == 0) {
return pjp.proceed();
}
//获取方法参数名
String[] paramNames = signature.getParameterNames();
//获取参数值
Object[] paranValues = pjp.getArgs();
//获取方法参数类型
Class<?>[] parameterTypes = method.getParameterTypes();
for (int i = 0; i < parameterAnnotations.length; i++) {
for (int j = 0; j < parameterAnnotations[i].length; j++) {
//如果该参数前面的注解不为空并且是ParamCheck的实例,并且notNull()=true,并且默认值为空,则进行非空校验
if (parameterAnnotations[i][j] != null && parameterAnnotations[i][j] instanceof ParamCheck && ((ParamCheck) parameterAnnotations[i][j]).notNull() && StringUtils.isEmpty(((ParamCheck)parameterAnnotations[i][j]).defaultValue())) {
paramIsNull(paramNames[i], paranValues[i], parameterTypes[i] == null ? null : parameterTypes[i].getName());
break;
}
//如果该参数前面的注解不为空并且是ParamCheck的实例,并且默认值不为空,并且参数值为空,则进行赋默认值
if(parameterAnnotations[i][j] != null && parameterAnnotations[i][j] instanceof ParamCheck && !StringUtils.isEmpty(((ParamCheck)parameterAnnotations[i][j]).defaultValue()) && (paranValues[i] == null || StringUtils.isEmpty(paranValues[i].toString()))){
paranValues[i] = putParam(((ParamCheck)parameterAnnotations[i][j]).defaultValue(), parameterTypes[i]);
}
}
}
return pjp.proceed(paranValues);
}
/**
• 在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理)
• @param joinPoint
*/
@AfterReturning(“checkParam()”)
public void doAfterReturning(JoinPoint joinPoint) {
}
/**
• 参数非空校验,如果参数为空,则抛出ParamIsNullException异常
• @param paramName
• @param value
• @param parameterType
*/
private void paramIsNull(String paramName, Object value, String parameterType) {
if (value == null || “”.equals(value.toString().trim())) {
throw new ParamIsNullException(paramName, parameterType,“参数为空”);
}
}
private Object putParam(Object value, Class<?> parameterType) {
return CastValueTypeUtil.parseValue(parameterType, value.toString());
}
}

需要注意,这个路径是你准备添加校验的controller的路径,改成你自己的:

然后是校验参数里面使用到的参数转换工具类,CastValueTypeUtil.java:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
*转换object类型
**/
public class CastValueTypeUtil {
public static Object parseValue(Class<?> parameterTypes, String value) {
if(value==null || value.trim().length()==0){
return null;
}
value = value.trim();
if (Byte.class.equals(parameterTypes) || Byte.TYPE.equals(parameterTypes)) {
return parseByte(value);
} else if (Boolean.class.equals(parameterTypes) || Boolean.TYPE.equals(parameterTypes)) {
return parseBoolean(value);
}/* else if (Character.class.equals(fieldType) || Character.TYPE.equals(fieldType)) {
return value.toCharArray()[0];
}*/ else if (String.class.equals(parameterTypes)) {
return value;
} else if (Short.class.equals(parameterTypes) || Short.TYPE.equals(parameterTypes)) {
return parseShort(value);
} else if (Integer.class.equals(parameterTypes) || Integer.TYPE.equals(parameterTypes)) {
return parseInt(value);
} else if (Long.class.equals(parameterTypes) || Long.TYPE.equals(parameterTypes)) {
return parseLong(value);
} else if (Float.class.equals(parameterTypes) || Float.TYPE.equals(parameterTypes)) {
return parseFloat(value);
} else if (Double.class.equals(parameterTypes) || Double.TYPE.equals(parameterTypes)) {
return parseDouble(value);
} else if (Date.class.equals(parameterTypes)) {
return parseDate(value);
} else {
throw new RuntimeException(“request illeagal type, type must be Integer not int Long not long etc, type=” + parameterTypes);
}
}
public static Byte parseByte(String value) {
try {
value = value.replaceAll(" ", “”);
return Byte.valueOf(value);
} catch(NumberFormatException e) {
throw new RuntimeException(“parseByte but input illegal input=” + value, e);
}
}
public static Boolean parseBoolean(String value) {
value = value.replaceAll(" ", “”);
if (Boolean.TRUE.toString().equalsIgnoreCase(value)) {
return Boolean.TRUE;
} else if (Boolean.FALSE.toString().equalsIgnoreCase(value)) {
return Boolean.FALSE;
} else {
throw new RuntimeException(“parseBoolean but input illegal input=” + value);
}
}
public static Integer parseInt(String value) {
try {
value = value.replaceAll(" ", “”);
return Integer.valueOf(value);
} catch(NumberFormatException e) {
throw new RuntimeException(“parseInt but input illegal input=” + value, e);
}
}
public static Short parseShort(String value) {
try {
value = value.replaceAll(" ", “”);
return Short.valueOf(value);
} catch(NumberFormatException e) {
throw new RuntimeException(“parseShort but input illegal input=” + value, e);
}
}
public static Long parseLong(String value) {
try {
value = value.replaceAll(" ", “”);
return Long.valueOf(value);
} catch(NumberFormatException e) {
throw new RuntimeException(“parseLong but input illegal input=” + value, e);
}
}
public static Float parseFloat(String value) {
try {
value = value.replaceAll(" ", “”);
return Float.valueOf(value);
} catch(NumberFormatException e) {
throw new RuntimeException(“parseFloat but input illegal input=” + value, e);
}
}
public static Double parseDouble(String value) {
try {
value = value.replaceAll(" ", “”);
return Double.valueOf(value);
} catch(NumberFormatException e) {
throw new RuntimeException(“parseDouble but input illegal input=” + value, e);
}
}
public static Date parseDate(String value) {
try {
String datePattern = “yyyy-MM-dd HH:mm:ss”;
SimpleDateFormat dateFormat = new SimpleDateFormat(datePattern);
return dateFormat.parse(value);
} catch(ParseException e) {
throw new RuntimeException(“parseDate but input illegal input=” + value, e);
}
}
}
然后是新建一个自定义异常,专门用于校验参数为空的时候抛出,ParamIsNullException.java:
/**
• @Author : JCccc
• @CreateTime : 2020/5/14
• @Description :
**/
public class ParamIsNullException extends RuntimeException {
private final String parameterName;
private final String parameterType;
private final String message;
public ParamIsNullException(String parameterName, String parameterType, String message) {
super();
this.parameterName = parameterName;
this.parameterType = parameterType;
this.message = message;
}
@Override
public String getMessage() {
return “请求参数类型:” + this.parameterType + “,参数名: '” + this.parameterName + message;
}
public final String getParameterName() {
return this.parameterName;
}
public final String getParameterType() {
return this.parameterType;
}
}

到这里,其实可以看到自定义注解以及AOP已经实现完毕。

接下来是做一下,统一的返回参以及全局异常捕获,

新建接口BaseErrorInfoInterface.java:

/**
• @Author:JCccc
• @Description:此接口用于返回码枚举使用
• @Date: created in 15:11 2019/5/3
*/
public interface BaseErrorInfoInterface {
/** 错误码*/
String getResultCode();
/** 错误描述*/
String getResultMsg();
}
返回码的枚举类,CommonEnum.java:
/**
• @Author:JCccc
• @Description:
• @Date: created in 15:13 2019/5/3
*/
public enum CommonEnum implements BaseErrorInfoInterface {
// 数据操作错误定义
SUCCESS(“200”, “成功!”),
BODY_NOT_MATCH(“400”, “请求的数据格式不符!”),
SIGNATURE_NOT_MATCH(“401”, “请求的数字签名不匹配!”),
NOT_FOUND(“404”, “未找到该资源!”),
INTERNAL_SERVER_ERROR(“500”, “服务器内部错误!”),
SERVER_BUSY(“503”, “服务器正忙,请稍后再试!”),
REQUEST_METHOD_SUPPORT_ERROR(“40001”,“当前请求方法不支持”);
/**
• 错误码
*/
private String resultCode;
/**
• 错误描述
*/
private String resultMsg;
CommonEnum(String resultCode, String resultMsg) {
this.resultCode = resultCode;
this.resultMsg = resultMsg;
}
@Override
public String getResultCode() {
return resultCode;
}
@Override
public String getResultMsg() {
return resultMsg;
}
}
然后是一个简单的返回体专用类,ResultBody.java:
相关文章
|
1天前
|
缓存 NoSQL Java
Springboot自定义注解+aop实现redis自动清除缓存功能
通过上述步骤,我们不仅实现了一个高度灵活的缓存管理机制,还保证了代码的整洁与可维护性。自定义注解与AOP的结合,让缓存清除逻辑与业务逻辑分离,便于未来的扩展和修改。这种设计模式非常适合需要频繁更新缓存的应用场景,大大提高了开发效率和系统的响应速度。
8 2
|
2月前
|
XML Java 数据库
Spring5入门到实战------10、操作术语解释--Aspectj注解开发实例。AOP切面编程的实际应用
这篇文章是Spring5框架的实战教程,详细解释了AOP的关键术语,包括连接点、切入点、通知、切面,并展示了如何使用AspectJ注解来开发AOP实例,包括切入点表达式的编写、增强方法的配置、代理对象的创建和优先级设置,以及如何通过注解方式实现完全的AOP配置。
|
3月前
|
分布式计算 Java MaxCompute
详解 Java 限流接口实现问题之在Spring框架中使用AOP来实现基于注解的限流问题如何解决
详解 Java 限流接口实现问题之在Spring框架中使用AOP来实现基于注解的限流问题如何解决
|
3月前
|
容器
springboot-自定义注解拦截ip aop和ioc
springboot-自定义注解拦截ip aop和ioc
|
JSON 前端开发 Java
SpringBoot自定义异常,优雅解决业务逻辑中的错误
SpringBoot自定义异常,优雅解决业务逻辑中的错误
6066 0
SpringBoot自定义异常,优雅解决业务逻辑中的错误
|
11天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的服装商城管理系统
基于Java+Springboot+Vue开发的服装商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的服装商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
33 2
基于Java+Springboot+Vue开发的服装商城管理系统
|
11天前
|
前端开发 JavaScript Java
SpringBoot项目部署打包好的React、Vue项目刷新报错404
本文讨论了在SpringBoot项目中部署React或Vue打包好的前端项目时,刷新页面导致404错误的问题,并提供了两种解决方案:一是在SpringBoot启动类中配置错误页面重定向到index.html,二是将前端路由改为hash模式以避免刷新问题。
53 1
|
8天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的大学竞赛报名管理系统
基于Java+Springboot+Vue开发的大学竞赛报名管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的大学竞赛报名管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
23 3
基于Java+Springboot+Vue开发的大学竞赛报名管理系统
|
9天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的蛋糕商城管理系统
基于Java+Springboot+Vue开发的蛋糕商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的蛋糕商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
21 3
基于Java+Springboot+Vue开发的蛋糕商城管理系统
|
9天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的美容预约管理系统
基于Java+Springboot+Vue开发的美容预约管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的美容预约管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
21 3
基于Java+Springboot+Vue开发的美容预约管理系统
下一篇
无影云桌面