简单的网贷独立子服务搭建
1. 需求
我们公司正在进行新信贷系统的迭代升级,但是之间呢我们系统又承接了一个网贷业务接口,需要给行内小型网贷提供预放款接口等几个接口,但是信贷系统还正在开发,所以就先提供一个子模块,一个独立的online-server,对外提供简单的网贷接口使用。这里简单记录下这个简单项目的开发流程
2. 整体设计
网贷子模块,功能比较简单,是一个过度方案,主要提供了接收行内放款信息数据,调用核心,成功之后再调用行内支付系统,主要就是提供公共的esb端调用解析方案即可,当前使用的用户也进行了分库,所以也需要使用多数据源进行数据切换,这里简单记录一下实现过程
- 1.编写项目基本框架,单一controller进入,通过服务svc_no,scn_no使用策略模式进行接口转发调用
- 2.编写通用的esb服务调用组件,方便进行esb外围服务接口调用,免除重复编写调用逻辑,并且记录外围调用以及自己调用外围接口流水信息,通过流水方便问题查询
- 3.服务启动有很多数据库码值,初始化读取码值到内存,后续减少数据库交互,提升逻辑校验效率
- 4.配置信息,包含yml以及log
- 5.编写测试类,进行简单逻辑测试
细节不赘述了,简单设计图如下
项目为简单的单体集群服务,pom也很简单,具体配置如下,就不介绍了
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>business-online</artifactId>
<groupId>cn.git</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>online-server</artifactId>
<description>信贷系统网贷子系统服务</description>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.git</groupId>
<artifactId>credit-log-starter</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>cn.git</groupId>
<artifactId>credit-oracle-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.git</groupId>
<artifactId>credit-swagger-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.ibm.informix</groupId>
<artifactId>jdbc</artifactId>
<version>4.50.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-log4j-2.x</artifactId>
<version>8.6.0</version>
</dependency>
<!-- spring-boot的测试框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<!-- compiler -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<!-- package -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
项目整体的结构如下图所示
3.具体实现如下
3.1 编写统一入口controller以及策略类
esb接收服务端调用也是http请求调用,传输的数据也是有固定格式的,请求体包含head,body,其中body内可以自定义自己系统的校验逻辑appHead(非必要参数),head中包含接口作用,全局流水,以及接口交易码等信息,body中则是请求参数体,包含具体请求参数信息,接收到信息后需要对接口参数进行转义,转义成json对象,再通过svc_no,scn_no,确定好处理类,从spring容器当中获取对应处理类,所有处理类都实现了EsbJsonHandler接口,最后统一调用process方法即可,具体实现逻辑如下
3.1.1 通用controller入口
通用入口,用于接收esb请求过来的信息,通过svc_no,scn_no进行业务跳转,调用对应的具体业务处理逻辑
package cn.git.online.controller;
import cn.git.online.entity.TbEsbLimitLogs;
import cn.git.online.entity.TbPubEsbServerConfig;
import cn.git.online.service.EsbClientService;
import cn.git.online.util.EsbCommonUtil;
import cn.git.online.util.LoanApiProperties;
import cn.git.online.util.NewCoreProperties;
import cn.git.online.util.OnlineExceptionContext;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
/**
* esb调用网贷服务通用controller接口
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2021-11-15
*/
@Slf4j
@Controller
@RequestMapping("/online")
public class OnlineEsbCommonController {
@Autowired
private EsbClientService esbClientService;
@Autowired
private EsbCommonUtil esbCommonUtil;
@PostMapping(value = "/esb")
public void onlineEsbServer(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 请求到DICS系统时间,以及服务最终返回响应时间
Date requestInDateTime = new Date();
Date responseOutDateTime = null;
// 设置请求以及响应信息类型以及字符
response.setContentType(NewCoreProperties.RESPONSE_TYPE_TEXT);
request.setCharacterEncoding(NewCoreProperties.UTF_8);
PrintWriter printWriter = response.getWriter();
response.setCharacterEncoding(NewCoreProperties.UTF_8);
response.setContentType(NewCoreProperties.RESPONSE_TYPE_JSON);
ServletInputStream inputStream = request.getInputStream();
String esbReqJsonStr = IoUtil.read(inputStream, NewCoreProperties.CHARSET);
JSONObject esbReqJsonParam = JSON.parseObject(esbReqJsonStr);
// 获取svnNo 和 scnNo
JSONObject jsonHead = esbReqJsonParam.getJSONObject(LoanApiProperties.HEAD);
String svcNo = jsonHead.getString(NewCoreProperties.CAPITAL_SVC_NO);
String scnNo = jsonHead.getString(NewCoreProperties.CAPITAL_SCN_NO);
String gloSeqNo = jsonHead.getString(NewCoreProperties.GLO_SEQ_NO_FLG);
// 最终返回json数据
JSONObject finalReturnJson = new JSONObject();
try {
// 本地配置表信息校验
TbEsbLimitLogs limitLogs = esbClientService.getLimitLogs(svcNo, scnNo);
TbPubEsbServerConfig serverConfig = esbClientService.getEsbServerConfig(svcNo, scnNo);
if (ObjectUtil.isEmpty(limitLogs) || ObjectUtil.isNull(serverConfig)) {
JSONObject optionRspJson = new JSONObject();
optionRspJson.put(NewCoreProperties.DICS_RESP_COD, NewCoreProperties.OPTION_PARAM_CODE);
optionRspJson.put(NewCoreProperties.DICS_RESP_MSG, NewCoreProperties.SVC_SCN_ERROR);
finalReturnJson = esbCommonUtil.getEsbReturnJsonInfo(esbReqJsonParam,
optionRspJson, NewCoreProperties.ONLINE_SYSTEM_FLAG);
} else {
// 调用本地服务接口,进行数据处理
JSONObject optionJsonInfo = esbCommonUtil.optionHandler(esbReqJsonParam, serverConfig);
finalReturnJson = esbCommonUtil.getEsbReturnJsonInfo(esbReqJsonParam,
optionJsonInfo,
NewCoreProperties.ONLINE_SYSTEM_FLAG);
responseOutDateTime = new Date();
}
printWriter.write(finalReturnJson.toJSONString());
} catch (Exception e) {
e.printStackTrace();
// 设定返回异常信息
String errorMsg = esbCommonUtil.getStackTraceInfo(e);
if (StrUtil.isNotBlank(e.getMessage())) {
errorMsg = e.getMessage();
}
// 获取自定义异常码值字段
String optionCode;
if (StrUtil.isBlank(OnlineExceptionContext.getExceptionCode())) {
optionCode = NewCoreProperties.OPTION_PARAM_CODE;
} else {
optionCode = OnlineExceptionContext.getExceptionCode();
OnlineExceptionContext.removeExceptionCode();
}
// 失败信息通用字段
JSONObject optionRspJson = new JSONObject();
optionRspJson.put(NewCoreProperties.DICS_RESP_COD, optionCode);
optionRspJson.put(NewCoreProperties.DICS_RESP_MSG,
StrUtil.format("信贷服务调用异常: 全局流水号[{}], 异常信息:{}",
gloSeqNo,
errorMsg));
finalReturnJson = esbCommonUtil.getEsbReturnJsonInfo(esbReqJsonParam,
optionRspJson, NewCoreProperties.ONLINE_SYSTEM_FLAG);
// 异常情况下调用时间计算
responseOutDateTime = new Date();
printWriter.write(finalReturnJson.toJSONString());
} finally {
// 调用日志信息插入库中
esbClientService.addEsbOperateConvertLog(JSON.parseObject(esbReqJsonStr),
finalReturnJson,
requestInDateTime,
responseOutDateTime);
printWriter.close();
}
}
}
3.1.2 ESB调用信贷系统通用handler类具体实现
一个通用的逻辑策略接口类,所有的详细逻辑类都需要实现此接口,并且实现此接口的process方法
package cn.git.online.handler;
import com.alibaba.fastjson.JSONObject;
/**
* ESB调用信贷系统通用handler类
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2021-11-15
*/
public interface EsbJsonHandler {
/**
* 调用具体实现类方法
* @param reqJsonParam 请求json参数
* @return JSONObject 处理后返回json数据
* @throws Exception 异常信息
*/
JSONObject process(JSONObject reqJsonParam) throws Exception;
}
3.1.3 esb调用text/json无法识别问题
在esb服务调用过程中,我发现会提示text/json无法识别问题,为了解决解决text/json无法识别问题,新增一个cnofig配置类
package cn.git.online.config;
import cn.git.online.util.NewCoreProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import java.util.ArrayList;
import java.util.List;
/**
* 解决text/json无法识别问题
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2021-11-30
*/
@Configuration
public class WebMvcConfig {
/**
* 新增请求类型
* @return MappingJackson2HttpMessageConverter 处理类
*/
@Bean
public MappingJackson2HttpMessageConverter getMappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
//设置MediaType
List<MediaType> list = new ArrayList<>();
list.add(MediaType.APPLICATION_JSON_UTF8);
list.add(MediaType.valueOf(NewCoreProperties.RESPONSE_TYPE_TEXT_JSON));
mappingJackson2HttpMessageConverter.setSupportedMediaTypes(list);
return mappingJackson2HttpMessageConverter;
}
}
3.1.4 具体逻辑接口
controller接口接收到数据最终调用类如下C012001301Tran类,C0120013为svc_no,01为scn_no,process方法则是正常的业务逻辑方法,首先接收jsonObject转换为基本处理DTO对象,之后调用基本service方法逻辑
package cn.git.online.esb;
import cn.git.online.dto.srcre.C012001301DTO;
import cn.git.online.dto.srcre.child.TbCsmCompTreatyDTO;
import cn.git.online.handler.EsbJsonHandler;
import cn.git.online.service.CustomerService;
import cn.git.online.service.TreatyService;
import cn.git.online.util.LoanApiProperties;
import cn.git.online.util.NewCoreProperties;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.Date;
/**
* @description: 新增合作方主协议以及合作方信息
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2022-06-22 04:09:00
*/
@Slf4j
@Component
public class C012001301Tran implements EsbJsonHandler {
@Autowired
private CustomerService customerService;
@Autowired
private TreatyService treatyService;
/**
* 调用具体实现类方法
* @param reqJsonParam 请求json参数
* @return JSONObject 处理后返回json数据
* @throws Exception 异常信息
*/
@Override
public JSONObject process(JSONObject reqJsonParam) throws Exception {
// 封装返回数据
JSONObject optionRspJson = new JSONObject();
optionRspJson.put(NewCoreProperties.DICS_RESP_COD, NewCoreProperties.OPTION_SUCCESS_CODE);
optionRspJson.put(NewCoreProperties.DICS_RESP_MSG, NewCoreProperties.OPTION_SUCCESS_MSG);
// 获取head信息
JSONObject jsonBody = reqJsonParam.getJSONObject(LoanApiProperties.BODY);
JSONObject jsonHead = reqJsonParam.getJSONObject(LoanApiProperties.HEAD);
log.info("调用支付接口,调用参数 reqJsonParam [{}]", reqJsonParam.toJSONString());
C012001301DTO c012001301DTO = JSONObject.parseObject(jsonBody.toJSONString(), C012001301DTO.class);
c012001301DTO.setGloSeqNo(jsonHead.getString(NewCoreProperties.GLO_SEQ_NO_FLG));
// 参数校验
String errorMessage = checkRequestParam(c012001301DTO);
if (StrUtil.isNotBlank(errorMessage)) {
errorMessage = StrUtil.format("数字信贷合作方信息新增参数错误,[{}]", errorMessage);
// 客户信息查询失败处理
optionRspJson.put(NewCoreProperties.DICS_RESP_COD, NewCoreProperties.OPTION_EXCEPTION_CODE);
optionRspJson.put(NewCoreProperties.DICS_RESP_MSG, errorMessage);
log.info("合作方客信息新增异常,异常信息为[{}]", errorMessage);
return optionRspJson;
}
// 查询ECIF客户信息进行落库
errorMessage = customerService.loadCorporationCustomer(c012001301DTO.getCooperationCustomerNum(), c012001301DTO);
if (StrUtil.isNotBlank(errorMessage)) {
errorMessage = StrUtil.format("数字信贷合作方信息落ECIF客户信息失败,失败信息[{}]", errorMessage);
// 客户信息查询失败处理
optionRspJson.put(NewCoreProperties.DICS_RESP_COD, NewCoreProperties.OPTION_EXCEPTION_CODE);
optionRspJson.put(NewCoreProperties.DICS_RESP_MSG, errorMessage);
log.info("合作方客信息新增异常,落ecif信息失败,失败信息为[{}]", errorMessage);
return optionRspJson;
}
// 开始落合作方信息
customerService.loadCompInfo(c012001301DTO);
// 落主协议信息
treatyService.loadMainTreatyInfo(c012001301DTO);
return optionRspJson;
}
/**
* 参数校验
* @param c012001301DTO 请求dto
* @return 错误信息
*/
public String checkRequestParam(C012001301DTO c012001301DTO) {
// 最终返回错误信息
String errorMessage = null;
if (StrUtil.isBlank(c012001301DTO.getCooperationCustomerNum())) {
errorMessage = "合作方客户编号".concat(NewCoreProperties.NOT_NULL_SUFFIX);
}
// 等等......
return errorMessage;
}
}
3.1.5 异常处理
在controller层catch中,进行了异常处理,将异常信息组装为正常最终返回的esb要求格式,所以在业务层,则可以直接抛出异常即可
// 先确认合作方客户信息本地是否存在
QueryWrapper<TbCsmCompInfo> compInfoQueryWrapper = new QueryWrapper<>();
compInfoQueryWrapper.lambda().eq(TbCsmCompInfo::getCustomerNum, c012001303DTO.getCooperationCustomerNum());
TbCsmCompInfo tbCsmCompInfo = tbCsmCompInfoMapper.selectOne(compInfoQueryWrapper);
if (ObjectUtil.isNull(tbCsmCompInfo)) {
// 合作方客户信息获取失败
OnlineExceptionContext.setExceptionCode(NewCoreProperties.OPTION_PARAM_CODE);
throw new RuntimeException(StrUtil.format("通过合作方客户编号未获取到合作方客户信息[{}]",
c012001303DTO.getCooperationCustomerNum()));
}
3.2 esb服务调用组件
此处编写为本服务调用esb外围接口通用类,也是通用组装esb json信息,信息格式依然是head,body,然后使用http工具进行一个转发操作,外部系统分为多个,所以有多个head头以及appHead头的拼写逻辑,进行统一封装,方便后续重用
3.2.1 客户端client编写
此部分,进行客户信息统一处理,通过svc_no,以及scn_no确定是哪个系统,分别进行不同请求头的封装
package cn.git.online.client;
import cn.git.online.dto.esb.EsbBaseDTO;
import cn.git.online.dto.esb.NewCoreBaseDTO;
import cn.git.online.entity.TbEsbLimitLogs;
import cn.git.online.entity.TbEsbNewCoreRecords;
import cn.git.online.mapper.TbEsbLimitLogsMapper;
import cn.git.online.mapper.TbEsbNewCoreRecordsMapper;
import cn.git.online.thread.ThreadPoolUtil;
import cn.git.online.util.EsbCommonUtil;
import cn.git.online.util.LoanApiProperties;
import cn.git.online.util.NewCoreProperties;
import cn.hutool.core.text.StrSpliter;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
/**
* 以jar包形式进行ESB新核心接口调用,不依赖feign形式,减少系统间调用次数
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2021-08-19
*/
@Slf4j
@Component
public class EsbCommonClient {
@Autowired
private EsbCommonUtil esbCommonUtil;
@Autowired
private TbEsbNewCoreRecordsMapper tbEsbNewCoreRecordsMapper;
@Autowired
private TbEsbLimitLogsMapper tbEsbLimitLogsMapper;
/**
* 发送信息到
* @param dto 传入的数据dto对象
* @return 交互后的ESB信息
*/
public JSONObject setBasicDtoInfoAndSendNewCore(EsbBaseDTO dto) {
// 计算调用时间长度
Long startTime = System.currentTimeMillis();
// 获取通过类名获取svc scn 编号
String fullClassName = dto.getClass().getName();
List<String> packageList = StrSpliter.split(fullClassName,
StrUtil.DOT,
NewCoreProperties.FLAG_INT_0,
NewCoreProperties.TRUE,
NewCoreProperties.FALSE);
String className = packageList.get(packageList.size() -1);
// 服务消费码
String svcNo = StrUtil.sub(className, NewCoreProperties.FLAG_INT_0, NewCoreProperties.FLAG_INT_8);
// 服务场景码
String scnNo = StrUtil.sub(className, NewCoreProperties.FLAG_INT_8,NewCoreProperties.FLAG_INT_10);
// 获取全局流水号信息 第三方平台传递
String gloSeqNo = dto.getGloSeqNo();
dto.setGloSeqNo(null);
// 渠道编号
String customReqCalCd = dto.getReqCalCd();
dto.setReqCalCd(null);
NewCoreBaseDTO newCoreBaseDTO = new NewCoreBaseDTO();
newCoreBaseDTO.setSvcNo(svcNo);
newCoreBaseDTO.setScnNo(scnNo);
newCoreBaseDTO.setCommonDTO(dto);
newCoreBaseDTO.setSvcVerNo(NewCoreProperties.SVC_VER_NO);
newCoreBaseDTO.setScnVerNo(NewCoreProperties.SCN_VER_NO);
if (ObjectUtil.isNull(gloSeqNo)) {
// 网贷系统自身请求头
String sequenceNo = tbEsbNewCoreRecordsMapper.getReqSequence();
gloSeqNo = esbCommonUtil.getGloSeqNo(sequenceNo);
}
newCoreBaseDTO.setGloSeqNo(gloSeqNo);
// 最终返回数据
JSONObject rspJsonObject = new JSONObject(false);
TbEsbLimitLogs tbEsbLimitLogs = null;
// 最终请求信息
JSONObject finalRequestJson = new JSONObject();
// 设置请求时间以及响应时间
Date requestDateTime = null;
Date responseDateTime = null;
try {
// 请求信息校验
JSONObject reqJsonInfo = esbCommonUtil.checkAndConvertEsbRequestParam(newCoreBaseDTO);
// 参数校验
if (StrUtil.isNotBlank(reqJsonInfo.getString(LoanApiProperties.RSP_MSG))) {
throw new RuntimeException(StrUtil
.format("调用svcNo[{}],scnNo[{}]服务操作员操作日期信息不全,全局流水号[{}]!",
svcNo,
scnNo,
gloSeqNo));
}
// 通过缓存平台获取参ESB参数信息
QueryWrapper<TbEsbLimitLogs> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(TbEsbLimitLogs::getSvcNo, svcNo);
queryWrapper.lambda().eq(TbEsbLimitLogs::getScnNo, scnNo);
tbEsbLimitLogs = tbEsbLimitLogsMapper.selectOne(queryWrapper);
if (ObjectUtil.isEmpty(tbEsbLimitLogs)) {
reqJsonInfo.put(LoanApiProperties.RSP_MSG, NewCoreProperties.SVC_SCN_ERROR);
reqJsonInfo.put(LoanApiProperties.RSP_ST, LoanApiProperties.RSP_ST_FAIL);
return reqJsonInfo;
}
// 获取首字母大写公共请求头 如果自定义渠道号,则使用自定义,否则默认数字信贷渠道
JSONObject coreReqHeadJsonObject = esbCommonUtil.getNewCoreReqPubHeader(newCoreBaseDTO,
reqJsonInfo,
customReqCalCd);
// 设置请求体中的外围系统标识 ECIF客户信息系统,CBS核心系统
JSONObject requestBodyJsonObject = esbCommonUtil.getRequestBodyJsonObject(reqJsonInfo, tbEsbLimitLogs);
finalRequestJson.put(NewCoreProperties.REQ_HEAD, coreReqHeadJsonObject);
finalRequestJson.put(NewCoreProperties.REQ_BODY, requestBodyJsonObject);
// 设置请求时间
requestDateTime = new Date();
rspJsonObject = esbCommonUtil.send(finalRequestJson);
responseDateTime = new Date();
Long endTime = System.currentTimeMillis();
log.info("{}调用时间: {}秒", newCoreBaseDTO.getGloSeqNo(), (startTime - endTime) / 1000);
// 返回信息封装
newCoreBaseDTO.setResponseJsonObject(rspJsonObject);
} catch (Exception e) {
// 调用异常设置响应时间
responseDateTime = new Date();
e.printStackTrace();
log.error("调用[{}{}]失败,gloSeqNo->[{}], 异常信息为: [{}]",
newCoreBaseDTO.getSvcNo(),
newCoreBaseDTO.getScnNo(),
newCoreBaseDTO.getGloSeqNo(),
e.getMessage());
} finally {
TbEsbLimitLogs finalTbEsbLimitLogs = tbEsbLimitLogs;
Date finalRequestDateTime = requestDateTime;
Date finalResponseDateTime = responseDateTime;
ThreadPoolUtil.THREAD_POOL.execute(() -> {
addEsbOperateLog(newCoreBaseDTO,
finalTbEsbLimitLogs,
finalRequestJson,
finalRequestDateTime,
finalResponseDateTime);
});
}
return rspJsonObject;
}
/**
* 调用ESB异步日志信息处理
* @param newCoreBaseDTO 新增日志处理参数
* @param tbEsbLimitLogs 管理表
* @param finalRequestJson 请求信息
*/
public void addEsbOperateLog(NewCoreBaseDTO newCoreBaseDTO,
TbEsbLimitLogs tbEsbLimitLogs,
JSONObject finalRequestJson,
Date requestDateTime,
Date responseDateTime) {
log.info("当前调用线程[{}]执行ESB交互日志插入", Thread.currentThread().getName());
JSONObject commonJsonObject = (JSONObject) JSON.toJSON(newCoreBaseDTO.getCommonDTO());
String busFlg = commonJsonObject.getString(NewCoreProperties.BUS_FLG);
// 获取日志管理类,通过配置关系确定是否插入请求信息
if (ObjectUtil.isNotNull(tbEsbLimitLogs) && NewCoreProperties.FLAG_1.equals(tbEsbLimitLogs.getFrontFlag())) {
// 查看是否需要进行数据大小写转换 0否1是
JSONObject requestJsonBodyObject = null;
if (NewCoreProperties.FLAG_0.equals(tbEsbLimitLogs.getIfCapitalLetter())) {
requestJsonBodyObject = esbCommonUtil.formatObjectToJsonObject(commonJsonObject);
} else {
requestJsonBodyObject = esbCommonUtil.formatObjectToInitialJsonObject(commonJsonObject);
}
// 将请求数据插入到日志表中
TbEsbNewCoreRecords tbEsbNewCoreRecords = new TbEsbNewCoreRecords();
tbEsbNewCoreRecords.setRecordId(IdUtil.simpleUUID());
tbEsbNewCoreRecords.setGloSeqNo(newCoreBaseDTO.getGloSeqNo());
tbEsbNewCoreRecords.setLocalBusFlag(busFlg);
tbEsbNewCoreRecords.setMessageInfo(finalRequestJson.toJSONString());
tbEsbNewCoreRecords.setMessageTime(requestDateTime);
tbEsbNewCoreRecords.setMessageType(NewCoreProperties.SEND);
if (ObjectUtil.isNotEmpty(requestJsonBodyObject)) {
tbEsbNewCoreRecords.setOrgCd(requestJsonBodyObject.getString(NewCoreProperties.ORG_CD_FLG));
tbEsbNewCoreRecords.setUserCd(requestJsonBodyObject.getString(NewCoreProperties.USER_CD_FLAG));
}
tbEsbNewCoreRecords.setReqSeqNo(StrUtil.sub(IdUtil.simpleUUID(),
NewCoreProperties.FLAG_INT_0,
NewCoreProperties.FLAG_INT_30));
tbEsbNewCoreRecords.setSvcNo(newCoreBaseDTO.getSvcNo());
tbEsbNewCoreRecords.setScnNo(newCoreBaseDTO.getScnNo());
tbEsbNewCoreRecords.setRspDate(null);
tbEsbNewCoreRecords.setRspSeqNo(null);
tbEsbNewCoreRecords.setRspSt(null);
tbEsbNewCoreRecordsMapper.insert(tbEsbNewCoreRecords);
}
// 返回信息插入记录表
if (ObjectUtil.isNotNull(newCoreBaseDTO.getResponseJsonObject())) {
addResponseJsonInfo(newCoreBaseDTO.getResponseJsonObject(), tbEsbLimitLogs, responseDateTime);
}
}
/**
* 请求ESB返回信息存入log表中
* @param rspJsonObject 返回json数据
* @param tbEsbLimitLogs 日志设置信息参数
*/
public void addResponseJsonInfo(JSONObject rspJsonObject, TbEsbLimitLogs tbEsbLimitLogs, Date responseDateTime) {
// 获取返回信息以及发送重要参数信息
JSONObject rspHeadJson = rspJsonObject.getJSONObject(NewCoreProperties.REQ_HEAD);
JSONObject rspBodyJson = rspJsonObject.getJSONObject(NewCoreProperties.REQ_BODY);
String svcNo = rspHeadJson.getString(NewCoreProperties.CAPITAL_SVC_NO);
String scnNo = rspHeadJson.getString(NewCoreProperties.CAPITAL_SCN_NO);
// 获取日志管理类,通过配置关系确定是否插入数据到日志表中
if (NewCoreProperties.FLAG_1.equals(tbEsbLimitLogs.getBehindFlag())) {
TbEsbNewCoreRecords tbEsbNewCoreRecords = new TbEsbNewCoreRecords();
tbEsbNewCoreRecords.setRecordId(IdUtil.simpleUUID());
tbEsbNewCoreRecords.setGloSeqNo(rspHeadJson.getString(NewCoreProperties.GLO_SEQ_NO_FLG));
tbEsbNewCoreRecords.setLocalBusFlag(rspJsonObject.getString(NewCoreProperties.BUS_FLG));
tbEsbNewCoreRecords.setMessageInfo(rspJsonObject.toJSONString());
tbEsbNewCoreRecords.setMessageTime(responseDateTime);
tbEsbNewCoreRecords.setMessageType(NewCoreProperties.ACCEPT);
if (ObjectUtil.isNotEmpty(rspBodyJson)) {
tbEsbNewCoreRecords.setOrgCd(rspBodyJson.getString(NewCoreProperties.ORG_CD_FLG));
tbEsbNewCoreRecords.setUserCd(rspBodyJson.getString(NewCoreProperties.USER_CD_FLAG));
}
tbEsbNewCoreRecords.setReqSeqNo(StrUtil.sub(IdUtil.simpleUUID(),
NewCoreProperties.FLAG_INT_0,
NewCoreProperties.FLAG_INT_30));
tbEsbNewCoreRecords.setSvcNo(svcNo);
tbEsbNewCoreRecords.setScnNo(scnNo);
tbEsbNewCoreRecords.setRspDate(rspHeadJson.getString(NewCoreProperties.RSP_DATE));
tbEsbNewCoreRecords.setRspSeqNo(rspHeadJson.getString(NewCoreProperties.RSP_SEQ_NO));
tbEsbNewCoreRecords.setRspSt(rspHeadJson.getString(NewCoreProperties.RSP_ST));
tbEsbNewCoreRecordsMapper.insert(tbEsbNewCoreRecords);
}
// 如果是撤销业务需要通过唯一业务编号对业务记录日志状态进行修改
if (NewCoreProperties.CANCEL_SVC_NO.equals(svcNo)
&& NewCoreProperties.CANCEL_SCN_NO.equals(scnNo)) {
TbEsbNewCoreRecords updateRecords = new TbEsbNewCoreRecords();
updateRecords.setRspSt(NewCoreProperties.RETURN_STATUS_F);
// 修改条件
UpdateWrapper<TbEsbNewCoreRecords> updateWrapper = new UpdateWrapper<>();
updateWrapper.lambda()
.eq(TbEsbNewCoreRecords::getSvcNo, svcNo)
.eq(TbEsbNewCoreRecords::getScnNo, scnNo)
.eq(TbEsbNewCoreRecords::getMessageType, NewCoreProperties.ACCEPT)
.eq(TbEsbNewCoreRecords::getLocalBusFlag, rspJsonObject.getString(NewCoreProperties.BUS_FLG));
tbEsbNewCoreRecordsMapper.update(updateRecords, updateWrapper);
}
}
}
esbCommonUtil工具类
package cn.git.online.util;
import cn.git.online.dto.esb.NewCoreBaseDTO;
import cn.git.online.entity.TbEsbLimitLogs;
import cn.git.online.entity.TbPubEsbServerConfig;
import cn.git.online.handler.EsbJsonHandler;
import cn.git.online.header.CbsAppHead;
import cn.git.online.header.CommonCoreReqHead;
import cn.git.online.header.EcifAppHead;
import cn.git.online.service.EsbClientService;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.PascalNameFilter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.InetAddress;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* ESB服务通用util工具类
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2021-08-19
*/
@Slf4j
@Component
public class EsbCommonUtil {
/**
* sit环境
*/
private static final String PROFILE_ACTIVE_SIT = "sit";
/**
* sit代理安装地址
*/
private static final String SIT_ADDRESS = "3.1.101.57";
@Value("${spring.profiles.active}")
private String profile;
@Autowired
private ApplicationContext applicationContext;
@Autowired
private EsbClientService esbClientService;
/**
* 设置转JSON字符串数据格式
* WriteNullListAsEmpty null list -> []
* WriteNullStringAsEmpty null string -> ""
* WriteBigDecimalAsPlain 防止BigDecimal的科学计数法
*/
public SerializerFeature[] FEATURES = new SerializerFeature[]{
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.WriteBigDecimalAsPlain
};
/**
* 获取全局序列号
* G + <系统编码(5位)>+<日期(8位)>+<保留2位>+<序列号9位>
* 前缀标识:1 位字符,固定为‘G’,用作全局流水号前缀标识。
* 系统编码:5 位字符,取值参见“系统编码规范”,不足5 位右补‘0’,如‘FTS00’,作为识别第一发起方系统的标识。
* 日期:8 位数字日期,格式:YYYYMMDD,如‘20190627
* 保留位:2 位,固定为‘00’,保留用作未来扩展。
* 序列号:9 位数字序列号,每天从‘000000001’开始,至‘999999999’
*/
public String getGloSeqNo(String seqNo) {
// 获取流水号拼装承对应格式,9 位数字序列号,每天从‘000000001’开始,至‘999999999’
String subBasicSeqNo = StrUtil.sub(
NewCoreProperties.GLO_SEQ_RULE_VAL,
NewCoreProperties.FLAG_INT_0,
NewCoreProperties.FLAG_INT_9 - seqNo.length());
String systemFlag = NewCoreProperties.ONLINE_SYSTEM_FLG_0;
// 开始拼接具体全局序列号: G + <系统编码(5位)>+<日期(8位)>+<保留2位>+<序列号9位>
String gloSeqNo = StrUtil.format(
NewCoreProperties.STRING_APPEND_TEMPLATE,
NewCoreProperties.FRONT_FLG,
systemFlag,
getSystemDate(),
NewCoreProperties.KEEP_STAY_FLG,
subBasicSeqNo,
seqNo);
return gloSeqNo;
}
/**
* 获取当前系统日期: yyyyMMdd 格式
* @return 系统时间
*/
public String getSystemDate() {
// 获取当前系统时间
Timestamp systemTime = new Timestamp(System.currentTimeMillis());
return DateUtil.format(new Date(systemTime.getTime()), NewCoreProperties.DATE_FORMAT);
}
/**
* 参数是否填入校验
* @param newCoreBaseDTO 参数dto
*/
public JSONObject checkAndConvertEsbRequestParam(NewCoreBaseDTO newCoreBaseDTO) {
// 请求参数转换为JSON格式数据,并且设置busFlg唯一标识到DTO中,删除共通FeignDTO中busFlg
JSONObject reqBodyJson = (JSONObject) JSON.toJSON(newCoreBaseDTO.getCommonDTO());
// 获取userCd, busFlg, orgCd信息,并且进行校验是否为空值
String busFlg = reqBodyJson.getString(NewCoreProperties.BUS_FLG);
String userCd = reqBodyJson.getString(NewCoreProperties.USER_CD_FLAG);
String orgCd = reqBodyJson.getString(NewCoreProperties.ORG_CD_FLG);
String sysDate = reqBodyJson.getString(NewCoreProperties.CURRENT_SYS_DATE_FLG);
reqBodyJson.put(NewCoreProperties.BUS_FLG, null);
if (StrUtil.isBlank(userCd) || StrUtil.isBlank(orgCd) || StrUtil.isBlank(sysDate)) {
reqBodyJson.put(LoanApiProperties.RSP_MSG, NewCoreProperties.PARAM_LOST_ERROR);
}
// 撤销操作busFlg必填校验
if (NewCoreProperties.CANCEL_SCN_NO.equals(newCoreBaseDTO.getScnNo())
&& NewCoreProperties.CANCEL_SVC_NO.equals(newCoreBaseDTO.getSvcNo())) {
if (StrUtil.isBlank(busFlg)) {
reqBodyJson.put(LoanApiProperties.RSP_MSG, NewCoreProperties.CANCEL_PARAM_ERROR);
} else {
// 调用cancelFeign接口,获取撤销操作的param参数信息
JSONObject cancelParam = esbClientService.getCancelParam(newCoreBaseDTO.getSvcNo(),
newCoreBaseDTO.getScnNo(),
busFlg);
if (ObjectUtil.isNotEmpty(cancelParam)) {
reqBodyJson.putAll(cancelParam);
}
}
}
return reqBodyJson;
}
/**
* 设置新核心请求公共头信息头(必输项)
* @param newCoreBaseDTO 请求NewCoreBaseDTO转换的jsonObject对象
* @param commonJsonObject 请求体
* @param reqCalCd 渠道号
* @return JSONObject header必输项信息
*/
public JSONObject getNewCoreReqPubHeader(NewCoreBaseDTO newCoreBaseDTO,
JSONObject commonJsonObject,
String reqCalCd) {
// 通用请求header
CommonCoreReqHead coreReqHead = BeanUtil.copyProperties(newCoreBaseDTO, CommonCoreReqHead.class);
// 渠道码
if (StrUtil.isBlank(reqCalCd)) {
coreReqHead.setReqCalCd(NewCoreProperties.ONLINE_REQ_CAL_CD);
} else {
coreReqHead.setReqCalCd(reqCalCd);
}
// 请求系统标识 对应系统英文名称 不满5位右侧补0
coreReqHead.setReqSysId(NewCoreProperties.ONLINE_SYSTEM_FLAG);
String loginUserSysDate = commonJsonObject.getString(NewCoreProperties.CURRENT_SYS_DATE_FLG);
coreReqHead.setReqDt(loginUserSysDate);
// 获取当前系统时间 HHMMSS
coreReqHead.setReqTm(getHourToSeconds());
coreReqHead.setReqSeqNo(IdUtil.simpleUUID()
.substring(NewCoreProperties.FLAG_INT_0, NewCoreProperties.FLAG_INT_30));
return formatObjectToInitialJsonObject(coreReqHead);
}
/**
* 通过配置信息获取请求头json数据
* @param commonJsonObject 请求体
* @param tbEsbLimitLogs 日志管理表信息
* @return 请求json头
*/
public JSONObject getRequestBodyJsonObject(JSONObject commonJsonObject,
TbEsbLimitLogs tbEsbLimitLogs) {
String requestSysFlag = StrUtil.toString(tbEsbLimitLogs.getSystemFlag());
// 获取调用接口请求信息body服务是否需要大写首字母
String ifCapitalLetter = StrUtil.toString(tbEsbLimitLogs.getIfCapitalLetter());
commonJsonObject.put(NewCoreProperties.BUS_FLG, null);
String loginUserOrgCd = commonJsonObject.getString(NewCoreProperties.ORG_CD_FLG);
String loginUserSysDate = commonJsonObject.getString(NewCoreProperties.CURRENT_SYS_DATE_FLG);
commonJsonObject.put(NewCoreProperties.ORG_CD_FLG, null);
commonJsonObject.put(NewCoreProperties.CURRENT_SYS_DATE_FLG, null);
commonJsonObject.put(NewCoreProperties.USER_CD_FLAG, null);
// 最终返回组装body体
JSONObject requestJsonBodyObject = null;
if (NewCoreProperties.FLAG_0.equals(ifCapitalLetter)) {
requestJsonBodyObject = formatObjectToJsonObject(commonJsonObject);
} else {
requestJsonBodyObject = formatObjectToInitialJsonObject(commonJsonObject);
}
if (NewCoreProperties.CBS_SYSTEM_FLG.equals(requestSysFlag)) {
// 新核心请求头
CbsAppHead cbsAppHead = new CbsAppHead();
cbsAppHead.setJiaoyijg(loginUserOrgCd);
cbsAppHead.setJiaoyigy(NewCoreProperties.ONLINE_USER_CD);
cbsAppHead.setJiaoyirq(loginUserSysDate);
cbsAppHead.setWaiblius(IdUtil.simpleUUID());
cbsAppHead.setWaibriqi(loginUserSysDate);
JSONObject appHead = formatObjectToJsonObject(cbsAppHead);
requestJsonBodyObject.put(NewCoreProperties.APP_HEAD, appHead);
} else if (NewCoreProperties.ECIF_SYSTEM_FLG.equals(requestSysFlag)) {
// 客户系统请求头
EcifAppHead ecifAppHead = new EcifAppHead();
ecifAppHead.setBrc(loginUserOrgCd);
ecifAppHead.setTeller(NewCoreProperties.ONLINE_USER_CD);
JSONObject appHead = formatObjectToInitialJsonObject(ecifAppHead);
requestJsonBodyObject.put(NewCoreProperties.APP_HEAD, appHead);
}
return requestJsonBodyObject;
}
/**
* 设置返回信息体
* @param esbReqJsonParam 请求json参数
* @param optionJson 调用信贷处理逻辑后返回信息
* @param requestSysFlag 请求消息系统标识
* @return 返回jsonObject
*/
public JSONObject getEsbReturnJsonInfo(JSONObject esbReqJsonParam,
JSONObject optionJson,
String requestSysFlag) {
// 最终返回的json体
JSONObject finalReturnJson = new JSONObject();
JSONObject jsonHead = esbReqJsonParam.getJSONObject(LoanApiProperties.HEAD);
// esbReqJsonParam 中有参数校验信息 则optionJson中处理信息不进行覆盖
jsonHead.put(LoanApiProperties.RSP_MSG, optionJson.getString(NewCoreProperties.DICS_RESP_MSG));
if (NewCoreProperties.OPTION_SUCCESS_CODE.equals(optionJson.getString(NewCoreProperties.DICS_RESP_COD))) {
jsonHead.put(LoanApiProperties.RSP_ST, LoanApiProperties.RSP_ST_SUCCESS);
} else {
jsonHead.put(LoanApiProperties.RSP_ST, LoanApiProperties.RSP_ST_FAIL);
}
// 设置最后反回信息
finalReturnJson.put(LoanApiProperties.BODY, optionJson);
// 设置响应参数信息
String svcNo = jsonHead.getString(NewCoreProperties.CAPITAL_SVC_NO);
String scnNo = jsonHead.getString(NewCoreProperties.CAPITAL_SCN_NO);
String rspDate = new SimpleDateFormat(NewCoreProperties.FULL_DATE_FORMAT).format(new Date());
// 响应码
String rspCd = NewCoreProperties.ONLINE_SYSTEM_FLAG.concat(NewCoreProperties.FLAG_0);
if (NewCoreProperties.OPTION_SUCCESS_CODE.equals(optionJson.getString(NewCoreProperties.DICS_RESP_COD))) {
rspCd = rspCd.concat(NewCoreProperties.FLAG_0).
concat(NewCoreProperties.OPTION_SUCCESS_CODE).
concat(NewCoreProperties.OPTION_SUCCESS_CODE);
} else {
rspCd = rspCd.concat(NewCoreProperties.RSP_CD_Y)
.concat(NewCoreProperties.OPTION_SUCCESS_CODE)
.concat(optionJson.getString(NewCoreProperties.DICS_RESP_COD));
}
jsonHead.put(LoanApiProperties.RSP_CD, rspCd);
jsonHead.put(LoanApiProperties.RSP_DT, rspDate.substring(0, 8));
jsonHead.put(LoanApiProperties.RSP_TM, rspDate.substring(8));
String rspSeqNo = StrUtil.format(NewCoreProperties.STR_TEMPLATE_FOUR,
requestSysFlag,
svcNo,
scnNo,
rspDate);
jsonHead.put(LoanApiProperties.RSP_SEQ_NO, rspSeqNo);
finalReturnJson.put(LoanApiProperties.HEAD, jsonHead);
return finalReturnJson;
}
/**
* 调用EsbHandler处理信息
* @param jsonParam 请求json参数
* @param serverConfig serverConfig
* @return 处理请求参数
*/
public JSONObject optionHandler(JSONObject jsonParam, TbPubEsbServerConfig serverConfig) throws Exception {
// 生成EsbHandler并且调用对应方法
String className = StrUtil.toString(serverConfig.getTarget());
EsbJsonHandler esbJsonHandler = applicationContext.getBean(className, EsbJsonHandler.class);
JSONObject optionJsonObject = esbJsonHandler.process(jsonParam);
return optionJsonObject;
}
/**
* 设置ESB调用本地服务本地处理后封装返回数据格式
* @param rspStatusEnum 处理状态
* @param rspMsg 消息信息
* @param optionJson 返回数据信息
* @return JSONObject 封装好数据信息
*/
public JSONObject makeReturnJsonInfo(RspStatusEnum rspStatusEnum, String rspMsg, JSONObject optionJson) {
if (ObjectUtil.isEmpty(optionJson)) {
optionJson = new JSONObject();
}
// 返回json
if (ObjectUtil.isNotNull(rspMsg)) {
optionJson.put(LoanApiProperties.RSP_MSG, rspMsg);
} else {
optionJson.put(LoanApiProperties.RSP_MSG, rspStatusEnum.getRspStDesc());
}
return optionJson;
}
/**
* 获取当前系统时分秒返回: HHmmss 格式
* @return 时分秒时间
*/
public String getHourToSeconds() {
// 获取当前系统时间
return DateUtil.format(new Date(), NewCoreProperties.TIME_FORMAT);
}
/**
* 格式化json格式对象 对第一层数据进行首字母大写
* @param object 格式化对象
* @return JSONObject
*/
public JSONObject formatObjectToInitialJsonObject(Object object) {
String parsedJson = JSONObject.toJSONString(object, new PascalNameFilter(), FEATURES);
return JSONObject.parseObject(parsedJson);
}
/**
* 格式化json格式对象 去除null空串等信息
* @param object 格式化对象
* @return JSONObject
*/
public JSONObject formatObjectToJsonObject(Object object) {
String parsedJson = JSONObject.toJSONString(object, FEATURES);
return JSONObject.parseObject(parsedJson);
}
/**
* 与ESB进行交互返回信息转换为JSONObject类型
* @param finalRequestJson 最终请求json信息
*/
public JSONObject send(JSONObject finalRequestJson) {
// 获取服务本机ip地址
InetAddress inetAddress = NetUtil.getLocalhost();
String ipAddress = StrUtil.format(
NewCoreProperties.IP_ADDRESS_HOST_TEMPLATE,
inetAddress.getHostAddress(),
NewCoreProperties.ONLINE_PORT);
ipAddress = NewCoreProperties.HTTP.concat(ipAddress);
// 判断profile是否为sit todo: 后期需要修改address地址信息,同步convert-server微服务地址
if (PROFILE_ACTIVE_SIT.equals(profile)) {
ipAddress = StrUtil.format(
NewCoreProperties.IP_ADDRESS_HOST_TEMPLATE,
SIT_ADDRESS,
NewCoreProperties.ONLINE_PORT);
}
String rspJsonStr = HttpUtil.post(ipAddress, finalRequestJson.toJSONString(), NewCoreProperties.REQ_TIME_OUT);
return JSONObject.parseObject(rspJsonStr);
}
/**
* 打印异常信息转字符串
* @param exception 异常
* @return 异常信息 todo: 文档上传 90修改250字段长度
*/
public String getStackTraceInfo(Exception exception) {
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
try {
exception.printStackTrace(printWriter);
printWriter.flush();
stringWriter.flush();
String errorMessage = stringWriter.toString();
if (StrUtil.isNotBlank(errorMessage) && errorMessage.length() > NewCoreProperties.FLAG_INT_200) {
errorMessage =
errorMessage.substring(NewCoreProperties.FLAG_INT_0, NewCoreProperties.FLAG_INT_200);
}
return errorMessage;
} finally {
try{
printWriter.close();
stringWriter.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
3.2.2 本地发起调用esb服务
本地发起esb服务调用例子如下,封装需要传递参数信息,调用client进行发送即可,下面是一个发送单笔代付的交易代码
/**
* 单笔代付交易请求接口
* @param reqJsonParam 请求参数
* @param p021001001DTO 请求参数
* @return 单笔代付交易请求结果
*/
@Override
public JSONObject doDefray(JSONObject reqJsonParam, P021001001DTO p021001001DTO) {
// 获取head信息
JSONObject jsonHead = reqJsonParam.getJSONObject(LoanApiProperties.HEAD);
String gloSeqNo = jsonHead.getString(NewCoreProperties.GLO_SEQ_NO_FLG);
// 拼接支付接口请求参数
P06100XX01DTO P06100XX01DTO = new P06100XX01DTO();
P06100XX01DTO.setTellerId(NewCoreProperties.ONLINE_USER_CD);
P06100XX01DTO.setBranchNo(p021001001DTO.getOptionOrgCd());
P06100XX01DTO.setGloSeqNo(gloSeqNo);
P06100XX01DTO.setBizJnlNo(gloSeqNo);
// 摘要代码
if (StrUtil.isBlank(p021001001DTO.getAdditional())) {
P06100XX01DTO.setAdditional(NewCoreProperties.ADDITIONAL_NUM);
} else {
P06100XX01DTO.setAdditional(p021001001DTO.getAdditional());
}
P06100XX01DTO.setTxnCode(NewCoreProperties.PAY_OPTION_CODE);
P06100XX01DTO.setVersion(NewCoreProperties.PAY_OPTION_VERSION);
// 产品编码 默认 POC01
if (StrUtil.isBlank(p021001001DTO.getPayProductCd())) {
P06100XX01DTO.setProductNo(NewCoreProperties.PAY_PRODUCT_NO);
} else {
P06100XX01DTO.setProductNo(p021001001DTO.getPayProductCd());
}
// 渠道编码 格式为: 渠道编码_产品编码
P06100XX01DTO.setMchtNo(NewCoreProperties.ONLINE_REQ_CAL_CD
.concat(StrUtil.UNDERLINE)
.concat(P06100XX01DTO.getProductNo()));
P06100XX01DTO.setTranDate(p021001001DTO.getTranDate());
P06100XX01DTO.setTranTime(p021001001DTO.getTranTime());
P06100XX01DTO.setTranNo(p021001001DTO.getTranNo());
// 路由规则
P06100XX01DTO.setRouteType(NewCoreProperties.ROUTE_TYPE_AUTO);
P06100XX01DTO.setMchtOrderDate(p021001001DTO.getOptionDate().replace(StrUtil.DASHED, StrUtil.EMPTY));
// 商户订单时间 若无对应字段接入商户可填写渠道交易时间
P06100XX01DTO.setMchtOrderTime(p021001001DTO.getTranTime());
P06100XX01DTO.setMchtOrderNo(p021001001DTO.getTranNo());
// 商户编码 没有默认: 渠道号_产品编码
P06100XX01DTO.setPmcMchtNo(P06100XX01DTO.getMchtNo());
// 商户类别 没有则默认 0000
P06100XX01DTO.setPmcMchtType(NewCoreProperties.PAY_DEFAULT_CUS_TYPE);
// 商户名称 没有默认渠道名称
P06100XX01DTO.setPmcMchtName(NewCoreProperties.SRCRE_REQ_CAL_NAME);
// 本行受托,放款账号 使用过渡户账号
P06100XX01DTO.setPayerAcctNo(p021001001DTO.getTransitAccount());
P06100XX01DTO.setPayerAcctName(p021001001DTO.getTransitName());
// 判断是否受托支付
if (!NewCoreProperties.FLAG_2.equals(p021001001DTO.getLoanDirection())) {
// 非受托支付
P06100XX01DTO.setPayeeAcctNo(p021001001DTO.getLoanNum());
P06100XX01DTO.setPayeeAcctName(p021001001DTO.getLoanName());
} else {
// 受托支付
P06100XX01DTO.setPayeeAcctNo(p021001001DTO.getOtherLoanNum());
P06100XX01DTO.setPayeeAcctName(p021001001DTO.getOtherLoanName());
}
P06100XX01DTO.setCurrency(codesConverter.getConvertCode(EsbSysCodesEnum.CURRENCY,
p021001001DTO.getCurrencyCd()));
// 借据金额 保留2位小数
P06100XX01DTO.setAmount(new BigDecimal(p021001001DTO.getLoanAmt())
.setScale(NewCoreProperties.FLAG_INT_2, BigDecimal.ROUND_DOWN).toString());
P06100XX01DTO.setCurrentSysDate(p021001001DTO.getOptionDate().replace(StrUtil.DASHED, StrUtil.EMPTY));
P06100XX01DTO.setUserCd(p021001001DTO.getOptionUserCd());
P06100XX01DTO.setOrgCd(p021001001DTO.getOptionOrgCd());
log.info("调用esb中的P061000301单笔代付交易请求接口,入参[{}]", JSONObject.toJSONString(P06100XX01DTO));
JSONObject resultJson = esbCommonClient.setBasicDtoInfoAndSendNewCore(P06100XX01DTO);
JSONObject resultBody = resultJson.getJSONObject(LoanApiProperties.BODY);
JSONObject resultHead = resultJson.getJSONObject(LoanApiProperties.HEAD);
if (ObjectUtil.isEmpty(resultBody)) {
String errorMessage;
if (ObjectUtil.isNotEmpty(resultHead)) {
errorMessage = resultHead.getString(LoanApiProperties.RSP_MSG);
} else {
errorMessage = "支付代付接口返回响应信息Head或者body为空!";
}
// 设定异常码值(放款成功,支付没有处理结果)
OnlineExceptionContext.setExceptionCode(NewCoreProperties.OPTION_PAY_PROCESSING_CODE);
// 失败情况同样记录支付信息,二次支付取当前记录查询,判断是否支付成功,避免二次支付
addDefferLocalInfo(P06100XX01DTO, p021001001DTO, NewCoreProperties.UN_KNOW);
throw new RuntimeException(StrUtil.format("当前借据编号[{}]调用支付代付交易失败,响应消息[{}]",
p021001001DTO.getBorrowNum(),
errorMessage));
}
if (ObjectUtil.isNotNull(resultHead)) {
String bodyStatusKey = resultBody.getString(NewCoreProperties.STATUS_KEY);
if (StrUtil.isBlank(bodyStatusKey)) {
bodyStatusKey = NewCoreProperties.UN_KNOW;
}
// 支付结果插入结果表中
addDefferLocalInfo(P06100XX01DTO, p021001001DTO, bodyStatusKey);
}
return resultJson;
}
3.3 加载初始化码值
接口中有很多的码值校验比如产品类型,行业门类,贷款投向等,如果每次都去数据库取,太过于麻烦,并且效率不高,而且当前项目为单服务集群,进行迭代的信贷微服务平台有专门的缓存平台处理码值,这样再开发一个码值管理模块没有必要,所以就进行初始化加载,存储到本地map中,方便使用,缺点就是修改不能马上更新,需要重启,考虑到不会经常重启,以及开发成本此为最优解。
package cn.git.online.util;
import cn.git.online.dto.srcre.P021001001DTO;
import cn.git.online.entity.TbSysProduct;
import cn.git.online.entity.TbSyscodesParseOtherSyscodes;
import cn.git.online.entity.TcSysCodes;
import cn.git.online.entity.TcSysCodes1;
import cn.git.online.mapper.TbSysProductMapper;
import cn.git.online.mapper.TbSyscodesParseOtherSyscodesMapper;
import cn.git.online.mapper.TcSysCodes1Mapper;
import cn.git.online.mapper.TcSysCodesMapper;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* ESB服务交互码值通用转换类
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2021-11-19
*/
@Slf4j
@Component
public class EsbSysCodesConverter implements ApplicationRunner {
@Autowired
private TbSyscodesParseOtherSyscodesMapper syscodesMapper;
@Autowired
private TcSysCodesMapper tcSysCodesMapper;
@Autowired
private TcSysCodes1Mapper tcSysCodes1Mapper;
@Autowired
private TbSysProductMapper tbSysProductMapper;
/**
* 码值map信息
*/
private final Map<String, Map<String, String>> sysCodeMap = new HashMap<>(NewCoreProperties.FLAG_INT_16);
/**
* 2017码值投向门类
*/
private Map<String, TcSysCodes1> industryType2017Map = new HashMap<>(NewCoreProperties.FLAG_INT_16);
/**
* 2011码值投向门类
*/
private Map<String, TcSysCodes> industryType2011Map = new HashMap<>(NewCoreProperties.FLAG_INT_16);
/**
* 产品种类码值信息
*/
private Map<String, TcSysCodes> productTypeMap = new HashMap<>(NewCoreProperties.FLAG_INT_16);
/**
* 产品品种信息
*/
private Map<String, TbSysProduct> businessTypeMap = new HashMap<>(NewCoreProperties.FLAG_INT_16);
/**
* 获取码值
* @param esbSysCodesEnum 码值枚举类型
* @param sysCode 需要转换码值
* @return 转换后码值
*/
public String getConvertCode(EsbSysCodesEnum esbSysCodesEnum, String sysCode) {
String codeKey = StrUtil.format(NewCoreProperties.IP_ADDRESS_HOST_TEMPLATE,
esbSysCodesEnum.getOtherSystemFlag(),
esbSysCodesEnum.getCodeTypeCd());
Map<String, String> codeMap = sysCodeMap.get(codeKey);
if (ObjectUtil.isNotEmpty(codeMap)) {
return codeMap.get(sysCode);
} else if (ObjectUtil.isNotNull(esbSysCodesEnum.getConvertDefaultValue())) {
return esbSysCodesEnum.getConvertDefaultValue();
} else {
return null;
}
}
/**
* @param irCountAccrualCycCd 计息周期
* @param expiryDate 贷款结息日
* @return 转换核心还款周期
*/
public String convertPayModeTerm(String irCountAccrualCycCd, String expiryDate) {
String finalPayModeTerm;
// 不足两位补齐
if (expiryDate.length() == 1) {
expiryDate = NewCoreProperties.FLAG_0.concat(expiryDate);
}
if (NewCoreProperties.FLAG_1.equals(irCountAccrualCycCd)) {
// 按月计息 1-间隔个数,M-月,A-实际日期
finalPayModeTerm = NewCoreProperties.PAY_MODE_1MA.concat(expiryDate);
} else if (NewCoreProperties.FLAG_2.equals(irCountAccrualCycCd)) {
// 按季计息 1-间隔个数,Q-季度,A-实际日期
finalPayModeTerm = NewCoreProperties.PAY_MODE_1QA.concat(expiryDate).concat(NewCoreProperties.PAY_MODE_E);
} else if (NewCoreProperties.FLAG_3.equals(irCountAccrualCycCd)) {
// 按半年计息 1-间隔个数,M-月,A-实际日期
finalPayModeTerm = NewCoreProperties.PAY_MODE_1YA12.concat(expiryDate);
} else {
// 按半年计
finalPayModeTerm = NewCoreProperties.PAY_MODE_1HA.concat(expiryDate);
}
return finalPayModeTerm;
}
/**
* 码表对应关系初始化
* @param args 系统参数
* @throws Exception on error
*/
@Override
public void run(ApplicationArguments args) throws Exception {
// 本地码值转换为其他系统码值
this.currentSysCodesCovertOther();
// 贷款投向门类码值初始化
this.industryTypeInit();
// 贷款种类码值信息
this.productTypeInit();
}
/**
* 系统不同码值转换初始化方法
*/
public void currentSysCodesCovertOther() {
// 获取所有码值内容
List<TbSyscodesParseOtherSyscodes> syscodesList = syscodesMapper.selectList(null);
if (ObjectUtil.isNotEmpty(syscodesList)) {
// 通过codeTypeCd去重
List<TbSyscodesParseOtherSyscodes> typeList = syscodesList.stream().collect(
Collectors.collectingAndThen(
Collectors.toCollection(() ->
new TreeSet<>(
Comparator.comparing(TbSyscodesParseOtherSyscodes::getCcmsCodeTypeCd))),
ArrayList::new
)
);
// 封装数据
typeList.forEach(type -> {
Map<String, String> codeMap = new HashMap<>(NewCoreProperties.FLAG_INT_16);
syscodesList.forEach(code -> {
if (type.getCcmsCodeTypeCd().equals(code.getCcmsCodeTypeCd())
&& type.getOtherSysFlag().equals(code.getOtherSysFlag())) {
codeMap.put(code.getCcmsCodeCd(), code.getOtherCodeCd());
}
});
sysCodeMap.put(StrUtil.format(NewCoreProperties.IP_ADDRESS_HOST_TEMPLATE,
type.getOtherSysFlag(),
type.getCcmsCodeTypeCd()), codeMap);
});
}
}
/**
* 2017,2011贷款投向门类码值初始化
* map结构 String: 码值cd , String: 码值parent_code_id
*/
public void industryTypeInit() {
// 2017行业门类
QueryWrapper<TcSysCodes1> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(TcSysCodes1::getCodeTypeCd, NewCoreProperties.INDUSTRY_TYPE_CD_FLAG);
List<TcSysCodes1> sysCodesList = tcSysCodes1Mapper.selectList(queryWrapper);
if (ObjectUtil.isNotEmpty(sysCodesList)) {
industryType2017Map = sysCodesList.stream().collect(
Collectors.toMap(TcSysCodes1::getCodeCd, Function.identity(), (k1, k2) -> k1)
);
}
// 2011行业门类
QueryWrapper<TcSysCodes> queryWrapperTwo = new QueryWrapper<>();
queryWrapperTwo.lambda().eq(TcSysCodes::getCodeTypeCd, NewCoreProperties.INDUSTRY_TYPE_CD_FLAG);
List<TcSysCodes> sysCodesTwoList = tcSysCodesMapper.selectList(queryWrapperTwo);
if (ObjectUtil.isNotEmpty(sysCodesTwoList)) {
industryType2011Map = sysCodesTwoList.stream().collect(
Collectors.toMap(TcSysCodes::getCodeCd, Function.identity(), (k1, k2) -> k1)
);
}
}
/**
* 校验正确性2017投向门类
* @param p021001001DTO 放款请求参数
* @result 错误信息
*/
public String check2017Industry(P021001001DTO p021001001DTO) {
String errorMessage = null;
TcSysCodes1 industryOne = industryType2017Map.get(p021001001DTO.getIndustryOneCd());
TcSysCodes1 industryTwo = industryType2017Map.get(p021001001DTO.getIndustryTwoCd());
TcSysCodes1 industryThree = industryType2017Map.get(p021001001DTO.getIndustryThreeCd());
TcSysCodes1 industryFour = industryType2017Map.get(p021001001DTO.getIndustryFourCd());
if (ObjectUtil.isNull(industryOne)) {
errorMessage = StrUtil.format("2017行业门类代码[{}]", p021001001DTO.getIndustryOneCd())
.concat(NewCoreProperties.PUT_ERROR_PARAM);
} else if (ObjectUtil.isNull(industryTwo)) {
errorMessage = StrUtil.format("2017行业大类代码[{}]", p021001001DTO.getIndustryTwoCd())
.concat(NewCoreProperties.PUT_ERROR_PARAM);
} else if (ObjectUtil.isNull(industryThree)) {
errorMessage = StrUtil.format("2017行业中类代码[{}]", p021001001DTO.getIndustryThreeCd())
.concat(NewCoreProperties.PUT_ERROR_PARAM);
} else if (ObjectUtil.isNull(industryFour)) {
errorMessage = StrUtil.format("2017行业小类代码[{}]", p021001001DTO.getIndustryFourCd())
.concat(NewCoreProperties.PUT_ERROR_PARAM);
}
if (StrUtil.isNotBlank(errorMessage)) {
return errorMessage;
}
// 层级校验
if (!NewCoreProperties.FLAG_1.equals(industryOne.getCodeLevelCd())) {
errorMessage = "所选2017行业门类代码层级必须为1级!";
} else if (!NewCoreProperties.FLAG_2.equals(industryTwo.getCodeLevelCd())) {
errorMessage = "所选2017行业大类代码层级必须为2级!";
} else if (!NewCoreProperties.FLAG_3.equals(industryThree.getCodeLevelCd())) {
errorMessage = "所选2017行业中类代码层级必须为3级!";
} else if (!NewCoreProperties.FLAG_4.equals(industryFour.getCodeLevelCd())) {
errorMessage = "所选2017行业小类代码层级必须为4级!";
}
if (StrUtil.isBlank(errorMessage)) {
return errorMessage;
}
// 父子关系校验
if (!industryOne.getCodeCd().equals(industryTwo.getParentCodeId())) {
errorMessage = "2017行业门类和行业大类不是父子关系!";
} else if (!industryTwo.getCodeCd().equals(industryThree.getParentCodeId())) {
errorMessage = "2017行业大类和行业中类不是父子关系!";
} else if (!industryThree.getCodeCd().equals(industryFour.getParentCodeId())) {
errorMessage = "2017行业中类和行业小类不是父子关系!";
}
return errorMessage;
}
/**
* 校验正确性2011投向门类
* @param p021001001DTO 放款请求参数
* @result 错误信息
*/
public String check2011Industry(P021001001DTO p021001001DTO) {
String errorMessage = null;
TcSysCodes industryOne = industryType2011Map.get(p021001001DTO.getNewOneCd());
TcSysCodes industryTwo = industryType2011Map.get(p021001001DTO.getNewTwoCd());
TcSysCodes industryThree = industryType2011Map.get(p021001001DTO.getNewThreeCd());
TcSysCodes industryFour = industryType2011Map.get(p021001001DTO.getNewFourCd());
if (ObjectUtil.isNull(industryOne)) {
errorMessage = StrUtil.format("2011行业门类代码[{}]", p021001001DTO.getIndustryOneCd())
.concat(NewCoreProperties.PUT_ERROR_PARAM);
} else if (ObjectUtil.isNull(industryTwo)) {
errorMessage = StrUtil.format("2011行业大类代码[{}]", p021001001DTO.getIndustryTwoCd())
.concat(NewCoreProperties.PUT_ERROR_PARAM);
} else if (ObjectUtil.isNull(industryThree)) {
errorMessage = StrUtil.format("2011行业中类代码[{}]", p021001001DTO.getIndustryThreeCd())
.concat(NewCoreProperties.PUT_ERROR_PARAM);
} else if (ObjectUtil.isNull(industryFour)) {
errorMessage = StrUtil.format("2011行业小类代码[{}]", p021001001DTO.getIndustryFourCd())
.concat(NewCoreProperties.PUT_ERROR_PARAM);
}
if (StrUtil.isNotBlank(errorMessage)) {
return errorMessage;
}
// 层级校验
if (!NewCoreProperties.FLAG_1.equals(industryOne.getCodeLevelCd())) {
errorMessage = "所选2011行业门类代码层级必须为1级!";
} else if (!NewCoreProperties.FLAG_2.equals(industryTwo.getCodeLevelCd())) {
errorMessage = "所选2011行业大类代码层级必须为2级!";
} else if (!NewCoreProperties.FLAG_3.equals(industryThree.getCodeLevelCd())) {
errorMessage = "所选2011行业中类代码层级必须为3级!";
} else if (!NewCoreProperties.FLAG_4.equals(industryFour.getCodeLevelCd())) {
errorMessage = "所选2011行业小类代码层级必须为4级!";
}
if (StrUtil.isBlank(errorMessage)) {
return errorMessage;
}
// 父子关系校验
if (!industryOne.getCodeCd().equals(industryTwo.getParentCodeId())) {
errorMessage = "行业门类和行业大类不是父子关系!";
} else if (!industryTwo.getCodeCd().equals(industryThree.getParentCodeId())) {
errorMessage = "行业大类和行业中类不是父子关系!";
} else if (!industryThree.getCodeCd().equals(industryFour.getParentCodeId())) {
errorMessage = "行业中类和行业小类不是父子关系!";
}
return errorMessage;
}
/**
* 贷款种类码值信息初始化
*/
public void productTypeInit() {
QueryWrapper<TcSysCodes> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(TcSysCodes::getCodeTypeCd, NewCoreProperties.SYS_PRODUCT_TYPE_CD_FLAG);
List<TcSysCodes> sysCodesList = tcSysCodesMapper.selectList(queryWrapper);
if (ObjectUtil.isNotEmpty(sysCodesList)) {
productTypeMap = sysCodesList.stream().collect(
Collectors.toMap(TcSysCodes::getCodeCd, Function.identity(), (k1, k2) -> k1)
);
}
// businessType产品品种信息初始化
List<TbSysProduct> productList = tbSysProductMapper.selectList(new QueryWrapper<>());
if (ObjectUtil.isNotEmpty(productList)) {
businessTypeMap = productList.stream().collect(
Collectors.toMap(TbSysProduct::getProductCd, Function.identity(), (k1, k2) -> k1)
);
}
}
/**
* 贷款种类校验
* @param p021001001DTO 请求参数
* @result errorMessage 错误消息
*/
public String checkProductType(P021001001DTO p021001001DTO) {
String errorMessage = null;
// 码值传递正确性校验
if (ObjectUtil.isNull(productTypeMap.get(p021001001DTO.getLoanType()))) {
errorMessage = StrUtil.format("贷款种类loanType[{}]不满足申请要求!", p021001001DTO.getLoanType());
}
TbSysProduct tbSysProduct = businessTypeMap.get(p021001001DTO.getBusinessType());
if (ObjectUtil.isNull(tbSysProduct)) {
errorMessage = StrUtil.format("业务品种businessType[{}]不满足申请要求!",
p021001001DTO.getBusinessType());
}
if (StrUtil.isNotBlank(errorMessage)) {
return errorMessage;
}
// loanType 为 businessType 父类校验
if (!p021001001DTO.getLoanType().equals(tbSysProduct.getSuperiorCd())) {
errorMessage = StrUtil.format("传递业务品种businessType[{}]不是贷款种类loanType[{}]子类",
p021001001DTO.getBusinessType(), p021001001DTO.getLoanType());
}
return errorMessage;
}
/**
* 分协议业务品种逗号分割
* @param businessTypes 产品类型
* @return 校验结果
*/
public String checkAssureTreatyProduct(String businessTypes) {
// 空值校验
if (StrUtil.isBlank(businessTypes)) {
return "分协议业务品种".concat(NewCoreProperties.NOT_NULL_SUFFIX);
}
// 将逗号品种信息转换为list, 判断是否有错误的产品编号
String errorMessage = null;
List<String> bisTypeList = Arrays.stream(businessTypes.split(StrUtil.COMMA)).collect(Collectors.toList());
for (String bisType : bisTypeList) {
if (ObjectUtil.isNull(businessTypeMap.get(bisType))) {
errorMessage = StrUtil.format("新增分协议业务品种[{}]信贷系统不存在!", bisType);
break;
}
}
return errorMessage;
}
}
3.4 配置文件
此项目为单体集群项目,没有使用nacos等注册中心,配置文件直接写入到resources目录中,具体结构如下
这里配置文件以sit为例,application.yml 配置文件内容为
spring:
profiles:
active: sit
application-sit.yml配置文件内容为
server:
port: 11208
spring:
application:
name: online-server
main:
allow-bean-definition-overriding: true
datasource:
druid:
driver-class-name: com.informix.jdbc.IfxDriver
url: jdbc:informix-sqli://xxxx:49001/loan:INFORMIXSERVER=loandb;NEWCODESET=gbk,8859-1,819
username: xxxxx
password: xxxxx
#password: Loan_108
#初始化连接池的连接数量 大小,最小,最大
initial-size: 5
min-idle: 5
max-active: 20
#配置获取连接等待超时的时间 毫秒
max-wait: 60000
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 30000
validation-query: select count(*) from systables
4. 编写测试类
测试类简单的进行server端调用逻辑测试,测试类以及测试效果如下
package cn.git.online;
import cn.git.online.util.NewCoreProperties;
import cn.hutool.http.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.math.BigDecimal;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Esb调用online项目测试
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2021-10-08
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = OnlineApplication.class)
@Slf4j
public class TestEsbClient {
@Test
public void esbTest() {
String reqJSONStr = "{\n" +
" \"Head\": {\n" +
" \"ReqTm\": \"065618\",\n" +
" \"GloEndTm\": \"\",\n" +
" \"ReqCalCd\": \"701055\",\n" +
" \"ReqFl\": \"\",\n" +
" \"SvcVerNo\": \"10\",\n" +
" \"ReqSeqNo\": \"2022071301662241xxxxx59035\",\n" +
" \"SvcNo\": \"P0230014\",\n" +
" \"ReqSysId\": \"SRCRE\",\n" +
" \"GloSeqNo\": \"GSRCRE202207130xxxxx00043\",\n" +
" \"ScnVerNo\": \"10\",\n" +
" \"ReqDt\": \"20220713\",\n" +
" \"ScnNo\": \"01\"\n" +
" },\n" +
" \"Body\": {\n" +
" \"borrowNum\": \"JJY2022071xxxxxx1\",\n" +
" \"mchtNo\": \"xxxx\",\n" +
" \"orgTranDate\": \"\",\n" +
" \"orgTxnCode\": \"xxxx\",\n" +
" \"orgTranNo\": \"\",\n" +
" \"payProductCd\": \"xxxx\"\n" +
" }\n" +
"}";
String serverUrl = "localhost:11208/online/esb";
String rspJsonStr = HttpUtil.post(serverUrl, reqJSONStr, NewCoreProperties.REQ_TIME_OUT);
System.out.println(rspJsonStr);
}
@Test
public void esbTestQuery() {
String reqJSONStr = "{\n" +
" \"Head\": {\n" +
" \"ReqTm\": \"151454\",\n" +
" \"GloEndTm\": \"\",\n" +
" \"ReqCalCd\": \"701055\",\n" +
" \"ReqFl\": \"\",\n" +
" \"SvcVerNo\": \"10\",\n" +
" \"ReqSeqNo\": \"2022010201524132968199735815\",\n" +
" \"SvcNo\": \"P0210010\",\n" +
" \"ReqSysId\": \"SRCRE\",\n" +
" \"GloSeqNo\": \"GSRCRE2022010200000000666\",\n" +
" \"ScnVerNo\": \"10\",\n" +
" \"ReqDt\": \"20220102\",\n" +
" \"ScnNo\": \"01\"\n" +
" },\n" +
" \"Body\": {\n" +
" \"specificSuretyModel\": \"1\",\n" +
" \"creditPartyType\": \"2\",\n" +
" \"contractHandlingUserNum\": \"130322\",\n" +
" \"contractTotalAmt\": \"7000.0\",\n" +
" \"limitState\": \"3\",\n" +
" \"endDate\": \"2034-10-19\",\n" +
" \"repaymentName\": \"测试102099xxxxxx\",\n" +
" \"evalStatusCd\": \"3\",\n" +
" \"channel\": \"1\",\n" +
" \"contractHandlingOrgCd\": \"1303\",\n" +
" \"loanTerm\": \"12\",\n" +
" \"rateDays\": \"3\",\n" +
" \"borrowStatus\": \"3\",\n" +
" \"optionUserName\": \"潘利楠\",\n" +
" \"timesPayFlag\": \"1\",\n" +
" \"handlingOrgCd\": \"1303\",\n" +
" \"contractId\": \"MCONY2022xxxxx02\",\n" +
" \"gracePeriodInterestType\": \"2\",\n" +
" \"contractNum\": \"MCONY2022xxxxx02\",\n" +
" \"borrowId\": \"JJY2xxxxxx000002\",\n" +
" \"loanDirection\": \"1\",\n" +
" \"irNegoSymbCd\": \"3\",\n" +
" \"ifGracePeriod\": \"1\",\n" +
" \"applyDate\": \"2033-10-19\",\n" +
" \"businessType\": \"020203\"\n" +
" }\n" +
"}";
String serverUrl = "localhost:11208/online/esb";
String rspJsonStr = HttpUtil.post(serverUrl, reqJSONStr, NewCoreProperties.REQ_TIME_OUT);
System.out.println(rspJsonStr);
}
/**
* 测试BigDecimal
*/
public static void main(String[] args) {
}
}
测试结果图如下,最终返回信息为json字符串格式,格式要求也是复核esb要求的head,body格式
问题查询使用如下sql,所有请求统一使用同一全局流水,一个流水定位所有外部esb请求