首先需要查看文档 知道h5支付的步骤
这里注意测试的时候需要用手机打开浏览器测试,如果用电脑的浏览器测试跳不出支付页面(可能是电脑检测不到微信)
h5支付很简单 h5支付不需授权直接调用统一下单微信支付结果通知-废话不多说直接上代码
1.前台页面
<!DOCTYPE HTML>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv=content-type>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="IE=edge,Chrome=1">
<meta name="renderer" content="webkit">
<title>支付</title>
</head>
<body>
<a href="javascript:f_authcode();" style="color:#000;">公众号支付</a>
<a href="javascript:f_test();" style="color:#000;">H5充值</a>
</body>
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<script type=text/javascript>
$.ajax({
url:"http://wx.hsjsns.com/v1/api/pay/MWEB/unifiedorder",
contentType: "application/json",
type:"post",
//data:"{'id': " + openid +",'id': " + openid +",'id': " + openid +"}"
data:JSON.stringify({money:"0.01",goods:"testH5充值",appid:"H5WG",account:"18068794602"}),//注释这些参数根据自己业务传
dataType: "json",
success: function(v_res){
alert(JSON.stringify(v_res.data.mweb_url));
console.log(v_res);
if(v_res.code==0){
//onBridgeReady(v_res.data);
document.location.href=v_res.data.mweb_url;
}
}
});
}
</script>
</html>
2.后台接口直接调用统一下单
@RestController
@RequestMapping(value = "v1/api")
public class WXApiController {
/**
* 微信支付统一下单
* @param order
* @return sn
*/
@RequestMapping(value = "/pay/{tradetype}/unifiedorder", method = RequestMethod.POST)
public ResponseEntity<JsonResult> unifiedorder (@PathVariable(value = "tradetype") String tradetype,@RequestBody(required=false) Map<String, String> order, HttpServletRequest request){
JsonResult r = null;
try {
if(!"JSAPI".equals(tradetype) && !"APP".equals(tradetype) && !"MWEB".equals(tradetype)) throw new ServiceException("微信支付交易类型有误!");
//请求验证
String ver_str = VerifyUtilsEx.verifyData(order, new String[] {"account","money","goods","appid"});
if(StringUtils.isNotBlank(ver_str)){
throw new ServiceException(ver_str);
}
String passback = order.containsKey("passback") ? order.get("passback") : "";
if("JSAPI".equals(tradetype) && !order.containsKey("openid")){
throw new ServiceException("公众号支付缺少openid");
}
String openid = order.containsKey("openid") ? order.get("openid") : "";
String ip = "";
//设定IP
if(order.containsKey("ip") && StringUtilsEx.IsIp(order.get("ip"))){
ip = order.get("ip");
}else{
ip = CommonUtilsEx.getIpAddr(request);
}
String moneystr = order.get("money");
Float money = Float.parseFloat(moneystr);
/**
* 首先创建订单
*/
String sn = wxApiService.createOrder(order.get("account"), money, order.get("goods"), order.get("appid"), ip, tradetype);//注释这个需要根据自己的业务区创建临时订单插入数据库,然后返回订单号
if(StringUtils.isBlank(sn)) throw new ServiceException("创建临时订单失败!");
Map<String, String> resData = null;
String callback = callback_domain+"pay/paycomplate";//微信支付结果通知
resData = wxApiService.unifiedorder_H5(openid, sn, money, order.get("goods"), passback, ip, callback);
r= new JsonResult("0", "", resData);
} catch(ServiceException se){
r= new JsonResult("-1", se.getMessage());
} catch (Exception e) {
r= new JsonResult("-2", "系统错误");
logger.error(e.getMessage());
e.printStackTrace();
}
return ResponseEntity.ok(r);
}
/**
* 微信支付结果通知
* @param request
* @param response
* @return
*/
@RequestMapping(value = "/pay/paycomplate", method = RequestMethod.POST)
public ResponseEntity<String> paycomplate(HttpServletRequest request, HttpServletResponse response){
String inputLine;
String notityXml = "";
String resXml = WXCommonUtil.setXML("FAIL", "");
try {
while ((inputLine = request.getReader().readLine()) != null) {
notityXml += inputLine;
}
request.getReader().close();
logger.info("接收到的报文:" + notityXml);
SortedMap<String, String> res = WXCommonUtil.doXMLParse(notityXml);
//校验是否接收成功
if(res != null && !res.isEmpty() && "SUCCESS".equals(res.get("result_code"))){
//校验参数格式是否正确
if(!res.containsKey("sign") || !res.containsKey("out_trade_no") || !res.containsKey("openid") || !res.containsKey("transaction_id") || !res.containsKey("total_fee")){
resXml = WXCommonUtil.setXML("FAIL", "参数格式校验错误");
logger.error("wx/paycomplate:WARN: ---------------------参数格式校验错误");
}else{
String sign = WXCommonUtil.createSign(res);
String v_signString = res.get("sign");
//校验签名
if(sign.equals(v_signString)){
resXml = WXCommonUtil.setXML("SUCCESS", "OK");
String sn = res.get("out_trade_no");
String transaction_id = res.get("transaction_id");
Double money = Double.parseDouble(res.get("total_fee"));
String passback = res.get("attach");
//微信传递金额为分 故需要转为元 /100
wxApiService.payComplate(sn, transaction_id, String.valueOf(money/100), passback);
}else{
resXml = WXCommonUtil.setXML("FAIL", "签名校验失败");
logger.error("wx/paycomplate:WARN: ---------------------签名校验失败");
//sysErrLogService.addErrInfo("WX_PAY", "签名校验失败", notityXml);
}
}
}else{
resXml = WXCommonUtil.setXML("FAIL", "报文为空");
logger.error("wx/paycomplate:WARN: ---------------------报文为空");
//sysErrLogService.addErrInfo("WX_PAY", "报文为空", "");
}
} catch (ServiceException se) {
logger.warn("wx/paycomplate:WARN:"+se.getMessage());
}catch (Exception e) {
//e.printStackTrace();
logger.error(e.getMessage());
e.printStackTrace();
}
return ResponseEntity.ok(resXml);
}
}
3.涉及到的工具类
public class WXCommonUtil {
public static String setXML(String return_code, String return_msg) {
return "<xml><return_code><![CDATA[" + return_code
+ "]]></return_code><return_msg><![CDATA[" + return_msg
+ "]]></return_msg></xml>";
}
/**
* 解析接收到的xml报文
* @param strxml
* @return SortedMap
* @throws JDOMException
* @throws IOException
*/
public static SortedMap<String, String> doXMLParse(String strxml) throws JDOMException, IOException {
strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
if(null == strxml || "".equals(strxml)) {
return null;
}
SortedMap m = new TreeMap();
InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(in);
Element root = doc.getRootElement();
List list = root.getChildren();
Iterator it = list.iterator();
while(it.hasNext()) {
Element e = (Element) it.next();
String k = e.getName();
String v = "";
List children = e.getChildren();
if(children.isEmpty()) {
v = e.getTextNormalize();
} else {
v = getChildrenText(children);
}
m.put(k, v);
}
//关闭流
in.close();
return m;
}
/**
* @author Mark
* @Description:sign签名
* @param characterEncoding 编码格式
* @param parameters 请求参数
* @return
*/
public static String createSign(SortedMap<String,String> parameters){
StringBuffer sb = new StringBuffer();
Set es = parameters.entrySet();
Iterator it = es.iterator();
while(it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
String k = (String) entry.getKey();
Object v = entry.getValue();
if(null != v && !"".equals(v)
&& !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
String key= "";
if(parameters.containsKey("key") && StringUtils.isNotBlank(parameters.get("key"))){
key = parameters.get("key");
}else{//通过商户ID获取秘钥KEY
WXConfigService service = SpringUtil.getBean(WXConfigService.class);
key = service.getKeyByMchid(parameters.get("mch_id"));
}
//System.out.println("WXCommUtile:------>> key:"+key);
sb.append("key=" + key);
System.out.println(sb);
String sign = Md5UtilsEx.getMD5Str(sb.toString()).toUpperCase();
return sign;
}
}
public class VerifyUtilsEx {
static String KEY = "RVqq0cifgVJCfeCSxnWU6LoyGIpwYOa6";
static long TIMESTAMP = 5*60; //时间戳5分钟 5*60
/**
* 接口必要参数签名验证
* @return String
* @throws UnsupportedEncodingException
*/
public static String verifyParam(HttpServletRequest request,String[] args) throws UnsupportedEncodingException{
Map params = transToMAP(request.getParameterMap());
return verifyData(params,args);
}
public static String verifyData(Map<String, String> data,String[] args) throws UnsupportedEncodingException{
String sign = "";
String arg_cnt = "";
String msg = "";
if(data == null || data.isEmpty()) return "没有检索到参数!";
for(String arg : args){
if(data.keySet().contains(arg)){
if(data.get(arg)==null || !StringUtils.hasText(String.valueOf(data.get(arg)))){
msg = "参数【"+arg+"】未明确,请确认!";
break;
}
if("sign".equals(arg)){
sign = String.valueOf(data.get(arg));
}
if("ts".equals(arg)){
long systime = System.currentTimeMillis()/1000;
long v_ts = Long.parseLong(data.get(arg));
//时间戳校验
if(Math.abs(systime-v_ts) > TIMESTAMP){
msg = "请求超出有效期!";
break;
}
}
}else{
msg = "参数【"+arg+"】未明确,请确认!";
break;
}
}
//参数都已明确并需要签名验证
if(StringUtils.hasText(sign) && !StringUtils.hasText(msg)){
for(String arg1 : args){
if(!"sign".equals(arg1)){
arg_cnt += String.valueOf(data.get(arg1));
}
}
//System.out.println(URLEncoder.encode(arg_cnt+KEY,"utf-8"));
String v_sign = Md5UtilsEx.getMD5Str(URLEncoder.encode(arg_cnt+KEY,"utf-8").toLowerCase());
//System.out.println(v_sign);
if(!sign.toLowerCase().equals(v_sign.toLowerCase())){
msg = "校验码错误!";
}
}
return msg;
}
private static Map transToMAP(Map parameterMap) throws UnsupportedEncodingException{
// 返回值Map
Map returnMap = new HashMap();
Iterator entries = parameterMap.entrySet().iterator();
Map.Entry entry;
String name = "";
String value = "";
while (entries.hasNext()) {
entry = (Map.Entry) entries.next();
name = (String) entry.getKey();
Object valueObj = entry.getValue();
if(null == valueObj){
value = "";
}else if(valueObj instanceof String[]){
String[] values = (String[])valueObj;
for(int i=0;i<values.length;i++){
value = values[i] + ",";
}
value = value.substring(0, value.length()-1);
}else{
value = valueObj.toString();
}
System.out.println(value);
returnMap.put(name, value);
}
return returnMap;
}
}