@@ -0,0 +1,107 @@ | |||||
<?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"> | |||||
<modelVersion>4.0.0</modelVersion> | |||||
<groupId>com.nsgk</groupId> | |||||
<artifactId>agentcenter-sdk</artifactId> | |||||
<version>1.0.0nsgk1</version> | |||||
<packaging>jar</packaging> | |||||
<description>NS代理中心SDK</description> | |||||
<properties> | |||||
<lombok.version>1.16.18</lombok.version> | |||||
<hutool.version>5.5.4</hutool.version> | |||||
<fastjson.version>2.0.23</fastjson.version> | |||||
<java.version>1.8</java.version> | |||||
<project.sourceEncoding>UTF-8</project.sourceEncoding> | |||||
</properties> | |||||
<build> | |||||
<plugins> | |||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-compiler-plugin</artifactId> | |||||
<configuration> | |||||
<source>${java.version}</source> | |||||
<target>${java.version}</target> | |||||
<encoding>${project.sourceEncoding}</encoding> | |||||
</configuration> | |||||
</plugin> | |||||
</plugins> | |||||
</build> | |||||
<dependencyManagement> | |||||
<dependencies> | |||||
<!-- lombok --> | |||||
<dependency> | |||||
<groupId>org.projectlombok</groupId> | |||||
<artifactId>lombok</artifactId> | |||||
<version>${lombok.version}</version> | |||||
</dependency> | |||||
<!-- hutool --> | |||||
<dependency> | |||||
<groupId>cn.hutool</groupId> | |||||
<artifactId>hutool-all</artifactId> | |||||
<version>${hutool.version}</version> | |||||
</dependency> | |||||
<!-- 阿里JSON解析器 --> | |||||
<dependency> | |||||
<groupId>com.alibaba.fastjson2</groupId> | |||||
<artifactId>fastjson2</artifactId> | |||||
<version>${fastjson.version}</version> | |||||
</dependency> | |||||
</dependencies> | |||||
</dependencyManagement> | |||||
<dependencies> | |||||
<dependency> | |||||
<groupId>org.projectlombok</groupId> | |||||
<artifactId>lombok</artifactId> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>cn.hutool</groupId> | |||||
<artifactId>hutool-all</artifactId> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.alibaba.fastjson2</groupId> | |||||
<artifactId>fastjson2</artifactId> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>javax.servlet</groupId> | |||||
<artifactId>javax.servlet-api</artifactId> | |||||
<version>4.0.1</version> | |||||
<scope>compile</scope> | |||||
</dependency> | |||||
</dependencies> | |||||
<repositories> | |||||
<repository> | |||||
<id>public</id> | |||||
<name>aliyun nexus</name> | |||||
<url>https://maven.aliyun.com/repository/public</url> | |||||
<releases> | |||||
<enabled>true</enabled> | |||||
</releases> | |||||
</repository> | |||||
</repositories> | |||||
<pluginRepositories> | |||||
<pluginRepository> | |||||
<id>public</id> | |||||
<name>aliyun nexus</name> | |||||
<url>https://maven.aliyun.com/repository/public</url> | |||||
<releases> | |||||
<enabled>true</enabled> | |||||
</releases> | |||||
<snapshots> | |||||
<enabled>false</enabled> | |||||
</snapshots> | |||||
</pluginRepository> | |||||
</pluginRepositories> | |||||
</project> |
@@ -0,0 +1,29 @@ | |||||
package com.nsgk.agentcentersdk; | |||||
import com.nsgk.agentcentersdk.api.NSApiResult; | |||||
import com.nsgk.agentcentersdk.api.NSSDK; | |||||
import com.nsgk.agentcentersdk.api.NSSDKClient; | |||||
import com.nsgk.agentcentersdk.core.NSProtocol; | |||||
import com.nsgk.agentcentersdk.entity.NSContractionEntity; | |||||
public final class NSMain | |||||
{ | |||||
public static void main(String[] args) | |||||
{ | |||||
NSSDKClient client; | |||||
NSContractionEntity entity; | |||||
NSApiResult result; | |||||
NSSDK.InitClient("http://localhost", (short) 8081, "test", "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=="); | |||||
client = NSSDK.InstanceClient(); | |||||
entity = new NSContractionEntity(); | |||||
entity.setBuildingTime("2000-12-23") | |||||
.setName("测试合同") | |||||
.setDeptId(187L) | |||||
.setBookId(166L) | |||||
; | |||||
result = client.Send(NSProtocol.NS_PROTOCOL_CONTRACTION, entity); | |||||
System.err.println(result); | |||||
} | |||||
} |
@@ -0,0 +1,10 @@ | |||||
package com.nsgk.agentcentersdk.api; | |||||
// 接口 | |||||
public final class NSApi | |||||
{ | |||||
public static final String NS_API_TEST = "/agentcenter/api/test"; | |||||
public static final String NS_API_REPORT = "/agentcenter/api/report"; | |||||
private NSApi() {} | |||||
} |
@@ -0,0 +1,30 @@ | |||||
package com.nsgk.agentcentersdk.api; | |||||
import com.alibaba.fastjson2.JSON; | |||||
import com.alibaba.fastjson2.JSONObject; | |||||
import lombok.Data; | |||||
// 服务端返回对象 | |||||
@Data | |||||
public class NSApiResult | |||||
{ | |||||
public final int code; | |||||
public final String msg; | |||||
public final Object data; | |||||
public final long timestamp = System.currentTimeMillis(); | |||||
NSApiResult(int code, String msg, Object data) | |||||
{ | |||||
this.code = code; | |||||
this.msg = msg; | |||||
this.data = data; | |||||
} | |||||
static NSApiResult FromJSON(String str) | |||||
{ | |||||
JSONObject jsonObject; | |||||
jsonObject = JSON.parseObject(str); | |||||
return new NSApiResult(jsonObject.getInteger("code"), jsonObject.getString("msg"), jsonObject.get("data")); | |||||
} | |||||
} |
@@ -0,0 +1,90 @@ | |||||
package com.nsgk.agentcentersdk.api; | |||||
import com.nsgk.agentcentersdk.utility.NSConv; | |||||
// SDK全局环境 | |||||
public final class NSSDK | |||||
{ | |||||
// client | |||||
private static final ThreadLocal<String> _host = new ThreadLocal<>(); | |||||
private static final ThreadLocal<Short> _port = new ThreadLocal<>(); | |||||
private static final ThreadLocal<String> _identifier = new ThreadLocal<>(); | |||||
private static final ThreadLocal<Boolean> _clientInit = new ThreadLocal<>(); | |||||
private static final ThreadLocal<String> _publicKey = new ThreadLocal<>(); | |||||
// server | |||||
private static final ThreadLocal<String> _privateKey = new ThreadLocal<>(); | |||||
private static final ThreadLocal<Boolean> _serverInit = new ThreadLocal<>(); | |||||
public static boolean InitClient(String host, short port, String identifier, String publicKey) | |||||
{ | |||||
if(NSConv.FALSE(_clientInit.get())) | |||||
return false; | |||||
_host.set(host); | |||||
_port.set(port); | |||||
_identifier.set(identifier); | |||||
_publicKey.set(publicKey); | |||||
_clientInit.set(true); | |||||
return true; | |||||
} | |||||
public static boolean ShutdownClient() | |||||
{ | |||||
if(NSConv.FALSE(_clientInit.get())) | |||||
return false; | |||||
_host.remove(); | |||||
_port.remove(); | |||||
_identifier.remove(); | |||||
_publicKey.remove(); | |||||
_clientInit.set(false); | |||||
return true; | |||||
} | |||||
public static String Host() | |||||
{ | |||||
return _host.get(); | |||||
} | |||||
public static short Port() | |||||
{ | |||||
return _port.get(); | |||||
} | |||||
public static String Identifier() | |||||
{ | |||||
return _identifier.get(); | |||||
} | |||||
public static NSSDKClient InstanceClient() | |||||
{ | |||||
if(!NSConv.FALSE(_clientInit.get())) | |||||
return null; | |||||
return new NSSDKClient(_host.get(), _port.get(), _identifier.get(), _publicKey.get()); | |||||
} | |||||
public static boolean InitServer(String privateKey) | |||||
{ | |||||
if(NSConv.FALSE(_serverInit.get())) | |||||
return false; | |||||
_privateKey.set(privateKey); | |||||
_serverInit.set(true); | |||||
return true; | |||||
} | |||||
public static boolean ShutdownServer() | |||||
{ | |||||
if(NSConv.FALSE(_serverInit.get())) | |||||
return false; | |||||
_privateKey.remove(); | |||||
_serverInit.set(false); | |||||
return true; | |||||
} | |||||
public static NSSDKServer InstanceServer() | |||||
{ | |||||
if(!NSConv.FALSE(_serverInit.get())) | |||||
return null; | |||||
return new NSSDKServer(_privateKey.get()); | |||||
} | |||||
} |
@@ -0,0 +1,59 @@ | |||||
package com.nsgk.agentcentersdk.api; | |||||
import cn.hutool.core.util.URLUtil; | |||||
import com.nsgk.agentcentersdk.core.NSReportObject; | |||||
import com.nsgk.agentcentersdk.entity.NSEntityBase; | |||||
import com.nsgk.agentcentersdk.network.NSNetworkManager; | |||||
import com.nsgk.agentcentersdk.network.NSNetworkRequest; | |||||
import com.nsgk.agentcentersdk.network.NSNetworkResponse; | |||||
// SDK客户端 | |||||
/* | |||||
请求: | |||||
<host>:<port>/<api>?identifier=<identifier>&protocol=<protocol>×tamp=<timestamp> | |||||
header: sign | |||||
body: 加密json | |||||
响应: | |||||
body: | |||||
code: 200 | |||||
msg: "" | |||||
timestamp: | |||||
data: "" // 加密json | |||||
*/ | |||||
public final class NSSDKClient | |||||
{ | |||||
private final String host; | |||||
private final short port; | |||||
private final String identifier; | |||||
private final String publicKey; | |||||
NSSDKClient(String host, short port, String identifier, String publicKey) | |||||
{ | |||||
this.host = host; | |||||
this.port = port; | |||||
this.identifier = identifier; | |||||
this.publicKey = publicKey; | |||||
} | |||||
// 发送请求 | |||||
public <T extends NSEntityBase> NSApiResult Send(int protocol, T object) | |||||
{ | |||||
String url; | |||||
NSReportObject<T> reportObject; | |||||
NSNetworkRequest request; | |||||
url = NSApi.NS_API_REPORT; | |||||
reportObject = new NSReportObject<>(identifier, protocol, object); | |||||
request = new NSNetworkRequest(); | |||||
request.setUrl(BuildUrl(url)); | |||||
request.WriteDataObject(reportObject, publicKey); | |||||
NSNetworkResponse response = NSNetworkManager.Post(request); | |||||
String json = response.getData(); | |||||
return NSApiResult.FromJSON(json); | |||||
} | |||||
private String BuildUrl(String url) | |||||
{ | |||||
return URLUtil.completeUrl(host + ":" + port, url); | |||||
} | |||||
} |
@@ -0,0 +1,50 @@ | |||||
package com.nsgk.agentcentersdk.api; | |||||
import com.nsgk.agentcentersdk.core.NSReportObject; | |||||
import com.nsgk.agentcentersdk.entity.NSEntityBase; | |||||
import com.nsgk.agentcentersdk.utility.NSArr; | |||||
import com.nsgk.agentcentersdk.utility.NSCrypto; | |||||
import com.nsgk.agentcentersdk.utility.NSHttp; | |||||
import javax.servlet.http.HttpServletRequest; | |||||
import java.util.Map; | |||||
// SDK服务端 | |||||
public final class NSSDKServer | |||||
{ | |||||
private final String privateKey; | |||||
public NSSDKServer(String privateKey) | |||||
{ | |||||
this.privateKey = privateKey; | |||||
} | |||||
// 解析请求 | |||||
public <T extends NSEntityBase> NSReportObject<T> Recv(HttpServletRequest request, Class<T> clazz) | |||||
{ | |||||
NSReportObject<T> res; | |||||
String sign; | |||||
String data; | |||||
sign = request.getHeader("sign"); | |||||
data = NSHttp.GetRequestBody(request); | |||||
res = new NSReportObject<>(); | |||||
res.SetTimestampStr(request.getParameter("timestamp")) | |||||
.setIdentifier(request.getParameter("identifier")) | |||||
.SetProtocolStr(request.getParameter("protocol")) | |||||
.SetDataStr(NSCrypto.RSADecrypt(data, privateKey), clazz) | |||||
; | |||||
if(!res.CheckSign(sign)) | |||||
{ | |||||
return null; | |||||
} | |||||
res.setSign(sign); | |||||
return res; | |||||
} | |||||
// 响应客户端 | |||||
public NSApiResult Resp(int code, String msg, Object...data) | |||||
{ | |||||
return new NSApiResult(code, msg, NSArr.DefParms(data)); | |||||
} | |||||
} |
@@ -0,0 +1,17 @@ | |||||
package com.nsgk.agentcentersdk.core; | |||||
// 协议常量 | |||||
public final class NSProtocol | |||||
{ | |||||
public static final int NS_PROTOCOL_INVALID = 0; | |||||
public static final int NS_PROTOCOL_TEST = 0x00001; | |||||
public static final int NS_PROTOCOL_CONTRACTION = 0x10001; | |||||
public static int FromString(String str) | |||||
{ | |||||
int i = Integer.parseInt(str); | |||||
return Math.abs(i); | |||||
} | |||||
private NSProtocol() {} | |||||
} |
@@ -0,0 +1,93 @@ | |||||
package com.nsgk.agentcentersdk.core; | |||||
import cn.hutool.core.bean.BeanUtil; | |||||
import com.alibaba.fastjson2.JSON; | |||||
import com.nsgk.agentcentersdk.utility.NSSignTool; | |||||
import com.nsgk.agentcentersdk.utility.NSStr; | |||||
import lombok.Data; | |||||
import lombok.experimental.Accessors; | |||||
import java.util.Map; | |||||
// 封装对象 | |||||
@Data | |||||
@Accessors(chain = true) | |||||
public class NSReportObject<T> | |||||
{ | |||||
protected static final String[] SIGN_FIELDS = { | |||||
"identifier", "protocol", "timestamp", "dataLength", | |||||
}; | |||||
private String identifier; // 识别ID | |||||
private String sign; // 签名 | |||||
private int protocol = NSProtocol.NS_PROTOCOL_INVALID; // 协议 | |||||
private Long timestamp; // 客户端时间戳 | |||||
private T data; | |||||
private String dataStr = ""; | |||||
public NSReportObject<T> setData(T d) | |||||
{ | |||||
data = d; | |||||
dataStr = ""; | |||||
if(null != data) | |||||
dataStr = JSON.toJSONString(data); | |||||
return this; | |||||
} | |||||
public NSReportObject<T> SetDataStr(String str, Class<T> clazz) | |||||
{ | |||||
data = JSON.parseObject(str, clazz); | |||||
dataStr = str; | |||||
return this; | |||||
} | |||||
public NSReportObject() | |||||
{ | |||||
} | |||||
public NSReportObject(String identifier, int protocol) | |||||
{ | |||||
this(identifier, protocol, null); | |||||
} | |||||
public NSReportObject(String identifier, int protocol, T data) | |||||
{ | |||||
this.identifier = identifier; | |||||
this.protocol = protocol; | |||||
timestamp = System.currentTimeMillis(); | |||||
setData(data); | |||||
sign = Sign(); | |||||
} | |||||
public boolean IsValid() | |||||
{ | |||||
return NSStr.IsNotEmpty(identifier) && null != timestamp && protocol > 0; | |||||
} | |||||
public String Sign() | |||||
{ | |||||
Map<String, Object> map; | |||||
map = BeanUtil.beanToMap(this); | |||||
map.put("dataLength", NSStr.Length(dataStr)); | |||||
return NSSignTool.Sign(map, SIGN_FIELDS); | |||||
} | |||||
public boolean CheckSign(String src) | |||||
{ | |||||
if(!IsValid()) | |||||
return false; | |||||
return src.equals(Sign()); | |||||
} | |||||
public NSReportObject<T> SetTimestampStr(String str) | |||||
{ | |||||
timestamp = Long.parseLong(str); | |||||
return this; | |||||
} | |||||
public NSReportObject<T> SetProtocolStr(String str) | |||||
{ | |||||
protocol = NSProtocol.FromString(str); | |||||
return this; | |||||
} | |||||
} |
@@ -0,0 +1,19 @@ | |||||
package com.nsgk.agentcentersdk.entity; | |||||
import lombok.Data; | |||||
import lombok.experimental.Accessors; | |||||
// 合同实体 | |||||
@Data | |||||
@Accessors(chain = true) | |||||
public class NSContractionEntity extends NSEntityBase | |||||
{ | |||||
private static final long serialVersionUID = 1L; | |||||
/** 合同名称 */ | |||||
private String name; | |||||
/** 签订日期 */ | |||||
private String buildingTime; | |||||
} |
@@ -0,0 +1,23 @@ | |||||
package com.nsgk.agentcentersdk.entity; | |||||
import lombok.Data; | |||||
import lombok.experimental.Accessors; | |||||
import java.io.Serializable; | |||||
// 基本实体 | |||||
@Data | |||||
@Accessors(chain = true) | |||||
public abstract class NSEntityBase implements Serializable | |||||
{ | |||||
private static final long serialVersionUID = 1L; | |||||
/** 账套ID */ | |||||
protected Long bookId; | |||||
/** 部门id */ | |||||
protected Long deptId; | |||||
/** 外部ID */ | |||||
private Long outId; | |||||
} |
@@ -0,0 +1,34 @@ | |||||
package com.nsgk.agentcentersdk.network; | |||||
import cn.hutool.http.HttpRequest; | |||||
import cn.hutool.http.HttpResponse; | |||||
import cn.hutool.http.HttpUtil; | |||||
import cn.hutool.http.Method; | |||||
import com.nsgk.agentcentersdk.utility.NSHttp; | |||||
// Http网络 | |||||
public final class NSNetworkManager | |||||
{ | |||||
public static NSNetworkResponse Post(NSNetworkRequest req) | |||||
{ | |||||
HttpRequest network; | |||||
HttpResponse execute; | |||||
NSNetworkResponse response; | |||||
network = CreateRequest(NSHttp.BuildUrl(req.getUrl(), req.getQuery()), "post"); | |||||
req.getHeaders().forEach(network::header); | |||||
network.body(req.getData()); | |||||
execute = network.execute(); | |||||
response = new NSNetworkResponse(); | |||||
response.setData(execute.body()); | |||||
response.setUrl(req.getUrl()); | |||||
execute.headers().forEach(response::AddHeader); | |||||
response.setStatusCode(execute.getStatus()); | |||||
return response; | |||||
} | |||||
private static HttpRequest CreateRequest(String url, String method) | |||||
{ | |||||
return HttpUtil.createRequest(Method.valueOf(method.toUpperCase()), url); | |||||
} | |||||
} |
@@ -0,0 +1,25 @@ | |||||
package com.nsgk.agentcentersdk.network; | |||||
import com.nsgk.agentcentersdk.core.NSReportObject; | |||||
import com.nsgk.agentcentersdk.utility.NSCrypto; | |||||
import lombok.Data; | |||||
import lombok.experimental.Accessors; | |||||
// Http请求 | |||||
@Data | |||||
@Accessors(chain = true) | |||||
public class NSNetworkRequest extends NSNetworkTransport | |||||
{ | |||||
public <T> void WriteDataObject(NSReportObject<T> object, String publicKey) | |||||
{ | |||||
String dataStr; | |||||
ClearHeaders().AddHeader("sign", object.getSign()); | |||||
ClearQueries().AddQuery("identifier", object.getIdentifier()) | |||||
.AddQuery("protocol", object.getProtocol()) | |||||
.AddQuery("timestamp", object.getTimestamp()) | |||||
; | |||||
dataStr = object.getDataStr(); | |||||
setData(NSCrypto.RSAEncrypt(dataStr, publicKey)); | |||||
} | |||||
} |
@@ -0,0 +1,19 @@ | |||||
package com.nsgk.agentcentersdk.network; | |||||
import cn.hutool.http.HttpStatus; | |||||
import com.nsgk.agentcentersdk.core.NSReportObject; | |||||
import lombok.Data; | |||||
import lombok.experimental.Accessors; | |||||
// Http响应 | |||||
@Data | |||||
@Accessors(chain = true) | |||||
public class NSNetworkResponse extends NSNetworkTransport | |||||
{ | |||||
private Integer statusCode; | |||||
public boolean IsSuccess() | |||||
{ | |||||
return null != statusCode && statusCode == HttpStatus.HTTP_OK; | |||||
} | |||||
} |
@@ -0,0 +1,62 @@ | |||||
package com.nsgk.agentcentersdk.network; | |||||
import com.nsgk.agentcentersdk.utility.NSArr; | |||||
import com.nsgk.agentcentersdk.utility.NSStr; | |||||
import lombok.Data; | |||||
import lombok.experimental.Accessors; | |||||
import java.util.HashMap; | |||||
import java.util.LinkedHashMap; | |||||
import java.util.Map; | |||||
// Http传输 | |||||
@Data | |||||
@Accessors(chain = true) | |||||
public class NSNetworkTransport | |||||
{ | |||||
private String url; | |||||
private final Map<String, String> headers = new LinkedHashMap<>(); | |||||
private final Map<String, Object> query = new LinkedHashMap<>(); | |||||
private String data; | |||||
public NSNetworkTransport() {} | |||||
public NSNetworkTransport(String url) | |||||
{ | |||||
this.url = url; | |||||
} | |||||
public NSNetworkTransport ClearHeaders() | |||||
{ | |||||
headers.clear(); | |||||
return this; | |||||
} | |||||
public NSNetworkTransport AddHeader(String name, Object value) | |||||
{ | |||||
headers.put(name, NSStr.ToString(value)); | |||||
return this; | |||||
} | |||||
public String Header(String name, String...value) | |||||
{ | |||||
return headers.getOrDefault(name, NSArr.DefParms(value)); | |||||
} | |||||
public NSNetworkTransport ClearQueries() | |||||
{ | |||||
query.clear(); | |||||
return this; | |||||
} | |||||
public NSNetworkTransport AddQuery(String name, Object value) | |||||
{ | |||||
query.put(name, value); | |||||
return this; | |||||
} | |||||
public Object Query(String name, Object...value) | |||||
{ | |||||
return query.getOrDefault(name, NSArr.DefParms(value)); | |||||
} | |||||
} |
@@ -0,0 +1,14 @@ | |||||
package com.nsgk.agentcentersdk.utility; | |||||
// 数组工具 | |||||
public final class NSArr | |||||
{ | |||||
public static <T> T DefParms(T...args) | |||||
{ | |||||
if(null == args || args.length == 0) | |||||
return null; | |||||
return args[0]; | |||||
} | |||||
private NSArr() {} | |||||
} |
@@ -0,0 +1,17 @@ | |||||
package com.nsgk.agentcentersdk.utility; | |||||
// 转换工具 | |||||
public final class NSConv | |||||
{ | |||||
public static boolean FALSE(Boolean b) | |||||
{ | |||||
return null != b ? b : false; | |||||
} | |||||
public static boolean TRUE(Boolean b) | |||||
{ | |||||
return null != b ? b : true; | |||||
} | |||||
private NSConv() {} | |||||
} |
@@ -0,0 +1,37 @@ | |||||
package com.nsgk.agentcentersdk.utility; | |||||
import cn.hutool.core.codec.Base64; | |||||
import cn.hutool.core.util.StrUtil; | |||||
import cn.hutool.crypto.SecureUtil; | |||||
import cn.hutool.crypto.asymmetric.KeyType; | |||||
import cn.hutool.crypto.asymmetric.RSA; | |||||
import java.nio.charset.StandardCharsets; | |||||
// 加密工具 | |||||
public final class NSCrypto | |||||
{ | |||||
// RSA公钥加密(客户端) raw -> base64 | |||||
public static String RSAEncrypt(String rawData, String publicKey_base64) | |||||
{ | |||||
RSA rsa; | |||||
if(NSStr.IsEmpty(rawData) || NSStr.IsEmpty(publicKey_base64)) | |||||
return ""; | |||||
rsa = SecureUtil.rsa(null, publicKey_base64); | |||||
return rsa.encryptBase64(rawData, KeyType.PublicKey); | |||||
} | |||||
// RSA私钥解密(服务端) base64 -> raw | |||||
public static String RSADecrypt(String encryptBase64Data, String privateKey_base64) | |||||
{ | |||||
RSA rsa; | |||||
if(NSStr.IsEmpty(encryptBase64Data) || NSStr.IsEmpty(privateKey_base64)) | |||||
return ""; | |||||
rsa = SecureUtil.rsa(privateKey_base64, null); | |||||
return StrUtil.str(rsa.decrypt(Base64.decode(encryptBase64Data), KeyType.PrivateKey), StandardCharsets.UTF_8); | |||||
} | |||||
private NSCrypto() {} | |||||
} |
@@ -0,0 +1,61 @@ | |||||
package com.nsgk.agentcentersdk.utility; | |||||
import cn.hutool.core.collection.CollectionUtil; | |||||
import cn.hutool.core.io.IoUtil; | |||||
import cn.hutool.core.net.url.UrlQuery; | |||||
import cn.hutool.core.util.URLUtil; | |||||
import javax.servlet.ServletInputStream; | |||||
import javax.servlet.http.HttpServletRequest; | |||||
import java.io.BufferedReader; | |||||
import java.nio.charset.StandardCharsets; | |||||
import java.util.LinkedHashMap; | |||||
import java.util.Map; | |||||
// Http工具 | |||||
public final class NSHttp | |||||
{ | |||||
public static Map<String, String> ParseQuery(String str) | |||||
{ | |||||
Map<String, String> map; | |||||
Map<CharSequence, CharSequence> queryMap; | |||||
map = new LinkedHashMap<>(); | |||||
if(NSStr.IsEmpty(str)) | |||||
return map; | |||||
queryMap = UrlQuery.of(str, StandardCharsets.UTF_8).getQueryMap(); | |||||
queryMap.forEach((k, v) -> map.put(k.toString(), NSStr.ToString(v))); | |||||
return map; | |||||
} | |||||
public static String GetRequestBody(HttpServletRequest request) | |||||
{ | |||||
ServletInputStream reader; | |||||
reader = null; | |||||
try | |||||
{ | |||||
reader = request.getInputStream(); | |||||
return IoUtil.read(reader, StandardCharsets.UTF_8); | |||||
} | |||||
catch(Exception e) | |||||
{ | |||||
e.printStackTrace(); | |||||
return ""; | |||||
} | |||||
finally | |||||
{ | |||||
IoUtil.close(reader); | |||||
} | |||||
} | |||||
public static String BuildUrl(String url, Map<String, Object> query) | |||||
{ | |||||
if(CollectionUtil.isEmpty(query)) | |||||
return url; | |||||
return url + "?" + URLUtil.buildQuery(query, StandardCharsets.UTF_8); | |||||
} | |||||
private NSHttp() {} | |||||
} |
@@ -0,0 +1,37 @@ | |||||
package com.nsgk.agentcentersdk.utility; | |||||
import cn.hutool.core.bean.BeanUtil; | |||||
import cn.hutool.crypto.SecureUtil; | |||||
import java.util.Arrays; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import java.util.stream.Collectors; | |||||
// 签名工具 | |||||
public final class NSSignTool | |||||
{ | |||||
public static String Sign(Object object, String...signFields) | |||||
{ | |||||
return Sign(BeanUtil.beanToMap(object), signFields); | |||||
} | |||||
public static String Sign(Map<String, Object> map, String...signFields) | |||||
{ | |||||
List<String> fields; | |||||
StringBuilder sb; | |||||
fields = Arrays.stream(signFields).sorted(String::compareTo).collect(Collectors.toList()); | |||||
sb = new StringBuilder(); | |||||
for(int i = 0; i < fields.size(); i++) | |||||
{//dataLength=69&identifier=test&protocol=1×tamp=1683442648774 | |||||
if(i > 0) | |||||
sb.append("&"); | |||||
String key = fields.get(i); | |||||
sb.append(fields.get(i)).append("=").append(map.getOrDefault(key, "")); | |||||
} | |||||
return SecureUtil.md5(sb.toString()); | |||||
} | |||||
private NSSignTool() {} | |||||
} |
@@ -0,0 +1,29 @@ | |||||
package com.nsgk.agentcentersdk.utility; | |||||
// 字符串工具 | |||||
public final class NSStr | |||||
{ | |||||
public static boolean IsEmpty(String str) | |||||
{ | |||||
if(null == str || str.isEmpty()) | |||||
return true; | |||||
return str.trim().isEmpty(); | |||||
} | |||||
public static boolean IsNotEmpty(String str) | |||||
{ | |||||
return !IsEmpty(str); | |||||
} | |||||
public static String ToString(Object obj) | |||||
{ | |||||
return null != obj ? obj.toString() : ""; | |||||
} | |||||
public static int Length(String str) | |||||
{ | |||||
return null != str ? str.length() : 0; | |||||
} | |||||
private NSStr() {} | |||||
} |
@@ -33,6 +33,8 @@ | |||||
<lombok.version>1.16.18</lombok.version> | <lombok.version>1.16.18</lombok.version> | ||||
<hutool.version>5.5.4</hutool.version> | <hutool.version>5.5.4</hutool.version> | ||||
<guava.version>31.1-jre</guava.version> <!--23.5-jre--> | |||||
<agentcentersdk.version>1.0.0nsgk1</agentcentersdk.version> | |||||
</properties> | </properties> | ||||
<!-- 依赖声明 --> | <!-- 依赖声明 --> | ||||
@@ -194,6 +196,18 @@ | |||||
<version>${ruoyi.version}</version> | <version>${ruoyi.version}</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>com.google.guava</groupId> | |||||
<artifactId>guava</artifactId> | |||||
<version>${guava.version}</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.nsgk</groupId> | |||||
<artifactId>agentcenter-sdk</artifactId> | |||||
<version>${agentcentersdk.version}</version> | |||||
</dependency> | |||||
</dependencies> | </dependencies> | ||||
</dependencyManagement> | </dependencyManagement> | ||||
@@ -218,6 +232,14 @@ | |||||
<groupId>cn.hutool</groupId> | <groupId>cn.hutool</groupId> | ||||
<artifactId>hutool-all</artifactId> | <artifactId>hutool-all</artifactId> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>com.google.guava</groupId> | |||||
<artifactId>guava</artifactId> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.nsgk</groupId> | |||||
<artifactId>agentcenter-sdk</artifactId> | |||||
</dependency> | |||||
</dependencies> | </dependencies> | ||||
<build> | <build> | ||||
@@ -17,14 +17,16 @@ public class RuoYiApplication | |||||
// System.setProperty("spring.devtools.restart.enabled", "false"); | // System.setProperty("spring.devtools.restart.enabled", "false"); | ||||
SpringApplication.run(RuoYiApplication.class, args); | SpringApplication.run(RuoYiApplication.class, args); | ||||
System.out.println("(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙ \n" + | System.out.println("(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙ \n" + | ||||
" .-------. ____ __ \n" + | |||||
" | _ _ \\ \\ \\ / / \n" + | |||||
" | ( ' ) | \\ _. / ' \n" + | |||||
" |(_ o _) / _( )_ .' \n" + | |||||
" | (_,_).' __ ___(_ o _)' \n" + | |||||
" | |\\ \\ | || |(_,_)' \n" + | |||||
" | | \\ `' /| `-' / \n" + | |||||
" | | \\ / \\ / \n" + | |||||
" ''-' `'-' `-..-' "); | |||||
"\n" + | |||||
"__/\\\\\\\\\\_____/\\\\\\______________/\\\\\\\\\\\\\\\\\\\\\\________________/\\\\\\\\\\\\\\\\\\\\\\\\___________/\\\\\\________/\\\\\\_ \n" + | |||||
" _\\/\\\\\\\\\\\\___\\/\\\\\\____________/\\\\\\/////////\\\\\\____________/\\\\\\//////////___________\\/\\\\\\_____/\\\\\\//__ \n" + | |||||
" _\\/\\\\\\/\\\\\\__\\/\\\\\\___________\\//\\\\\\______\\///____________/\\\\\\______________________\\/\\\\\\__/\\\\\\//_____ \n" + | |||||
" _\\/\\\\\\//\\\\\\_\\/\\\\\\____________\\////\\\\\\__________________\\/\\\\\\____/\\\\\\\\\\\\\\__________\\/\\\\\\\\\\\\//\\\\\\_____ \n" + | |||||
" _\\/\\\\\\\\//\\\\\\\\/\\\\\\_______________\\////\\\\\\_______________\\/\\\\\\___\\/////\\\\\\__________\\/\\\\\\//_\\//\\\\\\____ \n" + | |||||
" _\\/\\\\\\_\\//\\\\\\/\\\\\\__________________\\////\\\\\\____________\\/\\\\\\_______\\/\\\\\\__________\\/\\\\\\____\\//\\\\\\___ \n" + | |||||
" _\\/\\\\\\__\\//\\\\\\\\\\\\___________/\\\\\\______\\//\\\\\\___________\\/\\\\\\_______\\/\\\\\\__________\\/\\\\\\_____\\//\\\\\\__ \n" + | |||||
" _\\/\\\\\\___\\//\\\\\\\\\\__________\\///\\\\\\\\\\\\\\\\\\\\\\/____________\\//\\\\\\\\\\\\\\\\\\\\\\\\/___________\\/\\\\\\______\\//\\\\\\_ \n" + | |||||
" _\\///_____\\/////_____________\\///////////_______________\\////////////_____________\\///________\\///__\n" | |||||
); | |||||
} | } | ||||
} | } |
@@ -0,0 +1,50 @@ | |||||
package com.ruoyi.web.controller.agentcenter; | |||||
import com.nsgk.agentcentersdk.api.NSApiResult; | |||||
import com.nsgk.agentcentersdk.api.NSSDK; | |||||
import com.nsgk.agentcentersdk.api.NSSDKServer; | |||||
import com.nsgk.agentcentersdk.core.NSReportObject; | |||||
import com.nsgk.agentcentersdk.entity.NSContractionEntity; | |||||
import com.ruoyi.common.config.RuoYiConfig; | |||||
import com.ruoyi.common.core.controller.BaseController; | |||||
import org.springframework.web.bind.annotation.PostMapping; | |||||
import org.springframework.web.bind.annotation.RequestMapping; | |||||
import org.springframework.web.bind.annotation.RestController; | |||||
import javax.servlet.http.HttpServletRequest; | |||||
/** | |||||
* 上报接口Controller | |||||
* | |||||
* @author zhao | |||||
*/ | |||||
@RestController | |||||
@RequestMapping("/agentcenter/api") | |||||
public class AgentCenterController extends BaseController | |||||
{ | |||||
@PostMapping("/test") | |||||
public NSApiResult test(HttpServletRequest request) | |||||
{ | |||||
NSSDKServer server; | |||||
NSReportObject<NSContractionEntity> recv; | |||||
NSSDK.InitServer(RuoYiConfig.Secret.privateKey); | |||||
server = NSSDK.InstanceServer(); | |||||
recv = server.Recv(request, NSContractionEntity.class); | |||||
return server.Resp(200, "测试成功", recv.getDataStr()); | |||||
} | |||||
@PostMapping("/report") | |||||
public NSApiResult report(HttpServletRequest request) | |||||
{ | |||||
NSSDKServer server; | |||||
NSReportObject<NSContractionEntity> recv; | |||||
NSSDK.InitServer(RuoYiConfig.Secret.privateKey); | |||||
server = NSSDK.InstanceServer(); | |||||
recv = server.Recv(request, NSContractionEntity.class); | |||||
return server.Resp(200, "上报成功", recv.getDataStr()); | |||||
} | |||||
} |
@@ -129,3 +129,11 @@ xss: | |||||
excludes: /system/notice | excludes: /system/notice | ||||
# 匹配链接 | # 匹配链接 | ||||
urlPatterns: /system/*,/monitor/*,/tool/* | urlPatterns: /system/*,/monitor/*,/tool/* | ||||
secret: | |||||
disabled: false # UNUSED | |||||
# 客户端公钥 | |||||
publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ== | |||||
# 服务端私钥 | |||||
privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y= |
@@ -22,6 +22,10 @@ | |||||
<groupId>com.ruoyi</groupId> | <groupId>com.ruoyi</groupId> | ||||
<artifactId>ruoyi-common</artifactId> | <artifactId>ruoyi-common</artifactId> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>com.ruoyi</groupId> | |||||
<artifactId>ruoyi-common</artifactId> | |||||
</dependency> | |||||
</dependencies> | </dependencies> | ||||
@@ -0,0 +1,26 @@ | |||||
package com.ruoyi.agentcenter.listener; | |||||
import com.google.common.eventbus.AllowConcurrentEvents; | |||||
import com.google.common.eventbus.Subscribe; | |||||
import com.ruoyi.common.object.Message; | |||||
import com.ruoyi.common.utils.EventBusEngine; | |||||
import org.springframework.stereotype.Component; | |||||
import javax.annotation.PostConstruct; | |||||
@Component | |||||
public class TestListener | |||||
{ | |||||
@PostConstruct | |||||
public void init() | |||||
{ | |||||
EventBusEngine.Register(this); | |||||
} | |||||
@Subscribe | |||||
//@AllowConcurrentEvents | |||||
public void handle(Message msg) | |||||
{ | |||||
System.err.println("LLL " + msg.data + " " + Thread.currentThread().getId()); | |||||
} | |||||
} |
@@ -3,6 +3,8 @@ package com.ruoyi.common.config; | |||||
import org.springframework.boot.context.properties.ConfigurationProperties; | import org.springframework.boot.context.properties.ConfigurationProperties; | ||||
import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||
import java.nio.charset.StandardCharsets; | |||||
/** | /** | ||||
* 读取项目相关配置 | * 读取项目相关配置 | ||||
* | * | ||||
@@ -132,4 +134,29 @@ public class RuoYiConfig | |||||
{ | { | ||||
return getProfile() + "/upload"; | return getProfile() + "/upload"; | ||||
} | } | ||||
@Component | |||||
@ConfigurationProperties(prefix = "secret") | |||||
public static class Secret { | |||||
public static Boolean disabled; | |||||
public static String publicKey; | |||||
public static String privateKey; | |||||
public void setDisabled(Boolean disabled) { | |||||
Secret.disabled = disabled; | |||||
} | |||||
public void setPublicKey(String publicKey) { | |||||
Secret.publicKey = publicKey; | |||||
} | |||||
public void setPrivateKey(String privateKey) { | |||||
Secret.privateKey = privateKey; | |||||
} | |||||
public static boolean isDisabled() { | |||||
return null != Secret.disabled /*默认加密*/ && Secret.disabled; | |||||
} | |||||
} | |||||
} | } |
@@ -0,0 +1,14 @@ | |||||
package com.ruoyi.common.object; | |||||
import lombok.Data; | |||||
import lombok.experimental.Accessors; | |||||
@Data | |||||
@Accessors(chain = true) | |||||
public final class Message | |||||
{ | |||||
public static final int PROTOCOL_INVALID = 0; | |||||
public int protocol = PROTOCOL_INVALID; | |||||
public Object data; | |||||
} |
@@ -0,0 +1,71 @@ | |||||
package com.ruoyi.common.utils; | |||||
import com.google.common.eventbus.EventBus; | |||||
import org.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.beans.factory.annotation.Qualifier; | |||||
import org.springframework.stereotype.Component; | |||||
import javax.annotation.PreDestroy; | |||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
@Component | |||||
public final class EventBusEngine | |||||
{ | |||||
private static final Logger logger = LoggerFactory.getLogger("EventBusEngine" ); | |||||
private static EventBus _eventBus; | |||||
private static final List<Object> _listenerList = new ArrayList<>(); | |||||
@Autowired | |||||
public void setAsyncEventBus(@Qualifier("asyncEventBus" ) EventBus eventBus) | |||||
{ | |||||
EventBusEngine._eventBus = eventBus; | |||||
logger.info("EventBusEngine::initialization -> " + eventBus); | |||||
} | |||||
public static void Post(Object message) | |||||
{ | |||||
_eventBus.post(message); | |||||
} | |||||
public static void Register(Object listener) | |||||
{ | |||||
if(null == listener) | |||||
return; | |||||
synchronized(_listenerList) { | |||||
if(_listenerList.contains(listener)) | |||||
return; | |||||
_eventBus.register(listener); | |||||
_listenerList.add(listener); | |||||
logger.info("EventBusEngine::Register -> " + listener); | |||||
} | |||||
} | |||||
public static void Unregister(Object listener) | |||||
{ | |||||
if(null == listener) | |||||
return; | |||||
synchronized(_listenerList) { | |||||
if(!_listenerList.contains(listener)) | |||||
return; | |||||
_eventBus.unregister(listener); | |||||
_listenerList.remove(listener); | |||||
logger.info("EventBusEngine::Unregister -> " + listener); | |||||
} | |||||
} | |||||
@PreDestroy | |||||
public static void UnregisterAll() | |||||
{ | |||||
synchronized(_listenerList) { | |||||
logger.info("EventBusEngine::UnregisterAll -> " + _listenerList.size()); | |||||
if(!_listenerList.isEmpty()) | |||||
{ | |||||
_listenerList.forEach(_eventBus::unregister); | |||||
_listenerList.clear(); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,33 @@ | |||||
package com.ruoyi.framework.config; | |||||
import com.google.common.eventbus.AsyncEventBus; | |||||
import com.google.common.eventbus.EventBus; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.springframework.beans.factory.annotation.Qualifier; | |||||
import org.springframework.context.annotation.Bean; | |||||
import org.springframework.context.annotation.Lazy; | |||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | |||||
import org.springframework.stereotype.Component; | |||||
/** | |||||
* EventBus配置 | |||||
* | |||||
* @author zhao | |||||
*/ | |||||
@Component | |||||
public class EventBusConfig | |||||
{ | |||||
@Bean("asyncEventBus") | |||||
@Lazy(value = true) | |||||
public EventBus asyncEventBus(@Qualifier("threadPoolTaskExecutor" ) ThreadPoolTaskExecutor threadPool) | |||||
{ | |||||
return new AsyncEventBus("AsyncReportQueue", threadPool); | |||||
} | |||||
@Bean("syncEventBus") | |||||
@Lazy(value = true) | |||||
public EventBus syncEventBus() | |||||
{ | |||||
return new EventBus("SyncReportQueue"); | |||||
} | |||||
} |
@@ -115,6 +115,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter | |||||
// 静态资源,可匿名访问 | // 静态资源,可匿名访问 | ||||
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll() | .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll() | ||||
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll() | .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll() | ||||
// 外部上报通道 | |||||
.antMatchers("/agentcenter/api/**").permitAll() | |||||
// 除上面外的所有请求全部需要鉴权认证 | // 除上面外的所有请求全部需要鉴权认证 | ||||
.anyRequest().authenticated() | .anyRequest().authenticated() | ||||
.and() | .and() | ||||