diff --git a/docs/databases/table_create_customer-cashed.sql b/docs/databases/table_create_customer-cashed.sql
index 769adc2d..90758e52 100644
--- a/docs/databases/table_create_customer-cashed.sql
+++ b/docs/databases/table_create_customer-cashed.sql
@@ -147,7 +147,9 @@ CREATE TABLE `csm_cash_report` (
`tillTime` varchar(100) DEFAULT NULL COMMENT '截止时间',
`accountBalance` double(12,2) DEFAULT 0 COMMENT '账户余额',
`auditResult` varchar(1024) DEFAULT NULL COMMENT '审核结果',
- `reportDate` varchar(100) DEFAULT NULL COMMENT '日期(yyyy年MM月dd日)',
+ `reportDate` varchar(100) DEFAULT NULL COMMENT '日期(yyyy年MM月dd日)',
+ `fileFullPath` varchar(255) DEFAULT NULL COMMENT '文件完整路径',
+ `fileUrl` varchar(1024) DEFAULT NULL COMMENT '文件下载地址',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB COMMENT='每日回款审核报告' ;
diff --git a/yxt_supervise/supervise-customer/supervise-customer-biz/src/main/java/com/yxt/supervise/customer/biz/gdinventorylog/ReportInventoryDayStore.java b/yxt_supervise/supervise-customer/supervise-customer-biz/src/main/java/com/yxt/supervise/customer/biz/gdinventorylog/ReportInventoryDayStore.java
index f6d5eb5e..850d303f 100644
--- a/yxt_supervise/supervise-customer/supervise-customer-biz/src/main/java/com/yxt/supervise/customer/biz/gdinventorylog/ReportInventoryDayStore.java
+++ b/yxt_supervise/supervise-customer/supervise-customer-biz/src/main/java/com/yxt/supervise/customer/biz/gdinventorylog/ReportInventoryDayStore.java
@@ -31,6 +31,8 @@ public class ReportInventoryDayStore extends EntityWithId {
private String storeCode; // 门店编号',
private String storeCodeName; // [门店编号]门店名称',
private int productCountNumber; // 品种数量',
+
+ private int typeNumber;//商品品种数量
private double productAmount; // 货值',
private double countAmount; // 合计货值',
private long countProductNumber; // 合计品种数量',
@@ -106,6 +108,13 @@ public class ReportInventoryDayStore extends EntityWithId {
public void setProductCountNumber(int productCountNumber) {
this.productCountNumber = productCountNumber;
}
+ public int getTypeNumber() {
+ return typeNumber;
+ }
+
+ public void setTypeNumber(int typeNumber) {
+ this.typeNumber = typeNumber;
+ }
public double getProductAmount() {
return productAmount;
diff --git a/yxt_supervise/supervise-customer/supervise-customer-biz/src/main/java/com/yxt/supervise/customer/biz/gdinventorylog/ReportInventoryDayTobaccoStore.java b/yxt_supervise/supervise-customer/supervise-customer-biz/src/main/java/com/yxt/supervise/customer/biz/gdinventorylog/ReportInventoryDayTobaccoStore.java
index 2f20f37e..2c7f9ca2 100644
--- a/yxt_supervise/supervise-customer/supervise-customer-biz/src/main/java/com/yxt/supervise/customer/biz/gdinventorylog/ReportInventoryDayTobaccoStore.java
+++ b/yxt_supervise/supervise-customer/supervise-customer-biz/src/main/java/com/yxt/supervise/customer/biz/gdinventorylog/ReportInventoryDayTobaccoStore.java
@@ -20,7 +20,8 @@ public class ReportInventoryDayTobaccoStore extends EntityWithId {
private int warehouseType=2; // 仓库类型
private String storeCode ; // 门店编号
private String storeCodeName ; // [门店编号]门店名称
- private int productCountNumber; // 品种数量
+ private int productCountNumber; // 品种数量
+ private int typeNumber;
private double productAmount; // 货值
private double countAmount; // 合计货值
private long countProductNumber; // 合计品种数量
@@ -98,6 +99,14 @@ public class ReportInventoryDayTobaccoStore extends EntityWithId {
this.productCountNumber = productCountNumber;
}
+ public int getTypeNumber() {
+ return typeNumber;
+ }
+
+ public void setTypeNumber(int typeNumber) {
+ this.typeNumber = typeNumber;
+ }
+
public double getProductAmount() {
return productAmount;
}
diff --git a/yxt_supervise/supervise-report/supervise-report-api/src/main/java/com/yxt/supervise/report/api/csmcashreport/CsmCashReport.java b/yxt_supervise/supervise-report/supervise-report-api/src/main/java/com/yxt/supervise/report/api/csmcashreport/CsmCashReport.java
index aabd99d0..09151f4d 100644
--- a/yxt_supervise/supervise-report/supervise-report-api/src/main/java/com/yxt/supervise/report/api/csmcashreport/CsmCashReport.java
+++ b/yxt_supervise/supervise-report/supervise-report-api/src/main/java/com/yxt/supervise/report/api/csmcashreport/CsmCashReport.java
@@ -14,7 +14,11 @@ import java.util.Date;
@ApiModel(value = "每日回款审核报告-附件:昨日销售报表", description = "每日回款审核报告-附件:昨日销售报表")
@TableName("csm_cash_report")
@Data
-public class CsmCashReport extends BaseEntity {
+public class CsmCashReport {
+ private String id;
+ private String sid;
+ private String createTime;
+ private String remarks;
//'日期(yyyy-MM-dd)',
private String dataDate;
// '银行Sid',
@@ -51,4 +55,6 @@ public class CsmCashReport extends BaseEntity {
private String auditResult;
//'日期(yyyy年MM月dd日)',
private String reportDate;
+ private String fileFullPath;
+ private String fileUrl;
}
diff --git a/yxt_supervise/supervise-report/supervise-report-api/src/main/java/com/yxt/supervise/report/api/csmcashreport/CsmCashReportDto.java b/yxt_supervise/supervise-report/supervise-report-api/src/main/java/com/yxt/supervise/report/api/csmcashreport/CsmCashReportDto.java
index a3901f42..a57a840b 100644
--- a/yxt_supervise/supervise-report/supervise-report-api/src/main/java/com/yxt/supervise/report/api/csmcashreport/CsmCashReportDto.java
+++ b/yxt_supervise/supervise-report/supervise-report-api/src/main/java/com/yxt/supervise/report/api/csmcashreport/CsmCashReportDto.java
@@ -43,4 +43,6 @@ public class CsmCashReportDto {
private String auditResult;
//'日期(yyyy年MM月dd日)',
private String reportDate;
+ private String fileFullPath;
+ private String fileUrl;
}
diff --git a/yxt_supervise/supervise-report/supervise-report-biz/pom.xml b/yxt_supervise/supervise-report/supervise-report-biz/pom.xml
index 06d5f321..38b0133d 100644
--- a/yxt_supervise/supervise-report/supervise-report-biz/pom.xml
+++ b/yxt_supervise/supervise-report/supervise-report-biz/pom.xml
@@ -92,7 +92,11 @@
jdk15
2.4
-
+
+ commons-codec
+ commons-codec
+ 1.9
+
diff --git a/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/.WXBizMsgCrypt.java.swp b/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/.WXBizMsgCrypt.java.swp
new file mode 100644
index 00000000..27e0c276
Binary files /dev/null and b/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/.WXBizMsgCrypt.java.swp differ
diff --git a/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/AesException.java b/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/AesException.java
new file mode 100644
index 00000000..2078c494
--- /dev/null
+++ b/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/AesException.java
@@ -0,0 +1,59 @@
+package com.yxt.supervise.report.aes;
+
+@SuppressWarnings("serial")
+public class AesException extends Exception {
+
+ public final static int OK = 0;
+ public final static int ValidateSignatureError = -40001;
+ public final static int ParseXmlError = -40002;
+ public final static int ComputeSignatureError = -40003;
+ public final static int IllegalAesKey = -40004;
+ public final static int ValidateAppidError = -40005;
+ public final static int EncryptAESError = -40006;
+ public final static int DecryptAESError = -40007;
+ public final static int IllegalBuffer = -40008;
+ //public final static int EncodeBase64Error = -40009;
+ //public final static int DecodeBase64Error = -40010;
+ //public final static int GenReturnXmlError = -40011;
+
+ private int code;
+
+ private static String getMessage(int code) {
+ switch (code) {
+ case ValidateSignatureError:
+ return "签名验证错误";
+ case ParseXmlError:
+ return "xml解析失败";
+ case ComputeSignatureError:
+ return "sha加密生成签名失败";
+ case IllegalAesKey:
+ return "SymmetricKey非法";
+ case ValidateAppidError:
+ return "appid校验失败";
+ case EncryptAESError:
+ return "aes加密失败";
+ case DecryptAESError:
+ return "aes解密失败";
+ case IllegalBuffer:
+ return "解密后得到的buffer非法";
+// case EncodeBase64Error:
+// return "base64加密错误";
+// case DecodeBase64Error:
+// return "base64解密错误";
+// case GenReturnXmlError:
+// return "xml生成失败";
+ default:
+ return null; // cannot be
+ }
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+ AesException(int code) {
+ super(getMessage(code));
+ this.code = code;
+ }
+
+}
diff --git a/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/ByteGroup.java b/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/ByteGroup.java
new file mode 100644
index 00000000..b263b820
--- /dev/null
+++ b/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/ByteGroup.java
@@ -0,0 +1,26 @@
+package com.yxt.supervise.report.aes;
+
+import java.util.ArrayList;
+
+class ByteGroup {
+ ArrayList byteContainer = new ArrayList();
+
+ public byte[] toBytes() {
+ byte[] bytes = new byte[byteContainer.size()];
+ for (int i = 0; i < byteContainer.size(); i++) {
+ bytes[i] = byteContainer.get(i);
+ }
+ return bytes;
+ }
+
+ public ByteGroup addBytes(byte[] bytes) {
+ for (byte b : bytes) {
+ byteContainer.add(b);
+ }
+ return this;
+ }
+
+ public int size() {
+ return byteContainer.size();
+ }
+}
diff --git a/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/PKCS7Encoder.java b/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/PKCS7Encoder.java
new file mode 100644
index 00000000..b967d9b8
--- /dev/null
+++ b/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/PKCS7Encoder.java
@@ -0,0 +1,67 @@
+/**
+ * 对公众平台发送给公众账号的消息加解密示例代码.
+ *
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+// ------------------------------------------------------------------------
+
+package com.yxt.supervise.report.aes;
+
+import java.nio.charset.Charset;
+import java.util.Arrays;
+
+/**
+ * 提供基于PKCS7算法的加解密接口.
+ */
+class PKCS7Encoder {
+ static Charset CHARSET = Charset.forName("utf-8");
+ static int BLOCK_SIZE = 32;
+
+ /**
+ * 获得对明文进行补位填充的字节.
+ *
+ * @param count 需要进行填充补位操作的明文字节个数
+ * @return 补齐用的字节数组
+ */
+ static byte[] encode(int count) {
+ // 计算需要填充的位数
+ int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
+ if (amountToPad == 0) {
+ amountToPad = BLOCK_SIZE;
+ }
+ // 获得补位所用的字符
+ char padChr = chr(amountToPad);
+ String tmp = new String();
+ for (int index = 0; index < amountToPad; index++) {
+ tmp += padChr;
+ }
+ return tmp.getBytes(CHARSET);
+ }
+
+ /**
+ * 删除解密后明文的补位字符
+ *
+ * @param decrypted 解密后的明文
+ * @return 删除补位字符后的明文
+ */
+ static byte[] decode(byte[] decrypted) {
+ int pad = (int) decrypted[decrypted.length - 1];
+ if (pad < 1 || pad > 32) {
+ pad = 0;
+ }
+ return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
+ }
+
+ /**
+ * 将数字转化成ASCII码对应的字符,用于对明文进行补码
+ *
+ * @param a 需要转化的数字
+ * @return 转化得到的字符
+ */
+ static char chr(int a) {
+ byte target = (byte) (a & 0xFF);
+ return (char) target;
+ }
+
+}
diff --git a/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/Program.java b/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/Program.java
new file mode 100644
index 00000000..7687c5ed
--- /dev/null
+++ b/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/Program.java
@@ -0,0 +1,58 @@
+package com.yxt.supervise.report.aes;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.StringReader;
+
+public class Program {
+
+ public static void main(String[] args) throws Exception {
+
+ //
+ // 第三方回复公众平台
+ //
+
+ // 需要加密的明文
+ String encodingAesKey = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG";
+ String token = "pamtest";
+ String timestamp = "1409304348";
+ String nonce = "xxxxxx";
+ String appId = "wxb11529c136998cb6";
+ String replyMsg = " 中文1407743423";
+
+ WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId);
+ String mingwen = pc.encryptMsg(replyMsg, timestamp, nonce);
+ System.out.println("加密后: " + mingwen);
+
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ StringReader sr = new StringReader(mingwen);
+ InputSource is = new InputSource(sr);
+ Document document = db.parse(is);
+
+ Element root = document.getDocumentElement();
+ NodeList nodelist1 = root.getElementsByTagName("Encrypt");
+ NodeList nodelist2 = root.getElementsByTagName("MsgSignature");
+
+ String encrypt = nodelist1.item(0).getTextContent();
+ String msgSignature = nodelist2.item(0).getTextContent();
+
+ String format = "";
+ String fromXML = String.format(format, encrypt);
+
+ //
+ // 公众平台发送消息给第三方,第三方处理
+ //
+
+ // 第三方收到公众号平台发送的消息
+ String result2 = pc.decryptMsg(msgSignature, timestamp, nonce, fromXML);
+ System.out.println("解密后明文: " + result2);
+
+ //pc.verifyUrl(null, null, null, null);
+ }
+}
diff --git a/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/SHA1.java b/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/SHA1.java
new file mode 100644
index 00000000..62d0ef8e
--- /dev/null
+++ b/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/SHA1.java
@@ -0,0 +1,61 @@
+/**
+ * 对公众平台发送给公众账号的消息加解密示例代码.
+ *
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+// ------------------------------------------------------------------------
+
+package com.yxt.supervise.report.aes;
+
+import java.security.MessageDigest;
+import java.util.Arrays;
+
+/**
+ * SHA1 class
+ *
+ * 计算公众平台的消息签名接口.
+ */
+class SHA1 {
+
+ /**
+ * 用SHA1算法生成安全签名
+ * @param token 票据
+ * @param timestamp 时间戳
+ * @param nonce 随机字符串
+ * @param encrypt 密文
+ * @return 安全签名
+ * @throws AesException
+ */
+ public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws AesException
+ {
+ try {
+ String[] array = new String[] { token, timestamp, nonce, encrypt };
+ StringBuffer sb = new StringBuffer();
+ // 字符串排序
+ Arrays.sort(array);
+ for (int i = 0; i < 4; i++) {
+ sb.append(array[i]);
+ }
+ String str = sb.toString();
+ // SHA1签名生成
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ md.update(str.getBytes());
+ byte[] digest = md.digest();
+
+ StringBuffer hexstr = new StringBuffer();
+ String shaHex = "";
+ for (int i = 0; i < digest.length; i++) {
+ shaHex = Integer.toHexString(digest[i] & 0xFF);
+ if (shaHex.length() < 2) {
+ hexstr.append(0);
+ }
+ hexstr.append(shaHex);
+ }
+ return hexstr.toString();
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AesException(AesException.ComputeSignatureError);
+ }
+ }
+}
diff --git a/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/WXBizMsgCrypt.java b/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/WXBizMsgCrypt.java
new file mode 100644
index 00000000..e2ca2d61
--- /dev/null
+++ b/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/WXBizMsgCrypt.java
@@ -0,0 +1,288 @@
+/**
+ * 对公众平台发送给公众账号的消息加解密示例代码.
+ *
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * 针对org.apache.commons.codec.binary.Base64,
+ * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本)
+ * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi
+ */
+package com.yxt.supervise.report.aes;
+
+import org.apache.commons.codec.binary.Base64;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Random;
+
+/**
+ * 提供接收和推送给公众平台消息的加解密接口(UTF8编码的字符串).
+ *
+ * - 第三方回复加密消息给公众平台
+ * - 第三方收到公众平台发送的消息,验证消息的安全性,并对消息进行解密。
+ *
+ * 说明:异常java.security.InvalidKeyException:illegal Key Size的解决方案
+ *
+ * - 在官方网站下载JCE无限制权限策略文件(JDK7的下载地址:
+ * http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
+ * - 下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt
+ * - 如果安装了JRE,将两个jar文件放到%JRE_HOME%\lib\security目录下覆盖原来的文件
+ * - 如果安装了JDK,将两个jar文件放到%JDK_HOME%\jre\lib\security目录下覆盖原来文件
+ *
+ */
+public class WXBizMsgCrypt {
+ static Charset CHARSET = Charset.forName("utf-8");
+ Base64 base64 = new Base64();
+ byte[] aesKey;
+ String token;
+ String appId;
+
+ /**
+ * 构造函数
+ * @param token 公众平台上,开发者设置的token
+ * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey
+ * @param appId 公众平台appid
+ *
+ * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
+ */
+ public WXBizMsgCrypt(String token, String encodingAesKey, String appId) throws AesException {
+ if (encodingAesKey.length() != 43) {
+ throw new AesException(AesException.IllegalAesKey);
+ }
+
+ this.token = token;
+ this.appId = appId;
+ aesKey = Base64.decodeBase64(encodingAesKey + "=");
+ }
+
+ // 生成4个字节的网络字节序
+ byte[] getNetworkBytesOrder(int sourceNumber) {
+ byte[] orderBytes = new byte[4];
+ orderBytes[3] = (byte) (sourceNumber & 0xFF);
+ orderBytes[2] = (byte) (sourceNumber >> 8 & 0xFF);
+ orderBytes[1] = (byte) (sourceNumber >> 16 & 0xFF);
+ orderBytes[0] = (byte) (sourceNumber >> 24 & 0xFF);
+ return orderBytes;
+ }
+
+ // 还原4个字节的网络字节序
+ int recoverNetworkBytesOrder(byte[] orderBytes) {
+ int sourceNumber = 0;
+ for (int i = 0; i < 4; i++) {
+ sourceNumber <<= 8;
+ sourceNumber |= orderBytes[i] & 0xff;
+ }
+ return sourceNumber;
+ }
+
+ // 随机生成16位字符串
+ String getRandomStr() {
+ String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+ Random random = new Random();
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < 16; i++) {
+ int number = random.nextInt(base.length());
+ sb.append(base.charAt(number));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * 对明文进行加密.
+ *
+ * @param text 需要加密的明文
+ * @return 加密后base64编码的字符串
+ * @throws AesException aes加密失败
+ */
+ String encrypt(String randomStr, String text) throws AesException {
+ ByteGroup byteCollector = new ByteGroup();
+ byte[] randomStrBytes = randomStr.getBytes(CHARSET);
+ byte[] textBytes = text.getBytes(CHARSET);
+ byte[] networkBytesOrder = getNetworkBytesOrder(textBytes.length);
+ byte[] appidBytes = appId.getBytes(CHARSET);
+
+ // randomStr + networkBytesOrder + text + appid
+ byteCollector.addBytes(randomStrBytes);
+ byteCollector.addBytes(networkBytesOrder);
+ byteCollector.addBytes(textBytes);
+ byteCollector.addBytes(appidBytes);
+
+ // ... + pad: 使用自定义的填充方式对明文进行补位填充
+ byte[] padBytes = PKCS7Encoder.encode(byteCollector.size());
+ byteCollector.addBytes(padBytes);
+
+ // 获得最终的字节流, 未加密
+ byte[] unencrypted = byteCollector.toBytes();
+
+ try {
+ // 设置加密模式为AES的CBC模式
+ Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
+ SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
+ IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);
+ cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
+
+ // 加密
+ byte[] encrypted = cipher.doFinal(unencrypted);
+
+ // 使用BASE64对加密后的字符串进行编码
+ String base64Encrypted = base64.encodeToString(encrypted);
+
+ return base64Encrypted;
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AesException(AesException.EncryptAESError);
+ }
+ }
+
+ /**
+ * 对密文进行解密.
+ *
+ * @param text 需要解密的密文
+ * @return 解密得到的明文
+ * @throws AesException aes解密失败
+ */
+ String decrypt(String text) throws AesException {
+ byte[] original;
+ try {
+ // 设置解密模式为AES的CBC模式
+ Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
+ SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES");
+ IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
+ cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);
+
+ // 使用BASE64对密文进行解码
+ byte[] encrypted = Base64.decodeBase64(text);
+
+ // 解密
+ original = cipher.doFinal(encrypted);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AesException(AesException.DecryptAESError);
+ }
+
+ String xmlContent, from_appid;
+ try {
+ // 去除补位字符
+ byte[] bytes = PKCS7Encoder.decode(original);
+
+ // 分离16位随机字符串,网络字节序和AppId
+ byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);
+
+ int xmlLength = recoverNetworkBytesOrder(networkOrder);
+
+ xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
+ from_appid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length),
+ CHARSET);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AesException(AesException.IllegalBuffer);
+ }
+
+ // appid不相同的情况
+ if (!from_appid.equals(appId)) {
+ throw new AesException(AesException.ValidateAppidError);
+ }
+ return xmlContent;
+
+ }
+
+ /**
+ * 将公众平台回复用户的消息加密打包.
+ *
+ * - 对要发送的消息进行AES-CBC加密
+ * - 生成安全签名
+ * - 将消息密文和安全签名打包成xml格式
+ *
+ *
+ * @param replyMsg 公众平台待回复用户的消息,xml格式的字符串
+ * @param timeStamp 时间戳,可以自己生成,也可以用URL参数的timestamp
+ * @param nonce 随机串,可以自己生成,也可以用URL参数的nonce
+ *
+ * @return 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串
+ * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
+ */
+ public String encryptMsg(String replyMsg, String timeStamp, String nonce) throws AesException {
+ // 加密
+ String encrypt = encrypt(getRandomStr(), replyMsg);
+
+ // 生成安全签名
+ if (timeStamp == "") {
+ timeStamp = Long.toString(System.currentTimeMillis());
+ }
+
+ String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt);
+
+ // System.out.println("发送给平台的签名是: " + signature[1].toString());
+ // 生成发送的xml
+ String result = XMLParse.generate(encrypt, signature, timeStamp, nonce);
+ return result;
+ }
+
+ /**
+ * 检验消息的真实性,并且获取解密后的明文.
+ *
+ * - 利用收到的密文生成安全签名,进行签名验证
+ * - 若验证通过,则提取xml中的加密消息
+ * - 对消息进行解密
+ *
+ *
+ * @param msgSignature 签名串,对应URL参数的msg_signature
+ * @param timeStamp 时间戳,对应URL参数的timestamp
+ * @param nonce 随机串,对应URL参数的nonce
+ * @param postData 密文,对应POST请求的数据
+ *
+ * @return 解密后的原文
+ * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
+ */
+ public String decryptMsg(String msgSignature, String timeStamp, String nonce, String postData)
+ throws AesException {
+
+ // 密钥,公众账号的app secret
+ // 提取密文
+ Object[] encrypt = XMLParse.extract(postData);
+
+ // 验证安全签名
+ String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt[1].toString());
+
+ // 和URL中的签名比较是否相等
+ // System.out.println("第三方收到URL中的签名:" + msg_sign);
+ // System.out.println("第三方校验签名:" + signature);
+ if (!signature.equals(msgSignature)) {
+ throw new AesException(AesException.ValidateSignatureError);
+ }
+
+ // 解密
+ String result = decrypt(encrypt[1].toString());
+ return result;
+ }
+
+ /**
+ * 验证URL
+ * @param msgSignature 签名串,对应URL参数的msg_signature
+ * @param timeStamp 时间戳,对应URL参数的timestamp
+ * @param nonce 随机串,对应URL参数的nonce
+ * @param echoStr 随机串,对应URL参数的echostr
+ *
+ * @return 解密之后的echostr
+ * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
+ */
+ public String verifyUrl(String msgSignature, String timeStamp, String nonce, String echoStr)
+ throws AesException {
+ String signature = SHA1.getSHA1(token, timeStamp, nonce, echoStr);
+
+ if (!signature.equals(msgSignature)) {
+ throw new AesException(AesException.ValidateSignatureError);
+ }
+
+ String result = decrypt(echoStr);
+ return result;
+ }
+
+}
\ No newline at end of file
diff --git a/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/WXBizMsgCryptTest.java b/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/WXBizMsgCryptTest.java
new file mode 100644
index 00000000..50532c93
--- /dev/null
+++ b/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/WXBizMsgCryptTest.java
@@ -0,0 +1,148 @@
+package com.yxt.supervise.report.aes;
+
+import org.junit.*;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.io.StringReader;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class WXBizMsgCryptTest {
+ String encodingAesKey = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG";
+ String token = "pamtest";
+ String timestamp = "1409304348";
+ String nonce = "xxxxxx";
+ String appId = "wxb11529c136998cb6";
+ String replyMsg = "我是中文abcd123";
+ String xmlFormat = "";
+ String afterAesEncrypt = "jn1L23DB+6ELqJ+6bruv21Y6MD7KeIfP82D6gU39rmkgczbWwt5+3bnyg5K55bgVtVzd832WzZGMhkP72vVOfg==";
+ String randomStr = "aaaabbbbccccdddd";
+
+ String replyMsg2 = "1407743423";
+ String afterAesEncrypt2 = "jn1L23DB+6ELqJ+6bruv23M2GmYfkv0xBh2h+XTBOKVKcgDFHle6gqcZ1cZrk3e1qjPQ1F4RsLWzQRG9udbKWesxlkupqcEcW7ZQweImX9+wLMa0GaUzpkycA8+IamDBxn5loLgZpnS7fVAbExOkK5DYHBmv5tptA9tklE/fTIILHR8HLXa5nQvFb3tYPKAlHF3rtTeayNf0QuM+UW/wM9enGIDIJHF7CLHiDNAYxr+r+OrJCmPQyTy8cVWlu9iSvOHPT/77bZqJucQHQ04sq7KZI27OcqpQNSto2OdHCoTccjggX5Z9Mma0nMJBU+jLKJ38YB1fBIz+vBzsYjrTmFQ44YfeEuZ+xRTQwr92vhA9OxchWVINGC50qE/6lmkwWTwGX9wtQpsJKhP+oS7rvTY8+VdzETdfakjkwQ5/Xka042OlUb1/slTwo4RscuQ+RdxSGvDahxAJ6+EAjLt9d8igHngxIbf6YyqqROxuxqIeIch3CssH/LqRs+iAcILvApYZckqmA7FNERspKA5f8GoJ9sv8xmGvZ9Yrf57cExWtnX8aCMMaBropU/1k+hKP5LVdzbWCG0hGwx/dQudYR/eXp3P0XxjlFiy+9DMlaFExWUZQDajPkdPrEeOwofJb";
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() throws Exception {
+
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void testNormal() throws ParserConfigurationException, SAXException, IOException {
+ try {
+ WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId);
+ String afterEncrpt = pc.encryptMsg(replyMsg, timestamp, nonce);
+
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ StringReader sr = new StringReader(afterEncrpt);
+ InputSource is = new InputSource(sr);
+ Document document = db.parse(is);
+
+ Element root = document.getDocumentElement();
+ NodeList nodelist1 = root.getElementsByTagName("Encrypt");
+ NodeList nodelist2 = root.getElementsByTagName("MsgSignature");
+
+ String encrypt = nodelist1.item(0).getTextContent();
+ String msgSignature = nodelist2.item(0).getTextContent();
+ String fromXML = String.format(xmlFormat, encrypt);
+
+ // 第三方收到公众号平台发送的消息
+ String afterDecrpt = pc.decryptMsg(msgSignature, timestamp, nonce, fromXML);
+ assertEquals(replyMsg, afterDecrpt);
+ } catch (AesException e) {
+ fail("正常流程,怎么就抛出异常了??????");
+ }
+ }
+
+ @Test
+ public void testAesEncrypt() {
+ try {
+ WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId);
+ assertEquals(afterAesEncrypt, pc.encrypt(randomStr, replyMsg));
+ } catch (AesException e) {
+ e.printStackTrace();
+ fail("no异常");
+ }
+ }
+
+ @Test
+ public void testAesEncrypt2() {
+ try {
+ WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId);
+ assertEquals(afterAesEncrypt2, pc.encrypt(randomStr, replyMsg2));
+
+ } catch (AesException e) {
+ e.printStackTrace();
+ fail("no异常");
+ }
+ }
+
+ @Test
+ public void testIllegalAesKey() {
+ try {
+ new WXBizMsgCrypt(token, "abcde", appId);
+ } catch (AesException e) {
+ assertEquals(AesException.IllegalAesKey, e.getCode());
+ return;
+ }
+ fail("错误流程不抛出异常???");
+ }
+
+ @Test
+ public void testValidateSignatureError() throws ParserConfigurationException, SAXException,
+ IOException {
+ try {
+ WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId);
+ String afterEncrpt = pc.encryptMsg(replyMsg, timestamp, nonce);
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ StringReader sr = new StringReader(afterEncrpt);
+ InputSource is = new InputSource(sr);
+ Document document = db.parse(is);
+
+ Element root = document.getDocumentElement();
+ NodeList nodelist1 = root.getElementsByTagName("Encrypt");
+
+ String encrypt = nodelist1.item(0).getTextContent();
+ String fromXML = String.format(xmlFormat, encrypt);
+ pc.decryptMsg("12345", timestamp, nonce, fromXML); // 这里签名错误
+ } catch (AesException e) {
+ assertEquals(AesException.ValidateSignatureError, e.getCode());
+ return;
+ }
+ fail("错误流程不抛出异常???");
+ }
+
+ @Test
+ public void testVerifyUrl() throws AesException {
+ WXBizMsgCrypt wxcpt = new WXBizMsgCrypt("QDG6eK",
+ "jWmYm7qr5nMoAUwZRjGtBxmz3KA1tkAj3ykkR6q2B2C", "wx5823bf96d3bd56c7");
+ String verifyMsgSig = "5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3";
+ String timeStamp = "1409659589";
+ String nonce = "263014780";
+ String echoStr = "P9nAzCzyDtyTWESHep1vC5X9xho/qYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp+4RPcs8TgAE7OaBO+FZXvnaqQ==";
+ wxcpt.verifyUrl(verifyMsgSig, timeStamp, nonce, echoStr);
+ // 只要不抛出异常就好
+ }
+}
diff --git a/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/XMLParse.java b/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/XMLParse.java
new file mode 100644
index 00000000..533fbbfd
--- /dev/null
+++ b/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/aes/XMLParse.java
@@ -0,0 +1,71 @@
+/**
+ * 对公众平台发送给公众账号的消息加解密示例代码.
+ *
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+// ------------------------------------------------------------------------
+
+package com.yxt.supervise.report.aes;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.StringReader;
+
+/**
+ * XMLParse class
+ *
+ * 提供提取消息格式中的密文及生成回复消息格式的接口.
+ */
+class XMLParse {
+
+ /**
+ * 提取出xml数据包中的加密消息
+ * @param xmltext 待提取的xml字符串
+ * @return 提取出的加密消息字符串
+ * @throws AesException
+ */
+ public static Object[] extract(String xmltext) throws AesException {
+ Object[] result = new Object[3];
+ try {
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ StringReader sr = new StringReader(xmltext);
+ InputSource is = new InputSource(sr);
+ Document document = db.parse(is);
+
+ Element root = document.getDocumentElement();
+ NodeList nodelist1 = root.getElementsByTagName("Encrypt");
+ NodeList nodelist2 = root.getElementsByTagName("ToUserName");
+ result[0] = 0;
+ result[1] = nodelist1.item(0).getTextContent();
+ result[2] = nodelist2.item(0).getTextContent();
+ return result;
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AesException(AesException.ParseXmlError);
+ }
+ }
+
+ /**
+ * 生成xml消息
+ * @param encrypt 加密后的消息密文
+ * @param signature 安全签名
+ * @param timestamp 时间戳
+ * @param nonce 随机字符串
+ * @return 生成的xml字符串
+ */
+ public static String generate(String encrypt, String signature, String timestamp, String nonce) {
+
+ String format = "\n" + "\n"
+ + "\n"
+ + "%3$s\n" + "\n" + "";
+ return String.format(format, encrypt, signature, timestamp, nonce);
+
+ }
+}
diff --git a/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/biz/csmcashreport/CsmCashReportRest.java b/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/biz/csmcashreport/CsmCashReportRest.java
index 61fb1874..cd3fa110 100644
--- a/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/biz/csmcashreport/CsmCashReportRest.java
+++ b/yxt_supervise/supervise-report/supervise-report-biz/src/main/java/com/yxt/supervise/report/biz/csmcashreport/CsmCashReportRest.java
@@ -1,9 +1,11 @@
package com.yxt.supervise.report.biz.csmcashreport;
import cn.afterturn.easypoi.word.WordExportUtil;
+import cn.hutool.core.thread.ThreadUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yxt.common.core.result.ResultBean;
import com.yxt.supervise.report.api.csmcashlog.CsmCashLog;
+import com.yxt.supervise.report.api.csmcashreport.CsmCashReport;
import com.yxt.supervise.report.api.csmcashreport.CsmCashReportDto;
import com.yxt.supervise.report.api.csmcashreport.CsmCashReportQuery;
import com.yxt.supervise.report.api.csmcashreport.CsmCashReportVo;
@@ -13,6 +15,7 @@ import com.yxt.supervise.report.api.reportsalesdaystore.ReportSalesDayStoreDto;
import com.yxt.supervise.report.biz.csmcashlog.CsmCashLogService;
import com.yxt.supervise.report.biz.csmcashreportcashedtoday.CsmCashReportCashedTodayService;
import com.yxt.supervise.report.biz.csmcashreportsalesyesterday.CsmCashReportSalesYesterdayService;
+import com.yxt.supervise.report.biz.wechat.WechatRest;
import io.swagger.annotations.Api;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.junit.Test;
@@ -44,6 +47,8 @@ public class CsmCashReportRest {
CsmCashReportSalesYesterdayService csmCashReportSalesYesterdayService;
@Autowired
CsmCashLogService csmCashLogService;
+ @Autowired
+ WechatRest wechatRest;
private static final String TEMPLATE_FILE_NAME="C:\\Users\\www19\\Desktop\\每日回款审核报告模版.docx";
@Value("${image.upload.path:static/upload/}")
@@ -84,28 +89,27 @@ public class CsmCashReportRest {
Map params =csmCashReportService.getCsmReport(dataDate);
List