微信扫码支付

来源:互联网 发布:linux pl2303驱动下载 编辑:程序博客网 时间:2024/06/04 19:12

配置文件

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. * 微信支付配置文件 */@Componentpublic 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. */@Componentpublic 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("通知签名验证失败");        }    }
原创粉丝点击