以前写过一篇设置微信二维码失效时间的博客,最近又要新增微信退款的功能,于是又重新整理了一下前面的微信二维码扫码支付功能,感觉整体的实现方式都能够掌控了,于是将具体的源码拿出来分享一下。
开发之前,一定要先阅读这篇说明文档: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));//二维码的url
model.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);//二维码的url
model.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")
@ResponseBody
public 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;未付款返回false
result.setSuccess(ttl>1);
} catch (Exception e) {
result.setSuccess(false);
}
return result;
}
/**
* 接口三:微信支付回调接口
* 注意!注意!注意!这个接口不要做权限拦截操作,要直接放行
*/
@RequestMapping(value = "wxRedirect")
@ResponseBody
public 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成map
Map<String, String> m =XMLUtil.doXMLParse(sb.toString());
// 过滤空 设置 TreeMap
SortedMap<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;
}
// 到这里,说明是支付成功了
// 执行自己的业务逻辑
// 通知id
String mch_id = (String) packageParams.get("mch_id");
String openid = (String) packageParams.get("openid");//付款方的openId
String 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];//这个订单号对应的用户userId
double 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 + ">";
} else
xml += "<" + 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
+ "×tamp=" + 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地址。用户的客户端IP
String 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;//微信公众号的appsecret
String 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()));
else
resultString = 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);
// 创建一个新的SAXBuilder
SAXBuilder sb = new SAXBuilder();
// 通过输入源构造一个Document
Document 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()));
else
resultString = 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 {
// ���ͻ���֤��
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
// ����������֤��
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
// ���������ε�X509֤������
@Override
public 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%" />
至于具体的页面不分享,这个由你的前端自己写就可以了。
至此,分享结束,希望能对诸位有所帮助。