java实现网站微信扫码支付
一、网站微信扫码支付开发并没有现成的java示例,总结一下自己微信扫码支付心得
二、首先去微信公众平台申请账户
https://mp.weixin.qq.com
**
三、账户开通、开发者认证之后就可以进行微信支付开发了
1、微信统一下单接口调用获取预支付id,以及生成二维码所需的codeUrl
/** *保存订单,并生成二维码所需的codeUrl * *@paramrequest *@paramresponse *@paramnotifyURLBuf *@paramorder *@return *@throwsException */ @Override publicMapgetWechatOrderInfo(Stringip,Cuseruser,StringnotifyUrl,Orderorder)throwsException{ Map resultMap=newHashMap (); //生成并保存订单 order.setUserId(user.getId()); //支付方式0:银联1:支付宝2:网上银行3:微信4:其他 order.setPayType("3"); //生成订单号 order.setOrderNo(OrderNoGenerator.getOrderNo()); //订单类型1:消费2:退款 order.setOrderType("1"); //订单创建时间 order.setCreateTime(newDate()); //订单更新时间 order.setUpdateTime(newDate()); //订单状态0:交易中1:完成2:已取消 order.setOrderStatus("0"); //付款状态0:失败1:成功2、待付款 order.setPayStatus("2"); //设置订单失效时间 Calendarcalendar=Calendar.getInstance(); calendar.add(Calendar.HOUR,2); order.setExpireTime(calendar.getTime()); IntegerorderId=this.balanceDao.saveOrder(order); Map payPreIdMap=newHashMap<>(); payPreIdMap=WechatUtil.getPayPreId(String.valueOf(orderId),"体检报告",notifyUrl,ip, String.valueOf((order.getMoney().multiply(newBigDecimal(100)).intValue())),orderId.toString()); StringprePayId=payPreIdMap.get("prepay_id"); //更新 order.setId(orderId); order.setPrepayId(prePayId); order.setCodeUrl(payPreIdMap.get("code_url")); this.balanceDao.updateOrder(order); //returnWechatUtil.QRfromGoogle(order.getCodeUrl(),300,0); resultMap.put("codeUrl",order.getCodeUrl()); resultMap.put("orderId",String.valueOf(order.getId())); returnresultMap; }
此方法返回的数据如下
2、服务器端接受微信支付结果通知
/**
*保存微信通知结果
*
*@paramrequest
*@paramresponse
*@return
*@throwsException
*/
@Override
publicStringsaveWechatNotify(StringnotifyInfoXml)throwsException{
MapnoticeMap=XMLUtil.doXMLParse(notifyInfoXml);
//这个其实是订单的id
StringoutTradeNo=noticeMap.get("out_trade_no");
Orderorder=this.balanceDao.getOrderById(Integer.valueOf(outTradeNo));
//如果支付通知信息不为,说明请求已经处理过,直接返回
if(StringUtil.isNotEmpty(order.getNotifyInfo())){
return"SUCCESS";
}
Stringsign=noticeMap.get("sign");
noticeMap.remove("sign");
//验签通过
if(WechatUtil.getSignVeryfy(noticeMap,sign)){
//通信成功此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断
if("SUCCESS".equals(noticeMap.get("return_code"))){
//交易成功
if("SUCCESS".equals(noticeMap.get("result_code"))){
//商户订单号
//订单更新时间
order.setUpdateTime(newDate());
//------------------------------
//处理业务开始
//------------------------------
//是否交易成功,1:成功0:失败
//微信支付成功
order.setPayStatus("1");
//订单状态0:交易中1:完成2:已取消
order.setOrderStatus("1");
//保存通知信息
order.setNotifyInfo(notifyInfoXml);
this.balanceDao.updateOrder(order);
//处理业务完毕
}else{
//错误时,返回结果未签名,记录retcode、retmsg看失败详情。
logger.info("查询验证签名失败或业务错误");
logger.info("retcode:"+noticeMap.get("retcode")+"retmsg:"+noticeMap.get("retmsg"));
}
return"SUCCESS";
}else{
logger.info("后台调用通信失败");
}
return"SUCCESS";
}else{
logger.info("通知签名验证失败");
}
returnnull;
}
3、上面代码用到的工具方法都在WechatUtil.java工具类中
packagecom.caifu.tencent.common;
importjava.io.IOException;
importjava.net.URISyntaxException;
importjava.net.URLEncoder;
importjava.util.ArrayList;
importjava.util.Collections;
importjava.util.HashMap;
importjava.util.LinkedList;
importjava.util.List;
importjava.util.Map;
importjava.util.Random;
importorg.apache.commons.httpclient.HttpStatus;
importorg.apache.http.NameValuePair;
importorg.apache.http.client.config.RequestConfig;
importorg.apache.http.client.methods.CloseableHttpResponse;
importorg.apache.http.client.methods.HttpPost;
importorg.apache.http.client.utils.URIBuilder;
importorg.apache.http.entity.StringEntity;
importorg.apache.http.impl.client.CloseableHttpClient;
importorg.apache.http.impl.client.HttpClients;
importorg.apache.http.message.BasicNameValuePair;
importorg.apache.http.util.EntityUtils;
importorg.jdom2.JDOMException;
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
importcom.caifu.login.utils.XMLUtil;
publicclassWechatUtil{
privatestaticLoggerlogger=LoggerFactory.getLogger(WechatUtil.class);
publicstaticfinalStringTAG="Wechat.Util";
privatestaticfinalinttimeout=5000;
publicstaticbyte[]httpPost(Stringurl,Stringentity)throwsURISyntaxException,IOException{
if(url==null||url.length()==0){
logger.info(TAG,"httpPost,urlisnull");
returnnull;
}
CloseableHttpClienthttpClient=HttpClients.createDefault();
URIBuilderuriBuilder=newURIBuilder(url);
HttpPosthttpPost=newHttpPost(uriBuilder.build());
RequestConfigrequestConfig=RequestConfig.custom().setSocketTimeout(timeout).setConnectionRequestTimeout(timeout).setConnectTimeout(timeout).build();
httpPost.setConfig(requestConfig);
//避免汉字乱码导致请求失败,
httpPost.setEntity(newStringEntity(entity,"UTF-8"));
CloseableHttpResponseresp=null;
try{
resp=httpClient.execute(httpPost);
if(resp.getStatusLine().getStatusCode()!=HttpStatus.SC_OK){
logger.info(TAG,"httpGetfail,statuscode="+resp.getStatusLine().getStatusCode());
returnnull;
}
returnEntityUtils.toByteArray(resp.getEntity());
}catch(Exceptione){
logger.info(TAG,"httpPostexception,e="+e.getMessage());
e.printStackTrace();
returnnull;
}finally{
if(httpClient!=null){
httpClient.close();
}
if(resp!=null){
resp.close();
}
}
}
/**
*把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
*
*@paramparams
*需要排序并参与字符拼接的参数组
*@return拼接后字符串
*/
publicstaticStringcreateLinkString(Mapparams){
Listkeys=newArrayList(params.keySet());
Collections.sort(keys);
Stringprestr="";
for(inti=0;iParams,Stringsign){
//过滤空值、sign与sign_type参数
//MapsParaNew=AlipayCore.paraFilter(Params);
//获取待签名字符串
StringpreSignStr=createLinkString(Params);
preSignStr+="&key="+Configure.getKey();
//获得签名验证结果
StringresultSign=MD5.MD5Encode(preSignStr).toUpperCase();
//StringresultSign=MD5Util.MD5Encode(preSignStr.toString(),
//"UTF-8").toLowerCase();
if(sign.equals(resultSign)){
returntrue;
}else{
returnfalse;
}
}
/**
*装配xml,生成请求prePayId所需参数
*
*@paramparams
*@return
*/
publicstaticStringtoXml(Listparams){
StringBuildersb=newStringBuilder();
sb.append("");
for(inti=0;i");
sb.append(params.get(i).getValue());
sb.append(""+params.get(i).getName()+">");
}
sb.append(" ");
returnsb.toString();
}
/**
*生成签名
*/
publicstaticStringgenPackageSign(Listparams){
StringBuildersb=newStringBuilder();
for(inti=0;i");
ListpackageParams=newLinkedList();
packageParams.add(newBasicNameValuePair("appid",Configure.getAppid()));
packageParams.add(newBasicNameValuePair("body",body));
packageParams.add(newBasicNameValuePair("mch_id",Configure.getMchid()));
packageParams.add(newBasicNameValuePair("nonce_str",nonceStr));
packageParams.add(newBasicNameValuePair("notify_url",noticeUrl));
packageParams.add(newBasicNameValuePair("out_trade_no",goodOrderNo));
packageParams.add(newBasicNameValuePair("product_id",productId));
packageParams.add(newBasicNameValuePair("spbill_create_ip",ip));
packageParams.add(newBasicNameValuePair("total_fee",totalFee));
packageParams.add(newBasicNameValuePair("trade_type","NATIVE"));
Stringsign=genPackageSign(packageParams);
packageParams.add(newBasicNameValuePair("sign",sign));
Stringxmlstring=toXml(packageParams);
returnxmlstring;
}catch(Exceptione){
logger.info("genProductArgsfail,ex="+e.getMessage());
returnnull;
}
}
/**
*生成支付签名
*
*@paramparams
*@return
*/
publicstaticStringgenAppSign(Listparams){
StringBuildersb=newStringBuilder();
for(inti=0;igenPayReq(StringprepayId){
MapresultMap=newHashMap();
StringtimeStamp=getTimeStamp();
StringnonceStr=getNonceStr();
ListsignParams=newLinkedList();
signParams.add(newBasicNameValuePair("appid",Configure.getAppid()));
signParams.add(newBasicNameValuePair("noncestr",nonceStr));
signParams.add(newBasicNameValuePair("package","Sign=WXPay"));
signParams.add(newBasicNameValuePair("partnerid",Configure.getMchid()));
signParams.add(newBasicNameValuePair("prepayid",prepayId));
signParams.add(newBasicNameValuePair("timestamp",timeStamp));
Stringsign=genAppSign(signParams);
resultMap.put("appid",Configure.getAppid());
resultMap.put("noncestr",nonceStr);
resultMap.put("packageValue","Sign=WXPay");
resultMap.put("partnerid",Configure.getMchid());
resultMap.put("prepayid",prepayId);
resultMap.put("timestamp",timeStamp);
resultMap.put("sign",sign);
returnresultMap;
}
/**
*微信支付生成预支付订单
*
*@throwsIOException
*@throwsJDOMException
*/
publicstaticMapgetPayPreId(StringgoodOrderNo,Stringbody,StringnoticeUrl,Stringip,StringtotalFee,StringproductId)throwsException{
StringparamsXml=genProductArgs(goodOrderNo,body,noticeUrl,ip,totalFee,productId);
logger.info("orion",paramsXml);
byte[]buf=WechatUtil.httpPost(Configure.UNIFIEDORDER_API,paramsXml);
StringcontentXml=newString(buf);
MapresultMap=XMLUtil.doXMLParse(contentXml);
returnresultMap;
}
publicstaticStringgetNonceStr(){
Randomrandom=newRandom();
returnMD5.MD5Encode(String.valueOf(random.nextInt(10000)));
}
publicstaticStringgetTimeStamp(){
returnString.valueOf(System.currentTimeMillis()/1000);
}
/**
*生成支付二维码
*@paramrequest
*@paramresponse
*@paramwidth
*@paramheight
*@paramtext微信生成预定id时,返回的codeUrl
*/
publicstaticvoidgetQRcode(HttpServletRequestrequest,HttpServletResponseresponse,Integerwidth,Integerheight,Stringtext){
if(width==null){
width=300;
}
if(height==null){
height=300;
}
Stringformat="jpg";
Hashtablehints=newHashtable();
hints.put(EncodeHintType.CHARACTER_SET,"utf-8");
BitMatrixbitMatrix;
try{
bitMatrix=newMultiFormatWriter().encode(text,BarcodeFormat.QR_CODE,width,height,hints);
MatrixToImageWriter.writeToStream(bitMatrix,format,response.getOutputStream());
}catch(WriterExceptione){
e.printStackTrace();
}catch(IOExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
}
生成二维码需要两jar
com.google.zxing core 3.3.0 com.google.zxing javase 3.3.0
4、下面是用到的配置类
packagecom.caifu.tencent.common;
/**
*User:rizenguo
*Date:2014/10/29
*Time:14:40
*这里放置各种配置数据
*/
publicclassConfigure{
//这个就是自己要保管好的私有Key了(切记只能放在自己的后台代码里,不能放在任何可能被看到源代码的客户端程序中)
//每次自己Post数据给API的时候都要用这个key来对所有字段进行签名,生成的签名会放在Sign这个字段,API收到Post数据的时候也会用同样的签名算法对Post过来的数据进行签名和验证
//收到API的返回的时候也要用这个key来对返回的数据算下签名,跟API的Sign数据进行比较,如果值不一致,有可能数据被第三方给篡改
privatestaticStringkey="A6gB0Dy4dsfdssuPCPsdfdshkSCDQcr3eXS";
privatestaticStringappSecret="7584sdfdsfe4f26fadsfsdfs56f10728a";
//微信分配的公众号ID(开通公众号之后可以获取到)
privatestaticStringappID="wxaf0b86sdfsdf8afbf";
//微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
privatestaticStringmchID="14012313702";
//受理模式下给子商户分配的子商户号
privatestaticStringsubMchID="";
//HTTPS证书的本地路径
privatestaticStringcertLocalPath="";
//HTTPS证书密码,默认密码等于商户号MCHID
privatestaticStringcertPassword="";
//是否使用异步线程的方式来上报API测速,默认为异步模式
privatestaticbooleanuseThreadToDoReport=true;
//机器IP
privatestaticStringip="";
//以下是几个API的路径:
//1)被扫支付API
publicstaticStringUNIFIEDORDER_API="https://api.mch.weixin.qq.com/pay/unifiedorder";
publicstaticStringPAY_API="https://api.mch.weixin.qq.com/pay/micropay";
//2)被扫支付查询API
publicstaticStringPAY_QUERY_API="https://api.mch.weixin.qq.d/pay/orderquery";
//3)退款API
publicstaticStringREFUND_API="https://api.mch.weixin.qq.com/secapi/pay/refund";
//4)退款查询API
publicstaticStringREFUND_QUERY_API="https://api.mch.weixin.qq.com/pay/refundquery";
//5)撤销API
publicstaticStringREVERSE_API="https://api.mch.weixin.qq.com/secapi/pay/reverse";
//6)下载对账单API
publicstaticStringDOWNLOAD_BILL_API="https://api.mch.weixin.qq.com/pay/downloadbill";
//7)统计上报API
publicstaticStringREPORT_API="https://api.mch.weixin.qq.com/payitil/report";
publicstaticbooleanisUseThreadToDoReport(){
returnuseThreadToDoReport;
}
publicstaticvoidsetUseThreadToDoReport(booleanuseThreadToDoReport){
Configure.useThreadToDoReport=useThreadToDoReport;
}
publicstaticStringHttpsRequestClassName="com.tencent.common.HttpsRequest";
publicstaticvoidsetKey(Stringkey){
Configure.key=key;
}
publicstaticvoidsetAppID(StringappID){
Configure.appID=appID;
}
publicstaticvoidsetMchID(StringmchID){
Configure.mchID=mchID;
}
publicstaticvoidsetSubMchID(StringsubMchID){
Configure.subMchID=subMchID;
}
publicstaticvoidsetCertLocalPath(StringcertLocalPath){
Configure.certLocalPath=certLocalPath;
}
publicstaticvoidsetCertPassword(StringcertPassword){
Configure.certPassword=certPassword;
}
publicstaticvoidsetIp(Stringip){
Configure.ip=ip;
}
publicstaticStringgetKey(){
returnkey;
}
publicstaticStringgetAppid(){
returnappID;
}
publicstaticStringgetMchid(){
returnmchID;
}
publicstaticStringgetSubMchid(){
returnsubMchID;
}
publicstaticStringgetCertLocalPath(){
returncertLocalPath;
}
publicstaticStringgetCertPassword(){
returncertPassword;
}
publicstaticStringgetIP(){
returnip;
}
publicstaticvoidsetHttpsRequestClassName(Stringname){
HttpsRequestClassName=name;
}
}
在这里需要注意的配置
privatestaticStringkey=“A6gB0Dy4dsfdssuPCPsdfdshkSCDQcr3eXS”;
这里的key是登陆https://pay.weixin.qq.com/index.php/core/info(微信商户平台)设置的api_key
5、xml解析工具类
packagecom.caifu.login.utils;
importjava.io.ByteArrayInputStream;
importjava.io.IOException;
importjava.io.InputStream;
importjava.util.HashMap;
importjava.util.Iterator;
importjava.util.List;
importjava.util.Map;
importjavax.servlet.http.HttpServletRequest;
importorg.dom4j.io.SAXReader;
importorg.jdom2.Document;
importorg.jdom2.Element;
importorg.jdom2.JDOMException;
importorg.jdom2.input.SAXBuilder;
/**
*xml工具类
*
*@authormiklchen
*
*/
publicclassXMLUtil{
/**
*解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
*
*@paramstrxml
*@return
*@throwsJDOMException
*@throwsIOException
*/
publicstaticMapdoXMLParse(Stringstrxml)throwsJDOMException,IOException{
strxml=strxml.replaceFirst("encoding=\".*\"","encoding=\"UTF-8\"");
if(null==strxml||"".equals(strxml)){
returnnull;
}
Mapm=newHashMap();
InputStreamin=newByteArrayInputStream(strxml.getBytes("UTF-8"));
SAXBuilderbuilder=newSAXBuilder();
Documentdoc=builder.build(in);
Elementroot=doc.getRootElement();
Listlist=root.getChildren();
Iteratorit=list.iterator();
while(it.hasNext()){
Elemente=(Element)it.next();
Stringk=e.getName();
Stringv="";
Listchildren=e.getChildren();
if(children.isEmpty()){
v=e.getTextNormalize();
}else{
v=XMLUtil.getChildrenText(children);
}
m.put(k,v);
}
//关闭流
in.close();
returnm;
}
/**
*获取子结点的xml
*
*@paramchildren
*@returnString
*/
publicstaticStringgetChildrenText(Listchildren){
StringBuffersb=newStringBuffer();
if(!children.isEmpty()){
Iteratorit=children.iterator();
while(it.hasNext()){
Elemente=(Element)it.next();
Stringname=e.getName();
Stringvalue=e.getTextNormalize();
Listlist=e.getChildren();
sb.append("<"+name+">");
if(!list.isEmpty()){
sb.append(XMLUtil.getChildrenText(list));
}
sb.append(value);
sb.append(""+name+">");
}
}
returnsb.toString();
}
/**
*将requestxml通知结果转出啊成map
*@paramrequest
*@return
*@throwsException
*/
publicstaticMapparseXml(HttpServletRequestrequest)throwsException{
//解析结果存储在HashMap
Mapmap=newHashMap();
InputStreaminputStream=request.getInputStream();
//读取输入流
SAXReaderreader=newSAXReader();
org.dom4j.Documentdocument=reader.read(inputStream);
//得到xml根元素
org.dom4j.Elementroot=document.getRootElement();
//得到根元素的所有子节点
ListelementList=root.elements();
//遍历所有子节点
for(org.dom4j.Elemente:elementList)
map.put(e.getName(),e.getText());
//释放资源
inputStream.close();
inputStream=null;
returnmap;
}
}
6、整个后台服务已经完成,最后关闭页面微信支付二维码,告知用户支付已经完成了
varf;
/*定时任务方法,异步请求去查询订单是否支付*/
functionGetOrder(){
varorderId=$('#orderId').val();
if(orderId!=''){
$.ajax({
url:"${base}/balance/auth/isPay?orderId="+orderId,
type:"GET",
async:false,
success:function(d){
if(d=="1"){
//当获取到微信支付结果时,关闭二维码div
$(".weixinpay").css("display","none");
$("#zhichutankuang").css("display","block");
////当获取到微信支付结果时,关闭定时任务
clearInterval(f);
//layer.alert('付款成功',{
//skin:'layui-layer-molv',//样式类名
//closeBtn:0
//},function(){
//location.href="${base}/balance/auth/presentation?tjNo="+$("#tjNo").val();
//});
}
}
});
}
}
//异步请求获取生成二维码的url
$(".paylast").click(function(){
var$payType=$('input:radio:checked').val();
var$money=$("#money").val();
var$tjReportType=$("#tjReportType").val();
var$tjNo=$("#tjNo").val();
$.ajax({
url:"${base}/balance/auth/wechatInfo",
type:"POST",
async:false,
data:{
payType:$payType,
money:$money,
tjNo:$tjNo,
tjReportType:$tjReportType
},
success:function(d){
if(d.resultCode=="1000"){
//当请求成功时,设置二维码图片地址
$("#codeImg").attr('src',d.obj);
$("#orderId").val(d.attributes.orderId);
////当请求成功时,启动定时任务,每隔3秒去后台查询一次订单是否成功
f=setInterval(GetOrder,3000);
//GetOrder(true);
}
}
});
$(".selpaycon").css("display","none");
$(".weixinpay").css("display","block");
});
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。