1.配置测试支付目录域名,添加测试公众号。
2.因为公众号支付需要openid,所以配置网页授权域名。
3.pay页面调用H5微信授权,回调returnWxPay。
function wxpay(params){
var json = "{";
for(var item in params){
var value=params[item];//key所对应的value
json = json+"%22"+item+"%22:"+value+",";
}
json = json+"}";
var url = "http://xm.ysyisu.cn/server/returnWxPay";
var str = "https://open.weixin.qq.com/connect/oauth2/authorize?"+
"appid=wx87019669d6f33b43&"+
"redirect_uri="+encodeURI(url)+"&"+
"response_type=code&"+
"scope=snsapi_base&"+
"state="+json+
"#wechat_redirect";
window.location.href=str;
}
4、到回调方法执行业务,返回weixinPay页面
@RequestMapping("/returnWxPay")
public String returnWxPay(Model m,HttpServletRequest request,String code){
Map<String, Object> map = service.returnWxPay(request,code);
String state = request.getParameter("state");
int jsontype = service.getJSONType(state);
JSONObject json = new JSONObject();
JSONArray arr = new JSONArray();
if(jsontype==0){
json = new JSONObject(state);
Integer type = (Integer) json.get("type");
Integer mid = (Integer) json.get("mid");
Double price = (Double) json.get("price");
map.put("type", type);
map.put("mid", mid);
map.put("price", price);
if(type==1){ //广告
}else if(type==2){ //单品
Integer goodnum = (Integer) json.get("goodnum");
map.put("goodnum", goodnum);
}else if(type==3){ //购物车
}else if(type==4){ //头条
}
}else if(jsontype==1){ //购物车 购物车的类别为jsonarray
map.put("type", 3);
}
m.addAttribute("map", map);
return "client/weixinPay";
}
5.取到openid
public Map<String, Object> returnWxPay(HttpServletRequest request,String code) {
Map<String, String> result = UserServiceImpl.getUserInfoAccessToken(code);//通过这个code获取access_tokenString openId = result.get("openid");
Map<String, Object> param = new HashMap<String, Object>();
param.put("openid", openId);
Map<String, Object> map = new HashMap<String, Object>();
try {
map = WeixinReturn(request,param);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return map;
}
6.调用统一下单接口 并封装公众号H5调用支付的参数
// 请求微信服务器返回xml
public Map<String, Object> WeixinReturn(HttpServletRequest request,Map<String, Object> map)throws UnsupportedEncodingException {
String ip = getIpAddr(request); //获取真实IP
map = return_yw(request, map); //返回业务map 1.订单 2.金额 3.各类参数
Map<String, Object> result = new HashMap<String, Object>();
long a = Long.parseLong(String.valueOf(System.currentTimeMillis()).toString().substring(0,10));
String url = WeixinPayUtil.order_url;
Document doc = DocumentHelper.createDocument();
doc.setXMLEncoding("utf-8");
Element xml = doc.addElement("xml");
//公众账号ID
Element appid = xml.addElement("appid");
appid.addCDATA(WeixinPayUtil.appid);
//商户号
Element mch_id = xml.addElement("mch_id");
mch_id.addCDATA(WeixinPayUtil.mch_id);
//随机字符串
Element nonce_str = xml.addElement("nonce_str");
String suiji = WeixinPayUtil.MD5Encode("" + Math.random(),"utf-8");
nonce_str.addCDATA(suiji);
//商品描述
Element body = xml.addElement("body");
String str = "xm-sp";
body.addCDATA(str);
//商户订单号
Element out_trade_no = xml.addElement("out_trade_no");
out_trade_no.addCDATA(map.get("out_trade_no").toString());
//标价金额
Element total_fee = xml.addElement("total_fee");
total_fee.addCDATA(String.valueOf((int) Math.floor(Double.parseDouble(map.get("total_fee").toString()) * 100)));
//终端IP
Element spbill_create_ip = xml.addElement("spbill_create_ip");
spbill_create_ip.addCDATA(ip);
//通知地址
Element notify_url = xml.addElement("notify_url");
notify_url.addCDATA(WeixinPayUtil.notify_url);
//交易类型
Element trade_type = xml.addElement("trade_type");
trade_type.addCDATA(WeixinPayUtil.trade_type);
//openid
Element openid = xml.addElement("openid");
openid.addCDATA((String) map.get("openid"));
//参数attach
Element attach = xml.addElement("attach");
attach.addCDATA((String) map.get("attach"));
SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
parameters.put("appid", WeixinPayUtil.appid);
parameters.put("body", str);
parameters.put("mch_id", WeixinPayUtil.mch_id);
parameters.put("nonce_str", suiji);
parameters.put("notify_url", WeixinPayUtil.notify_url);
parameters.put("out_trade_no", map.get("out_trade_no").toString());
parameters.put("spbill_create_ip", ip);
parameters.put("total_fee", String.valueOf((int) Math.floor(Double.parseDouble(map.get("total_fee").toString()) * 100)));
parameters.put("trade_type", WeixinPayUtil.trade_type);
parameters.put("openid", (String) map.get("openid"));
parameters.put("attach", (String) map.get("attach"));
//签名
String stringSign = WeixinPayUtil.createSign("UTF-8", parameters);
Element sign = xml.addElement("sign");
sign.addCDATA(stringSign);
String xmlString = doc.asXML();
String xx = sendPost(url, xmlString); //调用统一下单
//String xx = doPost(url, xmlString, "utf-8");
Map<String, Object> res = new HashMap<String, Object>();
try {
Document reDocument = DocumentHelper.parseText(xx);
Element root = reDocument.getRootElement();
for (Iterator it = root.elementIterator(); it.hasNext();) {
Element element = (Element) it.next();
String name = element.getName();
String text = element.getTextTrim();
if("mch_id".equals(name)){
res.put("partnerId", text);
result.put("partnerId", text);
}else{
res.put(name, text);
result.put(name,text);
}
}
res.put("timestamp", Long.toString(a));
String return_code = res.get("return_code").toString();
String return_msg = res.get("return_msg").toString();
result.put("return_code", return_code);
result.put("return_msg", return_msg);
if (!return_code.equals("SUCCESS")){
return result;
}
String packageValue = "prepay_id="+res.get("prepay_id");
SortedMap<Object, Object> parm = new TreeMap<Object, Object>();
parm.put("appId", WeixinPayUtil.appid);
parm.put("timeStamp", Long.toString(a));
parm.put("nonceStr", res.get("nonce_str"));
parm.put("package", packageValue);
parm.put("signType", "MD5");
String returnSign = WeixinPayUtil.createSign("UTF-8", parm);
result.put("appid", WeixinPayUtil.appid);
result.put("timestamp", Long.toString(a));
result.put("noncestr", res.get("nonce_str"));
result.put("package", packageValue);
result.put("signType", "MD5");
result.put("mch_id", WeixinPayUtil.mch_id);
result.put("paySign", returnSign);
result.put("prepay_id", res.get("prepay_id"));
result.put("paySign", returnSign);
//业务
result.put("out_trade_no", map.get("out_trade_no")); //订单号
result.put("total_fee", map.get("total_fee")); //总金额
} catch (DocumentException e) {
e.printStackTrace();
return result;
}
return result;
}
/**
* 向指定 URL 发送POST方法的请求
*
* @param url
* 发送请求的 URL
* @param param
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(
new InputStreamReader(conn.getInputStream(),"utf-8"));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!"+e);
e.printStackTrace();
}
//使用finally块来关闭输出流、输入流
finally{
try{
if(out!=null){
out.close();
}
if(in!=null){
in.close();
}
}
catch(IOException ex){
ex.printStackTrace();
}
}
return result;
}
public String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
7.返回weixinPay页面,支付成功回调通知地址notify_url,该地址不能带其他参数,参数通过attach来传递
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
<script type="text/javascript">
var appId = "${map.appid}";
var timeStamp = "${map.timestamp}";
var nonceStr = "${map.noncestr}";
var prepay_id = "${map.prepay_id}";
var signType ="${map.signType}";
var paySign = "${map.paySign}";
var type = "${map.type}";
/* var mid = "${map.mid}";
var price = "${map.price}";
var goodnum = "${map.goodnum}"; */
/* wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: appId, // 必填,公众号的唯一标识
timestamp: timeStamp, // 必填,生成签名的时间戳
nonceStr: nonceStr, // 必填,生成签名的随机串
signature: paySign,// 必填,签名,见附录1
jsApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
}); */
function onBridgeReady(){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId" : appId, //公众号名称,由商户传入
"timeStamp": timeStamp, //时间戳,自1970年以来的秒数
"nonceStr" : nonceStr, //随机串
"package" : "prepay_id=" + prepay_id,
"signType" : signType, //微信签名方式:
"paySign" : paySign //微信签名
},
function(res){
WeixinJSBridge.log(res.err_msg);
if(res.err_msg == "get_brand_wcpay_request:ok"){
if(type==1){
window.location.href="${basePath}advert/manager";
}else if(type==2){
window.location.href="${basePath}order/manager";
}else if(type==3){
window.location.href="${basePath}order/manager";
}else if(type==4){
window.location.href="${basePath}main/details";
}
}else{
//返回跳转到订单详情页面
alert("支付失败!请重新下单再试!");
}
}
);
/* wx.chooseWXPay({
timestamp: timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
nonceStr: nonceStr, // 支付签名随机串,不长于 32 位
package: "prepay_id="+prepay_id, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
signType: signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
paySign: paySign, // 支付签名
success: function (res) {
// 支付成功后的回调函数
}
}); */
}
function pay(){
if (typeof WeixinJSBridge == "undefined"){
if( documentaddEventListener ){
documentaddEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}else if (documentattachEvent){
documentattachEvent('WeixinJSBridgeReady', onBridgeReady);
documentattachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
}else{
onBridgeReady();
}
}
</script>
8.通知回调
//微信通知 支付回调
public void weixinNotify(HttpServletRequest request,HttpServletResponse response) throws Exception{
InputStream inputStream;
StringBuffer sb = new StringBuffer();
inputStream = request.getInputStream();
String s ;
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
while ((s = in.readLine()) != null){
sb.append(s);
}
in.close();
inputStream.close();
//解析xml成map
Map<String, Object> m = new HashMap<String, Object>();
//m = XmlConverUtil.xmltoMap(sb.toString());
//m = XmlConverUtil.parseXmlStr(sb.toString());
Document document = DocumentHelper.parseText(sb.toString());
m = XmlConverUtil.Dom2Map(document);
//过滤空 设置 TreeMap
SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();
Iterator it = m.keySet().iterator();
while (it.hasNext()) {
String parameter = (String) it.next();
String parameterValue = m.get(parameter).toString();
String v = "";
if(null != parameterValue) {
v = parameterValue.trim();
}
packageParams.put(parameter, v);
}
// 账号信息
String key = WeixinPayUtil.key; // key
//判断签名是否正确
if(WeixinPayUtil.isTenpaySign("UTF-8", packageParams)) {
//------------------------------
//处理业务开始
//------------------------------
String resXml = "";
if("SUCCESS".equals((String)packageParams.get("result_code"))){
Map<String, Object> newMap = new HashMap<String, Object>();
// 这里是支付成功
//执行自己的业务逻辑
String out_trade_no = packageParams.get("out_trade_no").toString(); //系统订单
String total_fee = packageParams.get("total_fee").toString(); //金额
String transaction_id = packageParams.get("transaction_id").toString(); //微信订单
Double price = Double.valueOf(total_fee)/100;
String attach = packageParams.get("attach").toString();
int jsontype = getJSONType(attach);
JSONObject json = new JSONObject();
JSONArray arr = new JSONArray();
if(jsontype==0){
json = new JSONObject(attach);
Integer type = (Integer) json.get("type");
Integer uid = (Integer) json.get("uid");
Integer mid = (Integer) json.get("mid");
User user = dao.getUniqueResult(User.class, "id", uid); // 查询到人员信息
newMap.put("out_trade_no", out_trade_no);
newMap.put("total_fee", price);
newMap.put("transaction_id", transaction_id);
newMap.put("uid", uid);
newMap.put("type", type);
newMap.put("mid", mid);
if(type==1){ //广告
dao.updateEntity(Advert.class, new String[]{"price","paytime","status","transaction_id"},
new Object[]{price,TimeUtil.getUnixTimestamp(),1,transaction_id},
new String[]{"id"}, new Object[]{mid});
this.createOrder(newMap);
}else if(type==2){ //单品
Integer goodnum = (Integer) json.get("goodnum");
//Double price = Double.valueOf(total_fee)/100;
//订单表支付状态变更
dao.updateEntity(Order.class, new String[]{"status","paytype","paytime","transaction_id","total_fee","paykind"},
new Object[]{1,1,TimeUtil.getUnixTimestamp(),transaction_id,price,"2"},
new String[]{"id","uid"}, new Object[]{mid,uid});
//商品表 销量、总量变更
Order order = (Order) dao.getEntity(Order.class,mid);;
Good good = (Good) dao.getEntity(Good.class,order.getGid());
//取到商品销售 总量
int sales = good.getSales();
int total = good.getTotal();
//取到商品数量
dao.updateEntity(Good.class, new String[]{"sales","total"}, new Object[]{sales+goodnum,total-goodnum},
new String[]{"id"}, new Object[]{good.getId()});
}else if(type==3){ //购物车
}else if(type==4){ //头条
//保存头条信息
TopAdvert top = new TopAdvert();
top.setAid(mid);
top.setPaymoney(price);
top.setPaytime(TimeUtil.getUnixTimestamp());
top.setTransaction_id(transaction_id);
Integer tid = dao.saveEntityRetrunId(top);
newMap.put("tid", tid);
this.createOrder(newMap);
}
//防止seesion中user失效 重新塞入
HttpSession session = request.getSession();
session.setAttribute("Uid", uid);
session.setAttribute("User",user);
}else if(jsontype==1){ //购物车 购物车的类别为jsonarray
int uid_ = 0;
attach = attach.replaceAll("'", "\"");
arr = new JSONArray(attach);
for(int i=0;i<arr.length();i++){
JSONObject obj = arr.getJSONObject(i);
int mid = obj.getInt("mid");
int uid = obj.getInt("uid");
uid_ = uid;
//订单表支付状态变更
dao.updateEntity(Order.class, new String[]{"status","paytype","paytime","transaction_id","total_fee","paykind"},
new Object[]{1,1,TimeUtil.getUnixTimestamp(),transaction_id,price,"3"},
new String[]{"id","uid"}, new Object[]{mid,uid});
//商品表 销量、总量变更
Order order = (Order) dao.getEntity(Order.class,mid);;
Good good = (Good) dao.getEntity(Good.class,order.getGid());
//取到商品销售 总量
int sales = good.getSales();
int total = good.getTotal();
int goodnum = order.getGoodnum();
//取到商品数量
dao.updateEntity(Good.class, new String[]{"sales","total"}, new Object[]{sales+goodnum,total-goodnum},
new String[]{"id"}, new Object[]{good.getId()});
}
//防止seesion中user失效 重新塞入
HttpSession session = request.getSession();
session.setAttribute("Uid", uid_);
User user = dao.getUniqueResult(User.class, "id", uid_); // 查询到人员信息
session.setAttribute("User",user);
}
//执行自己的业务逻辑
//通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
} else {
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[付款失败]]></return_msg>" + "</xml> ";
}
//------------------------------
//处理业务完毕
//------------------------------
BufferedOutputStream out = new BufferedOutputStream(
response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
} else{
}
}