一、参数管理

在编程系统中,为了能写出良好的代码,会根据是各种设计模式、原则、约束等去规范代码,从而提高代码的可读性、复用性、可修改,实际上个人觉得,如果写出的代码很好,即别人修改也无法破坏原作者的思路和封装,这应该是非常高水准。

但是在日常开发中,碍于很多客观因素,很少有时间去不断思考和优化代码,所以只能从实际情况的角度去思考如何构建系统代码,保证以后自己还能读懂自己的代码,在自己的几年编程中,实际会考虑如下几个方面:代码层级管理,命名和注释统一,合理的设计业务数据库,明确参数风格。

这里就来聊一下参数管理,围绕:入参、校验、返参三个方面内容。

如何理解代码规范这个概念:即大多数开发认同,愿意遵守的约束,例如Spring框架和Mvc模式对于工程的管理,《Java开发手册》中对于业务开发的规定,其根本目的都是想避免随着业务发展,代码演变到无法维护的境界。

二、接收参数

接收参数方式有很多种,List,Map,Object等等,但是为了明确参数的语义,通常都需要设计参数对象的结构并且遵守一定的规范,例如明确禁止Map接收参数:

Rest风格接收单个ID参数:

@GetMapping("/param/single/{id}")
public String paramSingle (@PathVariable Integer id){
return "Resp:"+id ;
}

接收多个指定的参数:

@GetMapping("/param/multi")
public String paramMulti (@RequestParam("key") String key, @RequestParam("var") String var){
return "Resp:"+key+var ;
}

基于Java包装对象入参:

@PostMapping("/param/wrap")
public ParamIn paramWrap (@RequestBody ParamIn paramIn){
return paramIn ;
} -- 参数对象实体
public class ParamIn {
private Integer id ;
private String key ;
private String var ;
private String name ;
}

以上是在开发中常用的几种接参方式,这里通常会遵守下面几个习惯:

  • 参数语义:明确接收参数的作用;
  • 个数限制:参数超过三个使用包装对象;
  • 避免多个接口使用单个包装对象入参;
  • 避免包装对象主体过于复杂;

参数接收并没有很复杂的约束,整体上也比较容易遵守,通常的问题在于处理较大主体对象时,容易产生一个包装对象被多处复用,进而导致对象字段属性很多,这种情况在复杂业务中尤其容易出现,这种对象并不利于web层接口使用,或者很多时候都会在业务层和接口层混用对象;

在业务层封装复杂的BO对象来降低业务管理的复杂度,这是合理常见的操作,可以在web接口层面根据接口功能各自管理入参主体,在业务实现的过程中,再传入BO对象中。

避免复杂的业务包装对象在各个层乱飘,如果多个接口入参都是同一个复杂的对象,很容易让开发人员迷茫。

三、响应参数

与参数接收相对应的就是参数响应,参数响应通常具有明确的约束规范:响应主体数据,响应码,描述信息。通常来说就是这样三个核心要素。

响应参数主体:

这里泛型的使用通常用来做主体数据的接收。

public class Resp<T> {

    private int code ;
private String msg ;
private T data ; public static <T> Resp<T> ok (T data) {
Resp<T> result = new Resp<>(HttpStatus.OK);
result.setData(data);
return result ;
} public Resp (HttpStatus httpStatus) {
this.code = httpStatus.value();
this.msg = httpStatus.getReasonPhrase();
} public Resp(int code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
}

Code状态码

即接口状态,建议参照并遵守HttpStatus中状态码的描述,这是开发普遍遵守的规范,如果不满足业务需求,在适当自定义部分编码,可以完全自定义一套响应码,但是没太多必要。

Msg描述

描述接口的响应的Msg可能就是:成功或失败,更多的时候是需要处理业务异常的提示信息,例如单号不存在,账号冻结等等,通常需要从业务异常中捕获提示信息,并响应页面,或者入参校验不通过的描述。

Data数据

接口响应的主体数据,不同的业务响应的对象肯定不同,所以这里基于泛型机制接收即可,再以JSON格式响应页面。

参考案例

接口返参:

@PostMapping("/resp/wrap")
public Resp<KeyValue> respWrap (@RequestBody KeyValue keyValue){
return Resp.ok(keyValue) ;
}

响应格式:

{
"code": 200,
"msg": "OK",
"data": {
"key": "hello",
"value": "world"
}
}

四、参数校验

参数接收和响应相对都不是复杂的,比较难处理的就是参数校验:入参约束校验,业务合法性校验,响应参数非空非null校验,等各种场景。

在系统运行过程中,任何参数都不是绝对可靠的,所以参数校验随处可见,不同场景下的参数校验,都有其必要性,但其根本目的都是为了给到请求端提示信息,快速打断流程,快速响应。

1、借鉴参考

很多封装思想,设计模式,或者这里说的参数校验,都可以参考现有Java源码或者优秀的框架,这是一个应该具备的基础意识。

Java原生方法之java.lang.Thread线程:

public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0();
b.interrupt(this);
return;
}
}
interrupt0();
}

在Java源码中,大部分都是采用原生的if判断方式,对参数执行校验

Spring框架org.springframework.util.ClassUtils工具类部分代码:

public static Class<?> forName(String name, @Nullable ClassLoader classLoader)
throws ClassNotFoundException, LinkageError {
Assert.notNull(name, "Name must not be null");
Class<?> clazz = resolvePrimitiveClassName(name);
if (clazz == null) {
clazz = commonClassCache.get(name);
}
if (clazz != null) {
return clazz;
}
}

在Spring框架中除了基础的if判断之外,还封装一个org.springframework.util.Assert断言工具类。

2、常用校验方式

If判断

@GetMapping("/check/base")
public String baseCheck (@RequestParam("var") String var){
if (var == null) {
return var+" is null" ;
}
if ("".equals(var)){
return var+" is empty" ;
}
if ("hello".equals(var)){
return var+" sensitive word " ;
}
return var + " through " ;
}

这种判断在代码中很常见,只是一旦遇到校验的主体对象很大,并且在分布式的环境中,需要重复写if判断的话,容易出错是一个方面,对开发人员的耐心考验是另一个方面。

Valid组件

在早几年的时候,比较流行的常用校验组件Hibernate-Validator,后来兴起的Validation-Api,据说是参考前者实现,不过这并不重要,二者都简化了对JavaBean的校验机制。

基于注解的方式,标记Java对象的字段属性,并设定如果校验失败的提示信息。

public class JavaValid {

    @NotNull(message="ID不能为空")
private Integer id ; @Email(message="邮箱格式异常")
private String email ; @NotEmpty(message = "字段不能为空")
@Size(min = 2,max = 10,message = "字段长度不合理")
private String data ;
}

校验结果打印:

public class JavaValidTest {

    private static Validator validator ;

    @BeforeClass
public static void beforeBuild (){
validator = Validation.buildDefaultValidatorFactory().getValidator();
} @Test
public void checkValid (){
JavaValid valid = new JavaValid(null,"email","data") ;
Set<ConstraintViolation<JavaValid>> validateInfo = validator.validate(valid) ;
// 打印校验结果
validateInfo.stream().forEach(validObj -> {
System.out.println("validateInfo:"+validObj.getMessage());
});
}
}

接口使用:

@PostMapping("/java/valid")
public JavaValid javaValid (@RequestBody @Valid JavaValid javaValid,BindingResult errorMsg){
if (errorMsg.hasErrors()){
List<ObjectError> objectErrors = errorMsg.getAllErrors() ;
objectErrors.stream().forEach(objectError -> {
logger.info("CheckRes:{}",objectError.getDefaultMessage());
});
}
return javaValid ;
}

这种校验机制基于注解方式,可以大幅度简化普通的入参校验,但是对业务参数的合法校验并不适应,例如常见的ID不存在,状态拦截等。

Assert断言

关于Assert断言方式,起初是在单元测试中常见,后来在各种优秀的框架中开始常见,例如Spring、Mybatis等,然后就开始出现在业务代码中:

public class AssertTest {
private String varObject ;
@Before
public void before (){
varObject = RandomUtil.randomString(6) ;
} @Test
public void testEquals (){
Assert.assertEquals(varObject+"不匹配",varObject,RandomUtil.randomString(6));
}
@Test
public void testEmpty (){
Assert.assertTrue(StrUtil.isNotEmpty(varObject));
Assert.assertFalse(varObject+" not empty",StrUtil.isNotEmpty(varObject));
}
@Test
public void testArray (){
/*
数组元素不相等: arrays first differed at element [1];
Expected :u08
Actual :mwm
*/
String var = RandomUtil.randomString(5) ;
String[] arrOne = new String[]{var,RandomUtil.randomString(3)} ;
String[] arrTwo = new String[]{var,RandomUtil.randomString(3)} ;
Assert.assertArrayEquals("数组元素不相等",arrOne,arrTwo);
}
}

Assert断言,可以替换传统的if判断,大量减少参数校验的代码行数,提高程序的可读性,这种风格是目前比较流行的方式。

五、源代码地址

GitHub·地址
https://github.com/cicadasmile/middle-ware-parent
GitEE·地址
https://gitee.com/cicadasmile/middle-ware-parent

阅读标签

Java基础】【设计模式】【结构与算法】【Linux系统】【数据库

分布式架构】【微服务】【大数据组件】【SpringBoot进阶】【Spring&Boot基础

数据分析】【技术导图】【 职场

SpringBoot2 参数管理实践,入参出参与校验的更多相关文章

  1. 先查询再插入,改为存储过程,java部分入参出参、mybatisxml【我】

    先查询再插入,改为存储过程 create or replace procedure PRO_REVENUE_SI(l_p_cd in Varchar2, l_c_cd in Varchar2, l_p ...

  2. python调用c/c++ (入参出参为指针)

    python可以使用ctypes库调用c++编译的so库函数 0x01  c/c++编译为so库文件 编译C文件 gcc -o libpycallfoo.so -shared -fPIC rsa.c  ...

  3. springboot项目中接口入参的简单校验

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

  4. spring MVC模式拦截所有入口方法的入参出参打印

    import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.serializer.SerializerFeature; im ...

  5. SpringValid优雅校验入参

    一.简介 后台业务入口类Controller,对于入参的合法性校验,可以简单粗暴的写出一堆的 if 判断,如下: @RestController @RequestMapping("user& ...

  6. Egg.js 中入参的校验

    日常作业中免不了频繁处理 GET/POST 的入参,你当然可以每个 action 中都重复地去做这些事情, 从 query 或 body 取出入参, 对可选的入参进行判空, 处理入参的类型转换, 对入 ...

  7. visual studio -- 调试时自动传递给exe入参

    如果你写的main函数接受入参int main(int argc, char* argv[]),则可以 右键工程--属性--调试,在命令行参数中输入入参即可,这些字符串会被直接传递给exe.

  8. Saiku根据入参日期查询出对应的数据(二十)

    Saiku根据入参日期查询出对应的数据 之前好像有写过一篇博客关于saiku date range的,现在进一步更新啦!!! 这里的日期筛选会更完善一些,需要提供两个参数 开始日期与结束日期(star ...

  9. 字节码编程,Javassist篇二《定义属性以及创建方法时多种入参和出参类型的使用》

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 在上一篇 Helloworld 中,我们初步尝试使用了 Javassist字节编程的 ...

随机推荐

  1. drbd虚拟机宕机恢复方法

    问题现象 云南计算节点YN-ec-compute-19因系统盘损坏宕机且操作系统无法恢复,其上本地虚拟机无法疏散且无法迁移 拟采用drbd备份的数据对compute19上的虚拟机进行恢复 恢复方法 1 ...

  2. iwrite复制攻略

    打开iwrite,一提交作业,发现: 这可咋办啊! 那就跟着步骤来呗: 按F12打开元素审查 点一下左上角 再点一下文本框,就能定位到HTML中的位置 在文本框中写几个字母,康康具体位置: 那就复制进 ...

  3. @ResponseBody、@RequestBody

    @ResponseBody 我们在刚刚接触Springboot的第一个hello工程的时候,我们就接触了一个RestController,而通过进入它的源码,我们会发现@ResponseBody @R ...

  4. 封装了一些sqlsugar的常用方法 用来动态切换数据库和依赖注入 支持泛型

    接口: /// <summary> /// 数据库操作 /// </summary> public interface IDAL_Services { /// <summ ...

  5. 通过Dapr实现一个简单的基于.net的微服务电商系统(十二)——istio+dapr构建多运行时服务网格

    多运行时是一个非常新的概念.在 2020 年,Bilgin Ibryam 提出了 Multi-Runtime(多运行时)的理念,对基于 Sidecar 模式的各种产品形态进行了实践总结和理论升华.那到 ...

  6. MakeCode图形编程应用在micro:bit上的多工性能实测

    1. 简述 本文不涉及对测试中所用到的设备或软件的推广. micro:bit 是一款由英国广播电视公司(BBC)为青少年编程教育设计,并由微软,三星,ARM,英国兰卡斯特大学等合作伙伴共同完成开发的微 ...

  7. ruby基础(三)

    类和模块 1.类 类是面向对象中一个重要的术语.我们可以把类看作是对象的抽象, 所有的这类对象都有这些特征.而对象则是类的具体实现,按照类的要求创建的 对象就是该类的对象.类就像对象的雏形一样,决定了 ...

  8. 转圈 箭头 ⟳ 10227 27F3 刷新 HTML常用的特殊符号总结

    HTML常用的特殊符号总结 2014年9月12日 57621次浏览 html中经常会用到一些特殊符号,例如箭头,雪花,心形等等,这些符号就不用css样式或者图片来写了,直接用html特殊符号可以实现. ...

  9. Linux——定时清空日志内容和删除日志文件

    前言 最近在做性能压测试,会生成大量的日志,导致后续越压越慢,最终磁盘空间占满之类的问题.老是要手动删除日志文件,为避免此类问题发生,编写一个Linux日志定时清理的脚本,一劳永逸. 1.shell脚 ...

  10. 使用 dd 命令进行硬盘 I/O 性能检测

    使用 dd 命令进行硬盘 I/O 性能检测 作者: Vivek Gite 译者: LCTT DongShuaike | 2015-08-28 07:30   评论: 1 收藏: 6 如何使用dd命令测 ...