以前写过一篇设置微信二维码失效时间的博客,最近又要新增微信退款的功能,于是又重新整理了一下前面的微信二维码扫码支付功能,感觉整体的实现方式都能够掌控了,于是将具体的源码拿出来分享一下。

开发之前,一定要先阅读这篇说明文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_3

此处使用的微信二维码扫码支付功能,调用的是微信提供的“统一下单”接口,参考的微信官方文档是:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1  。

实现后的功能是这样的:

      

这个功能涉及到三个接口:

接口一:"http://www.*.com/项目名/pay/toWxPay.do",该接口调用微信支付统一下单接口,生成微信二维码并展示给用户,也就是前面那张图中,当用户点击微信支付图片的时候,就要调用该接口。注意,我这个接口使用的是springMVC来控制页面的跳转的,所以调用者调用这个接口时,应该使用表单提交的方式,发送post请求。

接口二:"http://www.*.com/项目名/pay/wxQuery.do",该接口用于查询当前订单是否支付成功,前端需要定时调用这个接口(比如每隔1秒调用一次),支付成功则关闭这个二维码页面,还未支付则继续调用这个接口。因为我的网站提供了多种支付方式,所有我并没有调用微信支付提供的订单查询接口https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_2,
因为不管订单最终是用哪种方式支付的,这个二维码最终都是要关闭,由此降低一个订单被多次支付的风险。虽然订单被重复支付后,可以申请退款,但是你退款的操作也要耗费资源,既然如此,为什么不一开始就降低这种风险呢。

接口三:"http://www.*.com/项目名/pay/wxRedirect.do",该接口是微信支付成功后的回调接口,就是用户扫码支付成功后,微信平台确认收到了钱,他平台那边处理完之后(比如做双方的扣款,转账,记录流水等操作),就会把这个处理的结果告诉我们,那么怎么告诉呢,就是通过这个回调接口了。所以需要注意,这个回调接口不要做登录拦截!!!

下面直接上代码,首先是导入依赖的jar包:

<!-- 微信支付开始-->
<!-- https://mvnrepository.com/artifact/com.google.zxing/core -->
<dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jdom/jdom -->
<dependency><groupId>org.jdom</groupId><artifactId>jdom</artifactId><version>1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/xml-apis/xml-apis -->
<dependency><groupId>xml-apis</groupId><artifactId>xml-apis</artifactId><version>1.0.b2</version>
</dependency>
<!-- 微信支付结束-->

然后是三个接口:

package wxpay;import java.io.*;
import java.util.*;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;@Controller
@RequestMapping("/pay")
public class PayController {private static final Logger logger = Logger.getLogger(PayController.class);/*** 接口一:调用微信Native支付统一下单接口,生成微信二维码*/@RequestMapping(value = "/toWxPay", method = RequestMethod.POST)public String toWxPay(String orderId,String userId,Double amount,Model model,HttpServletRequest request, HttpServletResponse response) throws Exception {String url="weixin";//默认是网页端的请求,此时你的webapp目录下需要一个weixin.jsp文件,这个页面也是你展示二维码的那个页面try {if(StringUtils.isBlank(orderId)||StringUtils.isBlank(userId)||amount==null){model.addAttribute("errorMsg", "缺少必要参数");return url;}//个人核心业务隐身符,此处需要拿着orderId和userId为查询条件去数据库查询这个订单是否存在,//判断是否已经支付过了,同时还要携带这个金额是否已数据库中记录的商品实际金额一致//如果检验不通过,就不执行后面的操作//默认失效时间是订单失效的时间,这个时间需要从你的数据库查询这个订单的剩余有效时间,此处暂时设置成30分钟Long expireTime=30*60L;String key="WX_RD_CODE_"+orderId;Long ttl = RedisUtils.ttl(key);//如果二维码还没有失效,就使用没有失效的二维码if(ttl>10){model.addAttribute("codeUrl", RedisUtils.get(key));//二维码的urlmodel.addAttribute("expire", ttl.intValue());//二维码有效期return url;}//因为通常,一个网站接入微信支付,pc端接入的是微信Native支付,//微信公众号端接入的是JSAPI支付,app接入的是微信app支付,此外还有H5支付。//开发时遇到同一个订单号,如果开始使用二维码支付,获取二维码后没有扫码,//二维码依旧有效的时候,公众号那边发起JSAPI支付会失败。//不可能同一个订单使用不同的订单号,这个本身就很矛盾,//所以还是订单号后面追加标识用于区分,当然了支付回调接口在接收的时候//也要通过处理获取真实的订单号。String outTrandNo=orderId+"_NATIVE";//如果原来的二维码失效了,就重新生成二维码String codeUrl = GenerateQrCodeUtil.getCodeurl(request,expireTime,outTrandNo,userId,amount);//生成的图片路径logger.info("生成的图片路径:"+codeUrl);String webParentPath = new File(request.getSession().getServletContext().getRealPath("/")).getParent();// 当前WEB环境的上层目录String xiangmuName = request.getContextPath();// 项目名称String fileUrl = GenerateQrCodeUtil.encodeQrcode(codeUrl,response,webParentPath +xiangmuName+ "/img","wxImg/");//二维码保存在/webapp/img/wxImg/ 文件夹下if(fileUrl != null){codeUrl="/img/"+fileUrl;model.addAttribute("codeUrl",codeUrl);//二维码的urlmodel.addAttribute("expire", ttl.intValue());//二维码有效期//设置一个标志,用来保存二维码的路径RedisUtils.set(key, codeUrl, expireTime.intValue());}} catch (Exception e) {logger.info("调用微信二维码失败:"+e.getMessage());throw e;}finally{//关闭保护RedisUtils.set(orderId, "1",60*60*24*50);}return url;}/*** 接口二:查询订单是否支付成功* 查询付款是否成功,主要是跳转到微信支付二维码页面之后,需要定时去查询这个订单是否已经支付成功,* 订单支付成功之后,前端需要及时关闭这个二维码页面。由于我这边有多种支付方式,所有后台并没有调用* 微信支付提供的订单查询接口,因为不管订单最终是用哪种方式支付的,这个二维码最终都是要关闭的*/@RequestMapping(value = "wxQuery")@ResponseBodypublic Result wxQuery(HttpServletResponse response , String orderId) {response.setHeader("Access-Control-Allow-Origin", "*");Result result = new Result();try {if(StringUtils.isBlank(orderId)){result.setSuccess(false);result.setMsg("缺少必要参数");return result;}Long ttl = RedisUtils.ttl("PAY_" + orderId);//判断是否付款成功,付款成功返回ture;未付款返回falseresult.setSuccess(ttl>1);} catch (Exception e) {result.setSuccess(false);}return result;}/*** 接口三:微信支付回调接口* 注意!注意!注意!这个接口不要做权限拦截操作,要直接放行*/@RequestMapping(value = "wxRedirect")@ResponseBodypublic void wxRedirect(HttpServletRequest req, HttpServletResponse resp) throws Exception {logger.info("微信支付回调开始了");// 创建支付应答对象ResponseHandler resHandler = new ResponseHandler(req, resp);// 读取参数InputStream inputStream = req.getInputStream();StringBuffer sb = new StringBuffer();BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));String s;while ((s = in.readLine()) != null) {sb.append(s);}in.close();inputStream.close();// 解析xml成mapMap<String, String> m =XMLUtil.doXMLParse(sb.toString());// 过滤空 设置 TreeMapSortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();Iterator<String> it = m.keySet().iterator();while (it.hasNext()) {String parameter = it.next();String parameterValue = m.get(parameter);String v = "";if (null != parameterValue) {v = parameterValue.trim();}packageParams.put(parameter, v);}// 判断签名是否正确if (!PayCommonUtil.isTenpaySign("UTF-8", packageParams, Constant.MCH_KEY)) {logger.info("回调后发现签名失败了...");return ;}if (!"SUCCESS".equals(packageParams.get("result_code"))) {// 错误时,返回结果未签名,记录retcode、retmsg看失败详情。logger.info("查询验证签名失败或业务错误");return;}// 到这里,说明是支付成功了// 执行自己的业务逻辑// 通知idString mch_id = (String) packageParams.get("mch_id");String openid = (String) packageParams.get("openid");//付款方的openIdString is_subscribe = (String) packageParams.get("is_subscribe");//是否关注公众号String out_trade_no = (String) packageParams.get("out_trade_no"); // 自己网站定义的订单号String attach = (String) packageParams.get("attach");//读取附带的参数String total_fee = (String) packageParams.get("total_fee");//支付金额String transaction_id = (String) packageParams.get("transaction_id");//微信那边生成的流水号,注意需要保存logger.info("attach:" + attach + ",mch_id:" + mch_id + ",openid:" + openid + ",is_subscribe:" + is_subscribe + ",out_trade_no:" + out_trade_no + ",total_fee:" + total_fee + ",transaction_id:"+ transaction_id);//因为前面已经有定义格式:网站的流水号_支付标识 out_trade_no=out_trade_no.split("_")[0];logger.info("真正的流水号是:"+out_trade_no);// ----------- 处理业务开始 --------------logger.info("处理业务逻辑开始。。。");// 处理数据库逻辑,注意交易单不要重复处理,注意判断返回金额try {//注意我们原来定义的参数形式是这样的:orderId+","+userId+","+amount+",wxpay";String[] str = attach.split(",");if (str == null || str.length != 4) {logger.info("微信回调的attach参数错误,可能是非法请求");return;}String orderId = str[0];//自己网站定义的订单号String userId = str[1];//这个订单号对应的用户userIddouble amount = Double.parseDouble(str[2]);//订单金额String type = str[3];//用于标识此次微信支付是支付那种类型的金额,由自己定义;//执行到这里,应该单独往表中添加一条记录,用于记录微信付款成功了,注意这里应该使用独立的事务,// 防止后面的业务失败时,导致整个事务回滚。// 主要是为了将来排查错误使用,比如同一个订单,但是前面2分钟用户已经使用支付宝支付了,现在用户又用//微信支付了一遍,此时回调操作怎么处理呢?所以类似的这个回调成功的记录都必须要有,后面退款的时候可能需要用if ("wxpay".equals(type)) {logger.info("进入微信支付后续处理逻辑");//执行你自己的业务逻辑,比如设置订单为已支付,添加资金流水等//······//设置支付成功标志,不管你用哪种支付方式,只要这个订单支付成功了,就要设置这个标志RedisUtils.set("PAY_"+orderId,"1",60*60*24*30);//设置有效期30天,具体时间看你自己的业务}} catch (Exception e) {logger.info("回调错误:"+ e.getMessage());}logger.info("商家流水号:" + out_trade_no);// 其他字段也可用类似方式获取logger.info("FrontRcvResponse前台接收报文返回结束");// ------------------------------// 处理业务完毕// ------------------------------// 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.String resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";resHandler.sendToCFT(resXml);}}

Result.java实体类不分享,可以自己创建一个;

RedisUtils工具类看我的另一篇博客:Jedis常用工具类,包含一些具有事务的设置值的方法;

WXUtil.java类

package wxpay;import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;
import java.util.Map.Entry;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** 微信开发相关工具* */
public class WXUtil {private static Logger log = LoggerFactory.getLogger(WXUtil.class);/*** 把HashMap转换成xml* @param arr* @return* #time:下午5:32:36**/public static String ArrayToXml(SortedMap<String, String> arr) {String xml = "<xml>";Iterator<Entry<String, String>> iter = arr.entrySet().iterator();while (iter.hasNext()) {Entry<String, String> entry = iter.next();String key = entry.getKey();String val = entry.getValue();if ("attach".equalsIgnoreCase(key)||"body".equalsIgnoreCase(key)||"sign".equalsIgnoreCase(key)) {xml += "<" + key + ">" + val + "</" + key + ">";} elsexml += "<" + key + "><![CDATA[" + val + "]]></" + key + ">";}xml += "</xml>";return xml;}/*** @date 2016-5-5下午2:32:05* @Description:将请求参数转换为xml格式的string* @param parameters*            请求参数* @return*/@SuppressWarnings("rawtypes")public static String getRequestXml(SortedMap<Object, Object> parameters) {StringBuffer sb = new StringBuffer();sb.append("<xml>");Set es = parameters.entrySet();Iterator it = es.iterator();while (it.hasNext()) {Map.Entry entry = (Map.Entry) it.next();String k = (String) entry.getKey();String v = (String) entry.getValue();if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k)|| "sign".equalsIgnoreCase(k)) {sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");} else {sb.append("<" + k + ">" + v + "</" + k + ">");}}sb.append("</xml>");return sb.toString();}/*** 根据内容类型判断文件扩展名* * @param contentType*            内容类型* @return*/public static String getFileExt(String contentType) {String fileExt = "";if ("image/jpeg".equals(contentType))fileExt = ".jpg";else if ("audio/mpeg".equals(contentType))fileExt = ".mp3";else if ("audio/amr".equals(contentType))fileExt = ".amr";else if ("video/mp4".equals(contentType))fileExt = ".mp4";else if ("video/mpeg4".equals(contentType))fileExt = ".mp4";return fileExt;}/*** 获取接口访问凭证* * @param appid*            凭证* @param appsecret*            密钥* @return*/public static Token getToken(String appid, String appsecret) {Token token = null;String requestUrl = Constant.TOKEN_URL.replace("APPID", appid).replace("APPSECRET", appsecret);// 发起GET请求获取凭证JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, "GET", null);if (null != jsonObject) {try {token = new Token();token.setAccessToken(jsonObject.getString("access_token"));token.setExpiresIn(jsonObject.getInt("expires_in"));} catch (JSONException e) {token = null;// 获取token失败log.error("获取token失败 errcode:{} errmsg:{}",jsonObject.getInt("errcode"),jsonObject.getString("errmsg"));}}return token;}/*** 获取验证签名* * @param map* @return*/public static String createSign(Map<String, String> map) {SortedMap<String, String> packageParams = new TreeMap<String, String>();for (Map.Entry<String, String> m : map.entrySet()) {packageParams.put(m.getKey(), m.getValue().toString());}StringBuffer sb = new StringBuffer();Set<?> es = packageParams.entrySet();Iterator<?> it = es.iterator();while (it.hasNext()) {@SuppressWarnings("rawtypes")Map.Entry entry = (Map.Entry) it.next();String k = (String) entry.getKey();String v = (String) entry.getValue();if (!StringUtils.isEmpty(v) && !"sign".equals(k)&& !"key".equals(k)) {sb.append(k + "=" + v + "&");}}sb.append("key=" + Constant.MCH_KEY);String sign = CommonUtil.MD5Encode(sb.toString(), Constant.CHARSET).toUpperCase();return sign;}/*** 创建订单号* * @return*/public static String getOrderNo() {String order = Constant.MCH_ID+ new SimpleDateFormat("yyyyMMdd").format(new Date());Random r = new Random();for (int i = 0; i < 10; i++) {order += r.nextInt(9);}return order;}/*** 拼接字符串成XML格式* * @param map* @return*/public static String createXML(Map<String, String> map) {String xml = "<xml>";Set<String> set = map.keySet();Iterator<String> i = set.iterator();while (i.hasNext()) {String str = i.next();xml += "<" + str + ">" + "<![CDATA[" + map.get(str) + "]]>" + "</"+ str + ">";}xml += "</xml>";return xml;}/*** 获取时间戳* * @return*/public static String getTimestamp() {return CommonUtil.toString(System.currentTimeMillis());}public static String createTimestamp() {return Long.toString(System.currentTimeMillis() / 1000);}/*** nonceStr生成签名的随机串* * @return*/public static String getNoncestr() {return CommonUtil.buildRandom();}public static String createNoncestr() {return UUID.randomUUID().toString();}/*** 获取非网页授权access_token* * @param appid* @param appsecret* @return*/public static Token getAccessTokenNoAuth(String appid, String appsecret) {return getToken(appid, appsecret);}/*** 校验签名* * @param jsapi_ticket* @param url* @return*/public static Map<String, String> sign(String jsapi_ticket, String url) {Map<String, String> ret = new HashMap<String, String>();String nonce_str = createNoncestr();String timestamp = createTimestamp();String string1;String signature = "";// 注意这里参数名必须全部小写,且必须有序string1 = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonce_str+ "&timestamp=" + timestamp + "&url=" + url;System.out.println(string1);try {MessageDigest crypt = MessageDigest.getInstance("SHA-1");crypt.reset();crypt.update(string1.getBytes("UTF-8"));signature = CommonUtil.byteToHex(crypt.digest());} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (UnsupportedEncodingException e) {e.printStackTrace();}ret.put("url", url);ret.put("jsapi_ticket", jsapi_ticket);ret.put("nonceStr", nonce_str);ret.put("timestamp", timestamp);ret.put("signature", signature);return ret;}/*** 校验签名* * @param signature*            微信加密签名* @param timestamp*            时间戳* @param nonce*            随机数* @return*/public static boolean checkSignature(String signature, String timestamp,String nonce) {// 对token、timestamp和nonce按字典排序String[] paramArr = new String[] { Constant.TOKEN, timestamp, nonce };Arrays.sort(paramArr);// 将排序后的结果拼接成一个字符串String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]);String ciphertext = null;try {MessageDigest md = MessageDigest.getInstance("SHA-1");// 对接后的字符串进行sha1加密byte[] digest = md.digest(content.toString().getBytes());ciphertext = CommonUtil.byteToStr(digest);} catch (NoSuchAlgorithmException e) {e.printStackTrace();}// 将sha1加密后的字符串与signature进行对比return ciphertext != null ? ciphertext.equals(signature.toUpperCase()): false;}/*** 验证签名。* * @param signature* @param timestamp* @param nonce* @return*/public static String getSignature(String sKey) throws Exception {String ciphertext = null;MessageDigest md = MessageDigest.getInstance("SHA-1");byte[] digest = md.digest(sKey.toString().getBytes());ciphertext = CommonUtil.byteToStr(digest);return ciphertext.toLowerCase();}/*** 获得分享链接的签名。* * @param ticket* @param nonceStr* @param timeStamp* @param url* @return* @throws Exception*/public static String getSignature(String ticket, String nonceStr,long timeStamp, String url) throws Exception {String sKey = "jsapi_ticket=" + ticket + "&noncestr=" + nonceStr+ "timestamp=" + timeStamp + "&url=" + url;return getSignature(sKey);}
}
Token.java类
package wxpay;/*** 凭证*/
public class Token {// 接口访问凭证private String accessToken;// 凭证有效期,单位:秒private int expiresIn;public String getAccessToken() {return accessToken;}public void setAccessToken(String accessToken) {this.accessToken = accessToken;}public int getExpiresIn() {return expiresIn;}public void setExpiresIn(int expiresIn) {this.expiresIn = expiresIn;}
}

GenerateQrCodeUtil.java类:

package wxpay;import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.*;import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;public class GenerateQrCodeUtil {private static final Logger logger = Logger.getLogger(GenerateQrCodeUtil.class);private static final int WHITE = 0xFFFFFFFF;private static final int BLACK = 0xFF000000;private static BufferedImage toBufferedImage(BitMatrix matrix) {int width = matrix.getWidth();int height = matrix.getHeight();BufferedImage image = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);for (int x = 0; x < width; x++) {for (int y = 0; y < height; y++) {image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);}}return image;}public static String encodeQrcode(String content, HttpServletResponse response,String webParentPath,String fileDir) {response.setCharacterEncoding("utf-8");if (StringUtils.isBlank(content))return null;MultiFormatWriter multiFormatWriter = new MultiFormatWriter();Map<EncodeHintType, String> hints = new HashMap<EncodeHintType, String>();hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // �����ַ��������BitMatrix bitMatrix = null;String fileUrl = null;try {bitMatrix = multiFormatWriter.encode(content,BarcodeFormat.QR_CODE, 300, 300, hints);BufferedImage image = toBufferedImage(bitMatrix);if(fileDir != null){FileOutputStream fos = null;try {File f = new File(webParentPath+File.separator+fileDir);if (!f.exists()) {f.mkdir();}fileUrl = fileDir+UUID.randomUUID().toString()+".png";fos = new FileOutputStream(webParentPath+File.separator+fileUrl);ImageIO.write(image, "png", fos);} catch (IOException e) {e.printStackTrace();} finally {if(fos != null){try {fos.close();} catch (IOException e) {e.printStackTrace();}}}}else{try {ImageIO.write(image, "png", response.getOutputStream());} catch (IOException e) {e.printStackTrace();}}} catch (WriterException e1) {e1.printStackTrace();}return fileUrl;}static String getOrderExpireTime(Long expire){SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");Date now = new Date();Date afterDate = new Date(now .getTime() + expire);return sdf.format(afterDate );}public static String getCodeurl( HttpServletRequest request,long time, String orderId,String userId,Double amount) {String attach = orderId+","+userId+","+amount+",wxpay";//附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用。String totalFee = getMoney(amount+"");//订单总金额,单位为分,详见支付金额String spbill_create_ip = request.getRemoteAddr();//支持IPV4和IPV6两种格式的IP地址。用户的客户端IPString notify_url = "https://www.域名.cn/项目名/pay/wxRedirect";//异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。String trade_type = "NATIVE";//交易类型String app_id= Constant.APP_ID;//微信支付分配的公众账号ID(企业号corpid即为此appId)String app_secret=Constant.APP_SECRET;//微信公众号的appsecretString mch_id = Constant.MCH_ID;//微信支付分配的商户号String mch_key=Constant.MCH_KEY;String nonce_str = WXUtil.createNoncestr().substring(1, 32);//随机字符串,长度要求在32位以内。String body = "平台-运费";//商品简单描述,该字段请按照规范传递,具体请见参数规定String expireTime=getOrderExpireTime(time*1000);//设置二维码超时失效时间String out_trade_no = orderId;//你自己平台生成的订单号,要求32个字符内,只能是数字、大小写字母_-|* 且在同一个商户号下唯一SortedMap<String, String> packageParams = new TreeMap<String, String>();packageParams.put("appid", app_id);packageParams.put("mch_id", mch_id);packageParams.put("nonce_str", nonce_str);packageParams.put("body", body);packageParams.put("attach", attach);packageParams.put("out_trade_no", out_trade_no);packageParams.put("total_fee", totalFee);packageParams.put("spbill_create_ip", spbill_create_ip);packageParams.put("notify_url", notify_url);packageParams.put("trade_type", trade_type);packageParams.put("time_expire", expireTime);//设置二维码超时失效时间String sign = WXUtil.createSign(packageParams);logger.info("生成的签名是:"+sign);packageParams.put("sign", sign);String xml =WXUtil.ArrayToXml(packageParams);logger.info("map转换成xml的结果:"+xml);String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";return GetWxOrderno.getCodeUrl(createOrderURL, xml);}public static String getMoney(String amount) {if (amount == null) {return "";}String currency = amount.replaceAll("\\$|\\¥|\\,", ""); int index = currency.indexOf(".");int length = currency.length();Long amLong = 0l;if (index == -1) {amLong = Long.valueOf(currency + "00");} else if (length - index >= 3) {amLong = Long.valueOf((currency.substring(0, index + 3)).replace(".", ""));} else if (length - index == 2) {amLong = Long.valueOf((currency.substring(0, index + 2)).replace(".", "") + 0);} else {amLong = Long.valueOf((currency.substring(0, index + 1)).replace(".", "") + "00");}return amLong.toString();}public String localIp() {String ip = null;Enumeration<?> allNetInterfaces;try {allNetInterfaces = NetworkInterface.getNetworkInterfaces();while (allNetInterfaces.hasMoreElements()) {NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();List<InterfaceAddress> InterfaceAddress = netInterface.getInterfaceAddresses();for (InterfaceAddress add : InterfaceAddress) {InetAddress Ip = add.getAddress();if (Ip != null && Ip instanceof Inet4Address) {ip = Ip.getHostAddress();}}}} catch (SocketException e) {e.printStackTrace();}return ip;}@SuppressWarnings("rawtypes")public static String createSign(SortedMap<String, String> packageParams) {StringBuffer sb = new StringBuffer();Set es = packageParams.entrySet();Iterator it = es.iterator();while (it.hasNext()) {Map.Entry entry = (Map.Entry) it.next();String k = (String) entry.getKey();String v = (String) entry.getValue();if (null != v && !"".equals(v) && !"sign".equals(k)&& !"key".equals(k)) {sb.append(k + "=" + v + "&");}}sb.append("key=" +Constant.MCH_KEY);String sign = MD5Encode(sb.toString(), "GBK").toUpperCase();return sign;}private static String byteArrayToHexString(byte b[]) {StringBuffer resultSb = new StringBuffer();for (int i = 0; i < b.length; i++)resultSb.append(byteToHexString(b[i]));return resultSb.toString();}private static String byteToHexString(byte b) {int n = b;if (n < 0)n += 256;int d1 = n / 16;int d2 = n % 16;return hexDigits[d1] + hexDigits[d2];}public static String MD5Encode(String origin, String charsetname) {String resultString = null;try {resultString = new String(origin);MessageDigest md = MessageDigest.getInstance("MD5");if (charsetname == null || "".equals(charsetname))resultString = byteArrayToHexString(md.digest(resultString.getBytes()));elseresultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));} catch (Exception exception) {}return resultString;}private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5","6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
}

GetWxOrderno.java类

package wxpay;import java.io.StringReader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.xml.sax.InputSource;public class GetWxOrderno {private static Logger logger = Logger.getLogger(GetWxOrderno.class);public static DefaultHttpClient httpclient;static {httpclient = new DefaultHttpClient();httpclient = (DefaultHttpClient) HttpClientConnectionManager.getSSLInstance(httpclient);}public static String getPayNo(String url, String xmlParam) {DefaultHttpClient client = new DefaultHttpClient();client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS,true);HttpPost httpost = HttpClientConnectionManager.getPostMethod(url);String prepay_id = "";try {httpost.setEntity(new StringEntity(xmlParam, "UTF-8"));HttpResponse response = httpclient.execute(httpost);String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");Map<String, String> map = parseXmlToMap(jsonStr);prepay_id = map.get("prepay_id");} catch (Exception e) {e.printStackTrace();}return prepay_id;}public static Map<String, String> getReturnUrl(String url, String xmlParam) {Map<String, String> map = new HashMap<>();DefaultHttpClient client = new DefaultHttpClient();client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true);HttpPost httpost = HttpClientConnectionManager.getPostMethod(url);try {httpost.setEntity(new StringEntity(xmlParam, "UTF-8"));HttpResponse response = httpclient.execute(httpost);String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");map = parseXmlToMap(jsonStr);} catch (Exception e) {e.printStackTrace();}return map;}public static String getCodeUrl(String url, String xmlParam) {DefaultHttpClient client = new DefaultHttpClient();client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS,true);HttpPost httpost = HttpClientConnectionManager.getPostMethod(url);String code_url = "";try {httpost.setEntity(new StringEntity(xmlParam, "UTF-8"));HttpResponse response = httpclient.execute(httpost);String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");Map<String, String> map = parseXmlToMap(jsonStr);code_url = map.get("code_url");} catch (Exception e) {e.printStackTrace();}return code_url;}public static String getOrderQuery(String url, String xmlParam) {DefaultHttpClient client = new DefaultHttpClient();client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS,true);HttpPost httpost = HttpClientConnectionManager.getPostMethod(url);String success = "";try {httpost.setEntity(new StringEntity(xmlParam, "UTF-8"));HttpResponse response = httpclient.execute(httpost);String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");Map<String, String> map = parseXmlToMap(jsonStr);success = map.get("return_code");} catch (Exception e) {e.printStackTrace();}return success;}public static Map<String, String> parseXmlToMap(String xml)throws Exception {if (StringUtils.isBlank(xml)) {return null;}Map<String, String> m = new HashMap<String, String>();StringReader read = new StringReader(xml);// 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入InputSource source = new InputSource(read);// 创建一个新的SAXBuilderSAXBuilder sb = new SAXBuilder();// 通过输入源构造一个DocumentDocument doc;doc = (Document) sb.build(source);Element root = doc.getRootElement();// 指向根节点List<Element> list = root.getChildren();if(list==null||list.size()<1){return null;}for (Element element : list) {logger.info("key是:" + element.getName() + ",值是:" + element.getText());m.put(element.getName(),element.getText());}return m;}}

HttpClientConnectionManager.java

package wxpay;import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;@SuppressWarnings("deprecation")
public class HttpClientConnectionManager {/*** ��ȡSSL��֤��HttpClient* * @param httpClient* @return*/public static HttpClient getSSLInstance(HttpClient httpClient) {ClientConnectionManager ccm = httpClient.getConnectionManager();SchemeRegistry sr = ccm.getSchemeRegistry();sr.register(new Scheme("https", MySSLSocketFactory.getInstance(), 443));httpClient = new DefaultHttpClient(ccm, httpClient.getParams());return httpClient;}/*** ģ�������post�ύ* * @param url* @return*/public static HttpPost getPostMethod(String url) {HttpPost pmethod = new HttpPost(url); // ������Ӧͷ��Ϣpmethod.addHeader("Connection", "keep-alive");pmethod.addHeader("Accept", "*/*");pmethod.addHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");pmethod.addHeader("Host", "api.mch.weixin.qq.com");pmethod.addHeader("X-Requested-With", "XMLHttpRequest");pmethod.addHeader("Cache-Control", "max-age=0");pmethod.addHeader("User-Agent","Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");return pmethod;}/*** ģ�������GET�ύ* * @param url* @return*/public static HttpGet getGetMethod(String url) {HttpGet pmethod = new HttpGet(url);// ������Ӧͷ��Ϣpmethod.addHeader("Connection", "keep-alive");pmethod.addHeader("Cache-Control", "max-age=0");pmethod.addHeader("User-Agent","Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");pmethod.addHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/;q=0.8");return pmethod;}
}

MD5Util.java

package wxpay;import java.security.MessageDigest;public class MD5Util {private static String byteArrayToHexString(byte b[]) {StringBuffer resultSb = new StringBuffer();for (int i = 0; i < b.length; i++)resultSb.append(byteToHexString(b[i]));return resultSb.toString();}private static String byteToHexString(byte b) {int n = b;if (n < 0)n += 256;int d1 = n / 16;int d2 = n % 16;return hexDigits[d1] + hexDigits[d2];}public static String MD5Encode(String origin, String charsetname) {String resultString = null;try {resultString = new String(origin);MessageDigest md = MessageDigest.getInstance("MD5");if (charsetname == null || "".equals(charsetname))resultString = byteArrayToHexString(md.digest(resultString.getBytes()));elseresultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));} catch (Exception exception) {}return resultString;}private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5","6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };}

MySSLSocketFactory.java

package wxpay;import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;import org.apache.http.conn.ssl.SSLSocketFactory;@SuppressWarnings("deprecation")
public class MySSLSocketFactory extends SSLSocketFactory {static {mySSLSocketFactory = new MySSLSocketFactory(createSContext());}private static MySSLSocketFactory mySSLSocketFactory = null;private static SSLContext createSContext() {SSLContext sslcontext = null;try {sslcontext = SSLContext.getInstance("SSL");} catch (NoSuchAlgorithmException e) {e.printStackTrace();}try {sslcontext.init(null,new TrustManager[] { new MyX509TrustManager() }, null);} catch (KeyManagementException e) {e.printStackTrace();return null;}return sslcontext;}private MySSLSocketFactory(SSLContext sslContext) {super(sslContext);this.setHostnameVerifier(ALLOW_ALL_HOSTNAME_VERIFIER);}public static MySSLSocketFactory getInstance() {if (mySSLSocketFactory != null) {return mySSLSocketFactory;} else {return mySSLSocketFactory = new MySSLSocketFactory(createSContext());}}
}

MyX509TrustManager.java

package wxpay;import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;import javax.net.ssl.X509TrustManager;public class MyX509TrustManager implements X509TrustManager {// ���ͻ���֤��@Overridepublic void checkClientTrusted(X509Certificate[] chain, String authType)throws CertificateException {}// ����������֤��@Overridepublic void checkServerTrusted(X509Certificate[] chain, String authType)throws CertificateException {}// ���������ε�X509֤������@Overridepublic X509Certificate[] getAcceptedIssuers() {return null;}
}

PayCommonUtil.java

package wxpay;import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;public class PayCommonUtil {/** * 是否签名正确,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。 * @return boolean */  @SuppressWarnings("rawtypes")public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {  StringBuffer sb = new StringBuffer();  Set<?> es = packageParams.entrySet();  Iterator<?> it = es.iterator();  while(it.hasNext()) {  Map.Entry entry = (Map.Entry)it.next();  String k = (String)entry.getKey();  String v = (String)entry.getValue();  if(!"sign".equals(k) && null != v && !"".equals(v)) {  sb.append(k + "=" + v + "&");  }  }  sb.append("key=" + API_KEY);  //算出摘要  String mysign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toLowerCase();  String tenpaySign = ((String)packageParams.get("sign")).toLowerCase();  //System.out.println(tenpaySign + "    " + mysign);  return tenpaySign.equals(mysign);  }  /** * @author * @date 2016-4-22 * @Description:sign签名 * @param characterEncoding *            编码格式 *            请求参数* @return */  @SuppressWarnings("rawtypes")public static String createSign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {  StringBuffer sb = new StringBuffer();  Set<?> es = packageParams.entrySet();  Iterator<?> it = es.iterator();  while (it.hasNext()) {  Map.Entry entry = (Map.Entry) it.next();  String k = (String) entry.getKey();  String v = (String) entry.getValue();  if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {  sb.append(k + "=" + v + "&");  }  }  sb.append("key=" + API_KEY);  String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();  return sign;  }  /** * @author * @date 2016-4-22 * @Description:将请求参数转换为xml格式的string * @param parameters *            请求参数 * @return */  @SuppressWarnings("rawtypes")public static String getRequestXml(SortedMap<Object, Object> parameters) {  StringBuffer sb = new StringBuffer();  sb.append("<xml>");  Set<?> es = parameters.entrySet();  Iterator<?> it = es.iterator();  while (it.hasNext()) {  Map.Entry entry = (Map.Entry) it.next();  String k = (String) entry.getKey();  String v = (String) entry.getValue();  if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {  sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");  } else {  sb.append("<" + k + ">" + v + "</" + k + ">");  }  }  sb.append("</xml>");  return sb.toString();  }  /** * 取出一个指定长度大小的随机正整数. *  * @param length *            int 设定所取出随机数的长度。length小于11 * @return int 返回生成的随机数。 */  public static int buildRandom(int length) {  int num = 1;  double random = Math.random();  if (random < 0.1) {  random = random + 0.1;  }  for (int i = 0; i < length; i++) {  num = num * 10;  }  return (int) ((random * num));  }  /** * 获取当前时间 yyyyMMddHHmmss *  * @return String */  public static String getCurrTime() {  Date now = new Date();  SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");  String s = outFormat.format(now);  return s;  }  }  

RequestHandler.java

package wxpay;import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class RequestHandler {private String tokenUrl;private String gateUrl;private String notifyUrl;private String appid;private String appkey;private String partnerkey;private String appsecret;private String Token;private String charset;private String last_errcode;protected HttpServletRequest request;protected HttpServletResponse response;private String key;private SortedMap<String, String> parameters;private String debugInfo;public void init(String app_id, String app_secret, String partner_key) {this.last_errcode = "0";this.Token = "token_";this.debugInfo = "";this.appid = app_id;this.partnerkey = partner_key;this.appsecret = app_secret;this.key = partner_key;}public RequestHandler(HttpServletRequest request,HttpServletResponse response) {this.request = request;this.response = response;notifyUrl = "https://gw.tenpay.com/gateway/simpleverifynotifyid.xml";this.gateUrl = "https://gw.tenpay.com/gateway/pay.htm";this.key = "";this.parameters = new TreeMap<String, String>();this.debugInfo = "";}public void init() {}public void init(String app_id, String app_secret, String app_key,String partner_key) {this.last_errcode = "0";this.Token = "token_";this.debugInfo = "";this.appkey = app_key;this.appid = app_id;this.partnerkey = partner_key;this.appsecret = app_secret;}public String getGateUrl() {return gateUrl;}public void setGateUrl(String gateUrl) {this.gateUrl = gateUrl;}public String getKey() {return key;}public void setKey(String key) {this.key = key;}public String getParameter(String parameter) {String s = this.parameters.get(parameter);return (null == s) ? "" : s;}public void setParameter(String parameter, String parameterValue) {String v = "";if (null != parameterValue) {v = parameterValue.trim();}this.parameters.put(parameter, v);}public SortedMap<String, String> getAllParameters() {return this.parameters;}public String getDebugInfo() {return debugInfo;}public String getRequestURL() throws UnsupportedEncodingException {this.createSign();StringBuffer sb = new StringBuffer();String enc = TenpayUtil.getCharacterEncoding(this.request,this.response);Set<?> es = this.parameters.entrySet();Iterator<?> it = es.iterator();while (it.hasNext()) {Map.Entry entry = (Map.Entry) it.next();String k = (String) entry.getKey();String v = (String) entry.getValue();if (!"spbill_create_ip".equals(k)) {sb.append(k + "=" + URLEncoder.encode(v, enc) + "&");} else {sb.append(k + "=" + v.replace("\\.", "%2E") + "&");}}// ȥ�����һ��&String reqPars = sb.substring(0, sb.lastIndexOf("&"));return this.getGateUrl() + "?" + reqPars;}public void doSend() throws UnsupportedEncodingException, IOException {this.response.sendRedirect(this.getRequestURL());}protected void createSign() {StringBuffer sb = new StringBuffer();Set<?> es = this.parameters.entrySet();Iterator<?> it = es.iterator();while (it.hasNext()) {Map.Entry entry = (Map.Entry) it.next();String k = (String) entry.getKey();String v = (String) entry.getValue();if (null != v && !"".equals(v) && !"sign".equals(k)&& !"key".equals(k)) {sb.append(k + "=" + v + "&");}}sb.append("key=" + this.getKey());String enc = TenpayUtil.getCharacterEncoding(this.request,this.response);String sign = MD5Util.MD5Encode(sb.toString(), enc).toUpperCase();this.setParameter("sign", sign);// debug��Ϣthis.setDebugInfo(sb.toString() + " => sign:" + sign);}protected void setDebugInfo(String debugInfo) {this.debugInfo = debugInfo;}protected HttpServletRequest getHttpServletRequest() {return this.request;}protected HttpServletResponse getHttpServletResponse() {return this.response;}public String getTokenUrl() {return tokenUrl;}public void setTokenUrl(String tokenUrl) {this.tokenUrl = tokenUrl;}public String getNotifyUrl() {return notifyUrl;}public void setNotifyUrl(String notifyUrl) {this.notifyUrl = notifyUrl;}public String getAppid() {return appid;}public void setAppid(String appid) {this.appid = appid;}public String getAppkey() {return appkey;}public void setAppkey(String appkey) {this.appkey = appkey;}public String getPartnerkey() {return partnerkey;}public void setPartnerkey(String partnerkey) {this.partnerkey = partnerkey;}public String getAppsecret() {return appsecret;}public void setAppsecret(String appsecret) {this.appsecret = appsecret;}public String getToken() {return Token;}public void setToken(String token) {Token = token;}public String getCharset() {return charset;}public void setCharset(String charset) {this.charset = charset;}public String getLast_errcode() {return last_errcode;}public void setLast_errcode(String last_errcode) {this.last_errcode = last_errcode;}public HttpServletRequest getRequest() {return request;}public void setRequest(HttpServletRequest request) {this.request = request;}public HttpServletResponse getResponse() {return response;}public void setResponse(HttpServletResponse response) {this.response = response;}public SortedMap<String, String> getParameters() {return parameters;}public void setParameters(SortedMap<String, String> parameters) {this.parameters = parameters;}public String getLasterrCode() {return last_errcode;}public void setAppKey(String key) {this.appkey = key;}public String UrlEncode(String src) throws UnsupportedEncodingException {return URLEncoder.encode(src, this.charset).replace("+", "%20");}public String genPackage(SortedMap<String, String> packageParams)throws UnsupportedEncodingException {String sign = createSign(packageParams);StringBuffer sb = new StringBuffer();Set es = packageParams.entrySet();Iterator it = es.iterator();while (it.hasNext()) {Map.Entry entry = (Map.Entry) it.next();String k = (String) entry.getKey();String v = (String) entry.getValue();sb.append(k + "=" + UrlEncode(v) + "&");}// ȥ�����һ��&String packageValue = sb.append("sign=" + sign).toString();System.out.println("packageValue=" + packageValue);return packageValue;}/*** ����md5ժҪ,������:���������a-z����,������ֵ�IJ���μ�ǩ��*/@SuppressWarnings("rawtypes")public String createSign(SortedMap<String, String> packageParams) {StringBuffer sb = new StringBuffer();Set es = packageParams.entrySet();Iterator it = es.iterator();while (it.hasNext()) {Map.Entry entry = (Map.Entry) it.next();String k = (String) entry.getKey();String v = (String) entry.getValue();if (null != v && !"".equals(v) && !"sign".equals(k)&& !"key".equals(k)) {sb.append(k + "=" + v + "&");}}sb.append("key=" + Constant.MCH_KEY);System.out.println("md5 sb:" + sb);String sign = MD5Util.MD5Encode(sb.toString(), this.charset).toUpperCase();return sign;}/*** ����packageǩ��*/@SuppressWarnings("rawtypes")public boolean createMd5Sign(String signParams) {StringBuffer sb = new StringBuffer();Set es = this.parameters.entrySet();Iterator it = es.iterator();while (it.hasNext()) {Map.Entry entry = (Map.Entry) it.next();String k = (String) entry.getKey();String v = (String) entry.getValue();if (!"sign".equals(k) && null != v && !"".equals(v)) {sb.append(k + "=" + v + "&");}}// ���ժҪString enc = TenpayUtil.getCharacterEncoding(this.request,this.response);String sign = MD5Util.MD5Encode(sb.toString(), enc).toLowerCase();String tenpaySign = this.getParameter("sign").toLowerCase();// debug��Ϣthis.setDebugInfo(sb.toString() + " => sign:" + sign + " tenpaySign:"+ tenpaySign);return tenpaySign.equals(sign);}// ���XML@SuppressWarnings("rawtypes")public String parseXML() {StringBuffer sb = new StringBuffer();sb.append("<xml>");Set es = this.parameters.entrySet();Iterator it = es.iterator();while (it.hasNext()) {Map.Entry entry = (Map.Entry) it.next();String k = (String) entry.getKey();String v = (String) entry.getValue();if (null != v && !"".equals(v) && !"appkey".equals(k)) {sb.append("<" + k + ">" + getParameter(k) + "</" + k + ">\n");}}sb.append("</xml>");return sb.toString();}public static String setXML(String return_code, String return_msg) {return "<xml><return_code><![CDATA[" + return_code+ "]]></return_code><return_msg><![CDATA[" + return_msg+ "]]></return_msg></xml>";}
}

ResponseHandler.java

package wxpay;import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** Ӧ������* Ӧ������̳д��࣬��дisTenpaySign�������ɡ�* @author miklchen**/
public class ResponseHandler { /** ��Կ */private String key;/** Ӧ��IJ��� */private SortedMap<String, String> parameters; /** debug��Ϣ */private String debugInfo;private HttpServletRequest request;private HttpServletResponse response;private String uriEncoding;/*** ���캯��* * @param request* @param response*/public ResponseHandler(HttpServletRequest request,HttpServletResponse response)  {this.request = request;this.response = response;this.key = "";this.parameters = new TreeMap<String, String>();this.debugInfo = "";this.uriEncoding = "";Map<?, ?> m = this.request.getParameterMap();Iterator<?> it = m.keySet().iterator();while (it.hasNext()) {String k = (String) it.next();String v = ((String[]) m.get(k))[0];           this.setParameter(k, v);}}/***��ȡ��Կ*/public String getKey() {return key;}/***������Կ*/public void setKey(String key) {this.key = key;}/*** ��ȡ����ֵ* @param parameter �������* @return String */public String getParameter(String parameter) {String s = this.parameters.get(parameter); return (null == s) ? "" : s;}/*** ���ò���ֵ* @param parameter �������* @param parameterValue ����ֵ*/public void setParameter(String parameter, String parameterValue) {String v = "";if(null != parameterValue) {v = parameterValue.trim();}this.parameters.put(parameter, v);}/*** �������еIJ���* @return SortedMap*/public SortedMap<String, String> getAllParameters() {return this.parameters;}/*** �Ƿ�Ƹ�ͨǩ��,������:���������a-z����,������ֵ�IJ���μ�ǩ��* @return boolean*/@SuppressWarnings("rawtypes")public boolean isTenpaySign() {StringBuffer sb = new StringBuffer();Set<?> es = this.parameters.entrySet();Iterator<?> it = es.iterator();while(it.hasNext()) {Map.Entry entry = (Map.Entry)it.next();String k = (String)entry.getKey();String v = (String)entry.getValue();if(!"sign".equals(k) && null != v && !"".equals(v)) {sb.append(k + "=" + v + "&");}}sb.append("key=" + this.getKey());//���ժҪString enc = TenpayUtil.getCharacterEncoding(this.request, this.response);String sign = MD5Util.MD5Encode(sb.toString(), enc).toLowerCase();String tenpaySign = this.getParameter("sign").toLowerCase();//debug��Ϣthis.setDebugInfo(sb.toString() + " => sign:" + sign +" tenpaySign:" + tenpaySign);return tenpaySign.equals(sign);}/*** ���ش������Ƹ�ͨ��������* @param msg: Success or fail��* @throws IOException */public void sendToCFT(String msg) throws IOException {String strHtml = msg;PrintWriter out = this.getHttpServletResponse().getWriter();out.println(strHtml);out.flush();out.close();}/*** ��ȡuri����* @return String*/public String getUriEncoding() {return uriEncoding;}/*** ����uri����* @param uriEncoding* @throws UnsupportedEncodingException*/public void setUriEncoding(String uriEncoding)throws UnsupportedEncodingException {if (!"".equals(uriEncoding.trim())) {this.uriEncoding = uriEncoding;// ����ת��String enc = TenpayUtil.getCharacterEncoding(request, response);Iterator<String> it = this.parameters.keySet().iterator();while (it.hasNext()) {String k = it.next();String v = this.getParameter(k);v = new String(v.getBytes(uriEncoding.trim()), enc);this.setParameter(k, v);}}}/***��ȡdebug��Ϣ*/public String getDebugInfo() {return debugInfo;}/***����debug��Ϣ*/protected void setDebugInfo(String debugInfo) {this.debugInfo = debugInfo;}protected HttpServletRequest getHttpServletRequest() {return this.request;}protected HttpServletResponse getHttpServletResponse() {return this.response;}
}

TenpayUtil.java

package wxpay;import java.text.SimpleDateFormat;
import java.util.Date;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class TenpayUtil {/*** �Ѷ���ת�����ַ�* @param obj* @return String ת�����ַ�,������Ϊnull,�?ؿ��ַ�.*/public static String toString(Object obj) {if(obj == null)return "";return obj.toString();}/*** �Ѷ���ת��Ϊint��ֵ.* * @param obj*            �����ֵĶ���.* @return int ת�������ֵ,�Բ���ת���Ķ��?�0��*/public static int toInt(Object obj) {int a = 0;try {if (obj != null)a = Integer.parseInt(obj.toString());} catch (Exception e) {}return a;}/*** ��ȡ��ǰʱ�� yyyyMMddHHmmss* @return String*/ public static String getCurrTime() {Date now = new Date();SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");String s = outFormat.format(now);return s;}/*** ��ȡ��ǰ���� yyyyMMdd* @param date* @return String*/public static String formatDate(Date date) {SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");String strDate = formatter.format(date);return strDate;}/*** ȡ��һ��ָ�����ȴ�С�����������.* * @param length*            int �趨��ȡ�������ij��ȡ�lengthС��11* @return int ������ɵ������*/public static int buildRandom(int length) {int num = 1;double random = Math.random();if (random < 0.1) {random = random + 0.1;}for (int i = 0; i < length; i++) {num = num * 10;}return (int) ((random * num));}/*** ��ȡ�����ַ�* @param request* @param response* @return String*/public static String getCharacterEncoding(HttpServletRequest request,HttpServletResponse response) {if(null == request || null == response) {return "gbk";}String enc = request.getCharacterEncoding();if(null == enc || "".equals(enc)) {enc = response.getCharacterEncoding();}if(null == enc || "".equals(enc)) {enc = "gbk";}return enc;}/*** ��ȡunixʱ�䣬��1970-01-01 00:00:00��ʼ������* @param date* @return long*/public static long getUnixTime(Date date) {if( null == date ) {return 0;}return date.getTime()/1000;}/*** ʱ��ת�����ַ�* @param date ʱ��* @param formatType ��ʽ������* @return String*/public static String date2String(Date date, String formatType) {SimpleDateFormat sdf = new SimpleDateFormat(formatType);return sdf.format(date);}}

XMLUtil.java

package wxpay;import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;public class XMLUtil {/*** ����xml,���ص�һ��Ԫ�ؼ�ֵ�ԡ�����һ��Ԫ�����ӽڵ㣬��˽ڵ��ֵ���ӽڵ��xml��ݡ�* * @param strxml* @return* @throws JDOMException* @throws IOException*/public static Map<String, String> doXMLParse(String strxml)throws JDOMException, IOException {strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");if (null == strxml || "".equals(strxml)) {return null;}Map<String, String> m = new HashMap<String, String>();InputStream 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<?> it = list.iterator();while (it.hasNext()) {Element e = (Element) it.next();String k = e.getName();String v = "";List<?> children = e.getChildren();if (children.isEmpty()) {v = e.getTextNormalize();} else {v = XMLUtil.getChildrenText(children);}m.put(k, v);}// �ر���in.close();return m;}/*** ��ȡ�ӽ���xml* * @param children* @return String*/public static String getChildrenText(List<?> children) {StringBuffer sb = new StringBuffer();if (!children.isEmpty()) {Iterator<?> it = children.iterator();while (it.hasNext()) {Element e = (Element) it.next();String name = e.getName();String value = e.getTextNormalize();List<?> list = e.getChildren();sb.append("<" + name + ">");if (!list.isEmpty()) {sb.append(XMLUtil.getChildrenText(list));}sb.append(value);sb.append("</" + name + ">");}}return sb.toString();}
}

Constant.java

package wxpay;public class Constant {String CHARSET = "UTF-8";String TOKEN = "struck2wechat";//与开发模式接口配置信息中的Token保持一致public static final String MCH_ID = "替换成你的商户号";// 微信支付商户号public static final String MCH_KEY ="替换成你的商户密钥";// 第三方用户唯一凭证public final static String APP_ID = "替换成你的appid";// 第三方用户唯一凭证密钥public final static String APP_SECRET = "替换成你的app_secretd";}

将上面的所有.java文件放在同一个包里,导入依赖的jar包就可以了。

展示二维码的方式如下:

 <img src="${pageContext.request.contextPath}${codeUrl}" width="100%" height="100%" />

至于具体的页面不分享,这个由你的前端自己写就可以了。

至此,分享结束,希望能对诸位有所帮助。

JAVA后端调用微信支付“统一下单”接口实现微信二维码扫码支付相关推荐

  1. APP 对接 java 微信支付统一下单接口

    首先插入微信支付的时序图 统一下单时候的请求对象,需要把这个转为xml 文件格式所以需要在pom.xml 文件中导入 .和微信支付的sdk <dependency> <groupId ...

  2. 微信支付-----统一下单接口对接

    本以为没有机会接触鼎鼎大名的支付宝和微信接口(公司本身是做第三方支付的),最近由于一个售货机项目需要对接银联,支付宝和微信接口,因为我自身已经对接了银联,之后根据安排,由我对接微信的相关接口.话不多说 ...

  3. 做微信h5支付的统一下单接口开发,虽然已经生成了mweb_url支付链接,但是访问时出现错误提示:‘商家参数格式有误,请联系商家解决’,但是检查h5支付提交的参数,都没有错误。 微信h5支付开发错误

    做微信h5支付的统一下单接口开发,虽然已经生成了mweb_url支付链接,但是访问时出现错误提示:'商家参数格式有误,请联系商家解决',但是检查h5支付提交的参数,都没有错误. 后面看到官方文档, 说 ...

  4. java微信支付 [统一下单接口] 与 [订单查询接口] 调用成功完整代码与结果

    公司最近要搞微信支付, 之前也没有做过, 但是搞过阿里云, 想来也不是很难. 在网上找了很多贴子, 在eclipse里做了5个测试工程, 没有测试成功, 后来下了微信SDK, 也做了个测试样例, 期间 ...

  5. php微信支付mch_id参数格式错误,在.net core上,Web网站调用微信支付-统一下单接口(xml传参)一直返回错误:mch_id参数格式错误...

    一.问题描述 在调用统一下单接口时,报mch_id参数格式错误,但商户ID确实是10位数字正确的,可就是一直报这个错误 返回的错误xml如下: 二.排错过程 1.多次对比官网xml格式,确认生成的xm ...

  6. 微信支付服务器system error,调用微信支付统一下单接口出现err_code:SYSTEMERROR错误...

    调用统一下单接口: 返回如下 {'appid': 'wxxxxxxxxx', 'err_code': 'SYSTEMERROR', 'err_code_des': 'system error', 'm ...

  7. 微信小程序支付统一下单接口and异步回调

     统一下单接口: <?phpnamespace pay;class WxPay {protected $appid;protected $mch_id;protected $key;protec ...

  8. 微信支付统一下单接口返回数据乱码

    做的一个网页扫码支付 微信公众号和商户号都已经申请号,密钥也配置了 验证签名通过,有的朋友问题会处在签名验证错误上,需要MD5加密设置编码格式为UTF-8 我的问题不在这里 统一下单后返回为fail ...

  9. 富友支付 统一下单接口 自创php版本demo

    看了文档才发现demo只有java版本的 那可不妙啊 还好在我的坚持与努力下 终于参透了这文档. 就这个文档 富友开放接口文档  有一说一这个验签的方式还是很简介的直接md5验签 害我找了半天的DES ...

  10. 微信小程序接入微信支付(二):后台调用统一下单接口

    微信统一支付官方文档:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1 因该接口需要商户系统中自己的订单编号,笔者先 ...

最新文章

  1. not syncing : corrupted stack end detected inside scheduler解决办法 以及高版本的激活码!
  2. yum是干什么的_什么是yum源,yum的工作原理又是什么
  3. long 雪花算法_海量数据分库分表方案(一)算法方案
  4. boost::exception模块实现boost :: tuple捆绑的测试程序
  5. 【JavaScript】数组
  6. html双翼布局,第19题 CSS如何实现双飞翼布局?
  7. 【渝粤题库】陕西师范大学163204 旅游规划学
  8. Bootstrap--导航栏样式编辑
  9. Python基础学习:svn导出差异文件脚本
  10. vs ajax工具包引用,vs2008中使用AJAX Control Tookit工具的问题?
  11. 硬件加速_消息称Xbox Series X主机将有专用音频硬件加速 带来更强沉浸感
  12. 8.exchange2013实战操作之RMS
  13. hadoop中的序列化和反序列化
  14. wps里为什么没有华文楷体_是谁动了我的字体?为什么Word或PPT换台电脑打开字体就变了呢?...
  15. linux中help的用法
  16. c# Pdf文件加密和解密
  17. 如何在WPS中给一组字母上方添加一个横线
  18. 石墨烯的加入,新量子装置使人类离第二次量子革命真正又近一步
  19. Apache 实现AJAX跨域请求
  20. 11 个最佳免费安全网站

热门文章

  1. aht10温湿度传感器特点及使用介绍
  2. 人民日报申论范文:如何写“担当”“责任”
  3. apple 关闭双重认证_如何在Apple Mail中关闭联系人和事件建议
  4. 想知道如何批量压缩图片?来试试这几个图片压缩工具
  5. 都说ApiPost香,它到底香在哪里?
  6. c语言中以e为底的指数怎么表示,c++中怎样表示以e为底的
  7. WIN7远程桌面连接显示凭据不工作的解决方法
  8. 清华团队夺冠清华-新南威尔士中澳数据科学大赛!跨学科交叉人才走出国门
  9. android实现高德地图实时导航,高德地图之实时导航
  10. Mac电脑无法从Photoshop 2020作为插件访问DeNoise AI的解决办法