微信开发部分。是关于微信公众平台的开发。
首先需要一个已经认证过的公众号。(是服务号)
配置好:服务器地址,token,域名,等等基本配置。这就是在公众号后台上做的基本配置。
接着就是代码的部分。
weixin.properties里面写好基本信息appid ,secret,token等基本信息与公众号一致。看调用的接口需要什么参数就配置什么。具体参见微信开发者文档https://mp.weixin.qq.com/wiki。
首先是关于菜单的生成。配置json数据,一级菜单和二级菜单的那么以及对应的url。然后传给微信。在浏览器访问这条链接。就会在对应的公众号平台生成菜单了。需要特别注意的地方-- 并没有需要特别注意的地方,大概就是微信菜单访问的地址不要弄错,记得菜单对应的链接是域名地址。
@RequestMapping("/menu")
@ResponseBody
public JSONObject menu(HttpServletRequest request){//http://cj.zptmall.com/v-U6128CJ683
String menuJson="{\"button\":[{\"type\":\"view\",\"name\":\"首页\",\"url\":\""+"http://xz.zptmall.com/xz/mobile/mainindex/index\"},"
+ "{\"name\":\"学生入口\",\"sub_button\":[{\"type\":\"view\",\"name\":\"找工作\",\"url\":\""+weixin.getWebsite()+"job/searchjob\"},{\"type\":\"view\",\"name\":\"投递箱\",\"url\":\""+weixin.getWebsite()+"student/deliverybox/1\"}]},"+
"{\"name\":\"企业入口\",\"sub_button\":[{\"type\":\"view\",\"name\":\"找人才\",\"url\":\""+weixin.getWebsite()+"enterprise/discovertalent\"},{\"type\":\"view\",\"name\":\"简历箱\",\"url\":\""+weixin.getWebsite()+"enterprise/resumebox/1\"}]}]}";
System.out.println(menuJson);
String accessToken = WeixinUtils.getAccessToken(weixin.getAppId(),weixin.getSecret());
String createMenuUrl = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token="+accessToken;
JSONObject jsonObject = WeixinUtils.httpRequest(createMenuUrl, "POST", menuJson);
return jsonObject;
}
接下来的就是通过进行我们自己想要的操作了。将html5的页面嵌入微信。注意页面的调节。字体大小,比例等等都是需要注意的地方。字体一般使用rem(em)作为单位。页面的高度按照百分比进行设定。如果实在无法适配,就只能采用利用js来控制。
关于微信拦截器的设置。用来判断用户是否授权是否登录。当然,如果用户没有登录,或者当前用户权限不允许访问这条链接的时候也会要求用户重新登录。这部分的判断则写入了用户登录的拦截器中。
这部分要注意的地方。保存用户的openID。以及用户的accesstoken是会每7200s失效一次的。所以我们要每次去刷新它,这是无法写死的参数。
//这是微信的拦截部分,每一条在微信上访问的链接实际上都会被微信先转换一次。
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object obj) throws Exception {
System.out.println("w333");
/* request.getSession().setAttribute(Constant.SESSION_OPENID,
"ozmycs1l5krwfrpVDUcYVdN0o7vw");*/
if (request.getSession().getAttribute(Constant.SESSION_OPENID) == null
|| request.getSession().getAttribute(Constant.SESSION_OPENID) == "") {
if (request.getParameterMap().get("code") != null
&& !StringUtils.isEmpty(((String[]) request.getParameterMap().get("code"))[0])) {
String[] code = (String[]) request.getParameterMap().get("code");
String openidPath = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + weixin.getAppId()
+ "&secret=" + weixin.getSecret().trim() + "&code=" + String.valueOf(code[0])
+ "&grant_type=authorization_code";
System.out.println(openidPath + "openidPath");
JSONObject jsonObject = WeixinUtils.httpRequest(openidPath, "GET", null);
System.out.println(jsonObject + "jsonObject");
String openid = jsonObject.getString("openid");
request.getSession().setAttribute(Constant.SESSION_OPENID, openid);
if (openid != null && openid != "") {
EnterpriseUser user = userService.getuserByOpenId(openid);
if(user != null){
request.getSession().setAttribute("user", user);
}
}
} else {
String requestPath = URLEncoder.encode(request.getRequestURL().toString(), "UTF-8");
String codePath = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + weixin.getAppId()
+ "&redirect_uri=" + requestPath
+ "&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";
response.sendRedirect(codePath);
return false;
}
}
return true;
}
/**
* 获取微信的accesstoken
*
* @param appid
* @param secret
* @return
*/
public static String getAccessToken(String appid, String secret) {
String accessToken = null;
String requestUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid
+ "&secret=" + secret;
JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
if (null != jsonObject) {
try {
accessToken = jsonObject.getString("access_token");
} catch (JSONException e) {
e.printStackTrace();
}
}
return accessToken;
}
微信支付部分
这次主要做的是微信扫码支付。即在网页生成二维码。在微信上进行扫码,进行支付的过程。
这次的二维码生成引用了插件qrcode。将信息传给微信,将微信返回的链接在网页生成二维码。微信将会生成一个订单号orderid,在支付的时候要将这个订单号传回给微信。
/**
* 获取微信扫码支付二维码连接
*/
public static String getCodeurl(WxPayDto tpWxPayDto) {
// 1 参数
// 订单号
String orderId = tpWxPayDto.getOrderId();
// 附加数据 原样返回
String attach = "";
// 总金额以分为单位,不带小数点
String totalFee = getMoney(tpWxPayDto.getTotalFee());
// 订单生成的机器 IP
String spbill_create_ip = tpWxPayDto.getSpbillCreateIp();
// 这里notify_url是 支付完成后微信发给该链接信息,可以判断会员是否支付成功,改变订单状态等。
String notify_url = notifyurl;
String trade_type = "NATIVE";
// 商户号
String mch_id = partner;
// 随机字符串
String nonce_str = getNonceStr();
// 商品描述根据情况修改
String body = tpWxPayDto.getBody();
// 商户订单号
String out_trade_no = orderId;
SortedMap<String, String> packageParams = new TreeMap<String, String>();
packageParams.put("appid", appid);
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);
// 这里写的金额为1 分到时修改
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);
RequestHandler reqHandler = new RequestHandler(null, null);
reqHandler.init(appid, appsecret, partnerkey);
String sign = reqHandler.createSign(packageParams);
String xml = "<xml>" + "<appid>" + appid + "</appid>" + "<mch_id>" + mch_id + "</mch_id>" + "<nonce_str>"
+ nonce_str + "</nonce_str>" + "<sign>" + sign + "</sign>" + "<body><![CDATA[" + body + "]]></body>"
+ "<out_trade_no>" + out_trade_no + "</out_trade_no>" + "<attach>" + attach + "</attach>"
+ "<total_fee>" + totalFee + "</total_fee>" + "<spbill_create_ip>" + spbill_create_ip
+ "</spbill_create_ip>" + "<notify_url>" + notify_url + "</notify_url>" + "<trade_type>" + trade_type
+ "</trade_type>" + "</xml>";
String code_url = "";
String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
code_url = new GetWxOrderno().getCodeUrl(createOrderURL, xml);
System.out.println("code_url----------------" + code_url);
return code_url;
}
//前端将链接生成二维码
var url = result.payurl;
$("#orderid").val(result.orderid);
//参数1表示图像大小,取值范围1-10;参数2表示质量,取值范围'L','M','Q','H'
var qr = qrcode(10, 'M');
qr.addData(url);
qr.make();
var dom = document.createElement('DIV');
var pp=document.createElement('p');
dom.innerHTML = qr.createImgTag();
pp.innerHTML="扫我支付--";
var element = document.getElementById("qrcode");
element.innerHTML ='';
element.appendChild(pp);
element.appendChild(dom);
然后不间断的访问后台获取支付结果的链接,等待支付成功。微信将自动根据orderid号更新这条订单的状态,这时候我们将这个结果在数据库进行更改。
------------------------我是分割线------------------------------
这里关于更改订单状态的操作。当订单状态被修改时,系统要更改的地方也要同时进行操作,这是一个事务性的操作。不能在外面获取订单状态之后再进行操作。
如果要复用这一个支付操作结果(一个系统中不止一个地方会使用支付),两种方式:1.设计订单表示加入相关字段信息2.已?id=的形式带入参数。
@RequestMapping("/result")
public String result(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.print("微信支付回调数据开始");
// 示例报文
// String xml =
// "<xml><appid><![CDATA[wxb4dc385f953b356e]]></appid><bank_type><![CDATA[CCB_CREDIT]]></bank_type><cash_fee><![CDATA[1]]></cash_fee><fee_type><![CDATA[CNY]]></fee_type><is_subscribe><![CDATA[Y]]></is_subscribe><mch_id><![CDATA[1228442802]]></mch_id><nonce_str><![CDATA[1002477130]]></nonce_str><openid><![CDATA[o-HREuJzRr3moMvv990VdfnQ8x4k]]></openid><out_trade_no><![CDATA[1000000000051249]]></out_trade_no><result_code><![CDATA[SUCCESS]]></result_code><return_code><![CDATA[SUCCESS]]></return_code><sign><![CDATA[1269E03E43F2B8C388A414EDAE185CEE]]></sign><time_end><![CDATA[20150324100405]]></time_end><total_fee>1</total_fee><trade_type><![CDATA[JSAPI]]></trade_type><transaction_id><![CDATA[1009530574201503240036299496]]></transaction_id></xml>";
String inputLine;
String notityXml = "";
String resXml = "";
try {
while ((inputLine = request.getReader().readLine()) != null) {
notityXml += inputLine;
}
request.getReader().close();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("接收到的报文:" + notityXml);
Map m = parseXmlToList2(notityXml);
WxPayResult wpr = new WxPayResult();
wpr.setAppid(m.get("appid").toString());
wpr.setBankType(m.get("bank_type").toString());
wpr.setCashFee(m.get("cash_fee").toString());
wpr.setFeeType(m.get("fee_type").toString());
wpr.setIsSubscribe(m.get("is_subscribe").toString());
wpr.setMchId(m.get("mch_id").toString());
wpr.setNonceStr(m.get("nonce_str").toString());
wpr.setOpenid(m.get("openid").toString());
wpr.setOutTradeNo(m.get("out_trade_no").toString());
wpr.setResultCode(m.get("result_code").toString());
wpr.setReturnCode(m.get("return_code").toString());
wpr.setSign(m.get("sign").toString());
wpr.setTimeEnd(m.get("time_end").toString());
wpr.setTotalFee(m.get("total_fee").toString());
wpr.setTradeType(m.get("trade_type").toString());
wpr.setTransactionId(m.get("transaction_id").toString());
if ("SUCCESS".equals(wpr.getResultCode())) {
// 支付成功
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
String orderid = m.get("out_trade_no").toString();
//在这里更改状态时,要将事务性的操作都做完
payService.UpdateDealStatus(orderid);
} else {
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
}
System.out.println("微信支付回调数据结束");
BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
// 更新数据库的状态
return resXml;
}
在前台获取到状态已变成已支付之后,整个过程就完成了。
需要注意商户号和partenerkey的设置。具体参见https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1。