IDEA项目搭建十三——服务消费端与生产端通信实现
一、简介
之前已经完成了EurekaClient的服务生产者和Feign的服务消费者模块的搭建,现在实现统一的通信约定
(1) 统一Request结构
(2) 统一Response结构
(3) 统一Error通知
二、代码
1、创建统一请求对象ServiceRequest<>实际参数就是这个泛型,使用统一的构造进行创建便于对数据进行统一的加密传输
- import java.util.Date;
- /**
- * 客户端请求内容对象
- */
- public class ServiceRequest<T> {
- //region 属性
- /**
- * 请求唯一ID
- */
- private String requestID;
- /**
- * 请求时间
- */
- private Date requestTime;
- /**
- * 客户端代号
- */
- private String clientCode;
- /**
- * 请求签名
- */
- private String requestSign;
- /**
- * 请求参数
- */
- private T reqData;
- public String getRequestID() {
- return requestID;
- }
- public void setRequestID(String requestID) {
- this.requestID = requestID;
- }
- public Date getRequestTime() {
- return requestTime;
- }
- public void setRequestTime(Date requestTime) {
- this.requestTime = requestTime;
- }
- public String getClientCode() {
- return clientCode;
- }
- public void setClientCode(String clientCode) {
- this.clientCode = clientCode;
- }
- public String getRequestSign() {
- return requestSign;
- }
- public void setRequestSign(String requestSign) {
- this.requestSign = requestSign;
- }
- /**
- * 禁止使用此方法-不能删除内部自动取值需要使用
- * @return
- */
- @Deprecated
- public T getReqData() {
- return reqData;
- }
- /**
- * 禁止使用此方法-不能删除内部自动赋值需要使用
- * @param reqData
- */
- @Deprecated
- public void setReqData(T reqData) {
- this.reqData = reqData;
- }
- //endregion
- //设置类的无参构造为私有禁止外部实例化
- private ServiceRequest() {
- }
- /**
- * 创建请求对象
- * @param data
- */
- public ServiceRequest(T data) {
- //后期从此处增加加解密代码...
- this.reqData = data;
- }
- /**
- * 获取请求参数
- * @param req
- * @param <T>
- * @return
- */
- public static <T> T getRequestData(ServiceRequest<T> req) {
- //后期从此处增加加解密代码...
- T obj = req.getReqData();
- return obj;
- }
- }
2、创建统一响应对象ServiceResponse<>实际响应就是这个泛型,使用统一的取值便于有需求时对响应数据进行统一的解密
- import com.google.common.base.Strings;
- import java.util.Date;
- /**
- * 服务端响应结果对象
- */
- public class ServiceResponse<T> {
- //region 属性
- /**
- * 请求唯一ID
- */
- private String requestID;
- /**
- * 响应代号
- * <p>
- * 000000 - 正确
- */
- private ServiceCodeMsgEnum resCodeMsg;
- /**
- * 响应时间
- */
- private Date resTime;
- /**
- * 响应结果
- */
- private T resData;
- public String getRequestID() {
- return requestID;
- }
- public void setRequestID(String requestID) {
- this.requestID = requestID;
- }
- public ServiceCodeMsgEnum getResCodeMsg() {
- return resCodeMsg;
- }
- public void setResCodeMsg(ServiceCodeMsgEnum resCodeMsg) {
- this.resCodeMsg = resCodeMsg;
- }
- public Date getResTime() {
- return resTime;
- }
- public void setResTime(Date resTime) {
- this.resTime = resTime;
- }
- /**
- * 禁止使用此方法-不能删除内部取值需要使用
- *
- * @return
- */
- @Deprecated
- public T getResData() {
- return resData;
- }
- /**
- * 禁止使用此方法-不能删除内部赋值需要使用
- *
- * @param resData
- */
- @Deprecated
- public void setResData(T resData) {
- this.resData = resData;
- }
- //endregion
- //设置类的无参构造为私有禁止外部实例化,只能通过下方静态方法创建
- private ServiceResponse() {
- }
- /**
- * 创建执行正确响应对象
- * @param data
- */
- public ServiceResponse(T data) {
- this.resCodeMsg = ServiceCodeMsgEnum.Success;
- this.resData = data;
- }
- /**
- * 创建执行错误响应对象
- * @param codeMsg
- */
- public ServiceResponse(ServiceCodeMsgEnum codeMsg) {
- this.resCodeMsg = codeMsg;
- this.resData = null;
- }
- /**
- * 获取响应CodeMsg(外部WebApi专用)
- *
- * @param res
- * @param <T>
- * @return ServiceCodeMsgEnum.Success为正确
- */
- private static <T> ServiceCodeMsgEnum getResponseCodeMsg(ServiceResponse<T> res) {
- return res.getResCodeMsg();
- }
- /**
- * 获取响应Msg(内部站点专用)
- *
- * @param res
- * @param <T>
- * @return null为正确
- */
- public static <T> String getResponseMsg(ServiceResponse<T> res) {
- return Strings.emptyToNull(res.getResCodeMsg().getMsg());
- }
- /**
- * 获取响应参数
- *
- * @param res
- * @param <T>
- * @return
- */
- public static <T> T getResponseData(ServiceResponse<T> res) {
- return res.getResData();
- }
- }
3、创建统一响应结果枚举,这里可以统一控制响应CodeMsg的对应关系,使用也简单直观
- /**
- * 服务通信CodeMsg枚举
- */
- public enum ServiceCodeMsgEnum {
- Success("000000", null),
- Error("999999", "系统异常");
- //region
- private String code;
- private String msg;
- ServiceCodeMsgEnum(String code, String msg) {
- this.code = code;
- this.msg = msg;
- }
- public String getCode() {
- return code;
- }
- public void setCode(String code) {
- this.code = code;
- }
- public String getMsg() {
- return msg;
- }
- public void setMsg(String msg) {
- this.msg = msg;
- }
- //endregion
- }
4、服务生产者这边,统一入参和返回值都是ServiceRequest和ServiceResponse,又可以根据泛型来识别到底是什么对象
- import com.google.gson.Gson;
- import com.ysl.ts.common.serviceModel.ServiceCodeMsgEnum;
- import com.ysl.ts.common.serviceModel.ServiceRequest;
- import com.ysl.ts.common.serviceModel.ServiceResponse;
- import com.ysl.ts.core.model.base.ts_base.SysUserModel;
- import com.ysl.ts.core.service.base.service.SysUserService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.RequestBody;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.ResponseBody;
- import java.util.List;
- import java.util.Map;
- @Controller
- @RequestMapping("/api/sysUser")
- public class SysUserController extends BaseController {
- @Autowired
- SysUserService service;
- @ResponseBody
- @RequestMapping("/save")
- public ServiceResponse<Integer> save(@RequestBody ServiceRequest<SysUserModel> req) {
- try {
- //使用统一的方法获取请求Data
- SysUserModel agent = ServiceRequest.getRequestData(req);
- //调用Service
- int result = service.save(agent);
- //响应-成功
- return new ServiceResponse<>(result);
- } catch (Exception e) {
- //响应-错误
- return new ServiceResponse<>(ServiceCodeMsgEnum.Error);
- }
- }
- @ResponseBody
- @RequestMapping("/delete")
- public ServiceResponse<Integer> delete(@RequestBody ServiceRequest<Integer> req) {
- try {
- //获取请求Data
- int id = ServiceRequest.getRequestData(req);
- //调用Service
- int result = service.delete(id);
- //响应-成功
- return new ServiceResponse<>(result);
- } catch (Exception e) {
- //响应-错误
- return new ServiceResponse<>(ServiceCodeMsgEnum.Error);
- }
- }
- @ResponseBody
- @RequestMapping("/get")
- public ServiceResponse<SysUserModel> get(@RequestBody ServiceRequest<Integer> req) {
- try {
- //获取请求Data
- int id = ServiceRequest.getRequestData(req);
- //调用Service
- SysUserModel result = service.get(id);
- //响应-成功
- return new ServiceResponse<>(result);
- } catch (Exception e) {
- //响应-错误
- return new ServiceResponse<>(ServiceCodeMsgEnum.Error);
- }
- }
- @ResponseBody
- @RequestMapping("/list")
- public ServiceResponse<List<SysUserModel>> list(@RequestBody ServiceRequest<String> req) {
- try {
- //获取请求Data
- String search = ServiceRequest.getRequestData(req);
- //调用Service
- List<SysUserModel> result = service.list();
- //响应-成功
- return new ServiceResponse<>(result);
- } catch (Exception e) {
- //响应-错误
- return new ServiceResponse<>(ServiceCodeMsgEnum.Error);
- }
- }
- }
5、服务消费者这边,使用了Feign所以需要一个接口来实现调用,我们直接传入ServiceRequest<>来做统一的请求对象,返回ServiceResponse<>来做统一的响应对象
- import com.ysl.ts.common.serviceModel.ServiceRequest;
- import com.ysl.ts.common.serviceModel.ServiceResponse;
- import com.ysl.ts.core.model.base.ts_base.SysUserModel;
- import org.springframework.cloud.openfeign.FeignClient;
- import org.springframework.stereotype.Service;
- import org.springframework.web.bind.annotation.RequestBody;
- import org.springframework.web.bind.annotation.RequestMapping;
- import java.util.List;
- @Service
- @FeignClient("YSL-TS-Core-Service-Base")//服务生产者名称
- @RequestMapping("/api/sysUser")//服务路由
- public interface SysUserService {
- @RequestMapping("/save")
- ServiceResponse<Integer> save(@RequestBody ServiceRequest<SysUserModel> req);
- @RequestMapping("/delete")
- ServiceResponse<Integer> delete(@RequestBody ServiceRequest<Integer> req);
- @RequestMapping("/get")
- ServiceResponse<SysUserModel> get(@RequestBody ServiceRequest<Integer> req);
- @RequestMapping("/list")
- ServiceResponse<List<SysUserModel>> list(@RequestBody ServiceRequest<String> req);
- }
6、获得基础数据实体后,在页面展现之前可能有些字段需要进行翻译,比如状态1:启用,0:禁用等等,这部分建立一个ModelEx类继承Model类,把其中需要翻译的字段写在ModelEx中,
用以下转换类对实体值进行拷贝,然后页面接收这个ModelEx对象,这样默认可以使用父类中的属性,如果要显示翻译的就用子类中的属性即可
- import java.util.ArrayList;
- import java.util.List;
- /**
- * Model 转换类
- *
- * @param <TModel> Model类型对象
- * @param <TModelEx> ModelEx类型对象*/
- public abstract class AbstractModelConvertor<TModel, TModelEx extends TModel> {
- /**
- * 转换
- *
- * @param model Model类型对象
- * @param modelEx ModelEx类型对象
- * @return
- */
- public TModelEx convert(TModel model, Class<TModelEx> modelEx) {
- TModelEx ex = new DeepClone().clone(model, modelEx);
- convertFields(ex);//填充翻译字段,需要子类重写
- return ex;
- }
- /**
- * 列表转换
- *
- * @param modelList Model类型对象列表
- * @param modelEx ModelEx类型对象
- * @return
- */
- public List<TModelEx> convert(List<TModel> modelList, Class<TModelEx> modelEx) {
- List<TModelEx> list = new ArrayList<>();
- for (TModel tModel : modelList) {
- list.add(convert(tModel, modelEx));
- }
- return list;
- }
- /**
- * 字段转换接口
- *
- * @param modelEx
- */
- protected abstract void convertFields(TModelEx modelEx);
- }
实际上就是使用Gson对实体做了一次序列化很简单
- import com.google.gson.Gson;
- /**
- * 深入拷贝
- */
- public class DeepClone {
- private Gson gson = new Gson();
- /**
- * 深拷贝
- *
- * @param t 源数据
- * @param clazz 目标类
- * @param <T> 源数据类型
- * @param <K> 目标类型
- * @return
- */
- public <T, K> K clone(T t, Class<K> clazz) {
- return gson.fromJson(gson.toJson(t), clazz);
- }
- }
7、每一个实体都继承抽象基类,这样就可以直接使用转换方法了
- import com.ysl.ts.common.AbstractModelConvertor;
- import com.ysl.ts.core.model.base.ts_base.SysUserModel;
- import com.ysl.ts.core.model.base.ts_base.ex.SysUserModelEx;
- public class SysUserConvertor extends AbstractModelConvertor<SysUserModel, SysUserModelEx> {
- /**
- * 填充待翻译字段
- */
- @Override
- protected void convertFields(SysUserModelEx sysUserModelEx) {
- }
- }
8、下面就是页面Controller的Action调用了
- import com.ysl.ts.common.serviceModel.ServiceRequest;
- import com.ysl.ts.common.serviceModel.ServiceResponse;
- import com.ysl.ts.core.model.base.ts_base.SysUserModel;
- import com.ysl.ts.core.model.base.ts_base.ex.SysUserModelEx;
- import com.ysl.ts.web.base.modelConvertors.ts_base.SysUserConvertor;
- import com.ysl.ts.web.base.service.SysUserService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Component;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.ResponseBody;
- import java.util.ArrayList;
- import java.util.List;
- @Controller
- @Component("AdminSysUser")
- @RequestMapping("/sysUser")
- public class SysUserController extends BaseController {
- //自动注入Feign接口对象
- @Autowired
- SysUserService service;
- @RequestMapping("/save")
- public boolean save(SysUserModel agent) {
- boolean result = false;
- //创建ServiceRequest
- ServiceRequest<SysUserModel> req = new ServiceRequest<>(agent);
- //调用Service并获得ServiceResponse
- ServiceResponse<Integer> res = service.save(req);
- //解析获得Code
- String msg = ServiceResponse.getResponseMsg(res);
- //NULL代表响应正常
- if (null == msg)
- {
- //解析获得T类型
- result = ServiceResponse.getResponseData(res) > 0;
- }
- return result;
- }
- @RequestMapping("/delete")
- public boolean delete(int id){
- boolean result = false;
- //创建ServiceRequest
- ServiceRequest<Integer> req = new ServiceRequest<>(id);
- //调用Service并获得ServiceResponse
- ServiceResponse<Integer> res = service.delete(req);
- //解析获得Code
- String msg = ServiceResponse.getResponseMsg(res);
- //NULL代表响应正常
- if (null == msg)
- {
- //解析获得T类型
- result = ServiceResponse.getResponseData(res) > 0;
- }
- return result;
- }
- @ResponseBody
- @RequestMapping("/get")
- public SysUserModelEx get(Model model, int id) {
- SysUserModelEx result = new SysUserModelEx();
- //创建ServiceRequest
- ServiceRequest<Integer> req = new ServiceRequest<>(id);
- //调用Service并获得ServiceResponse
- ServiceResponse<SysUserModel> res = service.get(req);
- //解析获得Code
- String msg = ServiceResponse.getResponseMsg(res);
- //NULL代表响应正常
- if (null == msg)
- {
- //解析获得T类型
- SysUserModel tmp = ServiceResponse.getResponseData(res);
- //翻译所需字段
- result = new SysUserConvertor().convert(tmp, SysUserModelEx.class);
- }
- return result;
- //model.addAttribute("model", result);
- //return "/hotel/get";
- }
- //直接返回json不写页面了
- @ResponseBody
- @RequestMapping("/list")
- public List<SysUserModelEx> list(String search) {
- List<SysUserModelEx> result = new ArrayList<>();
- //创建ServiceRequest
- ServiceRequest<String> req = new ServiceRequest<>(search);
- //调用Service并获得ServiceResponse
- ServiceResponse<List<SysUserModel>> res = service.list(req);
- //解析获得Code
- String msg = ServiceResponse.getResponseMsg(res);
- //NULL代表响应正常
- if (null == msg)
- {
- //解析获得T类型
- List<SysUserModel> tmp = ServiceResponse.getResponseData(res);
- //翻译所需字段
- result = new SysUserConvertor().convert(tmp, SysUserModelEx.class);
- }
- return result;
- }
- }
111
IDEA项目搭建十三——服务消费端与生产端通信实现的更多相关文章
- 为 rails 本地项目搭建 elasticsearch 服务
首先安装 elasticsearch 服务 OSX 系统 brew install elasticsearch brew services start elasticsearch 测试服务是否启动浏览 ...
- vue.js+koa2项目实战(四)搭建koa2服务端
搭建koa2服务端 安装两个版本的koa 一.版本安装 1.安装 koa1 npm install koa -g 注:必须安装到全局 2.安装 koa2 npm install koa@2 -g 二. ...
- Centos6.9 搭建rsync服务端与客户端 案例:全网备份项目
rsync的企业工作场景说明 1)定时备份 1.1生产场景集群架构服务器备份方案项目 借助cron+rsync把所有客户服务器数据同步到备份服务器 2)实时复制 本地数据传输模式(local-only ...
- SpringCloud系列三:SpringSecurity 安全访问(配置安全验证、服务消费端处理、无状态 Session 配置、定义公共安全配置程序类)
1.概念:SpringSecurity 安全访问 2.具体内容 所有的 Rest 服务最终都是暴露在公网上的,也就是说如果你的 Rest 服务属于一些你自己公司的私人业务,这样的结果会直接 导致你信息 ...
- Dubbo学习笔记4:服务消费端泛化调用与异步调用
本文借用dubbo.learn的Dubbo API方式来解释原理. 服务消费端泛化调用 前面我们讲解到,基于Spring和基于Dubbo API方式搭建简单的分布式系统时,服务消费端引入了一个SDK二 ...
- day97:MoFang:移动端APP开发准备&移动端项目搭建&APICloud前端框架
目录 1.移动端开发相关概念 1.APP类型 2.移动端屏幕介绍 3.移动端自适配方案 4.元信息(meta) 2.APP开发准备 1.注册APPCLoud账号 2.下载APP开发编辑器 3.下载AP ...
- .Net Core 3.1浏览器后端服务(一) Web API项目搭建
一.前言 基于CefSharp开发的浏览器项目已有一段时间,考虑到后期数据维护需要Server端来管理,故开启新篇章搭建浏览器后端服务.该项目前期以梳理服务端知识为主,后期将配合CefSharp浏览器 ...
- contos7搭建syslog服务端与客户端
搭建中心服务端1,编辑文件/etc/rsyslog.conf,找到以下内容,将前面的#注释符合去除#$ModLoad imtcp#$InputTCPServerRun 514 2,在/etc/rsys ...
- 《用OpenResty搭建高性能服务端》笔记
概要 <用OpenResty搭建高性能服务端>是OpenResty系列课程中的入门课程,主讲人:温铭老师.课程分为10个章节,侧重于OpenResty的基本概念和主要特点的介绍,包括它的指 ...
随机推荐
- 写给深圳首期Python自动化开发周未班的信
你是否做了正确的决定? 深圳首期周未班的同学们大家好,我是Alex, 老男孩教育的联合创始人,Python项目的发起人,51CTO学院连续2届最受学员喜爱的讲师,中国最早一批使用Python的程序员, ...
- python读取并写入csv文件
在ubuntu下,新建.csv文件的方法是使用LibreOffice来创建一个数据表,然后我们把表格存储为.csv的格式: “Save as”菜单把我们的表格存为一个CSV的文件格式:命名为csvDa ...
- AI - 参考消息(References)
01 - Machine learning infographic 图片解读机器学习的基本概念.五大流派与九种常见算法 EN:http://usblogs.pwc.com/emerging-techn ...
- pycharm中配置启动Django项目
1.先打开mange.py,然后再运行,会提示一堆东西,表示没有配置参数.在pycharm中点击edit configurations 编辑配置参数. 2.点开之后弹出如下对话框,在scrip par ...
- python通过手机抓取微信公众号
使用 Fiddler 抓包分析公众号 打开微信随便选择一个公众号,查看公众号的所有历史文章列表 在 Fiddler 上已经能看到有请求进来了,说明公众号的文章走的都是HTTPS协议,这些请求就是微信客 ...
- linux mint 安装 opencv2.4
Download opencv https://github.com/opencv/opencv/tree/2.4 安装必要的依赖 sudo apt-get install build-essenti ...
- git push 到github时,报错:ERROR: Permission to xxx.git denied to user
之前我电脑的本地git已经登录了一个github账号,今天想换另外一个新的github账户来提交项目,相当于同一台电脑使用两个github账户. 于是我先修改用户名和邮箱. git config -- ...
- 基于Github&Hexo的个人博客搭建过程
大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...
- for循环输出树木的形状【java】
使用for循环语句输出以下“树木”效果: * *** ***** ******* ********* * * * * * 代码: /* * *** ***** ******* ********* * ...
- 【原创】Python第二章——行与缩进
Python的基本组成——逻辑行和缩进 a="我是一个物理行" a="""我是一个逻辑行 因为我一条语句便跨越了2个物理行""&q ...