JAVA开发微信支付-公众号支付/微信浏览器支付(JSAPI)
一、配置微信平台
(1)配置微信公众平台
登录微信公众平台=》公众号设置=》功能设置=》网页授权域名
(2)配置微信商家平台
产品中心=》开发配置
(2.2) 后台代码的实现
JSAPI官方文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
①先去官方下载SDK,并导进项目中
地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1
②准备好11个参数
appid:商家平台ID。在微信的平台上有
body:商品描述。
mch_id:商户ID。在微信的平台上有
nonce_str:随机字符串,UUID就好了。
openid:用户标识。因为这边是用户已经登录成功了。所以在session中就能拿到。
out_trade_no:商户订单号
spbill_create_ip:终端IP。这个可以从请求头中拿到
total_fee:支付金额。单位是分。
trade_type:交易类型。这里我填JSAPI
notify_url:通知地址。就是用户支付成功之后,微信访问你的哪个接口,跟你传递支付成功的相关信息。
sign:签名。这个签名它是由上面的10个参数计算得出的。
③源码
controller层:
import com.dwl.common_utils.Result.Result;
import com.dwl.service_order.service.PayLogService;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* <p>
* 支付日志表 前端控制器
* </p>
*
* @author dwl
* @since 2021-02-23
*/
@RestController
@RequestMapping("/orderService/payLog")
@CrossOrigin
public class PayLogController {
private PayLogService payLogService;
@Autowired
public PayLogController(PayLogService payLogService) {
this.payLogService = payLogService;
}
public PayLogController() {
}
/**
* 生成微信支付二维码接口
*
* @param orderNo 参数是订单号
* @return
*/
@ApiOperation(value = "生成微信支付二维码接口,参数是订单号")
@GetMapping("/createNative/{orderNo}")
public Result createNative(
@ApiParam(name = "orderNo", value = "订单号", required = true)
@PathVariable String orderNo) {
// 返回信息,包含二维码地址,还有其他需要的信息
Map<String, Object> map = payLogService.createNatvie(orderNo);
return Result.ok().data(map);
}
/**
* 查询订单支付状态
*
* @param orderNo 订单号,根据订单号查询 支付状态
* @return
*/
@ApiOperation(value = "查询订单支付状态")
@GetMapping("/queryPayStatus/{orderNo}")
public Result queryPayStatus(
@ApiParam(name = "orderNo", value = "订单号", required = true)
@PathVariable String orderNo) {
Map<String, String> map = payLogService.queryPayStatus(orderNo);
if (map == null) {
return Result.error().message("支付出错了");
}
// 如果返回map里面不为空,通过map获取订单状态
if (map.get("trade_state").equals("SUCCESS")) {// 支付成功
// 添加记录到支付表,更新订单表订单状态
payLogService.updateOrdersStatus(map);
return Result.ok().message("支付成功");
}
return Result.ok().success(false).message("");
}
}
service层:
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dwl.common_utils.Result.ResultCode;
import com.dwl.common_utils.util.HttpClient;
import com.dwl.service_base.exception_handler.GuLiException;
import com.dwl.service_order.entity.Order;
import com.dwl.service_order.entity.PayLog;
import com.dwl.service_order.mapper.PayLogMapper;
import com.dwl.service_order.service.OrderService;
import com.dwl.service_order.service.PayLogService;
import com.dwl.service_order.util.WX;
import com.github.wxpay.sdk.WXPayUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* <p>
* 支付日志表 服务实现类
* </p>
*
* @author dwl
* @since 2021-02-23
*/
@Service
public class PayLogServiceImpl extends ServiceImpl<PayLogMapper, PayLog> implements PayLogService {
private OrderService orderService;
@Autowired
public PayLogServiceImpl(OrderService orderService) {
this.orderService = orderService;
}
public PayLogServiceImpl() {
}
/**
* 生成微信支付二维码接口
*
* @param orderNo
* @return
*/
@Override
public Map<String, Object> createNatvie(String orderNo) {
try {
// 1.根据订单号查询订单信息
QueryWrapper<Order> wrapper = new QueryWrapper<>();
wrapper.eq("order_no", orderNo);
Order order = orderService.getOne(wrapper);
// 2.使用map设置生成二维码需要参数
Map<String, String> m = new HashMap<>();
m.put("appid", WX.APP_ID.getStr()); // 商家平台ID
m.put("mch_id", WX.MCH_ID.getStr()); // 商户ID
m.put("nonce_str", WXPayUtil.generateNonceStr());
m.put("body", order.getCourseTitle()); // 课程标题
m.put("out_trade_no", orderNo); // 订单号
m.put("total_fee", order.getTotalFee().multiply(new BigDecimal("100")).longValue() + ""); // 支付金额,单位分
m.put("spbill_create_ip", "127.0.0.1"); // 终端IP
m.put("notify_url", WX.NOTIFY_URL.getStr() + "\n"); // 此路径是微信服务器调用支付结果通知路径随意写
m.put("trade_type", "NATIVE"); // 支付类型
// 3.发送httpclient请求,传递参数xml格式,微信支付提供的固定的地址
HttpClient client = new HttpClient(WX.PAY_CLIENT.getStr());
// 设置xml格式的参数
client.setXmlParam(WXPayUtil.generateSignedXml(m, WX.KEY.getStr()));
client.setHttps(true);
// 执行post请求发送
client.post();
/* 4.得到发送请求返回结果
返回内容,是使用xml格式返回 */
String xml = client.getContent();
// 把xml格式转换map集合,把map集合返回
Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
// 最终返回数据 的封装
Map<String, Object> map = new HashMap<>();
map.put("out_trade_no", orderNo); // 商户订单号 必传
map.put("course_id", order.getCourseId());
map.put("total_fee", order.getTotalFee()); // 支付金额,单位分 必传
map.put("result_code", resultMap.get("result_code")); // 返回二维码操作状态码 必传
map.put("code_url", resultMap.get("code_url")); // 二维码地址 必传
// 返回
return map;
} catch (Exception e) {
throw new GuLiException(ResultCode.ERROR.getStatus(), e + "");
}
}
/**
* 查询订单支付状态
*
* @param orderNo 订单号
* @return
*/
@Override
public Map<String, String> queryPayStatus(String orderNo) {
try {
// 1.封装参数
Map<String, String> m = new HashMap<>();
m.put("appid", WX.APP_ID.getStr());
m.put("mch_id", WX.MCH_ID.getStr());
m.put("out_trade_no", orderNo);
m.put("nonce_str", WXPayUtil.generateNonceStr());
// 2.发送httpclient
HttpClient client = new HttpClient(WX.QUERY_CLIENT.getStr());
client.setXmlParam(WXPayUtil.generateSignedXml(m, WX.KEY.getStr()));
client.setHttps(true);
client.post();
// 3.得到请求返回内容
String xml = client.getContent();
// 6.转成Map再返回
return WXPayUtil.xmlToMap(xml);
} catch (Exception e) {
return null;
}
}
/**
* 添加支付记录和更新订单状态
*
* @param map
*/
@Override
public void updateOrdersStatus(Map<String, String> map) {
// 从map获取订单号
String orderNo = map.get("out_trade_no");
// 根据订单号查询订单信息
QueryWrapper<Order> wrapper = new QueryWrapper<>();
wrapper.eq("order_no", orderNo);
Order order = orderService.getOne(wrapper);
// 更新订单表订单状态
if (order.getStatus() == 1) {
return;
}
order.setStatus(1);// 1代表已经支付
orderService.updateById(order);
// 向支付表添加支付记录
PayLog payLog = new PayLog();
payLog.setOrderNo(orderNo); // 订单号
payLog.setPayTime(new Date()); // 订单完成时间
payLog.setPayType(1);// 支付类型 1微信
payLog.setTotalFee(order.getTotalFee());// 总金额(分)
payLog.setTradeState(map.get("trade_state"));// 支付状态
payLog.setTransactionId(map.get("transaction_id")); // 流水号
payLog.setAttr(JSONObject.toJSONString(map));
baseMapper.insert(payLog);
}
}
工具类:
public enum WX {
APP_ID("xxxxxxxxxxxxxx"),
MCH_ID("xxxxxxxxxxxxx"),
PAY_CLIENT("https://api.mch.weixin.qq.com/pay/unifiedorder"),
QUERY_CLIENT("https://api.mch.weixin.qq.com/pay/orderquery"),
KEY("xxxxxxxxxxxxxxxxxxxx"),
NOTIFY_URL("http://guli.shop/api/order/weixinPay/weixinNotify");
private String str;
WX(String str) {
this.str = str;
}
public String getStr() {
return str;
}
}
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class HttpClient {
private String url;
private Map<String, String> param;
private int statusCode;
private String content;
private String xmlParam;
private boolean isHttps;
public boolean isHttps() {
return isHttps;
}
public void setHttps(boolean isHttps) {
this.isHttps = isHttps;
}
public String getXmlParam() {
return xmlParam;
}
public void setXmlParam(String xmlParam) {
this.xmlParam = xmlParam;
}
public HttpClient(String url, Map<String, String> param) {
this.url = url;
this.param = param;
}
public HttpClient(String url) {
this.url = url;
}
public void setParameter(Map<String, String> map) {
param = map;
}
public void addParameter(String key, String value) {
if (param == null)
param = new HashMap<String, String>();
param.put(key, value);
}
public void post() throws ClientProtocolException, IOException {
HttpPost http = new HttpPost(url);
setEntity(http);
execute(http);
}
public void put() throws ClientProtocolException, IOException {
HttpPut http = new HttpPut(url);
setEntity(http);
execute(http);
}
public void get() throws ClientProtocolException, IOException {
if (param != null) {
StringBuilder url = new StringBuilder(this.url);
boolean isFirst = true;
for (String key : param.keySet()) {
if (isFirst)
url.append("?");
else
url.append("&");
url.append(key).append("=").append(param.get(key));
}
this.url = url.toString();
}
HttpGet http = new HttpGet(url);
execute(http);
}
/**
* set http post,put param
*/
private void setEntity(HttpEntityEnclosingRequestBase http) {
if (param != null) {
List<NameValuePair> nvps = new LinkedList<NameValuePair>();
for (String key : param.keySet())
nvps.add(new BasicNameValuePair(key, param.get(key))); // 参数
http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // 设置参数
}
if (xmlParam != null) {
http.setEntity(new StringEntity(xmlParam, Consts.UTF_8));
}
}
private void execute(HttpUriRequest http) throws ClientProtocolException,
IOException {
CloseableHttpClient httpClient = null;
try {
if (isHttps) {
SSLContext sslContext = new SSLContextBuilder()
.loadTrustMaterial(null, new TrustStrategy() {
// 信任所有
public boolean isTrusted(X509Certificate[] chain,
String authType)
throws CertificateException {
return true;
}
}).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext);
httpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
.build();
} else {
httpClient = HttpClients.createDefault();
}
CloseableHttpResponse response = httpClient.execute(http);
try {
if (response != null) {
if (response.getStatusLine() != null)
statusCode = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
// 响应内容
content = EntityUtils.toString(entity, Consts.UTF_8);
}
} finally {
response.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
httpClient.close();
}
}
public int getStatusCode() {
return statusCode;
}
public String getContent() throws ParseException, IOException {
return content;
}
}
总结