一:需求
满足公司在网页上达到直接微信扫码支付的需求
二: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;
}
}
/**
* 统一下单返回参数
*
*/
<span>此处加注解是为了xml解析</span>
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;
}
}