commit 7ee96edd3aa6210669c525d2ac7586728f91e977 Author: pioneer Date: Fri Jul 29 15:33:54 2022 +0800 open diff --git a/README.md b/README.md new file mode 100644 index 0000000..54787e1 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# open-JSD-9778 + +JSD-9778 通过获取统计数据接口,实现程序数据集功能\ +免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\ +仅作为开发者学习参考使用!禁止用于任何商业用途!\ +为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系【pioneer】处理。 \ No newline at end of file diff --git a/doc/JSD-9778-需求确认书V1.docx b/doc/JSD-9778-需求确认书V1.docx new file mode 100644 index 0000000..e0623cc Binary files /dev/null and b/doc/JSD-9778-需求确认书V1.docx differ diff --git a/doc/JSD-9778配置使用文档.docx b/doc/JSD-9778配置使用文档.docx new file mode 100644 index 0000000..2faf6ff Binary files /dev/null and b/doc/JSD-9778配置使用文档.docx differ diff --git a/doc/apiDataset.cpt b/doc/apiDataset.cpt new file mode 100644 index 0000000..f4f699c --- /dev/null +++ b/doc/apiDataset.cpt @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
diff --git a/lib/finekit-10.0.jar b/lib/finekit-10.0.jar new file mode 100644 index 0000000..f4482fc Binary files /dev/null and b/lib/finekit-10.0.jar differ diff --git a/plugin.xml b/plugin.xml new file mode 100644 index 0000000..fc32a44 --- /dev/null +++ b/plugin.xml @@ -0,0 +1,24 @@ + + + com.fr.plugin.xxx.dataset + + yes + 1.2 + 10.0 + 2018-07-31 + fr.open + + + com.fr.plugin.xxx + + com.fanruan.api + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/xxx/LocaleFinder.java b/src/main/java/com/fr/plugin/xxx/LocaleFinder.java new file mode 100644 index 0000000..b5f2dcc --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/LocaleFinder.java @@ -0,0 +1,40 @@ + /* + * Copyright (C), 2018-2020 + * Project: starter + * FileName: LocaleFinder + * Author: xxx + * Date: 2020/8/31 22:19 + */ + package com.fr.plugin.xxx; + + import com.fr.intelli.record.Focus; + import com.fr.intelli.record.Original; + import com.fr.record.analyzer.EnableMetrics; + import com.fr.stable.fun.Authorize; + import com.fr.stable.fun.impl.AbstractLocaleFinder; + + import static com.fr.plugin.xxx.LocaleFinder.PLUGIN_ID; + + /** + *
+ * + * + * @author xxx + * @since 1.0.0 + */ + @EnableMetrics + @Authorize(callSignKey = PLUGIN_ID) + public class LocaleFinder extends AbstractLocaleFinder { + public static final String PLUGIN_ID = "com.fr.plugin.xxx.dataset"; + + @Override + @Focus(id = PLUGIN_ID, text = "Plugin-xxx", source = Original.PLUGIN) + public String find() { + return "com/fr/plugin/xxx/locale/lang"; + } + + @Override + public int currentAPILevel() { + return CURRENT_LEVEL; + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/xxx/data/UsersTableData.java b/src/main/java/com/fr/plugin/xxx/data/UsersTableData.java new file mode 100644 index 0000000..2bf7807 --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/data/UsersTableData.java @@ -0,0 +1,45 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: WechatTableData + * Author: xxx + * Date: 2021/12/8 16:55 + */ + package com.fr.plugin.xxx.data; + + import com.fanruan.api.data.open.BaseTableData; + import com.fr.base.TableData; + import com.fr.general.data.DataModel; + import com.fr.script.Calculator; + + /** + *
+ * + * + * @author xxx + * @since 1.0.0 + */ + public class UsersTableData extends BaseTableData { + private static final long serialVersionUID = -7456007025209900779L; + + @Override + public DataModel createDataModel(Calculator calculator) { + return createDataModel(calculator, TableData.RESULT_ALL); + } + + @Override + public DataModel createDataModel(Calculator calculator, int rowCount) { + return new UsersTableDataModel(Calculator.processParameters(calculator, super.getParameters(calculator))); + } + + @Override + public Object clone() throws CloneNotSupportedException { + UsersTableData cloned = (UsersTableData) super.clone(); + return cloned; + } + + @Override + public boolean equals(Object obj) { + return obj instanceof UsersTableData; + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/xxx/data/UsersTableDataModel.java b/src/main/java/com/fr/plugin/xxx/data/UsersTableDataModel.java new file mode 100644 index 0000000..9f6730d --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/data/UsersTableDataModel.java @@ -0,0 +1,104 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: WechatTableDataModel + * Author: xxx + * Date: 2021/12/8 19:09 + */ + package com.fr.plugin.xxx.data; + + import com.fanruan.api.i18n.I18nKit; + import com.fanruan.api.log.LogKit; + import com.fr.json.JSONArray; + import com.fr.json.JSONObject; + import com.fr.log.FineLoggerFactory; + import com.fr.plugin.context.PluginContexts; + import com.fr.plugin.xxx.kit.HttpKit; + import com.fr.plugin.xxx.util.RSAUtils; + import com.fr.stable.ParameterProvider; + import com.fr.third.org.apache.commons.codec.binary.Base64; + + import java.io.IOException; + import java.util.ArrayList; + import java.util.HashMap; + import java.util.Map; + + /** + *
+ * + * + * @author xxx + * @since 1.0.0 + */ + public class UsersTableDataModel extends WebTableDataModel { + public static final String TOTAL_CAGE_SUM = "totalCageSum"; + public static final String FREE_PRE = "freePre"; + public static final String NAME = "name"; + public static final String FREE_CAGE_SUM = "freeCageSum"; + public static final String FEED_ANIMAL_SUM = "feedAnimalSum"; + private static final long serialVersionUID = 1561845127687781184L; + + public UsersTableDataModel(ParameterProvider[] parameters) { + super(parameters); +// this.columnNames = new String[]{TOTAL_CAGE_SUM, FREE_PRE, NAME, FREE_CAGE_SUM, FEED_ANIMAL_SUM}; + this.columnNames = new String[]{"总笼位", "空置率", "名称", "空笼位", "在笼猴子数"}; + } + + @Override + protected void init() { + if (!PluginContexts.currentContext().isAvailable()) { + LogKit.error(I18nKit.getLocText("Plugin-xxx_Licence_Expired")); + return; + } + if (this.valueList != null) { + return; + } + this.valueList = new ArrayList(); + // 域名 + this.host = this.parameters[0].getValue().toString(); + // 应用标识 + String apiKey = this.parameters[1].getValue().toString(); + // 公钥 + String publicKey = this.parameters[2].getValue().toString(); + try { + JSONArray usersInfo = getUserInfo(apiKey, publicKey); + addFRUserInfo2List(usersInfo); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + + /** + * 人员获取 + * + * @param apiKey + * @param publicKey + * @return + * @throws IOException + */ + private JSONArray getUserInfo(String apiKey, String publicKey) throws Exception { + Map header = new HashMap<>(); + header.put("API_KEY", apiKey); + String response = HttpKit.get(this.host, new HashMap<>(), header); + LogKit.info("xxx-UsersTableDataModel-getUserInfo-response:{}", response); + byte[] bytes = Base64.decodeBase64(response); + byte[] decodedData = RSAUtils.decryptByPublicKey(bytes, publicKey); + String decodedDataStr = new String(decodedData); + LogKit.info("xxx-UsersTableDataModel-getUserInfo-decodedData:{}", decodedDataStr); + return new JSONArray(decodedDataStr); + } + + private void addFRUserInfo2List(JSONArray usersInfo) { + ArrayList frUserInfo; + for (Object o : usersInfo) { + JSONObject userInfo = (JSONObject) o; + frUserInfo = new ArrayList<>(); + frUserInfo.add(userInfo.getString(TOTAL_CAGE_SUM)); + frUserInfo.add(userInfo.getString(FREE_PRE)); + frUserInfo.add(userInfo.getString(NAME)); + frUserInfo.add(userInfo.getString(FREE_CAGE_SUM)); + frUserInfo.add(userInfo.getString(FEED_ANIMAL_SUM)); + this.valueList.add(frUserInfo.toArray()); + } + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/xxx/data/WebTableDataModel.java b/src/main/java/com/fr/plugin/xxx/data/WebTableDataModel.java new file mode 100644 index 0000000..b7dc4bf --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/data/WebTableDataModel.java @@ -0,0 +1,62 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: WebTableDataModel + * Author: xxx + * Date: 2021/12/16 8:17 + */ + package com.fr.plugin.xxx.data; + + import com.fanruan.api.data.open.BaseDataModel; + import com.fanruan.api.err.TableDataException; + import com.fr.stable.ParameterProvider; + + import java.util.ArrayList; + + /** + *
+ * + * + * @author xxx + * @since 1.0.0 + */ + public abstract class WebTableDataModel extends BaseDataModel { + private static final long serialVersionUID = 5010918328453603247L; + protected ParameterProvider[] parameters; + protected String[] columnNames; + protected ArrayList valueList = null; + protected String host; + + public WebTableDataModel(ParameterProvider[] parameters) { + this.parameters = parameters; + } + + @Override + public int getColumnCount() throws TableDataException { + return this.columnNames.length; + } + + @Override + public String getColumnName(int i) throws TableDataException { + return columnNames[i]; + } + + @Override + public int getRowCount() throws TableDataException { + init(); + return valueList.size(); + } + + @Override + public Object getValueAt(int row, int col) throws TableDataException { + init(); + return ((Object[]) valueList.get(row))[col]; + } + + @Override + public void release() throws Exception { + this.parameters = null; + } + + protected abstract void init(); + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/xxx/kit/HttpKit.java b/src/main/java/com/fr/plugin/xxx/kit/HttpKit.java new file mode 100644 index 0000000..4aaeaea --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/kit/HttpKit.java @@ -0,0 +1,706 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: HttpKit + * Author: xxx + * Date: 2021/3/17 14:19 + */ + package com.fr.plugin.xxx.kit; + + import com.fanruan.api.log.LogKit; + import com.fanruan.api.macro.EncodeConstants; + import com.fanruan.api.net.http.rs.HttpRequest; + import com.fanruan.api.net.http.rs.*; + import com.fr.third.guava.collect.Maps; + import com.fr.third.org.apache.http.*; + import com.fr.third.org.apache.http.client.HttpRequestRetryHandler; + import com.fr.third.org.apache.http.client.config.RequestConfig; + import com.fr.third.org.apache.http.client.entity.UrlEncodedFormEntity; + import com.fr.third.org.apache.http.client.methods.CloseableHttpResponse; + import com.fr.third.org.apache.http.client.methods.HttpEntityEnclosingRequestBase; + import com.fr.third.org.apache.http.client.methods.HttpRequestBase; + import com.fr.third.org.apache.http.client.protocol.HttpClientContext; + import com.fr.third.org.apache.http.client.utils.URIBuilder; + import com.fr.third.org.apache.http.config.Registry; + import com.fr.third.org.apache.http.config.RegistryBuilder; + import com.fr.third.org.apache.http.conn.routing.HttpRoute; + import com.fr.third.org.apache.http.conn.socket.ConnectionSocketFactory; + import com.fr.third.org.apache.http.conn.socket.LayeredConnectionSocketFactory; + import com.fr.third.org.apache.http.conn.socket.PlainConnectionSocketFactory; + import com.fr.third.org.apache.http.conn.ssl.SSLConnectionSocketFactory; + import com.fr.third.org.apache.http.conn.ssl.SSLSocketFactory; + import com.fr.third.org.apache.http.conn.ssl.TrustStrategy; + import com.fr.third.org.apache.http.entity.FileEntity; + import com.fr.third.org.apache.http.entity.mime.HttpMultipartMode; + import com.fr.third.org.apache.http.entity.mime.MultipartEntityBuilder; + import com.fr.third.org.apache.http.impl.client.CloseableHttpClient; + import com.fr.third.org.apache.http.impl.client.HttpClients; + import com.fr.third.org.apache.http.impl.conn.PoolingHttpClientConnectionManager; + import com.fr.third.org.apache.http.message.BasicNameValuePair; + import com.fr.third.org.apache.http.protocol.HttpContext; + import com.fr.third.org.apache.http.ssl.SSLContextBuilder; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + + import javax.net.ssl.SSLContext; + import javax.net.ssl.SSLException; + import javax.net.ssl.SSLHandshakeException; + import java.io.*; + import java.net.URI; + import java.net.URISyntaxException; + import java.net.URLEncoder; + import java.net.UnknownHostException; + import java.nio.charset.Charset; + import java.security.KeyManagementException; + import java.security.KeyStoreException; + import java.security.NoSuchAlgorithmException; + import java.security.cert.CertificateException; + import java.security.cert.X509Certificate; + import java.util.ArrayList; + import java.util.Collections; + import java.util.List; + import java.util.Map; + + import static com.fanruan.api.net.http.rs.HttpRequestType.POST; + + /** + *

+ * http请求工具类,封装了用于http请求的各种方法 + * 新增https忽略证书功能 Update By xxx on 2021-03-17 + *

+ */ + public class HttpKit { + + private static final int RETRY_TIMES = 5; + private final static Object SYNC_LOCK = new Object(); + private static CloseableHttpClient httpClient = null; + + /** + * 根据请求地址创建HttpClient对象 + * + * @param url 请求地址 + * @return HttpClient对象 + */ + public static CloseableHttpClient getHttpClient(String url) { + String hostname = url.split("/")[2]; + int port = 80; + if (hostname.contains(":")) { + String[] arr = hostname.split(":"); + hostname = arr[0]; + port = Integer.parseInt(arr[1]); + } + if (httpClient == null) { + synchronized (SYNC_LOCK) { + if (httpClient == null) { +// httpClient = createHttpClient(hostname, port, SSLContexts.createDefault()); + try { + httpClient = createHttpClient(hostname, port, createIgnoreVerifySSL()); + } catch (NoSuchAlgorithmException e) { + LogKit.error(e.getMessage(), e); + } catch (KeyManagementException e) { + LogKit.error(e.getMessage(), e); + } + } + } + } + return httpClient; + } + + /** + * 新增了https 请求绕过证书认证 + * + * @return + * @throws NoSuchAlgorithmException + * @throws KeyManagementException + */ + public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException { + + + try { + SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { + //信任所有 + public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { + return true; + } + }).build(); + return sslContext; + } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { + LogKit.error(e.getMessage(), e); + } + return null; + } + + public static CloseableHttpClient createHttpClient(String hostname, int port, SSLContext sslContext) { + return createHttpClient(200, 40, 100, hostname, port, sslContext); + } + + private static CloseableHttpClient createHttpClient(int maxTotal, + int maxPerRoute, + int maxRoute, + String hostname, + int port, + SSLContext sslContext) { + ConnectionSocketFactory socketFactory = PlainConnectionSocketFactory.getSocketFactory(); + LayeredConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + Registry registry = RegistryBuilder + .create() + .register("http", socketFactory) + .register("https", sslConnectionSocketFactory) + .build(); + PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry); + // 将最大连接数增加 + cm.setMaxTotal(maxTotal); + // 将每个路由基础的连接增加 + cm.setDefaultMaxPerRoute(maxPerRoute); + HttpHost httpHost = new HttpHost(hostname, port); + // 将目标主机的最大连接数增加 + cm.setMaxPerRoute(new HttpRoute(httpHost), maxRoute); + + // 请求重试处理 + HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() { + @Override + public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { + if (executionCount >= RETRY_TIMES) {// 如果已经重试了5次,就放弃 + return false; + } + if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接,那么就重试 + return true; + } + if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常 + return false; + } + if (exception instanceof InterruptedIOException) {// 超时 + return false; + } + if (exception instanceof UnknownHostException) {// 目标服务器不可达 + return false; + } + if (exception instanceof SSLException) {// SSL握手异常 + return false; + } + + HttpClientContext clientContext = HttpClientContext.adapt(context); + com.fr.third.org.apache.http.HttpRequest request = clientContext.getRequest(); + // 如果请求是幂等的,就再次尝试 + return !(request instanceof HttpEntityEnclosingRequest); + } + }; + + return HttpClients.custom() + .setConnectionManager(cm) + .setRetryHandler(httpRequestRetryHandler) + .build(); + } + + /** + * 设置 httpEntity + * + * @param requestBase 请求体 + * @param httpRequest 请求 + */ + private static void setHttpEntity(@NotNull HttpEntityEnclosingRequestBase requestBase, @NotNull HttpRequest httpRequest) { + HttpEntity httpEntity = httpRequest.getHttpEntity(); + if (httpEntity != null) { + // 如果存在 httpEntity 直接设置 + requestBase.setEntity(httpEntity); + return; + } + Map params = httpRequest.getParams(); + if (params == null || params.isEmpty()) { + return; + } + List pairs = new ArrayList(); + for (Map.Entry entry : params.entrySet()) { + pairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); + } + try { + requestBase.setEntity(new UrlEncodedFormEntity(pairs, httpRequest.getEncoding())); + } catch (UnsupportedEncodingException e) { + LogKit.error(e.getMessage(), e); + } + } + + private static Map transformMap(Map oldMap) { + if (oldMap == null) { + return null; + } + return Maps.transformEntries(oldMap, new Maps.EntryTransformer() { + @Override + public String transformEntry(@Nullable String key, @Nullable V value) { + return value == null ? null : value.toString(); + } + }); + } + + /** + * 发起POST请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params POST请求的参数 + * @return 服务器返回的文本内容 + */ + public static String post(String url, Map params) throws IOException { + return executeAndParse(HttpRequest + .custom() + .url(url) + .post(transformMap(params)) + .build()); + } + + /** + * 发起POST请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params POST请求的参数 + * @param responseType 返回类型 + * @return 服务器返回的文本内容 + * @see com.fanruan.api.net.http.HttpKit#execute(HttpRequest) + */ + @Deprecated + public static T post(String url, Map params, HttpResponseType responseType) throws IOException { + CloseableHttpResponse response = execute(HttpRequest + .custom() + .url(url) + .post(transformMap(params)) + .build()); + return responseType.result(response, null); + } + + /** + * 发起POST请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params POST请求的参数 + * @param headers 请求头 + * @return 服务器返回的文本内容 + * @see com.fanruan.api.net.http.HttpKit#executeAndParse(HttpRequest) + */ + @Deprecated + public static String post(String url, Map params, Map headers) throws IOException { + return executeAndParse(HttpRequest + .custom() + .url(url) + .post(transformMap(params)) + .headers(headers) + .build()); + } + + /** + * 发起POST请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params POST请求的参数 + * @param headers 请求头 + * @param responseType 返回类型 + * @return 服务器返回的文本内容 + * @see com.fanruan.api.net.http.HttpKit#execute(HttpRequest) + */ + @Deprecated + public static T post(String url, Map params, Map headers, HttpResponseType responseType) throws IOException { + CloseableHttpResponse response = execute(HttpRequest + .custom() + .url(url) + .post(transformMap(params)) + .headers(headers) + .build()); + return responseType.result(response, null); + } + + /** + * 发起POST请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params POST请求的参数 + * @param responseEncoding 响应的文本的编码 + * @return 服务器返回的文本内容 + * @see com.fanruan.api.net.http.HttpKit#executeAndParse(HttpRequest, BaseHttpResponseHandle) + */ + @Deprecated + public static String post(String url, Map params, String responseEncoding) throws IOException { + return executeAndParse(HttpRequest + .custom() + .url(url) + .post(transformMap(params)) + .build(), + new TextResponseHandle(responseEncoding)); + } + + /** + * 发起POST请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params POST请求的参数 + * @param responseEncoding 响应的文本的编码 + * @param headers 请求头 + * @return 服务器返回的文本内容 + * @see com.fanruan.api.net.http.HttpKit#executeAndParse(HttpRequest, BaseHttpResponseHandle) + */ + @Deprecated + public static String post(String url, Map params, String responseEncoding, Map headers) throws IOException { + return executeAndParse(HttpRequest + .custom() + .url(url) + .post(transformMap(params)) + .headers(headers) + .build(), + new TextResponseHandle(responseEncoding)); + } + + + /** + * 发起POST请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params POST请求的参数 + * @param responseEncoding 响应的文本的编码 + * @param paramsEncoding 参数编码 + * @param headers 请求头 + * @return 服务器返回的文本内容 + * @see com.fanruan.api.net.http.HttpKit#executeAndParse(HttpRequest, BaseHttpResponseHandle) + */ + public static String post(String url, Map params, String responseEncoding, String paramsEncoding, Map headers) throws IOException { + return executeAndParse(HttpRequest + .custom() + .url(url) + .post(transformMap(params)) + .encoding(paramsEncoding) + .headers(headers) + .build(), + new TextResponseHandle(responseEncoding)); + } + + /** + * 发起POST请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params POST请求的参数 + * @param responseEncoding 响应的文本的编码 + * @param paramsEncoding 参数编码 + * @param headers 请求头 + * @param responseType 返回值类型 + * @return 服务器返回的文本内容 + * @see com.fanruan.api.net.http.HttpKit#execute(HttpRequest) + */ + public static T post(String url, Map params, String responseEncoding, String paramsEncoding, Map headers, HttpResponseType responseType) throws IOException { + CloseableHttpResponse response = execute(HttpRequest + .custom() + .url(url) + .post(transformMap(params)) + .encoding(paramsEncoding) + .headers(headers) + .build()); + return responseType.result(response, responseEncoding); + } + + /** + * 发起GET请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @return 服务器返回的文本内容 + */ + public static String get(String url) throws IOException { + return executeAndParse(HttpRequest.custom().url(url).build()); + } + + /** + * 发起GET请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params 参数 + * @return 服务器返回的文本内容 + */ + public static String get(String url, Map params) throws IOException { + return executeAndParse(HttpRequest.custom().url(url).params(params).build()); + } + + /** + * 发起GET请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params 参数 + * @param headers 请求头 + * @return 服务器返回的文本内容 + * @see com.fanruan.api.net.http.HttpKit#executeAndParse(HttpRequest, BaseHttpResponseHandle) + */ + public static String get(String url, Map params, Map headers) throws IOException { + return executeAndParse(HttpRequest.custom().url(url).params(params).headers(headers).build()); + } + + /** + * 发起GET请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params 参数 + * @param responseEncoding 返回的文本的编码 + * @return 服务器返回的文本内容 + * @see com.fanruan.api.net.http.HttpKit#executeAndParse(HttpRequest, BaseHttpResponseHandle) + */ + public static String get(String url, Map params, String responseEncoding) throws IOException { + return executeAndParse(HttpRequest + .custom() + .url(url) + .params(params) + .build(), + new TextResponseHandle(responseEncoding)); + } + + /** + * 发起GET请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params 参数 + * @param responseEncoding 返回的文本的编码 + * @return 服务器返回的文本内容 + * @see com.fanruan.api.net.http.HttpKit#executeAndParse(HttpRequest, BaseHttpResponseHandle) + */ + public static String get(String url, Map params, String responseEncoding, Map headers) throws IOException { + return executeAndParse(HttpRequest + .custom() + .url(url) + .params(params) + .headers(headers) + .build(), + new TextResponseHandle(responseEncoding)); + } + + /** + * 从指定的地址下载文件 + * + * @param url 文件下载地址 + * @return 文件的字节流 + * @throws IOException 下载过程中出现错误则抛出此异常 + */ + public static ByteArrayInputStream download(String url) throws IOException { + return executeAndParse(HttpRequest.custom().url(url).build(), StreamResponseHandle.DEFAULT); + } + + /** + * 从指定的地址下载文件 + * + * @param url 文件下载地址 + * @param params 参数对 + * @param responseEncoding 响应的文件编码 + * @param headers 请求头 + * @return 文件的字节流 + * @throws IOException 下载过程中出现错误则抛出此异常 + */ + public static ByteArrayInputStream download(String url, Map params, String responseEncoding, Map headers) throws IOException { + return executeAndParse(HttpRequest + .custom() + .url(url) + .params(params) + .headers(headers) + .build(), + new StreamResponseHandle(responseEncoding)); + } + + /** + * 上传文件到指定的服务器 + * + * @param url 接收文件的服务器地址 + * @param file 要上传的文件,默认的文件编码为utf-8 + * @throws IOException 上传中出现错误则抛出此异常 + */ + public static void upload(String url, File file) throws IOException { + upload(url, file, Charset.forName("utf-8")); + } + + /** + * 上传文件到指定的服务器 + * + * @param url 接收文件的服务器地址 + * @param file 要上传的文件 + * @param charset 文件的编码 + * @throws IOException 上传中出现错误则抛出此异常 + */ + public static void upload(String url, File file, Charset charset) throws IOException { + upload(url, new FileEntity(file), charset); + } + + /** + * 上传文件到指定的服务器 + * + * @param url 接收文件的服务器地址 + * @param builder 附件构造器 + * @param charset 文件的编码 + * @throws IOException 上传中出现错误则抛出此异常 + */ + public static void upload(String url, MultipartEntityBuilder builder, Charset charset) throws IOException { + upload(url, builder, charset, Collections.emptyMap(), POST); + } + + /** + * 上传文件到指定的服务器 + * + * @param url 接收文件的服务器地址 + * @param fileEntity 文件实体 + * @param charset 文件的编码 + * @throws IOException 上传中出现错误则抛出此异常 + */ + public static void upload(String url, FileEntity fileEntity, Charset charset) throws IOException { + upload(url, fileEntity, charset, Collections.emptyMap(), POST); + } + + /** + * 上传多文件到指定的服务器 + * + * @param url 接收文件的服务器地址 + * @param builder 附件构造器 + * @param charset 文件的编码 + * @param headers 请求头 + * @param httpRequestType 请求类型 + * @throws IOException 上传中出现错误则抛出此异常 + */ + public static void upload(String url, MultipartEntityBuilder builder, Charset charset, Map headers, HttpRequestType httpRequestType) throws IOException { + // richie:采用浏览器模式,防止出现乱码 + builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); + HttpEntity reqEntity = builder.setCharset(charset).build(); + upload(url, reqEntity, charset, headers, httpRequestType); + } + + /** + * 上传文件到指定的服务器 + * + * @param url 接收文件的服务器地址 + * @param reqEntity 请求实体 + * @param charset 文件的编码 + * @param headers 请求头 + * @param httpRequestType 请求类型 + * @throws IOException 上传中出现错误则抛出此异常 + */ + public static void upload(String url, HttpEntity reqEntity, Charset charset, Map headers, HttpRequestType httpRequestType) throws IOException { + executeAndParse(HttpRequest + .custom() + .url(url) + .headers(headers) + .method(httpRequestType) + .httpEntity(reqEntity) + .encoding(charset.toString()) + .build(), + UploadResponseHandle.DEFAULT); + } + + /** + * 请求资源或服务,使用默认文本http解析器,UTF-8编码 + * + * @param httpRequest httpRequest + * @return 返回处理结果 + */ + public static String executeAndParse(HttpRequest httpRequest) throws IOException { + return executeAndParse(httpRequest, TextResponseHandle.DEFAULT); + } + + /** + * 请求资源或服务,自请求参数,并指定 http 响应处理器 + * 例: + *
+      *      String res = HttpToolbox.executeAndParse(HttpRequest
+      *              .custom()
+      *              .url("")
+      *              .build(),
+      *          TextResponseHandle.DEFAULT);
+      * 
+ * + * @param httpRequest httpRequest + * @param handle http 解析器 + * @return 返回处理结果 + */ + public static T executeAndParse(HttpRequest httpRequest, BaseHttpResponseHandle handle) throws IOException { + return handle.parse(execute(httpRequest)); + } + + /** + * 请求资源或服务,传入请求参数 + * + * @param httpRequest httpRequest + * @return 返回处理结果 + */ + public static CloseableHttpResponse execute(HttpRequest httpRequest) throws IOException { + return execute(getHttpClient(httpRequest.getUrl()), httpRequest); + } + + /** + * 请求资源或服务,自定义client对象,传入请求参数 + * + * @param httpClient http客户端 + * @param httpRequest httpRequest + * @return 返回处理结果 + */ + public static CloseableHttpResponse execute(CloseableHttpClient httpClient, HttpRequest httpRequest) throws IOException { + String url = httpRequest.getUrl(); + + // 创建请求对象 + HttpRequestBase httpRequestBase = httpRequest.getMethod().createHttpRequest(url); + + // 设置header信息 + httpRequestBase.setHeader("User-Agent", "Mozilla/5.0"); + Map headers = httpRequest.getHeaders(); + if (headers != null && !headers.isEmpty()) { + for (Map.Entry entry : headers.entrySet()) { + httpRequestBase.setHeader(entry.getKey(), entry.getValue()); + } + } + + // 配置请求的设置 + RequestConfig requestConfig = httpRequest.getConfig(); + if (requestConfig != null) { + httpRequestBase.setConfig(requestConfig); + } + + // 判断是否支持设置entity(仅HttpPost、HttpPut、HttpPatch支持) + if (HttpEntityEnclosingRequestBase.class.isAssignableFrom(httpRequestBase.getClass())) { + setHttpEntity((HttpEntityEnclosingRequestBase) httpRequestBase, httpRequest); + } else { + Map params = httpRequest.getParams(); + if (params != null && !params.isEmpty()) { + // 注意get等不支持设置entity需要更新拼接之后的URL,但是url变量没有更新 + httpRequestBase.setURI(URI.create(buildUrl(url, params, httpRequest.getEncoding()))); + } + } + + return httpClient.execute(httpRequestBase); + } + + /** + * 构建 Url + * + * @param url 请求地址 + * @param params 参数 + * @return 拼接之后的地址 + */ + public static String buildUrl(String url, Map params) { + try { + return buildUrl(url, params, EncodeConstants.ENCODING_UTF_8); + } catch (UnsupportedEncodingException ignore) { + } + return url; + } + + + /** + * 构建 Url + * + * @param url 请求地址 + * @param params 参数 + * @return 拼接之后的地址 + * @throws UnsupportedEncodingException 不支持的编码 + */ + private static String buildUrl(String url, Map params, String paramsEncoding) throws UnsupportedEncodingException { + if (params == null || params.isEmpty()) { + return url; + } + URIBuilder builder; + try { + builder = new URIBuilder(url); + for (Map.Entry entry : params.entrySet()) { + String key = URLEncoder.encode(entry.getKey(), paramsEncoding); + String value = URLEncoder.encode(entry.getValue(), paramsEncoding); + builder.setParameter(key, value); + } + return builder.build().toString(); + } catch (URISyntaxException e) { + LogKit.debug("Error to build url, please check the arguments."); + } + return url; + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/xxx/provider/UsersTableDataDefine.java b/src/main/java/com/fr/plugin/xxx/provider/UsersTableDataDefine.java new file mode 100644 index 0000000..c4323d0 --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/provider/UsersTableDataDefine.java @@ -0,0 +1,57 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: WechatTableDataDefine + * Author: xxx + * Date: 2021/12/8 16:41 + */ + package com.fr.plugin.xxx.provider; + + import com.fanruan.api.i18n.I18nKit; + import com.fr.base.TableData; + import com.fr.design.data.tabledata.tabledatapane.AbstractTableDataPane; + import com.fr.design.fun.ServerTableDataDefineProvider; + import com.fr.design.fun.impl.AbstractTableDataDefineProvider; + import com.fr.plugin.xxx.data.UsersTableData; + import com.fr.plugin.xxx.ui.UsersTableDataPane; + + /** + *
+ * + * + * @author xxx + * @since 1.0.0 + */ + public class UsersTableDataDefine extends AbstractTableDataDefineProvider implements ServerTableDataDefineProvider { + public static final String ICON_PATH = "/com/fr/plugin/xxx/images/logo16.png"; + + @Override + public Class classForTableData() { + return UsersTableData.class; + } + + @Override + public Class classForInitTableData() { + return UsersTableData.class; + } + + @Override + public Class appearanceForTableData() { + return UsersTableDataPane.class; + } + + @Override + public String nameForTableData() { + return I18nKit.getLocText("Plugin-xxx_Users_Table_Data"); + } + + @Override + public String prefixForTableData() { + return I18nKit.getLocText("Plugin-xxx_Users_Table_Data"); + } + + @Override + public String iconPathForTableData() { + return ICON_PATH; + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/xxx/ui/UsersTableDataPane.java b/src/main/java/com/fr/plugin/xxx/ui/UsersTableDataPane.java new file mode 100644 index 0000000..c418d1a --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/ui/UsersTableDataPane.java @@ -0,0 +1,52 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: WechatTableDataPane + * Author: xxx + * Date: 2021/12/8 19:19 + */ + package com.fr.plugin.xxx.ui; + + import com.fanruan.api.i18n.I18nKit; + import com.fr.plugin.xxx.data.UsersTableData; + import com.fr.script.Calculator; + import com.fr.stable.ParameterProvider; + + import java.util.List; + + /** + *
+ * + * + * @author xxx + * @since 1.0.0 + */ + public class UsersTableDataPane extends WebBaseTableDataPane { + + public UsersTableDataPane() { + super(); + } + + @Override + public void populateBean(UsersTableData data) { + if (data == null) { + return; + } + Calculator c = Calculator.createCalculator(); + this.editorPane.populate(data.getParameters(c)); + } + + @Override + public UsersTableData updateBean() { + UsersTableData data = new UsersTableData(); + List parameterProviderList = this.editorPane.update(); + ParameterProvider[] parameters = parameterProviderList.toArray(new ParameterProvider[0]); + data.setParameters(parameters); + return data; + } + + @Override + protected String title4PopupWindow() { + return I18nKit.getLocText("Plugin-xxx_Query"); + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/xxx/ui/WebBaseTableDataPane.java b/src/main/java/com/fr/plugin/xxx/ui/WebBaseTableDataPane.java new file mode 100644 index 0000000..e9b5b7d --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/ui/WebBaseTableDataPane.java @@ -0,0 +1,137 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: WebBaseTableDatapane + * Author: xxx + * Date: 2021/12/10 8:49 + */ + package com.fr.plugin.xxx.ui; + + import com.fanruan.api.design.DesignKit; + import com.fanruan.api.design.ui.action.UpdateAction; + import com.fanruan.api.design.ui.component.UIToolbar; + import com.fanruan.api.design.ui.component.table.UITableEditorPane; + import com.fanruan.api.design.ui.component.table.action.UITableEditAction; + import com.fanruan.api.design.ui.component.table.model.ParameterTableModel; + import com.fanruan.api.design.ui.component.table.model.UITableModelAdapter; + import com.fanruan.api.design.ui.toolbar.ToolBarDef; + import com.fanruan.api.design.work.BaseTableDataPane; + import com.fanruan.api.i18n.I18nKit; + import com.fanruan.api.log.LogKit; + import com.fanruan.api.util.IOKit; + import com.fr.base.TableData; + import com.fr.stable.ParameterProvider; + + import javax.swing.*; + import java.awt.*; + import java.awt.event.ActionEvent; + import java.io.IOException; + import java.net.URI; + + /** + *
+ * + * + * @author xxx + * @since 1.0.0 + */ + public abstract class WebBaseTableDataPane extends BaseTableDataPane { + public static final String ICON_HELP = "/com/fr/plugin/xxx/images/help.png"; + public static final String ICON_PREVIEW = "/com/fr/design/images/m_file/preview.png"; + public static final String ICON_REFRESH = "/com/fr/design/images/control/refresh.png"; + public static final String HELP_URL = "https://help.finereport.com/index.php"; + private static final String PREVIEW_BUTTON = I18nKit.getLocText("Plugin-xxx_Preview"); + private static final String REFRESH_BUTTON = I18nKit.getLocText("Plugin-xxx_Refresh"); + private static final String HELP_BUTTON = I18nKit.getLocText("Plugin-xxx_Help"); + + protected UITableEditorPane editorPane; + + public WebBaseTableDataPane() { + this.setLayout(new BorderLayout(4, 4)); + Box box = new Box(BoxLayout.Y_AXIS); + JPanel northPane = new JPanel(new BorderLayout(4, 4)); + JToolBar editToolBar = createToolBar(); + northPane.add(editToolBar, BorderLayout.CENTER); + JToolBar editHelpBar = createHelpBar(); + northPane.add(editHelpBar, BorderLayout.EAST); + northPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 6, 0)); + + UITableModelAdapter model = new ParameterTableModel(); + editorPane = new UITableEditorPane(model); + box.add(northPane); + box.add(editorPane); + JPanel sqlSplitPane = new JPanel(new BorderLayout(4, 4)); + sqlSplitPane.add(box, BorderLayout.CENTER); + this.add(sqlSplitPane, BorderLayout.CENTER); + } + + private JToolBar createToolBar() { + ToolBarDef toolBarDef = new ToolBarDef(); + toolBarDef.addShortCut(new PreviewAction()); + UIToolbar editToolBar = ToolBarDef.createJToolBar(); + toolBarDef.updateToolBar(editToolBar); + return editToolBar; + } + + private JToolBar createHelpBar() { + ToolBarDef helpBarDef = new ToolBarDef(); + helpBarDef.addShortCut(new HelpAction()); + UIToolbar editHelpBar = ToolBarDef.createJToolBar(); + helpBarDef.updateToolBar(editHelpBar); + return editHelpBar; + } + + @Override + protected String title4PopupWindow() { + return I18nKit.getLocText("Plugin-xxx_Query"); + } + + private void refresh() { + java.util.List existParameterList = editorPane.update(); + ParameterProvider[] ps = existParameterList == null ? new ParameterProvider[0] : existParameterList.toArray(new ParameterProvider[0]); + editorPane.populate(ps); + } + + private class PreviewAction extends UpdateAction { + public PreviewAction() { + this.setName(PREVIEW_BUTTON); + this.setMnemonic('P'); + this.setSmallIcon(IOKit.readIcon(ICON_PREVIEW)); + } + + public void actionPerformed(ActionEvent evt) { + DesignKit.previewTableData(WebBaseTableDataPane.this.updateBean()); + } + } + + private class HelpAction extends UpdateAction { + public HelpAction() { + this.setName(HELP_BUTTON); + this.setMnemonic('P'); + this.setSmallIcon(IOKit.readIcon(ICON_HELP)); + } + + public void actionPerformed(ActionEvent evt) { + try { + Desktop.getDesktop().browse(URI.create(HELP_URL)); + } catch (IOException e1) { + LogKit.error(e1.getMessage(), e1); + } + } + } + + protected class RefreshAction extends UITableEditAction { + public RefreshAction() { + this.setName(REFRESH_BUTTON); + this.setSmallIcon(IOKit.readIcon(ICON_REFRESH)); + } + + public void actionPerformed(ActionEvent e) { + refresh(); + } + + @Override + public void checkEnabled() { + } + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/xxx/ui/WebQueryPane.java b/src/main/java/com/fr/plugin/xxx/ui/WebQueryPane.java new file mode 100644 index 0000000..efd19d9 --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/ui/WebQueryPane.java @@ -0,0 +1,60 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: WechatQueryPane + * Author: xxx + * Date: 2021/12/14 15:32 + */ + package com.fr.plugin.xxx.ui; + + import com.fanruan.api.design.ui.component.UIButtonGroup; + import com.fanruan.api.design.ui.component.UILabel; + import com.fanruan.api.design.ui.container.BasicPane; + import com.fanruan.api.design.ui.layout.TableLayoutKit; + import com.fanruan.api.i18n.I18nKit; + + import java.awt.*; + + /** + *
+ * + * + * @author xxx + * @since 1.0.0 + */ + public class WebQueryPane extends BasicPane { + public static final String[] SEARCH_OPTIONS = new String[]{ + I18nKit.getLocText("Plugin-xxx_Search_User"), + I18nKit.getLocText("Plugin-xxx_Search_Department") + }; + private UIButtonGroup searchType; + + public WebQueryPane() { + setLayout(new BorderLayout()); + searchType = new UIButtonGroup(SEARCH_OPTIONS); + searchType.setSelectedIndex(0); + Component[][] coms = new Component[][]{ + {new UILabel(I18nKit.getLocText("Plugin-xxx_Search_Type") + ":"), searchType} + }; + + double p = TableLayoutKit.PREFERRED; + double f = TableLayoutKit.FILL; + double[] rowSize = {p}; + double[] columnSize = {p, f}; + + add(TableLayoutKit.createTableLayoutPane(coms, rowSize, columnSize)); + } + + @Override + protected String title4PopupWindow() { + return I18nKit.getLocText("Plugin-xxx_Query"); + } + + public int getSearchType() { + return searchType.getSelectedIndex(); + } + + public void setSearchType(int searchType) { + this.searchType.setSelectedIndex(searchType); + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/xxx/util/Base64Utils.java b/src/main/java/com/fr/plugin/xxx/util/Base64Utils.java new file mode 100644 index 0000000..3231d12 --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/util/Base64Utils.java @@ -0,0 +1,133 @@ +package com.fr.plugin.xxx.util; + +import com.fr.base.Base64; + +import java.io.*; + + +public class Base64Utils { + + /** */ + /** + * 文件读取缓冲区大小 + */ + private static final int CACHE_SIZE = 1024; + + /** */ + /** + *

+ * BASE64字符串解码为二进制数据 + *

+ * + * @param base64 + * @return + * @throws Exception + */ + public static byte[] decode(String base64) throws Exception { + return Base64.decode(base64); + } + + /** */ + /** + *

+ * 二进制数据编码为BASE64字符串 + *

+ * + * @param bytes + * @return + * @throws Exception + */ + public static String encode(byte[] bytes) throws Exception { + return new String(Base64.encode(bytes)); + } + + /** */ + /** + *

+ * 将文件编码为BASE64字符串 + *

+ *

+ * 大文件慎用,可能会导致内存溢出 + *

+ * + * @param filePath 文件绝对路径 + * @return + * @throws Exception + */ + public static String encodeFile(String filePath) throws Exception { + byte[] bytes = fileToByte(filePath); + return encode(bytes); + } + + /** */ + /** + *

+ * BASE64字符串转回文件 + *

+ * + * @param filePath 文件绝对路径 + * @param base64 编码字符串 + * @throws Exception + */ + public static void decodeToFile(String filePath, String base64) throws Exception { + byte[] bytes = decode(base64); + byteArrayToFile(bytes, filePath); + } + + /** */ + /** + *

+ * 文件转换为二进制数组 + *

+ * + * @param filePath 文件路径 + * @return + * @throws Exception + */ + public static byte[] fileToByte(String filePath) throws Exception { + byte[] data = new byte[0]; + File file = new File(filePath); + if (file.exists()) { + FileInputStream in = new FileInputStream(file); + ByteArrayOutputStream out = new ByteArrayOutputStream(2048); + byte[] cache = new byte[CACHE_SIZE]; + int nRead = 0; + while ((nRead = in.read(cache)) != -1) { + out.write(cache, 0, nRead); + out.flush(); + } + out.close(); + in.close(); + data = out.toByteArray(); + } + return data; + } + + /** */ + /** + *

+ * 二进制数据写文件 + *

+ * + * @param bytes 二进制数据 + * @param filePath 文件生成目录 + */ + public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception { + InputStream in = new ByteArrayInputStream(bytes); + File destFile = new File(filePath); + if (!destFile.getParentFile().exists()) { + destFile.getParentFile().mkdirs(); + } + destFile.createNewFile(); + OutputStream out = new FileOutputStream(destFile); + byte[] cache = new byte[CACHE_SIZE]; + int nRead = 0; + while ((nRead = in.read(cache)) != -1) { + out.write(cache, 0, nRead); + out.flush(); + } + out.close(); + in.close(); + } + +} diff --git a/src/main/java/com/fr/plugin/xxx/util/RSAUtils.java b/src/main/java/com/fr/plugin/xxx/util/RSAUtils.java new file mode 100644 index 0000000..b1c34d2 --- /dev/null +++ b/src/main/java/com/fr/plugin/xxx/util/RSAUtils.java @@ -0,0 +1,310 @@ +package com.fr.plugin.xxx.util; + +import javax.crypto.Cipher; +import java.io.ByteArrayOutputStream; +import java.security.*; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.HashMap; +import java.util.Map; + +public class RSAUtils { + /** */ + /** + * 加密算法RSA + */ + public static final String KEY_ALGORITHM = "RSA"; + + /** */ + /** + * 签名算法 + */ + public static final String SIGNATURE_ALGORITHM = "MD5withRSA"; + + /** */ + /** + * 获取公钥的key + */ + private static final String PUBLIC_KEY = "RSAPublicKey"; + + /** */ + /** + * 获取私钥的key + */ + private static final String PRIVATE_KEY = "RSAPrivateKey"; + + /** */ + /** + * RSA最大加密明文大小 + */ + private static final int MAX_ENCRYPT_BLOCK = 117; + + /** */ + /** + * RSA最大解密密文大小 + */ + private static final int MAX_DECRYPT_BLOCK = 128; + + /** */ + /** + *

+ * 生成密钥对(公钥和私钥) + *

+ * + * @return + * @throws Exception + */ + public static Map genKeyPair() throws Exception { + KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM); + keyPairGen.initialize(1024); + KeyPair keyPair = keyPairGen.generateKeyPair(); + RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); + RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); + Map keyMap = new HashMap(2); + keyMap.put(PUBLIC_KEY, publicKey); + keyMap.put(PRIVATE_KEY, privateKey); + return keyMap; + } + + /** */ + /** + *

+ * 用私钥对信息生成数字签名 + *

+ * + * @param data 已加密数据 + * @param privateKey 私钥(BASE64编码) + * @return + * @throws Exception + */ + public static String sign(byte[] data, String privateKey) throws Exception { + byte[] keyBytes = Base64Utils.decode(privateKey); + PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); + PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec); + Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); + signature.initSign(privateK); + signature.update(data); + return Base64Utils.encode(signature.sign()); + } + + /** */ + /** + *

+ * 校验数字签名 + *

+ * + * @param data 已加密数据 + * @param publicKey 公钥(BASE64编码) + * @param sign 数字签名 + * @return + * @throws Exception + */ + public static boolean verify(byte[] data, String publicKey, String sign) + throws Exception { + byte[] keyBytes = Base64Utils.decode(publicKey); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); + PublicKey publicK = keyFactory.generatePublic(keySpec); + Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); + signature.initVerify(publicK); + signature.update(data); + return signature.verify(Base64Utils.decode(sign)); + } + + /** */ + /** + *

+ * 私钥解密 + *

+ * + * @param encryptedData 已加密数据 + * @param privateKey 私钥(BASE64编码) + * @return + * @throws Exception + */ + public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) + throws Exception { + byte[] keyBytes = Base64Utils.decode(privateKey); + PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); + Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); + Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); + cipher.init(Cipher.DECRYPT_MODE, privateK); + int inputLen = encryptedData.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + byte[] cache; + int i = 0; + // 对数据分段解密 + while (inputLen - offSet > 0) { + if (inputLen - offSet > MAX_DECRYPT_BLOCK) { + cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); + } else { + cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + i++; + offSet = i * MAX_DECRYPT_BLOCK; + } + byte[] decryptedData = out.toByteArray(); + out.close(); + return decryptedData; + } + + /** */ + /** + *

+ * 公钥解密 + *

+ * + * @param encryptedData 已加密数据 + * @param publicKey 公钥(BASE64编码) + * @return + * @throws Exception + */ + public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) + throws Exception { + byte[] keyBytes = Base64Utils.decode(publicKey); + X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); + Key publicK = keyFactory.generatePublic(x509KeySpec); + Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); + cipher.init(Cipher.DECRYPT_MODE, publicK); + int inputLen = encryptedData.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + byte[] cache; + int i = 0; + // 对数据分段解密 + while (inputLen - offSet > 0) { + if (inputLen - offSet > MAX_DECRYPT_BLOCK) { + cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); + } else { + cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + i++; + offSet = i * MAX_DECRYPT_BLOCK; + } + byte[] decryptedData = out.toByteArray(); + out.close(); + return decryptedData; + } + + /** */ + /** + *

+ * 公钥加密 + *

+ * + * @param data 源数据 + * @param publicKey 公钥(BASE64编码) + * @return + * @throws Exception + */ + public static byte[] encryptByPublicKey(byte[] data, String publicKey) + throws Exception { + byte[] keyBytes = Base64Utils.decode(publicKey); + X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); + Key publicK = keyFactory.generatePublic(x509KeySpec); + // 对数据加密 + Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); + cipher.init(Cipher.ENCRYPT_MODE, publicK); + int inputLen = data.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + byte[] cache; + int i = 0; + // 对数据分段加密 + while (inputLen - offSet > 0) { + if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { + cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); + } else { + cache = cipher.doFinal(data, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + i++; + offSet = i * MAX_ENCRYPT_BLOCK; + } + byte[] encryptedData = out.toByteArray(); + out.close(); + + return encryptedData; + } + + /** */ + /** + *

+ * 私钥加密 + *

+ * + * @param data 源数据 + * @param privateKey 私钥(BASE64编码) + * @return + * @throws Exception + */ + public static byte[] encryptByPrivateKey(byte[] data, String privateKey) + throws Exception { + byte[] keyBytes = Base64Utils.decode(privateKey); + PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); + Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); + Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); + cipher.init(Cipher.ENCRYPT_MODE, privateK); + int inputLen = data.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + byte[] cache; + int i = 0; + // 对数据分段加密 + while (inputLen - offSet > 0) { + if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { + cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); + } else { + cache = cipher.doFinal(data, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + i++; + offSet = i * MAX_ENCRYPT_BLOCK; + } + byte[] encryptedData = out.toByteArray(); + out.close(); + return encryptedData; + } + + /** */ + /** + *

+ * 获取私钥 + *

+ * + * @param keyMap 密钥对 + * @return + * @throws Exception + */ + public static String getPrivateKey(Map keyMap) + throws Exception { + Key key = (Key) keyMap.get(PRIVATE_KEY); + return Base64Utils.encode(key.getEncoded()); + } + + /** */ + /** + *

+ * 获取公钥 + *

+ * + * @param keyMap 密钥对 + * @return + * @throws Exception + */ + public static String getPublicKey(Map keyMap) + throws Exception { + Key key = (Key) keyMap.get(PUBLIC_KEY); + return Base64Utils.encode(key.getEncoded()); + } +} diff --git a/src/main/resources/com/fr/plugin/xxx/images/help.png b/src/main/resources/com/fr/plugin/xxx/images/help.png new file mode 100644 index 0000000..0bd60db Binary files /dev/null and b/src/main/resources/com/fr/plugin/xxx/images/help.png differ diff --git a/src/main/resources/com/fr/plugin/xxx/images/logo16.png b/src/main/resources/com/fr/plugin/xxx/images/logo16.png new file mode 100644 index 0000000..5c21e96 Binary files /dev/null and b/src/main/resources/com/fr/plugin/xxx/images/logo16.png differ diff --git a/src/main/resources/com/fr/plugin/xxx/locale/lang.properties b/src/main/resources/com/fr/plugin/xxx/locale/lang.properties new file mode 100644 index 0000000..e5ab71a --- /dev/null +++ b/src/main/resources/com/fr/plugin/xxx/locale/lang.properties @@ -0,0 +1,11 @@ +Plugin-igqh=API Dataset Plugin +Plugin-igqh_Group=API Dataset Plugin +Plugin-igqh_Licence_Expired=API Dataset Plugin Licence Expired +Plugin-igqh_Users_Table_Data=API Table Data +Plugin-igqh_Query=Query +Plugin-igqh_Help=Help +Plugin-igqh_Preview=Preview +Plugin-igqh_Refresh=Refresh +Plugin-igqh_Search_Type=Search Type +Plugin-igqh_Search_User=User +Plugin-igqh_Search_Department=Department \ No newline at end of file diff --git a/src/main/resources/com/fr/plugin/xxx/locale/lang_zh_CN.properties b/src/main/resources/com/fr/plugin/xxx/locale/lang_zh_CN.properties new file mode 100644 index 0000000..0942b35 --- /dev/null +++ b/src/main/resources/com/fr/plugin/xxx/locale/lang_zh_CN.properties @@ -0,0 +1,11 @@ +Plugin-igqh=API\u6570\u636E\u96C6\u63D2\u4EF6 +Plugin-igqh_Group=API\u6570\u636E\u96C6\u63D2\u4EF6 +Plugin-igqh_Licence_Expired=API\u6570\u636E\u96C6\u63D2\u4EF6\u8BB8\u53EF\u8FC7\u671F +Plugin-igqh_Users_Table_Data=API\u6570\u636E\u96C6 +Plugin-igqh_Query=\u67E5\u8BE2 +Plugin-igqh_Help=\u5E2E\u52A9\u6587\u6863 +Plugin-igqh_Preview=\u9884\u89C8 +Plugin-igqh_Refresh=\u5237\u65B0 +Plugin-igqh_Search_Type=\u64CD\u4F5C\u79CD\u7C7B +Plugin-igqh_Search_User=\u7528\u6237 +Plugin-igqh_Search_Department=\u90E8\u95E8 \ No newline at end of file