@@ -93,6 +93,16 @@ task sampleProtocol(type:Jar){ | |||
dependsOn(classes) | |||
} | |||
task inssProtocol(type:Jar){ | |||
archiveBaseName='tj' | |||
archiveAppendix='inss-protocol' | |||
archiveVersion='1.0.0-SNAPSHOT' | |||
archiveExtension='jar' | |||
from("build/classes/java/main/cn/com/taiji/core/model/comm/protocol/inss") | |||
into('cn/com/taiji/core/model/comm/protocol/inss') | |||
dependsOn(classes) | |||
} | |||
task smpProtocol(type:Jar){ | |||
archiveBaseName='tj' | |||
archiveAppendix='smp-protocol' | |||
@@ -157,6 +167,13 @@ publishing { | |||
artifact sampleProtocol | |||
artifact packageCoreSrc | |||
} | |||
myPublicationInssProtocol(MavenPublication) { | |||
groupId ="${groupname}" | |||
artifactId ='inss-protocol' | |||
version ='1.0.0-SNAPSHOT' | |||
artifact inssProtocol | |||
artifact packageCoreSrc | |||
} | |||
myPublicationSmpProtocol(MavenPublication) { | |||
groupId ="${groupname}" | |||
artifactId ='smp-protocol' |
@@ -0,0 +1,126 @@ | |||
/* | |||
* Date: 2015年4月3日 author: Peream (peream@gmail.com) | |||
* | |||
*/ | |||
package cn.com.taiji.core.manager.comm; | |||
import cn.com.taiji.common.manager.AbstractManager; | |||
import cn.com.taiji.common.manager.net.http.ServiceHandleException; | |||
import cn.com.taiji.common.model.file.FileProtocolSystemError; | |||
import cn.com.taiji.common.pub.AssertUtil; | |||
import cn.com.taiji.core.model.comm.protocol.*; | |||
import com.google.common.collect.Maps; | |||
import com.zgglyun.common.manager.net.http.JsonPostHandleListener; | |||
import com.zgglyun.common.model.json.HandleJsonPostEvent; | |||
import com.zgglyun.common.model.json.JsonPostRequestInfo; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import javax.servlet.http.HttpServletRequest; | |||
import javax.servlet.http.HttpServletResponse; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.Map; | |||
public abstract class AbstractCommHandleManager extends AbstractManager implements JsonPostHandleManager { | |||
protected Logger logger = LoggerFactory.getLogger(getClass()); | |||
protected final List<SignServiceType> serviceTypes; | |||
protected final Map<SignServiceType, List<SignServiceCommand>> serviceMap = Maps.newConcurrentMap(); | |||
// json | |||
private final List<JsonPostHandleListener> jsonListeners = new ArrayList<>(); | |||
private final Map<SignServiceType, JsonPostServiceHandler<? extends SignServiceType>> jsonServices = | |||
Maps.newHashMap(); | |||
// bin | |||
protected AbstractCommHandleManager(SignServiceSystem serviceSystem) { | |||
this.serviceTypes = serviceSystem.listAllServices(); | |||
for (SignServiceType service : serviceTypes) { | |||
serviceMap.put(service, service.listAllCommands()); | |||
} | |||
} | |||
@Override | |||
public final SignJsonResponse handleComm(SignJsonRequest protocol, HttpServletRequest request, | |||
HttpServletResponse response) { | |||
// HandleJsonPostEvent event = HandleJsonPostEvent.newInstance(protocol, request); | |||
// HandleJsonPostEvent event = HandleJsonPostEvent.of().setRequest(protocol).setHttpRequest(request) | |||
// .setStartTime(LocalDateTime.now()); | |||
// long begin = System.currentTimeMillis(); | |||
JsonPostRequestInfo reqInfo = JsonPostRequestInfo.newInstance(request); | |||
try { | |||
checkProtocol(protocol); | |||
// if (!checkAuth(protocol, reqInfo)) | |||
// throw FileProtocolSystemError.AUTH_FAILED.toHandleException(protocol.getFilename()); | |||
// sendEvent(event.setResponse(rs).setExecTime(System.currentTimeMillis() - begin)); | |||
return handleRequest(protocol, reqInfo); | |||
} catch (ServiceHandleException e) { | |||
// JsonResponse rs = e.toJsonResponse(protocol); | |||
SignJsonResponse rs = new SignJsonResponse(e.getErrCode(), e.getMessage()); | |||
// .setBizContent(new JsonPostErrorResponse(protocol).toJson()); | |||
logger.warn("接口调用失败 statusCode:{},errorMsg:{},ifCode:{},reqId:{}", rs.getStatusCode(), rs.getErrorMsg(), | |||
protocol.getIfCode(), protocol.getReqId()); | |||
// sendEvent(event.setResponse(rs).setExecTime(System.currentTimeMillis() - begin)); | |||
return rs; | |||
} catch (Exception e) { | |||
logger.error("未知错误请排查:ifCode:{},reqId:{}" , protocol.getIfCode(),protocol.getReqId(), e); | |||
return handleError(FileProtocolSystemError.UNKNOWN_ERROR, e.getMessage(), protocol); | |||
} | |||
} | |||
@Override | |||
public <S extends SignServiceType> void registerJsonService(JsonPostServiceHandler<S> handler) { | |||
AssertUtil.notNull(handler, "JsonPostServiceHandler can not be null."); | |||
jsonServices.put(handler.getServiceType(), handler); | |||
} | |||
protected SignJsonResponse handleRequest(SignJsonRequest req, JsonPostRequestInfo reqInfo) | |||
throws ServiceHandleException { | |||
SignServiceType serviceType = checkCommRequest(req); | |||
JsonPostServiceHandler<?> handler = jsonServices.get(serviceType); | |||
if (handler == null) | |||
throw FileProtocolSystemError.NOT_SUPPORT.toHandleException("未注册的服务:" + serviceType); | |||
return handler.handleRequest(req.getProtocolClass(), req, reqInfo); | |||
} | |||
private SignJsonResponse handleError(FileProtocolSystemError error, String appendMsg, SignJsonRequest request) { | |||
// sendEvent(event.setResponse(rs).setExecTime(System.currentTimeMillis() - begin)); | |||
// rs.setBizContent(new JsonPostErrorResponse(request).toJson()); | |||
return new SignJsonResponse(error.getCode(), appendMsg); | |||
} | |||
private void sendEvent(HandleJsonPostEvent event) { | |||
for (JsonPostHandleListener listener : jsonListeners) { | |||
listener.jsonPostHandled(event); | |||
} | |||
} | |||
@Override | |||
public void addListener(JsonPostHandleListener listener) { | |||
if (listener != null) | |||
jsonListeners.add(listener); | |||
} | |||
/** | |||
* 检查请求协议 | |||
*/ | |||
protected SignServiceType checkCommRequest(SignJsonRequest req) throws ServiceHandleException { | |||
String ifCode = req.getIfCode(); | |||
SignServiceType serviceType = getServiceType(ifCode); | |||
if (serviceType == null) | |||
throw FileProtocolSystemError.NOT_SUPPORT.toHandleException(ifCode); | |||
SignServiceCommand cmd = getServiceCommand(ifCode, serviceMap.get(serviceType)); | |||
if (cmd == null) | |||
throw FileProtocolSystemError.NOT_SUPPORT | |||
.toHandleException(toLogString("{}服务不支持此命令,ifCode:{}", serviceType, ifCode)); | |||
req.setProtocolClass(cmd.getProtocolClass()); | |||
return serviceType; | |||
} | |||
private static SignServiceCommand getServiceCommand(String ifCode, List<SignServiceCommand> cmds) { | |||
return cmds.stream().filter(a -> a.isMyCommand(ifCode)).findFirst().orElse(null); | |||
} | |||
protected abstract SignServiceType getServiceType(String ifCode); | |||
} |
@@ -0,0 +1,43 @@ | |||
package cn.com.taiji.core.manager.comm; | |||
import cn.com.taiji.common.manager.net.http.ServiceHandleException; | |||
import cn.com.taiji.core.model.comm.protocol.*; | |||
import com.zgglyun.common.manager.net.http.BinCommUtil; | |||
import com.zgglyun.common.model.AbstractHttpRequestInfo; | |||
import com.zgglyun.common.model.json.JsonPostRequestInfo; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
public abstract class AbstractCommServiceHandler<S extends SignServiceType> | |||
implements JsonPostServiceHandler<S>, BinCommUtil { | |||
protected Logger logger = LoggerFactory.getLogger(getClass()); | |||
protected final S serviceType; | |||
protected AbstractCommServiceHandler(S serviceType) { | |||
super(); | |||
this.serviceType = serviceType; | |||
} | |||
@Override | |||
public final <T extends AbstractSignTypeRequest<?>> SignJsonResponse handleRequest(Class<T> clazz, | |||
SignJsonRequest req, JsonPostRequestInfo reqInfo) throws ServiceHandleException { | |||
String plainStr = req.getBizContent(); | |||
T request = json2Request(clazz, plainStr); | |||
// verifySign(signManager, req, request, signEncryptMode, event); | |||
baseValidate(request);// 基础格式校验// 网关来验签? | |||
AbstractSignTypeResponse rs = handleInternal(request, req, reqInfo); | |||
// jsonRs.setSign(signManager, rs, req, null, signEncryptMode, event);// 生成签名 | |||
return newSuccessJsonResponse(rs.toJson(), req.getReqId()); | |||
} | |||
/** | |||
* 业务逻辑处理 | |||
*/ | |||
protected abstract <T extends AbstractSignTypeRequest<?>> AbstractSignTypeResponse handleInternal(T request, | |||
SignJsonRequest commReq, AbstractHttpRequestInfo reqInfo) throws ServiceHandleException; | |||
@Override | |||
public final S getServiceType() { | |||
return serviceType; | |||
} | |||
} |
@@ -0,0 +1,65 @@ | |||
package cn.com.taiji.core.manager.comm; | |||
import cn.com.taiji.common.model.file.BinServiceResult; | |||
import cn.com.taiji.common.pub.AssertUtil; | |||
import cn.com.taiji.common.web.BaseController; | |||
import cn.com.taiji.core.model.comm.protocol.SignJsonRequest; | |||
import cn.com.taiji.core.model.comm.protocol.SignJsonResponse; | |||
import com.zgglyun.common.manager.net.http.handler.JsonServiceListener; | |||
import com.zgglyun.common.model.json.JsonServiceEvent; | |||
import javax.servlet.http.HttpServletRequest; | |||
import javax.servlet.http.HttpServletResponse; | |||
import java.io.IOException; | |||
public abstract class BaseJsonPostController extends BaseController { | |||
protected JsonServiceListener listener; | |||
protected BaseJsonPostController() { | |||
} | |||
protected BaseJsonPostController(JsonServiceListener listener) { | |||
this.listener = listener; | |||
} | |||
protected final void handleComm(SignJsonRequest req, String reqId, JsonPostHandleManager handleManager, | |||
HttpServletRequest request, HttpServletResponse response) throws IOException { | |||
long begin = System.currentTimeMillis(); | |||
AssertUtil.hasText(req.getIfCode(), "ifCode must be specified."); | |||
AssertUtil.hasText(reqId, "reqId must be specified."); | |||
long receiveTimeMs = System.currentTimeMillis() - begin; | |||
// 无法生成请求时,返回请求生成失败错误 | |||
SignJsonResponse rs = handleManager.handleComm(req, request, response); | |||
// long busTimeMs = System.currentTimeMillis() - begin - receiveTimeMs;//业务处理时间 | |||
// JsonServiceEvent event = JsonServiceEvent.newInstance(req, rs, request, receiveTimeMs); | |||
// event.setBusTimeMs(busTimeMs); | |||
try { | |||
responseJson(rs.toJson(), request, response); | |||
// if (JsonResponse.SUCCESS_CODE == rs.getStatusCode()) | |||
// sendEvent(event, BinServiceResult.SUCCESS, begin); | |||
// else | |||
// { | |||
// event.setErrorMsg(rs.getErrorMsg()); | |||
// sendEvent(event, BinServiceResult.HANDLE_FAILED, begin); | |||
// } | |||
} catch (IOException e) { | |||
logger.error("", e); | |||
// event.setErrorMsg("服务端已经成功处理,给客户端响应时网络异常"); | |||
// sendEvent(event, BinServiceResult.RESPONSE_FAILED, begin); | |||
throw e; | |||
} | |||
} | |||
protected void sendEvent(JsonServiceEvent event, BinServiceResult result, long begin) { | |||
if (listener == null) | |||
return; | |||
event.setResult(result).setExecTimeMs(System.currentTimeMillis() - begin); | |||
listener.onServiceFinished(event); | |||
} | |||
protected void setListener(JsonServiceListener listener) { | |||
this.listener = listener; | |||
} | |||
} |
@@ -0,0 +1,75 @@ | |||
/* | |||
* Date: 2019年7月29日 author: Peream | |||
* | |||
*/ | |||
package cn.com.taiji.core.manager.comm; | |||
import cn.com.taiji.common.manager.net.http.ServiceHandleException; | |||
import cn.com.taiji.common.model.BaseModel; | |||
import cn.com.taiji.common.model.file.FileProtocolSystemError; | |||
import cn.com.taiji.common.pub.json.JsonTools; | |||
import cn.com.taiji.core.model.comm.protocol.AbstractSignTypeRequest; | |||
import cn.com.taiji.core.model.comm.protocol.SignServiceType; | |||
import com.zgglyun.common.manager.net.http.BinCommUtil; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import javax.validation.ConstraintViolation; | |||
import javax.validation.Validation; | |||
import javax.validation.Validator; | |||
import javax.validation.groups.Default; | |||
import java.util.Set; | |||
/** | |||
* | |||
* @author Peream <br> | |||
* Create Time:2019年7月29日 上午8:27:57<br> | |||
* @since 1.0 | |||
* @version 1.0 | |||
*/ | |||
public interface CommServiceHandler<S extends SignServiceType> extends BinCommUtil { | |||
public static final String ENCODING = "UTF-8"; | |||
public static Logger myLogger = LoggerFactory.getLogger(CommServiceHandler.class); | |||
public static Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); | |||
default public Validator getValidator() { | |||
return validator; | |||
} | |||
public S getServiceType(); | |||
/** | |||
* 子类可通过覆盖此方法完成基础校验 | |||
* | |||
*/ | |||
default public <T extends AbstractSignTypeRequest<?>> void baseValidate(T t) throws ServiceHandleException { | |||
// verifySign(signManager, protocol, t);// 验签 | |||
Set<ConstraintViolation<T>> set = validator.validate(t, Default.class); | |||
if (set != null && !set.isEmpty()) { | |||
String jsonStr = violation2Json(set); | |||
throw new ServiceHandleException(jsonStr, 703); | |||
} | |||
} | |||
private <T extends AbstractSignTypeRequest<?>> String violation2Json(Set<ConstraintViolation<T>> cvs) { | |||
StringBuilder sb = new StringBuilder("{"); | |||
for (ConstraintViolation<?> cv : cvs) { | |||
sb.append("\"").append(cv.getPropertyPath()); | |||
sb.append("\":\"").append(cv.getMessage()).append("\","); | |||
} | |||
if (sb.length() > 1) | |||
sb.deleteCharAt(sb.length() - 1); | |||
sb.append("}"); | |||
return sb.toString(); | |||
} | |||
default public <T extends BaseModel> T json2Request(Class<T> clazz, String jsonStr) throws ServiceHandleException { | |||
try { | |||
return JsonTools.json2Object(jsonStr, clazz); | |||
} catch (Exception e) { | |||
myLogger.error("json解析错误:", e); | |||
throw FileProtocolSystemError.VALID_FAILED.toHandleException("请求的JSON格式不正确:" + e.getMessage()); | |||
} | |||
} | |||
} |
@@ -0,0 +1,55 @@ | |||
/* | |||
* Date: 2019年7月25日 author: Peream | |||
* | |||
*/ | |||
package cn.com.taiji.core.manager.comm; | |||
import cn.com.taiji.common.pub.StringTools; | |||
import cn.com.taiji.core.model.comm.protocol.SignJsonRequest; | |||
import cn.com.taiji.core.model.comm.protocol.SignJsonResponse; | |||
import cn.com.taiji.core.model.comm.protocol.SignServiceType; | |||
import com.zgglyun.common.manager.net.http.JsonPostHandleListener; | |||
import javax.servlet.http.HttpServletRequest; | |||
import javax.servlet.http.HttpServletResponse; | |||
/** | |||
* | |||
* @author Peream <br> | |||
* Create Time:2019年7月25日 下午10:25:10<br> | |||
* @since 1.0 | |||
* @version 1.0 | |||
*/ | |||
public interface JsonPostHandleManager { | |||
/** | |||
* 处理JsonPost请求 | |||
* | |||
*/ | |||
public SignJsonResponse handleComm(SignJsonRequest protocol, HttpServletRequest request, | |||
HttpServletResponse response); | |||
public void addListener(JsonPostHandleListener listener); | |||
/** | |||
* 注册服务 | |||
* | |||
*/ | |||
public <S extends SignServiceType> void registerJsonService(JsonPostServiceHandler<S> handler); | |||
default public void checkProtocol(SignJsonRequest jsonRequest) { | |||
if (!StringTools.hasText(jsonRequest.getIfCode())) | |||
throw new IllegalArgumentException("ifCode不能为空"); | |||
if (!StringTools.hasText(jsonRequest.getReqId())) | |||
throw new IllegalArgumentException("reqId不能为空"); | |||
if (jsonRequest.getSignType() == null) | |||
throw new IllegalArgumentException("signType不能为空"); | |||
if (!jsonRequest.getSignType().equals("NONE") && !StringTools.hasText(jsonRequest.getSign())) | |||
throw new IllegalArgumentException("需要验签时,sign不能为空"); | |||
if (jsonRequest.getEncryptType() == null) | |||
throw new IllegalArgumentException("encryptType不能为空"); | |||
if (jsonRequest.getTimestamp() == null) | |||
throw new IllegalArgumentException("timestamp必填"); | |||
if (!StringTools.hasText(jsonRequest.getBizContent())) | |||
throw new IllegalArgumentException("bizContent必填"); | |||
} | |||
} |
@@ -0,0 +1,39 @@ | |||
/* | |||
* Date: 2019年7月26日 author: Peream | |||
* | |||
*/ | |||
package cn.com.taiji.core.manager.comm; | |||
import cn.com.taiji.common.manager.net.http.ServiceHandleException; | |||
import cn.com.taiji.core.model.comm.protocol.AbstractSignTypeRequest; | |||
import cn.com.taiji.core.model.comm.protocol.SignJsonRequest; | |||
import cn.com.taiji.core.model.comm.protocol.SignJsonResponse; | |||
import cn.com.taiji.core.model.comm.protocol.SignServiceType; | |||
import com.zgglyun.common.model.json.JsonPostRequestInfo; | |||
import com.zgglyun.common.model.json.JsonResponse; | |||
/** | |||
* | |||
* @author Peream <br> | |||
* Create Time:2019年7月26日 上午1:39:28<br> | |||
* @since 1.0 | |||
* @version 1.0 | |||
*/ | |||
public interface JsonPostServiceHandler<S extends SignServiceType> extends CommServiceHandler<S> { | |||
/** | |||
* 处理请求 | |||
* | |||
* @param clazz | |||
* 请求具体协议的类型 | |||
* @param req | |||
* JsonRequest请求 | |||
*/ | |||
public <T extends AbstractSignTypeRequest<?>> SignJsonResponse handleRequest(Class<T> clazz, SignJsonRequest req, | |||
JsonPostRequestInfo reqInfo) throws ServiceHandleException; | |||
default public SignJsonResponse newSuccessJsonResponse(String bizContent,String reqId) { | |||
return new SignJsonResponse(JsonResponse.SUCCESS_CODE, "请求成功").setBizContent(bizContent).setReqId(reqId); | |||
} | |||
} |
@@ -1,8 +1,6 @@ | |||
package cn.com.taiji.core.manager.comm.client.feign; | |||
import com.zgglyun.common.model.EncryptType; | |||
import com.zgglyun.common.model.SignEncryptMode; | |||
import com.zgglyun.common.model.SignType; | |||
import lombok.Data; | |||
import org.springframework.boot.context.properties.ConfigurationProperties; | |||
import org.springframework.stereotype.Component; | |||
@@ -19,9 +17,9 @@ import java.util.Map; | |||
public class CommConfigProperties { | |||
private String appId; | |||
private String appSecret; | |||
private EncryptType encryptType; | |||
private String encryptType; | |||
private String password; | |||
private SignType signType; | |||
private String signType; | |||
private String version; | |||
private String serverPublicKey; | |||
private String selfPrivateKey; |
@@ -3,7 +3,7 @@ package cn.com.taiji.core.manager.comm.client.feign; | |||
import cn.com.taiji.common.manager.AbstractManager; | |||
import cn.com.taiji.common.model.file.FileProtocolConstant; | |||
import cn.com.taiji.common.pub.json.JsonTools; | |||
import com.zgglyun.common.model.json.JsonRequest; | |||
import cn.com.taiji.core.model.comm.protocol.SignJsonRequest; | |||
import feign.RequestInterceptor; | |||
import feign.RequestTemplate; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
@@ -17,10 +17,9 @@ public class FeignClientInterceptor extends AbstractManager implements RequestIn | |||
@Override | |||
public void apply(RequestTemplate template) { | |||
String json = new String(template.body(), template.requestCharset()); | |||
JsonRequest jsonRequest = JsonTools.json2ObjectSilent(json, JsonRequest.class); | |||
String fileName = jsonRequest.getFilename().replace(".", FileProtocolConstant.DOT_REPLACE.getValue()); | |||
template.uri(template.url() + fileName); | |||
SignJsonRequest jsonRequest = JsonTools.json2ObjectSilent(json, SignJsonRequest.class); | |||
// template.uri(template.url() + jsonRequest.getReqId()); | |||
template.header(FileProtocolConstant.AUTH_HEADER.getValue(), commConfig.getAuthStr()); | |||
} | |||
} | |||
} |
@@ -1,22 +1,24 @@ | |||
package cn.com.taiji.core.manager.comm.client.feign; | |||
import cn.com.taiji.core.model.comm.protocol.*; | |||
import com.zgglyun.common.manager.net.http.EncryptException; | |||
import com.zgglyun.common.model.comm.protocol.AbstractBinRequest; | |||
import com.zgglyun.common.model.comm.protocol.AbstractBinResponse; | |||
import com.zgglyun.common.model.comm.protocol.AbstractNestTypeRequest; | |||
import com.zgglyun.common.model.comm.protocol.AbstractTypeRequest; | |||
import com.zgglyun.common.model.json.JsonRequest; | |||
import java.io.IOException; | |||
public interface FeignClientManager { | |||
<T extends AbstractBinResponse> T jsonTypePost(AbstractTypeRequest<T> req) throws IOException; | |||
<T extends AbstractSignTypeResponse> T jsonTypePost(AbstractSignTypeRequest<T> req) throws IOException; | |||
<T extends AbstractBinResponse> T jsonTypePost(AbstractNestTypeRequest<T> req) throws IOException; | |||
<RE extends AbstractBinRequest, RS extends AbstractBinResponse> RS jsonPost(RE req, Class<RS> clazz) | |||
<RE extends AbstractSignTypeRequest<?>, RS extends AbstractSignTypeResponse> RS jsonPost(RE req, | |||
Class<RS> clazz) throws IOException; | |||
<T extends AbstractSignTypeResponse> T jsonTypePost(AbstractSignTypeRequest<T> req, String ifCode, String accessToken) throws IOException; | |||
<RE extends AbstractOldSystemRequest<RS>, RS> RS jsonPost(RE req, String accessToken) throws IOException; | |||
<RE extends AbstractSignTypeRequest<?>, RS extends AbstractSignTypeResponse> RS jsonPost(RE req, Class<RS> clazz, String ifCode, String accessToken) | |||
throws IOException; | |||
<RE extends AbstractBinRequest> JsonRequest createJsonRequest(RE req) throws EncryptException; | |||
<RE extends AbstractSignTypeRequest<?>> SignJsonRequest createJsonRequest(RE req, String ifCode, String accessToken) throws EncryptException; | |||
} |
@@ -3,23 +3,20 @@ package cn.com.taiji.core.manager.comm.client.feign; | |||
import cn.com.taiji.common.manager.AbstractManager; | |||
import cn.com.taiji.common.manager.net.http.binclient.ApiRequestException; | |||
import cn.com.taiji.common.model.file.FileProtocolSystemError; | |||
import cn.com.taiji.common.pub.AssertUtil; | |||
import cn.com.taiji.common.pub.TimeTools; | |||
import cn.com.taiji.common.pub.json.JsonTools; | |||
import cn.com.taiji.core.manager.tools.sm4.SM4Utils; | |||
import cn.com.taiji.core.model.comm.protocol.*; | |||
import cn.hutool.json.JSONUtil; | |||
import com.zgglyun.common.manager.net.http.EncryptException; | |||
import com.zgglyun.common.manager.net.http.client.HttpCommClient; | |||
import com.zgglyun.common.model.BaseProtocolRequestPara; | |||
import com.zgglyun.common.model.ServiceSystem; | |||
import com.zgglyun.common.model.comm.protocol.*; | |||
import com.zgglyun.common.model.json.JsonPostErrorResponse; | |||
import com.zgglyun.common.model.json.JsonPostRequestPara; | |||
import com.zgglyun.common.model.json.JsonRequest; | |||
import com.zgglyun.common.model.json.JsonResponse; | |||
import com.zgglyun.common.pub.SignException; | |||
import org.apache.commons.lang3.RandomStringUtils; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.beans.factory.annotation.Value; | |||
import org.springframework.stereotype.Service; | |||
import javax.annotation.PostConstruct; | |||
import java.io.IOException; | |||
import java.lang.reflect.Type; | |||
import java.time.LocalDateTime; | |||
import java.util.Map; | |||
import java.util.concurrent.ConcurrentHashMap; | |||
@@ -31,138 +28,183 @@ import java.util.concurrent.ConcurrentHashMap; | |||
*/ | |||
@Service | |||
public class FeignClientManagerImpl extends AbstractManager implements FeignClientManager { | |||
public static String GATEWAY_SERVICE_NAME = "gateway"; | |||
@Value("${app.nodeNum}") | |||
private String nodeNum; | |||
public static SignServiceSystem GATEWAY_SYSTEM = IfztServiceSystem.IFZT; | |||
@Autowired | |||
private CommConfigProperties commConfig; | |||
@Autowired | |||
private DynamicFeignClientFactory<FeignCommClient> feignClientFactory; | |||
private SenderGenerator senderGenerator; | |||
private JsonPostRequestPara jsonPostRequestPara; | |||
private final Map<ServiceSystem, FeignCommClient> clientCache = new ConcurrentHashMap<>(); | |||
private final Map<SignServiceSystem, FeignCommClient> clientCache = new ConcurrentHashMap<>(); | |||
@PostConstruct | |||
public void init() { | |||
senderGenerator = createSenderGenerator(); | |||
jsonPostRequestPara = createJsonRequestPara(); | |||
@Override | |||
public <T extends AbstractSignTypeResponse> T jsonTypePost(AbstractSignTypeRequest<T> req) throws IOException { | |||
return jsonPost(req, req.getResponseType(), null, null); | |||
} | |||
@Override | |||
public <T extends AbstractBinResponse> T jsonTypePost(AbstractTypeRequest<T> req) throws IOException { | |||
return jsonPost(req, req.getResponseType()); | |||
public <RE extends AbstractSignTypeRequest<?>, RS extends AbstractSignTypeResponse> RS jsonPost(RE req, | |||
Class<RS> clazz) throws IOException { | |||
return jsonPost(req, clazz, null, null); | |||
} | |||
@Override | |||
public <T extends AbstractBinResponse> T jsonTypePost(AbstractNestTypeRequest<T> req) throws IOException { | |||
return jsonPost(req, req.getResponseType()); | |||
public <T extends AbstractSignTypeResponse> T jsonTypePost(AbstractSignTypeRequest<T> req, String ifCode, | |||
String accessToken) throws IOException { | |||
return jsonPost(req, req.getResponseType(), ifCode, accessToken); | |||
} | |||
@Override | |||
public <RE extends AbstractBinRequest, RS extends AbstractBinResponse> RS jsonPost(RE req, Class<RS> clazz) | |||
throws IOException { | |||
JsonRequest jsonReq = createJsonRequest(req); | |||
ServiceSystem serviceSystem = req.getServiceCommand().getServiceType().getServiceSystem(); | |||
public <RE extends AbstractSignTypeRequest<?>, RS extends AbstractSignTypeResponse> RS jsonPost(RE req, | |||
Class<RS> clazz, String ifCode, String accessToken) throws IOException { | |||
SignServiceSystem serviceSystem; | |||
if (ifCode != null) { | |||
serviceSystem = GATEWAY_SYSTEM; | |||
} else { | |||
serviceSystem = req.getServiceCommand().getServiceType().getServiceSystem(); | |||
} | |||
FeignCommClient client = clientCache.computeIfAbsent(serviceSystem, a -> { | |||
Map<String, String> serviceAddrMap = commConfig.getServiceAddr(); | |||
String serviceName = | |||
serviceAddrMap.containsKey(serviceSystem.getAppId()) ? serviceSystem.getAppId() : GATEWAY_SERVICE_NAME; | |||
return feignClientFactory.getFeignClient(FeignCommClient.class, serviceName, serviceSystem.getJsonUri()); | |||
boolean isCustomService = serviceAddrMap.containsKey(serviceSystem.getAppId()); | |||
if (isCustomService) { | |||
return feignClientFactory.getFeignClient(FeignCommClient.class, serviceSystem.getAppId(), | |||
serviceSystem.getJsonUri()); | |||
} | |||
return feignClientFactory.getFeignClient(FeignCommClient.class, GATEWAY_SYSTEM.getAppId(), | |||
GATEWAY_SYSTEM.getJsonUri()); | |||
}); | |||
JsonResponse jsonRes = client.jsonApi(jsonReq); | |||
return handleJsonResponse(jsonRes, jsonPostRequestPara, clazz, jsonReq, req, req.getFilename()); | |||
SignJsonRequest jsonReq = createJsonRequest(req, ifCode, accessToken); | |||
SignJsonResponse jsonRes = client.jsonApi(jsonReq); | |||
return handleJsonResponse(jsonRes, clazz, jsonReq, req); | |||
} | |||
@Override | |||
public <RE extends AbstractOldSystemRequest<RS>, RS> RS jsonPost(RE req, String accessToken) throws IOException { | |||
FeignCommClient client = feignClientFactory.getFeignClient(FeignCommClient.class, GATEWAY_SYSTEM.getAppId(), | |||
GATEWAY_SYSTEM.getJsonUri()); | |||
SignJsonRequest jsonReq = createOldSystemRequest(req, accessToken); | |||
SignJsonResponse jsonRes = client.jsonApi(jsonReq); | |||
return handleOldSystemResponse(jsonRes, req.getResponseType(), jsonReq, req); | |||
} | |||
@Override | |||
public <RE extends AbstractBinRequest> JsonRequest createJsonRequest(RE req) throws EncryptException { | |||
req.setSenderGenerator(senderGenerator); | |||
JsonRequest jsonReq = jsonPostRequestPara.toJsonRequest(req.getFilename()); | |||
// logger.debug("filename:{}\t reqFilename:{}", filename, jsonReq.getFilename()); | |||
jsonReq.setBizContent(req.toJson()).encrypyBizContent(jsonPostRequestPara.getPassword());// 设置业务内容并按要求加密 | |||
jsonReq.setSign(req, jsonPostRequestPara);// 设置签名值 | |||
public <RE extends AbstractSignTypeRequest<?>> SignJsonRequest createJsonRequest(RE req, String ifCode, | |||
String accessToken) { | |||
String reqId = commConfig.getAppId() + "_" + LocalDateTime.now().format(TimeTools.yyyyMMddHHmmssSSS) + "_" | |||
+ RandomStringUtils.randomNumeric(5); | |||
req.setReqId(reqId); | |||
SignJsonRequest jsonReq = new SignJsonRequest(); | |||
jsonReq.setAppId(commConfig.getAppId()); | |||
if (hasText(ifCode)) { | |||
jsonReq.setIfCode(ifCode); | |||
} else { | |||
jsonReq.setIfCode(req.getServiceCommand().getIfCode()); | |||
} | |||
jsonReq.setReqId(reqId); | |||
jsonReq.setTimestamp(LocalDateTime.now().format(TimeTools.ISO_LOCAL_DATE_TIME)); | |||
jsonReq.setEncryptType(commConfig.getEncryptType()); | |||
jsonReq.setSignType(commConfig.getSignType()); | |||
jsonReq.setBizContent(req.toJson());// 设置业务内容并按要求加密 | |||
if(commConfig.getEncryptType().equals("SM4")){ | |||
jsonReq.setBizContent(SM4Utils.encryptECB(jsonReq.getBizContent(), commConfig.getSelfPrivateKey())); | |||
} | |||
if (hasText(accessToken)) { | |||
jsonReq.setAccessToken(accessToken); | |||
} | |||
jsonReq.setSign(jsonReq.toSignContent(commConfig.getServerPublicKey())); | |||
return jsonReq; | |||
} | |||
private <RE extends AbstractBinRequest, RS extends AbstractBinResponse> RS handleJsonResponse(JsonResponse jsonRes, | |||
BaseProtocolRequestPara para, Class<RS> clazz, JsonRequest jsonReq, RE req, String filename) | |||
throws IOException { | |||
private <RE extends AbstractSignTypeRequest<?>, RS extends AbstractSignTypeResponse> RS handleJsonResponse( | |||
SignJsonResponse jsonRes, Class<RS> clazz, SignJsonRequest jsonReq, RE req) throws IOException { | |||
if (jsonRes == null) { | |||
logger.error("jsonRes is null!!! filename:{}", filename); | |||
JsonResponse rs = new JsonResponse(FileProtocolSystemError.UNKNOWN_ERROR, "调用接口返回空"); | |||
rs.setBizContent(new JsonPostErrorResponse(jsonReq).toJson()); | |||
logger.error("jsonRes is null ifCode:{},reqId:{}", jsonReq.getIfCode(), jsonReq.getReqId()); | |||
SignJsonResponse rs = new SignJsonResponse(FileProtocolSystemError.UNKNOWN_ERROR.getCode(), "调用接口返回空"); | |||
throw new ApiRequestException(rs.toJson(), rs.getStatusCode()); | |||
} | |||
if (JsonResponse.SUCCESS_CODE != jsonRes.getStatusCode()) { | |||
if (SignJsonResponse.SUCCESS_CODE != jsonRes.getStatusCode()) { | |||
throw new ApiRequestException(jsonRes.toJson(), jsonRes.getStatusCode()); | |||
} | |||
// 成功时返回具体类型 | |||
// 成功时返回具体类型 | |||
RS rs = decryptBizContent(jsonRes, para, clazz, req); | |||
boolean verifyResult = false; | |||
switch (para.getSignEncryptMode()) { | |||
case SIGN_ENCRYPT:// 默认 | |||
verifyResult = | |||
jsonReq.getSignType().verify(para.getServerPublicKey(), rs, null, jsonRes.getSign(), null);// 验签 | |||
break; | |||
case ENCRYPT_SIGN: | |||
verifyResult = | |||
jsonReq.getSignType().verify(para.getServerPublicKey(), jsonRes, jsonRes.getSign(), null); | |||
break; | |||
default: | |||
break; | |||
} | |||
RS rs = decryptBizContent(jsonRes, clazz, req); | |||
boolean verifyResult = verify(commConfig.getServerPublicKey(), null, jsonRes.getSign()); | |||
if (!verifyResult) { | |||
throw new ApiRequestException("处理返回时验签失败:" + filename, FileProtocolSystemError.SIGN_FAILED.getCode()); | |||
throw new ApiRequestException("处理返回时验签失败:" + jsonReq.getReqId(), | |||
FileProtocolSystemError.SIGN_FAILED.getCode()); | |||
} | |||
return rs; | |||
} | |||
public static <RE extends AbstractBinRequest, RS extends AbstractBinResponse> RS | |||
decryptBizContent(JsonResponse jsonRes, BaseProtocolRequestPara para, Class<RS> clazz, RE req) | |||
throws IOException, ApiRequestException { | |||
AssertUtil.allElementsHasValue(para.getEncryptType(), jsonRes); | |||
String jsonStr = para.getEncryptType().decrypt(jsonRes.getBizContent(), para.getPassword()); | |||
if (WrapModelResponse.class.isAssignableFrom(clazz) || // | |||
WrapListResponse.class.isAssignableFrom(clazz) || // | |||
WrapPagnResponse.class.isAssignableFrom(clazz) || // | |||
WrapLargePagnResponse.class.isAssignableFrom(clazz)) { | |||
AbstractNestTypeRequest<?> nestReq = (AbstractNestTypeRequest<?>)req; | |||
return JsonTools.json2Object(jsonStr, clazz, nestReq.getModelType()); | |||
} else { | |||
return JsonTools.json2Object(jsonStr, clazz); | |||
public <RE extends AbstractSignTypeRequest<?>, RS extends AbstractSignTypeResponse> RS | |||
decryptBizContent(SignJsonResponse jsonRes, Class<RS> clazz, RE req) throws IOException, ApiRequestException { | |||
String jsonStr = jsonRes.getBizContent(); | |||
if(commConfig.getEncryptType().equals("SM4")){ | |||
jsonStr= SM4Utils.decrypt(jsonRes.getBizContent(), commConfig.getPassword(),false); | |||
} | |||
RS rs = JsonTools.json2Object(jsonStr, clazz); | |||
rs.setBizContent(jsonStr); | |||
return rs; | |||
} | |||
private JsonPostRequestPara createJsonRequestPara() { | |||
JsonPostRequestPara para = new JsonPostRequestPara(); | |||
para.setSignEncryptMode(commConfig.getSignEncryptMode()); | |||
para.setVersion(HttpCommClient.DEFAULT_VEERFSION); | |||
para.setEncryptType(commConfig.getEncryptType()); | |||
para.setPassword(commConfig.getPassword()); | |||
para.setSignType(commConfig.getSignType()); | |||
para.setServerPublicKey(commConfig.getServerPublicKey()); | |||
para.setSelfPrivateKey(commConfig.getSelfPrivateKey()); | |||
para.setDeleteTmpFile(commConfig.isDeleteTmpFile()); | |||
return para; | |||
public boolean verify(String pubKeyBase64, String signContent, String signValue) { | |||
return true; | |||
} | |||
private <RE extends AbstractOldSystemRequest<RS>, RS> SignJsonRequest createOldSystemRequest(RE req, | |||
String accessToken) { | |||
if (!hasText(req.getIfCode())) { | |||
throw new ApiRequestException("ifCode IS NULL", FileProtocolSystemError.REQ_DATA_ERR.getCode()); | |||
} | |||
String reqId = commConfig.getAppId() + "_" + LocalDateTime.now().format(TimeTools.yyyyMMddHHmmssSSS) + "_" | |||
+ RandomStringUtils.randomNumeric(5); | |||
req.setReqId(reqId); | |||
SignJsonRequest jsonReq = new SignJsonRequest(); | |||
jsonReq.setAppId(commConfig.getAppId()); | |||
jsonReq.setIfCode(req.getIfCode()); | |||
jsonReq.setReqId(reqId); | |||
jsonReq.setTimestamp(LocalDateTime.now().format(TimeTools.ISO_LOCAL_DATE_TIME)); | |||
jsonReq.setEncryptType(commConfig.getEncryptType()); | |||
jsonReq.setSignType(commConfig.getSignType()); | |||
jsonReq.setBizContent(req.toJson());// 设置业务内容并按要求加密 | |||
if(commConfig.getEncryptType().equals("SM4")){ | |||
jsonReq.setBizContent(SM4Utils.encrypt(commConfig.getPassword(), jsonReq.getBizContent(),false)); | |||
} | |||
if (hasText(accessToken)) { | |||
jsonReq.setAccessToken(accessToken); | |||
} | |||
jsonReq.setSign(jsonReq.toSignContent(commConfig.getServerPublicKey())); | |||
return jsonReq; | |||
} | |||
private SenderGenerator createSenderGenerator() { | |||
return new SenderGenerator() { | |||
@Override | |||
public String getSender() { | |||
return commConfig.getAppId(); | |||
} | |||
private <RE extends AbstractOldSystemRequest<RS>, RS> RS handleOldSystemResponse(SignJsonResponse jsonRes, | |||
Type clazz, SignJsonRequest jsonReq, RE req) { | |||
if (jsonRes == null) { | |||
logger.error("jsonRes is null ifCode:{},reqId:{}", jsonReq.getIfCode(), jsonReq.getReqId()); | |||
SignJsonResponse rs = new SignJsonResponse(FileProtocolSystemError.UNKNOWN_ERROR.getCode(), "调用接口返回空"); | |||
throw new ApiRequestException(rs.toJson(), rs.getStatusCode()); | |||
} | |||
if (SignJsonResponse.SUCCESS_CODE != jsonRes.getStatusCode()) { | |||
throw new ApiRequestException(jsonRes.toJson(), jsonRes.getStatusCode()); | |||
} | |||
// 成功时返回具体类型 | |||
String jsonStr = jsonRes.getBizContent(); | |||
if(commConfig.getEncryptType().equals("SM4")){ | |||
jsonStr= SM4Utils.decrypt(jsonRes.getBizContent(), commConfig.getPassword(),false); | |||
} | |||
RS rs = JSONUtil.toBean(jsonStr, clazz, false); | |||
@Override | |||
public String getNodeNum() { | |||
return nodeNum; | |||
} | |||
}; | |||
boolean verifyResult = verify(commConfig.getServerPublicKey(), null, jsonRes.getSign()); | |||
if (!verifyResult) { | |||
throw new ApiRequestException("处理返回时验签失败:" + jsonReq.getReqId(), | |||
FileProtocolSystemError.SIGN_FAILED.getCode()); | |||
} | |||
return rs; | |||
} | |||
public static <RE extends AbstractReqIdTypeRequest, RS> RS decryptReqIdBizContent(SignJsonResponse jsonRes, | |||
Class<RS> clazz, RE req) throws ApiRequestException { | |||
// TODO 解密 | |||
String jsonStr = jsonRes.getBizContent(); | |||
return JSONUtil.toBean(jsonStr, clazz); | |||
} | |||
} |
@@ -1,11 +1,8 @@ | |||
package cn.com.taiji.core.manager.comm.client.feign; | |||
import com.zgglyun.common.model.json.JsonRequest; | |||
import com.zgglyun.common.model.json.JsonResponse; | |||
import cn.com.taiji.core.model.comm.protocol.SignJsonRequest; | |||
import cn.com.taiji.core.model.comm.protocol.SignJsonResponse; | |||
import org.springframework.web.bind.annotation.PostMapping; | |||
import java.io.IOException; | |||
/** | |||
* <pre> | |||
* FeignClient注解的name为字面量值gateway或ServiceSystem的appId,例如:sampleService | |||
@@ -15,9 +12,9 @@ import java.io.IOException; | |||
* | |||
* </pre> | |||
*/ | |||
//@FeignClient(name = "feignClient", url = "dynamic") | |||
//@FeignClient(name = "ifzt", path = "/api/interfaceMidGroundIn", contextId = "core.ifzt") | |||
public interface FeignCommClient { | |||
@PostMapping({""}) | |||
JsonResponse jsonApi(JsonRequest jsonRequest) throws IOException; | |||
SignJsonResponse jsonApi(SignJsonRequest jsonRequest); | |||
} |
@@ -0,0 +1,15 @@ | |||
package cn.com.taiji.core.manager.comm.client.feign; | |||
import cn.com.taiji.core.model.comm.protocol.SignJsonRequest; | |||
import cn.com.taiji.core.model.comm.protocol.SignJsonResponse; | |||
import org.springframework.cloud.openfeign.FeignClient; | |||
import org.springframework.web.bind.annotation.RequestMapping; | |||
import org.springframework.web.bind.annotation.RequestMethod; | |||
@FeignClient(name = "ifzt", path = "/api/interfaceMidGroundIn", contextId = "core.ifzt") | |||
public interface IfztClient { | |||
@RequestMapping(method = RequestMethod.POST) | |||
public SignJsonResponse jsonApi(SignJsonRequest jsonRequest); | |||
} |
@@ -0,0 +1,33 @@ | |||
package cn.com.taiji.core.model.comm.protocol; | |||
import cn.com.taiji.common.model.BaseModel; | |||
import com.fasterxml.jackson.annotation.JsonIgnore; | |||
import lombok.Getter; | |||
import lombok.Setter; | |||
import java.lang.reflect.ParameterizedType; | |||
import java.lang.reflect.Type; | |||
/** | |||
* 请求老系统的协议父类,用来替代AbstractReqIdTypeRequest | |||
*/ | |||
@Getter | |||
public abstract class AbstractOldSystemRequest<R> extends BaseModel { | |||
@Setter | |||
private String reqId; | |||
@Setter | |||
private String ifCode; | |||
@JsonIgnore | |||
private final Type responseType; | |||
@JsonIgnore | |||
private final SignServiceCommand serviceCommand; | |||
// ParameterizedTypeImpl | |||
protected AbstractOldSystemRequest(String ifCode, SignServiceCommand serviceCommand) { | |||
this.ifCode = ifCode; | |||
this.serviceCommand = serviceCommand; | |||
ParameterizedType parameterizedType = (ParameterizedType)getClass().getGenericSuperclass(); | |||
responseType = parameterizedType.getActualTypeArguments()[0]; | |||
} | |||
} |
@@ -0,0 +1,25 @@ | |||
package cn.com.taiji.core.model.comm.protocol; | |||
import cn.com.taiji.common.model.BaseModel; | |||
import com.fasterxml.jackson.annotation.JsonIgnore; | |||
/** | |||
* @Author ChenChao | |||
* @Date 2024/9/25 13:08 | |||
* @Description 无参数化(response)、无三段式的request | |||
*/ | |||
public abstract class AbstractReqIdTypeRequest extends BaseModel { | |||
@JsonIgnore | |||
protected String reqId; | |||
public String getReqId() { | |||
return reqId; | |||
} | |||
public void setReqId(String reqId) { | |||
// if (this.reqId != null) { | |||
// throw new RuntimeException("不允许设置reqId"); | |||
// } | |||
this.reqId = reqId; | |||
} | |||
} |
@@ -0,0 +1,50 @@ | |||
package cn.com.taiji.core.model.comm.protocol; | |||
import cn.com.taiji.common.model.BaseModel; | |||
import com.fasterxml.jackson.annotation.JsonIgnore; | |||
import com.zgglyun.common.pub.CommonUtil; | |||
import lombok.Setter; | |||
import java.lang.reflect.ParameterizedType; | |||
/** | |||
* 参数化(response)的request | |||
* | |||
* @author lijun <br> | |||
* Create Time:2018年9月25日 下午7:56:24<br> | |||
* | |||
* @since 1.0 | |||
* @version 1.0 | |||
*/ | |||
public abstract class AbstractSignTypeRequest<R extends AbstractSignTypeResponse> extends BaseModel | |||
implements CommonUtil { | |||
@JsonIgnore | |||
protected final Class<R> responseType; | |||
@JsonIgnore | |||
protected final SignServiceCommand serviceCommand; | |||
// if (this.reqId != null) { | |||
// throw new RuntimeException("不允许设置reqId"); | |||
// } | |||
@Setter | |||
protected String reqId; | |||
@SuppressWarnings("unchecked") | |||
protected AbstractSignTypeRequest(SignServiceCommand serviceCommand) { | |||
this.serviceCommand = serviceCommand; | |||
ParameterizedType parameterizedType = (ParameterizedType)getClass().getGenericSuperclass(); | |||
responseType = (Class<R>)parameterizedType.getActualTypeArguments()[0]; | |||
} | |||
public Class<R> getResponseType() { | |||
return responseType; | |||
} | |||
public SignServiceCommand getServiceCommand() { | |||
return serviceCommand; | |||
} | |||
public String getReqId() { | |||
return reqId; | |||
} | |||
} |
@@ -0,0 +1,11 @@ | |||
package cn.com.taiji.core.model.comm.protocol; | |||
import cn.com.taiji.common.model.BaseModel; | |||
import lombok.Getter; | |||
import lombok.Setter; | |||
@Getter | |||
@Setter | |||
public class AbstractSignTypeResponse extends BaseModel { | |||
private String bizContent; | |||
} |
@@ -0,0 +1,40 @@ | |||
package cn.com.taiji.core.model.comm.protocol; | |||
import java.util.List; | |||
public enum IfztServiceSystem implements SignServiceSystem { | |||
IFZT("ifzt", "业务中台", "/api/interfaceMidGroundIn"); | |||
private final String appId;// 微服务环境当做注册中心的服务名 | |||
private final String appName; | |||
private final String jsonUri; | |||
IfztServiceSystem(String appId, String appName, String jsonUri) { | |||
this.appId = appId; | |||
this.appName = appName; | |||
this.jsonUri = jsonUri; | |||
} | |||
@Override | |||
public List<SignServiceType> listAllServices() { | |||
return null; | |||
} | |||
@Override | |||
public String getAppId() { | |||
return appId; | |||
} | |||
@Override | |||
public String getAppName() { | |||
return appName; | |||
} | |||
@Override | |||
public String getJsonUri() { | |||
return jsonUri; | |||
} | |||
} |
@@ -0,0 +1,136 @@ | |||
package cn.com.taiji.core.model.comm.protocol; | |||
import org.bouncycastle.crypto.digests.SM3Digest; | |||
import org.bouncycastle.crypto.macs.HMac; | |||
import org.bouncycastle.crypto.params.KeyParameter; | |||
import org.bouncycastle.jce.provider.BouncyCastleProvider; | |||
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils; | |||
import java.io.UnsupportedEncodingException; | |||
import java.security.Security; | |||
import java.util.Arrays; | |||
public class SM3Utils { | |||
private static final String ENCODING = "UTF-8"; | |||
static { | |||
Security.addProvider(new BouncyCastleProvider()); | |||
} | |||
/** | |||
* sm3算法加密 | |||
* | |||
* @param paramStr 待加密字符串 | |||
* @return 返回加密后,固定长度=32的16进制字符串 | |||
* @explain | |||
*/ | |||
public static String encrypt(String paramStr) { | |||
// 将返回的hash值转换成16进制字符串 | |||
String resultHexString = ""; | |||
try { | |||
// 将字符串转换成byte数组 | |||
byte[] srcData = paramStr.getBytes(ENCODING); | |||
// 调用hash() | |||
byte[] resultHash = hash(srcData); | |||
// 将返回的hash值转换成16进制字符串 | |||
// 将返回的hash值转化为string类型的字符串 | |||
resultHexString = ByteUtils.toHexString(resultHash); | |||
} catch (UnsupportedEncodingException e) { | |||
e.printStackTrace(); | |||
} | |||
return resultHexString; | |||
} | |||
/** | |||
* 返回长度=32的byte数组 | |||
* | |||
* @param srcData | |||
* @return | |||
* @explain 生成对应的hash值 | |||
*/ | |||
public static byte[] hash(byte[] srcData) { | |||
SM3Digest digest = new SM3Digest(); | |||
digest.update(srcData, 0, srcData.length); | |||
byte[] hash = new byte[digest.getDigestSize()]; | |||
digest.doFinal(hash, 0); | |||
return hash; | |||
} | |||
/** | |||
* sm3算法加密 | |||
* | |||
* @param paramStr 待加密字符串 | |||
* @param key 密钥 | |||
* @return 返回加密后,固定长度=32的16进制字符串 | |||
* @explain | |||
*/ | |||
public static String encryptPlus(String paramStr, String key) { | |||
// 将返回的hash值转换成16进制字符串 | |||
String resultHexString = ""; | |||
try { | |||
// 将字符串转换成byte数组 | |||
byte[] srcData = paramStr.getBytes(ENCODING); | |||
// 调用hash() | |||
byte[] resultHash = hmac(key.getBytes(ENCODING), srcData); | |||
// 将返回的hash值转换成16进制字符串 | |||
resultHexString = ByteUtils.toHexString(resultHash); | |||
} catch (UnsupportedEncodingException e) { | |||
e.printStackTrace(); | |||
} | |||
return resultHexString; | |||
} | |||
/** | |||
* 通过密钥进行加密 | |||
* | |||
* @param key 密钥 | |||
* @param srcData 被加密的byte数组 | |||
* @return | |||
* @explain 指定密钥进行加密 | |||
*/ | |||
public static byte[] hmac(byte[] key, byte[] srcData) { | |||
KeyParameter keyParameter = new KeyParameter(key); | |||
SM3Digest digest = new SM3Digest(); | |||
HMac mac = new HMac(digest); | |||
mac.init(keyParameter); | |||
mac.update(srcData, 0, srcData.length); | |||
byte[] result = new byte[mac.getMacSize()]; | |||
mac.doFinal(result, 0); | |||
return result; | |||
} | |||
/** | |||
* 判断源数据与加密数据是否一致 | |||
* | |||
* @param srcStr 原字符串 | |||
* @param sm3HexString 16进制字符串 | |||
* @return 校验结果 | |||
* @explain 通过验证原数组和生成的hash数组是否为同一数组,验证2者是否为同一数据 | |||
*/ | |||
public static boolean verify(String srcStr, String sm3HexString) { | |||
boolean flag = false; | |||
try { | |||
byte[] srcData = srcStr.getBytes(ENCODING); | |||
byte[] sm3Hash = ByteUtils.fromHexString(sm3HexString); | |||
byte[] newHash = hash(srcData); | |||
if (Arrays.equals(newHash, sm3Hash)) { | |||
flag = true; | |||
} | |||
} catch (UnsupportedEncodingException e) { | |||
e.printStackTrace(); | |||
} | |||
return flag; | |||
} | |||
public static void main(String[] args) { | |||
String str = "123"; | |||
//秘钥 | |||
String key = "WVdSdGFXNHdNREZmTWpBeU16QTRNRE09"; | |||
String hexPls = SM3Utils.encryptPlus(str, key).toUpperCase(); | |||
String hex = SM3Utils.encrypt(str); | |||
System.out.println("参数:" + str); | |||
System.out.println("密文:" + hexPls); | |||
System.out.println("密文:" + hex); | |||
} | |||
} |
@@ -0,0 +1,41 @@ | |||
package cn.com.taiji.core.model.comm.protocol; | |||
import cn.com.taiji.common.model.BaseModel; | |||
import com.fasterxml.jackson.annotation.JsonIgnore; | |||
import lombok.Getter; | |||
import lombok.Setter; | |||
import lombok.experimental.Accessors; | |||
@Setter | |||
@Getter | |||
@Accessors(chain = true) | |||
public class SignJsonRequest extends BaseModel { | |||
@JsonIgnore | |||
private Class<? extends AbstractSignTypeRequest<?>> protocolClass; | |||
private String appId;// 由黔通分配给渠道的请求来源标识 | |||
private String ifCode;// appName_serviceType_cmd | |||
private String reqId;// appId_yyyyMMddHHmmssSSS_12543(五位随机数字) | |||
private String encryptType;// SM4,NONE | |||
private String signType;// SM3,NONE | |||
private String sign;// 验签字段 | |||
private String timestamp;// yyyy-MM-ddTHH:mm:ss | |||
private String bizContent; | |||
private String accessToken; | |||
public String toSignContent(String key) { | |||
String content = "appId=" + this.appId + "&bizContent=" + this.bizContent + "&signType=" + this.signType | |||
+ "&encryptType=" + this.encryptType + "×tamp=" + timestamp | |||
+ "&ifCode=" + this.ifCode + "&reqId=" + this.reqId; | |||
if (this.accessToken != null) { | |||
content = content + "&accessToken=" + this.accessToken; | |||
} | |||
return SM3Utils.encryptPlus(content, key); | |||
} | |||
public static void main(String[] args) { | |||
String a = | |||
"appId=3d0aff8ad268486e8928d974ae2f6442&bizContent=SFG+7BPLWKwzEy9mxRJ7JaPNXHAgsFPxrdyh90Hz8M6UVrib3nIUmbWlCAScGNQADrFULOcvcyXQ6PCdstUXKg==&signType=SM3&encryptType=SM4×tamp=2023-08-22T14:58:22&ifCode=1004&reqId=3d0aff8ad268486e8928d974ae2f6442_20230822145822022_52258"; | |||
System.out.println( | |||
SM3Utils.encryptPlus(a, "TTJRd1lXWm1PR0ZrTWpZNE5EZzJaVGc1TWpoa09UYzBZV1V5WmpZME5ESmZNakF5TXpBNE1UVT0=")); | |||
} | |||
} |
@@ -0,0 +1,33 @@ | |||
package cn.com.taiji.core.model.comm.protocol; | |||
import cn.com.taiji.common.model.BaseModel; | |||
import lombok.Getter; | |||
import lombok.Setter; | |||
import lombok.experimental.Accessors; | |||
/** | |||
* @ClassName CommonResponse | |||
* @Description 公共出参实体 | |||
* @Author shake | |||
* @Date 2023/2/1 15:30 | |||
* @Version 1.0 | |||
*/ | |||
@Getter | |||
@Setter | |||
@Accessors(chain = true) | |||
public class SignJsonResponse extends BaseModel { | |||
public static final int SUCCESS_CODE = 0; | |||
private Integer statusCode; | |||
private String errorMsg; | |||
private String bizContent; | |||
private String sign; | |||
private String reqId; | |||
public SignJsonResponse() {} | |||
public SignJsonResponse(Integer statusCode, String errorMsg) { | |||
this.statusCode = statusCode; | |||
this.errorMsg = errorMsg; | |||
} | |||
} |
@@ -0,0 +1,45 @@ | |||
package cn.com.taiji.core.model.comm.protocol; | |||
public interface SignServiceCommand { | |||
SignServiceType getServiceType(); | |||
String getValue(); | |||
/** | |||
* 是否是当前命令 | |||
* | |||
*/ | |||
public boolean isMyCommand(String fileName); | |||
/** | |||
* 取得当前命令的具体协议类型 | |||
* | |||
*/ | |||
public Class<? extends AbstractSignTypeRequest<?>> getProtocolClass(); | |||
/** | |||
* appName_serviceType_cmd | |||
*/ | |||
public default String getIfCode() { | |||
return getServiceType().getServiceSystem().getAppId().toUpperCase() + "_" + getServiceType() + "_" + this; | |||
} | |||
public static String getServiceTypeStr(String ifCode) { | |||
String[] split = ifCode.split("_"); | |||
return split[split.length-2]; | |||
} | |||
public static String getCmdStr(String ifCode) { | |||
String[] split = ifCode.split("_"); | |||
return split[split.length-1]; | |||
} | |||
public static <T extends Enum<T>> T fromName(Class<T> enumType, String name) { | |||
try { | |||
return Enum.valueOf(enumType, name); | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
return null; | |||
} | |||
} | |||
} |
@@ -0,0 +1,46 @@ | |||
/* | |||
* Date: 2019年7月26日 | |||
* author: Peream | |||
* | |||
*/ | |||
package cn.com.taiji.core.model.comm.protocol; | |||
import java.util.List; | |||
/** | |||
* | |||
* @author Peream <br> | |||
* Create Time:2019年7月26日 上午2:20:20<br> | |||
* @since 1.0 | |||
* @version 1.0 | |||
*/ | |||
public interface SignServiceSystem | |||
{ | |||
/** | |||
* 在服务网关注册的APPID<br> | |||
* 服务网关提供管理页面,申请注册服务时由网关分配<br> | |||
* 网关平台负责验证对方服务存活性,收集密钥,公钥,服务方名称等信息<br> | |||
* 分为内部和外部系统,外部系统采集URL,内部系统填jsonUri和binUri | |||
*/ | |||
public String getAppId(); | |||
/** | |||
* 服务名称 | |||
* | |||
*/ | |||
public String getAppName(); | |||
/** | |||
* 内部系统的jsonUri | |||
*/ | |||
public String getJsonUri(); | |||
/** | |||
* 内部系统的binUri | |||
* | |||
*/ | |||
public List<SignServiceType> listAllServices(); | |||
} |
@@ -0,0 +1,44 @@ | |||
/* | |||
* Date: 2019年7月26日 | |||
* author: Peream | |||
* | |||
*/ | |||
package cn.com.taiji.core.model.comm.protocol; | |||
import java.util.List; | |||
import java.util.regex.Pattern; | |||
/** | |||
* | |||
* @author Peream <br> | |||
* Create Time:2019年7月26日 上午1:11:48<br> | |||
* @since 1.0 | |||
* @version 1.0 | |||
*/ | |||
public interface SignServiceType | |||
{ | |||
/** | |||
* 服务名字 | |||
* | |||
* @return | |||
*/ | |||
public String getValue(); | |||
/** | |||
* 服务所属的系统 | |||
* | |||
* @return | |||
*/ | |||
public SignServiceSystem getServiceSystem(); | |||
/** | |||
* 服务包含的命令集合 | |||
* | |||
* @return | |||
*/ | |||
public List<SignServiceCommand> listAllCommands(); | |||
public Pattern getReqNamePattern(); | |||
} |
@@ -0,0 +1,21 @@ | |||
package cn.com.taiji.core.model.comm.protocol.inss; | |||
import cn.com.taiji.core.model.comm.protocol.AbstractSignTypeRequest; | |||
import cn.com.taiji.core.model.comm.protocol.SignServiceCommand; | |||
/** | |||
* | |||
* @author Peream <br> | |||
* Create Time:2016年3月21日 上午11:58:25<br> | |||
* <a href="mailto:peream@gmail.com">peream@gmail.com</a> | |||
* @since 1.0 | |||
* @version 1.0 | |||
*/ | |||
public abstract class AbstractInssRequest<R extends AbstractInssResponse> extends AbstractSignTypeRequest<R> | |||
{ | |||
protected AbstractInssRequest(SignServiceCommand serviceCommand) { | |||
super(serviceCommand); | |||
} | |||
} |
@@ -0,0 +1,6 @@ | |||
package cn.com.taiji.core.model.comm.protocol.inss; | |||
import cn.com.taiji.core.model.comm.protocol.AbstractSignTypeResponse; | |||
public abstract class AbstractInssResponse extends AbstractSignTypeResponse { | |||
} |
@@ -0,0 +1,57 @@ | |||
package cn.com.taiji.core.model.comm.protocol.inss; | |||
import cn.com.taiji.core.manager.comm.client.CommServiceCommand; | |||
import cn.com.taiji.core.model.comm.protocol.AbstractSignTypeRequest; | |||
import cn.com.taiji.core.model.comm.protocol.SignServiceCommand; | |||
import cn.com.taiji.core.model.comm.protocol.SignServiceType; | |||
import cn.com.taiji.core.model.comm.protocol.sample.valid.demo.EtcFreeTransUploadRequest; | |||
import cn.com.taiji.core.model.comm.protocol.sample.valid.demo.OtherFreeTransUploadRequest; | |||
import com.zgglyun.common.model.comm.protocol.AbstractBinRequest; | |||
import com.zgglyun.common.model.comm.protocol.SenderGenerator; | |||
import lombok.Getter; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
public enum InssServiceCmd implements SignServiceCommand { | |||
BATCHAPPLY("批次管理类交易","BatchApply", VfijBatchApplyRequest.class), // | |||
; | |||
private final String value; | |||
private final String transCode; | |||
private final Class<? extends AbstractSignTypeRequest<?>> reqClass; | |||
InssServiceCmd(String value,String transCode, Class<? extends AbstractSignTypeRequest<?>> reqClass) { | |||
this.value = value; | |||
this.transCode = transCode; | |||
this.reqClass = reqClass; | |||
} | |||
@Override | |||
public SignServiceType getServiceType() { | |||
return InssServiceType.VFJ; | |||
} | |||
public static InssServiceCmd fromIfCode(String ifCode) { | |||
return SignServiceCommand.fromName(InssServiceCmd.class, SignServiceCommand.getCmdStr(ifCode)); | |||
} | |||
@Override | |||
public boolean isMyCommand(String ifCode) { | |||
return this == fromIfCode(ifCode); | |||
} | |||
@Override | |||
public String getValue() { | |||
return value; | |||
} | |||
public String getTransCode() { | |||
return transCode; | |||
} | |||
@Override | |||
public Class<? extends AbstractSignTypeRequest<?>> getProtocolClass() { | |||
return reqClass; | |||
} | |||
} |
@@ -0,0 +1,49 @@ | |||
package cn.com.taiji.core.model.comm.protocol.inss; | |||
import cn.com.taiji.core.model.comm.protocol.SignServiceSystem; | |||
import cn.com.taiji.core.model.comm.protocol.SignServiceType; | |||
import com.zgglyun.common.model.ServiceSystem; | |||
import com.zgglyun.common.model.ServiceType; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
public enum InssServiceSystem implements SignServiceSystem { | |||
INSS("inss", "指令服务接口", "/inss/api/json", "/inss/common/binapi/") { | |||
public List<SignServiceType> listAllServices() { | |||
return Arrays.asList(InssServiceType.values()); | |||
} | |||
}; | |||
private final String appId;// 微服务环境当做注册中心的服务名 | |||
private final String appName; | |||
private final String jsonUri; | |||
InssServiceSystem(String appId, String appName, String jsonUri, String binUri) { | |||
this.appId = appId; | |||
this.appName = appName; | |||
this.jsonUri = jsonUri; | |||
} | |||
@Override | |||
public List<SignServiceType> listAllServices() { | |||
return new ArrayList<>(); | |||
} | |||
@Override | |||
public String getAppId() { | |||
return appId; | |||
} | |||
@Override | |||
public String getAppName() { | |||
return appName; | |||
} | |||
@Override | |||
public String getJsonUri() { | |||
return jsonUri; | |||
} | |||
} |
@@ -0,0 +1,52 @@ | |||
package cn.com.taiji.core.model.comm.protocol.inss; | |||
import cn.com.taiji.core.manager.comm.client.CommServiceCommand; | |||
import cn.com.taiji.core.model.comm.protocol.SignServiceCommand; | |||
import cn.com.taiji.core.model.comm.protocol.SignServiceSystem; | |||
import cn.com.taiji.core.model.comm.protocol.SignServiceType; | |||
import lombok.Getter; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import java.util.regex.Pattern; | |||
public enum InssServiceType implements SignServiceType { | |||
VFJ("VFJ操作", "^VFJ_\\S+\\.json$", InssServiceCmd.values()), | |||
; | |||
@Getter | |||
private final String value; | |||
@Getter | |||
private final Pattern reqNamePattern; | |||
private final List<SignServiceCommand> commands; | |||
InssServiceType(String value, String reqNameRegex, SignServiceCommand[] commands) { | |||
this.value = value; | |||
this.reqNamePattern = Pattern.compile(reqNameRegex); | |||
this.commands = Arrays.asList(commands); | |||
} | |||
@Override | |||
public SignServiceSystem getServiceSystem() { | |||
return InssServiceSystem.INSS; | |||
} | |||
@Override | |||
public List<SignServiceCommand> listAllCommands() { | |||
return commands; | |||
} | |||
public static InssServiceType fromName(String name) { | |||
return CommServiceCommand.fromName(InssServiceType.class, name); | |||
} | |||
public static InssServiceType fromFileName(String filename) { | |||
return fromName(CommServiceCommand.getServiceTypeStr(filename)); | |||
} | |||
public static InssServiceType fromIfCode(String ifCode) { | |||
return SignServiceCommand.fromName(InssServiceType.class, SignServiceCommand.getServiceTypeStr(ifCode)); | |||
} | |||
} |
@@ -0,0 +1,56 @@ | |||
package cn.com.taiji.core.model.comm.protocol.inss; | |||
import cn.com.taiji.core.model.comm.protocol.constraint.StringConstant; | |||
import com.fasterxml.jackson.annotation.JsonProperty; | |||
import lombok.Getter; | |||
import lombok.Setter; | |||
import javax.validation.constraints.NotBlank; | |||
@Getter | |||
@Setter | |||
public class VfijBatchApplyRequest extends AbstractInssRequest<VfjBatchApplyResponse> { | |||
protected VfijBatchApplyRequest() { | |||
super(InssServiceCmd.BATCHAPPLY); | |||
} | |||
@NotBlank(message = "请指定厂家代码") | |||
@JsonProperty(value = "FtyCode") | |||
private String ftyCode;// 厂家代码 | |||
@NotBlank(message = "请指定厂家名称") | |||
@JsonProperty(value = "ChanelName") | |||
private String chanelName;// 渠道名称/厂家名称 | |||
@NotBlank(message = "请指定ESAM厂家代码") | |||
@JsonProperty(value = "EsamFtyCode") | |||
private String esamFtyCode;// ESAM厂家代码 | |||
@NotBlank(message = "请指定OBU厂家代码") | |||
@JsonProperty(value = "ObuFtyCode") | |||
private String obuFtyCode;// OBU厂家代码 | |||
@NotBlank(message = "请指定OBU版本号") | |||
@JsonProperty(value = "ObuVersion") | |||
private String obuVersion;// OBU版本号 | |||
@JsonProperty(value = "CardVersion") | |||
private String cardVersion;//卡版本号 | |||
@NotBlank(message = "请指定卡片类型") | |||
@StringConstant(values = "22,23") | |||
@JsonProperty(value = "CardType") | |||
private String cardType;// 卡片类型 | |||
@NotBlank(message = "请指定发行模式") | |||
@StringConstant(values = "PER,NOR") | |||
@JsonProperty(value = "IssueMode") | |||
private String issueMode;// 发行模式 | |||
@NotBlank(message = "请指定合同号") | |||
@JsonProperty(value = "ContractId") | |||
private String contractId;// 合同号 | |||
@NotBlank(message = "请指定数量") | |||
@JsonProperty(value = "Count") | |||
private String count;// 数量 | |||
} |
@@ -0,0 +1,30 @@ | |||
package cn.com.taiji.core.model.comm.protocol.inss; | |||
import com.fasterxml.jackson.annotation.JsonProperty; | |||
import lombok.Getter; | |||
import lombok.Setter; | |||
@Getter | |||
@Setter | |||
public class VfjBatchApplyResponse extends AbstractInssResponse { | |||
/*** 批次号 */ | |||
@JsonProperty(value = "BatchNo") | |||
private String batchNo; | |||
/*** OBU序列号首号 */ | |||
@JsonProperty(value = "ObuStartSn") | |||
private String obuStartSn; | |||
/*** OBU序列号尾号 */ | |||
@JsonProperty(value = "ObuEndSn") | |||
private String obuEndSn; | |||
/*** 卡序列号首号 */ | |||
@JsonProperty(value = "CardStartNum") | |||
private String cardStartNum; | |||
/*** 卡序列号尾号 */ | |||
@JsonProperty(value = "CardEnd") | |||
private String cardEnd; | |||
} |
@@ -1,5 +1,5 @@ | |||
distributionBase=GRADLE_USER_HOME | |||
distributionPath=wrapper/dists | |||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip | |||
distributionUrl=https://mirrors.cloud.tencent.com/gradle/gradle-6.8-rc-2-bin.zip | |||
zipStoreBase=GRADLE_USER_HOME | |||
zipStorePath=wrapper/dists |