From 68280ba5d81628b8ecf173bc1176b367d06934a5 Mon Sep 17 00:00:00 2001 From: "LAPTOP-SB56SG4Q\\86185" Date: Tue, 2 Nov 2021 10:24:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E5=BC=80=E6=BA=90=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E6=9D=90=E6=96=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- JSD-8235-需求确认书V1.2(1).docx | Bin 0 -> 63799 bytes README.md | 5 +- plugin.xml | 20 + .../java/com/fr/plugin/JHHandlerProvider.java | 25 + .../java/com/fr/plugin/JHURLAliasBridge.java | 30 ++ .../com/fr/plugin/api/DataTableExport.java | 214 ++++++++ .../java/com/fr/plugin/api/EncryptionApi.java | 63 +++ .../java/com/fr/plugin/api/SQLQueryApi.java | 67 +++ .../java/com/fr/plugin/api/SQLUpdateApi.java | 71 +++ .../java/com/fr/plugin/utils/AesUtils.java | 96 ++++ .../java/com/fr/plugin/utils/DbUtils.java | 290 +++++++++++ .../java/com/fr/plugin/utils/RespUtils.java | 34 ++ src/main/resources/com/fr/plugin/alert.html | 35 ++ .../resources/com/fr/plugin/demo.properties | 1 + .../com/fr/plugin/demo_zh_CN.properties | 1 + src/main/resources/com/fr/plugin/js/print.js | 476 ++++++++++++++++++ 16 files changed, 1427 insertions(+), 1 deletion(-) create mode 100644 JSD-8235-需求确认书V1.2(1).docx create mode 100644 plugin.xml create mode 100644 src/main/java/com/fr/plugin/JHHandlerProvider.java create mode 100644 src/main/java/com/fr/plugin/JHURLAliasBridge.java create mode 100644 src/main/java/com/fr/plugin/api/DataTableExport.java create mode 100644 src/main/java/com/fr/plugin/api/EncryptionApi.java create mode 100644 src/main/java/com/fr/plugin/api/SQLQueryApi.java create mode 100644 src/main/java/com/fr/plugin/api/SQLUpdateApi.java create mode 100644 src/main/java/com/fr/plugin/utils/AesUtils.java create mode 100644 src/main/java/com/fr/plugin/utils/DbUtils.java create mode 100644 src/main/java/com/fr/plugin/utils/RespUtils.java create mode 100644 src/main/resources/com/fr/plugin/alert.html create mode 100644 src/main/resources/com/fr/plugin/demo.properties create mode 100644 src/main/resources/com/fr/plugin/demo_zh_CN.properties create mode 100644 src/main/resources/com/fr/plugin/js/print.js diff --git a/JSD-8235-需求确认书V1.2(1).docx b/JSD-8235-需求确认书V1.2(1).docx new file mode 100644 index 0000000000000000000000000000000000000000..f0382ebf60123de33f6fe792068c7026176a2529 GIT binary patch literal 63799 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

wY8-PNS9StaBpU-vO=S8z#-#lzwUQeBY7q?i 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

mZD64niA>FwVZ^s8h5>D*yn%xdA>@NdEV}2& zvi_>?t18>gApTH@m?9|evS^XC`#jq5&;kkLP7Po-yt!cVr@#&2={hM;o*y@F5m27z zNIYS3lBT&jhwhHu&S>tB51z}Uo;L5&pFUF$AD42SezydSt_>v`SYAGfvkuojnDmvU zSP11~n+MhFD{3!6aJH1`cbsF(Mbhc*p|pILXG^^{W27ff1FK!g6q`o3$>?tp(0chk zfvf07FT_^4*+utsW~>Y2o}rV3aB5vt2Wf?i^8?!( z$!_hO8#Scl2&!8pkLX1I7Ds2AzZN%8vxS{`;s18Hf7_e?KMa@QM`g+XGpk$HY;D~9 z;>hC=KMSGM_+AQV3@q%l4!)Mmdb=ovUy6w27EAwMHtoLHXQzxr3sl3ZSG*{$iD` zCrVu`lp-ObB*Z$Fycuw?#-L}~0CFloQP#&q@>*W##59ryAPU)C;P)^%Jf(qh(+BJy6g3ccOZ2LZH zN0TP04Y$sY0wA$hqDwg$X>aIPao{`Xbp5+U~wi!N(<) zGutJA4m_S>SAr#G?&nIIZCK%09p)ro8tR)->HmmW?H9Mxqb)H@u9m$hl)HRWXo5r2 znS0BBxoo?B!zC2CYIIBSZjbcV(jRuK_3;4w7IqB> z?>WP*t~TxyJo^y+$ojji|5)@|!0W2V zUji5!UJLlcjMoBQ^C$iiK%V_tz%Mq%*HT^=EdG-6{0}q!kn%TM{@oE@g4dtzuho9Z zi~fMVoLhchTufMUUgMX5=lpVV`K$BK#U*(W@gJCumDP{f_Zlt8e$DLig06f)!~Lo9 zC;CSa{SR8t(&mo>#MkhWTla~l7ntWu=O1OKKiW^YA@JYfe{gmF(*N&+ekpzYv;7!H zJjkC3zV)BqA%;f0>iWb03#-VuN(r!@=rm3pPtw7 z*EOuaX6E|qpYY!*T3_S$T#3!MU!1Ar#TkD0W=75b;4SU`%t>FPldoej>t4|2|3G)@ z{f7SA2K@CXsUR+WR(aV6^DmEq-*p!m{D%Hx_Wq&!DkC}S#p!upJoR_1 z%Kchw_uqlP3g=#r`!!4JFA)Mcf9n2?v-LHe>>Y1S?8_0d+v|1w`oQ`p-qyg*?uGHy z_E-4%wd9n+MP~9$000~rfB>*RbicHpA))@S@MCM|Y-aE`@c(AsXpR5WZD(v?Zt#zg zZSq1L7y9C4Y%iy+A0>uA+E1-2zXSh(|8e?~76W|&000oad|iVB0Fa;j`02j@kFqLz literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 7559581..acd26f2 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ # open-JSD-8476 -JSD-8476 开源任务材料 \ No newline at end of file +JSD-8476 基于http服务的finedb操作接口【高危慎用!】\ +免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\ +仅作为开发者学习参考使用!禁止用于任何商业用途!\ +为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系hugh处理。 \ No newline at end of file diff --git a/plugin.xml b/plugin.xml new file mode 100644 index 0000000..05556e7 --- /dev/null +++ b/plugin.xml @@ -0,0 +1,20 @@ + + com.fr.plugin.jh.export + + yes + 1.0.9 + 10.0 + 2018-07-31 + author + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/JHHandlerProvider.java b/src/main/java/com/fr/plugin/JHHandlerProvider.java new file mode 100644 index 0000000..f99aef8 --- /dev/null +++ b/src/main/java/com/fr/plugin/JHHandlerProvider.java @@ -0,0 +1,25 @@ +package com.fr.plugin; + +import com.fr.decision.fun.HttpHandler; +import com.fr.decision.fun.impl.AbstractHttpHandlerProvider; +import com.fr.plugin.api.DataTableExport; +import com.fr.plugin.api.EncryptionApi; +import com.fr.plugin.api.SQLQueryApi; +import com.fr.plugin.api.SQLUpdateApi; +import com.fr.plugin.transform.ExecuteFunctionRecord; +import com.fr.plugin.transform.FunctionRecorder; + +@FunctionRecorder +public class JHHandlerProvider extends AbstractHttpHandlerProvider { + @Override + @ExecuteFunctionRecord + public HttpHandler[] registerHandlers() { + return new HttpHandler[]{ + new DataTableExport(), + new SQLQueryApi(), + new EncryptionApi(), + new SQLUpdateApi() + }; + } + +} diff --git a/src/main/java/com/fr/plugin/JHURLAliasBridge.java b/src/main/java/com/fr/plugin/JHURLAliasBridge.java new file mode 100644 index 0000000..0bee076 --- /dev/null +++ b/src/main/java/com/fr/plugin/JHURLAliasBridge.java @@ -0,0 +1,30 @@ +package com.fr.plugin; + +import com.fr.decision.fun.impl.AbstractURLAliasProvider; +import com.fr.decision.webservice.url.alias.URLAlias; +import com.fr.decision.webservice.url.alias.URLAliasFactory; +import com.fr.general.IOUtils; +import com.fr.stable.StringUtils; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.Scanner; +import java.util.Set; + +public class JHURLAliasBridge extends AbstractURLAliasProvider { + + @Override + public URLAlias[] registerAlias() { + return new URLAlias[]{ + URLAliasFactory.createPluginAlias("/dynamic/dataresource/api/update", "/update", false), + URLAliasFactory.createPluginAlias("/dynamic/enpwd", "/encryption", false), + URLAliasFactory.createPluginAlias("/dynamic/dataresource/api/query", "/query", false), + URLAliasFactory.createPluginAlias("/dynamic/dataresource/api/output", "/output", false), + }; + } + + +} diff --git a/src/main/java/com/fr/plugin/api/DataTableExport.java b/src/main/java/com/fr/plugin/api/DataTableExport.java new file mode 100644 index 0000000..7a0cf18 --- /dev/null +++ b/src/main/java/com/fr/plugin/api/DataTableExport.java @@ -0,0 +1,214 @@ +package com.fr.plugin.api; + +import com.fr.decision.fun.impl.BaseHttpHandler; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.utils.AesUtils; +import com.fr.plugin.utils.DbUtils; +import com.fr.plugin.utils.RespUtils; +import com.fr.third.org.apache.commons.lang3.time.DateFormatUtils; +import com.fr.third.springframework.util.StringUtils; +import com.fr.third.springframework.web.bind.annotation.RequestMethod; +import com.fr.web.utils.WebUtils; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.BufferedWriter; +import java.io.OutputStreamWriter; +import java.util.*; + + +public class DataTableExport extends BaseHttpHandler { + + @Override + public RequestMethod getMethod() { + return RequestMethod.POST; + } + + @Override + public String getPath() { + return "/output"; + } + + + @Override + public boolean isPublic() { + return false; + } + + @Override + public void handle(HttpServletRequest request, HttpServletResponse httpServletResponse) throws Exception { + //获取参数 + List keys = new ArrayList<>(); + keys.add("table_name"); + keys.add("where"); + keys.add("field_break"); + keys.add("fields"); + keys.add("need_title"); +// keys.add("line_break"); + keys.add("m_flag"); + + Map params = new HashMap<>(); + //for debug +// FineLoggerFactory.getLogger().info("加密fine_user为:{}", AesUtils.encryptPassword("find_user")); +// FineLoggerFactory.getLogger().info("加密后在解密测试:{}", AesUtils.decryptPassword(AesUtils.encryptPassword("find_user"))); +// for (String key : keys) { +// String value = WebUtils.getHTTPRequestParameter(request, key); +// params.put(key, value); +// } + for (String key : keys) { + String value = WebUtils.getHTTPRequestParameter(request, key); + if (StringUtils.isEmpty(value)) { + FineLoggerFactory.getLogger().info("导出接口:传入的{}为空", key); + httpServletResponse.setStatus(500); + WebUtils.printAsJSON(httpServletResponse, RespUtils.buildError(-100, "未提供" + key + "参数")); + return; + } + try { + FineLoggerFactory.getLogger().info("导出接口:待解密{}:{}", key, value); + String temp = AesUtils.decryptPassword(value); + if (temp == null) { + temp = ""; + } + FineLoggerFactory.getLogger().info("导出接口:解密{} 之后为:{}", key, temp); + params.put(key, temp); + } catch (Exception e) { + FineLoggerFactory.getLogger().error("导出接口:解密SQL异常 ", e); + httpServletResponse.setStatus(500); + WebUtils.printAsJSON(httpServletResponse, RespUtils.buildError(-102, "解密query参数失败")); + return; + } + } + + + try { + String tableName = params.get("table_name"); + DbUtils dbUtils = new DbUtils("finedb"); + DbUtils logdb = new DbUtils("logdb"); + boolean isLogdb = false; + boolean allfind = false; + if (StringUtils.isEmpty(tableName)) { + FineLoggerFactory.getLogger().error("导出接口:传过来的表为空{} ", tableName); + httpServletResponse.setStatus(500); + WebUtils.printAsJSON(httpServletResponse, RespUtils.buildError(-103, "表不存在:" + tableName)); + return; + } + if (logdb.checkTableExit(tableName)) { + allfind = true; + isLogdb = true; + dbUtils = logdb;//如果表在logdb里面就把数据源切换到logdb + } else { + FineLoggerFactory.getLogger().error("导出接口:传过来的表{} 在logdb中 不存在", tableName); + } + if (!allfind) { + if (dbUtils.checkTableExit(tableName)) { + allfind = true; + } else { + FineLoggerFactory.getLogger().error("导出接口:传过来的表{} 在finedb中 不存在", tableName); + } + } + if (!allfind) { + FineLoggerFactory.getLogger().error("导出接口:传过来的表{} 在findb和logdb中均不存在", tableName); + FineLoggerFactory.getLogger().error("导出接口:传过来的表不存在{} ", tableName); + httpServletResponse.setStatus(500); + WebUtils.printAsJSON(httpServletResponse, RespUtils.buildError(-103, "表在logdb和finedb中均不存在:" + tableName)); + } + + String where = params.get("where"); + String countSql = String.format("select count(1) from %s %s", tableName, where); + int rowCount = 0; + int pageSize = 2000; + int totalPage = 0; + if (!isLogdb) { + rowCount = dbUtils.countRows(countSql); + totalPage = rowCount % pageSize == 0 ? rowCount / pageSize : (rowCount / pageSize) + 1; + } + String fields = params.get("fields"); + String m_flag = params.get("m_flag"); + //获取一个写出的流 + String date = DateFormatUtils.format(new Date(), "yyyyMMddHHmmssSSS"); + httpServletResponse.setHeader("file_name", String.format("{%s}__%s__%s__%d.dat", m_flag, tableName, date, rowCount)); + ServletOutputStream outputStream = httpServletResponse.getOutputStream(); + BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream)); + String line_break = params.get("line_break"); + if (StringUtils.isEmpty(line_break)) { + line_break = "|@|\r\n"; + } +// String line_break = "|@|\r\n"; + String field_break = params.get("field_break"); + if (StringUtils.isEmpty(field_break)) { + field_break = "|@|"; + } + if (StringUtils.isEmpty(where)) { + where = ""; + } + String need_title = params.get("need_title"); + boolean needTitle = com.fr.stable.StringUtils.equals(need_title, "true"); + //如果需要标题,先做一次预查寻,把表头查出来 + if (needTitle) { + String preSql = String.format("select %s from %s %s limit 1", fields, tableName, where); + if (isLogdb) { + preSql = String.format("select %s from %s where uuid=1", fields, tableName); + } + List lists = dbUtils.getQueryFields(preSql); + StringBuilder builder = new StringBuilder(); + boolean isFirst = true; + for (String name : lists) { + String temp = StringUtils.trimAllWhitespace(name); + if (isFirst) { + builder.append("m_flag").append(field_break); + isFirst = false; + } else { + builder.append(field_break); + } + builder.append(temp); + } + builder.append(line_break); + bufferedWriter.write(builder.toString()); + } + if (!isLogdb) { + for (int i = 0; i < totalPage; i++) { + List dataByPage = getDataByPage(tableName, fields, where, i, pageSize, dbUtils, line_break, field_break,m_flag); + for (String line : dataByPage) { + bufferedWriter.write(line); + } + } + } else { + getDataFromLogDb(tableName, fields, where, dbUtils, line_break, field_break, bufferedWriter,m_flag); + } + bufferedWriter.flush(); + + } catch (Exception e) { + FineLoggerFactory.getLogger().error("导出接口:执行SQL异常 ", e); + httpServletResponse.setStatus(500); + WebUtils.printAsJSON(httpServletResponse, RespUtils.buildError(-103, "SQL执行失败:" + RespUtils.Exception2String(e))); + } + } + + private void getDataFromLogDb(String tableName, String fields, String where, DbUtils dbUtils, String line_break, String field_break, BufferedWriter bufferedWriter, String m_flag) throws Exception { + String sql = String.format("select %s from %s %s", fields, tableName, where); + dbUtils.queryfromlogdb(sql, line_break, field_break, bufferedWriter,m_flag); + } + + private List getDataByPage(String tableName, String fields, String where, int page, int pageSize, DbUtils dbUtils, String line_break, String field_break,String m_flag) throws Exception { + String sql = String.format("select %s from %s %s limit %d,%d", fields, tableName, where, page * pageSize, pageSize); + return dbUtils.query(sql, line_break, field_break,m_flag); + } + + public static void main(String[] args) { +// String table_name = AesUtils.encryptPassword("fine_user"); +// String where = AesUtils.encryptPassword("where id>100"); +// String fields = AesUtils.encryptPassword("id,name,xxxxx,xxx"); +// String field_break = AesUtils.encryptPassword("xxx"); +// //以及剩下的 +// StringBuilder builder = new StringBuilder(); +// builder.append("table_name=").append(table_name) +// .append("&where=").append(where) +// .append("&fields=").append(fields) +// .append("&field_break=").append(field_break); +// //以及剩下的,按照这种格式弄 +// String params = builder.toString(); +// HttpUtils.doPostToFile("/output", params, null, "xxx地址"); + } + +} diff --git a/src/main/java/com/fr/plugin/api/EncryptionApi.java b/src/main/java/com/fr/plugin/api/EncryptionApi.java new file mode 100644 index 0000000..a1acb4d --- /dev/null +++ b/src/main/java/com/fr/plugin/api/EncryptionApi.java @@ -0,0 +1,63 @@ +package com.fr.plugin.api; + +import com.fr.decision.fun.impl.BaseHttpHandler; +import com.fr.decision.privilege.TransmissionTool; +import com.fr.json.JSONArray; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.utils.AesUtils; +import com.fr.plugin.utils.DbUtils; +import com.fr.plugin.utils.RespUtils; +import com.fr.security.SecurityConfig; +import com.fr.security.encryption.transmission.TransmissionEncryptors; +import com.fr.stable.StringUtils; +import com.fr.third.springframework.web.bind.annotation.RequestMethod; +import com.fr.web.utils.WebUtils; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + + +public class EncryptionApi extends BaseHttpHandler { + + @Override + public RequestMethod getMethod() { + return RequestMethod.POST; + } + + @Override + public String getPath() { + return "/encryption"; + } + + @Override + public boolean isPublic() { + return false; + } + + @Override + public void handle(HttpServletRequest request, HttpServletResponse httpServletResponse) throws Exception { + //获取参数 + String query = WebUtils.getHTTPRequestParameter(request, "pawd"); + if (StringUtils.isBlank(query)) { + FineLoggerFactory.getLogger().info("加密接口:传入的密文为空"); + WebUtils.printAsJSON(httpServletResponse, RespUtils.buildError(-100, "未提供密文参数")); + return; + } + String password = ""; + try { + FineLoggerFactory.getLogger().info("加密接口:待解密密碼:{}", query); + password = AesUtils.decryptPassword(query); + FineLoggerFactory.getLogger().info("加密接口:解密之后为:{}", password); + if (StringUtils.isBlank(password)) { + WebUtils.printAsJSON(httpServletResponse, RespUtils.buildError(-101, "解密之后的SQL为空")); + return; + } + String resultPassword = TransmissionEncryptors.getInstance().encrypt(password); +// String resultPassword = TransmissionTool.encrypt(password); + WebUtils.printAsJSON(httpServletResponse, RespUtils.buildSuccess(resultPassword)); + } catch (Exception e) { + FineLoggerFactory.getLogger().error("加密接口:解密密碼异常 ", e); + WebUtils.printAsJSON(httpServletResponse, RespUtils.buildError(-102, "解密query参数失败")); + } + } +} diff --git a/src/main/java/com/fr/plugin/api/SQLQueryApi.java b/src/main/java/com/fr/plugin/api/SQLQueryApi.java new file mode 100644 index 0000000..209cece --- /dev/null +++ b/src/main/java/com/fr/plugin/api/SQLQueryApi.java @@ -0,0 +1,67 @@ +package com.fr.plugin.api; + +import com.fr.decision.fun.impl.BaseHttpHandler; +import com.fr.json.JSONArray; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.utils.AesUtils; +import com.fr.plugin.utils.DbUtils; +import com.fr.plugin.utils.RespUtils; +import com.fr.stable.StringUtils; +import com.fr.third.springframework.web.bind.annotation.RequestMethod; +import com.fr.web.utils.WebUtils; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + + +public class SQLQueryApi extends BaseHttpHandler { + + @Override + public RequestMethod getMethod() { + return RequestMethod.POST; + } + + @Override + public String getPath() { + return "/query"; + } + + @Override + public boolean isPublic() { + return false; + } + + @Override + public void handle(HttpServletRequest request, HttpServletResponse httpServletResponse) throws Exception { + //获取参数 + String query = WebUtils.getHTTPRequestParameter(request, "query"); + if (StringUtils.isBlank(query)) { + FineLoggerFactory.getLogger().info("查询接口:传入的sql为空"); + WebUtils.printAsJSON(httpServletResponse, RespUtils.buildError(-100, "未提供query参数")); + return; + } + String sql = ""; + try { + FineLoggerFactory.getLogger().info("查询接口:待解密query:{}", query); + sql = AesUtils.decryptPassword(query); + FineLoggerFactory.getLogger().info("查询接口:解密之后为:{}", sql); + if (StringUtils.isBlank(sql)) { + WebUtils.printAsJSON(httpServletResponse, RespUtils.buildError(-101, "解密之后的SQL为空")); + return; + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error("查询接口:解密SQL异常 ", e); + WebUtils.printAsJSON(httpServletResponse, RespUtils.buildError(-102, "解密query参数失败")); + return; + } + try { + DbUtils dbUtils = new DbUtils(); + JSONArray jsonArray = dbUtils.exQuery(sql); + WebUtils.printAsJSON(httpServletResponse, RespUtils.buildSuccess(jsonArray)); + } catch (Exception e) { + FineLoggerFactory.getLogger().error("查询接口:执行SQL异常 ", e); + WebUtils.printAsJSON(httpServletResponse, RespUtils.buildError(-103, "SQL执行失败:" + RespUtils.Exception2String(e))); + return; + } + } +} diff --git a/src/main/java/com/fr/plugin/api/SQLUpdateApi.java b/src/main/java/com/fr/plugin/api/SQLUpdateApi.java new file mode 100644 index 0000000..378d4cb --- /dev/null +++ b/src/main/java/com/fr/plugin/api/SQLUpdateApi.java @@ -0,0 +1,71 @@ +package com.fr.plugin.api; + +import com.fr.decision.fun.impl.BaseHttpHandler; +import com.fr.json.JSONArray; +import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.utils.AesUtils; +import com.fr.plugin.utils.DbUtils; +import com.fr.plugin.utils.RespUtils; +import com.fr.stable.StringUtils; +import com.fr.third.springframework.web.bind.annotation.RequestMethod; +import com.fr.web.utils.WebUtils; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + + +public class SQLUpdateApi extends BaseHttpHandler { + + @Override + public RequestMethod getMethod() { + return RequestMethod.POST; + } + + @Override + public String getPath() { + return "/update"; + } + + + @Override + public boolean isPublic() { + return false; + } + + @Override + public void handle(HttpServletRequest request, HttpServletResponse httpServletResponse) throws Exception { + //获取参数 + String query = WebUtils.getHTTPRequestParameter(request, "query"); + if (StringUtils.isBlank(query)) { + FineLoggerFactory.getLogger().info("更新接口:传入的sql为空"); + WebUtils.printAsJSON(httpServletResponse, RespUtils.buildError(-100, "未提供query参数")); + return; + } + String sql = ""; + try { + FineLoggerFactory.getLogger().info("更新接口:待解密query:{}", query); + sql = AesUtils.decryptPassword(query); + FineLoggerFactory.getLogger().info("更新接口:解密之后为:{}", sql); + if (StringUtils.isBlank(sql)) { + WebUtils.printAsJSON(httpServletResponse, RespUtils.buildError(-101, "解密之后的SQL为空")); + return; + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error("更新接口:解密SQL异常 ", e); + WebUtils.printAsJSON(httpServletResponse, RespUtils.buildError(-102, "解密query参数失败")); + return; + } + try { + DbUtils dbUtils = new DbUtils(); + int rows = dbUtils.exSqlUpdate(sql); + JSONObject resp=new JSONObject(); + resp.put("rows", rows); + WebUtils.printAsJSON(httpServletResponse, RespUtils.buildSuccess(resp)); + } catch (Exception e) { + FineLoggerFactory.getLogger().error("更新接口:执行SQL异常 ", e); + WebUtils.printAsJSON(httpServletResponse, RespUtils.buildError(-103, "SQL执行失败:" + RespUtils.Exception2String(e))); + return; + } + } +} diff --git a/src/main/java/com/fr/plugin/utils/AesUtils.java b/src/main/java/com/fr/plugin/utils/AesUtils.java new file mode 100644 index 0000000..1787802 --- /dev/null +++ b/src/main/java/com/fr/plugin/utils/AesUtils.java @@ -0,0 +1,96 @@ +package com.fr.plugin.utils; + + +import com.fr.log.FineLoggerFactory; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +public class AesUtils { + public static String encrypt(byte[] byteContent, String keyPass) { + try { + SecretKeySpec secretKey = new SecretKeySpec(keyPass.getBytes(), "AES"); + Cipher cipher = Cipher.getInstance("AES");// 创建密码器 + cipher.init(Cipher.ENCRYPT_MODE, secretKey);// 初始化 + byte[] result = cipher.doFinal(byteContent); + return Base64.getUrlEncoder().encodeToString(result); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static String encrypt(String keyPass, String content) { + try { + SecretKeySpec secretKey = new SecretKeySpec(keyPass.getBytes(), "AES"); + Cipher cipher = Cipher.getInstance("AES");// 创建密码器 + byte[] byteContent = content.getBytes(Charset.forName("UTF-8")); + cipher.init(Cipher.ENCRYPT_MODE, secretKey);// 初始化 + byte[] result = cipher.doFinal(byteContent); + return Base64.getUrlEncoder().encodeToString(result); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static String decrypt(byte[] content, String keyPass) { + try { + SecretKeySpec secretKey = new SecretKeySpec(keyPass.getBytes(), "AES"); + Cipher cipher = Cipher.getInstance("AES");// 创建密码器 + cipher.init(Cipher.DECRYPT_MODE, secretKey);// 初始化 + byte[] result = cipher.doFinal(content); + return new String(result, StandardCharsets.UTF_8); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static String decrypt(String keyPass, String source) { + byte[] content = Base64.getUrlDecoder().decode(source); + + try { + SecretKeySpec secretKey = new SecretKeySpec(keyPass.getBytes(), "AES"); + Cipher cipher = Cipher.getInstance("AES");// 创建密码器 + cipher.init(Cipher.DECRYPT_MODE, secretKey);// 初始化 + byte[] result = cipher.doFinal(content); + + return new String(result, StandardCharsets.UTF_8); + } catch (Exception e) { + FineLoggerFactory.getLogger().error("解密数据出错,"); + printException2Frlog(e); + } + return null; + } + + public static void printException2Frlog(Exception e) { + StringWriter writer = new StringWriter(); + e.printStackTrace(new PrintWriter(writer)); + String s = writer.toString(); + FineLoggerFactory.getLogger().error("错误:{}", s); + } + public static String decryptPassword(String source) { + return decrypt("6CyqN1T6dTe9tCev", source); + } + + public static String encryptPassword(String source) { + return encrypt("6CyqN1T6dTe9tCev", source); + } + + public static void main(String[] args) { + System.out.println(encryptPassword("fine_user")); +// System.out.println(encryptPassword("id,email,mobile,password")); +// System.out.println(encryptPassword("&&")); +// System.out.println(encryptPassword("$$")); +// System.out.println(encryptPassword("where id ='6b2bc0e1-6b83-41b3-b4e5-81787dc94b9e'")); +// System.out.println(encryptPassword("$$")); +// System.out.println(encryptPassword("aabb")); +// System.out.println(encryptPassword("true")); + System.out.println(decryptPassword(encryptPassword("fine_user"))); + } + +} diff --git a/src/main/java/com/fr/plugin/utils/DbUtils.java b/src/main/java/com/fr/plugin/utils/DbUtils.java new file mode 100644 index 0000000..dc617a7 --- /dev/null +++ b/src/main/java/com/fr/plugin/utils/DbUtils.java @@ -0,0 +1,290 @@ +package com.fr.plugin.utils; + +import com.fr.file.ConnectionConfig; +import com.fr.json.JSONArray; +import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; +import com.fr.log.FineLoggerProvider; +import com.fr.third.springframework.util.StringUtils; + +import java.io.BufferedWriter; +import java.sql.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class DbUtils { + String db_name = "finedb"; + + FineLoggerProvider logger = FineLoggerFactory.getLogger(); + + public DbUtils(String db_name) { + this.db_name = db_name; + } + + public DbUtils() { + } + + public com.fr.data.impl.Connection getDbConnect() { + return ConnectionConfig.getInstance().getConnection(db_name); + } + + public JSONArray select(String sql, Object... params) { + logger.info("query data by sql:" + sql + Arrays.toString(params)); + try { + com.fr.data.impl.Connection dbConnect = getDbConnect(); + Connection con = dbConnect.createConnection(); + PreparedStatement preparedStatement = con.prepareStatement(sql); + setParams(preparedStatement, params); + ResultSet rs = preparedStatement.executeQuery(sql); + // 获得记录的详细信息,然后获得总列数 + ResultSetMetaData resMetaData = rs.getMetaData(); + int colNum = resMetaData.getColumnCount(); + // 用对象保存数据 + String name = ""; + String value = ""; + JSONArray list = new JSONArray(); + while (rs.next()) { + JSONObject cells = new JSONObject(); + for (int i = 0; i < colNum; i++) { + name = resMetaData.getColumnLabel(i); + if (cells.get(name) != null) { + name = resMetaData.getColumnLabel(i); + } + if (rs.getObject(i) != null && resMetaData.getColumnTypeName(i).equals("DATETIME") || resMetaData.getColumnTypeName(i).equals("TIMESTAMP")) { + value = rs.getObject(i).toString(); + cells.put(name, value.substring(0, value.length() - 2)); + } else { + cells.put(name, rs.getString(i)); + } + } + list.add(cells); + } + // 释放数据库资源 + rs.close(); + preparedStatement.close(); + con.close(); + return list; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public JSONObject findOneRow(String sql, Object... params) { + JSONArray select = select(sql, params); + if (select != null) { + if (!select.isEmpty()) { + return select.getJSONObject(0); + } + } + return null; + } + + public int countRows(String sql, Object... params) throws Exception { + Connection connection = null; + PreparedStatement pstmt = null; + try { + connection = getDbConnect().createConnection(); + pstmt = connection.prepareStatement(sql); + setParams(pstmt, params); + ResultSet resultSet = pstmt.executeQuery(); + if (resultSet.next()) { + return resultSet.getInt(1); + } + } catch (Exception e) { + throw e; + } finally { + try { + if (pstmt != null) { + pstmt.close(); + } + if (connection != null) { + connection.close(); + } + } catch (Exception e) { + } + } + return 0; + } + + public boolean checkExist(String sql, Object... params) throws Exception { + Connection connection = null; + PreparedStatement pstmt = null; + try { + connection = getDbConnect().createConnection(); + pstmt = connection.prepareStatement(sql); + setParams(pstmt, params); + ResultSet resultSet = pstmt.executeQuery(); + if (resultSet.next()) { + } + return true; + } catch (SQLException e) { + return false; + } catch (Exception e) { + throw e; + } finally { + try { + if (pstmt != null) { + pstmt.close(); + } + if (connection != null) { + connection.close(); + } + } catch (Exception e) { + + } + } + } + + public boolean checkTableExit(String tableName) throws Exception { + String sql = "SELECT\n" + + "*" + + "FROM\n" + + "\t" + tableName + " \n"; + return checkExist(sql); + } + + private void setParams(PreparedStatement pstmt, Object... params) throws SQLException { + if (params.length > 0) { + int length = params.length; + for (int i = 1; i <= length; i++) { + pstmt.setObject(i, params[i - 1]); + } + } + } + + public int exSqlUpdate(String sql, Object... params) throws Exception { + logger.info("update data by sql:" + sql + " params " + Arrays.toString(params)); + com.fr.data.impl.Connection dbConnect = getDbConnect(); + Connection connection = dbConnect.createConnection(); + PreparedStatement pstmt = connection.prepareStatement(sql); + setParams(pstmt, params); + int i = pstmt.executeUpdate(); + pstmt.close(); + connection.close(); + return i; + } + + /** + * 取查询结果集字段 + * + * @param sql + * @param params + * @return + * @throws Exception + */ + public JSONArray exQuery(String sql, Object... params) throws Exception { + logger.info("query data by sql:" + sql + " params " + Arrays.toString(params)); + com.fr.data.impl.Connection dbConnect = getDbConnect(); + Connection connection = dbConnect.createConnection(); + PreparedStatement pstmt = connection.prepareStatement(sql); + setParams(pstmt, params); + ResultSet resultSet = pstmt.executeQuery(); + ResultSetMetaData resMetaData = resultSet.getMetaData(); + int columnCount = resMetaData.getColumnCount(); + JSONArray arrs = new JSONArray(); + while (resultSet.next()) { + String name; + String value; + JSONObject one = new JSONObject(); + for (int i = 1; i <= columnCount; i++) { + name = resMetaData.getColumnLabel(i); + if (one.get(name) != null) { + name = resMetaData.getColumnLabel(i); + } + if (resultSet.getObject(i) != null && resMetaData.getColumnTypeName(i).equals("DATETIME") || resMetaData.getColumnTypeName(i).equals("TIMESTAMP")) { + value = resultSet.getObject(i).toString(); + one.put(name, value.substring(0, value.length() - 2)); + } else { + one.put(name, resultSet.getString(i)); + } + } + arrs.add(one); + } + + pstmt.close(); + connection.close(); + logger.info("查询结果:" + arrs); + return arrs; + } + + public void queryfromlogdb(String sql, String line_break, String field_break, BufferedWriter bufferedWriter, String m_flag) throws Exception { + com.fr.data.impl.Connection dbConnect = getDbConnect(); + Connection connection = dbConnect.createConnection(); + PreparedStatement pstmt = connection.prepareStatement(sql); + ResultSet resultSet = pstmt.executeQuery(); + ResultSetMetaData resMetaData = resultSet.getMetaData(); + int columnCount = resMetaData.getColumnCount(); + int size = 0; + StringBuilder builder = new StringBuilder( ) ; + while (resultSet.next()) { + for (int i = 1; i <= columnCount; i++) { + if (i == 1) { + builder.append(m_flag).append(field_break); + }else{ + builder.append(field_break); + } + String data = resultSet.getString(i); + builder.append(StringUtils.trimAllWhitespace(data)); + } + builder.append(line_break); + if (size > 10) { + bufferedWriter.write(builder.toString()); + builder = new StringBuilder(); + } + size++; + } + bufferedWriter.write(builder.toString()); + resultSet.close(); + pstmt.close(); + connection.close(); + } + + public List query(String sql, String line_break, String field_break,String m_flag) throws Exception { + com.fr.data.impl.Connection dbConnect = getDbConnect(); + Connection connection = dbConnect.createConnection(); + PreparedStatement pstmt = connection.prepareStatement(sql); + ResultSet resultSet = pstmt.executeQuery(); + ResultSetMetaData resMetaData = resultSet.getMetaData(); + int columnCount = resMetaData.getColumnCount(); + List arrs = new ArrayList<>(); + while (resultSet.next()) { + StringBuilder builder = new StringBuilder(); + for (int i = 1; i <= columnCount; i++) { + if (i == 1) { + builder.append(m_flag).append(field_break); + }else{ + builder.append(field_break); + } + String data = resultSet.getString(i); + builder.append(StringUtils.trimAllWhitespace(data)); + } + builder.append(line_break); + arrs.add(builder.toString()); + } + resultSet.close(); + pstmt.close(); + connection.close(); + return arrs; + } + + public List getQueryFields(String preSql, Object... params) throws Exception { + com.fr.data.impl.Connection dbConnect = getDbConnect(); + Connection connection = dbConnect.createConnection(); + PreparedStatement pstmt = connection.prepareStatement(preSql); + setParams(pstmt, params); + ResultSet resultSet = pstmt.executeQuery(); + ResultSetMetaData resMetaData = resultSet.getMetaData(); + int columnCount = resMetaData.getColumnCount(); + List arrs = new ArrayList<>(); + for (int i = 0; i < columnCount; i++) { + String columnName = resMetaData.getColumnName(i + 1); + arrs.add(columnName); + } + resultSet.close(); + pstmt.close(); + connection.close(); + return arrs; + } +} diff --git a/src/main/java/com/fr/plugin/utils/RespUtils.java b/src/main/java/com/fr/plugin/utils/RespUtils.java new file mode 100644 index 0000000..f479337 --- /dev/null +++ b/src/main/java/com/fr/plugin/utils/RespUtils.java @@ -0,0 +1,34 @@ +package com.fr.plugin.utils; + + +import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; + +import java.io.PrintWriter; +import java.io.StringWriter; + +public class RespUtils { + public static JSONObject buildResp(int code, String msg, Object data) { + JSONObject res = new JSONObject(); + res.put("code", code); + res.put("msg", msg); + res.put("data", data); + return res; + } + public static String Exception2String(Throwable e) { + StringWriter writer = new StringWriter(); + e.printStackTrace(new PrintWriter(writer)); + return writer.toString(); + } + public static JSONObject buildError(int code, String msg) { + return buildResp(code, msg, ""); + } + + public static JSONObject buildNormalError(String msg) { + return buildResp(-1, msg, ""); + } + + public static JSONObject buildSuccess(Object data) { + return buildResp(0, "success", data); + } +} diff --git a/src/main/resources/com/fr/plugin/alert.html b/src/main/resources/com/fr/plugin/alert.html new file mode 100644 index 0000000..bfb2ea2 --- /dev/null +++ b/src/main/resources/com/fr/plugin/alert.html @@ -0,0 +1,35 @@ + + + + + alert + + + + + + + \ No newline at end of file diff --git a/src/main/resources/com/fr/plugin/demo.properties b/src/main/resources/com/fr/plugin/demo.properties new file mode 100644 index 0000000..9bc5f29 --- /dev/null +++ b/src/main/resources/com/fr/plugin/demo.properties @@ -0,0 +1 @@ +Plugin-Test_Function_Abs=Test ABS \ No newline at end of file diff --git a/src/main/resources/com/fr/plugin/demo_zh_CN.properties b/src/main/resources/com/fr/plugin/demo_zh_CN.properties new file mode 100644 index 0000000..aa910e8 --- /dev/null +++ b/src/main/resources/com/fr/plugin/demo_zh_CN.properties @@ -0,0 +1 @@ +Plugin-Test_Function_Abs=测试ABS函数 \ No newline at end of file diff --git a/src/main/resources/com/fr/plugin/js/print.js b/src/main/resources/com/fr/plugin/js/print.js new file mode 100644 index 0000000..e5965af --- /dev/null +++ b/src/main/resources/com/fr/plugin/js/print.js @@ -0,0 +1,476 @@ +!function (e, t) { + "object" == typeof exports && "object" == typeof module ? module.exports = t() : "function" == typeof define && define.amd ? define([], t) : "object" == typeof exports ? exports.printJS = t() : e.printJS = t() +}(window, function () { + return function (n) { + var r = {}; + + function o(e) { + if (r[e]) return r[e].exports; + var t = r[e] = {i: e, l: !1, exports: {}}; + return n[e].call(t.exports, t, t.exports, o), t.l = !0, t.exports + } + + return o.m = n, o.c = r, o.d = function (e, t, n) { + o.o(e, t) || Object.defineProperty(e, t, {enumerable: !0, get: n}) + }, o.r = function (e) { + "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {value: "Module"}), Object.defineProperty(e, "__esModule", {value: !0}) + }, o.t = function (t, e) { + if (1 & e && (t = o(t)), 8 & e) return t; + if (4 & e && "object" == typeof t && t && t.__esModule) return t; + var n = Object.create(null); + if (o.r(n), Object.defineProperty(n, "default", { + enumerable: !0, + value: t + }), 2 & e && "string" != typeof t) for (var r in t) o.d(n, r, function (e) { + return t[e] + }.bind(null, r)); + return n + }, o.n = function (e) { + var t = e && e.__esModule ? function () { + return e.default + } : function () { + return e + }; + return o.d(t, "a", t), t + }, o.o = function (e, t) { + return Object.prototype.hasOwnProperty.call(e, t) + }, o.p = "", o(o.s = 4) + }([function (e, t, n) { + "use strict"; + Object.defineProperty(t, "__esModule", {value: !0}); + var r, o = n(2), i = (r = o) && r.__esModule ? r : {default: r}, a = n(1); + var l = { + send: function (r, e) { + document.getElementsByTagName("body")[0].appendChild(e); + var o = document.getElementById(r.frameId); + o.onload = function () { + if ("pdf" !== r.type) { + var e = o.contentWindow || o.contentDocument; + if (e.document && (e = e.document), e.body.appendChild(r.printableElement), "pdf" !== r.type && r.style) { + var t = document.createElement("style"); + t.innerHTML = r.style, e.head.appendChild(t) + } + var n = e.getElementsByTagName("img"); + 0 < n.length ? function (e) { + var t = [], n = !0, r = !1, o = void 0; + try { + for (var i, a = e[Symbol.iterator](); !(n = (i = a.next()).done); n = !0) { + var l = i.value; + t.push(u(l)) + } + } catch (e) { + r = !0, o = e + } finally { + try { + !n && a.return && a.return() + } finally { + if (r) throw o + } + } + return Promise.all(t) + }(n).then(function () { + return d(o, r) + }) : d(o, r) + } else d(o, r) + } + } + }; + + function d(t, n) { + try { + if (t.focus(), i.default.isEdge() || i.default.isIE()) try { + t.contentWindow.document.execCommand("print", !1, null) + } catch (e) { + t.contentWindow.print() + } else t.contentWindow.print() + } catch (e) { + n.onError(e) + } finally { + (0, a.cleanUp)(n) + } + } + + function u(n) { + return new Promise(function (t) { + !function e() { + n && void 0 !== n.naturalWidth && 0 !== n.naturalWidth && n.complete ? t() : setTimeout(e, 500) + }() + }) + } + + t.default = l + }, function (e, t, n) { + "use strict"; + Object.defineProperty(t, "__esModule", {value: !0}); + var i = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (e) { + return typeof e + } : function (e) { + return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e + }; + t.addWrapper = function (e, t) { + return '

' + e + "
" + }, t.capitalizePrint = function (e) { + return e.charAt(0).toUpperCase() + e.slice(1) + }, t.collectStyles = f, t.loopNodesCollectStyles = function e(t, n) { + for (var r = 0; r < t.length; r++) { + var o = t[r]; + if (-1 === n.ignoreElements.indexOf(o.getAttribute("id"))) { + var i = o.tagName; + if ("INPUT" === i || "TEXTAREA" === i || "SELECT" === i) { + var a = f(o, n), l = o.parentNode, + d = "SELECT" === i ? document.createTextNode(o.options[o.selectedIndex].text) : document.createTextNode(o.value), + u = document.createElement("div"); + u.appendChild(d), u.setAttribute("style", a), l.appendChild(u), l.removeChild(o) + } else o.setAttribute("style", f(o, n)); + var c = o.children; + c && c.length && e(c, n) + } else o.parentNode.removeChild(o) + } + }, t.addHeader = function (e, t) { + var n = document.createElement("div"); + if (l(t.header)) n.innerHTML = t.header; else { + var r = document.createElement("h1"), o = document.createTextNode(t.header); + r.appendChild(o), r.setAttribute("style", t.headerStyle), n.appendChild(r) + } + e.insertBefore(n, e.childNodes[0]) + }, t.cleanUp = function (t) { + t.showModal && r.default.close(); + t.onLoadingEnd && t.onLoadingEnd(); + (t.showModal || t.onLoadingStart) && window.URL.revokeObjectURL(t.printable); + if (t.onPrintDialogClose) { + var n = "mouseover"; + (o.default.isChrome() || o.default.isFirefox()) && (n = "focus"); + window.addEventListener(n, function e() { + window.removeEventListener(n, e), t.onPrintDialogClose() + }) + } + }, t.isRawHTML = l; + var r = a(n(3)), o = a(n(2)); + + function a(e) { + return e && e.__esModule ? e : {default: e} + } + + function f(e, t) { + var n = document.defaultView || window, r = "", o = n.getComputedStyle(e, ""); + return Object.keys(o).map(function (e) { + (-1 !== t.targetStyles.indexOf("*") || -1 !== t.targetStyle.indexOf(o[e]) || function (e, t) { + for (var n = 0; n < e.length; n++) if ("object" === (void 0 === t ? "undefined" : i(t)) && -1 !== t.indexOf(e[n])) return !0; + return !1 + }(t.targetStyles, o[e])) && o.getPropertyValue(o[e]) && (r += o[e] + ":" + o.getPropertyValue(o[e]) + ";") + }), r += "max-width: " + t.maxWidth + "px !important;" + t.font_size + " !important;" + } + + function l(e) { + return new RegExp("<([A-Za-z][A-Za-z0-9]*)\\b[^>]*>(.*?)").test(e) + } + }, function (e, t, n) { + "use strict"; + Object.defineProperty(t, "__esModule", {value: !0}); + var r = { + isFirefox: function () { + return "undefined" != typeof InstallTrigger + }, isIE: function () { + return -1 !== navigator.userAgent.indexOf("MSIE") || !!document.documentMode + }, isEdge: function () { + return !r.isIE() && !!window.StyleMedia + }, isChrome: function () { + return !!(0 < arguments.length && void 0 !== arguments[0] ? arguments[0] : window).chrome + }, isSafari: function () { + return 0 < Object.prototype.toString.call(window.HTMLElement).indexOf("Constructor") || -1 !== navigator.userAgent.toLowerCase().indexOf("safari") + } + }; + t.default = r + }, function (e, t, n) { + "use strict"; + Object.defineProperty(t, "__esModule", {value: !0}); + var a = { + show: function (e) { + var t = document.createElement("div"); + t.setAttribute("style", "font-family:sans-serif; display:table; text-align:center; font-weight:300; font-size:30px; left:0; top:0;position:fixed; z-index: 9990;color: #0460B5; width: 100%; height: 100%; background-color:rgba(255,255,255,.9);transition: opacity .3s ease;"), t.setAttribute("id", "printJS-Modal"); + var n = document.createElement("div"); + n.setAttribute("style", "display:table-cell; vertical-align:middle; padding-bottom:100px;"); + var r = document.createElement("div"); + r.setAttribute("class", "printClose"), r.setAttribute("id", "printClose"), n.appendChild(r); + var o = document.createElement("span"); + o.setAttribute("class", "printSpinner"), n.appendChild(o); + var i = document.createTextNode(e.modalMessage); + n.appendChild(i), t.appendChild(n), document.getElementsByTagName("body")[0].appendChild(t), document.getElementById("printClose").addEventListener("click", function () { + a.close() + }) + }, close: function () { + var e = document.getElementById("printJS-Modal"); + e.parentNode.removeChild(e) + } + }; + t.default = a + }, function (e, t, n) { + e.exports = n(5) + }, function (e, t, n) { + "use strict"; + Object.defineProperty(t, "__esModule", {value: !0}), n(6); + var r, o = n(7); + var i = ((r = o) && r.__esModule ? r : {default: r}).default.init; + "undefined" != typeof window && (window.printJS = i), t.default = i + }, function (e, t, n) { + }, function (e, t, n) { + "use strict"; + Object.defineProperty(t, "__esModule", {value: !0}); + var i = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (e) { + return typeof e + } : function (e) { + return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e + }, a = r(n(2)), l = r(n(3)), d = r(n(8)), u = r(n(9)), c = r(n(10)), f = r(n(11)), s = r(n(12)); + + function r(e) { + return e && e.__esModule ? e : {default: e} + } + + var p = ["pdf", "html", "image", "json", "raw-html"]; + t.default = { + init: function () { + var t = { + printable: null, + fallbackPrintable: null, + type: "pdf", + header: null, + headerStyle: "font-weight: 300;", + maxWidth: 800, + font: "TimesNewRoman", + font_size: "12pt", + honorMarginPadding: !0, + honorColor: !1, + properties: null, + gridHeaderStyle: "font-weight: bold; padding: 5px; border: 1px solid #dddddd;", + gridStyle: "border: 1px solid lightgray; margin-bottom: -1px;", + showModal: !1, + onError: function (e) { + throw e + }, + onLoadingStart: null, + onLoadingEnd: null, + onPrintDialogClose: null, + onPdfOpen: null, + onBrowserIncompatible: function () { + return !0 + }, + modalMessage: "Retrieving Document...", + frameId: "printJS", + printableElement: null, + documentTitle: "Document", + targetStyle: ["clear", "display", "width", "min-width", "height", "min-height", "max-height"], + targetStyles: ["border", "box", "break", "text-decoration"], + ignoreElements: [], + imageStyle: "max-width: 100%;", + repeatTableHeader: !0, + css: null, + style: null, + scanStyles: !0, + base64: !1 + }, e = arguments[0]; + if (void 0 === e) throw new Error("printJS expects at least 1 attribute."); + switch (void 0 === e ? "undefined" : i(e)) { + case"string": + t.printable = encodeURI(e), t.fallbackPrintable = t.printable, t.type = arguments[1] || t.type; + break; + case"object": + for (var n in t.printable = e.printable, t.base64 = void 0 !== e.base64, t.fallbackPrintable = void 0 !== e.fallbackPrintable ? e.fallbackPrintable : t.printable, t.fallbackPrintable = t.base64 ? "data:application/pdf;base64," + t.fallbackPrintable : t.fallbackPrintable, t) "printable" !== n && "fallbackPrintable" !== n && "base64" !== n && (t[n] = void 0 !== e[n] ? e[n] : t[n]); + break; + default: + throw new Error('Unexpected argument type! Expected "string" or "object", got ' + (void 0 === e ? "undefined" : i(e))) + } + if (!t.printable) throw new Error("Missing printable information."); + if (!t.type || "string" != typeof t.type || -1 === p.indexOf(t.type.toLowerCase())) throw new Error("Invalid print type. Available types are: pdf, html, image and json."); + t.showModal && l.default.show(t), t.onLoadingStart && t.onLoadingStart(); + var r = document.getElementById(t.frameId); + r && r.parentNode.removeChild(r); + var o = void 0; + switch ((o = document.createElement("iframe")).setAttribute("style", "visibility: hidden; height: 0; width: 0; position: absolute;"), o.setAttribute("id", t.frameId), "pdf" !== t.type && (o.srcdoc = "" + t.documentTitle + "", null !== t.css && (Array.isArray(t.css) || (t.css = [t.css]), t.css.forEach(function (e) { + o.srcdoc += '' + })), o.srcdoc += ""), t.type) { + case"pdf": + if (a.default.isFirefox() || a.default.isEdge() || a.default.isIE()) try { + if (console.info("PrintJS currently doesn't support PDF printing in Firefox, Internet Explorer and Edge."), !0 === t.onBrowserIncompatible()) window.open(t.fallbackPrintable, "_blank").focus(), t.onPdfOpen && t.onPdfOpen() + } catch (e) { + t.onError(e) + } finally { + t.showModal && l.default.close(), t.onLoadingEnd && t.onLoadingEnd() + } else d.default.print(t, o); + break; + case"image": + f.default.print(t, o); + break; + case"html": + u.default.print(t, o); + break; + case"raw-html": + c.default.print(t, o); + break; + case"json": + s.default.print(t, o) + } + } + } + }, function (e, t, n) { + "use strict"; + Object.defineProperty(t, "__esModule", {value: !0}); + var r, o = n(0), i = (r = o) && r.__esModule ? r : {default: r}, a = n(1); + + function l(e, t, n) { + var r = new window.Blob([n], {type: "application/pdf"}); + r = window.URL.createObjectURL(r), t.setAttribute("src", r), i.default.send(e, t) + } + + t.default = { + print: function (e, t) { + if (e.base64) { + var n = Uint8Array.from(atob(e.printable), function (e) { + return e.charCodeAt(0) + }); + l(e, t, n) + } else { + e.printable = /^(blob|http)/i.test(e.printable) ? e.printable : window.location.origin + ("/" !== e.printable.charAt(0) ? "/" + e.printable : e.printable); + var r = new window.XMLHttpRequest; + r.responseType = "arraybuffer", r.addEventListener("load", function () { + if (-1 === [200, 201].indexOf(r.status)) return (0, a.cleanUp)(e), void e.onError(r.statusText); + l(e, t, r.response) + }), r.open("GET", e.printable, !0), r.send() + } + } + } + }, function (e, t, n) { + "use strict"; + Object.defineProperty(t, "__esModule", {value: !0}); + var r, o = n(1), i = n(0), a = (r = i) && r.__esModule ? r : {default: r}; + t.default = { + print: function (e, t) { + var n = document.getElementById(e.printable); + n ? (e.printableElement = function e(t, n) { + var r = t.cloneNode(); + var o = !0; + var i = !1; + var a = void 0; + try { + for (var l, d = t.childNodes[Symbol.iterator](); !(o = (l = d.next()).done); o = !0) { + var u = l.value; + if (-1 === n.ignoreElements.indexOf(u.id)) { + var c = e(u, n); + r.appendChild(c) + } + } + } catch (e) { + i = !0, a = e + } finally { + try { + !o && d.return && d.return() + } finally { + if (i) throw a + } + } + switch (t.tagName) { + case"SELECT": + r.value = t.value; + break; + case"CANVAS": + r.getContext("2d").drawImage(t, 0, 0) + } + return r + }(n, e), e.header && (0, o.addHeader)(e.printableElement, e), a.default.send(e, t)) : window.console.error("Invalid HTML element id: " + e.printable) + } + } + }, function (e, t, n) { + "use strict"; + Object.defineProperty(t, "__esModule", {value: !0}); + var r, o = n(0), i = (r = o) && r.__esModule ? r : {default: r}; + t.default = { + print: function (e, t) { + e.printableElement = document.createElement("div"), e.printableElement.setAttribute("style", "width:100%"), e.printableElement.innerHTML = e.printable, i.default.send(e, t) + } + } + }, function (e, t, n) { + "use strict"; + Object.defineProperty(t, "__esModule", {value: !0}); + var r, o = n(1), i = n(0), a = (r = i) && r.__esModule ? r : {default: r}; + t.default = { + print: function (r, e) { + r.printable.constructor !== Array && (r.printable = [r.printable]), r.printableElement = document.createElement("div"), r.printable.forEach(function (e) { + var t = document.createElement("img"); + t.setAttribute("style", r.imageStyle), t.src = e; + var n = document.createElement("div"); + n.appendChild(t), r.printableElement.appendChild(n) + }), r.header && (0, o.addHeader)(r.printableElement, r), a.default.send(r, e) + } + } + }, function (e, t, n) { + "use strict"; + Object.defineProperty(t, "__esModule", {value: !0}); + var r, o = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (e) { + return typeof e + } : function (e) { + return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e + }, c = n(1), i = n(0), a = (r = i) && r.__esModule ? r : {default: r}; + t.default = { + print: function (t, e) { + if ("object" !== o(t.printable)) throw new Error("Invalid javascript data object (JSON)."); + if ("boolean" != typeof t.repeatTableHeader) throw new Error("Invalid value for repeatTableHeader attribute (JSON)."); + if (!t.properties || !Array.isArray(t.properties)) throw new Error("Invalid properties array for your JSON data."); + t.properties = t.properties.map(function (e) { + return { + field: "object" === (void 0 === e ? "undefined" : o(e)) ? e.field : e, + displayName: "object" === (void 0 === e ? "undefined" : o(e)) ? e.displayName : e, + columnSize: "object" === (void 0 === e ? "undefined" : o(e)) && e.columnSize ? e.columnSize + ";" : 100 / t.properties.length + "%;" + } + }), t.printableElement = document.createElement("div"), t.header && (0, c.addHeader)(t.printableElement, t), t.printableElement.innerHTML += function (e) { + var t = e.printable, n = e.properties, + r = ''; + e.repeatTableHeader && (r += ""); + r += ""; + for (var o = 0; o < n.length; o++) r += '"; + r += "", e.repeatTableHeader && (r += ""); + r += ""; + for (var i = 0; i < t.length; i++) { + r += ""; + for (var a = 0; a < n.length; a++) { + var l = t[i], d = n[a].field.split("."); + if (1 < d.length) for (var u = 0; u < d.length; u++) l = l[d[u]]; else l = l[n[a].field]; + r += '" + } + r += "" + } + return r += "
' + (0, c.capitalizePrint)(n[o].displayName) + "
' + l + "
" + }(t), a.default.send(t, e) + } + } + }]).default +}); + +/** + * 打印图片,传入要打印的图片,相对路径或者绝对路径都可以 + * @param url + */ +function printImage(url) { + printJS(url, 'image') +} + +window.printImage=printImage; +/** + * PDF文件必须与使用的程序在相同的域中。在打印文件之前会使用iframe加载文件,因此受到Same Origin Policy的限制。 + */ +function printPdf(url) { + printJS(url, 'pdf') +} +window.printPdf=printPdf; +/** + * 使用base64封装的pdfdata对象。 + */ +function printPdfBase64(data) { + printJS({printable: data, type: 'pdf', base64: true}) +} +window.printPdfBase64=printPdfBase64; +/** + * 打印dom对象, 传递要打印dom的id 不带#号 + */ +function printDom(nodeId) { + printJS({printable: nodeId, type: 'html'}) +} +window.printDom=printDom; \ No newline at end of file