一共需要5处
1.pom,添加如下依赖
<dependency> <groupId>com.github.wxpaygroupId> <artifactId>wxpay-sdkartifactId> <version>0.0.3version> dependency>
2.配置文件(文件夹):
WxpayConfig.properties
#微信支付配置 #移动端appid APP_ID = wx3d3c125230d2ba** #商户号 BUSINESS_CODE = 153982*** #秘钥--sign获取需要的,在 账户中心-->api安全--api秘钥设置 API_KEY = gin201907*********** APIV3_KEY = gin2******* #签名类型 HMAC-SHA256和MD5,默认为MD5 SIGN_TYPE = MD5 #证书地址 PEM_ADDRESS = /wxConfig/**/apiclient_cert.p12 #异步通知地址(请注意必须是外网) NOTIFY_URL =http://***/wxAppPay/notify #公众号的appID --待确定--- #GZH_APP_ID = wxcfe45ec****
同时可以再同目录文件夹放入证书,微信支付部分功能需要证书
3. 生成sign的util类:WxMD5Util
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
/**
* Created by Mafy on 2019/7/9.
* 该类是生成签名用
*/
public class WxMD5Util {
public static String getSign(Map data) throws Exception {
WXConfigUtil config = WXConfigUtil.initWXconfigUtil();
Set keySet = data.keySet();
String[] keyArray = keySet.toArray(new String[keySet.size()]);
Arrays.sort(keyArray);
StringBuilder sb = new StringBuilder();
for (String k : keyArray) {
if (k.equals(WXPayConstants.FIELD_SIGN)) {
continue;
}
if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
sb.append(k).append("=").append(data.get(k).trim()).append("&");
}
sb.append("key=").append(config.getKey());
MessageDigest md = null;
try {
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
byte[] array = new byte[0];
try {
array = md.digest(sb.toString().getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
StringBuilder sb2 = new StringBuilder();
for (byte item : array) {
sb2.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
}
return sb2.toString().toUpperCase();
}
}
4.获取配置文件的配置类--该处使用单例模式
import com.github.wxpay.sdk.WXPayConfig;
import org.springframework.util.ObjectUtils;
import java.io.*;
import java.util.Properties;
/**
* Created by Mafy on 2019/7/9.
*/
public class WXConfigUtil implements WXPayConfig{
Properties properties= null;
private byte[] certData;
private static WXConfigUtil wxConfigUtil = new WXConfigUtil();
public static WXConfigUtil initWXconfigUtil(){
return wxConfigUtil;
}
private WXConfigUtil() {
String certPath = PropertiesUtil.class.getResource(getProperties().getProperty("PEM_ADDRESS")).getPath();//从微信商户平台下载的安全证书存放的路径
InputStream certStream = null;
try {
File file = new File(certPath);
certStream = new FileInputStream(file);
this.certData = new byte[(int) file.length()];
certStream.read(this.certData);
} catch (IOException e) {
e.printStackTrace();
}finally {
if(!ObjectUtils.isEmpty(certStream)){
try {
certStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Override
public String getAppID() {
return getProperties().getProperty("APP_ID");
}
//parnerid,商户号
@Override
public String getMchID() {
return getProperties().getProperty("BUSINESS_CODE");
}
@Override
public String getKey() {
return getProperties().getProperty("API_KEY");
}
@Override
public InputStream getCertStream() {
ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
return certBis;
}
@Override
public int getHttpConnectTimeoutMs() {
return 8000;
}
@Override
public int getHttpReadTimeoutMs() {
return 10000;
}
Properties getProperties() {
if(null == properties) {
properties = PropertiesUtil.getProperties("/wxConfig/WxpayConfig.properties");
}
return properties;
}
}
5.调用支付接口的controller:WxAppPayController
import com.alibaba.fastjson.JSONObject;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import com.xinlianpu.util.PropertiesUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* Created by Mafy on 2019/7/9.
*/
@Controller
@ResponseBody
@RequestMapping("/wxAppPay")
public class WxAppPayController {
static Properties properties= null;
final static Logger logger = LoggerFactory.getLogger(WxAppPayController.class);
// @Resource
// private WxPayService wxPayService;
//异步通知地址(请注意必须是外网)
public static final String NOTIFY_URL = getProperties().getProperty("NOTIFY_URL");
//交易类型,JSAPI--JSAPI支付(或小程序支付)、NATIVE--Native支付、APP--app支付,MWEB--H5支付
public static final String TRADE_TYPE_APP = "APP";
/**
* 统一下单--不需要证书
* 包括生成预支付订单-->订单生成-->返回订单数据到前端
* 官方文档:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1
* @param jsonObject
* @return
* @throws Exception
*/
@RequestMapping(value = "/pay",method = RequestMethod.POST)
// public Map wxPay(@RequestParam(value = "userId") String user_id, @RequestParam(value = "totalFee") String total_fee) throws Exception {
public DataResponse wxPayUnEncryption(@RequestBody JSONObject jsonObject) throws Exception {
logger.info("下单支付,app传过来的参数:{}",jsonObject);
DataResponse dataResponse = DataResponse.success();
// String user_id = TokenManager.getUserId();
String user_id = "123";
// String total_fee = jsonObject.getString("totalFee");//总金额
String total_fee = "1";//总金额--分
String spbillCreateIp = jsonObject.getString("spbillCreateIp");//点击支付按钮的机器的ip
// String spbillCreateIp = "0.01";//点击支付按钮的机器的ip
Map map = null;
try {
// String attach = "{\"user_id\":\"" + user_id + "\"}";//扩展字段,原样返回
String attach = "扩展字段";//扩展字段,原样返回
//请求预支付订单
Map result = dounifiedOrder(attach, total_fee,spbillCreateIp);
logger.info("下单之前,预支付返回信息:{}",JSONObject.toJSON(result));
//可判断改预支付订单的数据是否正确
//预支付订单之后,生成带签名的客户端您支付信息
map = new HashMap<>();
//返回APP端的数据
//参加调起支付的签名字段有且只能是6个,分别为 appid、partnerid、prepayid、package、noncestr 和 timestamp,而且都必须是小写---start--
map.put("appid", result.get("appid"));
map.put("partnerid", result.get("mch_id"));
map.put("prepayid", result.get("prepay_id"));
map.put("package", "Sign=WXPay");
map.put("noncestr", result.get("nonce_str"));
String signTimstamp = String.valueOf(System.currentTimeMillis() / 1000);
map.put("timestamp", signTimstamp);//单位为秒
//参加调起支付的签名字段有且只能是6个,分别为appid、partnerid、prepayid、package、noncestr和timestamp,而且都必须是小写---end--
Map mobileParam = new HashMap<>();
mobileParam.put("appId", result.get("appid"));
mobileParam.put("partnerId", result.get("mch_id"));
mobileParam.put("prepayId", result.get("prepay_id"));
mobileParam.put("packageValue", "Sign=WXPay");//???
mobileParam.put("nonceStr", result.get("nonce_str"));
mobileParam.put("timeStamp", signTimstamp);//单位为秒
//----这里不要使用请求预支付订单时返回的签名-------
mobileParam.put("sign", WxMD5Util.getSign(map));
mobileParam.put("extData", attach);
logger.info("支付返回参数:{}",JSONObject.toJSONString(map));
logger.info("返回移动端的参数:{}",JSONObject.toJSONString(mobileParam));
dataResponse.setData(mobileParam);
} catch (Exception e) {
e.printStackTrace();
return DataResponse.failure();
}
return dataResponse;
}
/**
* 微信退款接口--申请退款
* @param jsonObject
* @return
*/
public DataResponse wxRefund(@RequestBody JSONObject jsonObject){
DataResponse model= DataResponse.success();
String orderId = jsonObject.getString("orderId");//订单ID
try {
WXConfigUtil config = WXConfigUtil.initWXconfigUtil();
WXPay wxpay = new WXPay(config);
Map data = new HashMap<>();
Map refund = wxpay.refund(data);
} catch (Exception e) {
e.printStackTrace();
}
return model;
}
/**
* 支付异步结果通知,我们在请求预支付订单时传入的地址--无参数
* 官方文档 :https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_7&index=3
*/
@RequestMapping(value = "/notify", method = {RequestMethod.GET, RequestMethod.POST})
public String wxPayNotifyUnEncryption(HttpServletRequest request, HttpServletResponse response) {
String resXml = "";
try {
InputStream inputStream = request.getInputStream();
//将InputStream转换成xmlString
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
resXml = sb.toString();
String result = payBack(resXml);
return result;
} catch (Exception e) {
logger.info("微信手机支付失败:" + e.getMessage());
System.out.println("微信手机支付失败:" + e.getMessage());
String result = "" + "" + "" + " ";
return result;
}
}
/**
* 调用官方SDK 获取预支付订单等参数
*
* @param attach 额外参数
* @param total_fee 总价
* @return
* @throws Exception
*/
public Map dounifiedOrder(String attach, String total_fee,String spbillCreateIp) throws Exception {
logger.info("进入调用官方sdk方法,参数:{},{}",attach,total_fee);
Map returnMap = new HashMap<>();
WXConfigUtil config = WXConfigUtil.initWXconfigUtil();
WXPay wxpay = new WXPay(config);
Map data = new HashMap<>();
//生成商户订单号,不可重复
String out_trade_no = "wxpay" + System.currentTimeMillis();
data.put("appid", config.getAppID());//应用ID
data.put("mch_id", config.getMchID());//商户号
data.put("nonce_str", WXPayUtil.generateNonceStr());//随机字符串,不长于32位。推荐随机数生成算法
String body = "新脸谱微信订单支付-测试-"+ System.currentTimeMillis();
data.put("body", body); //商品描述
data.put("out_trade_no", out_trade_no); //商户订单号
data.put("total_fee", total_fee); //总金额
data.put("spbill_create_ip", spbillCreateIp);//自己的服务器IP地址 ---点击支付的机器IP
data.put("notify_url", NOTIFY_URL);//异步通知地址(请注意必须是外网)
data.put("trade_type", TRADE_TYPE_APP);//交易类型
data.put("attach", attach);//附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
String sign1 = WxMD5Util.getSign(data);
data.put("sign", sign1); //签名
logger.info("生成预订单的参数,{}", JSONObject.toJSON(data));
try {
//使用官方API请求预付订单
Map response = wxpay.unifiedOrder(data);
logger.info("预订单的返回结果,{}", JSONObject.toJSON(response));
String returnCode = response.get("return_code"); //获取返回码
//若返回码为SUCCESS,则会返回一个result_code,再对该result_code进行判断
if (returnCode.equals("SUCCESS")) {//主要返回以下5个参数
logger.info("预订单的返回结果SUCCESS,{}", JSONObject.toJSON(response));
String resultCode = response.get("result_code");
returnMap.put("appid", response.get("appid"));
returnMap.put("mch_id", response.get("mch_id"));
returnMap.put("nonce_str", response.get("nonce_str"));
returnMap.put("sign", response.get("sign"));
if ("SUCCESS".equals(resultCode)) {//resultCode 为SUCCESS,才会返回prepay_id和trade_type
//获取预支付交易回话标志
returnMap.put("trade_type", response.get("trade_type"));
returnMap.put("prepay_id", response.get("prepay_id"));
return returnMap;
} else {
logger.info("预订单的返回结果ERROR,{}", JSONObject.toJSON(response));
//此时返回没有预付订单的数据
return returnMap;
}
} else {
return returnMap;
}
} catch (Exception e) {
System.out.println(e);
//系统等其他错误的时候
}
return returnMap;
}
/**
* @param notifyData 异步通知后的XML数据
* @return
*/
public String payBack(String notifyData) {
logger.info("异步通知进入方法数据:{}",notifyData);
WXConfigUtil config = null;
try {
config = WXConfigUtil.initWXconfigUtil();
} catch (Exception e) {
e.printStackTrace();
}
WXPay wxpay = new WXPay(config);
String xmlBack = "";
Map notifyMap = null;
try {
notifyMap = WXPayUtil.xmlToMap(notifyData); // 调用官方SDK转换成map类型数据
logger.info("支付异步结果通知:{}",JSONObject.toJSONString(notifyMap));
if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {//验证签名是否有效,有效则进一步处理
String return_code = notifyMap.get("return_code");//状态
String out_trade_no = notifyMap.get("out_trade_no");//商户订单号
if (return_code.equals("SUCCESS")) {
if (out_trade_no != null) {
// 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户的订单状态从退款改成支付成功
// 注意特殊情况:微信服务端同样的通知可能会多次发送给商户系统,所以数据持久化之前需要检查是否已经处理过了,处理了直接返回成功标志
//业务数据持久化
System.err.println("支付成功");
logger.info("微信手机支付回调成功订单号:{}", out_trade_no);
xmlBack = "" + "" + "" + " ";
} else {
logger.info("微信手机支付回调失败订单号:{}", out_trade_no);
xmlBack = "" + "" + "" + " ";
}
}
return xmlBack;
} else {
// 签名错误,如果数据里没有sign字段,也认为是签名错误
//失败的数据要不要存储?
logger.error("手机支付回调通知签名错误");
xmlBack = "" + "" + "" + " ";
return xmlBack;
}
} catch (Exception e) {
logger.error("手机支付回调通知失败", e);
xmlBack = "" + "" + "" + " ";
}
return xmlBack;
}
static Properties getProperties() {
if(null == properties) {
properties = PropertiesUtil.getProperties("/wxConfig/WxpayConfig.properties");
}
return properties;
}
微信支付wxpay -- 移动端app第二章节 -- java 后端代码
原文:https://www.cnblogs.com/mafy/p/11888968.html