lzy 1 hafta önce
ebeveyn
işleme
1d2bb2b571

+ 39 - 22
pom.xml

@@ -38,23 +38,23 @@
             <version>0.9.0</version>
         </dependency>
 
-<!--        <dependency>-->
-<!--            <groupId>io.jsonwebtoken</groupId>-->
-<!--            <artifactId>jjwt-api</artifactId>-->
-<!--            <version>0.11.5</version>-->
-<!--        </dependency>-->
-<!--        <dependency>-->
-<!--            <groupId>io.jsonwebtoken</groupId>-->
-<!--            <artifactId>jjwt-impl</artifactId>-->
-<!--            <version>0.11.5</version>-->
-<!--            <scope>runtime</scope>-->
-<!--        </dependency>-->
-<!--        <dependency>-->
-<!--            <groupId>io.jsonwebtoken</groupId>-->
-<!--            <artifactId>jjwt-jackson</artifactId>-->
-<!--            <version>0.11.5</version>-->
-<!--            <scope>runtime</scope>-->
-<!--        </dependency>-->
+        <!--        <dependency>-->
+        <!--            <groupId>io.jsonwebtoken</groupId>-->
+        <!--            <artifactId>jjwt-api</artifactId>-->
+        <!--            <version>0.11.5</version>-->
+        <!--        </dependency>-->
+        <!--        <dependency>-->
+        <!--            <groupId>io.jsonwebtoken</groupId>-->
+        <!--            <artifactId>jjwt-impl</artifactId>-->
+        <!--            <version>0.11.5</version>-->
+        <!--            <scope>runtime</scope>-->
+        <!--        </dependency>-->
+        <!--        <dependency>-->
+        <!--            <groupId>io.jsonwebtoken</groupId>-->
+        <!--            <artifactId>jjwt-jackson</artifactId>-->
+        <!--            <version>0.11.5</version>-->
+        <!--            <scope>runtime</scope>-->
+        <!--        </dependency>-->
 
         <dependency>
             <groupId>commons-io</groupId>
@@ -68,17 +68,14 @@
         <dependency>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-lang3</artifactId>
-            <version>3.3.2</version>
+            <version>3.13.0</version>
         </dependency>
         <dependency>
             <groupId>commons-httpclient</groupId>
             <artifactId>commons-httpclient</artifactId>
             <version>3.1</version>
         </dependency>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-web</artifactId>
-        </dependency>
+
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-data-redis</artifactId>
@@ -153,6 +150,26 @@
             <artifactId>spring-boot-starter</artifactId>
         </dependency>
         <dependency>
+            <groupId>com.github.binarywang</groupId>
+            <artifactId>weixin-java-miniapp</artifactId>
+            <version>4.5.7.B</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.binarywang</groupId>
+            <artifactId>weixin-java-pay</artifactId>
+            <version>4.5.7.B</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.binarywang</groupId>
+            <artifactId>weixin-java-open</artifactId>
+            <version>4.5.7.B</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.binarywang</groupId>
+            <artifactId>weixin-java-mp</artifactId>
+            <version>4.5.7.B</version>
+        </dependency>
+        <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-configuration-processor</artifactId>
             <optional>true</optional>

+ 244 - 0
src/main/java/com/futu/course/common/utils/EraHelper.java

@@ -0,0 +1,244 @@
+package com.futu.course.common.utils;
+
+import javax.servlet.http.HttpServletRequest;
+import java.math.BigDecimal;
+import java.security.MessageDigest;
+import java.util.UUID;
+
+
+/**
+ * 项目相关帮助函数。
+ *
+ *
+ */
+public class EraHelper {
+
+
+
+	/**
+	 * 生产新的UUID。
+	 *
+	 * @return uuid
+	 */
+	public static final String newUUID() {
+		return UUID.randomUUID().toString().replaceAll("-", "");
+	}
+
+	/**
+	 * 判断银行卡号是否合法。
+	 *
+	 * @param cardNumber
+	 *            银行卡号
+	 * @return boolean 表示合法
+	 */
+	public static final boolean isBankCard(String cardNumber) {
+		if (cardNumber == null || cardNumber.isEmpty() || cardNumber.length() <= 2) {
+			return false;
+		}
+		char[] chs = cardNumber.trim().toCharArray();
+		int luhmSum = 0;
+		for (int i = chs.length - 2, j = 0; i >= 0; i--, j++) {
+			if (!Character.isDigit(chs[i])) {
+				return false;
+			}
+			int k = chs[i] - '0';
+			if (j % 2 == 0) {
+				k *= 2;
+				k = k / 10 + k % 10;
+			}
+			luhmSum += k;
+		}
+		return ((luhmSum % 10 == 0) ? '0' : (char) ((10 - luhmSum % 10) + '0')) == chs[chs.length - 1];
+	}
+
+	/**
+	 * 获取远程请求IP
+	 *
+	 * @param request
+	 *            HTTP请求
+	 * @return String ip
+	 */
+	public static String getRemoteIP(HttpServletRequest request) {
+		String xff = request.getHeader("X-Forwarded-For");
+		if (xff != null && !xff.isEmpty()) {
+			return xff.split(", ?")[0];
+		} else {
+			return request.getRemoteAddr();
+		}
+	}
+
+	/**
+	 * 判断手机号是否合法。
+	 *
+	 * @param mobile
+	 *            手机号码
+	 * @return boolean 表示合法
+	 */
+	public static boolean isMobile(String mobile) {
+		if (mobile == null || mobile.length() != 11) {
+			return false;
+		}
+		int index = 0;
+		for (char ch : mobile.toCharArray()) {
+			if (index == 0 && ch != '1') {
+				return false;
+			}
+			if (!Character.isDigit(ch)) {
+				return false;
+			}
+			index++;
+		}
+		return true;
+	}
+
+	/**
+	 * 手机号打码
+	 *
+	 * @param mobile
+	 *            手机号码
+	 * @return String 打码后的手机号码
+	 */
+	public static String maskMobile(String mobile) {
+		StringBuilder builder = new StringBuilder();
+		builder.append(mobile, 0, 3);
+		builder.append("****").append(mobile.substring(7));
+		return builder.toString();
+	}
+
+	/**
+	 * 银行卡号打码
+	 *
+	 * @param cardNumber
+	 *            银行卡号
+	 * @return String 打码后的银行卡号
+	 */
+	public static String maskBankCard(String cardNumber) {
+		StringBuilder builder = new StringBuilder();
+		if (cardNumber.length() > 8) {
+			builder.append(cardNumber, 0, 4);
+			builder.append(" **** ").append(" **** ").append(cardNumber.substring(cardNumber.length() - 4));
+		}
+		return builder.toString();
+	}
+
+	/**
+	 * 判断短信验证码是否合法。
+	 *
+	 * @param verifyCode
+	 *            短信验证码
+	 * @return boolean 表示合法
+	 */
+	public static boolean isSMSCode(String verifyCode) {
+		if (verifyCode == null || verifyCode.length() != 4) {
+			return false;
+		}
+		for (char ch : verifyCode.toCharArray()) {
+			if (!Character.isDigit(ch)) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	/**
+	 * 转换为十六进制字符串
+	 *
+	 * @param b
+	 *            字节数组
+	 * @return String 十六进制字符串
+	 */
+	public static String byte2HexStr(byte[] b) {
+		StringBuilder sb = new StringBuilder("");
+		for (int n = 0; n < b.length; n++) {
+			String stmp = Integer.toHexString(b[n] & 0xFF);
+			sb.append((stmp.length() == 1) ? "0" + stmp : stmp);
+		}
+		return sb.toString().toUpperCase().trim();
+	}
+
+
+
+	/**
+	 * 密码等资料混淆摘要
+	 *
+	 * @param content
+	 *            待混淆内容
+	 * @return String
+	 */
+	public static String confuse(String content) {
+		if (content == null || content.isEmpty()) {
+			return null;
+		}
+		try {
+			MessageDigest md5 = MessageDigest.getInstance("MD5");
+			md5.update(content.getBytes("UTF-8"));
+			MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
+			return byte2HexStr(sha256.digest(md5.digest()));
+		} catch (Throwable e) {
+			e.printStackTrace();
+			return null;
+		}
+	}
+
+
+
+
+	private static double EARTH_RADIUS = 6378.137;// 地球半径
+
+	private static double rad(double d) {
+		return d * Math.PI / 180.0;
+	}
+
+	/**
+	 * 计算两个经纬度坐标距离.
+	 *
+	 * @param lat1
+	 * @param lng1
+	 * @param lat2
+	 * @param lng2
+	 * @return double
+	 */
+	public static BigDecimal getDistance(double lat1, double lng1, double lat2, double lng2) {
+		double radLat1 = rad(lat1);
+		double radLat2 = rad(lat2);
+		double a = radLat1 - radLat2;
+		double b = rad(lng1) - rad(lng2);
+		double s = 2 * Math.asin(Math.sqrt(
+				Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
+		s = s * EARTH_RADIUS;
+		return BigDecimal.valueOf(s).setScale(2, BigDecimal.ROUND_HALF_UP);
+	}
+
+	/**
+	 * 判断是否为微信。
+	 *
+	 * @param userAgent
+	 *            终端类型字符串
+	 * @return boolean true表示终端类型为微信
+	 */
+	public static boolean isWeiXin(String userAgent) {
+		return userAgent == null || userAgent.isEmpty() ? false : userAgent.indexOf("MicroMessenger") != -1;
+	}
+
+	/**
+	 * 判断是否为安卓。
+	 *
+	 * @param userAgent
+	 *            终端类型字符串
+	 * @return boolean true表示终端类型为安卓
+	 */
+	public static boolean isAndroid(String userAgent) {
+		return userAgent == null || userAgent.isEmpty() ? false : userAgent.indexOf("Android") != -1;
+	}
+
+	/**
+	 * 判断是否为iPhone。
+	 *
+	 * @param userAgent
+	 *            终端类型字符串
+	 * @return boolean true表示终端类型为iPhone
+	 */
+	public static boolean isIPhone(String userAgent) {
+		return userAgent == null || userAgent.isEmpty() ? false : userAgent.indexOf("iPhone") != -1;
+	}
+}

+ 356 - 0
src/main/java/com/futu/course/common/utils/PayUtil.java

@@ -0,0 +1,356 @@
+package com.futu.course.common.utils;
+
+import cn.hutool.core.util.IdUtil;
+import com.futu.course.common.vo.ResultVo;
+import com.futu.course.pay.config.WxConfigV2;
+import com.futu.course.pay.dto.CreateOrderDto;
+import com.futu.course.pay.vo.OrderWxPayVo;
+import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
+import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.WxPayService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSession;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.math.BigDecimal;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.security.MessageDigest;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+@Slf4j
+public class PayUtil {
+    public static ResultVo createOrderPreId(CreateOrderDto dto, WxPayService wxPayService) throws WxPayException {
+
+        // 订单参数
+
+        String openId = dto.getOpenId();
+        // 按业务场景填写
+        String attach = "微信支付";
+
+        String outTradeNo =dto.getOrderId().toString();
+        BigDecimal orderAmount = dto.getOrderAmount();
+        String description =dto.getDescription();
+
+        // 失效时间
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+        Long expireTime = System.currentTimeMillis() + (60 * 1000 * 15);
+        String timeExpire = format.format(expireTime) + "+08:00";
+
+        // 订单信息
+        WxPayUnifiedOrderV3Request wxPayUnifiedOrderV3Request = new WxPayUnifiedOrderV3Request();
+        wxPayUnifiedOrderV3Request.setOutTradeNo(outTradeNo);
+        wxPayUnifiedOrderV3Request.setDescription("微信支付");
+        wxPayUnifiedOrderV3Request.setTimeExpire(timeExpire);
+        wxPayUnifiedOrderV3Request.setAttach(attach);
+
+
+        wxPayUnifiedOrderV3Request.setNotifyUrl("https://mini.workervip.com/pay/notify");
+        log.info("################# 回调地址: {}", wxPayUnifiedOrderV3Request.getNotifyUrl());
+
+        // 订单金额
+        WxPayUnifiedOrderV3Request.Amount amount = new WxPayUnifiedOrderV3Request.Amount();
+        amount.setTotal(orderAmount.multiply(new BigDecimal("100")).intValue());
+        amount.setCurrency("CNY");
+        wxPayUnifiedOrderV3Request.setAmount(amount);
+
+        // 付款人员
+        WxPayUnifiedOrderV3Request.Payer payer = new WxPayUnifiedOrderV3Request.Payer();
+        payer.setOpenid(openId);
+
+        // H5平台
+        TradeTypeEnum tradeTypeEnum = TradeTypeEnum.JSAPI;
+
+//
+        System.out.println(wxPayUnifiedOrderV3Request.toString());
+        // 发起订单
+        wxPayUnifiedOrderV3Request.setPayer(payer);
+
+
+        Object obj=wxPayService.createOrderV3(tradeTypeEnum, wxPayUnifiedOrderV3Request);
+        return ResultVo.success(obj);
+
+
+    }
+
+    public static OrderWxPayVo getPreIdV2(CreateOrderDto dto,WxConfigV2 configV2){
+
+        Map map = new HashMap();
+        map.put("orderId", dto.getOrderId());
+//            map.put("payType", );
+
+        //如果没有生成支付订单去支付
+
+
+        Map<String, String> setting = new TreeMap<>();
+        String key = configV2.getApiKey();
+        setting.put("timeStamp", System.currentTimeMillis() / 1000 + "");
+        String nonceStr = IdUtil.getSnowflake().nextIdStr();
+        setting.put("nonce_str", nonceStr);
+//            setting.put("openid", "4zeWDXewwKm5vKpvBIFhS2U");
+        setting.put("openid", dto.getOpenId());
+
+        BigDecimal payMoney = dto.getOrderAmount();
+
+
+        try {
+            String getPreId= wxMiniAppPrePayId("47.240.226.34",dto.getOrderId().toString(),payMoney,setting,configV2);
+            setting.put("package", "prepay_id=" + getPreId);
+            String paySign=  getPaySign(setting,configV2);
+            OrderWxPayVo responseData=new OrderWxPayVo();
+            responseData.setAppid(configV2.getAppId());
+            responseData.setPartnerid(configV2.getMchId());
+            responseData.setPaySign(paySign);
+            responseData.setNonceStr(nonceStr);
+            responseData.setOrderId(dto.getOrderId());
+            responseData.setOrderNumber(dto.getOrderId().toString());
+            responseData.setPayAmount(payMoney.setScale(2, BigDecimal.ROUND_HALF_UP));
+            responseData.setSigntype("MD5");
+            responseData.setTimestart(setting.get("timeStamp"));
+            responseData.setPackages("prepay_id=" + getPreId);
+            return responseData;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+
+    }
+    public static String wxMiniAppPrePayId(String remoteIP, String orderNumber, BigDecimal amount,
+                                           Map<String, String> settingn,WxConfigV2 configV2) throws Exception {
+
+        Map<String, String> setting = new TreeMap<>();
+        String key = configV2.getApiKey();
+        setting.put("appid", configV2.getAppId());
+        setting.put("mch_id", configV2.getMchId());
+        setting.put("notify_url", configV2.getNotiyUrl());
+        setting.put("body",configV2.getWxBody());
+        setting.put("trade_type", "JSAPI");
+
+        setting.put("out_trade_no", orderNumber);
+        setting.put("total_fee",
+                amount.multiply(BigDecimal.valueOf(100)).setScale(0, BigDecimal.ROUND_HALF_UP).toPlainString());
+        setting.put("spbill_create_ip", remoteIP);
+        setting.put("nonce_str", settingn.get("nonce_str"));
+        setting.put("timeStamp", settingn.get("timeStamp"));
+        if (!StringUtils.isBlank(settingn.get("openid"))) {
+            setting.put("openid", settingn.get("openid"));
+        }
+//                setting.put("time_start",settingn.get("time_start"));
+//                setting.put("time_expire",settingn.get("time_expire"));
+        StringBuilder builder = new StringBuilder();
+        String sign = "";
+        {
+            // 签名
+            boolean notFirst = false;
+            for (Map.Entry<String, String> entry : setting.entrySet()) {
+                String k = entry.getKey();
+                String v = entry.getValue();
+                if (v == null || v.trim().isEmpty()) {
+                    continue;
+                }
+                if (notFirst) {
+                    builder.append('&');
+                } else {
+                    notFirst = true;
+                }
+                builder.append(k).append('=').append(v);
+            }
+            builder.append('&').append("key=").append(key);
+
+            System.out.println("vvv="+builder.toString());
+            try {
+                sign = EraHelper
+                        .byte2HexStr(MessageDigest.getInstance("MD5").digest(builder.toString().getBytes("UTF-8")));
+                log.info("sign========="+sign);
+                setting.put("sign", sign);
+                log.info(builder.toString());
+
+            } catch (Throwable e) {
+                e.printStackTrace();
+            }
+        }
+
+        // 发送请求
+        try {
+            // 生成请求内容
+            builder.setLength(0);
+            builder.append("<xml>");
+            for (Map.Entry<String, String> entry : setting.entrySet()) {
+                String k = entry.getKey();
+                String v = entry.getValue();
+                if (v == null || v.trim().isEmpty()) {
+                    continue;
+                }
+                builder.append('<').append(k).append('>');
+                builder.append("<![CDATA[").append(v).append("]]>");
+                builder.append("</").append(k).append('>');
+            }
+            builder.append("</xml>");
+
+            log.info("H5微信支付请求数据:" + builder.toString());
+
+            URL location = new URL("https://api.mch.weixin.qq.com/pay/unifiedorder");
+            HttpsURLConnection connection = (HttpsURLConnection) location.openConnection();
+            connection.setHostnameVerifier(new HostnameVerifier() {
+                @Override
+                public boolean verify(String hostname, SSLSession session) {
+                    return true;
+                }
+            });
+            connection.setRequestProperty("Connection", "Close");
+            connection.setRequestProperty("Accept-Language", "*");
+            connection.setRequestProperty("Accept-Encoding", "identity");
+            connection.setRequestProperty("User-Agent", "MYTIM-PAY-GATE");
+            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+            connection.setDoOutput(true);
+            connection.setDoInput(true);
+            connection.setUseCaches(false);
+            try (OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(), "UTF-8")) {
+                writer.write(builder.toString());
+                writer.flush();
+            }
+            builder.setLength(0);
+
+            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
+                try (InputStream inputStream = connection.getInputStream()) {
+                    String responseStr = parseResult(inputStream);
+                    log.debug("H5微信支付返回预付款id数据:" + responseStr);
+                    return responseStr;
+                }
+            } else {
+                throw new Exception("错误的响应代码:" + connection.getResponseCode());
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+
+        } catch (Throwable e) {
+            e.printStackTrace();
+
+        }
+        return null;
+    }
+    private static String parseResult(InputStream inputStream) throws Exception {
+        try {
+            Map<String, String> values = parseMap(inputStream);
+            log.info("pay-wei-xin return : " + values.toString());
+            if ("SUCCESS".equalsIgnoreCase(values.get("return_code"))
+                    && "SUCCESS".equalsIgnoreCase(values.get("result_code"))) {
+                String prepay_id = values.get("prepay_id");
+                if (prepay_id == null || prepay_id.isEmpty()) {
+                    throw new Exception("响应成功,但解析预交易单号失败");
+                }
+                return prepay_id;
+            } else {
+                if ("OUT_TRADE_NO_USED".equals(values.get("err_code"))) {
+                    throw new Exception("微信支付不支持金额修改,请选用其他方式");
+                }
+                throw new Exception(values.get("return_msg"));
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw e;
+        } catch (Throwable e) {
+
+            e.printStackTrace();
+            throw new Exception("解析响应数据失败");
+        }
+
+    }
+    public static Map<String, String> parseMap(InputStream inputStream) throws Throwable {
+
+        Map<String, String> notifies = new TreeMap<>();
+        SAXParserFactory factory = SAXParserFactory.newInstance();
+        factory.setNamespaceAware(false);
+        SAXParser parser = factory.newSAXParser();
+        Set<String> ignoreFields = new HashSet<>();
+        ignoreFields.add("xml");
+        parser.parse(inputStream, new DefaultHandler() {
+
+            String currentElem = null;
+            String value = null;
+
+            @Override
+            public void startElement(String uri, String localName, String qName, Attributes attributes)
+                    throws SAXException {
+                currentElem = qName;
+            }
+
+            @Override
+            public void endElement(String uri, String localName, String qName) throws SAXException {
+                if (ignoreFields.contains(currentElem) || currentElem == null || value == null || value.isEmpty()) {
+                    return;
+                }
+                notifies.put(currentElem, value);
+                currentElem = null;
+                value = null;
+            }
+
+            @Override
+            public void characters(char[] ch, int start, int length) throws SAXException {
+                if (ignoreFields.contains(currentElem)) {
+                    return;
+                }
+                value = new String(ch, start, length);
+            }
+        });
+        return notifies;
+    }
+
+
+
+
+    public static String getPaySign( Map<String, String> settingn,WxConfigV2 configV2)
+            throws Exception {
+        Map<String, String> setting = new TreeMap<>();
+        String key = configV2.getApiKey();
+        setting.put("appId", configV2.getAppId());
+        setting.put("timeStamp", settingn.get("timeStamp"));
+        setting.put("nonceStr", settingn.get("nonce_str"));
+        setting.put("package", settingn.get("package"));
+        setting.put("signType", "MD5");
+
+        StringBuilder builder = new StringBuilder();
+        String sign = "";
+        {
+            // 签名
+            boolean notFirst = false;
+            for (Map.Entry<String, String> entry : setting.entrySet()) {
+                String k = entry.getKey();
+                String v = entry.getValue();
+                if (v == null || v.trim().isEmpty()) {
+                    continue;
+                }
+                if (notFirst) {
+                    builder.append('&');
+                } else {
+                    notFirst = true;
+                }
+                builder.append(k).append('=').append(v);
+            }
+            builder.append('&').append("key=").append(key);
+            System.out.println("vvv="+builder.toString());
+            try {
+                sign = EraHelper
+                        .byte2HexStr(MessageDigest.getInstance("MD5").digest(builder.toString().getBytes("UTF-8")));
+                log.info("sign========="+sign);
+
+            } catch (Throwable e) {
+                e.printStackTrace();
+            }
+        }
+        // 发送请求
+
+        return sign;
+    }
+}

+ 43 - 0
src/main/java/com/futu/course/common/vo/ResultVo.java

@@ -0,0 +1,43 @@
+package com.futu.course.common.vo;
+
+import lombok.Data;
+
+@Data
+public class ResultVo<T> {
+    private Integer code;
+    private String msg;
+    private  T obj;
+    public ResultVo(Integer code, String msg) {
+        this.code=code;
+        this.msg=msg;
+    }
+    public ResultVo() {}
+    public static ResultVo success(Object object) {
+        ResultVo resultVO = new ResultVo(200,"成功");
+        resultVO.setObj(object);
+        return resultVO;
+    }
+
+    public static ResultVo success() {
+        return success(null);
+    }
+    public static ResultVo error(Integer code, String msg) {
+        ResultVo resultVO = new ResultVo();
+        resultVO.setCode(code);
+        resultVO.setMsg(msg);
+        return resultVO;
+    }
+    public static ResultVo error(){
+        ResultVo resultVO=new ResultVo();
+        resultVO.setCode(0);
+        resultVO.setMsg("失败");
+        return resultVO;
+    }
+    public static ResultVo error(Integer code,String msg,Object obj){
+        ResultVo resultVO=new ResultVo();
+        resultVO.setCode(0);
+        resultVO.setMsg(msg);
+        resultVO.setObj(obj);
+        return resultVO;
+    }
+}

+ 28 - 0
src/main/java/com/futu/course/pay/config/WxConfig.java

@@ -0,0 +1,28 @@
+package com.futu.course.pay.config;
+
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class WxConfig {
+    @Bean
+    public WxPayService getWxPayService(){
+        WxPayService wxPayService=new WxPayServiceImpl();
+        WxPayConfig payConfig = new WxPayConfig();
+        payConfig.setAppId("wxdaab98514493ac69");
+        payConfig.setMchId("1616232347");
+        payConfig.setMchKey("ztatvgto6jtpetxtebrs0bmwd86ybugo");
+        payConfig.setApiV3Key("ztatvgto6jtpetxtebrs0bmwd86ybugo");
+        payConfig.setKeyPath("classpath:apiclient_cert.p12"); // API证书路径,退款等接口需要
+        payConfig.setPrivateKeyPath("classpath:apiclient_cert.p12");
+        // 以下是可选配置
+        payConfig.setNotifyUrl("https://mini.workervip.com/pay/notify");
+        payConfig.setTradeType("JSAPI"); // 交易类型,如JSAPI、NATIVE等
+
+        wxPayService.setConfig(payConfig);
+        return wxPayService;
+    }
+}

+ 21 - 0
src/main/java/com/futu/course/pay/config/WxConfigV2.java

@@ -0,0 +1,21 @@
+package com.futu.course.pay.config;
+
+import lombok.Data;
+
+@Data
+public class WxConfigV2 {
+    //    private String appId="wxc8a6a80ca6808238";
+    private String appId="wx28259a006c4eb246";
+    private String mchId="1628726718";
+//    private String mchId="1516562401";
+
+    private String notiyUrl="https://mini.workervip.com/pay/notify";
+
+    private String apiKey="7f633cbfbd892b4d256bc6edffe3b089";
+
+    private String wxBody="futu";
+
+    private String wxPackage="Sign=WXPay";
+    // openCertPath: /data/cert/
+    // certFileName: apiclient_cert.p12
+}

+ 35 - 0
src/main/java/com/futu/course/pay/controller/PayController.java

@@ -0,0 +1,35 @@
+package com.futu.course.pay.controller;
+
+import com.futu.course.common.annotation.NonLoginRequired;
+import com.futu.course.common.utils.PayUtil;
+import com.futu.course.common.vo.ResultVo;
+import com.futu.course.pay.config.WxConfigV2;
+import com.futu.course.pay.dto.CreateOrderDto;
+import com.futu.course.pay.vo.OrderWxPayVo;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.WxPayService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("pay")
+public class PayController {
+
+
+  @Autowired
+    private WxPayService wxService;
+
+
+
+   @NonLoginRequired
+  @GetMapping("/getPreId")
+    public ResultVo getPreId(@RequestBody CreateOrderDto dto) throws WxPayException {
+     WxConfigV2 wxConfigV2 = new WxConfigV2();
+     OrderWxPayVo preIdV2 = PayUtil.getPreIdV2(dto, wxConfigV2);
+     System.out.println(preIdV2);
+    return null;
+  }
+}

+ 14 - 0
src/main/java/com/futu/course/pay/dto/CreateOrderDto.java

@@ -0,0 +1,14 @@
+package com.futu.course.pay.dto;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+@Data
+public class CreateOrderDto {
+
+   private String openId;
+   private Long  orderId;
+   private String Description;
+   private BigDecimal orderAmount;
+
+}

+ 34 - 0
src/main/java/com/futu/course/pay/vo/OrderWxPayVo.java

@@ -0,0 +1,34 @@
+package com.futu.course.pay.vo;
+
+import lombok.Data;
+import org.springframework.stereotype.Component;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Component
+@Data
+public class OrderWxPayVo implements Serializable {
+
+    private Long orderId;
+
+    private String orderNumber;
+
+    private BigDecimal payAmount;
+
+    private String appid;
+
+    private String partnerid;
+
+    private String paySign;
+
+    private String nonceStr;
+
+    private String packages;
+
+    private String timestart;
+
+    private String signtype;
+
+}
+

BIN
src/main/resources/apiclient_cert.p12