http://blog.csdn.net/userwyh/article/details/46773641
基于微信支付文档V3.3.7进行编码,使用JS API(网页内)并测试通过,应用在项目中。
Form:
- public class PayForm extends BaseForm{
- private String code; //通过code换取微信的openid,谁支付的
- private Integer transactionID; //交易ID
- private String appId; //公众账号ID
- private String timeStamp; //时间戳
- private String nonceStr; //随机字符串
- private String packages; //订单详情扩展字符串
- private String paySign; //签名
- private String openid; //微信openid
- private Integer masterOrderID; //订单ID
- //set get
- }
请求支付的Action:
- @ParentPackage("main")
- @Namespace("/pay")
- @Controller
- public class PayAction extends BaseAction{
- private PayForm form;
- @Resource
- private TransactionService transactionService;
- @Action(value = "weChatPay",
- results = {
- @Result(name = SUCCESS, location = "/html/transaction/jsp/weChatPay.jsp"),
- @Result(name = ERROR , location = "/html/common/errors/sys_error.jsp")}
- )
- public String weChatPay(){
- SystemLogger.info("用户请求支付订单号:"+form.getTransactionID());
- if (StringUtils.isNotEmpty(form.getCode())) {
- String url = WeixinUtil.getUrl().replace("CODE", form.getCode());
- String openid ="";
- try {
- Map<String, Object> map = JsonUtil.getMapByUrl(url);
- openid = map.get("openid").toString();
- form.setOpenid(openid);
- } catch (Exception e) {
- SystemLogger.info("用户请求支付订单号:"+form.getTransactionID()+"时拉取微信用户信息失败");
- }
- try {
- transactionService.createWeChatRequest(form);
- return SUCCESS;
- } catch (BusinessException e) {
- SystemLogger.error(e.getMessage());
- form.setMessage(e.getMessage());
- return ERROR;
- }
- }else{
- SystemLogger.info("用户请求支付订单号:"+form.getTransactionID()+"的链接为非法链接,已拒绝");
- form.setMessage("请通过合法链接进行订单支付");
- return ERROR;
- }
- }
- @Override
- public Object getModel() {
- if(form==null){
- form = new PayForm();
- }
- return form;
- }
- }
微信支付结果回调请求的Action:
- @ParentPackage("main")
- @Namespace("/pay")
- @Controller
- public class NotifyAction {
- @Resource
- private TransactionService transactionService;
- @Action(value = "notify",
- results = {
- @Result(name = "success", type = "plainText",params = { "charSet", "UTF-8"})},
- interceptorRefs = { @InterceptorRef("defaultStack")}
- )
- public String weChatNotify(){
- Map<String, String> requestMap = null;
- SortedMap<String, String> returnMap = new TreeMap<String, String>();
- String requestXML = "";
- try {
- requestMap = TenPayUtil.parseXml(ServletActionContext.getRequest());
- SystemLogger.info("接收到的微信支付回调通知:"+requestMap.toString());
- SortedMap<String, String> map = new TreeMap<String, String>();
- map.putAll(requestMap);
- String weixinSign = map.get("sign");
- map.remove("sign");
- String sign = TenPayUtil.sign(map, WeixinUtil.partnerKey);
- if(!sign.equals(weixinSign)){
- SystemLogger.info("签名失败");
- returnMap.put("return_code", "FAIL");
- returnMap.put("return_msg", "签名失败");
- requestXML = TenPayUtil.getRequestXml(returnMap);
- }else{
- try {
- //更新订单的状态等等操作...
- returnMap.put("return_code", "SUCCESS");
- requestXML = TenPayUtil.getRequestXml(returnMap);
- } catch (BusinessException e) {
- SystemLogger.info(e.getMessage());
- returnMap.put("return_code", "FAIL");
- returnMap.put("return_msg", "签名失败");
- requestXML = TenPayUtil.getRequestXml(returnMap);
- }
- }
- } catch (Exception e) {
- SystemLogger.info("转换微信请求参数错误");
- returnMap.put("return_code", "FAIL");
- returnMap.put("return_msg", "转换微信请求参数错误");
- requestXML = TenPayUtil.getRequestXml(returnMap);
- }
- try{
- PrintWriter out = ServletActionContext.getResponse().getWriter();
- out.print(requestXML);
- out.flush();
- out.close();
- }catch(Exception ex){
- }
- return "success";
- }
- }
Service:
- @Transactional
- @Service(value = "transactionService")
- public class TransactionServiceImpl implements TransactionService{
- <span style="white-space:pre"> </span>.......
- @Override
- public void createWeChatRequest(PayForm form) throws BusinessException {
- Transaction po = this.getTransactionByID(form.getTransactionID());
- String shopOrderIDs = po.getMuiltFlag().equals("1") ? po.getRelateIDs() : po.getRelateID().toString();
- MasterOrder order = masterorderService.getMasterOrderByShopOrderIDs(shopOrderIDs);
- if(order.getPayFlag() == 1){
- throw new BusinessException("该笔订单已支付");
- }else{
- form.setMasterOrderID(order.getMasterOrderID());
- String payTypeID = po.getPayTypeID().toString();
- if(AppKeys.PAY_TYPE_ID_WECHAT.equals(payTypeID)){
- //请求参数按参数名称大小进行排序
- SortedMap<String, String> params = createSortedMap(form,po);
- //签名
- String sign = TenPayUtil.sign(params, WeixinUtil.partnerKey);
- params.put("sign", sign);
- //生成xml格式
- String requestXML = TenPayUtil.getRequestXml(params);
- //获取证书
- HttpServletRequest request = ServletActionContext.getRequest();
- InputStream instream = request.getSession().getServletContext().getResourceAsStream("/WEB-INF/weixinCert/apiclient_cert.p12");
- String responseXML;
- try {
- //创建微信订单返回结果
- responseXML = TenPayUtil.post(WeixinUtil.CREATE_ORDER_URL,WeixinUtil.partner,requestXML,instream);
- Map<String,String> resultMap = XmlUtil.parseXml(responseXML);
- String return_code = resultMap.get("return_code").toString();
- if(return_code.equals("SUCCESS")){
- //创建微信订单成功,获取微信预支付订单ID
- String prepay_id = (String) resultMap.get("prepay_id");
- SortedMap<String, String> finalpackage = new TreeMap<String, String>();
- String prepay_id2 = "prepay_id="+prepay_id;
- String packages = prepay_id2;
- String timeStamp = TenPayUtil.getTimeStamp();
- String nonceStr = TenPayUtil.createNonceStr();
- finalpackage.put("appId", WeixinUtil.appId);
- finalpackage.put("timeStamp", timeStamp);
- finalpackage.put("nonceStr", nonceStr);
- finalpackage.put("package", packages);
- finalpackage.put("signType", "MD5");
- //签名
- sign = TenPayUtil.sign(finalpackage, WeixinUtil.partnerKey);
- form.setAppId(WeixinUtil.appId);
- form.setTimeStamp(timeStamp);
- form.setPaySign(sign);
- form.setNonceStr(nonceStr);
- form.setPackages(packages);
- }else{
- throw new BusinessException("统一支付接口获取预支付订单出错");
- }
- }catch (Exception e) {
- e.printStackTrace();
- SystemLogger.info(e.getMessage());
- throw new BusinessException("支付异常");
- }
- }else{
- throw new BusinessException("手机端仅支持微信支付");
- }
- }
- }
- private SortedMap<String, String> createSortedMap(PayForm form,Transaction po){
- //公众账号ID
- String appId = WeixinUtil.appId;
- //商户号
- String partner = WeixinUtil.partner;
- //当前时间
- String currTime = TenPayUtil.getCurrTime();
- //8位日期
- String strTime = currTime.substring(8, currTime.length());
- //四位随机数
- String strRandom = TenPayUtil.getRandomNum(4);
- //10位序列号,可以自行调整。
- String strReq = strTime + strRandom;
- //商户号
- String mch_id = partner;
- //子商户号 非必输
- String sub_mch_id="";
- //设备号 非必输
- String device_info="";
- //随机字符串
- String nonce_str = strReq;
- //商品描述
- String body = po.getTitle();
- //附加数据
- String attach = "测试";
- //商户订单号
- String out_trade_no = po.getTransactionID().toString();
- int intMoney = (int)(po.getAmount()*100);
- //总金额以分为单位,不带小数点
- int total_fee = intMoney;
- //订单生成的机器 IP
- String spbill_create_ip = ServletActionContext.getRequest().getRemoteAddr();
- //订 单 生 成 时 间 非必输
- String time_start = currTime;
- //订单失效时间 非必输
- String time_expire = "";
- //商品标记 非必输
- String goods_tag = "";
- //这里notify_url是 支付完成后微信发给该链接信息,可以判断会员是否支付成功,改变订单状态等。
- String notify_url =WeixinUtil.notifyURL;
- //交易类型
- String trade_type = "JSAPI";
- //用户标识
- String openid = form.getOpenid();
- //非必输
- String product_id = "";
- 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);
- packageParams.put("total_fee", total_fee+"");
- packageParams.put("spbill_create_ip", spbill_create_ip);
- packageParams.put("notify_url", notify_url);
- packageParams.put("trade_type", trade_type);
- packageParams.put("openid", openid);
- return packageParams;
- }
- <span style="white-space:pre"> </span>......
- }
TenPayUtil:
- public class TenPayUtil {
- /**
- * 对请求参数名ASCII码从小到大排序后签名
- * @param openid
- * @param userId
- * @return
- */
- public static String sign(SortedMap<String, String> params,String KEY){
- Set<Entry<String,String>> entrys=params.entrySet();
- Iterator<Entry<String,String>> it=entrys.iterator();
- StringBuffer result = new StringBuffer();
- while(it.hasNext())
- {
- Entry<String,String> entry=it.next();
- result.append(entry.getKey())
- .append("=")
- .append(entry.getValue())
- .append("&");
- }
- result.append("key=").append(KEY);
- SystemLogger.info(result.toString());
- String sign = "";
- try {
- sign = MD5Util.MD5(result.toString());
- } catch (Exception e) {
- e.printStackTrace();
- }
- return sign.toString().toUpperCase();
- }
- public static String getRequestXml(SortedMap<String,String> params){
- StringBuffer sb = new StringBuffer();
- sb.append("<xml>");
- Set es = params.entrySet();
- Iterator it = es.iterator();
- while(it.hasNext()) {
- Map.Entry entry = (Map.Entry)it.next();
- String k = (String)entry.getKey();
- String v = (String)entry.getValue();
- if ("body".equalsIgnoreCase(k)||"attach".equalsIgnoreCase(k)||"goodstag".equalsIgnoreCase(k)||"sign".equalsIgnoreCase(k)) {
- sb.append("<"+k+">"+"<![CDATA["+v+"]]></"+k+">");
- }else {
- sb.append("<"+k+">"+v+"</"+k+">");
- }
- }
- sb.append("</xml>");
- return sb.toString();
- }
- /**
- * 生成随机字符串
- * @return
- */
- public static String createNonceStr() {
- return UUID.randomUUID().toString().toUpperCase().replace("-", "");
- }
- /**
- * 获取当前日期 yyyyMMdd
- *
- * @param date
- * @return String
- */
- public static String getCurrTime() {
- SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
- String strDate = formatter.format(new Date());
- return strDate;
- }
- /**
- * 生成特定位数的随机数字
- * @param length
- * @return
- */
- public static String getRandomNum(int length) {
- String val = "";
- Random random = new Random();
- for (int i = 0; i < length; i++) {
- val += String.valueOf(random.nextInt(10));
- }
- return val;
- }
- /**
- * 获取时间戳
- * @return
- */
- public static String getTimeStamp() {
- return String.valueOf(System.currentTimeMillis() / 1000);
- }
- /**
- *
- * @param url 请求URL
- * @param MCH_ID 商户号
- * @param requestXML 请求参数
- * @param instream 证书流
- * @return
- * @throws NoSuchAlgorithmException
- * @throws CertificateException
- * @throws IOException
- * @throws KeyManagementException
- * @throws UnrecoverableKeyException
- * @throws KeyStoreException
- */
- public static String post(String url,String MCH_ID,String requestXML,InputStream instream) throws NoSuchAlgorithmException, CertificateException, IOException, KeyManagementException, UnrecoverableKeyException, KeyStoreException{
- KeyStore keyStore = KeyStore.getInstance("PKCS12");
- try {
- keyStore.load(instream, MCH_ID.toCharArray());
- } finally {
- instream.close();
- }
- SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, MCH_ID.toCharArray()).build();
- SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
- sslcontext,
- new String[] { "TLSv1" },
- null,
- SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
- CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
- String result = "";
- try {
- HttpPost httpPost = new HttpPost(url);
- StringEntity reqEntity = new StringEntity(requestXML,"UTF-8");
- reqEntity.setContentType("application/x-www-form-urlencoded");
- httpPost.setEntity(reqEntity);
- CloseableHttpResponse response = httpclient.execute(httpPost);
- try {
- HttpEntity entity = response.getEntity();
- if (entity != null) {
- BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(),"UTF-8"));
- String text;
- while ((text = bufferedReader.readLine()) != null) {
- result +=text;
- }
- }
- EntityUtils.consume(entity);
- } finally {
- response.close();
- }
- } finally {
- httpclient.close();
- }
- return result;
- }
- /**
- * 解析微信发来的请求(XML)
- *
- * @param request
- * @return
- * @throws Exception
- */
- @SuppressWarnings("unchecked")
- public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
- // 将解析结果存储在HashMap中
- Map<String, String> map = new HashMap<String, String>();
- // 从request中取得输入流
- InputStream inputStream = request.getInputStream();
- // 读取输入流
- SAXReader reader = new SAXReader();
- Document document = reader.read(inputStream);
- // 得到xml根元素
- Element root = document.getRootElement();
- // 得到根元素的所有子节点
- List<Element> elementList = root.elements();
- // 遍历所有子节点
- for (Element e : elementList)
- map.put(e.getName(), e.getText());
- // 释放资源
- inputStream.close();
- inputStream = null;
- return map;
- }
- }
weChatPay.jsp
- <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
- <%@ include file="/html/common/taglibs.jsp"%>
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8" >
- <title>订单支付</title>
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
- <meta name="apple-mobile-web-app-capable" content="yes">
- <meta name="apple-mobile-web-app-status-bar-style" content="black">
- <link rel="stylesheet" href="<s:url value='/html/css/common/common.css' />" >
- <link rel="stylesheet" href="<s:url value='/html/css/index.css' />" >
- </head>
- <body>
- <div class="content">
- <a href="javascript:callpay();" class="payment">微信支付</a>
- <hr>
- <img src="<s:url value='/html/images/logo.svg' />" class="logo">
- </div>
- <script type="text/javascript">
- var clicked = !1; // false
- function callpay() {
- if (clicked) return false;
- clicked = !0; // true
- WeixinJSBridge.invoke('getBrandWCPayRequest', {
- "appId" : "${appId}",
- "timeStamp" : "${timeStamp}",
- "nonceStr" : "${nonceStr}",
- "package" : "${packages}",
- "signType" : "MD5",
- "paySign" : "${paySign}"
- }, function(res) {
- WeixinJSBridge.log(res.err_msg);
- if (res.err_msg == "get_brand_wcpay_request:ok") {
- window.location.href = "../pay/payResult.action?transactionID=${transactionID}&masterOrderID=${masterOrderID}";
- } else if (res.err_msg == "get_brand_wcpay_request:cancel") {
- clicked = !1; // false
- window.location.href = "../pay/payResult.action?message=crm.pay.cancel";
- } else {
- clicked = !1; // false
- window.location.href = "../pay/payResult.action?message=crm.pay.error";
- }
- })
- }
- </script>
- </body>
- </html>