微信原生支付方式二(实现一)

1.maven引用:

<dependency>
    <groupId>org.jdom</groupId>
    <artifactId>jdom2</artifactId>
    <version>2.0.6</version>
</dependency>

2.配置文件(application.yml)

wx:
  api_key: *** #生成签名信息
  appid: *** #公众账号ID
  mch_id: *** #商户号
  notify_url: 外网访问的回调地址

3.工具类实现文件

package com.common.util.weChat;

import java.security.MessageDigest;

/**
 * @Author FangYN
 * @Date 2020/6/29 9:16
 * @Description MD5工具类
 **/
public class MD5Util {
    private static String byteArrayToHexString(byte b[]) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++)
            resultSb.append(byteToHexString(b[i]));

        return resultSb.toString();
    }

    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0)
            n += 256;
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    public static String MD5Encode(String origin, String charsetname) {
        String resultString = null;
        try {
            resultString = new String(origin);
            MessageDigest md = MessageDigest.getInstance("MD5");
            if (charsetname == null || "".equals(charsetname))
                resultString = byteArrayToHexString(md.digest(resultString
                        .getBytes()));
            else
                resultString = byteArrayToHexString(md.digest(resultString
                        .getBytes(charsetname)));
        } catch (Exception exception) {
        }
        return resultString;
    }

    private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
}
package com.common.util;

import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Pattern;

/**
 * @Author FangYN
 * @Date 2020/6/29 9:32
 * @Description 时间工具类
 **/
public class DateUtil {

    // 格式:年-月-日 小时:分钟:秒
    public static final String FORMAT_ONE = "yyyy-MM-dd HH:mm:ss";
    // 格式:年-月-日 小时:分钟
    public static final String FORMAT_TWO = "yyyy-MM-dd HH:mm";
    // 格式:年月日 小时分钟秒
    public static final String FORMAT_THREE = "yyyyMMdd-HHmmss";
    // 格式:年月日
    public static final String FORMAT_FOUR = "yyyyMMdd";
    // 格式:年-月-日
    public static final String LONG_DATE_FORMAT = "yyyy-MM-dd";
    // 格式:月-日
    public static final String SHORT_DATE_FORMAT = "MM-dd";
    // 格式:小时:分钟:秒
    public static final String LONG_TIME_FORMAT = "HH:mm:ss";
    //格式:年-月
    public static final String MONTH_DATE_FORMAT = "yyyy-MM";
    // 年的加减
    public static final int SUB_YEAR = Calendar.YEAR;
    // 月加减
    public static final int SUB_MONTH = Calendar.MONTH;
    // 天的加减
    public static final int SUB_DAY = Calendar.DATE;
    // 小时的加减
    public static final int SUB_HOUR = Calendar.HOUR;
    // 分钟的加减
    public static final int SUB_MINUTE = Calendar.MINUTE;
    // 秒的加减
    public static final int SUB_SECOND = Calendar.SECOND;

    static final String dayNames[] = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};

    public DateUtil() {
    }

    public static LocalDateTime dateToLocalDateTime(Date date){
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), zoneId);
        return localDateTime;
    }

    /**
     * 把符合日期格式的字符串转换为日期类型
     */
    public static Date stringToDate(String dateStr, String formatStr) {
        Date d = null;
        SimpleDateFormat format = new SimpleDateFormat(formatStr);
        try {
            format.setLenient(false);
            d = format.parse(dateStr);
        } catch (Exception e) {
            d = null;
        }
        return d;
    }

    /**
     * 把符合日期格式的字符串转换为日期类型
     */
    public static Date stringToDate(String dateStr, String formatStr, ParsePosition pos) {
        Date d = null;
        SimpleDateFormat format = new SimpleDateFormat(formatStr);
        try {
            format.setLenient(false);
            d = format.parse(dateStr, pos);
        } catch (Exception e) {
            d = null;
        }
        return d;
    }

    /**
     * 把日期转换为字符串
     */
    public static String dateToString(Date date, String formatStr) {
        String result = "";
        SimpleDateFormat format = new SimpleDateFormat(formatStr);
        try {
            result = format.format(date);
        } catch (Exception e) {
            // log.error(e);
        }
        return result;
    }

    /**
     * 获取当前时间的指定格式
     */
    public static String getCurrDate(String format) {
        return dateToString(new Date(), format);
    }

    /**
     * @param dateKind 例:Calendar.DAY_OF_MONTH
     * @param dateStr  指定日期
     * @param amount   增加(减去)的时间量
     * @return String
     * @Title dateSub
     * @Date 2014-1-9 上午10:44:02
     * @Description 得到指定日期前(后)的日期
     */
    public static String dateSub(int dateKind, String dateStr, int amount) {
        Date date = stringToDate(dateStr, MONTH_DATE_FORMAT);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(dateKind, amount);
        return dateToString(calendar.getTime(), FORMAT_ONE);
    }

    /**
     * @return 昨日日期
     */
    public static String yesterdayDate(String dateStr) {
        Date date = stringToDate(dateStr, LONG_DATE_FORMAT);//取时间
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(SUB_DAY, -1);//把日期往后增加一天.整数往后推,负数往前移动
        //date=calendar.getTime();  //这个时间就是日期往后推一天的结果
        return dateToString(calendar.getTime(), LONG_DATE_FORMAT);
    }

    /**
     * @return 相减得到的秒数 (两个日期相减)
     */
    public static long timeSub(String firstTime, String secTime) {
        long first = stringToDate(firstTime, FORMAT_ONE).getTime();
        long second = stringToDate(secTime, FORMAT_ONE).getTime();
        return (second - first) / 1000;
    }

    /**
     * 两个日期相减
     * 参数地DATE
     * second 两个日期相差的秒
     *
     * @return 相减得到的秒数
     * 后面时间减去前面时间 再减去 相差秒数  如果大于0 返回 FASLE
     */
    public static boolean timeSub(Date firstTime, Date secTime, long secs) {
        long first = firstTime.getTime();
        long second = secTime.getTime();
        // 判断两个时间 是否间隔那么长 secs。
        return (second - first - secs) <= 0;
    }

    /**
     * 两个日期相减
     * 参数地DATE
     *
     * @return 相减得到的秒数
     * 后面时间减去前面时间 如果大于0 返回 false
     */
    public static boolean timeSub(Date firstTime, Date secTime) {
        long first = firstTime.getTime();
        long second = secTime.getTime();
        return (second - first) <= 0;
    }

    /**
     * 获得某月的天数
     */
    public static int getDaysOfMonth(String year, String month) {
        int days;
        if (month.equals("1") || month.equals("3") || month.equals("5")
                || month.equals("7") || month.equals("8") || month.equals("10")
                || month.equals("12")) {
            days = 31;
        } else if (month.equals("4") || month.equals("6") || month.equals("9")
                || month.equals("11")) {
            days = 30;
        } else {
            if ((Integer.parseInt(year) % 4 == 0 && Integer.parseInt(year) % 100 != 0)
                    || Integer.parseInt(year) % 400 == 0) {
                days = 29;
            } else {
                days = 28;
            }
        }

        return days;
    }

    /**
     * 获取某年某月的天数
     */
    public static int getDaysOfMonth(int year, int month) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month - 1, 1);
        return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
    }

    /**
     * 获得当前日期
     */
    public static int getToday() {
        Calendar calendar = Calendar.getInstance();
        return calendar.get(SUB_DAY);
    }

    /**
     * 获得当前月份
     */
    public static int getToMonth() {
        Calendar calendar = Calendar.getInstance();
        return calendar.get(SUB_MONTH) + 1;
    }

    /**
     * 获得当前年份
     */
    public static int getToYear() {
        Calendar calendar = Calendar.getInstance();
        return calendar.get(SUB_YEAR);
    }

    /**
     * 返回日期的天
     */
    public static int getDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(SUB_DAY);
    }

    /**
     * 返回日期的年
     */
    public static int getYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(SUB_YEAR);
    }

    /**
     * 返回日期的月份,1-12
     */
    public static int getMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(SUB_MONTH) + 1;
    }

    /**
     * 计算两个日期相差的天数,如果date2 > date1 返回正数,否则返回负数
     */
    public static long dayDiff(Date date1, Date date2) {
        return (date2.getTime() - date1.getTime()) / 86400000;
    }

    /**
     * 比较两个日期的年差
     */
    public static int yearDiff(String before, String after) {
        Date beforeDay = stringToDate(before, LONG_DATE_FORMAT);
        Date afterDay = stringToDate(after, LONG_DATE_FORMAT);
        return getYear(afterDay) - getYear(beforeDay);
    }

    /**
     * 比较指定日期与当前日期的差
     */
    public static int yearDiffCurr(String after) {
        Date beforeDay = new Date();
        Date afterDay = stringToDate(after, LONG_DATE_FORMAT);
        return getYear(beforeDay) - getYear(afterDay);
    }

    /**
     * 获取每月的第一周
     */
    public static int getFirstWeekdayOfMonth(int year, int month) {
        Calendar c = Calendar.getInstance();
        c.setFirstDayOfWeek(Calendar.SATURDAY); // 星期天为第一天
        c.set(year, month - 1, 1);
        return c.get(Calendar.DAY_OF_WEEK);
    }

    /**
     * 获取每月的最后一周
     */
    public static int getLastWeekdayOfMonth(int year, int month) {
        Calendar c = Calendar.getInstance();
        c.setFirstDayOfWeek(Calendar.SATURDAY); // 星期天为第一天
        c.set(year, month - 1, getDaysOfMonth(year, month));
        return c.get(Calendar.DAY_OF_WEEK);
    }

    /**
     * @return 获得当前日期字符串,格式"yyyy-MM-dd HH:mm:ss"
     */
    public static String getNow() {
        Calendar today = Calendar.getInstance();
        return dateToString(today.getTime(), FORMAT_ONE);
    }

    /**
     * @param date YYYY-mm-dd
     * @return 判断日期是否有效, 包括闰年的情况
     */
    public static boolean isDate(String date) {
        StringBuffer reg = new StringBuffer(
                "^((\\d{2}(([02468][048])|([13579][26]))-?((((0?");
        reg.append("[13578])|(1[02]))-?((0?[1-9])|([1-2][0-9])|(3[01])))");
        reg.append("|(((0?[469])|(11))-?((0?[1-9])|([1-2][0-9])|(30)))|");
        reg.append("(0?2-?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][12");
        reg.append("35679])|([13579][01345789]))-?((((0?[13578])|(1[02]))");
        reg.append("-?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))");
        reg.append("-?((0?[1-9])|([1-2][0-9])|(30)))|(0?2-?((0?[");
        reg.append("1-9])|(1[0-9])|(2[0-8]))))))");
        Pattern p = Pattern.compile(reg.toString());
        return p.matcher(date).matches();
    }


    /*****
     * 时间 增加、减少 n个小时以后时间
     * @param d YYYY-mm-dd HH:mm:ss
     * @param num >0 小时
     * @param type 增加和减少标志
     * **/
    public static Date adjustDateByHour(Date d, Integer num, int type) {
        Calendar Cal = Calendar.getInstance();
//        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Cal.setTime(d);
        if (type == 0) {
            Cal.add(SUB_MINUTE, -num);
            // System.out.println("date:"+df.format(Cal.getTime()));

        } else {
            Cal.add(SUB_MINUTE, num);
            //System.out.println("date:"+df.format(Cal.getTime()));
        }
        return Cal.getTime();
    }

    /*****
     * 时间 增加、减少 n个分钟以后时间
     * @param d YYYY-mm-dd HH:mm:ss
     * @param num>0 分钟
     * @param type 增加和减少标志
     * **/
    public static Date adjustDateByMinutes(Date d, Integer num, int type) {
        Calendar Cal = Calendar.getInstance();
//        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Cal.setTime(d);
        if (type == 0) {
            Cal.add(SUB_MINUTE, -num);
            // System.out.println("date:"+df.format(Cal.getTime()));
        } else {
            Cal.add(SUB_MINUTE, num);
            //  System.out.println("date:"+df.format(Cal.getTime()));
        }
        return Cal.getTime();
    }

//    public static void main(String[] args) {
      String dateStr = DateUtil.yearthDate("2017-05-30");
      System.out.println(dateStr);
      long min = DateUtil.timeSub("2017-04-12 00:00:00", "2017-04-13 00:00:00")/60;
      System.out.println(min);
//        String settlementDate = DateUtil.dateToString(new Date(), "yyyy-MM-dd");
//        long day = DateUtil.dayDiff(DateUtil.stringToDate("2017-06-22", "yyyy-MM-dd"), DateUtil.stringToDate(settlementDate, "yyyy-MM-dd"));
//        if (day >= 0) {
//            System.out.println(day);
//        }
//
//        String goodsArriveTime = "2017-04-02 17:00-18:00";
//        int space_index = goodsArriveTime.indexOf(" ");
//        String arrive_date = goodsArriveTime.substring(0, space_index);
//        String arrive_time = goodsArriveTime.substring(space_index + 1, goodsArriveTime.length());
//
//        System.out.println(arrive_date);
//        System.out.println(arrive_time);
//        String arrive_start_time = arrive_time.substring(0, 2);
//        String arrive_end_time = arrive_time.substring(6, 8);
//
//        System.out.println(arrive_start_time);
//        System.out.println(arrive_end_time);
//
//        String Time = DateUtil.getCurrDate("HH");
//        System.out.println(Time);
//
//        String Time2 = DateUtil.getCurrDate("mm");
//        System.out.println(Time2);
//    }
}
package com.common.util;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Component
public class SpringUtil implements ApplicationContextAware {


    /**
     * @param num 数值
     * @return 数值类型前面补零(共13位)
     */
    public static String supplementZeroGenerateThirteen(int num) {
        return String.format("%013d", num);
    }

    /**
     * @param num 数值
     * @return 数值类型前面补零(共16位)
     */
    public static String supplementZeroGenerateSixteen(int num) {
        return String.format("%016d", num);
    }

    /**
     * @param num 数值
     * @return 数值类型前面补零(共3位)
     */
    public static String supplementZeroGenerateThree(int num) {
        return String.format("%03d", num);
    }

    /**
     * @param str 字符串
     * @return 判断字符串是不是double型
     */
    public static boolean isNumeric(String str) {
        Pattern pattern = Pattern.compile("[0-9]+[.]{0,1}[0-9]*[dD]{0,1}");
        Matcher isNum = pattern.matcher(str);
        if (!isNum.matches()) return false;
        return true;
    }

    public static String trim(String str, boolean nullFlag) {
        String tempStr = null;
        if (str != null) tempStr = str.trim();

        if (nullFlag) {
            if ("".equals(tempStr) || "null".equals(tempStr)) tempStr = null;
        } else {
            if (tempStr == null) tempStr = "";
        }
        return tempStr;
    }

    public static String replace(String strSource, String strFrom, String strTo) {
        if (strSource == null) return null;
        int i = 0;
        if ((i = strSource.indexOf(strFrom, i)) >= 0) {
            char[] cSrc = strSource.toCharArray();
            char[] cTo = strTo.toCharArray();
            int len = strFrom.length();
            StringBuffer buf = new StringBuffer(cSrc.length);
            buf.append(cSrc, 0, i).append(cTo);
            i += len;
            int j = i;
            while ((i = strSource.indexOf(strFrom, i)) > 0) {
                buf.append(cSrc, j, i - j).append(cTo);
                i += len;
                j = i;
            }
            buf.append(cSrc, j, cSrc.length - j);
            return buf.toString();
        }
        return strSource;
    }

    public static String deal(String str) {
        str = replace(str, "\\", "\\\\");
        str = replace(str, "'", "\\'");
        str = replace(str, "\r", "\\r");
        str = replace(str, "\n", "\\n");
        str = replace(str, "\"", "\\\"");
        return str;
    }

    public static String GetMapToXML(Map<String, String> param) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        for (Map.Entry<String, String> entry : param.entrySet()) {
            sb.append("<" + entry.getKey() + ">");
            sb.append(entry.getValue());
            sb.append("</" + entry.getKey() + ">");
        }
        sb.append("</xml>");
        return sb.toString();
    }

  /*  public static void main(String[] args) {
        //String a = StringUtil.supplementZeroGenerateThirteen(1000);
        double a = 32.;
        System.out.println(isNumeric("32."));
        System.out.println(a);
    }*/
}
package com.common.util.weChat;

import lombok.Data;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyStore;
import java.util.*;

/**
 * @Author FangYN
 * @Date 2020/6/29 9:14
 * @Description 微信支付工具类
 **/
@Component
@Data
public class PayCommonUtil {
    //微信参数配置
    @Value("${wx.api_key}")
    public static String API_KEY;
    /**
     * 应用ID
     */
    @Value("${wx.appid}")
    public static String APP_ID;
    /**
     * 商户号
     */
    @Value("${wx.mch_id}")
    public static String MCH_ID;
    /**
     * 回调地址
     */
    @Value("${wx.notify_url}")
    public static String NOTIFY_URL;

    //随机字符串生成
    public static String getRandomString(int length) { //length表示生成字符串的长度
        String base = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    /**
     * @param request 请求对象
     * @return 读取 request body 内容作为字符串
     * @throws IOException
     */
    public static String readRequest(HttpServletRequest request) throws IOException {
        InputStream inStream = request.getInputStream();
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1)
            outSteam.write(buffer, 0, len);
        String resultXml = new String(outSteam.toByteArray(), "utf-8");
        outSteam.close();
        inStream.close();
        return resultXml;
    }

    //请求xml组装
    public static String getRequestXml(SortedMap<String, Object> parameters) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            if ("attach".equalsIgnoreCase(key) || "body".equalsIgnoreCase(key) || "sign".equalsIgnoreCase(key)) {
                sb.append("<" + key + ">" + "<![CDATA[" + value + "]]></" + key + ">");
            } else {
                sb.append("<" + key + ">" + value + "</" + key + ">");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }

    //生成签名
    public static String createSign(String characterEncoding, SortedMap<String, Object> parameters) {
        StringBuffer sb = new StringBuffer();
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            Object v = entry.getValue();
            if (null != v && !"".equals(v)
                    && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + API_KEY);
        System.out.println(sb.toString());
        String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
        return sign;
    }

    /**
     * @return 验证回调签名
     */
    public static boolean isTenPaySign(Map<String, String> map) {
        String characterEncoding = "utf-8";
        String charset = "utf-8";
        String signFromAPIResponse = map.get("sign");
        if (signFromAPIResponse == null || signFromAPIResponse.equals("")) {
            System.out.println("API返回的数据签名数据不存在,有可能被第三方篡改!!!");
            return false;
        }
        System.out.println("服务器回包里面的签名是:" + signFromAPIResponse);
        //过滤空 设置 TreeMap
        SortedMap<String, String> packageParams = new TreeMap();
        for (String parameter : map.keySet()) {
            String parameterValue = map.get(parameter);
            String v = "";
            if (null != parameterValue) {
                v = parameterValue.trim();
            }
            packageParams.put(parameter, v);
        }

        StringBuffer sb = new StringBuffer();
        Set es = packageParams.entrySet();
        Iterator it = es.iterator();

        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (!"sign".equals(k) && null != v && !"".equals(v)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + API_KEY);

        //将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
        //算出签名
        String resultSign = "";
        String tobeSign = sb.toString();

        if (null == charset || "".equals(charset)) {
            resultSign = MD5Util.MD5Encode(tobeSign, characterEncoding).toUpperCase();
        } else {
            try {
                resultSign = MD5Util.MD5Encode(tobeSign, characterEncoding).toUpperCase();
            } catch (Exception e) {
                resultSign = MD5Util.MD5Encode(tobeSign, characterEncoding).toUpperCase();
            }
        }

        String tenPaySign = ((String) packageParams.get("sign")).toUpperCase();
        return tenPaySign.equals(resultSign);
    }

    //请求方法
    public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
        try {
            URL url = new URL(requestUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();

            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            // 设置请求方式(GET/POST)
            conn.setRequestMethod(requestMethod);
            conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
            // 当outputStr不为null时向输出流写数据
            if (null != outputStr) {
                OutputStream outputStream = conn.getOutputStream();
                // 注意编码格式
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }
            // 从输入流读取返回内容
            InputStream inputStream = conn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            StringBuffer buffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            // 释放资源
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            inputStream = null;
            conn.disconnect();
            return buffer.toString();
        } catch (ConnectException ce) {
            System.out.println("连接超时:{}" + ce);
        } catch (Exception e) {
            System.out.println("https请求异常:{}" + e);
        }
        return null;
    }

    //退款的请求方法
    public static String httpsRequest2(String requestUrl, String requestMethod, String outputStr) throws Exception {
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        StringBuilder res = new StringBuilder("");
        FileInputStream inStream = new FileInputStream(new File("/home/apiclient_cert.p12"));
        try {
            keyStore.load(inStream, "".toCharArray());
        } finally {
            inStream.close();
        }

        // Trust own CA and all self-signed certs
        SSLContext sslcontext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, "1313329201".toCharArray())
                .build();
        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslCSF = new SSLConnectionSocketFactory(
                sslcontext,
                new String[]{"TLSv1"},
                null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLSocketFactory(sslCSF)
                .build();
        try {

            HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");
            httpPost.addHeader("Connection", "keep-alive");
            httpPost.addHeader("Accept", "*/*");
            httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
            httpPost.addHeader("Host", "api.mch.weixin.qq.com");
            httpPost.addHeader("X-Requested-With", "XMLHttpRequest");
            httpPost.addHeader("Cache-Control", "max-age=0");
            httpPost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
            StringEntity entity2 = new StringEntity(outputStr, Consts.UTF_8);
            httpPost.setEntity(entity2);
            System.out.println("executing request" + httpPost.getRequestLine());
            CloseableHttpResponse response = httpClient.execute(httpPost);

            try {
                HttpEntity entity = response.getEntity();
                System.out.println("----------------------------------------");
                System.out.println(response.getStatusLine());
                if (entity != null) {
                    System.out.println("Response content length: " + entity.getContentLength());
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
                    String text = "";
                    res.append(text);
                    while ((text = bufferedReader.readLine()) != null) {
                        res.append(text);
                        System.out.println(text);
                    }

                }
                EntityUtils.consume(entity);
            } finally {
                response.close();
            }
        } finally {
            httpClient.close();
        }
        return res.toString();
    }

    //xml解析
    public static Map doXMLParse(String strXml) throws JDOMException, IOException {
        strXml = strXml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
        if (null == strXml || "".equals(strXml)) return null;

        Map m = new HashMap();
        InputStream in = new ByteArrayInputStream(strXml.getBytes("UTF-8"));
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(in);
        Element root = doc.getRootElement();
        List list = root.getChildren();
        Iterator it = list.iterator();
        while (it.hasNext()) {
            Element e = (Element) it.next();
            String k = e.getName();
            String v = "";
            List children = e.getChildren();
            if (children.isEmpty()) {
                v = e.getTextNormalize();
            } else {
                v = getChildrenText(children);
            }
            m.put(k, v);
        }
        in.close();  //关闭流
        return m;
    }

    public static String getChildrenText(List children) {
        StringBuffer sb = new StringBuffer();
        if (!children.isEmpty()) {
            Iterator it = children.iterator();
            while (it.hasNext()) {
                Element e = (Element) it.next();
                String name = e.getName();
                String value = e.getTextNormalize();
                List list = e.getChildren();
                sb.append("<" + name + ">");
                if (!list.isEmpty()) {
                    sb.append(getChildrenText(list));
                }
                sb.append(value);
                sb.append("</" + name + ">");
            }
        }

        return sb.toString();
    }

    public static String getRemoteHost(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
            ip = request.getHeader("Proxy-Client-IP");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
            ip = request.getHeader("WL-Proxy-Client-IP");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
            ip = request.getRemoteAddr();
        return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
    }
}

4.具体实现

package com.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.common.util.DateUtil;
import com.common.util.SpringUtil;
import com.common.util.UUIDUtils;
import com.common.util.weChat.PayCommonUtil;
import com.domain.WxOrder;
import com.orange.physical.mapper.WxOrderMapper;
import com.service.IWxOrderService;
import com.vo.pay.WeChatPayVo;
import org.apache.commons.io.IOUtils;
import org.jdom2.JDOMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * @Author: FangYN
 * @Date: 2020/6/29
 * @Description: 微信订单支付逻辑实现
 */
@Service
public class **ServiceImpl extends ServiceImpl<**Mapper, **> implements I**Service {
    private static Logger log = LoggerFactory.getLogger(WxOrderServiceImpl.class);
    private String randomString = PayCommonUtil.getRandomString(32);
    private static final String PLACE_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";// 下单 API 地址
    @Autowired
    private WxPayService wxService;

    // 创建预订单,返回收款二维码
    @Transactional(rollbackFor = Exception.class)
    @Override
    public WeChatPayVo createOrder(HttpServletRequest request) throws Exception {
        BigDecimal totalAmount = new BigDecimal("0.01");// 支付金额
        String tradeNo = UUIDUtils.getUUID();// 订单编号
        String description = request.getParameter("description");// 订单描述
        String productId = "1";
        Map<String, String> map = weChatPrePay(tradeNo, totalAmount, description, productId, productId, request);
        if ("FAIL".equals(map.get("return_code")) || "FAIL".equals(map.get("result_code")))
            throw new Exception("订单创建失败,请重新请求");
        // 保存订单信息
        WxOrder insertOrder = new WxOrder();
        insertOrder.setTradeNo(tradeNo);
        insertOrder.setPrepayId(map.get("prepay_id"));
        insertOrder.setTotalFee(totalAmount);
        insertOrder.setBody(description);
        insertOrder.setDetail(description);
        baseMapper.insert(insertOrder);
        // 返回订单相关数据
//        Map app = new HashMap();
//        app.put("appid", PayCommonUtil.APP_ID);
//        app.put("partnerid",PayCommonUtil.MCH_ID);
//        app.put("prepayid", map.get("prepay_id"));
//        app.put("package", "Sign=WXPay");                   // 固定字段,保留,不可修改
//        app.put("noncestr", map.get("nonce_str"));
//        app.put("timestamp", new Date().getTime() / 1000);  // 时间为秒,JDK 生成的是毫秒,故除以 1000

        WeChatPayVo prePay = new WeChatPayVo();
        prePay.setPrice(totalAmount);
        prePay.setDescription(description);
        prePay.setTradeNo(tradeNo);
        prePay.setOrderId(insertOrder.getOrderId());
        prePay.setPrepayId(insertOrder.getPrepayId());
        prePay.setCodeUrl(map.get("code_url"));
        return prePay;
    }

    /**
     * 统一下单
     * 应用场景:商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易回话标识后再在APP里面调起支付。
     *
     * @param tradeNo     系统生成的订单号
     * @param totalAmount 订单金额
     * @param description 订单描述
     * @param openid      用户标识 trade_type=JSAPI时(即JSAPI支付),此参数必传,此参数为微信用户在商户对应appid下的唯一标识
     * @param productId   trade_type=NATIVE时,此参数必传。此参数为二维码中包含的商品ID
     * @param request     请求信息
     * @return 预支付信息
     */
    @SuppressWarnings("unchecked")
    public Map<String, String> weChatPrePay(String tradeNo, BigDecimal totalAmount, String description, String openid, String productId, HttpServletRequest request) throws Exception {
        SortedMap<String, Object> parameterMap = new TreeMap<String, Object>();
        parameterMap.put("appid", PayCommonUtil.APP_ID); // 应用appid
        parameterMap.put("mch_id", PayCommonUtil.MCH_ID); // 商户号
        parameterMap.put("device_info", "WEB");
        parameterMap.put("nonce_str", randomString);
        parameterMap.put("body", description);// 商品名称
        parameterMap.put("out_trade_no", tradeNo);// 当前系统生成的订单编号
        parameterMap.put("fee_type", "CNY");// 默认:人民币
        BigDecimal total = totalAmount.multiply(new BigDecimal(100)); //接口中参数支付金额单位为【分】,参数值不能带小数,所以乘以100
        java.text.DecimalFormat df = new java.text.DecimalFormat("0");
        parameterMap.put("total_fee", df.format(total.intValue()));// 标价金额
        parameterMap.put("spbill_create_ip", PayCommonUtil.getRemoteHost(request));// 终端IP
        parameterMap.put("notify_url", PayCommonUtil.NOTIFY_URL);// 通知地址
        parameterMap.put("trade_type", "NATIVE");// "JSAPI","APP"
        if ("JSAPI".equals(parameterMap.get("trade_type").toString()))
            parameterMap.put("openid", openid);
        if ("NATIVE".equals(parameterMap.get("trade_type").toString()))
            parameterMap.put("product_id", productId);
        parameterMap.put("sign", PayCommonUtil.createSign("UTF-8", parameterMap));
        String requestXML = PayCommonUtil.getRequestXml(parameterMap);
        log.info("微信统一下单:下单构建数据请求内容===>" + requestXML);
        String result = PayCommonUtil.httpsRequest(PLACE_URL, "POST", requestXML);
        log.info("微信统一下单:下单返回数据===>" + result);
        Map<String, String> map;
        try {
            map = PayCommonUtil.doXMLParse(result);
        } catch (JDOMException e) {
            e.printStackTrace();
            throw new Exception("订单创建失败");
        } catch (IOException e) {
            e.printStackTrace();
            throw new Exception("订单创建失败");
        }
        return map;
    }

    // 支付成功回调方法
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String callBack(HttpServletRequest request) throws IOException, JDOMException {
        // 读取参数,解析Xml为map
        Map<String, String> params = PayCommonUtil.doXMLParse(PayCommonUtil.readRequest(request));
        log.info("微信notify:微信支付回调:读取数据result===>" + params);
        if (!PayCommonUtil.isTenPaySign(params) || "FAIL".equals(params.get("return_code"))) {// 签名验证失败
            return fail();
        }
        String tradeNo = params.get("out_trade_no");// 系统订单号
        if ("FAIL".equals(params.get("result_code"))) {// 支付失败
            baseMapper.updateStatusByTradeNo(tradeNo, "2", params.get("err_code_des"));
            return fail();
        }
        log.info("微信notify:微信支付回调:修改的订单===>" + tradeNo);
      
        // 更新订单交易成功相关数据等逻辑
        // 验证订单金额是否一致
        // BigDecimal totalFee = new BigDecimal(params.get("total_fee")).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UNNECESSARY);
        // if (totalFee.compareTo(**.getTotalFee()) != 0)
        //   return fail();
        return success();

    }

    private String fail() {
        Map<String, String> return_data = new HashMap<>();
        return_data.put("return_code", "FAIL");
        return_data.put("return_msg", "return_code不正确");
        return SpringUtil.GetMapToXML(return_data);
    }

    private String success() {
        Map<String, String> return_data = new HashMap<>();
        return_data.put("return_code", "SUCCESS");
        return_data.put("return_msg", "OK");
        return SpringUtil.GetMapToXML(return_data);
    }
}

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值