使用框架springboot 数据库 mysql
阅读本文请先详细阅读微信文件 https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1(以统一下单为例)。
微信支付还是有很多坑的,在开发中还是需要和移动端或者前端多沟通,多交流方能解决。
微信支付接口签名校验工具 https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=20_1(下面会用到)
下面开始准备阶段,准备阶段是需要开发之前的一些准备工作,虽然看似简单,但是会影响后续的开发工作,所以这步也是重中之重。
微信app支付是不同于微信公众号支付的他是独立之外的所以申请时也要格外注意。
然后需要去商户平台去拿商户号以及key(api key ) 以及api证书
这是我的config文件这块还是有坑的后续还是需要优化的,appid、mac_id /api_key等文件是绝密是需要做处理的不应该这么显示。
做之前一定要有一个大概思路,而不应该乱,知道这步该干什么下步该干什么,做好有条不紊。
下面开始上代码,不上代码的程序员就是在耍流氓。
config层
public String app_id = "appid";
/**
* 商户号
*/
public String mch_id = "商户号";
/**
* API 密钥
*/
//
public String key = "api秘钥";
/**
* API证书绝对路径 (本项目放在了 /src/resources/cert/wxpay/apiclient_cert.p12")
*/
private String certPath = ClassUtils.getDefaultClassLoader().getResource("").getPath()+"/certificate/apiclient_cert.p12";
controller 这块我只截了一部分,里面的逻辑还需要自己处理。
@Autowired
HttpServletRequest request;
@ApiOperation(value = "微信支付统一下单", notes = "统一下单")
@GetMapping("/unifiedOrder")
@ResponseBody
public ResponseResult<Object> unifiedOrder(HttpServletRequest request,
@ApiParam(value = "订单号") @RequestParam String orderNum, @ApiParam(value = "订单金额") @RequestParam Double countsum,
@ApiParam(value = "商品描述") @RequestParam String body, @ApiParam(value = "用户标识") @RequestParam Long memberId) {
wxpayService.unifiedOrder(orderNum,countsum,body,memberId);
}
重点来了 servicempl
@Override
public Map<String, String> unifiedOrder(String orderNum, Double amount, String body,Long memberId) {
System.out.println("--------------去支付------------------");
Map<String, String> hashMap = new HashMap<>();
final Logger logger = LoggerFactory.getLogger("MainLogger");
final String SPBILL_CREATE_IP = "ip地址";
final String NOTIFY_URL = "回调地址";
final String TRADE_TYPE_APP = "APP";
final Map<String, String> map = new HashMap<String, String>();
try {
WxchatpayConfig wxchatpayConfig = new WxchatpayConfig();
map.put("appid", wxchatpayConfig.getAppID()); //应用Id
map.put("mch_id", wxchatpayConfig.getMchID()); //商户号
map.put("nonce_str",WXPayUtil.generateNonceStr()); //随机字符串
map.put("body", body); //商品描述
map.put("out_trade_no",orderNum); //商户订单号
map.put("total_fee","1"); //总金额
map.put("spbill_create_ip",SPBILL_CREATE_IP); //终端ip
StringBuffer notifyUrl = new StringBuffer();
notifyUrl.append(NOTIFY_URL);
if(memberId != null){
notifyUrl.append("?member_id=").append(memberId);
}
//通知地址
map.put("notify_url",NOTIFY_URL);
//交易类型
map.put("trade_type", "APP");
String xml = WXPayUtil.generateSignedXml(map, wxchatpayConfig.getKey());
logger.info("out_trade_no:" + orderNum + ",调用微信APP支付参数:" + xml);
String res = pay(xml, "https://api.mch.weixin.qq.com/pay/unifiedorder");
logger.info("out_trade_no:" + orderNum + ",调用微信APP支付返回:" + res);
hashMap = WXPayUtil.xmlToMap(res);
String currentTime = System.currentTimeMillis() / 1000 + "";
Map<String, String> resultMap = new HashMap<>();
resultMap.put("appid", wxchatpayConfig.getAppID());
resultMap.put("partnerid", wxchatpayConfig.getMchID());
resultMap.put("prepayid", hashMap.get("prepay_id"));
resultMap.put("package", "Sign=WXPay");
resultMap.put("noncestr",WXPayUtil.generateNonceStr());
resultMap.put("timestamp", currentTime);
resultMap.put("sign",WXPayUtil.generateSignature(resultMap,
wxchatpayConfig.getKey()));
return resultMap;
} catch (Exception e) {
e.printStackTrace();
}
return hashMap;
}
/****
* 支付
* @param reqBody
* @param url
* @return
* @throws Exception
*/
private String pay(String reqBody, String url) throws Exception {
String UTF8 = "UTF-8";
URL httpUrl = new URL(url);
HttpURLConnection httpURLConnection = (HttpURLConnection) httpUrl.openConnection();
httpURLConnection.setRequestProperty("Host", "api.mch.weixin.qq.com");
httpURLConnection.setDoOutput(true);
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setConnectTimeout(10 * 1000);
httpURLConnection.setReadTimeout(10 * 1000);
httpURLConnection.connect();
OutputStream outputStream = httpURLConnection.getOutputStream();
outputStream.write(reqBody.getBytes(UTF8));
//获取内容
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new
InputStreamReader(inputStream, UTF8));
final StringBuffer stringBuffer = new StringBuffer();
String line = null;
while ((line = bufferedReader.readLine()) != null) {
stringBuffer.append(line);
}
String resp = stringBuffer.toString();
if (stringBuffer != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resp;
}
敲黑板!!!!!
有的时候不只是仅仅要实现就行了,还得了解原理,能说出来,毕竟还要面试吗,做火箭的过程还是要有的,虽然生活处处都在拧螺丝,但是不要放弃,坚持。
如果你从头到尾按我的步骤走的那么此时你的接口应该可以被客户端调起来了
util类
public class WXPayUtil {
/**
* XML格式字符串转换为Map
* @param strXML XML字符串
* @return XML数据转换后的Map
* @throws Exception
*/
public static Map<String, String> xmlToMap(String strXML) throws Exception {
try {
Map<String, String> data = new HashMap<String, String>();
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
org.w3c.dom.Document doc = documentBuilder.parse(stream);
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getDocumentElement().getChildNodes();
for (int idx = 0; idx < nodeList.getLength(); ++idx) {
Node node = nodeList.item(idx);
if (node.getNodeType() == Node.ELEMENT_NODE) {
org.w3c.dom.Element element = (org.w3c.dom.Element) node;
data.put(element.getNodeName(), element.getTextContent());
}
}
try {
stream.close();
} catch (Exception ex) {
// do nothing
}
return data;
} catch (Exception ex) {
WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);
throw ex;
}
}
/**
* 获取随机字符串 Nonce Str
*
* @return String 随机字符串
*/
public static String generateNonceStr() {
return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
}
/**
* 生成带有 sign 的 XML 格式字符串
*
* @param data Map类型数据
* @param key API密钥
* @param signType 签名类型
* @return 含有sign字段的XML
*/
public static String generateSignedXml(final Map<String, String> data, String key, WXPayConstants.SignType signType) throws Exception {
String sign = generateSignature(data, key, signType);
data.put(WXPayConstants.FIELD_SIGN, sign);
return mapToXml(data);
}
}
回调
/****
* @微信支付回调方法
*/
@RequestMapping("/notify")
@ResponseBody
public String payNotify(HttpServletRequest request) throws Exception {
System.out.println("------------微信回调函数");
ResponseResult responseResult = new ResponseResult<>();
BufferedReader reader = null;
reader = request.getReader();
String line = "";
String xmlString = null;
StringBuffer inputString = new StringBuffer();
while ((line = reader.readLine()) != null) {
inputString.append(line);
}
xmlString = inputString.toString();
reader.close();
Map<String,String> map= WXPayUtil.xmlToMap(xmlString);
for(String s:map.keySet()){
System.out.println("微信回调信息为 =================KEY"+s+"=============="+map.get(s).toString());
}
String returnCode= map.get("return_code");
if("SUCCESS".equals(returnCode)){
String outTradeNo=map.get("out_trade_no");
Order order= wxpayService.findOrder(outTradeNo);
if(order!=null&& OrderConstant.UNPAID==order.getPayStatus()&&"SUCCESS".equals(map.get("result_code"))){
Pay pay=new Pay();
pay.setCreatAt(new Date()); //创建时间
pay.setOrderNum(outTradeNo); //订单号
pay.setPayPrice(map.get("total_fee")); //总金额
// pay.setPayPrice((new BigDecimal(map.get("total_fee"))).divide(new BigDecimal("100")));
pay.setBuyerAccounts(map.get("openid")); //用户付款账号
pay.setCode(Pay.class.getName());
pay.setPayType(2); //支付方式 1.支付宝 2.微信
pay.setPayStatus(PayReturnConstant.paySuccess); //支付状态
pay.setTr(1); //状态
long currentTimeMillis = DateTimeUtils.currentTimeMillis();
pay.setPayTime(new Date(currentTimeMillis)); //支付时间
pay.setTradeNo(map.get("transaction_id")); //交易流水号
wxpayService.add(pay);
wxpayService.updateWechatPayStatus(outTradeNo);
}
}
return "SUCCESS";
}