diff --git a/nursing-unit-admin/nu-admin-biz/pom.xml b/nursing-unit-admin/nu-admin-biz/pom.xml
index d76ec65..60bf3dd 100644
--- a/nursing-unit-admin/nu-admin-biz/pom.xml
+++ b/nursing-unit-admin/nu-admin-biz/pom.xml
@@ -10,6 +10,17 @@
nu-admin-biz
+
+
+ com.github.wechatpay-apiv3
+ wechatpay-apache-httpclient
+ 0.4.9
+
+
+ com.github.wxpay
+ wxpay-sdk
+ 0.0.3
+
com.nursingunit.boot
nu-admin-local-api
diff --git a/nursing-unit-admin/nu-admin-biz/src/main/java/com/nu/modules/wechart/controller/WechatPay2Controller.java b/nursing-unit-admin/nu-admin-biz/src/main/java/com/nu/modules/wechart/controller/WechatPay2Controller.java
new file mode 100644
index 0000000..f635384
--- /dev/null
+++ b/nursing-unit-admin/nu-admin-biz/src/main/java/com/nu/modules/wechart/controller/WechatPay2Controller.java
@@ -0,0 +1,76 @@
+package com.nu.modules.wechart.controller;
+
+
+import cn.hutool.core.util.IdUtil;
+import com.github.wxpay.sdk.WXPay;
+import com.github.wxpay.sdk.WXPayConstants;
+import com.github.wxpay.sdk.WXPayUtil;
+import com.nu.modules.wechart.entity.WXConfig;
+import com.nu.modules.wechart.entity.WechatpayConfig;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/weiXinPay2")
+@Slf4j
+public class WechatPay2Controller {
+ @Autowired
+ public WechatpayConfig wechatpayConfig;
+
+
+ /**
+ * Native下单
+ * 调用统一下单API,生成支付二维码
+ */
+ @PostMapping("/native")
+ public Map nativePay() throws Exception {
+ log.info("生成订单");
+ //生成订单
+ log.info("存入数据库...");
+
+ log.info("调用统一下单API");
+ // 订单号
+ String orderNo = IdUtil.simpleUUID();
+ // 请求body参数 看官方文档
+ WXConfig config = new WXConfig();
+ config.setAppId(wechatpayConfig.getAppid());
+ config.setMchId(wechatpayConfig.getMchId());
+ config.setKey(wechatpayConfig.getApiV3Key());
+
+ Map paramsMap = new HashMap<>();
+ paramsMap.put("appid", wechatpayConfig.getAppid());
+ paramsMap.put("mchid", wechatpayConfig.getMchId());
+ paramsMap.put("description", "iPhone 15 Pro Max 5G");
+ paramsMap.put("out_trade_no", orderNo);
+ // 回调的地址
+ paramsMap.put("notify_url",wechatpayConfig.getNotifyDomain()+"/native/notify");
+
+ Map amountMap = new HashMap();
+ //订单总金额,单位为分。
+ amountMap.put("total", 1);
+ //CNY:人民币,境内商户号仅支持人民币。
+ amountMap.put("currency", "CNY");
+ paramsMap.put("total_fee", 1+"");
+ paramsMap.put("trade_type", "JSAPI");
+ String generateNonceStr = WXPayUtil.generateNonceStr();
+ paramsMap.put("nonce_str", generateNonceStr);
+ String body = "body";
+ paramsMap.put("body", body);
+ paramsMap.put("sign", WXPayUtil.generateSignature(paramsMap, wechatpayConfig.getApiV3Key(), WXPayConstants.SignType.MD5));
+
+ log.info("请求参数:" + paramsMap);
+
+
+
+ WXPay wxpay = new WXPay(config);
+ Map response = wxpay.unifiedOrder(paramsMap);
+ for (String key : response.keySet()) {
+ log.info("微信支付订单微信返回参数:keys:" + key + " value:" + response.get(key).toString());
+ }
+ return null;
+ }
+}
diff --git a/nursing-unit-admin/nu-admin-biz/src/main/java/com/nu/modules/wechart/controller/WechatPayController.java b/nursing-unit-admin/nu-admin-biz/src/main/java/com/nu/modules/wechart/controller/WechatPayController.java
new file mode 100644
index 0000000..c078de5
--- /dev/null
+++ b/nursing-unit-admin/nu-admin-biz/src/main/java/com/nu/modules/wechart/controller/WechatPayController.java
@@ -0,0 +1,345 @@
+package com.nu.modules.wechart.controller;
+
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.json.JSONUtil;
+import com.github.wxpay.sdk.WXPayUtil;
+import com.nu.modules.wechart.entity.WechatpayConfig;
+import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.util.HashMap;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/weiXinPay")
+@Slf4j
+public class WechatPayController {
+
+
+ @Resource
+ public WechatpayConfig wechatpayConfig;
+
+
+ /**
+ * Native下单
+ * 调用统一下单API,生成支付二维码
+ */
+ @PostMapping("/native")
+ public Map nativePay() throws Exception {
+ log.info("生成订单");
+ //生成订单
+ log.info("存入数据库...");
+
+ log.info("调用统一下单API");
+ //调用统一下单API
+ HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/native");
+
+ // 订单号
+ String orderNo = IdUtil.simpleUUID();
+ // 请求body参数 看官方文档
+ Map paramsMap = new HashMap();
+ paramsMap.put("appid", wechatpayConfig.getAppid());
+ paramsMap.put("mchid", wechatpayConfig.getMchId());
+ paramsMap.put("description", "iPhone 15 Pro Max 5G");
+ paramsMap.put("out_trade_no", orderNo);
+ // 回调的地址
+ paramsMap.put("notify_url",wechatpayConfig.getNotifyDomain()+"/native/notify");
+ Map amountMap = new HashMap();
+ //订单总金额,单位为分。
+ amountMap.put("total", 1);
+ //CNY:人民币,境内商户号仅支持人民币。
+ amountMap.put("currency", "CNY");
+
+ paramsMap.put("amount", amountMap);
+
+
+
+ //将参数转换成json字符串
+ String jsonParams = JSONUtil.toJsonStr(paramsMap);
+ log.info("请求参数:" + jsonParams);
+
+ StringEntity entity = new StringEntity(jsonParams,"utf-8");
+ entity.setContentType("application/json");
+ httpPost.setEntity(entity);
+ httpPost.setHeader("Accept", "application/json");
+ httpPost.setHeader("Authorization", "WECHATPAY2-SHA256-RSA2048 "+ jsonParams);
+ //创建httpclient对象
+ CloseableHttpClient wxPayClient = HttpClients.createDefault();
+ //完成签名并执行请求
+ CloseableHttpResponse response = wxPayClient.execute(httpPost);
+ try {
+ String bodyAsString = EntityUtils.toString(response.getEntity());//响应体
+ int statusCode = response.getStatusLine().getStatusCode();//响应状态码
+ if (statusCode == 200) { //处理成功
+ log.info("成功, 返回结果 = " + bodyAsString);
+ } else if (statusCode == 204) { //处理成功,无返回Body
+ log.info("成功");
+ } else {
+ log.info("Native下单失败,响应码 = " + statusCode+ ",返回结果 = " +
+ bodyAsString);
+ throw new IOException("request failed");
+ }
+ //响应结果
+ Map resultMap = JSONUtil.toBean(bodyAsString,HashMap.class);
+ //二维码
+ String codeUrl = resultMap.get("code_url");
+ Map map = new HashMap<>();
+ map.put("codeUrl", codeUrl);
+ map.put("orderNo", orderNo.toString());
+ return map;
+ } finally {
+ response.close();
+ }
+ }
+ /**
+ * 支付通知
+ * 微信支付通过支付通知接口将用户支付成功消息通知给商户
+ */
+ @PostMapping("/native/notify")
+ public Map nativeNotify(@RequestBody Map signalRes, HttpServletResponse response){
+ Map map = new HashMap<>();//应答对象
+ log.info("支付通知的完整数据 ===> {}", signalRes);
+ try {
+ //用密文解密出明文
+ Map resource=(Map)signalRes.get("resource");
+ String ciphertext=resource.get("ciphertext");
+ String associatedData=resource.get("associated_data");
+ String nonce=resource.get("nonce");
+ // 拿到明文
+ String plainText=new AesUtil(wechatpayConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8)).decryptToString(associatedData.getBytes(StandardCharsets.UTF_8),nonce.getBytes(StandardCharsets.UTF_8),ciphertext);
+ //转换
+ HashMap data= JSONUtil.toBean(plainText,HashMap.class);
+ log.info("解密后的完整数据:{}",data);
+ //处理订单
+ log.info("处理订单...");
+ //成功应答:成功应答必须为200或204,否则就是失败应答
+ response.setStatus(200);
+ map.put("code", "SUCCESS");
+ } catch (GeneralSecurityException e) {
+ response.setStatus(500);
+ map.put("code", "FAIL");
+ map.put("message","失败");
+ }
+ return map;
+ }
+ /**
+ * 查询订单
+ * @param orderNo
+ * @return
+ * @throws Exception
+ */
+ @GetMapping("/query/{orderNo}")
+ public String queryOrder(@PathVariable String orderNo) throws Exception {
+ log.info("查询订单");
+ String url = String.format("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/%s", orderNo);
+ url = url+"?mchid="+wechatpayConfig.getMchId();
+ HttpGet httpGet = new HttpGet(url);
+ httpGet.setHeader("Accept", "application/json");
+
+ //创建httpclient对象
+ CloseableHttpClient wxPayClient = HttpClients.createDefault();
+ //完成签名并执行请求
+ CloseableHttpResponse response = wxPayClient.execute(httpGet);
+ try {
+ String bodyAsString = EntityUtils.toString(response.getEntity());//响应体
+ int statusCode = response.getStatusLine().getStatusCode();//响应状态码
+ if (statusCode == 200) { //处理成功
+ log.info("成功, 返回结果 = " + bodyAsString);
+ } else if (statusCode == 204) { //处理成功,无返回Body
+ log.info("成功");
+ } else {
+ log.info("查单接口调用,响应码 = " + statusCode+ ",返回结果 = " + bodyAsString);
+ throw new IOException("request failed");
+ }
+ return bodyAsString;
+ } finally {
+ response.close();
+ }
+
+ }
+ /**
+ * 用户取消订单
+ * @param orderNo 订单id
+ */
+ @PostMapping("/cancel/{orderNo}")
+ public String cancel(@PathVariable String orderNo) throws Exception {
+ log.info("用户取消订单");
+ //创建远程请求对象
+ String url = String.format("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/%s/close", orderNo);
+ HttpPost httpPost = new HttpPost(url);
+
+ //组装json请求体
+ Map paramsMap = new HashMap<>();
+ paramsMap.put("mchid", wechatpayConfig.getMchId());
+ String jsonParams = JSONUtil.toJsonStr(paramsMap);
+ log.info("请求参数 ===> {}", jsonParams);
+
+ //将请求参数设置到请求对象中
+ StringEntity entity = new StringEntity(jsonParams,"utf-8");
+ entity.setContentType("application/json");
+ httpPost.setEntity(entity);
+ httpPost.setHeader("Accept", "application/json");
+
+ //创建httpclient对象
+ CloseableHttpClient wxPayClient = HttpClients.createDefault();
+ //完成签名并执行请求
+ CloseableHttpResponse response = wxPayClient.execute(httpPost);
+ try {
+ int statusCode = response.getStatusLine().getStatusCode();//响应状态码
+ if (statusCode == 200) { //处理成功
+ log.info("成功200");
+ } else if (statusCode == 204) { //处理成功,无返回Body
+ log.info("成功204");
+ } else {
+ log.info("Native下单失败,响应码 = " + statusCode);
+ throw new IOException("request failed");
+ }
+ return "订单取消成功";
+ } finally {
+ response.close();
+ }
+ }
+ /**
+ * 申请退款
+ * @param orderNo 订单编号
+ */
+ @PostMapping("/refunds/{orderNo}")
+ public Map refunds(@PathVariable String orderNo) throws Exception {
+
+ log.info("创建退款单记录...");
+ //根据订单编号创建退款单
+
+ log.info("调用退款API");
+
+ //调用统一下单API
+ HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds");
+
+ // 请求body参数
+ Map paramsMap = new HashMap();
+ paramsMap.put("out_trade_no", orderNo);//订单编号
+
+ // 给它一个退款单号
+ paramsMap.put("out_refund_no", "tk202412120001");//退款单编号
+ paramsMap.put("reason", "买了不发货");//退款原因
+ paramsMap.put("notify_url", wechatpayConfig.getNotifyDomain()+"/refunds/notify");//退款通知地址
+
+ Map amountMap = new HashMap();
+ amountMap.put("refund", 1);//退款金额
+ amountMap.put("total", 1);//原订单金额
+ amountMap.put("currency", "CNY");//退款币种
+ paramsMap.put("amount", amountMap);
+
+ //将参数转换成json字符串
+ String jsonParams = JSONUtil.toJsonStr(paramsMap);
+ log.info("请求参数 ===> {}" + jsonParams);
+
+ StringEntity entity = new StringEntity(jsonParams, "utf-8");
+ entity.setContentType("application/json");//设置请求报文格式
+ httpPost.setEntity(entity);//将请求报文放入请求对象
+ httpPost.setHeader("Accept", "application/json");//设置响应报文格式
+
+ //创建httpclient对象
+ CloseableHttpClient wxPayClient = HttpClients.createDefault();
+ //完成签名并执行请求,并完成验签
+ CloseableHttpResponse response = wxPayClient.execute(httpPost);
+
+ try {
+ //解析响应结果
+ String bodyAsString = EntityUtils.toString(response.getEntity());
+ int statusCode = response.getStatusLine().getStatusCode();
+ if (statusCode == 200) {
+ log.info("成功, 退款返回结果 = " + bodyAsString);
+ } else if (statusCode == 204) {
+ log.info("成功");
+ } else {
+ throw new RuntimeException("退款异常, 响应码 = " + statusCode + ", 退款返回结果 = " + bodyAsString);
+ }
+ log.info("更新订单状态......");
+ log.info("更新退款单......");
+ return JSONUtil.toBean(bodyAsString,Map.class);
+ } finally {
+ response.close();
+ }
+ }
+ /**
+ * 退款结果通知
+ * 退款状态改变后,微信会把相关退款结果发送给商户。
+ */
+ @PostMapping("/refunds/notify")
+ public String refundsNotify(@RequestBody Map signalRes, HttpServletResponse response){
+ log.info("退款通知执行");
+ Map map = new HashMap<>();//应答对象
+ try {
+ Map resource=(Map)signalRes.get("resource");
+ String ciphertext=resource.get("ciphertext");
+ String associatedData=resource.get("associated_data");
+ String nonce=resource.get("nonce");
+ // 拿到明文
+ String plainText=new AesUtil(wechatpayConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8)).decryptToString(associatedData.getBytes(StandardCharsets.UTF_8),nonce.getBytes(StandardCharsets.UTF_8),ciphertext);
+
+ //转换
+ HashMap data= JSONUtil.toBean(plainText,HashMap.class);
+ log.info("解密后的完整数据:{}",data);
+ log.info("处理退款单................................");
+ log.info("更新订单状态................................");
+
+ //成功应答
+ response.setStatus(200);
+ map.put("code", "SUCCESS");
+ map.put("message", "成功");
+ return JSONUtil.toJsonStr(map);
+ } catch (Exception e) {
+ e.printStackTrace();
+ //失败应答
+ response.setStatus(500);
+ map.put("code", "ERROR");
+ map.put("message", "失败");
+ return JSONUtil.toJsonStr(map);
+ }
+ }
+ /**
+ * 查询退款
+ * @param refundNo 退款订单
+ */
+ @GetMapping("/query-refund/{refundNo}")
+ public String queryRefund(@PathVariable String refundNo) throws Exception {
+
+ log.info("查询退款接口调用 ===> {}", refundNo);
+ String url = String.format("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/%s", refundNo);
+ //创建远程Get 请求对象
+ HttpGet httpGet = new HttpGet(url);
+ httpGet.setHeader("Accept", "application/json");
+ //创建httpclient对象
+ CloseableHttpClient wxPayClient = HttpClients.createDefault();
+ //完成签名并执行请求
+ CloseableHttpResponse response = wxPayClient.execute(httpGet);
+ try {
+ String bodyAsString = EntityUtils.toString(response.getEntity());
+ int statusCode = response.getStatusLine().getStatusCode();
+ if (statusCode == 200) {
+ log.info("成功, 查询退款返回结果 = " + bodyAsString);
+ } else if (statusCode == 204) {
+ log.info("成功");
+ } else {
+ throw new RuntimeException("查询退款异常, 响应码 = " + statusCode+ ", 查询退款返回结果 = " + bodyAsString);
+ }
+ return bodyAsString;
+ } finally {
+ response.close();
+ }
+ }
+
+}
diff --git a/nursing-unit-admin/nu-admin-biz/src/main/java/com/nu/modules/wechart/entity/WXConfig.java b/nursing-unit-admin/nu-admin-biz/src/main/java/com/nu/modules/wechart/entity/WXConfig.java
new file mode 100644
index 0000000..06224b1
--- /dev/null
+++ b/nursing-unit-admin/nu-admin-biz/src/main/java/com/nu/modules/wechart/entity/WXConfig.java
@@ -0,0 +1,89 @@
+package com.nu.modules.wechart.entity;
+
+import com.github.wxpay.sdk.WXPayConfig;
+import lombok.Data;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+/**
+ * @author fang
+ * @date 2020/2/26
+ */
+@Data
+public class WXConfig implements WXPayConfig {
+ private byte[] certData;
+
+ public String appId;
+ public String key;
+ public String mchId;
+
+ /*public WXConfigUtil() throws Exception {
+ String certPath = ClassUtils.getDefaultClassLoader().getResource("").getPath()+"/weixin/apiclient_cert.p12";//从微信商户平台下载的安全证书存放的路径
+ File file = new File(certPath);
+ InputStream certStream = new FileInputStream(file);
+ this.certData = new byte[(int) file.length()];
+ certStream.read(this.certData);
+ certStream.close();
+ }*/
+
+ public byte[] getCertData() {
+ return certData;
+ }
+
+ public void setCertData(byte[] certData) {
+ this.certData = certData;
+ }
+
+ public String getAppId() {
+ return appId;
+ }
+
+ public void setAppId(String appId) {
+ this.appId = appId;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public String getMchId() {
+ return mchId;
+ }
+
+ public void setMchId(String mchId) {
+ this.mchId = mchId;
+ }
+
+ @Override
+ public String getAppID() {
+ return this.appId;
+ }
+
+ //parnerid,商户号
+ @Override
+ public String getMchID() {
+ return this.mchId;
+ }
+
+ @Override
+ public String getKey() {
+ return this.key;
+ }
+
+ @Override
+ public InputStream getCertStream() {
+ ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
+ return certBis;
+ }
+
+ @Override
+ public int getHttpConnectTimeoutMs() {
+ return 8000;
+ }
+
+ @Override
+ public int getHttpReadTimeoutMs() {
+ return 10000;
+ }
+}
diff --git a/nursing-unit-admin/nu-admin-biz/src/main/java/com/nu/modules/wechart/entity/WechatpayConfig.java b/nursing-unit-admin/nu-admin-biz/src/main/java/com/nu/modules/wechart/entity/WechatpayConfig.java
new file mode 100644
index 0000000..00bb7b0
--- /dev/null
+++ b/nursing-unit-admin/nu-admin-biz/src/main/java/com/nu/modules/wechart/entity/WechatpayConfig.java
@@ -0,0 +1,38 @@
+package com.nu.modules.wechart.entity;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@Slf4j
+@Data
+public class WechatpayConfig {
+ // 商户ID
+ @Value("${wxpay.mch-id}")
+ private String mchId;
+
+ // 商户API证书序列号
+ @Value("${wxpay.mch-serial-no}")
+ private String mchSerialNo;
+
+ // 商户私钥文件
+ @Value("${wxpay.private-key-path}")
+ private String privateKeyPath;
+
+ // APIv3密钥
+ @Value("${wxpay.api-v3-key}")
+ private String apiV3Key;
+
+ // APPID
+ @Value("${wxpay.appid}")
+ private String appid;
+
+ // 接收结果通知地址
+ @Value("${wxpay.notify-domain}")
+ private String notifyDomain;
+
+
+
+}
diff --git a/nursing-unit-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java b/nursing-unit-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
index cbbaa42..e0937cd 100644
--- a/nursing-unit-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
+++ b/nursing-unit-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
@@ -113,6 +113,8 @@ public class ShiroConfig {
filterChainDefinitionMap.put("/sys/checkAuth", "anon"); //授权接口排除
filterChainDefinitionMap.put("/h5Api/nuBizAdvisoryInfo/**", "anon"); //授权接口排除
filterChainDefinitionMap.put("/h5Api/nuBaseInfo/**", "anon"); //授权接口排除
+ filterChainDefinitionMap.put("/weiXinPay/**", "anon"); //微信支付接口
+ filterChainDefinitionMap.put("/weiXinPay2/**", "anon"); //微信支付接口
//update-begin--Author:scott Date:20221116 for:排除静态资源后缀
filterChainDefinitionMap.put("/", "anon");
diff --git a/nursing-unit-invoicing/nu-invoicing-biz/src/main/java/com/nu/modules/ConfigMaterial/controller/ConfigMaterialCategoryController.java b/nursing-unit-invoicing/nu-invoicing-biz/src/main/java/com/nu/modules/ConfigMaterial/controller/ConfigMaterialCategoryController.java
index edf8292..5b8b39d 100644
--- a/nursing-unit-invoicing/nu-invoicing-biz/src/main/java/com/nu/modules/ConfigMaterial/controller/ConfigMaterialCategoryController.java
+++ b/nursing-unit-invoicing/nu-invoicing-biz/src/main/java/com/nu/modules/ConfigMaterial/controller/ConfigMaterialCategoryController.java
@@ -175,7 +175,6 @@ public class ConfigMaterialCategoryController extends JeecgController${commonmark.version}
-
- com.alibaba.cloud
- spring-cloud-starter-alibaba-nacos-discovery
- 2021.0.5.0
-
+
+
+
+
+
-
- com.alibaba.cloud
- spring-cloud-starter-alibaba-nacos-config
- 2021.0.5.0
-
+
+
+
+
+
org.springframework.boot