微信支付后台接口开发(扫码版)

来源:互联网 发布:如何打开防火墙端口 编辑:程序博客网 时间:2024/06/06 02:52

一:需求

满足公司在网页上达到直接微信扫码支付的需求

二:API官方文档

参考链接:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1

三:微信支付的过程(用户-商家-微信服务器)

四:代码实现

实体类:参考链接:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1

1.统一下单请求参数

/** * 统一下单请求参数(必填) */@XmlRootElement <span>此处加注解是为了后台xmljiepublic class UnifiedOrderRequest { private String appid;  //IDprivate String mch_id;   //商户号private String nonce_str;   //随机字符串private String sign;    //数字签名private String body;    //商品描述private String out_trade_no;  //商户订单private String total_fee;   //总金额private String spbill_create_ip;  //终端Ipprivate String notify_url;   //通知地址private String trade_type;    //交易类型public UnifiedOrderRequest(){};public UnifiedOrderRequest(String appid, String mch_id,String nonce_str, String sign, String body,String out_trade_no, String total_fee, String spbill_create_ip,String notify_url, String trade_type) {super();this.appid = appid;this.mch_id = mch_id;this.nonce_str = nonce_str;this.sign = sign;this.body = body;this.out_trade_no = out_trade_no;this.total_fee = total_fee;this.spbill_create_ip = spbill_create_ip;this.notify_url = notify_url;this.trade_type = trade_type;}}


统一下单参数(非必须)
/** * 统一下单请求参数(非必填) */@XmlRootElement <span>此处加注解是为了xml解析</span>public class UnifiedOrderRequestExt extends UnifiedOrderRequest{private String device_info; //设备号private String detail;  //商品详情private String attach;  //附加数据private String fee_type;  //货币类型private String time_start;     //交易起始时间private String time_expire;  //交易结束时间private String goods_tag;  //商品标记private String product_id; //商品IDprivate String limit_pay;  //指定支付方式private String openid;  //用户标志public UnifiedOrderRequestExt(){super();}public UnifiedOrderRequestExt(String appid, String mch_id,String nonce_str, String sign, String body, String out_trade_no,String total_fee, String spbill_create_ip, String notify_url,String trade_type, String device_info, String detail,String attach, String fee_type, String time_start,String time_expire, String goods_tag, String product_id,String limit_pay, String openid) {super(appid, mch_id, nonce_str, sign, body, out_trade_no, total_fee,spbill_create_ip, notify_url, trade_type);this.device_info = device_info;this.detail = detail;this.attach = attach;this.fee_type = fee_type;this.time_start = time_start;this.time_expire = time_expire;this.goods_tag = goods_tag;this.product_id = product_id;this.limit_pay = limit_pay;this.openid = openid;}}
3.订单返回参数
/** * 统一下单返回参数 * */
<span>此处加注解是为了xml解析</span>
@XmlAccessorType(XmlAccessType.FIELD)@XmlRootElement(name = "UnifiedOrderRespose")@XmlType(propOrder={"return_code","return_msg","appid","mch_id","device_info","nonce_str","sign","result_code","err_code","err_code_des","trade_type","prepay_id","code_url"})public class UnifiedOrderRespose {private String return_code; //返回状态码private String return_msg; //返回信息private String appid; //公众账号IDprivate String mch_id; //商户号private String device_info; //设备号private String nonce_str; //随机字符串private String sign; //数字签名private String result_code; //业务结果private String err_code; //错误代码private String err_code_des; // 错误代码描述private String trade_type; //交易类型private String prepay_id; //预支付交易会话标致private String code_url; //二维码链接public UnifiedOrderRespose(){}public UnifiedOrderRespose(String return_code, String return_msg,String appid, String mch_id, String device_info, String nonce_str,String sign, String result_code, String err_code,String err_code_des, String trade_type, String prepay_id,String code_url) {super();this.return_code = return_code;this.return_msg = return_msg;this.appid = appid;this.mch_id = mch_id;this.device_info = device_info;this.nonce_str = nonce_str;this.sign = sign;this.result_code = result_code;this.err_code = err_code;this.err_code_des = err_code_des;this.trade_type = trade_type;this.prepay_id = prepay_id;this.code_url = code_url;}

二:xml解析(二种解析类型,已封装,可直接使用)

import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.Node;import org.w3c.dom.NodeList;public class XMLObjectConvertUtil {/** * 将xml文件转换为Map集合 * @param String类型的xml * @return map集合 */public static Map<String, String> getMap(String xml) throws Exception{try{Map<String, String> maps = new HashMap<String, String>();DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();InputStream inputStream = new ByteArrayInputStream(xml.getBytes("utf-8"));Document document = documentBuilder.parse(inputStream);document.getDocumentElement().normalize();//获得所有的节点NodeList nodeList = document.getDocumentElement().getChildNodes();for (int i = 0; i < nodeList.getLength(); i++) {Node node = nodeList.item(i);//如果为标记节点 如 <username>if(node.getNodeType() == node.ELEMENT_NODE){Element e = (Element) node;//将节点名称与节点内容放进map集合中maps.put(e.getNodeName(),e.getTextContent());}}return maps;}catch(Exception e){e.printStackTrace();}return null;}/** * 将Map集合转换成String类型的xml * @param maps * @return * @throws Exception */public String getXml(Map<String, String> maps) throws Exception{DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();Document document = documentBuilder.newDocument();//创建根目录Element  root = document.createElement("xml");//添加根目录进文档document.appendChild(root);//遍历所有的keyfor(String key:maps.keySet()){//获得key所对应的valueString value= maps.get(key);if(value == null){value ="";}//去掉空格value = value.trim();//创建子节点Element filed = document.createElement(key);//将key所对应的value放入node中filed.appendChild(document.createTextNode(value));//将子节点放入根节点中root.appendChild(filed);}TransformerFactory transformerFactory = TransformerFactory.newInstance();Transformer transformer =transformerFactory.newTransformer();DOMSource domSource = new DOMSource(document);transformer.setOutputProperty(OutputKeys.ENCODING,"utf-8");transformer.setOutputProperty(OutputKeys.INDENT,"yes");StringWriter sw = new StringWriter();StreamResult sr = new StreamResult(sw);transformer.transform(domSource, sr);String output = sw.getBuffer().toString();return output;}/** * 将java对象转换成String类型的xml * @param obj * @return * @throws Exception */public String getXml(Object obj) throws Exception{StringWriter sw = new StringWriter();JAXBContext context = JAXBContext.newInstance(obj.getClass());Marshaller mar = context.createMarshaller();//统一编码mar.setProperty(mar.JAXB_ENCODING, "utf-8");mar.setProperty(mar.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);mar.marshal(obj, sw);return sw.toString();}}
四:现在实体类和转换方法都已经贴出。现在就是后台接口的编写了

package com.util;import java.io.BufferedOutputStream;import java.io.BufferedReader;import java.io.ByteArrayInputStream;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.StringReader;import java.io.StringWriter;import java.net.HttpURLConnection;import java.net.MalformedURLException;import java.net.URL;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Map.Entry;import java.util.Set;import java.util.SortedMap;import java.util.TreeMap;import java.util.UUID;import javax.servlet.http.HttpServletResponse;import javax.xml.bind.JAXBContext;import javax.xml.bind.JAXBException;import javax.xml.bind.Marshaller;import javax.xml.bind.Unmarshaller;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.ParserConfigurationException;import org.apache.struts2.ServletActionContext;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import org.xml.sax.SAXException;import com.bean.UnifiedOrderRequest;import com.bean.UnifiedOrderRespose;import com.google.zxing.BarcodeFormat;import com.google.zxing.EncodeHintType;import com.google.zxing.MultiFormatWriter;import com.google.zxing.common.BitMatrix;import com.sun.org.apache.xalan.internal.xsltc.runtime.Hashtable;public class MainAction {String orderId;HttpServletResponse response;String msg;/** * 创建二维码 */public void createCode(){//创建订单String orderInfo = createOrderInfo(orderId);if(orderInfo!=null){//得到统一下单 APIString codeUrl = httpOrder(orderInfo);if(codeUrl!=null){//利用 返回的预支付交易链接(codeUrl) 生成扫描的二维码try {int width =200; //宽200int height = 200; //高200String format = "jpg"; //图片格式//开始创建二维码Hashtable hs = new Hashtable();//设置编码格式hs.put(EncodeHintType.CHARACTER_SET, "utf-8");//设置二维码BitMatrix bit = new MultiFormatWriter().encode(codeUrl, BarcodeFormat.QR_CODE, width, height);OutputStream out = null;out = ServletActionContext.getResponse().getOutputStream();MatrixToImageWriter.writeToStream(bit,format,out);out.flush();out.close();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}/** * 调统一下单API */private String httpOrder(String orderInfo) {//微信支付统一接口String url ="https://api.mch.weixin.qq.com/pay/unifiedorder";try {//连接微信统一支付urlHttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();//加入数据conn.setRequestMethod("POST");//打开传输输出流conn.setDoOutput(true);//获取输出流BufferedOutputStream buffer = new BufferedOutputStream(conn.getOutputStream());buffer.write(orderInfo.getBytes());buffer.flush();buffer.close();//获取输入流BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));//接受数据String line = null; StringBuffer sb = new StringBuffer();//将输入流中的信息放在sb中while((line=reader.readLine())!=null){sb.append(line);};//解析xml成对象JAXBContext context = JAXBContext.newInstance(UnifiedOrderRespose.class);//反序列化成对象Unmarshaller unmarshaller = context.createUnmarshaller();//读取数据StringReader sr = new StringReader(sb.toString());//根据微信Demo 将xml转换成MapMap<String, String> ResponseMap = new  HashMap<String, String>();//创建文档类型 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();DocumentBuilder db = dbf.newDocumentBuilder();//将获取到的xml放入输入流中InputStream in = new ByteArrayInputStream(sb.toString().getBytes("utf-8"));Document doc;doc = db.parse(in);NodeList nl = doc.getDocumentElement().getChildNodes();for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);if(node.getNodeType() == node.ELEMENT_NODE){Element e = (Element) node;ResponseMap.put(e.getNodeName(), e.getTextContent());}}/* 转换成UnifiedOrderRespose对象UnifiedOrderRespose unRespose = (UnifiedOrderRespose) unmarshaller.unmarshal(new File("C:/Users/Administrator/Workspaces/MyEclipse 10/weixinpay/WebRoot/xmls/Result.xml"));      UnifiedOrderRespose unRespose = (UnifiedOrderRespose) unmarshaller.unmarshal(sr);      System.out.println(unRespose.getReturn_code()+"|"+unRespose.getReturn_msg());unRespose.setReturn_code("SUCCESS");unRespose.setReturn_msg("SUCCESS");unRespose.setCode_url("www.baidu.com");*///如果请求成功返回 ,则返回支付链接if(null!=ResponseMap && "SUCCESS".equals(ResponseMap.get("return_code"))&& "SUCCESS".equals(ResponseMap.get("return_msg"))){return ResponseMap.get("code_url");}else{return null;}}catch (SAXException e) {// TODO Auto-generated catch blocke.printStackTrace();}catch (ParserConfigurationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (JAXBException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (MalformedURLException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;}/** * 生成订单,返回xml文件 */private String createOrderInfo(String orderId) {UnifiedOrderRequest un = new UnifiedOrderRequest();un.setAppid("xxxxxxxxxxxxx");//公众账号ID  un.setMch_id("xxxxxxxxx");//商户号  un.setNonce_str(UUID.randomUUID().toString().substring(0,30));//随机字符串       <span style="color:#ff0000;"><strong>说明2(见文末)</strong></span>  un.setBody("xxxxxx");//商品描述  un.setOut_trade_no(orderId);//商户订单号  un.setTotal_fee("10000");  //金额需要扩大100倍:1代表支付时是0.01  un.setSpbill_create_ip("xxxxxxxxxxxxx");//终端IP  un.setNotify_url("xxxxxxxxxxxxxx");//支付成功后,回调的地址  un.setSign(createSign(un));//签名un.setTrade_type("NATIVE");//JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付try {//将订单对象转为xml格式StringWriter sw = new StringWriter();JAXBContext context = JAXBContext.newInstance(un.getClass());Marshaller mar = context.createMarshaller();mar.setProperty(mar.JAXB_ENCODING, "utf-8");mar.setProperty(mar.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);mar.marshal(un, sw);/*将xml转换为对象JAXBContext context = JAXBContext.newInstance(UnifiedOrderRequest.class);              Unmarshaller unmarshaller = context.createUnmarshaller();              UnifiedOrderRequest unifiedOrderRequest = (UnifiedOrderRequest)unmarshaller.unmarshal(new StringReader("xml文件"));               */return sw.toString();} catch (JAXBException e) {// TODO Auto-generated catch blocke.printStackTrace();} return null;}/** * 生成数字签名 */private String createSign(UnifiedOrderRequest un) {//创建可排序的Map集合SortedMap<String, String> packageParms = new TreeMap<String, String>();packageParms.put("appid", un.getAppid());packageParms.put("body", un.getBody());packageParms.put("mch_id", un.getMch_id());packageParms.put("nonce_str", un.getNonce_str());packageParms.put("notify_url", un.getNotify_url());packageParms.put("out_trade_no", un.getOut_trade_no());packageParms.put("spbill_create_ip", un.getSpbill_create_ip());packageParms.put("trade_type", un.getTrade_type());packageParms.put("total_fee", un.getTotal_fee());StringBuffer sb = new StringBuffer();//按照字典排序Set se = packageParms.entrySet();//迭代器Iterator iterator = se.iterator();while(iterator.hasNext()){Map.Entry entry = (Entry) iterator.next();String k = (String) entry.getKey();String v = (String) entry.getValue();//为空不参与签名,参数名区分大小写if(null!=v && !"".equals(v)&& !"key".equals(k) && !"sign".equals(k)){sb.append(k+ "="+v+"&");}}/*拼接 key,设置路径:微信商户平台(pay.weixin.com)->账户设置->API安全-->秘钥设置 */sb.append("key="+"xxxxxxxxxxx");MD5Utile md5= new MD5Utile();String sign = md5.getMD5(sb.toString(),"utf-8");return sign;}public String getOrderId() {return orderId;}public void setOrderId(String orderId) {this.orderId = orderId;}}

看到这里,包括二维码的制作,与用户,服务器的交互都已完成。如有不懂,可以私信!