话不多说直接上代码,首先是controller层代码
@Autowired
private IWxPayServiceH5 wxPayServiceH5;
@ResponseBody
@RequestMapping(value = "/wxpayH5.do" )
public Message weixinPayWap(HttpServletRequest request, HttpServletResponse response){
response.setHeader("Access-Control-Allow-Origin", "*");
try{
String orderNo = request.getParameter("orderNo");//订单号
String notify_url ="这里写回调页面";
String tradeType = "MWEB";//H5支付交易类型
return wxPayServiceH5.unifiedorderH5(request, orderNo, notify_url, tradeType );
}catch(BusinessException e){
logger.error("获取微信支付所需参数接口:业务异常【{}】", e.getMessage());
return new Message(false, e.getMessage());
}catch(Exception e){
logger.error("获取微信支付所需参数接口:系统异常【{}】", e.getMessage());
e.printStackTrace();
return new Message(false, "系统异常");
}
}
下面是service层的代码
@Override
public Message unifiedorderH5(HttpServletRequest request, String openid,
String orderNo, String notify_url, String tradeType)
throws Exception {
logger.info("=====>Method:【unifiedorderH5】>>H5调用微信统一下单接口");
// appid
String appid = CodeTable.APPID;
// 商户号
String mch_id = CodeTable.SALE_MCH_ID;
// 商户签名KEY
String SIGNKEY = CodeTable.SALE_MCH_KEY;
//上面的三个参数都是申请H5支付微信给的参数
// 用户端ip
String spbill_create_ip = WxPayInaddrUtil.getRealIp(request);
// 随机数
String nonce_str = WxPayMD5Util.getMessageDigest(String.valueOf(
new Random().nextInt(10000)).getBytes());
// 微信订单号为订单号
String out_trade_no = orderNo;
// 产品名称
String body = "H5支付接口";
// 金额
String total_fee = "1";
// 签名数据
StringBuilder sb = new StringBuilder();
sb.append("appid=" + appid);
sb.append("&body=" + body);
sb.append("&mch_id=" + mch_id);
sb.append("&nonce_str=" + nonce_str);
sb.append("¬ify_url=" + notify_url);
sb.append("&out_trade_no=" + out_trade_no);
sb.append("&sign_type=" + "MD5");//这个开发文档上说不是必要参数,但是不加有时候会报错
sb.append("&spbill_create_ip=" + spbill_create_ip);
sb.append("&total_fee=" + total_fee);
sb.append("&trade_type=" + tradeType);
sb.append("&key=" + SIGNKEY);
System.out.println("sb=>" + sb);
// 签名MD5加密
String sign = WxPayMD5Util.MD5Encode(sb.toString(), "UTF-8");
System.out.println("sign=" + sign);
if (StringUtils.isBlank(sign)) {
logger.info("生成签名失败!");
throw new BusinessException("生成支付签名失败!");
}
// 拼接请求xml(由于用实体拼接,拼接后的xml下划线会很长,所以用字符串拼接)
Map<String, Object> map = new HashMap<String, Object>();
String xml = "<xml>" +
"<appid>" + appid + "</appid>" +
"<mch_id>" + mch_id + "</mch_id>" +
"<nonce_str>" + nonce_str + "</nonce_str>" +
"<sign>" + sign + "</sign>" +
"<body>" + body + "</body>"+
"<out_trade_no>" + out_trade_no + "</out_trade_no>" +
"<total_fee>" + total_fee + "</total_fee>"+
"<trade_type>" + tradeType + "</trade_type>" +
"<notify_url>" + notify_url + "</notify_url>"+
"<sign_type>MD5</sign_type>" +
"<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>"+
"</xml>";
map.put("sign", sign);
logger.info("请求下单接口,请求报文==【{}】", map);
Message msg = postWeChatByStr(CodeTable.WXPAY_ORDER, xml);
//WXPAY_ORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";//这是微信统一下单接口
if (!msg.getResult()) {
logger.info("请求核心异常");
throw new BusinessException("请求核心异常");
}
// xml转实体
ResultBean resultBean = (ResultBean) XstreamUtils.getBean(
msg.getInfo(), ResultBean.class);
if (resultBean == null) {
logger.info("转换实体失败!");
throw new BusinessException("转换实体失败!");
}
//转换实体可以不用,我是为了方便
// 判断是否成功返回
if ("SUCCESS".equals(resultBean.getReturn_code())
&& "SUCCESS".equals(resultBean.getResult_code())) {
logger.info("下单接口调用成功!");
Map<String, Object> maps = new HashMap<String, Object>();
String return_code = resultBean.getReturn_code();
String return_msg = resultBean.getReturn_msg();
String mweb_url = resultBean.getMweb_url();
maps.put("return_code", return_code);
maps.put("return_msg", return_msg);
maps.put("mweb_url", mweb_url);
//个人认为对于H5微信支付最重要的就是这个mweb_url
return new Message(true, "生成微信支付参数成功!", maps);
} else {
logger.info("下单接口调用失败!");
throw new BusinessException("下单接口调用失败!");
}
}
/**
* 调用微信下单接口
*
* @param interfaceCode
* @param paramStr
* @return
* @throws Exception
*/
private Message postWeChatByStr(String interfaceCode, String paramStr) {
String URL = BaseConstantService.queryCanstant(interfaceCode);
if (StringUtils.isNotBlank(URL)) {
// 请求核心
logger.info("请求微信:链接【{}】参数串【{}】", URL, paramStr);
String json = HttpUtil.post(URL, paramStr, 30000);
logger.info("请求微信:返回【{}】", json);
// 返回结果非空校验
if (StringUtils.isBlank(json)) {
throw new BusinessException("微信返回结果为空");
}
return new Message(true, json);
} else {
throw new BusinessException("微信接口地址为空!或不符合格式!");
}
}
下面是用到的util
public class HttpUtil {
/**
*
* @description 通过HTTP协议向服务器段发送请求,并得到返回结果,根据项目要求所有请求代码为UTF-8,请求地址必须用 URLEncoder.encode进行UTF-8转化。
* @param serviceUrl 服务器地址
* @param pMap 请求的键值对入参
* @return String 返回数据
*/
public static String post(String requestUrl, String para, int timeout) {
String result = "";
CloseableHttpClient httpclient = null;
CloseableHttpResponse response = null;
long start_time = System.currentTimeMillis();
try {
HttpPost httpPost = new HttpPost(requestUrl);
httpPost.setConfig(getConfig(timeout));
if (para != null && !para.trim().equals("")) {
StringEntity reqEntity = new StringEntity(para, DEFAULT_CHARSET);
reqEntity.setContentType("charset=" + DEFAULT_CHARSET);
reqEntity.setContentEncoding(DEFAULT_CHARSET);
httpPost.setEntity(reqEntity);
}
if(requestUrl.indexOf("https://") == 0){
logger.info("根据请求地址【{}】转换访问方式成https",requestUrl);
httpclient = createSSLClientDefault();
}else{
httpclient = createSSLClientDefaultBycrert(null, null);
}
response = httpclient.execute(httpPost);
int statusCode = response.getStatusLine().getStatusCode();
logger.info("执行http请求返回状态码【{}】,耗时【{}】", statusCode, (System.currentTimeMillis() - start_time));
HttpEntity entity = response.getEntity();
StringBuffer sb = new StringBuffer();
if (entity != null) {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(), DEFAULT_CHARSET));
String text = null;
while ((text = bufferedReader.readLine()) != null) {
sb.append(text);
}
}
result = sb.toString();
EntityUtils.consume(entity);
if(statusCode != 200){
logger.info("Http请求异常,返回码【{}】,返回内容【{}】", statusCode, result);
return null;
}
return result;
} catch (ConnectTimeoutException ex) {
logger.error("执行http请求,发生异常。异常信息如下:", ex);
throw new BusinessException("连接超时");
}catch(SocketTimeoutException ex){
logger.error("执行http请求,发生异常。异常信息如下:", ex);
throw new MyTimeoutException("读取信息超时");
}catch(Exception ex){
logger.error("执行http请求,发生异常。异常信息如下:", ex);
throw new BusinessException("系统正在维护中,请稍后再试");
} finally {
try {
if (response != null) {
response.close();
}
if (httpclient != null) {
httpclient.close();
}
} catch (IOException e) {
e.printStackTrace();
}
logger.info("根据请求地址【{}】返回信息【{}】,请求耗时【{}】", requestUrl, result, (System.currentTimeMillis() - start_time));
}
}
}
public class WxPayMD5Util {
/**
* 返回大写MD5
*
* @param origin
* @param charsetname
* @return
*/
public static String MD5Encode(String origin, String charsetname) {
String resultString = null;
try {
resultString = new String(origin);
MessageDigest md = MessageDigest.getInstance("MD5");
if (charsetname == null || "".equals(charsetname))
resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
else
resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
} catch (Exception exception) {
}
return resultString.toUpperCase();
}
public final static String getMessageDigest(byte[] buffer) {
char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f' };
try {
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
mdTemp.update(buffer);
byte[] md = mdTemp.digest();
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
return null;
}
}
}
public class WxPayInaddrUtil {
/**
*
* 获取真实ip地址 通过阿帕奇代理的也能获取到真实ip
*
* @param request
*
* @return
*/
public static String getRealIp(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}
页面的话在返回mweb_url 后不要直接访问这个链接,在当前页面用js
window.location.href = mweb_url
跳转就可以了