1. 具体的流程及需要注意的地方见文档
2.调用的htmljs代码
function weixinPay(){
var totalprice=$("#totalprice").html();
totalprice='0.01';
totalprice=Number(totalprice)*100;
window.location.href="https://open.weixin.qq.com/connect/oauth2/authorize?appid=xxx&redirect_uri=http%3A%2F%2Fwx.nongyuancui.com%2Fnyc%2Fwap%2Fweixin_openid.action?totalprice="+totalprice+"&response_type=code&scope=snsapi_base&state=123#wechat_redirect";
//回调地址 注意编码 ':' 用'%3A'代替 '/' 用'%2F'代替
}
2.java 代码
WeixinController
package xhsoft.yxd.wap.controller;
import java.util.Date;
import java.util.HashMap;
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.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import xhsoft.utils.EnvUtils;
import xhsoft.utils.StringUtils;
import xhsoft.web.exp.BusinessExeption;
import xhsoft.yxd.base.model.PayStatus;
import xhsoft.yxd.base.service.IPayStatus;
import xhsoft.yxd.core.constant.WeiXinPayInfo;
import xhsoft.yxd.core.constant.WeiXinPayOrderInfo;
import xhsoft.yxd.core.mv.WapModelAndView;
import xhsoft.yxd.core.uitl.PropertyUtil;
import xhsoft.yxd.core.weixintools.HttpRequest;
import xhsoft.yxd.core.weixintools.Signature;
import xhsoft.yxd.core.weixintools.WeiXinUtils;
/**
* @author WangMeng
* @date 2017年1月11日
*/
@Controller
@RequestMapping("/wap")
public class WeixinController
{
@Autowired
IPayStatus payStatusService;
private static Logger logger = Logger.getLogger(WeixinController.class);
/**
* 获取微信用户openId
*
* @param request
* @param response
* @param buyerId
* @author WangMeng
* @date 2016年6月7日
*/
@RequestMapping(value = "/weixin_openid")
public ModelAndView getOpenId(HttpServletRequest request, HttpServletResponse response)
throws BusinessExeption
{
String code = request.getParameter("code");
String totalprice = request.getParameter("totalprice");
String oauth_url = StringUtils.format(
"{0}?appid={1}&secret={2}&code={3}&grant_type=authorization_code",
WeiXinPayInfo.OPIDURL, WeiXinPayInfo.APPID, WeiXinPayInfo.SECERT, code);
JSONObject jsonObject = null;
try
{
jsonObject = HttpRequest.httpsRequestToJsonObject(oauth_url, "POST", null);
}
catch (Exception e)
{
logger.error("微信支付发送acctoken请求异常");
throw new BusinessExeption("微信支付发送acctoken请求异常", e);
}
Object errorCode = jsonObject.get("errcode");
String openId = "";
if (errorCode != null)
{
logger.error("微信支付请求openId发送请求返回错误,错误码:" + errorCode);
}
else
{
openId = jsonObject.getString("openid");
}
return weixinPay(openId, request, response, Integer.parseInt(totalprice));
}
/**
* 根据openId进行预支付,获取信息
*
* @param openId
* @param request
* @param response
* @return
* @author WangMeng
* @date 2016年6月8日
*/
private ModelAndView weixinPay(String openId, HttpServletRequest request,
HttpServletResponse response, int totalPrice) throws BusinessExeption
{
// 预支付请求返回的map集合
Map<String, String> map = new HashMap<String, String>();
// 返回给前端页面进行支付的数据
SortedMap<Object, Object> params = new TreeMap<Object, Object>();
String out_trade_no = EnvUtils.getHashId();
try
{
String sign = WeiXinUtils.getSign(request, openId, out_trade_no, totalPrice);
map = HttpRequest.httpsRequestToXML(WeiXinPayInfo.PREPARE, "POST", sign);
}
catch (java.lang.Exception e)
{
logger.error("微信签名异常");
throw new BusinessExeption("微信支付发送授权请求异常", e);
}
params.put("appId", WeiXinPayInfo.APPID);
params.put("timeStamp", Long.toString(new Date().getTime()));
params.put("nonceStr", WeiXinUtils.create_nonce_str().replace("-", ""));
params.put("signType", WeiXinPayOrderInfo.SIGNTYPE);
String packageValue = StringUtils.format("prepay_id={0}", map.get("prepay_id"));
params.put("package", packageValue);
String paySign = Signature.createSign("UTF-8", params);
params.put("packageValue", packageValue); // 这里用packageValue是预防package是关键字在js获取值出错
params.put("paySign", paySign); // paySign的生成规则和Sign的生成规则一致
params.put("sendUrl", WeiXinPayOrderInfo.NOTIFY); // 付款成功后跳转的页面
params.put("out_trade_no", out_trade_no); // 付款成功后跳转的页面
ModelAndView mv = new WapModelAndView("wap/weixin.html", request, response);
mv.addObject("payParams", params);
return mv;
}
/**
* 发送微信授权请求 TODO 暂时在前段使用localtion.href发请求,不清楚为什么后台发这个请求不好用
*
* @param request
* @param response
* @param buyerId
* @author WangMeng
* @date 2016年6月7日
*/
@RequestMapping(value = "/weixin_outh")
public void sendouth(HttpServletRequest request, HttpServletResponse response)
throws BusinessExeption
{
System.out.println("weixin_outh start............");
String autoCallbackUrl;
try
{
String key = StringUtils
.format("appid={1}&redirect_uri={2}&response_type=code&scope=snsapi_base&state=123#wechat_redirect",
WeiXinPayInfo.OAUTHURL, PropertyUtil.getProperty("wxGZpay_appId"),
PropertyUtil.getProperty("wxGZpay_auth_callurl"));
// System.out.println("weixin_outh outhUrl............" + outhUrl);
// HttpRequest.httpsRequest(outhUrl, "GET", null);
System.out.println("key:" + key);
// System.out
// .println(HttpRequest
// .sendGet("https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx19026bd3a5c42ed2&redirect_uri=http%3A%2F%2Fwx.nongyuancui.com%2Fnyc%2Fwap%2Fweixin_openid.action&response_type=code&scope=snsapi_base&state=123#wechat_redirect"));
response.sendRedirect("https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx19026bd3a5c42ed2&redirect_uri=http%3A%2F%2Fwx.nongyuancui.com%2Fnyc%2Fwap%2Fweixin_openid.action&response_type=code&scope=snsapi_base&state=123#wechat_redirect");
}
catch (Exception e)
{
logger.error("微信支付发送授权请求异常", e);
throw new BusinessExeption("微信支付发送授权请求异常", e);
}
}
/**
* 验证是否支付成功
*
* @param request
* @param response
* @author WangMeng
* @date 2016年6月8日
*/
@ResponseBody
@RequestMapping(value = "/weixin_validate")
public String validate(HttpServletRequest request, HttpServletResponse response,
@RequestParam("outTradeNo") String outTradeNo)
{
PayStatus payStatus = payStatusService.getDao().get(outTradeNo);
String status = payStatus.getStatus();
JSONObject jObject = new JSONObject();
jObject.put("flag", false);
if ("SUCCESS".equals(status))
{
jObject.put("flag", true);
payStatusService.getDao().delete(payStatus);
}
return jObject.toString();
}
}
回调url代码
WeixinNotifyController
package xhsoft.yxd.wap.controller;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import xhsoft.utils.DateTimeUtils;
import xhsoft.web.controller.BaseController;
import xhsoft.web.exp.BusinessExeption;
import xhsoft.yxd.base.model.PayStatus;
import xhsoft.yxd.base.service.IPayStatus;
import xhsoft.yxd.core.weixintools.WeiXinUtils;
import xhsoft.yxd.core.weixintools.XMLUtil;
/**
* @author WangMeng
* @date 2016年6月8日
*/
@Controller
@RequestMapping(value = "/wap")
public class WeixinNotifyController extends BaseController
{
@Autowired
IPayStatus payStatusService;
private static Logger logger = Logger.getLogger(WeixinNotifyController.class);
@RequestMapping(value = "/weixin_notify")
public void weiixnNotify(HttpServletRequest request, HttpServletResponse response)
throws BusinessExeption
{
try
{
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);
String out_trade_no = map.get("out_trade_no").toString();
if (map.get("result_code").toString().equalsIgnoreCase("SUCCESS"))
{
PayStatus payStatus = new PayStatus();
payStatus.setId(out_trade_no);
payStatus.setTradeNode(out_trade_no);
payStatus.setStatus("SUCCESS");
payStatus.setOpTime(DateTimeUtils.getNowTimeStanderd());
payStatusService.getDao().saveOrUpdate(payStatus);
response.getWriter().write(WeiXinUtils.setXML("SUCCESS", "")); // 告诉微信服务器,我收到信息了,不要在调用回调action了
}
}
catch (Exception e)
{
logger.error("微信回调异常");
throw new BusinessExeption("微信回调异常", e);
}
}
}
发起支付的html页面
<script>
$(document).ready(function() {
var outTradeNo = '${payParams.get("out_trade_no")}';
function onBridgeReady(){
WeixinJSBridge.invoke('getBrandWCPayRequest', {
"appId" : '${payParams.get("appId")}', //公众号名称,由商户传入
"timeStamp" : '${payParams.get("timeStamp")}', //时间戳,自1970年以来的秒数
"nonceStr" : '${payParams.get("nonceStr")}', //随机串
"package" : '${payParams.get("packageValue")}',
"signType" : '${payParams.get("signType")}', //微信签名方式:
"paySign" : '${payParams.get("paySign")}'
//微信签名
}, function(res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
weixinPayValidate(outTradeNo);
} // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
else {
$api.rmStorage('orderData');
history.back(-1);
}
});
}
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
}else{
onBridgeReady();
}
})
/**
* 验证支付是否成功
*/
function weixinPayValidate(outTradeNo) {
var data = {
outTradeNo : outTradeNo
}
extApi.ajax('wap/weixin_validate.action', data, function(data) {
if (JSON.parse(data).flag) {
newOrder();
} else {
//$api.rmStorage('orderData');
history.back(-1);
}
});
}
/**
* 下单
*/
function newOrder() {
var orderData = $api.getStorage("orderData");
var key=$api.getStorage("orderDataKey");
var url;
if(key=="shopData"){
url='shop/order_new.action';
}else{
url='shop/order_pre_new.action';
}
extApi.ajax(url, orderData, newOrerCallback);
}
/**
*下单回调函数
*/
function newOrerCallback(data) {
//异常
if (data.flag == false) {
extApi.toast('下单失败');
return;
}
extApi.toast('订单已经生成');
var key=$api.getStorage("orderDataKey");
if(key=="shopData"){
// 如果用户选择了积分兑换,下单成功后将用户的积分减去
minUserScore();
}else{
ordernewSuccess();
}
}
/**
*如果用户选择了积分兑换,下单成功后将用户的积分清零
*/
function minUserScore() {
var user = $api.getStorage('user');
var score=0;
if($("input[type=checkbox]").prop('checked')){
score=user.store;
}
var data = {
buyerId : user.id,
score : score
};
extApi.ajax('shop/buyer_score_edit.action', data, function(data) {
user.store = data.store;
$api.setStorage('user', user);
ordernewSuccess();
});
}
function ordernewSuccess(){
var key=$api.getStorage("orderDataKey");
$api.rmStorage(key);
$api.rmStorage('orderData');
$api.rmStorage('orderDataKey');
var count=$api.getStorage("orderDataCount");
//购物车减去数量监听
shopcart.minCountTocart(count);
//清理缓存
window.history.go(-2);
}
</script>