微信支付和分享到朋友圈-struts版本
来源:互联网 发布:原生js实现数据绑定 编辑:程序博客网 时间:2024/04/29 09:32
上次写了一篇微信支付的文章,倒也还行就是逻辑上面有点欠妥当,这次针对这个问题我用struts2写了一套用于微信验证并能处理各种消息以及H5支付的一套程序,也针对分享到朋友圈这个功能使用了微信的jssdk,感触特别深,废话不多说下面就开始分享我的心得
一 微信如何和struts2整合
针对这个问题,网上基本没有这方面的资料,因此本人也就特别想针对这方面写篇博客,网上没资料其实道理很简单,首先java开发微信应用本身就比较少,市场都被php占领了;还有就是struts2的原因,目前市面上大家熟知的springmvc大大的挤压了struts的空间。所以.......
1 struts2整合微信的注意事项
struts2本身其实就是一个控制器,微信开发首先就是服务器配置那个部分的验证(使用GET请求)以及各种常用消息的接收和回复(POST)请求,因此只需在struts2里写方法暴露给微信服务器访问就OK,这个方法只要区分出GET和POST两种请求就行,GET请求就调用微信验证的相应方法,POST请求就调用消息处理的方法。这样就搞定了,来看下我的方法
package com.debug.weixin.action;import java.io.IOException;import java.io.PrintWriter;import java.io.UnsupportedEncodingException;import java.util.Map;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.struts2.ServletActionContext;import com.debug.weixin.service.CoreService;import com.debug.weixin.util.MessageUtil;import com.debug.weixin.util.SignUtil;import com.opensymphony.xwork2.ActionContext;public class WeixinAction {public void execute() {HttpServletRequest request = ServletActionContext.getRequest();HttpServletResponse response = ServletActionContext.getResponse();// 判断请求方法是get还是postString method = request.getMethod().trim();if ("get".equalsIgnoreCase(method)) {wxCheck(request, response);} else if ("post".equalsIgnoreCase(method)) {try {processRequest(request, response);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}public void wxCheck(HttpServletRequest request, HttpServletResponse response) {// 微信加密签名String signature = request.getParameter("signature");// 时间戳String timestamp = request.getParameter("timestamp");// 随机数String nonce = request.getParameter("nonce");// 随机字符串String echostr = request.getParameter("echostr");PrintWriter out = null;try {out = response.getWriter();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败if (SignUtil.checkSignature(signature, timestamp, nonce)) {out.print(echostr);}out.close();out = null;}public void processRequest(HttpServletRequest request, HttpServletResponse response) throws Exception{ request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); String encryptType = request.getParameter("encrypt_type"); // 微信加密签名 String signature = request.getParameter("signature"); // 时间戳 String timestamp = request.getParameter("timestamp"); // 随机数 String nonce = request.getParameter("nonce"); // 响应消息 try{ PrintWriter out = response.getWriter(); if (SignUtil.checkSignature(signature, timestamp, nonce)) { Map<String, String> requestMap = null; if("aes".equals(encryptType)){ requestMap=MessageUtil.parseXmlCrypt(request); String respXml=CoreService.processRequest(requestMap); respXml=MessageUtil.getWxCrypt().encryptMsg(respXml,timestamp,nonce); //System.out.println(respXml); out.print(respXml); }else{ requestMap=MessageUtil.parseXml(request); String respXml=CoreService.processRequest(requestMap); //respXml=MessageUtil.getWxCrypt().encryptMsg(respXml,timestamp,nonce); out.print(respXml); //System.out.println(respXml); } // 调用核心业务类接收消息、处理消息 //String respMessage = CoreService.processRequest(request); out.close(); } }catch(Exception e){ e.printStackTrace(); } }}
这个action还支持密文消息模式,下面就是struts的配置文件了:
<package name="weixin" namespace="/" extends="struts-default"> <action name="weixin" class="com.debug.weixin.action.WeixinAction"> </action> </package>
二 struts2版微信实现H5支付
微信H5支付其实是3种支付方式之中,最简单的一种,难点是取得openId和生成微信支付签名2个部分,下面我拆分开来说一下
为了简化操作我写了一个表单,只需填写订单号,提交之后取得openId之后直接调用统一下单接口跳转到支付确认界面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <base href="<%=basePath%>"> <title>提交订单</title><meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"> <meta name="description" content="admin-themes-lab"> <meta name="author" content="themes-lab"><!--<link rel="stylesheet" type="text/css" href="styles.css">--> </head> <body> <form action="order/order_payConfirm.action" method="POST"> 订单号:<input name="orderNo" id="orderNo" value="HK2015012315"/><br/> <input type="submit" value="提交订单"/> </form> </body></html>
接下来是Action里的代码
package com.debug.weixin.action;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import java.util.Map;import java.util.SortedMap;import java.util.TreeMap;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import net.sf.json.JSONObject;import org.apache.struts2.ServletActionContext;import com.debug.weixin.pojo.WeixinOauth2Token;import com.debug.weixin.util.AdvancedUtil;import com.debug.weixin.util.CommonUtil;import com.debug.weixin.util.ConfigUtil;import com.debug.weixin.util.PayCommonUtil;import com.debug.weixin.util.XMLUtil;public class OrderAction extends BaseAction{ public String orderIndex(){//HttpServletRequest request = ServletActionContext.getRequest();//HttpServletResponse response = ServletActionContext.getResponse(); return "orderIndex"; } public void payConfirm() throws Exception{HttpServletRequest request = ServletActionContext.getRequest();HttpServletResponse response = ServletActionContext.getResponse();String orderNo=request.getParameter("orderNo");response.sendRedirect(initOpenId("http://chenwill3.imwork.net/StrutsWX/order/order_h5Pay.action?orderNo="+orderNo)); } public void paySuccess() throws Exception{ HttpServletRequest request = ServletActionContext.getRequest(); HttpServletResponse response = ServletActionContext.getResponse();//这里处理订单 InputStream inStream = request.getInputStream(); ByteArrayOutputStream outSteam = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while ((len = inStream.read(buffer)) != -1) { outSteam.write(buffer, 0, len); } outSteam.close(); inStream.close(); String result = new String(outSteam.toByteArray(),"utf-8");//获取微信调用我们notify_url的返回信息 Map<Object, Object> map = XMLUtil.doXMLParse(result); for(Object keyValue : map.keySet()){ System.out.println(keyValue+"="+map.get(keyValue)); } if (map.get("result_code").toString().equalsIgnoreCase("SUCCESS")) { String orderNo=map.get("out_trade_no").toString(); response.getWriter().write(PayCommonUtil.setXML("SUCCESS", "")); //告诉微信服务器,我收到信息了,不要在调用回调action了 System.out.println("-------------"+PayCommonUtil.setXML("SUCCESS", "")); } } public String h5Pay() throws Exception{ HttpServletRequest request = ServletActionContext.getRequest(); HttpServletResponse response = ServletActionContext.getResponse(); String orderNo=request.getParameter("orderNo"); String code=request.getParameter("code"); WeixinOauth2Token token=AdvancedUtil.getOauth2AccessToken(ConfigUtil.APPID, ConfigUtil.APP_SECRECT, code); SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();parameters.put("appid", ConfigUtil.APPID);parameters.put("mch_id", ConfigUtil.MCH_ID);parameters.put("device_info", "1000"); parameters.put("body", "测试支付订单");parameters.put("nonce_str", PayCommonUtil.CreateNoncestr()); parameters.put("out_trade_no", orderNo);//parameters.put("total_fee", String.valueOf(combo.getPrice()*100));parameters.put("total_fee", "1");parameters.put("spbill_create_ip", request.getRemoteAddr());parameters.put("notify_url", ConfigUtil.NOTIFY_URL);parameters.put("trade_type", "JSAPI");parameters.put("openid", token.getOpenId());String sign = PayCommonUtil.createSign("UTF-8", parameters);//System.out.println("我 的签名是:"+sign); parameters.put("sign", sign);String requestXML = PayCommonUtil.getRequestXml(parameters);String result = CommonUtil.httpsRequestForString(ConfigUtil.UNIFIED_ORDER_URL,"POST", requestXML);System.out.println("----------------------------------");System.out.println(result);System.out.println("----------------------------------");String m=getH5PayStr(result,request);request.setAttribute("h5Info", m);return "wxPay"; }}
这个Action里最主要的方法是payConfirm和paySuccess,payConfirm调用之后会跳转到h5Pay这个方法,之后调用统一下单接口,调用之后进入支付确认界面,该界面的jsp代码如下
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <base href="<%=basePath%>"> <title>H5订单支付</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"> <meta name="description" content="admin-themes-lab"> <meta name="author" content="themes-lab"><!--<link rel="stylesheet" type="text/css" href="styles.css">--> </head> <script type="text/javascript">function jsApiCall(){WeixinJSBridge.invoke('getBrandWCPayRequest',${h5Info}, function(res){WeixinJSBridge.log(res.err_msg);//alert(res.err_code+res.err_desc+res.err_msg);if(res.err_msg == "get_brand_wcpay_request:ok" ) { alert("恭喜你,购买成功!"); }else{ alert("支付失败了,请联系商户!"); } });}function callpay(){if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', jsApiCall, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', jsApiCall); document.attachEvent('onWeixinJSBridgeReady', jsApiCall); }}else{ jsApiCall();}}</script> <body> <input type="button" value="确认支付" onclick="callpay()"/> </body></html>
这样支付流程就走通了,下面贴出BaseAction的2个主要方法:
public String initOpenId(String destUrl) throws Exception { String re = URLEncoder.encode(destUrl, "UTF-8"); String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect"; url = url.replace("APPID", ConfigUtil.APPID);url = url.replace("REDIRECT_URI", re); return url; } public String getH5PayStr(String result,HttpServletRequest request) throws Exception{ Map<String, String> map = XMLUtil.doXMLParse(result); SortedMap<Object,Object> params = new TreeMap<Object,Object>(); params.put("appId", ConfigUtil.APPID); params.put("timeStamp", Long.toString(new Date().getTime())); params.put("nonceStr", PayCommonUtil.CreateNoncestr()); params.put("package", "prepay_id="+map.get("prepay_id")); params.put("signType", ConfigUtil.SIGN_TYPE); String paySign = PayCommonUtil.createSign("UTF-8", params); params.put("packageValue", "prepay_id="+map.get("prepay_id")); //这里用packageValue是预防package是关键字在js获取值出错 params.put("paySign", paySign); //paySign的生成规则和Sign的生成规则一致 params.put("sendUrl", ConfigUtil.SUCCESS_URL); //付款成功后跳转的页面 String userAgent = request.getHeader("user-agent"); char agent = userAgent.charAt(userAgent.indexOf("MicroMessenger")+15); params.put("agent", new String(new char[]{agent}));//微信版本号,用于前面提到的判断用户手机微信的版本是否是5.0以上版本。 String json = JSONObject.fromObject(params).toString(); return json; }
第一个方法是按照获取openid的API写的方法,这个不解释,理解不了只能去看微信开发文档了;第二个方法是拼接用于H5支付的json串
关于支付来最后看下运行截图:
下面就是支付时的截图
到这里支付相关的代码就完结了
三 分享到朋友圈功能(使用JSSDK)
难点:取得AccessToken、取得JSAPITicket、生成jssdk签名
1 取得jsapiticket
accessToken的获取之前已经写过博客,这里直接进入取得jsapiticket的流程,java代码如下
public static JSAPITicket getJsApiTicket(String accessToken){String requestUrl="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";requestUrl=requestUrl.replace("ACCESS_TOKEN", accessToken);JSONObject json=CommonUtil.httpsRequest(requestUrl, "GET", null);JSAPITicket js=new JSAPITicket();js.setTicket(json.getString("ticket"));js.setExpires_in(json.getInt("expires_in"));return js;}
有关JSAPITicket方法的代码如下
package com.debug.weixin.pojo;public class JSAPITicket {private String ticket;private int expires_in;public String getTicket() {return ticket;}public void setTicket(String ticket) {this.ticket = ticket;}public int getExpires_in() {return expires_in;}public void setExpires_in(int expiresIn) {expires_in = expiresIn;}}
2 生成jssdk的签名
微信提供了一个生成签名的方法,我这边使用的代码和微信提供的形式上有点差异,但效果是一样的,下面是生成签名的方法
package com.debug.weixin.util;import java.util.Arrays;import java.util.UUID;import java.util.Map;import java.util.HashMap;import java.util.Formatter;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.io.IOException;import java.io.UnsupportedEncodingException; public class JSSDKSign {public static Map<String, Object> sign(String jsapi_ticket, String url) { Map<String, Object> ret = new HashMap<String, Object>(); String nonce_str = create_nonce_str(); String timestamp = create_timestamp(); String[] paramArr = new String[] { "jsapi_ticket=" + jsapi_ticket, "timestamp=" + timestamp, "noncestr=" + nonce_str, "url=" + url}; Arrays.sort(paramArr); // 将排序后的结果拼接成一个字符串 String content = paramArr[0].concat("&"+paramArr[1]).concat("&"+paramArr[2]) .concat("&"+paramArr[3]); String gensignature = null; try { MessageDigest md = MessageDigest.getInstance("SHA-1"); // 对拼接后的字符串进行 sha1 加密 byte[] digest = md.digest(content.toString().getBytes()); gensignature = byteToStr(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } ret.put("url", url); ret.put("jsapi_ticket", jsapi_ticket); ret.put("nonceStr", nonce_str); ret.put("timestamp", Long.parseLong(timestamp)); ret.put("signature", gensignature); return ret; }private static String byteToStr(byte[] byteArray) { String strDigest = ""; for (int i = 0; i < byteArray.length; i++) { strDigest += byteToHexStr(byteArray[i]); } return strDigest;}private static String byteToHexStr(byte mByte) { char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; char[] tempArr = new char[2]; tempArr[0] = Digit[(mByte >>> 4) & 0X0F]; tempArr[1] = Digit[mByte & 0X0F]; String s = new String(tempArr); return s;} private static String byteToHex(final byte[] hash) { Formatter formatter = new Formatter(); for (byte b : hash) { formatter.format("%02x", b); } String result = formatter.toString(); formatter.close(); return result; } private static String create_nonce_str() { return UUID.randomUUID().toString(); } private static String create_timestamp() { return Long.toString(System.currentTimeMillis() / 1000); }}
其实也就是自己加了几个方法,当然了用微信提供的sign方法也是OK的,如果微信自带的有问题,可以用我的
3 展示界面代码如下
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <title>分享到朋友圈</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"> <meta name="description" content="admin-themes-lab"> <meta name="author" content="themes-lab"><!--<link rel="stylesheet" type="text/css" href="styles.css">--> <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script> <script type="text/javascript" src="jquery.min.js"></script> </head> <script type="text/javascript"> $(document).ready(function(){initPage();});function initPage() {//alert(window.location.href);/***用于获得当前连接url用**//***用户点击分享到微信圈后加载接口接口*******/$.post("jssdk_getJSPara.action",{"url":'http://chenwill3.imwork.net/StrutsWX/jssdk_toSharePage.action'},function(data,status){ wx.config({ debug: true, appId: '你的appId', timestamp:Number(data.timestamp), nonceStr:data.nonceStr, signature:data.signature, jsApiList: [ 'checkJsApi', 'onMenuShareTimeline', 'hideOptionMenu' ] });});wx.ready(function(){ wx.checkJsApi({ jsApiList: [ 'onMenuShareTimeline', ] }); wx.onMenuShareTimeline({ title: '互联网之子', link: 'http://wx.vland.cc/mobile.php?act=module&rid=406&fromuser=oktsYuHivHXuzdsMeCbWyF7b14UU&name=hllihe&do=sharelihe&weid=7', imgUrl: 'http://wx.vland.cc/resource/attachment/images/7/2015/01/fl2Lk2p5o3iOJP3jdp9iPXI9i93iPm.jpg', trigger: function (res) { alert('用户点击分享到朋友圈'); }, success: function (res) { alert('已分享'); }, cancel: function (res) { alert('已取消'); }, fail: function (res) { alert('wx.onMenuShareTimeline:fail: '+JSON.stringify(res)); } }); }); };function share(){ } </script> <body> <input type="button" value="分享" onclick="share()"/> </body></html>
出现这样的alert说明jssdk配置成功了,为了保险起见一般还要判断下微信浏览器是否支持分享到朋友圈
接下来就是点右上方的分享到朋友圈测功能了
输入内容点发送就OK
最后打开朋友圈就能看到分享的东西了
一般情况下这种场景是用在点分享到朋友圈要分享值得内容的功能,正常情况或没特别定制性要求的应用可能用不到,使用jssdk要注意配置这里:
如果是微信支付要配置网页账号和微信支付开发配置
微信支付开发配置一般如下
- 微信支付和分享到朋友圈-struts版本
- 微信分享到朋友圈和会话
- 微信分享到朋友圈
- 微信6.0.2版本js获取分享到朋友圈和发送给朋友事件
- UC浏览器 分享到朋友圈和微信好友
- 微信分享多个图片和文字到朋友圈
- 微信开发--分享到朋友圈和发送给好友
- 微信和微信朋友圈分享
- 微信分享到朋友圈JS代码
- 微信分享到朋友圈JS代码
- iOS 微信分享到朋友圈
- 微信分享页面到朋友圈
- 微信分享到朋友圈接口用法
- 微信分享到朋友或朋友圈
- 微信公众号开发--微信JS-SDK分享到朋友圈和分享给朋友
- 在微信浏览器中做分享到朋友圈和分享到好友
- React-Native之微信好友、朋友圈分享、支付
- React-Native之微信好友、朋友圈分享、支付
- PAT 1050. String Subtraction (20)
- 1051 Pop Sequence
- 使用@property
- delphi7编程技巧
- Leetcode166: Number of Islands
- 微信支付和分享到朋友圈-struts版本
- 【Spark系列2】reduceByKey和groupByKey区别与用法
- ns3的编译伏击
- J2EE实验4:Cookie操作
- 1189: HH的字符逆序
- tabBarController
- Stack
- jQuery--元素抖动效果的简单实现
- SSH面试常考题(1)