其实严格来讲,ServerResponse应该归类到common包中。可是我实在太喜欢这玩意儿了。并且用得也很是频繁,因此忍不住推荐一下。前端
借此机会,申明一点,这个系列的类并非都是我原创的,都是我从各个项目中看到的,感受很是赞,一点点攒起来的。固然后面也有我本身写的一些工具。重要的是学习,从中学习到知识,就算脱离了这些工具,咱们也能够本身写一个。java
这个场景我真的以为只要写过接口的,都须要这个。web
其实,在刚刚接触代码的时候,看到大佬接口返回的JSON。JSON里面除了必要的data外,还有各类状态码,状态说明什么的,感受很厉害。后来渐渐明白了,这个东西是必须的,你不写试试,看与你交互的大佬会不会把你拍成肉饼。spring
后端:呀,前端发来的这个请求,数据库没有对应数据啊。返回一个null吧。数据库
前端:大哥,你返回给我一个null,是否是接口有问题啊?后端
后端:那是你请求的数据在数据库中没有。服务器
前端:哦。那我知道了。微信
后端:呀,前端发来的这个请求,参数不对啊(可能必要参数为空什么的)。我要返回null。架构
前端:大哥,你给我返回个null,是数据库没有对应数据嘛?可是这个条件应该有数据啊。app
后端:不是的,你请求的参数有问题啊。
前端:大哥,那你却是给我要给回馈啊。不然,我还觉得是你接口没数据呢。
后端:好的吧。让我想一想。
后端:嘿,兄弟。我想到了一个好办法,我写了一个ResultVo,它是这样的……%¥&¥……。
前端:好的。我了解了。
后端:呀,前端发来的这个请求,没有足够的权限啊。我要返回data=null&code=10。而后在常量表中设置一下。
前端:我刚刚无心间发现,你的code又增长了10,什么意思?
后端:啊。忘了告诉你了。code=10表示权限不足。
前端:那我须要就这个状况,给用户提供专门的说明呀。
后端:这样效率过低了。并且之后可能会有更复杂多变的状况。我得想一想办法。
后端:嘿,兄弟。我将原来的ResultVo进行了升级,它是这样的&……%&%&……。
前端:这挺不错的,之后不少地方,我能够直接显示msg就好了。可是,如今有一个问题,如今的code太多了。我每次进行处理时都要遍历判断,而我经常只须要判断这个响应是否成功了。
后端:这样啊。我还得再改进一下。
后端:请教大佬后,我获得了很是棒的解决方案。而且,我根据本身的业务状况,进行细微的调整,这下就没什么问题了。
前端&后端:咱们感觉到了效率的显著提高,以及最为重要的代码规范(契约)。
ServerResponse就是用来统一服务器接口调用的响应
package tech.jarry.learning; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; import org.codehaus.jackson.annotate.JsonIgnore; import org.codehaus.jackson.map.annotate.JsonSerialize; import java.io.Serializable; /** * @Author: jarry */ // 确保序列化JSON时,若是是null对象,其key也会消失。 @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) // 生成无参构造,确保在RPC调用时,不会出现反序列失败 @NoArgsConstructor public class ServerResponse<T> implements Serializable { private int status; private String msg; private T data; private ServerResponse(int status) { this.status = status; } private ServerResponse(int status, String msg) { this.status = status; this.msg = msg; } // 这里存在一个问题,若是构造函数传入的参数列表为(int,String),那么是调用上面的(int,String),仍是这里的(int,T),毕竟T做为泛型是能够表示String的 // 答案是调用上面的(int,String)(能够理解为上面的是专业的)。那么有时候data做为T类型传入的就是String啊,岂不是就出问题了。这里会在下方对应的public函数处理 private ServerResponse(int status, T data) { this.status = status; this.data = data; } private ServerResponse(int status, String msg, T data) { this.status = status; this.msg = msg; this.data = data; } // 使之不在JSON序列化结果当中 @JsonIgnore // 能够快速进行成功与否的条件判断 public boolean isSuccess() { return this.status == ResponseCode.SUCCESS.getCode(); } @JsonIgnore // 能够快速进行成功与否的条件判断,判断false时,不用加!。囧 public boolean isFail() { return this.status != ResponseCode.SUCCESS.getCode(); } public int getStatus() { return status; } public String getMsg() { return msg; } public T getData() { return data; } // 快速构建返回结果 // 成功时的调用 public static <T> ServerResponse<T> createBySuccess() { return new ServerResponse<T>(ResponseCode.SUCCESS.getCode()); } public static <T> ServerResponse<T> createBySuccessMessage(String msg) { return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(), msg); } public static <T> ServerResponse<T> createBySuccess(T data) { return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(), data); } public static <T> ServerResponse<T> createBySuccess(String msg, T data) { return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(), msg, data); } // 失败时的调用 public static <T> ServerResponse<T> createByError() { return new ServerResponse<T>(ResponseCode.ERROR.getCode(), ResponseCode.ERROR.getDesc()); } public static <T> ServerResponse<T> createByErrorMessage(String errorMessage) { return new ServerResponse<T>(ResponseCode.ERROR.getCode(), errorMessage); } public static <T> ServerResponse<T> createByErrorCodeMessage(int errorCode, String errorMessage) { return new ServerResponse<T>(errorCode, errorMessage); } }
lombok(绝对的效率工具,值得推荐)
package tech.jarry.learning.terminal.client; import com.renewable.terminal.terminal.common.ServerResponse; import com.renewable.terminal.terminal.entity.Terminal; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseBody; import java.util.List; /** * @Description:经过feign,对外提供termina服务的调用接口 * @Author: jarry */ @FeignClient(name = "terminal", fallback = TerminalClient.TerminalClientFallback.class) public interface TerminalClient { @PostMapping("/terminal/update_from_center.do") ServerResponse updateTerminalFromCenter(@RequestBody Terminal terminal); @PostMapping("/terminal/update.do") ServerResponse updateTerminal(@RequestBody Terminal terminal); @GetMapping("/terminal/refresh.do") ServerResponse refreshTerminal(); @Component public static class TerminalClientFallback implements TerminalClient { @Override public ServerResponse updateTerminalFromCenter(@RequestBody Terminal terminal){ return ServerResponse.createByErrorMessage("Busy service about Terminal/updateTerminalFromCenter()."); } @Override public ServerResponse updateTerminal(Terminal terminal) { return ServerResponse.createByErrorMessage("Busy service about Terminal/updateTerminal()."); } @Override public ServerResponse refreshTerminal(){ return ServerResponse.createByErrorMessage("Busy service about Terminal/refreshTerminal()."); } } }
package tech.jarry.learning.terminal.controller; import com.renewable.terminal.message.client.TerminalMessageClient; import com.renewable.terminal.terminal.common.ServerResponse; import com.renewable.terminal.terminal.entity.Terminal; import com.renewable.terminal.terminal.service.ITerminalService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; /** * <p> * 前端控制器 * </p> * * @author jarry * @since 2019-07-22 */ @RestController @RequestMapping("/terminal/") public class TerminalController { @Autowired private ITerminalService iTerminalService; @GetMapping("get_terminal.do") @ResponseBody public ServerResponse getTerminal(){ return iTerminalService.getTerminal(); } @PostMapping("update.do") @ResponseBody public ServerResponse updateTerminal(@RequestBody Terminal terminal){ boolean result = iTerminalService.updateById(terminal); iTerminalService.refresh(); if (!result){ return ServerResponse.createByErrorMessage("fail !"); } return ServerResponse.createBySuccess(terminal); } @PostMapping("update_from_center.do") @ResponseBody public ServerResponse updateTerminalFromCenter(@RequestBody Terminal terminal){ boolean result = iTerminalService.updateById(terminal); if (!result){ return ServerResponse.createByErrorMessage("fail !"); } return ServerResponse.createBySuccessMessage("success"); } @GetMapping("refresh.do") @ResponseBody public ServerResponse refreshTerminal(){ return iTerminalService.refresh(); } }
在使用ServerResponse的过程当中,曾经遇到一个问题。
那就是ServerResponse在SpringCloud架构中的Feign中的RPC调用中,没法进行反序列化。
找到的解释是,缺少无参构造器(若是类中具备任意构造器,JVM就不会提供默认的无参构造器)。
因此在类的开头增长了@NoArgsConstructor,使得类具有无参构造器,问题解决。
做为服务器响应的统一数据格式,网上有不少的写法。这个ServerResponse也不必定是最好的。即便是最好的,也不必定是最适合你的。
每每咱们在项目中须要一些工具实现一些特定功能,在实现功能以后,都或多或少会对现有的工具作一些调整,使得其更适合本身现有项目。
因此说,最好的不必定最适合。咱们须要根据现有的状况,进行调整,重构,乃至自研。
偷偷地推荐一下本身的我的博客。目前这个博客还处于测试阶段。还有不少的调整,以后还会与我本身微信公众号绑定,目测须要到今年下半年,才能所有完成。囧。有什么意见也能够提一提。
另外,因为还在测试阶段,因此若是哪天看不了,实属正常。囧