可以参见对网关的说明:
网关:https://blog.csdn.net/ganjing222/article/details/53924402
支付框架:https://blog.csdn.net/huangshulang1234/article/details/78726195
RAS工具:http://web.chacuo.net/netrsakeypair
JAVA反射:https://www.cnblogs.com/zhengtu2015/p/5829740.html
业务背景:
在一个支付平台中,一个商户可以有效,安全,快捷的接入是至关重要的。支付网关的存在最重要的功能和职责,是验证请求方的数据安全,有效,同时,要转发这笔请求到后端的支持系统。
网关设计:

RSAUtil2工具类,提供RSA的加密方式:import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
public class RSAUtil2 {
public static final String ENCRYPTION_ALGORITHM = "RSA";
public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
/**
* 生成密钥
*/
public static Map<String, Object> initKey() throws Exception {
/* 初始化密钥生成器 */
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ENCRYPTION_ALGORITHM);
keyPairGenerator.initialize(1024);
/* 生成密钥 */
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
Map<String, Object> keyMap = new HashMap<String, Object>(2);
keyMap.put("PublicKey", publicKey);
keyMap.put("PrivateKey", privateKey);
return keyMap;
}
/**
* 取得公钥
*/
public static String getPublicKey(Map<String, Object> keyMap)
throws Exception {
Key key = (Key) keyMap.get("PublicKey");
return Base64Util2.encryptBASE64(key.getEncoded());
}
/**
* 取得私钥
*/
public static String getPrivateKey(Map<String, Object> keyMap)
throws Exception {
Key key = (Key) keyMap.get("PrivateKey");
return Base64Util2.encryptBASE64(key.getEncoded());
}
/**
* 加密
*/
public static byte[] encrypt(byte[] data, String keyString, boolean isPublic) throws Exception {
Map<String, Object> keyAndFactoryMap = RSAUtil2.generateKeyAndFactory(keyString, isPublic);
KeyFactory keyFactory = RSAUtil2.getKeyFactory(keyAndFactoryMap);
Key key = RSAUtil2.getKey(keyAndFactoryMap);
// 对数据加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(data);
}
/**
* 解密
*/
public static byte[] decrypt(byte[] data, String keyString, boolean isPublic) throws Exception {
Map<String, Object> keyAndFactoryMap = RSAUtil2.generateKeyAndFactory(keyString, isPublic);
KeyFactory keyFactory = RSAUtil2.getKeyFactory(keyAndFactoryMap);
Key key = RSAUtil2.getKey(keyAndFactoryMap);
// 对数据加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(data);
}
/**
* 生成钥匙
*/
public static Map<String, Object> generateKeyAndFactory(String keyString, boolean isPublic) throws Exception {
byte[] keyBytes = Base64Util2.decryptBASE64(keyString);
KeyFactory keyFactory = KeyFactory.getInstance(ENCRYPTION_ALGORITHM);
Key key = null;
if (isPublic) {
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
key = keyFactory.generatePublic(x509KeySpec);
} else {
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
key = keyFactory.generatePrivate(pkcs8KeySpec);
}
Map<String, Object> keyAndFactoryMap = new HashMap<String, Object>(2);
keyAndFactoryMap.put("key", key);
keyAndFactoryMap.put("keyFactory", keyFactory);
return keyAndFactoryMap;
}
/**
* 从指定对象中获取钥匙
*/
public static Key getKey(Map<String, Object> map) {
if (map.get("key") == null) {
return null;
}
return (Key)map.get("key");
}
/**
* 从指定对象中获取钥匙工厂
*/
public static KeyFactory getKeyFactory(Map<String, Object> map) {
if (map.get("keyFactory") == null) {
return null;
}
return (KeyFactory)map.get("keyFactory");
}
/**
* 对信息生成数字签名(用私钥)
*/
public static String sign(byte[] data, String keyString) throws Exception {
Map<String, Object> keyAndFactoryMap = RSAUtil2.generateKeyAndFactory(keyString, false);
Key key = RSAUtil2.getKey(keyAndFactoryMap);
PrivateKey privateKey = (PrivateKey)key;
// 用私钥对信息生成数字签名
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initSign(privateKey);
signature.update(data);
return Base64Util2.encryptBASE64(signature.sign());
}
/**
* 校验数字签名(用公钥)
*/
public static boolean verify(byte[] data, String keyString, String sign)
throws Exception {
Map<String, Object> keyAndFactoryMap = RSAUtil2.generateKeyAndFactory(keyString, true);
Key key = RSAUtil2.getKey(keyAndFactoryMap);
PublicKey publicKey = (PublicKey)key;
// 取公钥匙对象
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(publicKey);
signature.update(data);
// 验证签名是否正常
return signature.verify(Base64Util2.decryptBASE64(sign));
}
}
Base64Util2工具类,提供防中文乱码的(加解密)方式:
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class Base64Util2 {
/**
* Base64加密
*/
public static String encryptBASE64(byte[] key) throws Exception {
return (new BASE64Encoder()).encodeBuffer(key);
}
/**
* Base64解密
*/
public static byte[] decryptBASE64(String key) throws Exception {
return (new BASE64Decoder()).decodeBuffer(key);
}
}DESUtil2 工具包,提供DES 的对称加解密算法:
import com.qudian.pay.gateway.constance.C;
import org.apache.commons.lang3.StringUtils;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.security.SecureRandom;
public class DESUtil2 {
/**
* 加密
*
* @param content 待加密内容
* @param key 加密的密钥
* @return
*/
public static byte[] encrypt(String content, String key) {
try {
SecureRandom random = new SecureRandom();
DESKeySpec desKey = new DESKeySpec(key.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(desKey);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
byte[] result = cipher.doFinal(content.getBytes());
return result;
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
/**
* 加密
*
* @param content 待加密内容
* @param key 密钥
* @param charsetName 字符集
* @return
*/
public static String encrypt2Str(String content, String key, String charsetName) {
try {
byte[] bytes = encrypt(content, key);
if (StringUtils.isBlank(charsetName)) charsetName = C.DEFAULT_CHAREST;
return new String(bytes, charsetName);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
/**
* 解密
*
* @param content 待解密内容
* @param key 解密的密钥
* @return
*/
public static String decrypt(byte[] content, String key) throws Exception {
SecureRandom random = new SecureRandom();
DESKeySpec desKey = new DESKeySpec(key.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(desKey);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, securekey, random);
byte[] result = cipher.doFinal(content);
return new String(result);
}
/**
* 解密
*
* @param content 待解密内容
* @param key 解密的密钥
* @return
*/
public static String decrypt(String content, String key) throws Exception{
return decrypt(content.getBytes(C.DEFAULT_CHAREST), key);
}
/**
* 解密
*
* @param content 待解密内容
* @param key 密钥
* @param charsetName 字符集,默认为UTF-8
* @return
*/
public static String decryptByStr(String content, String key, String charsetName) {
if (StringUtils.isBlank(charsetName)) charsetName = C.DEFAULT_CHAREST;
try {
SecureRandom random = new SecureRandom();
DESKeySpec desKey = new DESKeySpec(key.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(desKey);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, securekey, random);
byte[] result = cipher.doFinal(content.getBytes(charsetName));
return new String(result);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
}怎样使用:
import static org.junit.Assert.*;
import com.alibaba.dubbo.common.io.Bytes;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.sun.javafx.scene.control.skin.VirtualFlow;
import org.junit.Before;
import org.junit.Test;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
public class How2Use {
private String publicKey = null;
private String privateKey = null;
@Before
public void setUp() throws Exception {
Map<String, Object> keyMap = RSAUtil2.initKey();
publicKey = RSAUtil2.getPublicKey(keyMap);
privateKey = RSAUtil2.getPrivateKey(keyMap);
publicKey="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqpGuBelqd9gceb2a6y8W0xhRz\n" +
"f6O9h0ALrCwIxsHUFF2YU0nUpAfrR/LbbpSmCEClOLwh80ZBf6ea8GDKubHaQvma\n" +
"vdMgFzs0lWltWUzT1dbXGd3ahobOpTk7dceWIXcbB0SgQ/zENqCAl9lyJUFnXsbJ\n" +
"eEh6HSf1+/stIAJpAQIDAQAB";
privateKey="MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKqka4F6Wp32Bx5v\n" +
"ZrrLxbTGFHN/o72HQAusLAjGwdQUXZhTSdSkB+tH8ttulKYIQKU4vCHzRkF/p5rw\n" +
"YMq5sdpC+Zq90yAXOzSVaW1ZTNPV1tcZ3dqGhs6lOTt1x5YhdxsHRKBD/MQ2oICX\n" +
"2XIlQWdexsl4SHodJ/X7+y0gAmkBAgMBAAECgYB7wvxl0APhBQtsu4dae2hNEEzM\n" +
"6Aot7+Y3kQvu4Zi65HptfBrUKpPDxU8Sb0VIljusmVV5miOeZaN98FGDNuMSJnDX\n" +
"CmYUGjJTijxS1Ao6ft3QsSkyQK5ZkUOU8JxPzyr3QQbvWwHz426WxSNZWX9l5SDv\n" +
"SfTiTyBW+MGeLJ7tAQJBANtZMedQhHLt9+msxr7sBFwrfenmSvEke2y8yG/99tn5\n" +
"b4+vcAZbe/fiy8SduJQ2fUhNyPcDc7GZlAPWyVEGOYkCQQDHJ8e4FbxdXikmRsJ6\n" +
"bHOmx40RwMd6fqR7/zSszoKhHjKx6ROI1LZTBYUmrlJ/nCnEZhAmw9P3KiFKSKy4\n" +
"h+25AkAgVpAS6D3+q7LHEp/iee1SoV7Y4wjdcGF58IMkb667CBk4d8buSQKH0znz\n" +
"bMVPpJDn3f/o2uttnZTC1CGt/lrxAkBB5ykRAqhVoU4uq2W5y1+uBgTppgicwYG+\n" +
"wqH0uVXC6VJPS1i6g+FdscrxFOiZ79xmcHvRyCXBecCQa2I0ok6JAkAoV6H2ApSB\n" +
"2BJHM27nFG8kjb7cajoPcLxPND1BPR7y1dQKBYEG1qOcb6sG+cknd1k+UOgDoeQq\n" +
"K3eH1zw2Txps";
System.out.println("公钥 -> " + publicKey);
System.out.println("私钥 -> " + privateKey);
}
@Test
public void test() throws Exception {
System.out.println("公钥加密,私钥解密");
String sourceString = "hi, RSA";
byte[] encodedData = RSAUtil2.encrypt(sourceString.getBytes(), publicKey, true);
byte[] decodedData = RSAUtil2.decrypt(encodedData, privateKey, false);
String targetString = new String(decodedData);
System.out.println("加密前: " + sourceString + ",解密后: " + targetString);
assertEquals(sourceString, targetString);
}
@Test
public void test2() throws Exception {
System.out.println("私钥签名,公钥验证签名");
String sourceString = "hello, RSA sign";
sourceString="{\"amount\":200000,\"merchantId\":\"MR0000001\",\"merchantIp\":\"192.168.1.1\",\"merchantNo\":\"201803060000000000000004\",\"transCur\":\"CNY\",\"transTime\":1526537403392}";
byte[] data = sourceString.getBytes();
// 产生签名
String sign = RSAUtil2.sign(data, privateKey);
System.out.println("签名 -> " + sign);
// 验证签名
boolean status = RSAUtil2.verify(data, publicKey, sign);
System.out.println("状态 -> " + status);
assertTrue(status);
}
@Test
public void test3() throws Exception {
System.out.println("私钥加密,公钥解密");
String sourceString = "hello, reRSA";
byte[] data = sourceString.getBytes();
byte[] encodedData = RSAUtil2.encrypt(data, privateKey, false);
byte[] decodedData = RSAUtil2.decrypt(encodedData, publicKey, true);
String targetString = new String(decodedData);
System.out.println("加密前: " + sourceString + ",解密后: " + targetString);
assertEquals(sourceString, targetString);
}
}JSON 数据和对象互转过程:
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.io.Writer;
/**
* Created by xun on 2015/9/1.
* <p>
* JSON Utils
*/
public class JsonParser {
static Logger logger = LoggerFactory.getLogger(JsonParser.class);
private static ObjectMapper objectMapper = new ObjectMapper();
static {
objectMapper.configure(com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
/**
* 将对象序列化为JSON字符串
*
* @param object
* @return JSON字符串
*/
public static String serialize(Object object) {
Writer write = new StringWriter();
try {
objectMapper.writeValue(write, object);
} catch (JsonGenerationException e) {
logger.error("JsonGenerationException when serialize object to json", e);
} catch (JsonMappingException e) {
logger.error("JsonMappingException when serialize object to json", e);
} catch (IOException e) {
logger.error("IOException when serialize object to json", e);
}
return write.toString();
}
/**
* 将JSON字符串反序列化为对象
*
* @param json
* @return JSON字符串
*/
@SuppressWarnings("unchecked")
public static <T> T deserialize(String json, Class<T> clazz) throws IOException {
Object object = null;
object = objectMapper.readValue(json, TypeFactory.rawClass(clazz));
return (T) object;
}
/**
* 将JSON字符串反序列化为对象
*
* @param json
* @return JSON字符串
*/
@SuppressWarnings("unchecked")
public static <T> T deserialize(InputStream json, Class<T> clazz) {
Object object = null;
try {
object = objectMapper.readValue(json, TypeFactory.rawClass(clazz));
} catch (JsonParseException e) {
logger.error("JsonParseException when serialize object to json", e);
} catch (JsonMappingException e) {
logger.error("JsonMappingException when serialize object to json", e);
} catch (IOException e) {
logger.error("IOException when serialize object to json", e);
}
return (T) object;
}
/**
* 将JSON字符串反序列化为对象
*
* @param json
* @return JSON字符串
*/
@SuppressWarnings("unchecked")
public static <T> T deserialize(String json, TypeReference<T> typeRef) {
try {
return (T) objectMapper.readValue(json, typeRef);
} catch (JsonParseException e) {
logger.error("JsonParseException when deserialize json", e);
} catch (JsonMappingException e) {
logger.error("JsonMappingException when deserialize json", e);
} catch (IOException e) {
logger.error("IOException when deserialize json", e);
}
return null;
}
public static JavaType getCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
return objectMapper.getTypeFactory().constructParametrizedType(collectionClass, collectionClass, elementClasses);
}
/**
* 将JSON字符串反序列化为对象
*
* @param json
* @return JSON字符串
*/
@SuppressWarnings("unchecked")
public static <T> T deserialize(String json, JavaType javaType) {
Object object = null;
try {
object = objectMapper.readValue(json, javaType);
} catch (JsonParseException e) {
logger.error("JsonParseException when serialize object to json", e);
} catch (JsonMappingException e) {
logger.error("JsonMappingException when serialize object to json", e);
} catch (IOException e) {
logger.error("IOException when serialize object to json", e);
}
return (T) object;
}
public static JsonNode deserialize(String json) {
try {
return objectMapper.readTree(json);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
我们需要把调用业务系统的方法,进行配置,无需在代码中写死。
在系统中支持DUBBO 的 HESSIAN 两种协议。
import com.qudian.pay.gateway.entity.dto.MethodInfo;
import com.qudian.pay.gateway.entity.dto.MethodMap;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@Component
public class InitService {
private static final Logger logger = LoggerFactory.getLogger(InitService.class);
@Resource(name = "dubboServiceCodeMap")
private Map<String, Object> dubboServiceCodeMap;
@Resource(name = "hessianServiceCodeMap")
private Map<String, Object> hessianServiceCodeMap;
static Set<String> hessianIlLegal = new HashSet<>();
/**
* hessian自带的方法,需要排除
*/
static {
hessianIlLegal.add("equals");
hessianIlLegal.add("toString");
hessianIlLegal.add("hashCode");
hessianIlLegal.add("indexOf");
hessianIlLegal.add("isFrozen");
hessianIlLegal.add("setPreFiltered");
hessianIlLegal.add("setExposeProxy");
hessianIlLegal.add("setTargetSource");
hessianIlLegal.add("getTargetClass");
hessianIlLegal.add("getTargetSource");
hessianIlLegal.add("getProxiedInterfaces");
hessianIlLegal.add("isProxyTargetClass");
hessianIlLegal.add("isExposeProxy");
hessianIlLegal.add("isPreFiltered");
hessianIlLegal.add("isInterfaceProxied");
hessianIlLegal.add("getAdvisors");
hessianIlLegal.add("addAdvice");
hessianIlLegal.add("addAdvisor");
hessianIlLegal.add("removeAdvisor");
hessianIlLegal.add("replaceAdvisor");
hessianIlLegal.add("removeAdvice");
hessianIlLegal.add("toProxyConfigString");
}
@PostConstruct
public void init() throws BeansException {
logger.info("开始加载自定义map");
if (CollectionUtils.isEmpty(dubboServiceCodeMap) && CollectionUtils.isEmpty(hessianServiceCodeMap)) {
logger.info("自动注入map为空,加载结束");
return;
}
Map<String, MethodInfo> methodMap = new HashMap<String, MethodInfo>();
//处理dubbo注入
for (String serviceName : dubboServiceCodeMap.keySet()) {
Object serviceInteface = dubboServiceCodeMap.get(serviceName);
Method[] methods = serviceInteface.getClass().getDeclaredMethods();
for (Method method : methods) {
String methodName = method.getName();
if (methodName.equals("$echo")) continue;
Class[] methodParams = method.getParameterTypes();
Class resp = method.getReturnType();
MethodInfo methodInfo = new MethodInfo();
methodInfo.setInteface(serviceInteface);
methodInfo.setMethodName(method);
methodInfo.setParam(methodParams[0]);
methodInfo.setResp(resp);
methodMap.put(serviceName + "." + methodName, methodInfo);
logger.info("Dubbo已加载:{}.{}", serviceName, methodName);
}
}
//处理hessian注入
for (String serviceName : hessianServiceCodeMap.keySet()) {
Object serviceInteface = hessianServiceCodeMap.get(serviceName);
Method[] methods = serviceInteface.getClass().getDeclaredMethods();
for (Method method : methods) {
String methodName = method.getName();
if (isIlLegal(methodName)) continue;
Class[] methodParams = method.getParameterTypes();
Class resp = method.getReturnType();
MethodInfo methodInfo = new MethodInfo();
methodInfo.setInteface(serviceInteface);
methodInfo.setMethodName(method);
methodInfo.setParam(methodParams[0]);
methodInfo.setResp(resp);
methodMap.put(serviceName + "." + methodName, methodInfo);
logger.info("hessian已加载:{}.{}", serviceName, methodName);
}
}
MethodMap.setMethodMap(methodMap);
logger.info("自定义map加载完毕");
}
/**
* 判断方法是否是hessian自带的,如果是返回true
*
* @param hessionMethodName
* @return
*/
private Boolean isIlLegal(String hessionMethodName) {
if (StringUtils.isBlank(hessionMethodName)) return true;
return hessianIlLegal.contains(hessionMethodName);
}
}<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:reference interface="com.xxx.pay.trade.facade.PaymentOrderFacade" id="pay" registry="gateway"
group="${dubbo.service.group}" version="${dubbo.service.version}" retries="0" timeout="20000"
check="false"/>
</beans><?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="dubboServiceCodeMap" class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="targetMapClass" value="java.util.HashMap"/>
<property name="sourceMap">
<map>
<entry key="com.xxx.pay.trade.facade.PaymentOrderFacade" value-ref="pay"/>
</map>
</property>
</bean>
<!--hessian接口Map-->
<bean id="hessianServiceCodeMap" class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="targetMapClass" value="java.util.HashMap"/>
<property name="sourceMap">
<map>
<entry key="com.xxx.pay.bills.common.api.IBillsFacade" value-ref="billsFacade"/>
</map>
</property>
</bean>
</beans><?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
<bean id="timeoutHessionProxyFactory" class="com.caucho.hessian.client.HessianProxyFactory">
<property name="connectTimeout" value="${bills.connect.timeout}"/>
<property name="readTimeout" value="${bills.read.timeout}"/>
</bean>
<bean id="billsFacade" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
<property name="serviceUrl" value="${bills.server.url}/hessian/billFacade"/>
<property name="serviceInterface" value="com.xxx.pay.bills.common.api.IBillsFacade"/>
<property name="proxyFactory" ref="timeoutHessionProxyFactory"/>
</bean>
</beans>调用使用:doHandler 这块可以参考,其他的实现,无所谓了。
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.qudian.pay.gateway.dto.DoHandlerVo;
import com.qudian.pay.gateway.dto.HttpRequestDto;
import com.qudian.pay.gateway.dto.HttpResponseDto;
import com.qudian.pay.gateway.entity.BizInfo;
import com.qudian.pay.gateway.entity.BizKey;
import com.qudian.pay.gateway.entity.dto.MethodInfo;
import com.qudian.pay.gateway.entity.dto.MethodMap;
import com.qudian.pay.gateway.enums.ExceptionEnums;
import com.qudian.pay.gateway.exception.GatewayException;
import com.qudian.pay.gateway.service.BizDetailService;
import com.qudian.pay.gateway.service.BizInfoService;
import com.qudian.pay.gateway.service.BizKeyService;
import com.qudian.pay.gateway.service.GatewayDetailService;
import com.qudian.pay.gateway.service.GatewayService;
import com.qudian.pay.gateway.service.WhiteIpService;
import com.qudian.pay.gateway.utils.JsonParser;
import com.qudian.pay.gateway.utils.LogUtil;
import com.qudian.pay.gateway.utils.VerfyUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.util.HashSet;
import java.util.Set;
/**
* 业务线请求处理
*/
public class HttpServiceImpl implements GatewayService<HttpRequestDto, HttpResponseDto> {
private static Logger logger = LoggerFactory.getLogger(HttpServiceImpl.class);
@Resource
private BizInfoService bizInfoServiceImpl;
@Resource
private BizDetailService bizDetailServiceImpl;
@Resource
private WhiteIpService whiteIpServiceImpl;
@Resource
private BizKeyService bizKeyServiceImpl;
@Resource
private GatewayDetailService gatewayDetailServiceImpl;
private final static Set<String> whiteListServiceCode;
static {
whiteListServiceCode = new HashSet<>();
whiteListServiceCode.add("com.qufenqi.insurance.facade.InsuranceNotifyFacade.tkRefundNotify");
}
/**
* 参数验证
*
* @param req
* @return
*/
@Override
public void validate(HttpRequestDto req) throws GatewayException {
if(req==null){
throw new GatewayException(ExceptionEnums.REQUEST_NULL);
}
String bizCode = req.getBizCode();
String serviceCode = req.getServiceCode();
if(org.apache.commons.lang3.StringUtils.isBlank(bizCode)){
throw new GatewayException(ExceptionEnums.REQ_BIZCODE_NULL);
}
if(org.apache.commons.lang3.StringUtils.isBlank(req.getContext())){
throw new GatewayException(ExceptionEnums.REQ_CONTEXT_NULL);
}
if(org.apache.commons.lang3.StringUtils.isBlank(serviceCode)){
throw new GatewayException(ExceptionEnums.REQ_SERVICECODE_NULL);
}
if(org.apache.commons.lang3.StringUtils.isBlank(req.getSign())){
throw new GatewayException(ExceptionEnums.REQ_SIGN_NULL);
}
BizInfo bizInfo = bizInfoServiceImpl.queryBizInfoByCache(bizCode);
if(bizInfo==null){
throw new GatewayException(ExceptionEnums.QUERY_BIZCODE_NULL);
}
if(bizDetailServiceImpl.checkBizDetail(bizCode,serviceCode)){
throw new GatewayException(ExceptionEnums.QUERY_SERVICE_CODE_NULL);
}
if(bizInfo.getIsValidateIp()){
if(!whiteIpServiceImpl.checkIp(req.getIp(),bizCode)){
throw new GatewayException(ExceptionEnums.IP_NULL);
}
}
}
/**
* 处理前
*
* @param req
*/
@Override
public void beforeHandler(HttpRequestDto req) throws GatewayException{
req.setServiceCode(gatewayDetailServiceImpl.getServiceCodeByName(req.getServiceCode()));
BizKey bizKey = bizKeyServiceImpl.getBizKey(req.getBizCode(),req.getKeyGroupName());
if(!VerfyUtil.verfySign(bizKey.getSignType(),req.getContext(),req.getSign(),bizKey.getSignKey())){
String logSignKey = bizKey.getSignKey();
if (StringUtils.isNotBlank(logSignKey) && logSignKey.length()>=2) {
logSignKey = logSignKey.substring(logSignKey.length()-2);
}
LogUtil.error(logger,"验签失败,SignType:{0},Context:{1},Sign:{2},SignKey:{3},bizKey:{4}",
bizKey.getSignType(),req.getContext(),req.getSign(),logSignKey,bizKey);
throw new GatewayException(ExceptionEnums.UNSIGN_ERROR);
}
String context = VerfyUtil.decrypt(bizKey.getEncryptType(),req.getContext(),bizKey.getEncryptKey());
logger.info("收到业务线请求:{}",context);
req.setContext(context);
}
/**
* 处理中
*
* @param req
* @return
*/
@Override
public DoHandlerVo doHandler(HttpRequestDto req) throws GatewayException{
if (!whiteListServiceCode.contains(req.getServiceCode())) {
throw new GatewayException(ExceptionEnums.QUERY_SERVICE_CODE_NULL);
}
DoHandlerVo vo = new DoHandlerVo();
MethodInfo methodInfo = MethodMap.getMethodMap().get(req.getServiceCode());
if (methodInfo == null) {
throw new GatewayException(ExceptionEnums.INVOKE_UNIMPL_METHOD);
}
Object params = null;
try {
params = JSONObject.parseObject(req.getContext(), methodInfo.getParam());
} catch (JSONException je) {
logger.error("jSON字符串转换对象异常", je);
throw new GatewayException(ExceptionEnums.PARAM_PARSE_OBJECT_ERROR);
} catch (Exception e) {
logger.error("jSON字符串转换对象未知异常", e);
throw new GatewayException(ExceptionEnums.PARAM_ERROR);
}
try {
long start = System.currentTimeMillis();
Object object = methodInfo.getMethodName().invoke(methodInfo.getInteface(), params);
vo.setObject(object);
vo.setTimes(System.currentTimeMillis() - start);
return vo;
} catch (InvocationTargetException ite) {
logger.error("调用第三方接口异常", ite);
throw new GatewayException(ExceptionEnums.INVOKE_METHOD_ERROR);
} catch (Exception e) {
logger.error("接口调用失败", e);
throw new GatewayException(ExceptionEnums.HANDLER_ERROR);
}
}
/**
* 处理后
*
* @param respDto
*/
@Override
public HttpResponseDto afterHandler(Object respDto) {
return HttpResponseDto.build(ExceptionEnums.SUCCESS,JsonParser.serialize(respDto));
}
}所需要的SQL表:
CREATE TABLE `biz_key` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`biz_id` int(11) DEFAULT NULL COMMENT '合作伙伴唯一ID',
`status` tinyint(2) DEFAULT NULL COMMENT '密钥状态',
`key_group_name` varchar(128) DEFAULT NULL COMMENT '密钥组名称',
`encrypt_type` varchar(16) DEFAULT NULL COMMENT '加密类型',
`encrypt_key` varchar(256) DEFAULT NULL COMMENT '加密密钥',
`sign_type` varchar(16) DEFAULT NULL COMMENT '签名类型',
`sign_key` varchar(1024) DEFAULT NULL COMMENT '签名密钥',
`operator` varchar(32) DEFAULT NULL COMMENT '操作人',
`create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
`update_time` timestamp NULL DEFAULT NULL COMMENT '修改时间',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
# Dump of table gateway_detail
# ------------------------------------------------------------
DROP TABLE IF EXISTS `gateway_detail`;
CREATE TABLE `gateway_detail` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`service_code` varchar(255) DEFAULT NULL COMMENT '服务编码',
`service_name` varchar(128) DEFAULT NULL COMMENT '服务名称',
`owner` varchar(32) DEFAULT '' COMMENT '服务拥有者',
`version` varchar(16) DEFAULT NULL COMMENT '接口版本',
`status` tinyint(2) DEFAULT NULL COMMENT '是否可用',
`create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
`update_time` timestamp NULL DEFAULT NULL COMMENT '修改时间',
`operator` varchar(32) DEFAULT NULL COMMENT '操作人',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`),
UNIQUE KEY `gateway_detail_scode` (`service_code`) USING BTREE,
UNIQUE KEY `gateway_detail_sname` (`service_name`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERT INTO gateway.`biz_key` (`id`, `biz_id`, `status`, `key_group_name`, `encrypt_type`, `encrypt_key`, `sign_type`, `sign_key`, `operator`, `create_time`, `update_time`, `remark`)
VALUES
(1,1,0,'','AES','45bE9Lfcu2Ppkmnm','MD5','Nrrw7YGldC','xiaoming',now(),now(),NULL);
INSERT INTO gateway.`gateway_detail` (`id`, `service_code`, `service_name`, `owner`, `version`, `status`, `create_time`, `update_time`, `operator`, `remark`)
VALUES
(1,'com.xxx.pay.trade.facade.PaymentOrderFacade.payment','trade.payment','xiaoming','1.0.0',0,now(),now(),NULL,NULL),
(2,'com.xxx.pay.trade.facade.PaymentOrderFacade.paymentQuery','trade.paymentQuery','xiaoming','1.0.0',0,now(),now(),NULL,NULL);

2003

被折叠的 条评论
为什么被折叠?



