微信端代码
JS:
//index.js //获取应用实例 var app = getApp() Page({ data: { motto: 'Hello World', userInfo: {} }, onLoad: function () { console.log('onLoad') }, // payoff: function(e){ var that = this; wx.login({ success: function(res) { that.getOpenId(res.code); } }); }, //获取openid getOpenId: function(code){ var that = this; wx.request({ url: 'http://localhost:8080/VoteSystemServer/OnLogin.do', method: 'POST', header: { 'content-type': 'application/x-www-form-urlencoded' }, data: {'code':code}, success: function(res) { var openId = res.data.openid; that.xiadan(openId); } }) }, //下单 xiadan: function(openId){ var that = this; wx.request({ url: 'http://localhost:8080/VoteSystemServer/doPay.do', method: 'POST', header: { 'content-type': 'application/x-www-form-urlencoded' }, data: {'openid':openId}, success: function(res) { var prepay_id = res.data.prepay_id; console.log("统一下单返回 prepay_id:"+prepay_id); that.sign(prepay_id); } }) }, //签名 sign: function(prepay_id){ var that = this; wx.request({ url: 'http://localhost:8080/VoteSystemServer/doSign.do', method: 'POST', header: { 'content-type': 'application/x-www-form-urlencoded' }, data: {'repay_id':prepay_id}, success: function(res) { that.requestPayment(res.data); } }) }, //申请支付 requestPayment: function(obj){ wx.requestPayment({ 'timeStamp': obj.timeStamp, 'nonceStr': obj.nonceStr, 'package': obj.package, 'signType': obj.signType, 'paySign': obj.paySign, 'success':function(res){ }, 'fail':function(res){ } }) } })
WXML:
<!--index.wxml--> <view class="container"> <button bindtap="payoff">支付</button> </view>
JAVA服务端
GetOpenId.java
package com.weixinpay; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder; import com.weixinpay.common.Configure; /** * Servlet implementation class GetOpenId */ public class GetOpenId extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public GetOpenId() { super(); } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String code = request.getParameter("code"); HttpGet httpGet = new HttpGet("https://api.weixin.qq.com/sns/jscode2session?appid="+Configure.getAppID()+"&secret="+Configure.getSecret()+"&js_code="+code+"&grant_type=authorization_code"); //设置请求器的配置 HttpClient httpClient = HttpClients.createDefault(); HttpResponse res = httpClient.execute(httpGet); HttpEntity entity = res.getEntity(); String result = EntityUtils.toString(entity, "UTF-8"); response.getWriter().append(result); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } }
PayResult.java
package com.weixinpay; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import com.weixinpay.common.StreamUtil; /** * 接收支付结果 */ public class PayResult extends HttpServlet { private static final long serialVersionUID = 1L; private static final Logger L = Logger.getLogger(PayResult.class); /** * @see HttpServlet#HttpServlet() */ public PayResult() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub //response.getWriter().append("Served at: ").append(request.getContextPath()); String reqParams = StreamUtil.read(request.getInputStream()); L.info("-------支付结果:"+reqParams); StringBuffer sb = new StringBuffer("<xml><return_code>SUCCESS</return_code><return_msg>OK</return_msg></xml>"); response.getWriter().append(sb.toString()); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } }
Sign.java
package com.weixinpay; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import com.alibaba.fastjson.JSONObject; import com.weixinpay.common.Configure; import com.weixinpay.common.RandomStringGenerator; import com.weixinpay.common.Signature; import com.weixinpay.model.SignInfo; /** * 再签名 */ public class Sign extends HttpServlet { private static final long serialVersionUID = 1L; private static final Logger L = Logger.getLogger(Sign.class); public Sign() { super(); } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { String repay_id = request.getParameter("repay_id"); SignInfo signInfo = new SignInfo(); signInfo.setAppId(Configure.getAppID()); long time = System.currentTimeMillis()/1000; signInfo.setTimeStamp(String.valueOf(time)); signInfo.setNonceStr(RandomStringGenerator.getRandomStringByLength(32)); signInfo.setRepay_id("prepay_id="+repay_id); signInfo.setSignType("MD5"); //生成签名 String sign = Signature.getSign(signInfo); JSONObject json = new JSONObject(); json.put("timeStamp", signInfo.getTimeStamp()); json.put("nonceStr", signInfo.getNonceStr()); json.put("package", signInfo.getRepay_id()); json.put("signType", signInfo.getSignType()); json.put("paySign", sign); L.info("-------再签名:"+json.toJSONString()); response.getWriter().append(json.toJSONString()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); L.error("-------", e); } } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } }
Xiadan.java
package com.weixinpay; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import com.alibaba.fastjson.JSONObject; import com.thoughtworks.xstream.XStream; import com.weixinpay.common.Configure; import com.weixinpay.common.HttpRequest; import com.weixinpay.common.RandomStringGenerator; import com.weixinpay.common.Signature; import com.weixinpay.model.OrderInfo; import com.weixinpay.model.OrderReturnInfo; /** * 统一下单接口 */ public class Xiadan extends HttpServlet { private static final long serialVersionUID = 1L; private static final Logger L = Logger.getLogger(Xiadan.class); /** * @see HttpServlet#HttpServlet() */ public Xiadan() { super(); } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub try { String openid = request.getParameter("openid"); OrderInfo order = new OrderInfo(); order.setAppid(Configure.getAppID()); order.setMch_id(Configure.getMch_id()); order.setNonce_str(RandomStringGenerator.getRandomStringByLength(32)); order.setBody("dfdfdf"); order.setOut_trade_no(RandomStringGenerator.getRandomStringByLength(32)); order.setTotal_fee(10); order.setSpbill_create_ip("123.57.218.54"); order.setNotify_url("https://www.see-source.com/weixinpay/PayResult"); order.setTrade_type("JSAPI"); order.setOpenid(openid); order.setSign_type("MD5"); //生成签名 String sign = Signature.getSign(order); order.setSign(sign); String result = HttpRequest.sendPost("https://api.mch.weixin.qq.com/pay/unifiedorder", order); System.out.println(result); L.info("---------下单返回:"+result); XStream xStream = new XStream(); xStream.alias("xml", OrderReturnInfo.class); OrderReturnInfo returnInfo = (OrderReturnInfo)xStream.fromXML(result); JSONObject json = new JSONObject(); json.put("prepay_id", returnInfo.getPrepay_id()); response.getWriter().append(json.toJSONString()); } catch (Exception e) { e.printStackTrace(); L.error("-------", e); } } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } }
Configure.java
package com.weixinpay.common; public class Configure { private static String key = "你的商户的api秘钥"; //小程序ID private static String appID = "你的小程序id"; //商户号 private static String mch_id = "你的商户号"; // private static String secret = "你的小程序的secret"; public static String getSecret() { return secret; } public static void setSecret(String secret) { Configure.secret = secret; } public static String getKey() { return key; } public static void setKey(String key) { Configure.key = key; } public static String getAppID() { return appID; } public static void setAppID(String appID) { Configure.appID = appID; } public static String getMch_id() { return mch_id; } public static void setMch_id(String mch_id) { Configure.mch_id = mch_id; } }
HttpRequest.java
package com.weixinpay.common; import java.io.IOException; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import javax.net.ssl.X509TrustManager; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder; public class HttpRequest { //连接超时时间,默认10秒 private static final int socketTimeout = 10000; //传输超时时间,默认30秒 private static final int connectTimeout = 30000; /** * post请求 * @throws IOException * @throws ClientProtocolException * @throws NoSuchAlgorithmException * @throws KeyStoreException * @throws KeyManagementException * @throws UnrecoverableKeyException */ public static String sendPost(String url, Object xmlObj) throws ClientProtocolException, IOException, UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException { HttpPost httpPost = new HttpPost(url); //解决XStream对出现双下划线的bug XStream xStreamForRequestPostData = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("-_", "_"))); xStreamForRequestPostData.alias("xml", xmlObj.getClass()); //将要提交给API的数据对象转换成XML格式数据Post给API String postDataXML = xStreamForRequestPostData.toXML(xmlObj); //得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别 StringEntity postEntity = new StringEntity(postDataXML, "UTF-8"); httpPost.addHeader("Content-Type", "text/xml"); httpPost.setEntity(postEntity); //设置请求器的配置 RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build(); httpPost.setConfig(requestConfig); HttpClient httpClient = HttpClients.createDefault(); HttpResponse response = httpClient.execute(httpPost); HttpEntity entity = response.getEntity(); String result = EntityUtils.toString(entity, "UTF-8"); return result; } /** * 自定义证书管理器,信任所有证书 * @author pc * */ public static class MyX509TrustManager implements X509TrustManager { @Override public void checkClientTrusted( java.security.cert.X509Certificate[] arg0, String arg1) throws java.security.cert.CertificateException { // TODO Auto-generated method stub } @Override public void checkServerTrusted( java.security.cert.X509Certificate[] arg0, String arg1) throws java.security.cert.CertificateException { // TODO Auto-generated method stub } @Override public java.security.cert.X509Certificate[] getAcceptedIssuers() { // TODO Auto-generated method stub return null; } } }
MD5.java
package com.weixinpay.common; import java.security.MessageDigest; public class MD5 { private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"}; /** * 转换字节数组为16进制字串 * @param b 字节数组 * @return 16进制字串 */ public static String byteArrayToHexString(byte[] b) { StringBuilder resultSb = new StringBuilder(); for (byte aB : b) { resultSb.append(byteToHexString(aB)); } return resultSb.toString(); } /** * 转换byte到16进制 * @param b 要转换的byte * @return 16进制格式 */ private static String byteToHexString(byte b) { int n = b; if (n < 0) { n = 256 + n; } int d1 = n / 16; int d2 = n % 16; return hexDigits[d1] + hexDigits[d2]; } /** * MD5编码 * @param origin 原始字符串 * @return 经过MD5加密之后的结果 */ public static String MD5Encode(String origin) { String resultString = null; try { resultString = origin; MessageDigest md = MessageDigest.getInstance("MD5"); resultString = byteArrayToHexString(md.digest(resultString.getBytes())); } catch (Exception e) { e.printStackTrace(); } return resultString; } }
RandomStringGenerator.java
package com.weixinpay.common; import java.util.Random; /** * 随机字符串生成 * * */ public class RandomStringGenerator { /** * 获取一定长度的随机字符串 * @param length 指定字符串长度 * @return 一定长度的字符串 */ public static String getRandomStringByLength(int length) { String base = "abcdefghijklmnopqrstuvwxyz0123456789"; Random random = new Random(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < length; i++) { int number = random.nextInt(base.length()); sb.append(base.charAt(number)); } return sb.toString(); } }
Signature.java
package com.weixinpay.common; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.Map; import org.apache.log4j.Logger; import com.thoughtworks.xstream.annotations.XStreamAlias; /** * 签名 * * */ public class Signature { private static final Logger L = Logger.getLogger(Signature.class); /** * 签名算法 * @param o 要参与签名的数据对象 * @return 签名 * @throws IllegalAccessException */ public static String getSign(Object o) throws IllegalAccessException { ArrayList<String> list = new ArrayList<String>(); Class cls = o.getClass(); Field[] fields = cls.getDeclaredFields(); for (Field f : fields) { f.setAccessible(true); if (f.get(o) != null && f.get(o) != "") { String name = f.getName(); XStreamAlias anno = f.getAnnotation(XStreamAlias.class); if(anno != null) name = anno.value(); list.add(name + "=" + f.get(o) + "&"); } } int size = list.size(); String [] arrayToSort = list.toArray(new String[size]); Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER); StringBuilder sb = new StringBuilder(); for(int i = 0; i < size; i ++) { sb.append(arrayToSort[i]); } String result = sb.toString(); result += "key=" + Configure.getKey(); System.out.println("签名数据:"+result); result = MD5.MD5Encode(result).toUpperCase(); return result; } public static String getSign(Map<String,Object> map){ ArrayList<String> list = new ArrayList<String>(); for(Map.Entry<String,Object> entry:map.entrySet()){ if(entry.getValue()!=""){ list.add(entry.getKey() + "=" + entry.getValue() + "&"); } } int size = list.size(); String [] arrayToSort = list.toArray(new String[size]); Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER); StringBuilder sb = new StringBuilder(); for(int i = 0; i < size; i ++) { sb.append(arrayToSort[i]); } String result = sb.toString(); result += "key=" + Configure.getKey(); //Util.log("Sign Before MD5:" + result); result = MD5.MD5Encode(result).toUpperCase(); //Util.log("Sign Result:" + result); return result; } }
StreamUtil.java
package com.weixinpay.common; import java.io.ByteArrayOutputStream; import java.io.InputStream; public class StreamUtil { public static String read(InputStream is){ try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); int len = 0; byte[] buffer = new byte[512]; while((len = is.read(buffer)) != -1){ baos.write(buffer, 0, len); } return new String(baos.toByteArray(), 0, baos.size(), "utf-8"); }catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return ""; } }
OrderInfo.java
package com.weixinpay.model; /** * 预订单 * * * */ public class OrderInfo { private String appid;// 小程序ID private String mch_id;// 商户号 private String nonce_str;// 随机字符串 private String sign_type;//签名类型 private String sign;// 签名 private String body;// 商品描述 private String out_trade_no;// 商户订单号 private int total_fee;// 标价金额 ,单位为分 private String spbill_create_ip;// 终端IP private String notify_url;// 通知地址 private String trade_type;// 交易类型 private String openid;//用户标识 public String getSign_type() { return sign_type; } public void setSign_type(String sign_type) { this.sign_type = sign_type; } public String getOpenid() { return openid; } public void setOpenid(String openid) { this.openid = openid; } public String getAppid() { return appid; } public void setAppid(String appid) { this.appid = appid; } public String getMch_id() { return mch_id; } public void setMch_id(String mch_id) { this.mch_id = mch_id; } public String getNonce_str() { return nonce_str; } public void setNonce_str(String nonce_str) { this.nonce_str = nonce_str; } public String getSign() { return sign; } public void setSign(String sign) { this.sign = sign; } public String getBody() { return body; } public void setBody(String body) { this.body = body; } public String getOut_trade_no() { return out_trade_no; } public void setOut_trade_no(String out_trade_no) { this.out_trade_no = out_trade_no; } public int getTotal_fee() { return total_fee; } public void setTotal_fee(int total_fee) { this.total_fee = total_fee; } public String getSpbill_create_ip() { return spbill_create_ip; } public void setSpbill_create_ip(String spbill_create_ip) { this.spbill_create_ip = spbill_create_ip; } public String getNotify_url() { return notify_url; } public void setNotify_url(String notify_url) { this.notify_url = notify_url; } public String getTrade_type() { return trade_type; } public void setTrade_type(String trade_type) { this.trade_type = trade_type; } }
OrderReturnInfo.java
package com.weixinpay.model; public class OrderReturnInfo { private String return_code; private String return_msg; private String result_code; private String appid; private String mch_id; private String nonce_str; private String sign; private String prepay_id; private String trade_type; public String getReturn_code() { return return_code; } public void setReturn_code(String return_code) { this.return_code = return_code; } public String getReturn_msg() { return return_msg; } public void setReturn_msg(String return_msg) { this.return_msg = return_msg; } public String getResult_code() { return result_code; } public void setResult_code(String result_code) { this.result_code = result_code; } public String getAppid() { return appid; } public void setAppid(String appid) { this.appid = appid; } public String getMch_id() { return mch_id; } public void setMch_id(String mch_id) { this.mch_id = mch_id; } public String getNonce_str() { return nonce_str; } public void setNonce_str(String nonce_str) { this.nonce_str = nonce_str; } public String getSign() { return sign; } public void setSign(String sign) { this.sign = sign; } public String getPrepay_id() { return prepay_id; } public void setPrepay_id(String prepay_id) { this.prepay_id = prepay_id; } public String getTrade_type() { return trade_type; } public void setTrade_type(String trade_type) { this.trade_type = trade_type; } }
SignInfo.java
package com.weixinpay.model; import com.thoughtworks.xstream.annotations.XStreamAlias; /** * 签名信息 * * */ public class SignInfo { private String appId;//小程序ID private String timeStamp;//时间戳 private String nonceStr;//随机串 @XStreamAlias("package") private String repay_id; private String signType;//签名方式 public String getAppId() { return appId; } public void setAppId(String appId) { this.appId = appId; } public String getTimeStamp() { return timeStamp; } public void setTimeStamp(String timeStamp) { this.timeStamp = timeStamp; } public String getNonceStr() { return nonceStr; } public void setNonceStr(String nonceStr) { this.nonceStr = nonceStr; } public String getRepay_id() { return repay_id; } public void setRepay_id(String repay_id) { this.repay_id = repay_id; } public String getSignType() { return signType; } public void setSignType(String signType) { this.signType = signType; } }
log4j.properties
log4j.rootLogger = DEBUG,file,stdout log4j.appender.file = org.apache.log4j.RollingFileAppender log4j.appender.file.File = /Users/zuoliangzhu/logs/weixinpay.log log4j.appender.file.MaxFileSize = 10MB log4j.appender.file.MaxBackupIndex = 20 log4j.appender.file.Append = true log4j.appender.file.layout = org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern = %-d{yyyy-MM-dd HH\:mm\:ss} [%c]-[%p] [%t] (%F\:%L)->%m %n log4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
POM.XML
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.weixinpay</groupId> <artifactId>weixinpay</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>weixinpay Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.16</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.3.5</version> </dependency> <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.4.7</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.9</version> </dependency> </dependencies> <build> <finalName>weixinpay</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.1</version> <executions> <execution> <id>copy-xmls</id> <phase>process-sources</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> <outputDirectory>${basedir}/target/classes</outputDirectory> <resources> <resource> <directory>${basedir}/src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> </resources> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>