关闭

userwyh的专栏

When you can't hold it anymore, better to let it go.
15
原创
1
转载
0
译文
41
评论
39530
访问

2015七月
06

微信支付(JS API) JAVA

基于微信支付文档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>


img

userwyh

等级:

排名:千里之外

博客专栏
文章分类
文章存档
阅读排行
评论排行
推荐文章
最新评论
img