一、简介

之前已经完成了EurekaClient的服务生产者和Feign的服务消费者模块的搭建,现在实现统一的通信约定

(1) 统一Request结构

(2) 统一Response结构

(3) 统一Error通知

二、代码

1、创建统一请求对象ServiceRequest<>实际参数就是这个泛型,使用统一的构造进行创建便于对数据进行统一的加密传输

  1. import java.util.Date;
  2.  
  3. /**
  4. * 客户端请求内容对象
  5. */
  6. public class ServiceRequest<T> {
  7.  
  8. //region 属性
  9.  
  10. /**
  11. * 请求唯一ID
  12. */
  13. private String requestID;
  14. /**
  15. * 请求时间
  16. */
  17. private Date requestTime;
  18. /**
  19. * 客户端代号
  20. */
  21. private String clientCode;
  22. /**
  23. * 请求签名
  24. */
  25. private String requestSign;
  26. /**
  27. * 请求参数
  28. */
  29. private T reqData;
  30.  
  31. public String getRequestID() {
  32. return requestID;
  33. }
  34.  
  35. public void setRequestID(String requestID) {
  36. this.requestID = requestID;
  37. }
  38.  
  39. public Date getRequestTime() {
  40. return requestTime;
  41. }
  42.  
  43. public void setRequestTime(Date requestTime) {
  44. this.requestTime = requestTime;
  45. }
  46.  
  47. public String getClientCode() {
  48. return clientCode;
  49. }
  50.  
  51. public void setClientCode(String clientCode) {
  52. this.clientCode = clientCode;
  53. }
  54.  
  55. public String getRequestSign() {
  56. return requestSign;
  57. }
  58.  
  59. public void setRequestSign(String requestSign) {
  60. this.requestSign = requestSign;
  61. }
  62.  
  63. /**
  64. * 禁止使用此方法-不能删除内部自动取值需要使用
  65. * @return
  66. */
  67. @Deprecated
  68. public T getReqData() {
  69. return reqData;
  70. }
  71.  
  72. /**
  73. * 禁止使用此方法-不能删除内部自动赋值需要使用
  74. * @param reqData
  75. */
  76. @Deprecated
  77. public void setReqData(T reqData) {
  78. this.reqData = reqData;
  79. }
  80.  
  81. //endregion
  82.  
  83. //设置类的无参构造为私有禁止外部实例化
  84. private ServiceRequest() {
  85. }
  86.  
  87. /**
  88. * 创建请求对象
  89. * @param data
  90. */
  91. public ServiceRequest(T data) {
  92. //后期从此处增加加解密代码...
  93. this.reqData = data;
  94. }
  95.  
  96. /**
  97. * 获取请求参数
  98. * @param req
  99. * @param <T>
  100. * @return
  101. */
  102. public static <T> T getRequestData(ServiceRequest<T> req) {
  103. //后期从此处增加加解密代码...
  104. T obj = req.getReqData();
  105. return obj;
  106. }
  107. }

2、创建统一响应对象ServiceResponse<>实际响应就是这个泛型,使用统一的取值便于有需求时对响应数据进行统一的解密

  1. import com.google.common.base.Strings;
  2. import java.util.Date;
  3.  
  4. /**
  5. * 服务端响应结果对象
  6. */
  7. public class ServiceResponse<T> {
  8.  
  9. //region 属性
  10.  
  11. /**
  12. * 请求唯一ID
  13. */
  14. private String requestID;
  15. /**
  16. * 响应代号
  17. * <p>
  18. * 000000 - 正确
  19. */
  20. private ServiceCodeMsgEnum resCodeMsg;
  21. /**
  22. * 响应时间
  23. */
  24. private Date resTime;
  25. /**
  26. * 响应结果
  27. */
  28. private T resData;
  29.  
  30. public String getRequestID() {
  31. return requestID;
  32. }
  33.  
  34. public void setRequestID(String requestID) {
  35. this.requestID = requestID;
  36. }
  37.  
  38. public ServiceCodeMsgEnum getResCodeMsg() {
  39. return resCodeMsg;
  40. }
  41.  
  42. public void setResCodeMsg(ServiceCodeMsgEnum resCodeMsg) {
  43. this.resCodeMsg = resCodeMsg;
  44. }
  45.  
  46. public Date getResTime() {
  47. return resTime;
  48. }
  49.  
  50. public void setResTime(Date resTime) {
  51. this.resTime = resTime;
  52. }
  53.  
  54. /**
  55. * 禁止使用此方法-不能删除内部取值需要使用
  56. *
  57. * @return
  58. */
  59. @Deprecated
  60. public T getResData() {
  61. return resData;
  62. }
  63.  
  64. /**
  65. * 禁止使用此方法-不能删除内部赋值需要使用
  66. *
  67. * @param resData
  68. */
  69. @Deprecated
  70. public void setResData(T resData) {
  71. this.resData = resData;
  72. }
  73.  
  74. //endregion
  75.  
  76. //设置类的无参构造为私有禁止外部实例化,只能通过下方静态方法创建
  77. private ServiceResponse() {
  78. }
  79.  
  80. /**
  81. * 创建执行正确响应对象
  82. * @param data
  83. */
  84. public ServiceResponse(T data) {
  85. this.resCodeMsg = ServiceCodeMsgEnum.Success;
  86. this.resData = data;
  87. }
  88.  
  89. /**
  90. * 创建执行错误响应对象
  91. * @param codeMsg
  92. */
  93. public ServiceResponse(ServiceCodeMsgEnum codeMsg) {
  94. this.resCodeMsg = codeMsg;
  95. this.resData = null;
  96. }
  97.  
  98. /**
  99. * 获取响应CodeMsg(外部WebApi专用)
  100. *
  101. * @param res
  102. * @param <T>
  103. * @return ServiceCodeMsgEnum.Success为正确
  104. */
  105. private static <T> ServiceCodeMsgEnum getResponseCodeMsg(ServiceResponse<T> res) {
  106. return res.getResCodeMsg();
  107. }
  108.  
  109. /**
  110. * 获取响应Msg(内部站点专用)
  111. *
  112. * @param res
  113. * @param <T>
  114. * @return null为正确
  115. */
  116. public static <T> String getResponseMsg(ServiceResponse<T> res) {
  117. return Strings.emptyToNull(res.getResCodeMsg().getMsg());
  118. }
  119.  
  120. /**
  121. * 获取响应参数
  122. *
  123. * @param res
  124. * @param <T>
  125. * @return
  126. */
  127. public static <T> T getResponseData(ServiceResponse<T> res) {
  128. return res.getResData();
  129. }
  130. }

3、创建统一响应结果枚举,这里可以统一控制响应CodeMsg的对应关系,使用也简单直观

  1. /**
  2. * 服务通信CodeMsg枚举
  3. */
  4. public enum ServiceCodeMsgEnum {
  5.  
  6. Success("000000", null),
  7. Error("999999", "系统异常");
  8.  
  9. //region
  10.  
  11. private String code;
  12. private String msg;
  13.  
  14. ServiceCodeMsgEnum(String code, String msg) {
  15. this.code = code;
  16. this.msg = msg;
  17. }
  18.  
  19. public String getCode() {
  20. return code;
  21. }
  22.  
  23. public void setCode(String code) {
  24. this.code = code;
  25. }
  26.  
  27. public String getMsg() {
  28. return msg;
  29. }
  30.  
  31. public void setMsg(String msg) {
  32. this.msg = msg;
  33. }
  34.  
  35. //endregion
  36. }

4、服务生产者这边,统一入参和返回值都是ServiceRequest和ServiceResponse,又可以根据泛型来识别到底是什么对象

  1. import com.google.gson.Gson;
  2. import com.ysl.ts.common.serviceModel.ServiceCodeMsgEnum;
  3. import com.ysl.ts.common.serviceModel.ServiceRequest;
  4. import com.ysl.ts.common.serviceModel.ServiceResponse;
  5. import com.ysl.ts.core.model.base.ts_base.SysUserModel;
  6. import com.ysl.ts.core.service.base.service.SysUserService;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.stereotype.Controller;
  9. import org.springframework.web.bind.annotation.RequestBody;
  10. import org.springframework.web.bind.annotation.RequestMapping;
  11. import org.springframework.web.bind.annotation.ResponseBody;
  12.  
  13. import java.util.List;
  14. import java.util.Map;
  15.  
  16. @Controller
  17. @RequestMapping("/api/sysUser")
  18. public class SysUserController extends BaseController {
  19. @Autowired
  20. SysUserService service;
  21.  
  22. @ResponseBody
  23. @RequestMapping("/save")
  24. public ServiceResponse<Integer> save(@RequestBody ServiceRequest<SysUserModel> req) {
  25. try {
  26. //使用统一的方法获取请求Data
  27. SysUserModel agent = ServiceRequest.getRequestData(req);
  28. //调用Service
  29. int result = service.save(agent);
  30. //响应-成功
  31. return new ServiceResponse<>(result);
  32. } catch (Exception e) {
  33. //响应-错误
  34. return new ServiceResponse<>(ServiceCodeMsgEnum.Error);
  35. }
  36. }
  37.  
  38. @ResponseBody
  39. @RequestMapping("/delete")
  40. public ServiceResponse<Integer> delete(@RequestBody ServiceRequest<Integer> req) {
  41. try {
  42. //获取请求Data
  43. int id = ServiceRequest.getRequestData(req);
  44. //调用Service
  45. int result = service.delete(id);
  46. //响应-成功
  47. return new ServiceResponse<>(result);
  48. } catch (Exception e) {
  49. //响应-错误
  50. return new ServiceResponse<>(ServiceCodeMsgEnum.Error);
  51. }
  52. }
  53.  
  54. @ResponseBody
  55. @RequestMapping("/get")
  56. public ServiceResponse<SysUserModel> get(@RequestBody ServiceRequest<Integer> req) {
  57. try {
  58. //获取请求Data
  59. int id = ServiceRequest.getRequestData(req);
  60. //调用Service
  61. SysUserModel result = service.get(id);
  62. //响应-成功
  63. return new ServiceResponse<>(result);
  64. } catch (Exception e) {
  65. //响应-错误
  66. return new ServiceResponse<>(ServiceCodeMsgEnum.Error);
  67. }
  68. }
  69.  
  70. @ResponseBody
  71. @RequestMapping("/list")
  72. public ServiceResponse<List<SysUserModel>> list(@RequestBody ServiceRequest<String> req) {
  73. try {
  74. //获取请求Data
  75. String search = ServiceRequest.getRequestData(req);
  76. //调用Service
  77. List<SysUserModel> result = service.list();
  78. //响应-成功
  79. return new ServiceResponse<>(result);
  80. } catch (Exception e) {
  81. //响应-错误
  82. return new ServiceResponse<>(ServiceCodeMsgEnum.Error);
  83. }
  84. }
  85. }

5、服务消费者这边,使用了Feign所以需要一个接口来实现调用,我们直接传入ServiceRequest<>来做统一的请求对象,返回ServiceResponse<>来做统一的响应对象

  1. import com.ysl.ts.common.serviceModel.ServiceRequest;
  2. import com.ysl.ts.common.serviceModel.ServiceResponse;
  3. import com.ysl.ts.core.model.base.ts_base.SysUserModel;
  4. import org.springframework.cloud.openfeign.FeignClient;
  5. import org.springframework.stereotype.Service;
  6. import org.springframework.web.bind.annotation.RequestBody;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8.  
  9. import java.util.List;
  10.  
  11. @Service
  12. @FeignClient("YSL-TS-Core-Service-Base")//服务生产者名称
  13. @RequestMapping("/api/sysUser")//服务路由
  14. public interface SysUserService {
  15.  
  16. @RequestMapping("/save")
  17. ServiceResponse<Integer> save(@RequestBody ServiceRequest<SysUserModel> req);
  18.  
  19. @RequestMapping("/delete")
  20. ServiceResponse<Integer> delete(@RequestBody ServiceRequest<Integer> req);
  21.  
  22. @RequestMapping("/get")
  23. ServiceResponse<SysUserModel> get(@RequestBody ServiceRequest<Integer> req);
  24.  
  25. @RequestMapping("/list")
  26. ServiceResponse<List<SysUserModel>> list(@RequestBody ServiceRequest<String> req);
  27. }

6、获得基础数据实体后,在页面展现之前可能有些字段需要进行翻译,比如状态1:启用,0:禁用等等,这部分建立一个ModelEx类继承Model类,把其中需要翻译的字段写在ModelEx中,

用以下转换类对实体值进行拷贝,然后页面接收这个ModelEx对象,这样默认可以使用父类中的属性,如果要显示翻译的就用子类中的属性即可

  1. import java.util.ArrayList;
  2. import java.util.List;
  3.  
  4. /**
  5. * Model 转换类
  6. *
  7. * @param <TModel> Model类型对象
  8. * @param <TModelEx> ModelEx类型对象*/
  9. public abstract class AbstractModelConvertor<TModel, TModelEx extends TModel> {
  10.  
  11. /**
  12. * 转换
  13. *
  14. * @param model Model类型对象
  15. * @param modelEx ModelEx类型对象
  16. * @return
  17. */
  18. public TModelEx convert(TModel model, Class<TModelEx> modelEx) {
  19. TModelEx ex = new DeepClone().clone(model, modelEx);
  20. convertFields(ex);//填充翻译字段,需要子类重写
  21. return ex;
  22. }
  23.  
  24. /**
  25. * 列表转换
  26. *
  27. * @param modelList Model类型对象列表
  28. * @param modelEx ModelEx类型对象
  29. * @return
  30. */
  31. public List<TModelEx> convert(List<TModel> modelList, Class<TModelEx> modelEx) {
  32. List<TModelEx> list = new ArrayList<>();
  33.  
  34. for (TModel tModel : modelList) {
  35. list.add(convert(tModel, modelEx));
  36. }
  37.  
  38. return list;
  39. }
  40.  
  41. /**
  42. * 字段转换接口
  43. *
  44. * @param modelEx
  45. */
  46. protected abstract void convertFields(TModelEx modelEx);
  47. }

实际上就是使用Gson对实体做了一次序列化很简单

  1. import com.google.gson.Gson;
  2.  
  3. /**
  4. * 深入拷贝
  5. */
  6. public class DeepClone {
  7.  
  8. private Gson gson = new Gson();
  9.  
  10. /**
  11. * 深拷贝
  12. *
  13. * @param t 源数据
  14. * @param clazz 目标类
  15. * @param <T> 源数据类型
  16. * @param <K> 目标类型
  17. * @return
  18. */
  19. public <T, K> K clone(T t, Class<K> clazz) {
  20. return gson.fromJson(gson.toJson(t), clazz);
  21. }
  22. }

7、每一个实体都继承抽象基类,这样就可以直接使用转换方法了

  1. import com.ysl.ts.common.AbstractModelConvertor;
  2. import com.ysl.ts.core.model.base.ts_base.SysUserModel;
  3. import com.ysl.ts.core.model.base.ts_base.ex.SysUserModelEx;
  4.  
  5. public class SysUserConvertor extends AbstractModelConvertor<SysUserModel, SysUserModelEx> {
  6. /**
  7. * 填充待翻译字段
  8. */
  9. @Override
  10. protected void convertFields(SysUserModelEx sysUserModelEx) {
  11.  
  12. }
  13. }

8、下面就是页面Controller的Action调用了

  1. import com.ysl.ts.common.serviceModel.ServiceRequest;
  2. import com.ysl.ts.common.serviceModel.ServiceResponse;
  3. import com.ysl.ts.core.model.base.ts_base.SysUserModel;
  4. import com.ysl.ts.core.model.base.ts_base.ex.SysUserModelEx;
  5. import com.ysl.ts.web.base.modelConvertors.ts_base.SysUserConvertor;
  6. import com.ysl.ts.web.base.service.SysUserService;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.stereotype.Component;
  9. import org.springframework.stereotype.Controller;
  10. import org.springframework.ui.Model;
  11. import org.springframework.web.bind.annotation.RequestMapping;
  12. import org.springframework.web.bind.annotation.ResponseBody;
  13.  
  14. import java.util.ArrayList;
  15. import java.util.List;
  16.  
  17. @Controller
  18. @Component("AdminSysUser")
  19. @RequestMapping("/sysUser")
  20. public class SysUserController extends BaseController {
  21. //自动注入Feign接口对象
  22. @Autowired
  23. SysUserService service;
  24.  
  25. @RequestMapping("/save")
  26. public boolean save(SysUserModel agent) {
  27. boolean result = false;
  28. //创建ServiceRequest
  29. ServiceRequest<SysUserModel> req = new ServiceRequest<>(agent);
  30. //调用Service并获得ServiceResponse
  31. ServiceResponse<Integer> res = service.save(req);
  32. //解析获得Code
  33. String msg = ServiceResponse.getResponseMsg(res);
  34. //NULL代表响应正常
  35. if (null == msg)
  36. {
  37. //解析获得T类型
  38. result = ServiceResponse.getResponseData(res) > 0;
  39. }
  40. return result;
  41. }
  42.  
  43. @RequestMapping("/delete")
  44. public boolean delete(int id){
  45. boolean result = false;
  46. //创建ServiceRequest
  47. ServiceRequest<Integer> req = new ServiceRequest<>(id);
  48. //调用Service并获得ServiceResponse
  49. ServiceResponse<Integer> res = service.delete(req);
  50. //解析获得Code
  51. String msg = ServiceResponse.getResponseMsg(res);
  52. //NULL代表响应正常
  53. if (null == msg)
  54. {
  55. //解析获得T类型
  56. result = ServiceResponse.getResponseData(res) > 0;
  57. }
  58. return result;
  59. }
  60.  
  61. @ResponseBody
  62. @RequestMapping("/get")
  63. public SysUserModelEx get(Model model, int id) {
  64. SysUserModelEx result = new SysUserModelEx();
  65. //创建ServiceRequest
  66. ServiceRequest<Integer> req = new ServiceRequest<>(id);
  67. //调用Service并获得ServiceResponse
  68. ServiceResponse<SysUserModel> res = service.get(req);
  69. //解析获得Code
  70. String msg = ServiceResponse.getResponseMsg(res);
  71. //NULL代表响应正常
  72. if (null == msg)
  73. {
  74. //解析获得T类型
  75. SysUserModel tmp = ServiceResponse.getResponseData(res);
  76. //翻译所需字段
  77. result = new SysUserConvertor().convert(tmp, SysUserModelEx.class);
  78. }
  79. return result;
  80. //model.addAttribute("model", result);
  81. //return "/hotel/get";
  82. }
  83.  
  84. //直接返回json不写页面了
  85. @ResponseBody
  86. @RequestMapping("/list")
  87. public List<SysUserModelEx> list(String search) {
  88. List<SysUserModelEx> result = new ArrayList<>();
  89. //创建ServiceRequest
  90. ServiceRequest<String> req = new ServiceRequest<>(search);
  91. //调用Service并获得ServiceResponse
  92. ServiceResponse<List<SysUserModel>> res = service.list(req);
  93. //解析获得Code
  94. String msg = ServiceResponse.getResponseMsg(res);
  95. //NULL代表响应正常
  96. if (null == msg)
  97. {
  98. //解析获得T类型
  99. List<SysUserModel> tmp = ServiceResponse.getResponseData(res);
  100. //翻译所需字段
  101. result = new SysUserConvertor().convert(tmp, SysUserModelEx.class);
  102. }
  103. return result;
  104. }
  105. }

111

IDEA项目搭建十三——服务消费端与生产端通信实现的更多相关文章

  1. 为 rails 本地项目搭建 elasticsearch 服务

    首先安装 elasticsearch 服务 OSX 系统 brew install elasticsearch brew services start elasticsearch 测试服务是否启动浏览 ...

  2. vue.js+koa2项目实战(四)搭建koa2服务端

    搭建koa2服务端 安装两个版本的koa 一.版本安装 1.安装 koa1 npm install koa -g 注:必须安装到全局 2.安装 koa2 npm install koa@2 -g 二. ...

  3. Centos6.9 搭建rsync服务端与客户端 案例:全网备份项目

    rsync的企业工作场景说明 1)定时备份 1.1生产场景集群架构服务器备份方案项目 借助cron+rsync把所有客户服务器数据同步到备份服务器 2)实时复制 本地数据传输模式(local-only ...

  4. SpringCloud系列三:SpringSecurity 安全访问(配置安全验证、服务消费端处理、无状态 Session 配置、定义公共安全配置程序类)

    1.概念:SpringSecurity 安全访问 2.具体内容 所有的 Rest 服务最终都是暴露在公网上的,也就是说如果你的 Rest 服务属于一些你自己公司的私人业务,这样的结果会直接 导致你信息 ...

  5. Dubbo学习笔记4:服务消费端泛化调用与异步调用

    本文借用dubbo.learn的Dubbo API方式来解释原理. 服务消费端泛化调用 前面我们讲解到,基于Spring和基于Dubbo API方式搭建简单的分布式系统时,服务消费端引入了一个SDK二 ...

  6. day97:MoFang:移动端APP开发准备&移动端项目搭建&APICloud前端框架

    目录 1.移动端开发相关概念 1.APP类型 2.移动端屏幕介绍 3.移动端自适配方案 4.元信息(meta) 2.APP开发准备 1.注册APPCLoud账号 2.下载APP开发编辑器 3.下载AP ...

  7. .Net Core 3.1浏览器后端服务(一) Web API项目搭建

    一.前言 基于CefSharp开发的浏览器项目已有一段时间,考虑到后期数据维护需要Server端来管理,故开启新篇章搭建浏览器后端服务.该项目前期以梳理服务端知识为主,后期将配合CefSharp浏览器 ...

  8. contos7搭建syslog服务端与客户端

    搭建中心服务端1,编辑文件/etc/rsyslog.conf,找到以下内容,将前面的#注释符合去除#$ModLoad imtcp#$InputTCPServerRun 514 2,在/etc/rsys ...

  9. 《用OpenResty搭建高性能服务端》笔记

    概要 <用OpenResty搭建高性能服务端>是OpenResty系列课程中的入门课程,主讲人:温铭老师.课程分为10个章节,侧重于OpenResty的基本概念和主要特点的介绍,包括它的指 ...

随机推荐

  1. 写给深圳首期Python自动化开发周未班的信

    你是否做了正确的决定? 深圳首期周未班的同学们大家好,我是Alex, 老男孩教育的联合创始人,Python项目的发起人,51CTO学院连续2届最受学员喜爱的讲师,中国最早一批使用Python的程序员, ...

  2. python读取并写入csv文件

    在ubuntu下,新建.csv文件的方法是使用LibreOffice来创建一个数据表,然后我们把表格存储为.csv的格式: “Save as”菜单把我们的表格存为一个CSV的文件格式:命名为csvDa ...

  3. AI - 参考消息(References)

    01 - Machine learning infographic 图片解读机器学习的基本概念.五大流派与九种常见算法 EN:http://usblogs.pwc.com/emerging-techn ...

  4. pycharm中配置启动Django项目

    1.先打开mange.py,然后再运行,会提示一堆东西,表示没有配置参数.在pycharm中点击edit configurations 编辑配置参数. 2.点开之后弹出如下对话框,在scrip par ...

  5. python通过手机抓取微信公众号

    使用 Fiddler 抓包分析公众号 打开微信随便选择一个公众号,查看公众号的所有历史文章列表 在 Fiddler 上已经能看到有请求进来了,说明公众号的文章走的都是HTTPS协议,这些请求就是微信客 ...

  6. linux mint 安装 opencv2.4

    Download opencv https://github.com/opencv/opencv/tree/2.4 安装必要的依赖 sudo apt-get install build-essenti ...

  7. git push 到github时,报错:ERROR: Permission to xxx.git denied to user

    之前我电脑的本地git已经登录了一个github账号,今天想换另外一个新的github账户来提交项目,相当于同一台电脑使用两个github账户. 于是我先修改用户名和邮箱. git config -- ...

  8. 基于Github&Hexo的个人博客搭建过程

    大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...

  9. for循环输出树木的形状【java】

    使用for循环语句输出以下“树木”效果: * *** ***** ******* ********* * * * * * 代码: /* * *** ***** ******* ********* * ...

  10. 【原创】Python第二章——行与缩进

    Python的基本组成——逻辑行和缩进 a="我是一个物理行" a="""我是一个逻辑行 因为我一条语句便跨越了2个物理行""&q ...