谁要是再敢用Map传参,我过去就是一JIO

image


还记得上次我写过一篇关于实际项目代码分层和规划的文章《看完这篇,别人的开源项目结构应该能看懂了》, 在文尾处提到过一些注意事项,其中第一条就是:java

  • Contorller层参数传递建议不要使用HashMap,推荐使用数据模型定义

私信里居然有不少小伙伴提问说,为何不能这样作?后端

我内心暗自寻思:难道这么作的小伙伴都没有被同事捶吗?(滑稽)markdown

得嘞,今天我们就掰扯掰扯这件事,这是实际写代码时常忽略的一个问题app


是否是有人也这么写过?

我本身曾经接手过一个前人留下来的老项目,拿到代码,导入IDEA的那一刻,我哭出了声。工具

image

由于它的Controller层代码都是相似这样写的:oop

@RestController
@RequestMapping("/index")
public class IndexController {

    // 获取App首页内容
    @PostMapping("/getIndexContent")
    public ResponseWrapper getIndexContent( @RequestBody Map<String, Object> paramMap ) {

        ResponseWrapper res = new ResponseWrapper();

        // 下面开始作传参有效性的校验
        if (!paramMap.containsKey("article_id")) {
            res.setCode(500);
            res.setMsg("缺乏 article_id 信息");
            return res;
        }

        if (!paramMap.containsKey("page")) {
            res.setCode(500);
            res.setMsg("缺乏 page 信息");
            return res;
        }

        if (!paramMap.containsKey("size")) {
            res.setCode(500);
            res.setMsg("缺乏 size 信息");
            return res;
        }

        if (!paramMap.containsKey("version")) {
            res.setCode(500);
            res.setMsg("缺乏 version 信息");
            return res;
        }

        // ...... 此处省略

    }

    // ...... 此处省略

}
复制代码

别的咱先不说,竟然明目张胆地在Controller层里方法里用Map传参?!简直丧心病狂了。幸好下面还有一波传参有效性的验证,对于传递的参数,我好歹也能猜个大概,否则那真是喵了个咪了。测试

接下来,咱们就好好唠一唠:为何不要在Controller层传参时使用Map类型!spa


Map一时爽,维护爽歪歪

正好,这地方有一个咱小伙伴活生生的例子。插件

记得以前有个小伙伴提问,问过一个这样的问题,说他接手了一个别人的老项目,问了我一个相似这样的问题:3d

image

看到没!

Map传参的第一个(也是最大的一个)弊端就是:这会致使后续接手和维护的人怀疑本身的人生,由于他根本不知道代码传的啥参数,想要构造参数去调试接口只能靠脑补摸瞎、以及猜想了。

试想一下,其实咱们代码里任何一个地方的传参均可以使用Map来传,若是真的这么作了,代码中连任何数据模型类都不须要定义了,果然如此的话,这样的代码咱能看懂吗?

并且这位小伙伴接手的项目竟然还用的是LinkedHashMap参数,能够说很秀了。

image

除此以外,紧接着还会带来下面这个问题。


好用的API工具与你无缘了

我以前写过一篇文章《先后端都分离了,该搞个好用的API管理系统了!》,聊过如今市面上一些比较好用的、能极大提高先后端开发效率的API管理工具,这对于先后端开发来讲,简直是莫大的福音。

咱们就以Swagger这个API工具为例,若是Controller传参使用Map的话:

// 获取App首页内容
@ApiOperation("获取App首页内容")
@PostMapping("/getIndexContent")
public ResponseWrapper getIndexContent( @RequestBody Map<String, Object> paramMap ) {

    // ...... 此处省略

}
复制代码

API工具没法读取具体参数项目和参数类型,因此传参什么的也看不出来:

image

换言之,我若是将上面的Map传参改成自定义数据模型类IndexQueryDto来传参的话:

// 获取App首页内容
@ApiOperation("获取App首页内容(改造后)")
@PostMapping("/getIndexContent")
public ResponseWrapper getIndexContent( @RequestBody IndexQueryDto indexQueryDto ) {

    // ...... 此处省略

}
复制代码
@ApiModel(value = "App首页内容请求参数实体对象")
class IndexQueryDto {

    @ApiModelProperty(value = "文章ID号")
    @NotNull(message = "缺乏 article_id 信息")
    private Long article_id;


    @ApiModelProperty(value = "页面数")
    @NotNull(message = "缺乏 page 信息")
    private Integer page;

    @ApiModelProperty(value = "每页条目数")
    @NotNull(message = "缺乏 size 信息")
    private Integer size;

    @ApiModelProperty(value = "App版本号")
    @NotNull(message = "缺乏 version 信息")
    private String version;

    // ...... 此处省略set/get方法

}
复制代码

则相似Swagger这种API工具就很是方便地能帮助咱们管理参数了:

image

这样不论是本身调试,仍是前、后端对接口都会方便得多。


同理,除了Swagger这种API管理工具以外,像在个人前文《没用过这些IDEA插件?怪不得写代码头疼》中推荐过的一个很是好用的接口管理插件RestfulToolkit也没法识别出Map类型所盛放的具体参数:

image

可是对于数据模型的定义参数,就能很是清晰的给出参数细节,并方便地提供接口测试:

image


优秀的注解无法使用了

仍是以文章开头举例的代码来讲,无论怎么样,写这段代码的哥们仍是负责的,毕竟兢兢业业地用手工连环if()判断完成了全部参数的有效性校验:

image

但问题是,咱们真的须要这种辣眼睛的手工连环if()判断来作参数校验吗?

image

一样在前文《啥?据说你还在手写复杂的参数校验?》中也说过了,咱们其实能够经过注解来方便地规避繁杂的参数校验工做,但前提是不能使用Map类型传参,须要使用数据模型的定义,就像这样:

class IndexQueryDto {

    @NotNull(message = "缺乏 article_id 信息")
    private Long article_id;

    @NotNull(message = "缺乏 page 信息")
    private Integer page;

    @NotNull(message = "缺乏 size 信息")
    private Integer size;

    @NotNull(message = "缺乏 version 信息")
    private String version;

    // ...... 此处省略get/set方法
}
复制代码

一个NotNull注解便可搞定,它不香吗?


Map传参真的一无可取吗?

有些小伙伴表示用Map传参的好处就是能够随意扩展,后期变更灵活,想往里面塞几个参数就塞几个参数;并且也省去了各类对象定义和命名的烦恼。

image


若是非要用Map传参

若是实在不能避免用Map传参,也麻请配备完备的测试用例吧,免得让后来接手维护的人每天看着代码怀疑人生了。

经过测试用例,后来接手维护的人也能快速搞清代码间的参数传递和调用,否则真的只能靠脑补画面去调试了。


嘘...

好了,说了这么多,若是你项目的Controller层代码还在使用Map传参的话,答应我,二话别说,赶快所有偷偷去改掉,快!速度!跑步前进!

image
相关文章
相关标签/搜索