1 . 註冊獲取微信appid等相關信息 pay.weixin.qq.com
2 . 下載SDK和DEMO文件 https://pay.weixin.qq.com/wiki/doc/api/native_sl.php?chapter=11_1
3 . 複製WxPayUtil.java和WXPayConstants.java 和WXPayXmlUtil.java3個文件到項目以及一個發送請求的工具類
WxPayRequest
public class WxPayRequest {
private static int readTimeoutMs = 1000;
private static int connectTimeoutMs = 1000;
public static String wxPayRequest(String url,String data) {
BasicHttpClientConnectionManager connManager = new BasicHttpClientConnectionManager(
RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", SSLConnectionSocketFactory.getSocketFactory())
.build(),
null,
null,
null
);
HttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(connManager)
.build();
HttpPost httpPost = new HttpPost(url);
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(readTimeoutMs).setConnectTimeout(connectTimeoutMs).build();
httpPost.setConfig(requestConfig);
StringEntity postEntity = new StringEntity(data, "UTF-8");
httpPost.addHeader("Content-Type", "text/xml");
httpPost.setEntity(postEntity);
HttpResponse httpResponse = null;
try {
httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
return EntityUtils.toString(httpEntity, "UTF-8");
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
4 . 創建一個配置類WxPayConfig.java
public class WxPayConfig {
//微信支付分配的公衆賬號ID(企業號corpid即爲此appId)
private String appid;
//微信支付分配的商戶號
private String mch_id;
//支付寶和商戶的密鑰
private String key;
//自定義參數,可以爲終端設備號(門店號或收銀設備ID),PC網頁或公衆號內支付可以傳"WEB"
private String device_info;
//隨機字符串,長度要求在32位以內。推薦隨機數生成算法
//private String nonce_str;
//簽名類型,默認爲MD5,支持HMAC-SHA256和MD5。
private String sign_type;
//商品簡單描述,該字段請按照規範傳遞,具體請見參數規定
private String body;
//商品詳細描述,對於使用單品優惠的商戶,改字段必須按照規範上傳,詳見“單品優惠參數說明”
private String detail;
//符合ISO 4217標準的三位字母代碼,默認人民幣:CNY,詳細列表請參見貨幣類型
private String fee_type;
//APP和網頁支付提交用戶端ip,Native支付填調用微信支付API的機器IP。
private String spbill_create_ip;
//異步接收微信支付結果通知的回調地址,通知url必須爲外網可訪問的url,不能攜帶參數。
private String notify_url;
//JSAPI 公衆號支付 NATIVE 掃碼支付 APP APP支付 說明詳見參數規定
private String trade_type;
//請求微信生成二維碼的地址
自己生成get/set方法及構造方法
5 . 在spring配置文件中注入配置bean , value根據 微信官網推薦進行配置
<!--微信支付相關配置-->
<bean id="wxPayConfig" class="cn.itrip.trade.config.WxPayConfig">
<property name="appid" value="wxab8acb865bb1637e"/>
<property name="mch_id" value="11473623"/>
<property name="key" value="dfsfddre32sdrf2"/>
<property name="device_info" value="013467007045764"/>
<property name="body" value="騰訊充值中心-QQ會員充值"/>
<property name="detail" value=""/>
<property name="fee_type" value="CNY"/>
<property name="notify_url" value="http://localhost:8080/trade/wxpay/api/notify"/>
<property name="sign_type" value="HMAC-SHA256"/>
<property name="spbill_create_ip" value="123.12.12.123"/>
<property name="trade_type" value="JSAPI"/>
<property name="url" value="https://api.mch.weixin.qq.com/pay/unifiedorder"/>
</bean>
6 . 編寫訂單id生成二維碼的controller類方法
//1.訂單生產二維碼
@ResponseBody
@ApiOperation(value = "生成微信支付二維碼")
@RequestMapping(value = "/pay/{orderNo}",method = RequestMethod.GET)
public Dto createQRCode(@ApiParam(name = "orderNo",required = true) @PathVariable String orderNo){
try {
//1 .獲取訂單信息
ItripHotelOrder order = orderService.loadItripHotelOrder(orderNo);
//2 .構造參數
HashMap<String, String> data = new HashMap<>();
//訂單信息
data.put("out_trade_no","orderNo");//訂單id 商戶系統內部訂單號,要求32個字符內,只能是數字、大小寫字母_-|* 且在同一個商戶號下唯一。詳見商戶訂單號
data.put("total_fee",order.getPayAmount().multiply(new BigDecimal(100)).toBigInteger().toString());//訂單金額,單位分,沒有小數
data.put("product_id",order.getId().toString());//商品id
data.put("nonce_str", WXPayUtil.generateNonceStr());//隨機字符串,長度要求在32位以內。推薦隨機數生成算法
//商戶信息
data.put("appid",wxPayConfig.getAppid());//微信支付分配的公衆賬號ID(企業號corpid即爲此appId)
data.put("mch_id",wxPayConfig.getMch_id());//微信支付分配的公衆賬號ID(企業號corpid即爲此appId)
//商品簡單描述,該字段請按照規範傳遞,具體請見參數規定
data.put("body",wxPayConfig.getBody());
//自定義參數,可以爲終端設備號(門店號或收銀設備ID),PC網頁或公衆號內支付可以傳"WEB"
data.put("device_info",wxPayConfig.getDevice_info());
//符合ISO 4217標準的三位字母代碼,默認人民幣:CNY,詳細列表請參見貨幣類型
data.put("fee_type",wxPayConfig.getFee_type());
//APP和網頁支付提交用戶端ip,Native支付填調用微信支付API的機器IP
data.put("spbill_create_ip",wxPayConfig.getSpbill_create_ip());
//異步接收微信支付結果通知的回調地址,通知url必須爲外網可訪問的url,不能攜帶參數。
data.put("notify_url",wxPayConfig.getNotify_url());
//JSAPI公衆號支付 NATIVE掃碼支付 APP APP支付 說明詳見參數規定
data.put("trade_type",wxPayConfig.getTrade_type());
// 簽名類型,默認爲MD5,支持HMAC-SHA256和MD5
data.put("sign_type", wxPayConfig.getSign_type());
String requestXml=null;
//3.轉換成wx支付的xml
if (wxPayConfig.getSign_type().equals("MD5")){
requestXml = WXPayUtil.generateSignedXml(data, wxPayConfig.getKey(), WXPayConstants.SignType.MD5);
}else {
requestXml = WXPayUtil.generateSignedXml(data, wxPayConfig.getKey(), WXPayConstants.SignType.HMACSHA256);
}
//4. 發送請求獲取二維碼地址
// url就是請求wx的地址,
String resultXml = WxPayRequest.wxPayRequest(wxPayConfig.getUrl(), requestXml);
Map<String, String> responseMap = WXPayUtil.xmlToMap(resultXml);
if (responseMap.get("return_code").equals("SUCCESS") && responseMap.get("result_code").equals("SUCCESS") ){
HashMap<String, Object> map = new HashMap<>();
map.put("code_url",responseMap.get("code_url"));
return DtoUtils.returnDataSuccess(map);
}else {
return DtoUtils.returnFail(responseMap.get("return_msg"),"100002");
}
} catch (Exception e) {
e.printStackTrace();
}
return DtoUtils.returnFail("請求二維碼失敗","100002");
}
7 . 編寫回調方法 , 執行付款成功/失敗的方法
@ApiOperation(value = "微信支付回調方法 ")
@RequestMapping(value = "/notify",method = RequestMethod.GET)
public void wxNotify(HttpServletRequest request, HttpServletResponse response){
//1 .從回調請求中獲取信息
StringBuffer stringBuffer = new StringBuffer();
ServletInputStream inputStream = null;
String responseXml = null;
try {
inputStream = request.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String temp;
while ((temp=reader.readLine())!=null){
stringBuffer.append(temp);
}
reader.close();
inputStream.close();
Map<String, String> requestMap = WXPayUtil.xmlToMap(stringBuffer.toString());
//2 .驗證是否支付成功
boolean result = false;
if (wxPayConfig.getSign_type().equals("MD5")){
result = WXPayUtil.isSignatureValid(requestMap, wxPayConfig.getSign(), WXPayConstants.SignType.MD5);
}else {
result = WXPayUtil.isSignatureValid(requestMap, wxPayConfig.getSign(), WXPayConstants.SignType.HMACSHA256);
}
Map<String, String> returnMap = new HashMap<>();
//3.成功,修改訂單信息
if (result){
if (requestMap.get("return_code").equals("SUCCESS") && requestMap.get("result_code").equals("SUCCESS") ){
orderService.paySuccess(requestMap.get("out_trade_no"),2,requestMap.get("prepay_id"));
returnMap.put("return_code","SUCCESS");
returnMap.put("return_msg","SUCCESS");
}else {
orderService.payFail(requestMap.get("out_trade_no"),2,requestMap.get("prepay_id"));
returnMap.put("return_code","FAIL");
returnMap.put("return_msg","付款失敗!");
}
}else {
returnMap.put("return_code","FAIL");
returnMap.put("return_msg","付款失敗!");
}
responseXml = WXPayUtil.generateSignedXml(returnMap, wxPayConfig.getSign(), WXPayConstants.SignType.MD5);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
response.getWriter().write(responseXml);
response.getWriter().flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}