微信扫码支付

配置文件

package com.nroad.config;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;

/**
 * WeixinPayConfig
 * Created by Administrator on 2017/5/4.
 * 微信支付配置文件
 */
@Component
public class WeixinPayConfig {



    private static Log log = LogFactory.getLog(WeixinPayConfig.class);
    private static Configuration configs;
    static {
        WeixinPayConfig.init("weixinpayinfo.properties");
    }
    public static String appid;     //微信支付分配的公众账号ID(企业号corpid即为此appId)

    public static String mch_id;       //微信支付分配的商户号

    public static String device_info;         //设备号,PC网页或公众号内支付可以传"WEB"

    public static String post_url;           //请求路径

    public static String query_url;           //查询路径

    public static String appsecret;

    public static String mchsecret;              //签名时使用的key

    private WeixinPayConfig() {
    }

    private static synchronized void init(String filePath) {
        if (configs == null) {
            try {
                configs = new PropertiesConfiguration(filePath);
            } catch (ConfigurationException var2) {
                var2.printStackTrace();
            }
        }
        if (configs == null) {
            throw new IllegalStateException("can`t find file by path:" + filePath);
        } else {
            appid = configs.getString("appid");
            mch_id = configs.getString("mch_id");
            device_info = configs.getString("device_info");
            post_url = configs.getString("post_url");
            query_url = configs.getString("query_url");
            appsecret = configs.getString("appsecret");
            mchsecret = configs.getString("mchsecret");
            log.info("微信支付配置如下: ");
            log.info("配置文件名: " + filePath);
            log.info(description());
        }
    }

    private static String description() {
        StringBuilder sb = new StringBuilder("Configs{");
        sb.append("微信公众账号ID: ").append(appid).append("\n");
        sb.append("微信商户号: ").append(mch_id).append("\n");
        sb.append("微信设备号: ").append(device_info).append("\n");
        sb.append("请求路径: ").append(post_url).append("\n");
        sb.append("查询路径: ").append(query_url).append("\n");
        sb.append("支付秘钥: ").append(mchsecret).append("\n");
        sb.append("}");
        return sb.toString();
    }

微信支付业务流程

package com.nroad.service.wechat.pay;

import com.nroad.config.WeixinPayConfig;
import com.nroad.dto.OrderDto;
import com.nroad.exception.PayException;
import com.nroad.utils.MathUtil;
import com.nroad.utils.OrderUtil;
import com.nroad.utils.PayCommonUtil;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * Created by Administrator on 2017/5/4.
 */
@Component
public class WeChat {

    /**
     * 获取微信支付二维码
     * @return
     */
    public String trade_precreate(String cip, OrderDto orderDto,String serverName){
        //获取二维码生存周期
        String[] QRTime = OrderUtil.QRTime();
        //生成随机字符串
        String nonce_str =  OrderUtil.nonce();
        //参数收集
        SortedMap<Object,Object> params=new TreeMap<Object, Object>();
        params.put("appid", WeixinPayConfig.appid);   //公众账号ID
        params.put("mch_id", WeixinPayConfig.mch_id);  //商户号
        params.put("device_info", WeixinPayConfig.device_info); //设备号
        params.put("nonce_str", nonce_str);   //随机字符串
        params.put("out_trade_no",orderDto.getOrderNo());      //商户订单号
        params.put("body",orderDto.getSubject());   //商品描述
        params.put("detail",orderDto.getBody());    //商品详情
        params.put("total_fee", MathUtil.movePointRight_s(orderDto.getTotalMoney(),2));         //订单总金额
        params.put("spbill_create_ip",cip);    //用户端ip
        params.put("time_start",QRTime[0]);     //订单生成时间
        params.put("time_expire",QRTime[1]);    //订单失效时间
        params.put("notify_url","http://"+serverName+":8100/weChat_notify");       //异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。
        params.put("trade_type","NATIVE");      //交易类型---JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付
        //生成签名
        String sign = PayCommonUtil.generateSign("UTF-8", params, WeixinPayConfig.mchsecret);
        params.put("sign",sign);    //添加签名信息
        //生成xml格式的String
        String requestXml = PayCommonUtil.generateRequestXml(params);
        //将xml格式数据发送给微信第三方,通知获取到其反馈信息(也为xml格式)
        String resXml = null;
        try {
            resXml = PayCommonUtil.postData(WeixinPayConfig.post_url, requestXml);
        } catch (PayException e) {
            e.printStackTrace();
            throw new PayException("微信支付异常");
        }
        //将xml解析为map
        Map map = PayCommonUtil.doXMLParse(resXml);
        return (String) map.get("code_url");
    }

    /**
     * 支付结果结果查询
     */
    public String resultQuery(WeChatQuery weChatQuery){
        SortedMap<Object, Object> requestMap = weChatQuery.getMap();
        requestMap.put("nonce_str",OrderUtil.nonce());
        String sign = PayCommonUtil.generateSign("UTF-8", requestMap, WeixinPayConfig.mchsecret);
        requestMap.put("sign",sign);
        // 生成xml格式的String
        String requestXml = PayCommonUtil.generateRequestXml(requestMap);
        //将xml格式数据发送给微信第三方,通知获取到其反馈信息(也为xml格式)
        String resXml = PayCommonUtil.postData(WeixinPayConfig.query_url, requestXml);
        //将xml解析为map
        Map map = PayCommonUtil.doXMLParse(resXml);
        String result = (String) map.get("trade_state");
        System.out.println("微信支付 : " + result);
        return result;
    }
}

需要使用的工具类

package com.nroad.utils;

import java.time.LocalDateTime;

/**
 * Created by Administrator on 2017/5/4.
 * 订单工具
 */
public class OrderUtil {
    public final static String TIME_REGEX = "[-:T.]";
    /**
     * 生成订单号
     * @return
     */
    public static String nonce(){
        return String.valueOf(System.currentTimeMillis()
                + (long) (Math.random() * 10000000L));
    }

    /**
     * 生成商户订单号
     * @return
     */
    public static String merchantNo(){
        String now = LocalDateTime.now().toString();
        return now.replaceAll(TIME_REGEX, "")+"Lb"+(long)(Math.random()*1000000000000L);
    }

    /**
     * 获取交易起始时间和失效时间
     * 暂时默认为10分钟
     */
    public static String[] QRTime(){
        LocalDateTime startTime = LocalDateTime.now();
        LocalDateTime endTime = startTime.plusMinutes(30L);
        String start = startTime.toString().split("[.]")[0];
        String end = endTime.toString().split("[.]")[0];
        return new String[]{start.replaceAll(TIME_REGEX, ""), end.replaceAll(TIME_REGEX, "")};
    }
}
package com.nroad.utils;

import org.apache.commons.lang.StringUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;

/**
 * Created by Administrator on 2017/5/5.
 * 支付相关工具
 */
public class PayCommonUtil {
    private final static int CONNECT_TIMEOUT = 5000;
    private final static String DEFAULT_ENCODING = "UTF-8";

    /**
     * 生成签名
     *
     * @param characterEncoding
     * @param packageParams
     * @param API_KEY
     * @return
     */
    public static String generateSign(String characterEncoding, Map<Object, Object> packageParams, String API_KEY) {
        StringBuffer sb = new StringBuffer();
        Set<Map.Entry<Object, Object>> entries = packageParams.entrySet();
        Iterator<Map.Entry<Object, Object>> iterator = entries.iterator();
        //第一步,生成签名字符串
        while (iterator.hasNext()) {
            Map.Entry entry = iterator.next();
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            if (null != value && !"".equals(value) && !"sign".equals(key) && !"key".equals(key)) {
                sb.append(key + "=" + value + "&");
            }
        }
        sb.append("key=" + API_KEY);
        //通过MD5算法转换 并将其全部转化成大写
        String sign = MD5.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
        return sign;
    }

    /**
     * 将请求参数转换为xml格式的string
     *
     * @param parameters
     * @return
     */
    public static String generateRequestXml(SortedMap<Object, Object> parameters) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        Set<Map.Entry<Object, Object>> entries = parameters.entrySet();
        Iterator<Map.Entry<Object, Object>> iterator = entries.iterator();
        while (iterator.hasNext()) {
            Map.Entry next = iterator.next();
            String key = (String) next.getKey();
            String value = (String) next.getValue();
            if ("".equals(StringUtils.trimToEmpty(value))){
                continue;
            }
            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();
    }

    /**
     * 将xml数据转换成为 Map类型
     *
     * @param strxml
     * @return
     */
    public static Map doXMLParse(String strxml) {
        strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
        if (null == strxml || "".equals(strxml)) {
            return null;
        }
        Map m = new HashMap();
        InputStream  in =null;
        try {
            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 iterator = list.iterator();
            while (iterator.hasNext()) {
                Element e = (Element) iterator.next();
                String name = e.getName();
                String value = "";
                List children = e.getChildren();
                //如果存在子节点,继续遍历
                if (children.isEmpty()) {
                    value = e.getTextNormalize();
                } else {
                    value = PayCommonUtil.getChildrenText(children);
                }
                m.put(name, value);
            }

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (JDOMException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (in !=null){
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return m;

    }

    /**
     * 获取子节点的xml
     * @param children
     * @return
     */
    public static String getChildrenText(List children){
        StringBuffer sb =new StringBuffer();
        //子节点不为空,迭代子节点
        if (!children.isEmpty()){
            Iterator iterator = children.iterator();
            while (iterator.hasNext()){
                Element element = (Element) iterator.next();
                String name = element.getName();
                String value = element.getTextNormalize();
                List list = element.getChildren();
                sb.append("<" + name + ">");
                if (!list.isEmpty()){
                    sb.append(PayCommonUtil.getChildrenText(list));
                }
                sb.append(value);
                sb.append("</" + name +">");
            }
        }
        return sb.toString();
    }


    /**
     * 请求数据
     * @param url
     * @param requestXML
     * @return
     */
    public static String postData(String url, String requestXML) {
        return postData(url, requestXML, null);
    }

    /**
     * 请求数据,如果成功,获得的是一个xml数据
     * @param strUrl
     * @param data
     * @param conentType
     * @return
     */
    private static String postData(String strUrl, String data, String conentType) {
        BufferedReader reader = null;
        try {
            URL url = new URL(strUrl);
            URLConnection conn = url.openConnection();
            conn.setDoOutput(true);
            conn.setConnectTimeout(CONNECT_TIMEOUT);
            conn.setReadTimeout(CONNECT_TIMEOUT);
            if (conentType != null) {
                conn.setRequestProperty("content-type", conentType);
            }
            OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), DEFAULT_ENCODING);
            if (data == null) {
                data = "";
            }
            writer.write(data);
            writer.flush();
            writer.close();

            reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), DEFAULT_ENCODING));
            StringBuffer sb = new StringBuffer();
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
                sb.append("\r\n");
            }
            return sb.toString();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null)
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
        return null;
    }

    public static boolean isTenpaySign(String characterEncoding , SortedMap<Object, Object> packageParams, String API_KEY){
        StringBuffer sb = new StringBuffer();
        Set<Map.Entry<Object, Object>> entries = packageParams.entrySet();
        Iterator<Map.Entry<Object, Object>> iterator = entries.iterator();
        while (iterator.hasNext()){
            Map.Entry entry = (Map.Entry) iterator.next();
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            if (!"sign".equalsIgnoreCase(key) && null != value && !"".equals(value)){
                sb.append(key + "=" + value +"&");
            }
        }
        sb.append("key=" + API_KEY);
        //算出摘要
        String mysign = MD5.MD5Encode(sb.toString(), characterEncoding).toLowerCase();
        String tenpaySign = ((String)packageParams.get("sign")).toLowerCase();
        System.out.println("mysign : "+mysign);
        System.out.println("tenpaySign : "+tenpaySign);
        return tenpaySign.equals(mysign);
    }
}

异步通知

@RequestMapping("/weChat_notify")
    public void weChat_notify(HttpServletRequest request, HttpServletResponse response) {
        log.info("微信异步通知开始");
        //读取参数
        InputStream inputStream = null;
        StringBuffer sb = new StringBuffer();
        BufferedReader bufferedReader = null;
        try {
            log.info("获取返回参数");
            String s = "";
            inputStream = request.getInputStream();
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
            while ((s = bufferedReader.readLine()) != null) {
                sb.append(s);
            }
        } catch (IOException e) {
            log.info("返回参数获取失败");
            e.printStackTrace();
        } finally {
            try {
                if (null != bufferedReader)
                    bufferedReader.close();
                if (null != inputStream)
                    inputStream.close();
            } catch (IOException e) {
                log.info("io流关闭失败");
                e.printStackTrace();
            }
        }
        log.info("开始解析xml参数");
        //解析xml成map
        Map<String, String> m = new HashMap<String, String>();
        Map map = PayCommonUtil.doXMLParse(sb.toString());
        //过滤空 设置 TreeMap
        log.info("开始过滤空值");
        SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
        Iterator iterator = map.keySet().iterator();
        while (iterator.hasNext()) {
            String parameter = (String) iterator.next();
            String paramterValue = (String) map.get(parameter);

            String value = "";
            //去空格,将NULL 和 "" 转换为""
            value = StringUtils.trimToEmpty(paramterValue);
            packageParams.put(parameter, value);
        }
        //判断签名是否正确
        log.info("签名验证开始");
        if (PayCommonUtil.isTenpaySign("UTF-8", packageParams, WeixinPayConfig.mchsecret)) {
            log.info("签名验证成功");
            //------------------------------
            //处理业务开始
            //------------------------------
            String resXml = "";
            if ("SUCCESS".equals((String) packageParams.get("result_code"))) {
                //这里是支付成功
                ///////////////////开始自己的业务///////////////////////
                String out_trade_no = (String) packageParams.get("out_trade_no");
                save(out_trade_no,"微信");
                ///////////////////开始自己的业务///////////////////////
                log.info("支付成功");
                //通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
            } else {
                log.info("支付失败,错误信息:" + packageParams.get("err_code"));
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                        + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
            }
            //------------------------------
            //处理业务完毕
            //------------------------------
            BufferedOutputStream out = null;
            try {
                out = new BufferedOutputStream(
                        response.getOutputStream());
                out.write(resXml.getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    out.flush();
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } else {
            log.info("通知签名验证失败");
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值