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

一:需求

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

二: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>此处加注解是为了后台xmljie
public class UnifiedOrderRequest { 
		private String appid;			  //ID
		private 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;  //终端Ip
		private 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;				 //商品ID
	private 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);
		//遍历所有的key
		for(String key:maps.keySet()){
			//获得key所对应的value
			String 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){
		//得到统一下单 API
		String codeUrl = httpOrder(orderInfo);
		if(codeUrl!=null){
		//利用 返回的预支付交易链接(codeUrl) 生成扫描的二维码
		try {
			int width =200; //宽200
			int height = 200; //高200
			String 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 block
			e.printStackTrace();
		}
	}
	}
	}
	/**
	 * 调统一下单API
	 */
	private String httpOrder(String orderInfo) {
		//微信支付统一接口
		String url ="https://api.mch.weixin.qq.com/pay/unifiedorder";
		try {
			//连接微信统一支付url
			HttpURLConnection 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转换成Map
			Map<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 block
				e.printStackTrace();
			}
			catch (ParserConfigurationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
			} catch (JAXBException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.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 block
			e.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;
	}
	
	
}

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值