| @@ -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() | ||||