技术控

    今日:114| 主题:49431
收藏本版 (1)
最新软件应用技术尽在掌握

[其他] Spring AOP完成一个简单的参数统一校验框架

[复制链接]
橘虞 发表于 2016-10-17 19:22:52
148 4

立即注册CoLaBug.com会员,免费获得投稿人的专业资料,享用更多功能,玩转个人品牌!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
版权声明:此文章转载自_infocool
  原文链接:http://www.infocool.net/kb/Java/201610/200829.html
  如需转载请联系听云College团队成员小尹 邮箱:yinhy#tingyun.com
  最近刚刚学习了Spring AOP,也是首次使用Spring AOP进行项目开发,尝试写了一个简单的参数校验框架,也许对像我一样新接触spring AOP的童鞋有所参考,故此分享,若有不合理的地方,请大神帮忙指正,非常感谢!
  搭建Spring开发环境这里就不详细说明了,除了spring的一些核心包,再引入spring-aop.jar即可。
  我想要做的效果是:在所有的Controller方法中,通过注解开关定义是否校验参数,并且可配置参数实体中各个元素的校验规则。
  
       
  •       定义参数校验的开关
      
  在controller方法中,可能有些参数需要校验,也有些参数不需要校验,所以定义了一个参数校验开关。我使用的是一个注解,Valid注解定义如下:
  1. package com.test.constant.annotation;
  2. import java.lang.annotation.ElementType;
  3. import java.lang.annotation.Retention;
  4. import java.lang.annotation.RetentionPolicy;
  5. import java.lang.annotation.Target;
  6. @Target({ElementType.METHOD,ElementType.PARAMETER})
  7. @Retention(RetentionPolicy.RUNTIME)
  8. public @interface Valid {
  9. }
  10.     Valid只是一个简单的注解,注意它的ElementType我主要用在PARAMETER上,因为这样才可以选择性地去定义哪个参数需要做校验。
  11.     @Valid注解在controller中方法使用如下:
  12. /**
  13. * 功能: 修改问题
  14. * @param form
  15. * @param servletRequest
  16. * @param servletResponse
  17. * @return
  18. * @throws Exception
  19. */
  20. @ResponseBody
  21. @RequestMapping("/work/disProblemController/update")
  22. public ResponseInfo<String> updateProblem(@Valid UpdateProblemForm form,HttpServletRequest servletRequest,
  23. HttpServletResponse servletResponse) throws Exception {
复制代码
  1. ResponseInfo<String> responseInfo = new ResponseInfo<String>();
  2. try {
  3. problemService.updateProblem(form);
  4. } catch (Exception e) {
  5. throw new Exception("修改问题异常",e);
  6. }
  7. responseInfo.setRtnCode(AlmRetConstant.code.APP_RET_SUCCESS_CODE);
  8. responseInfo.setRtnMsg(AlmRetConstant.msg.APP_RET_SUCCESS_CODE);
  9. responseInfo.setSuccess(true);
  10. return responseInfo;
  11. }
复制代码
2. 定义参数校验规则
  Check注解定义参数校验规则,现在只做了几种简单的校验规则,如后续接入其他更复杂的规则,考虑使用正则表达式校验。代码如下:
  1. package com.test.constant.annotation;
  2. import java.lang.annotation.ElementType;
  3. import java.lang.annotation.Retention;
  4. import java.lang.annotation.RetentionPolicy;
  5. import java.lang.annotation.Target;
  6. @Target({ ElementType.METHOD, ElementType.FIELD})
  7. @Retention(RetentionPolicy.RUNTIME)
  8. public @interface Check {
  9. /**
  10. * 是否非空
  11. */
  12. public boolean notNull() default false;
  13. /**
  14. * 是否为数值
  15. */
  16. public boolean numeric() default false;
  17. /**
  18. * 最大长度
  19. */
  20. public int maxLen() default -1;
  21. /**
  22. * 最小长度
  23. */
复制代码
  1. public int minLen() default -1;
  2. /**
  3. * 最小数值
  4. */
  5. public long minNum() default -999999;
  6. }
  7.    
  8.     @Check注解在参数实体中的使用方式如下(以UpdateProblemForm实体为例):
  9. package com.test.form;
  10. import com.pingan.almcenter.constant.annotation.Check;
  11. /**
  12. * 修改问题表单
  13. *
  14. */
  15. public class UpdateProblemForm {
  16. @Check(notNull=true)
  17. private Integer id; //问题ID
  18. @Check(notNull = true, maxLen = 30)
  19. private String problemName;// 问题名称
  20. @Check(notNull = true, maxLen = 3)
  21. private String problemType;// 问题类型
  22. @Check(notNull = true, maxLen = 3)
  23. private String problemStatus;// 问题状态
复制代码
  1. @Check(maxLen = 320)
  2. private String problemMsg;// 问题详细信息
  3. @Check(notNull = true, maxLen = 30)
  4. private String bankName;// 所属银行名称
  5. [email protected](notNull=true)
  6. private Integer bankId;// 所属银行id
  7. public Integer getId() {
  8. return id;
  9. }
  10. public void setId(Integer id) {
  11. this.id = id;
  12. }
  13. public String getProblemName() {
  14. return problemName;
  15. }
  16. public void setProblemName(String problemName) {
  17. this.problemName = problemName;
  18. }
  19. public String getProblemType() {
  20. return problemType;
  21. }
  22. public void setProblemType(String problemType) {
  23. this.problemType = problemType;
  24. }
  25. public String getProblemStatus() {
  26. return problemStatus;
  27. }
  28. public void setProblemStatus(String problemStatus) {
复制代码
  1. this.problemStatus = problemStatus;
  2. }
  3. public String getProblemMsg() {
  4. return problemMsg;
  5. }
  6. public void setProblemMsg(String problemMsg) {
  7. this.problemMsg = problemMsg;
  8. }
  9. public String getBankName() {
  10. return bankName;
  11. }
  12. public void setBankName(String bankName) {
  13. this.bankName = bankName;
  14. }
  15. public Integer getBankId() {
  16. return bankId;
  17. }
  18. public void setBankId(Integer bankId) {
  19. this.bankId = bankId;
  20. }
  21. }
复制代码
3. 最后是Aspect的主体内容,定义 Around方法并实现参数校验
  Aspect类的代码如下:
  定义切点。我只想用它来校验controller包中方法的参数,所以我切点切在controller上,切点的定义方式还有很多种,可以考虑其他方式。
  1. package com.test.aspect;
  2. import org.aspectj.lang.ProceedingJoinPoint;
  3. import org.aspectj.lang.annotation.Around;
  4. import org.aspectj.lang.annotation.Aspect;
  5. import org.aspectj.lang.annotation.Pointcut;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.stereotype.Component;
  8. @Component
  9. @Aspect
  10. public class ParameterCheckAspect {
  11. @Autowired
  12. private ParameterCheckOption parameterCheckOption;
  13. // 定义切点
  14. @Pointcut("within(com.pingan.almcenter.controller..*)")
  15. public void check() {
  16. }
  17. /**
  18. * 切面方法,使用统一异常处理
  19. *
  20. * @param joinPoint
  21. * @return
  22. * @throws Throwable
  23. */
  24. @Around(value = "check()", argNames = "Valid")
  25. public Object checkIsValid(ProceedingJoinPoint joinPoint) throws Throwable {
复制代码
  1. Object object = null;
  2. // 参数校验,未抛出异常表示验证OK
  3. parameterCheckOption.checkValid(joinPoint);
  4. object = ((ProceedingJoinPoint) joinPoint).proceed();
  5. return object;
  6. }
  7. }
  8.    ParameterCheckOption处理类代码如下:
  9. package com.test.aspect;
  10. import java.lang.annotation.Annotation;
  11. import java.lang.reflect.Field;
  12. import java.lang.reflect.Method;
  13. import java.math.BigDecimal;
  14. import org.aspectj.lang.ProceedingJoinPoint;
  15. import org.springframework.stereotype.Component;
  16. import org.springframework.util.StringUtils;
  17. import com.pingan.almcenter.constant.BaseComponent;
  18. import com.pingan.almcenter.constant.annotation.Check;
  19. import com.pingan.almcenter.constant.annotation.Valid;
  20. import com.pingan.almcenter.constant.exception.ParameterException;
  21. @Component
  22. public class ParameterCheckOption extends BaseComponent{
复制代码
  1. public void checkValid(ProceedingJoinPoint joinPoint) throws Exception{
  2. Object[] args = null;
  3. Method method = null;
  4. Object target = null;
  5. String methodName = null;
  6. String str = "";
  7. try {
  8. methodName = joinPoint.getSignature().getName();
  9. target = joinPoint.getTarget();
  10. method = getMethodByClassAndName(target.getClass(), methodName);
  11. Annotation[][] annotations = method.getParameterAnnotations();
  12. args = joinPoint.getArgs(); // 方法的参数
  13. if (annotations != null) {
  14. for (int i = 0; i < annotations.length; i++) {
  15. Annotation[] anno = annotations[i];
  16. for (int j = 0; j < anno.length; j++) {
  17. if (annotations[i][j].annotationType().equals(
  18. Valid.class)) {
  19. str = checkParam(args[i]);
  20. if (StringUtils.hasText(str)) {
  21. throw new ParameterException(str);
  22. }
  23. }
  24. }
  25. }
  26. }
复制代码
  1. } catch (Throwable e) {
  2. logger.error("参数校验异常" + e);
  3. throw new ParameterException(str);
  4. }
  5. }
  6. /**
  7. * 校验参数
  8. *
  9. * @param args
  10. * @return
  11. * @throws Exception
  12. */
  13. private String checkParam(Object args) throws Exception {
  14. String retStr = "";
  15. Field[] field = args.getClass().getDeclaredFields();// 获取方法参数(实体)的field
  16. for (int j = 0; j < field.length; j++) {
  17. Check check = field[j].getAnnotation(Check.class);// 获取方法参数(实体)的field上的注解Check
  18. if (check != null) {
  19. String str = validateFiled(check, field[j], args);
  20. if (StringUtils.hasText(str)) {
  21. retStr = str;
  22. return retStr;
  23. }
  24. }
  25. }
  26. return retStr;
  27. }
复制代码
  1. ResponseInfo<String> responseInfo = new ResponseInfo<String>();
  2. try {
  3. problemService.updateProblem(form);
  4. } catch (Exception e) {
  5. throw new Exception("修改问题异常",e);
  6. }
  7. responseInfo.setRtnCode(AlmRetConstant.code.APP_RET_SUCCESS_CODE);
  8. responseInfo.setRtnMsg(AlmRetConstant.msg.APP_RET_SUCCESS_CODE);
  9. responseInfo.setSuccess(true);
  10. return responseInfo;
  11. }0
复制代码
  1. ResponseInfo<String> responseInfo = new ResponseInfo<String>();
  2. try {
  3. problemService.updateProblem(form);
  4. } catch (Exception e) {
  5. throw new Exception("修改问题异常",e);
  6. }
  7. responseInfo.setRtnCode(AlmRetConstant.code.APP_RET_SUCCESS_CODE);
  8. responseInfo.setRtnMsg(AlmRetConstant.msg.APP_RET_SUCCESS_CODE);
  9. responseInfo.setSuccess(true);
  10. return responseInfo;
  11. }1
复制代码
  1. ResponseInfo<String> responseInfo = new ResponseInfo<String>();
  2. try {
  3. problemService.updateProblem(form);
  4. } catch (Exception e) {
  5. throw new Exception("修改问题异常",e);
  6. }
  7. responseInfo.setRtnCode(AlmRetConstant.code.APP_RET_SUCCESS_CODE);
  8. responseInfo.setRtnMsg(AlmRetConstant.msg.APP_RET_SUCCESS_CODE);
  9. responseInfo.setSuccess(true);
  10. return responseInfo;
  11. }2
复制代码
由于框架使用了另一个统一异常处理小框架,所以所有的异常都没处理,而是直接抛出,由统一异常处理类去处理。单独用可以自主处理异常。
  终上所述,Spring AOP进行参数统一校验的功能就实现了。由于是初接触AOP,所以写得比较粗糙,若有不妥之处,请大牛们批评指正,  
  想阅读更多技术文章,请访问听云技术博客,访问听云官方网站感受更多应用性能优化魔力。
友荐云推荐




上一篇:最专业的配送体系 江湖外卖O2O系统一站式解决方案
下一篇:Studying the Internet Censorship in South Korea
酷辣虫提示酷辣虫禁止发表任何与中华人民共和国法律有抵触的内容!所有内容由用户发布,并不代表酷辣虫的观点,酷辣虫无法对用户发布内容真实性提供任何的保证,请自行验证并承担风险与后果。如您有版权、违规等问题,请通过"联系我们"或"违规举报"告知我们处理。

刘坤明 发表于 2016-10-17 22:37:02
打酱油的人拉,回复下赚取积分
回复 支持 反对

使用道具 举报

黄蓉 发表于 2016-10-17 23:29:59
今年楼主不送礼,送礼就给楼下的!
回复 支持 反对

使用道具 举报

淡醇熏骨染云笺 发表于 2016-10-19 08:19:20
勤奋灌水,天天向上!
回复 支持 反对

使用道具 举报

立果 发表于 2016-11-6 11:55:56
支持楼主,用户楼主,楼主英明呀!!!
回复 支持 反对

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

我要投稿

推荐阅读

扫码访问 @iTTTTT瑞翔 的微博
回页顶回复上一篇下一篇回列表手机版
手机版/CoLaBug.com ( 粤ICP备05003221号 | 文网文[2010]257号 )|网站地图 酷辣虫

© 2001-2016 Comsenz Inc. Design: Dean. DiscuzFans.

返回顶部 返回列表