基于反射+注解+springAop +统一处理异常打造属于自己的校验工具告别if判断让代码更简明

xiaoxiao2021-02-28  31

回想以前的写的代码,对于数据的校验当时写好多if 那时看着自己都觉得那个代码简直就是垃圾呀,后来发现其实spring也有一个数据校验Validator 但是这个工具只能作用于一个bean 上 但是有时我们代码根本不用一个bean去接收数据 ,所以它不能满足我的需求,后来自己有一个想法,就想着,填补 Validator 这个功能没有的功能进行填坑,后来根据自己的经验和查资料 原来是可以的 废话不多说 直接上代码  定义多一个注解如下   package com.irongyan.client.tools.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** *@Author: yw *@Desciption: 检验是否为邮箱 *@Date:10:18 2018/5/4 *@param:No such property: code for class: Script1 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD,ElementType.PARAMETER,ElementType.METHOD}) public @interface IsEmail { boolean isNull() default true;//是否允许为空 true 允许 |false 不允许 isnull 为false 或者 true 必须该属性必须有值 时候才可以才可以用 String value () default "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$";///邮箱正则 String keyName()default "";//对应字段名字 } /** *@Author: yw *@Desciption: 校验参数是否是数字 *@Date:9:57 2018/5/4 *@param:No such property: code for class: Script1 */ @Target({ElementType.FIELD,ElementType.PARAMETER,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface IsNumber { String keyName()default "";//对应字段名字 boolean isNull () default true;// 是否允许为空 true 允许 |false 不允许 ///以下的注解元素必须在 isnull 为false 或者 true 必须该属性必须有值 时候才可以才可以用 int min () default 0;//默认是0 int max () default Integer.MAX_VALUE; ///最大值 } /** *@Author: yw *@Desciption: 检查手机号 *@Date:10:15 2018/5/4 *@param:No such property: code for class: Script1 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD,ElementType.PARAMETER,ElementType.METHOD}) public @interface IsPhone { String keyName()default "";//对应字段名字 boolean isNull() default true;//是否允许为空 true 允许 |false 不允许 isnull 为false 或者 true 必须该属性必须有值 时候才可以才可以用 String value () default "^1(3|4|5|7|8)\\d{9}$"; } /** *@Author: yw *@Desciption: 用于在自定义正则表达式 *@Date:10:22 2018/5/4 *@param:No such property: code for class: Script1 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD,ElementType.PARAMETER,ElementType.METHOD}) public @interface IsRegexp { String keyName()default "";//对应字段名字 boolean isNull() default true;//是否允许为空 true 允许 |false 不允许 isnull 为false 或者 true 必须该属性必须有值 时候才可以才可以用 String value()default "";///正则表达 String msg() default "请按照规则填数据";//描述说明 } /** *@Author: yw *@Desciption: 做用于方法上 自定义的对象 表示该对象要开启aop 校验 *@Date:15:28 2018/5/7 *@param:No such property: code for class: Script1 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD,ElementType.PARAMETER,ElementType.METHOD}) public @interface IsValidator { } /** *@Author: yw *@Desciption: 被注解的字段 长度范围 *@Date:10:27 2018/5/4 *@param:No such property: code for class: Script1 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER}) public @interface Length { String keyName()default "";//对应字段名字 boolean isNull () default true;// 是否允许为空 true 允许 |false 不允许 ///以下的注解元素必须在 isnull 为false 或者 true 必须该属性必须有值 时候才可以才可以用 int min () default 0;//长度默认是0 int max () default Integer.MAX_VALUE;//默认是 } @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER}) public @interface NotEmpty { String value() default "";//默认是没有值 如有值 就说明该字段必须为该值!!!!! String keyName()default "";//对应字段名字 } /** *@Author: yw *@Desciption:用于springmvc 的方法上 表示该方法启动校验数据 *@Date:10:50 2018/5/4 */ @Target({ElementType.PARAMETER,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface VerifyObjPar { } 以上定义所有的注解 。

 对注解的解析和判断 代码运用的反射  代码如下:

package com.irongyan.client.tools; import com.irongyan.client.tools.annotation.*; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @Author: yw * @Desciption: 对注解进行解析和判断 * @Date:10:30 2018/5/4 * @param:No such property: code for class: Script1 */ public class AnnotationHelpUtils { /** * @Author: yw * @Desciption: 校验是否含有该注解 * @Date:10:33 2018/5/4 * @param:No such property: code for class: Script1 */ public static boolean isVerify(Method method) { VerifyObjPar annotation = method.getAnnotation(VerifyObjPar.class); if (annotation != null) { return true; } return false; } /** * @Author: yw * @Desciption: 校验自定义的对象 * @Date:15:53 2018/5/7 * @param:No such property: code for class: Script1 */ public static String isObjAnntation(Parameter parameter, Object object) throws Exception { StringBuilder sb = new StringBuilder();//线程不安全 但是快效率高 Field[] declaredFields =parameter.getType().getDeclaredFields(); String msg=null; for (Field field : declaredFields) { field.setAccessible(true);///开启强制反射 System.out.println("getName:" + field.getName()); msg=anntationTools(field,field.get(object)); sb.append(msg).append(","); } if (sb.length() > 0) { sb.deleteCharAt(sb.length() - 1); } return sb.toString(); } private static String anntationTools(Object parameter, Object object) { StringBuilder sb = new StringBuilder();//线程不安全 但是快效率高 String isEmail,isNumber,isPhone,isRegexp ,length,notEmpty; if(parameter.getClass().equals(Field.class)){ isEmail = isEmail((Field)parameter, object); isNumber = isNumber((Field)parameter, object); isPhone = isPhone((Field)parameter, object); isRegexp = isRegexp((Field)parameter, object); length = length((Field)parameter, object); notEmpty = notEmpty((Field)parameter, object); }else{ isEmail = isEmail((Parameter)parameter, object); isNumber = isNumber((Parameter)parameter, object); isPhone = isPhone((Parameter)parameter, object); isRegexp = isRegexp((Parameter)parameter, object); length = length((Parameter)parameter, object); notEmpty = notEmpty((Parameter)parameter, object); } sb.append(isEmail == null ? "" : isEmail + ","); sb.append(isNumber == null ? "" : isNumber + ","); sb.append(isPhone == null ? "" : isPhone + ","); sb.append(isRegexp == null ? "" : isRegexp + ","); sb.append(length == null ? "" : length + ","); sb.append(notEmpty == null ? "" : notEmpty + ","); if (sb.length() > 0) { sb.deleteCharAt(sb.length() - 1); } return sb.toString().trim(); } /** * @Author: yw * @Desciption: 校验单个属性 * @Date:15:51 2018/5/7 * @param:No such property: code for class: Script1 */ public static String isAnntation(Parameter parameter, Object object) { return anntationTools( parameter, object).trim(); } /** * @return 符合规则则是返回null 否则就是有不符合规则的说明 * @Author: yw * @Desciption: 校验邮箱 * @Date:11:47 2018/5/4 */ public static String isEmail(Parameter parameter, Object object) { IsEmail annotation = parameter.getAnnotation(IsEmail.class); return email(annotation, object); } private static String isEmail(Field field, Object object) { IsEmail annotation = field.getAnnotation(IsEmail.class); return email(annotation, object); } private static String email(IsEmail annotation, Object object) { //有注解 允许为空 if (annotation != null && annotation.isNull() && (object == null || object.toString().length() == 0)) { return null; } //有注解 不许为空 if (annotation != null && !annotation.isNull() && (object == null || object.toString().length() == 0)) { return annotation.keyName() + "," + "该邮箱不可为空"; } //有注解 而还有值 if (annotation != null && object != null && object.toString().length() > 0 && !annotation.value().equals("")) { Pattern compile = Pattern.compile(annotation.value()); Matcher matcher = compile.matcher(object.toString()); return matcher.matches() ? null : annotation.keyName() + "," + "请输入正确邮箱电址"; } return null; } /** * @return 符合规则则是返回null 否则就是有不符合规则的说明 * @Author: yw * @Desciption: 校验数字 * @Date:11:28 2018/5/4 */ public static String isNumber(Parameter parameter, Object object) { IsNumber annotation = parameter.getAnnotation(IsNumber.class); return number(annotation,object); } private static String isNumber(Field parameter, Object object) { IsNumber annotation = parameter.getAnnotation(IsNumber.class); return number(annotation,object); } private static String number(IsNumber annotation, Object object) { //有注解 允许为空 if (annotation != null && annotation.isNull() && (object == null || object.toString().length() == 0)) { return null; } //有注解 不许为空 if (annotation != null && !annotation.isNull() && (object == null || object.toString().length() == 0)) { return annotation.keyName() + "," + "该字段不可为空"; } //有注解 而还有值 if (annotation != null && object != null && object.toString().length() > 0) { Pattern compile = Pattern.compile("^[0-9]+$"); Matcher matcher = compile.matcher(object.toString()); if (!matcher.matches()) { return annotation.keyName() + "," + "请输入正确数字"; } Double d = Double.valueOf(object.toString()); if (annotation.min() <= d && annotation.max() >= d) { return null; } return annotation.keyName() + "," + "该字段有效值范围是 最小值=" + annotation.min() + " 最大值 = " + annotation.max(); } return null; } /** * @return 符合规则则是返回null 否则就是有不符合规则的说明 * @Author: yw * @Desciption: 检验是否含有该注解 校验手机号码 * @Date:11:23 2018/5/4 */ public static String isPhone(Parameter parameter, Object object) { IsPhone annotation = parameter.getAnnotation(IsPhone.class); return phone(annotation,object); } private static String isPhone(Field parameter, Object object) { IsPhone annotation = parameter.getAnnotation(IsPhone.class); return phone(annotation,object); } private static String phone(IsPhone annotation,Object object){ //有注解 允许为空 if (annotation != null && annotation.isNull() && (object == null || object.toString().length() == 0)) { return null; } //有注解 不许为空 if (annotation != null && !annotation.isNull() && (object == null || object.toString().length() == 0)) { return annotation.keyName() + ":" + "该字段不可为空"; } //有注解 而还有值 if (annotation != null && !annotation.value().equals("")) { Pattern compile = Pattern.compile(annotation.value()); Matcher matcher = compile.matcher(object.toString()); return matcher.matches() ? null : annotation.keyName() + "," + "请输入正确手机号码"; } return null; } /** * @return 符合规则则是返回null 否则就是有不符合规则的说明 * @Author: yw * @Desciption: 检验是否匹配队对应的注解 * @Date:11:12 2018/5/4 */ public static String isRegexp(Parameter parameter, Object object) { IsRegexp annotation = parameter.getAnnotation(IsRegexp.class); return regexp(annotation,object); } private static String isRegexp(Field parameter, Object object) { IsRegexp annotation = parameter.getAnnotation(IsRegexp.class); return regexp(annotation,object); } private static String regexp(IsRegexp annotation,Object object){ //有注解 允许为空 if (annotation != null && annotation.isNull() && (object == null || object.toString().length() == 0)) { return null; } //有注解 不许为空 if (annotation != null && !annotation.isNull() && (object == null || object.toString().length() == 0)) { return annotation.keyName() + "," + "该字段不可为空"; } //有注解 而还有值 if (annotation != null && object != null && !annotation.value().equals("")) { Pattern compile = Pattern.compile(annotation.value()); Matcher matcher = compile.matcher(object.toString()); return matcher.matches() ? null : annotation.keyName() + ":" + annotation.msg(); } return null; } /** * @return 符合规则则是返回null 否则就是有不符合规则的说明 * @Author: yw * @Desciption: 校验参数的长度 * @Date:10:52 2018/5/4 */ public static String length(Parameter parameter, Object object) { Length annotation = parameter.getAnnotation(Length.class); if (annotation == null) { return null; } return length(annotation,object); } private static String length(Field parameter, Object object) { Length annotation = parameter.getAnnotation(Length.class); if (annotation == null) { return null; } return length(annotation,object); } private static String length(Length annotation,Object object){ //有注解 但是允许为空 if (annotation != null && annotation.isNull() && (object == null || object.toString().equals(""))) { return null; } ///有注解 不允许为空 if (annotation != null && !annotation.isNull() && object == null) { return annotation.keyName() + "," + "该字段长度范围必须是" + annotation.min() + "到" + annotation.max(); } //有注解 而且该字段有值 if (annotation != null && object != null) { if (annotation.min() <= object.toString().length() && annotation.max() >= object.toString().length()) { return null; } return annotation.keyName() + "," + "该字段长度范围必须是" + annotation.min() + "到" + annotation.max(); } return null; } /** * @return 符合规则则是返回null 否则就是有不符合规则的说明 * @Author: yw * @Desciption: 校验是否为空 * @Date:10:45 2018/5/4 */ public static String notEmpty(Parameter parameter, Object object) { NotEmpty annotation = parameter.getAnnotation(NotEmpty.class); if (annotation == null) { return null; } return notEmpty(annotation,object); } private static String notEmpty(Field parameter, Object object) { NotEmpty annotation = parameter.getAnnotation(NotEmpty.class); if (annotation == null) { return null; } return notEmpty(annotation,object); } private static String notEmpty( NotEmpty annotation,Object object ){ if (annotation != null && object != null && object.toString().length() > 0) { if (annotation.value() != null && !annotation.value().equals("") && !annotation.value().equals(object.toString())) { return annotation.keyName() + "," + "该参数必须等于" + annotation.value(); } return null; } return annotation.keyName() + "," + "该字段不可以为空"; } }

 然后就是配置aop 和切入点 在springmvc 中配置 这样的代码 

<aop:aspectj-autoproxy proxy-target-class="true"/> <bean class="com.irongyan.client.aop.ParAopVerify"/>切入点:

package com.irongyan.client.aop; import com.irongyan.client.dto.ResultMsg; import com.irongyan.client.exception.VerifyException; import com.irongyan.client.tools.AnnotationHelpUtils; import com.irongyan.client.tools.ResultUtil; import com.irongyan.client.tools.annotation.IsValidator; import com.irongyan.client.tools.annotation.NotEmpty; import com.irongyan.client.tools.annotation.VerifyObjPar; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.MethodSignature; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Parameter; import java.util.Arrays; @Aspect public class ParAopVerify { @Pointcut("execution(* com.irongyan.client.controller.*.*(..))") public void doParAopVerify(){} @Before("doParAopVerify()") public void requestParVerify(JoinPoint joinPoint) throws Exception { Object[] args = joinPoint.getArgs(); MethodSignature methodSignature= (MethodSignature)joinPoint.getSignature(); VerifyObjPar verifyObjPar = methodSignature.getMethod().getAnnotation(VerifyObjPar.class); //如果为空 说明该方法不要进行参数校验 if(verifyObjPar==null){ return ; } Parameter[] parameters = methodSignature.getMethod().getParameters(); StringBuilder sb = new StringBuilder();//线程不安全 但是快效率高 for (int i=0; i<parameters.length; i++) { System.out.println("getName----"+args[i].getClass().getName()); ///自定义类 dto if(args[i].getClass().getName().toString().indexOf("com.irongyan.client.dto")>=0){ ///查看对象是含有该注解 如果有就说明是需要开启aop 的校验 IsValidator annotation = parameters[i].getAnnotation(IsValidator.class); if(annotation!=null){ sb.append(AnnotationHelpUtils.isObjAnntation(parameters[i],args[i])); } continue; } sb.append(AnnotationHelpUtils.isAnntation(parameters[i], args[i])); } if(sb.length()>1){ throw new VerifyException(ResultMsg.IS_NULL.getCode(),sb.toString()); } System.out.println("-------------前置通知--------------"+sb.toString()); } }

以上就差不多搞完了  接下就是配置统一处理异常和返回的工具 统一处理异常 :

@ControllerAdvice @ResponseBody() public class ExceptionHandle { @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ExceptionHandler(RuntimeException.class) public Result test(RuntimeException e){ e.printStackTrace(); if(e instanceof VerifyException){ VerifyException v=(VerifyException)e; return ResultUtil.error(v.getCode(),v.getMsg()); } return ResultUtil.success(); } } public class ResultUtil { public static <T> Result success(T t){ Result res=new Result(); res.setMsg(ResultMsg.SUCCESS.getMessage()); res.setCode(ResultMsg.SUCCESS.getCode()); res.setData(t); return res; } public static Result success() { return success(null); } public static Result error(String code,String msg){ Result res=new Result(); res.setMsg(msg); res.setCode(code); return res; } } package com.irongyan.client.dto; public class Result<T> { //提示信息 private String msg; //提示码 private String code ; ///提示内容 private T data; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public T getData() { return data; } public void setData(T data) { this.data = data; } } package com.irongyan.client.dto; public enum ResultMsg { IS_NULL("10001","参数校验失败"), SUCCESS("10000","成功") ; private String message; private String code ; ResultMsg(String code, String message) { this.message = message; this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } }

目前基本所有的工具和类基本完成 接下就用法了

@RequestMapping(value="/{id}/findById",produces="application/json;charset=UTF-8") @ResponseBody @VerifyObjPar //开启校验参数 public Result<Tb_User> findById( @IsNumber(max=1000,keyName = "id",isNull = false) //表明不允许为空,而且对大值是1000 @PathVariable(value="id",required = false) Integer id, @IsValidator TestDto dto,///作用于bean HttpServletRequest request) throws Exception { Tb_User user = userService.queryById(id); request.getSession().setAttribute("TEST_SESSION",user); return ResultUtil.success(user); } public class TestDto { @NotEmpty(keyName = "name") private String name; @IsNumber(keyName = "age",isNull = false,max = 100) private Integer age;}

以上用法就是这样 如有不对,请指出 马上修改呀 3Q~

转载请注明原文地址: https://www.6miu.com/read-2632107.html

最新回复(0)