在编写RESTful接口时,一个常用的实践是,我们并不直接返回前端需要的数据,而是对数据进行二次包装后再返回。
比如,一个查询用户详情的接口并不是返回:
{"name":"尤慕","age":18}
而是会返回:
{"code":,"message":"success","data":{"name":"尤慕","age":18}}
同理,一个查询用户订单数的接口不会直接返回一个数字:
而是返回:
{"code":,"message":"success","data":}
如果接口出错,则返回:
{"code":,"message":"用户不存在","data":null}
这样的一个好处是,客户端在使用数据之前,可以先根据code判断请求是否得到正确的处理。如果失败,根据code和message做相应错误反馈;成功则使用data内的数据做展示或其它操作。
那么,在SpringBoot中如何对数据进行较为优雅的封装呢?
注意,以上的接口设计实践并不限于SpringBoot,其它语言亦同。
1使用SpringBoot封装RESTful接口首先,我们需要一个数据包装类RestResult,它代表接口的返回类型:
DatapublicclassRestResultT{/***错误码。**1.code=时表示正常处理*2.code=其它值的含义,由业务方自己定义*/privateintcode;/***错误详情*/privateStringmessage;/***真实的数据*/privateTdata;}泛型参数T表示数据集可以是任何类型。
为了使用方便,我们给此类添加一些静态构造方法:
DatapublicclassRestResultT{/***调用成功时使用*/publicstaticTRestResultTsuccess(Tdata){RestResultTres=newRestResult();res.code=;res.message="success";res.data=data;returnres;}/***失败时使用*/publicstaticTRestResultTfail(intcode,Stringmessage){RestResultTres=newRestResult();res.code=code;res.message=message;returnres;}}我们以一个假想的关于Foo的服务来做使用说明:
一个关于Foo的实体:
DatapublicclassFoo{privateStringname;privateintrank;}一个关于Foo的Service:
ServicepublicclassFooService{publicFoogetFoo(){Foofoo=newFoo();foo.setName("尤慕");foo.setAge(18);returnfoo;}publicStringgetFooName(){returngetFoo().getName();}publicintgetFooAge(){returngetFoo().getAge();}}最后,一个关于Foo的Controller:
AllArgsConstructorRestControllerRequestMapping("foo/v1")publicclassFooController{privateFooServicefooService;GetMappingRestResultFoogetFoo(){returnRestResult.success(fooService.getFoo());}GetMapping("name")RestResultStringgetFooName(){returnRestResult.success(fooService.getFooName());}GetMapping("age")RestResultIntegergetFooAge(){returnRestResult.success(fooService.getFooAge());}}这些类比较普通,没什么要多做说明的。我们先介绍一个怎么在IntelliJIDEA中测试HTTP服务的方法,再讨论上面代码的问题。
怎么在IDEA中调试HTTP先在项目根目录下创建一个