@@ -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> | |||
<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> | |||
<!-- 依赖声明 --> | |||
@@ -194,6 +196,18 @@ | |||
<version>${ruoyi.version}</version> | |||
</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> | |||
</dependencyManagement> | |||
@@ -218,6 +232,14 @@ | |||
<groupId>cn.hutool</groupId> | |||
<artifactId>hutool-all</artifactId> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.google.guava</groupId> | |||
<artifactId>guava</artifactId> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.nsgk</groupId> | |||
<artifactId>agentcenter-sdk</artifactId> | |||
</dependency> | |||
</dependencies> | |||
<build> | |||
@@ -17,14 +17,16 @@ public class RuoYiApplication | |||
// System.setProperty("spring.devtools.restart.enabled", "false"); | |||
SpringApplication.run(RuoYiApplication.class, args); | |||
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 | |||
# 匹配链接 | |||
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> | |||
<artifactId>ruoyi-common</artifactId> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.ruoyi</groupId> | |||
<artifactId>ruoyi-common</artifactId> | |||
</dependency> | |||
</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.stereotype.Component; | |||
import java.nio.charset.StandardCharsets; | |||
/** | |||
* 读取项目相关配置 | |||
* | |||
@@ -132,4 +134,29 @@ public class RuoYiConfig | |||
{ | |||
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("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll() | |||
// 外部上报通道 | |||
.antMatchers("/agentcenter/api/**").permitAll() | |||
// 除上面外的所有请求全部需要鉴权认证 | |||
.anyRequest().authenticated() | |||
.and() | |||