2019独角兽企业重金招聘Python工程师标准>>>

背景

首先,我们达成以下共识:

  • 一个服务方法,如果入参太多,且基本为非pojo,会给调用方造成不必要的干扰。尽管可以把文档写的很完善,但还是建议使用pojo对多个参数合理封装。
    如下示例:
@Data
public class UserVo {private String       username;private Integer      age;private List<String> hobby;
}
  • 执行方法都应该对入参进行校验。对于一些通用的简单的不涉及业务逻辑的校验,比如字符串不为空,数字的范围限制,我们没必要将校验代码写在方法内部。如下示例
@Service
public class UserService {public void addUser(UserVo userVo) {// 参数基本校验if (StringUtils.isEmpty(userVo.getUsername())|| userVo.getAge() < 0|| userVo.getAge() > 200|| CollectionUtils.isEmpty(userVo.getHobby())) {throw new IllegalArgumentException();}// 业务逻辑操作}
}
  • 我们的项目采用了spring框架,这是标配,且service bean是要被调用的。

实现思路

有了上述共识之后,我们来开始实现一点想法:结合Spring的切面用法,能够很方便的拿到切点的方法入参,然后可以进行参数校验。

比较常见的一种方式是:使用Java bean注解校验。大致用法就是:在pojo加上相应的校验注解,然后在切面中利用hibernate-validator进行校验。这种方式springmvc已经帮我们实现了,而且使用效果不错。

@Data
public class UserVo {@NotEmptyprivate String       username;@Max(value = 200)@Min(value = 1)private Integer      age;@NotEmptyprivate List<String> hobby;
}

前面提到,暴露的方法尽量简洁易用,不要造成太多的干扰。pojo的属性应该保持简洁,加上必要的注释。

我们原本的想法就是,利用切面把方法中大量类似的简单的校验逻辑抽离出来,在切面中执行校验的过程。不同pojo有不同的属性,那么校验逻辑还是会存在不同,如果不使用注解校验,在切面中拿到了不同的pojo,可能会写很多的 instance of判断,当然也可以利用设计模式实现的很好。总之,我们确实把service方法中的校验抽离出来了。

铺垫了这么多,我们为什么不可以把校验逻辑放进对应的pojo中呢?这样,调用方也能够清晰地看到基本的校验逻辑,其调用前也可以调用校验方法检查参数的合法性。

具体实现

1. 定义pojo要实现的校验接口

public interface ValidationHandler {/*** 校验pojo的属性** @return 通过/不通过*/boolean isValid();
}

2. pojo实现接口ValidationHandler,编写校验逻辑

@Data
public class UserVo implements ValidationHandler {private String       username;private Integer      age;private List<String> hobby;@Overridepublic boolean isValid() {return StringUtils.isNotEmpty(username)&& age > 0&& age < 100&& !hobby.isEmpty();}
}

3. 切面

  • 此处切点使用注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ParamValidation {
}
  • 在service中使用
@Service
public class UserService {@ParamValidationpublic void addUser(UserVo userVo) {// 业务逻辑操作}
}
  • 具体切面代码
@Component @Aspect
public class ParamValidator {@Pointcut("@annotation(com.ex.validator.ParamValidation)")public void validate() { }@Before("validate()")public void before(JoinPoint joinPoint) {for (Object arg : joinPoint.getArgs()) {if (arg instanceof ValidationHandler) {if (!((ValidationHandler) arg).isValid()) {throw new IllegalArgumentException("参数校验不通过");}}}}
}

4. 调用结果

自行写方法调用,能够正常执行到aop校验

升级版

本来写到这里就结束了,偶然发现了一个彩蛋,于是有了升级版。

我们看一下bean validation的标准注解@javax.validation.constraints.AssertTrue,这个注解要求bean的属性为true,除了放在属性上,也可以放在get/is方法上。经过测试,==可以放在自定义方法上,该方法名需以isget开头==。

说到底,我们就干了一件事:把校验逻辑放进对应的pojo。其实上面的实现都是没必要的,既然都用上了,就不重复造轮子了。把自定义接口和切面都去掉,UserVo可以变成如下:

@Data
public class UserVo {private String       username;private Integer      age;private List<String> hobby;@AssertTruepublic boolean isValid() {return StringUtils.isNotEmpty(username)&& age > 0&& age < 100&& !hobby.isEmpty();}
}

service方法就变成了:

@Validated //打开校验开关
@Service
public class UserService {// 入参pojo添加@Validpublic void addUser(@Valid UserVo userVo) {// 业务逻辑操作}
}

是不是很熟悉呢?校验效果和前面一样,种一棵树最好的时间是十年前,而后是现在!

转载于:https://my.oschina.net/u/3980693/blog/2992816

Java开发中业务层入参校验详细解析相关推荐

  1. 【蓝桥杯】Java开发A组省赛真题+详细解析

    1. 世纪末的星期 曾有邪教称1999年12月31日是世界末日.当然该谣言已经不攻自破.   还有人称今后的某个世纪末的12月31日,如果是星期一则会-   有趣的是,任何一个世纪末的年份的12月31 ...

  2. 线程同步锁 java_java多线程同步之重入锁,详细解析

    上次已经为大家介绍过java多线程同步,Volatile详解的主要内容了.今天再来为大家介绍一些相关的内容,也就是java多线程同步之重入锁,一起来了解一下吧. 使用重入锁实现线程同步 在JavaSE ...

  3. java中Long类型传参校验注解_JAVA——实现json bean实体类的传参校验模板及注解详解...

    关注wx:CodingTechWork,一起学习进步. 引言 在java开发中,经常需要和外界系统进行参数对接,api设计中难免会遇到json传参不一致的情况,虽然纸面或者接口规范约束了应该怎么传参, ...

  4. Java开发中巧妙使用链表来实现模拟栈的入栈出栈操作

    2019独角兽企业重金招聘Python工程师标准>>> 在Java开发中经常会碰到需要你用Java链表来实现入栈出栈的模拟操作,下文就这个操作做了一个详细的描述. 栈:后进先出:最后 ...

  5. 编写高质量代码:改善Java程序的151个建议 (第1章 Java开发中通用的方法和准则)

    第1章 Java开发中通用的方法和准则 The reasonable man adapts himself to the world;the unreasonable one persists in ...

  6. Java开发中Netty线程模型原理解析!

    Java开发中Netty线程模型原理解析,Netty是Java领域有名的开源网络库具有高性能和高扩展性的特点,很多流行的框架都是基于它来构建.Netty 线程模型不是一成不变的,取决于用户的启动参数配 ...

  7. JAVA表示层,业务层,持久层的框架分别有哪些

    JAVA表示层,业务层,持久层的框架分别有哪些 1.表示层 JSP,Freemark,Velocity, 2.控制层 Struts,Struts2 3.持久层 Hibernate.Mybatis.My ...

  8. Java开发中经常使用到的几种WebService技术实现方案

    Java开发中经常使用到的几种WebService技术实现方案 随着异构系统互联需求的不断增加,WebService的重要性也日益彰显出来.凭借webservice,我们可以实现基于不同程序语言的项目 ...

  9. Java开发中Websocket的技术选型参考

    1. 前言 Websocket是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议.WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据 ...

最新文章

  1. JZOJ 5048. 【GDOI2017模拟一试4.11】IQ测试
  2. 安卓系统源码编译系列(六)——单独编译内置浏览器WebView教程
  3. ONE-ReactNative
  4. 曲演杂坛--SQLCMD下执行命令失败但没有任何错误提示的坑
  5. GitHub上README写法暨markdown语法解读
  6. 鸟哥的linux私房菜中推荐的linux学习网站
  7. RPA案例 | 电商使用超自动化平台提升运营精细化
  8. Python中的*和**
  9. psycopg2 : cursor already closed
  10. 如何获取手机的屏幕尺寸
  11. DataTable数据过滤方法
  12. 王者荣耀英雄选中界面html5制作
  13. 7-20 帅到没朋友
  14. 「雕爷学编程」Arduino动手做(23)——矩形脉冲发生器
  15. 百度地图之鼠标绘制工具条库(开源库)
  16. mac服务器文件同步软件,[MACOS]使用fswatch和SCP配合实现自动单向实时同步文件
  17. RTX51Tiny 学习笔记(三)
  18. 80%的人都关注的电子合同签署疑问,君子签官方解答来了!
  19. matlab中conj和,[转载]matlab中 conv和xcorr两个函数的区别conj()函数
  20. java 用代码清除图片_Java清除图片中的恶意信息(利用jmagick)

热门文章

  1. document.execCommand()方法处理Html数据
  2. Mysql连接问题:com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException
  3. Linux文件压缩与归档
  4. 《Hack与HHVM权威指南》——1.5.2 覆盖方法的类型
  5. Downloading the Source
  6. 2012年度IT博客大赛50强报道:高俊峰
  7. IhttpHandler
  8. .f90文件批量转为dll文件_办公必备神器DropIt V8.5.1Portable文件整理分类工具
  9. 5G NR — O-RAN 的系统架构
  10. Kong APIGW — OpenResty