一:web网站接入微信扫码支付功能(NATIVE)
二:准备工作
微信支付配置参数
1:appId 商家平台ID
2:mchID 商户平台ID
3:machSecret 商户平台密钥
以上三个参数找老板要(缺一不可)
三:官方DEMO下载地址
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1
官方demo在项目的md文件里
四:代码
1:maven依赖
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
非maven项目下载demo打jar包
2:配置文件
最后边俩个属性是俩种支付方式的回调地址(也是调用接口必填参数)
3:配置类
@Component
public class WxpayConfig implements WXPayConfig {
@Autowired
private WxProperties properties;
private byte[] certData;
public WxPayConfig(WxProperties properties) {
this.properties = properties;
}
public WxPayConfig() {
}
public WxpayConfig() throws Exception {
String certPath = "/path/to/apiclient_cert.p12";
File file = new File(certPath);
InputStream certStream = new FileInputStream(file);
this.certData = new byte[(int) file.length()];
certStream.read(this.certData);
certStream.close();
}
@Override
public String getAppID() {
return properties.getAppID();
}
@Override
public String getMchID() {
return properties.getMchID();
}
@Override
public String getKey() {
return properties.getKey();
}
@Override
public InputStream getCertStream() {
ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
return certBis;
}
@Override
public int getHttpConnectTimeoutMs() {
return Integer.parseInt(properties.getHttpConnectTimeoutMs());
}
@Override
public int getHttpReadTimeoutMs() {
return Integer.parseInt(properties.getHttpReadTimeoutMs());
}
}
4:controller层
private static final Integer[] PAY_ARR={1,2,3};
@ApiOperation("学员端提交订单")
@PostMapping("/student/order/create")
public DataResult<Map<String,String>> createOrderByStudent(@RequestBody @Valid StuCreateOrderReqVo vo, BindingResult result, HttpServletRequest request){
log.info("学员端创建订单接收到请求");
if(result.hasErrors()){
return new DataResult(BaseResponseCode.DATA_ERROR,result.getFieldError().getDefaultMessage());
}
List<Integer> list = Arrays.asList(PAY_ARR);
if(!list.contains(vo.getPayType()) || vo.getPayType()==null){
return new DataResult(BaseResponseCode.DATA_ERROR,"支付类型有误");
}
//创建订单
UserOrders userOrders =userOrdersService.stuCreateOrderWeb(vo,request);
log.info("订单创建成功,走支付流程");
Map<String,String> map=payOrderService.stuPayOrder(userOrders,request);
return DataResult.success(map);
}
5:service层(只写实现类)
/**
* 拉起支付
* @param userOrders
* @return
*/
public Map<String, String> stuPayOrder(UserOrders userOrders, HttpServletRequest request) {
Map<String,String> map=null;
String ipAddr = IPUtils.getIpAddr(request);
if(userOrders.getPaytype()==1){
log.info("调用微信统一下单");
map = wxPayService.unifiedOrder(userOrders, ipAddr);
if("true".equalsIgnoreCase(map.get("success"))){
map.put("orderId",userOrders.getId()+"");
}
}else if(userOrders.getPaytype()==3){
log.info("调用支付宝统一下单");
map = aliPayService.prePay(userOrders, ipAddr);
if("true".equalsIgnoreCase(map.get("success"))){
map.put("orderId",userOrders.getId()+"");
}
}
return map;
6:WxService
/**
* 统一下单:商户先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易后调起支付。
*
* @param order 订单信息
* @param clientIP ip
*/
public Map<String, String> unifiedOrder(UserOrders order, String clientIP) {
UserInfo student = sourcePackagesMapper.queryOneStudent(order.getUserinfoId());
WXPayConfig config = new WxPayConfig(properties);
WXPay wxpay = new WXPay(config);
Map<String, String> requestData = new HashMap<>();
// 商品描述
requestData.put("body", order.getPackageName());
// 商户订单号
requestData.put("out_trade_no", order.getOrderNum());
long total_fee = (long) (order.getPayPrice() * 100L);
log.info(" 订单总金额,单位为分:" + total_fee);
// 订单总金额,单位为分
requestData.put("total_fee", String.valueOf(total_fee));
log.info("下单用户IP:" + clientIP);
// 用户端实际ip
requestData.put("spbill_create_ip", clientIP);
Map<String, String> returnData = new HashMap<>();
Map<String, String> responseData = null;
// WEB端
// 接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数
requestData.put("notify_url", properties.getCallbackUrlWeb());
//我用的是扫码支付所以这儿填NATIVE
requestData.put("trade_type", "NATIVE");
requestData.put("product_id", order.getPackageId() + "");
try {
responseData = wxpay.unifiedOrder(requestData);
} catch (Exception e) {
log.error("请求支付失败", e);
returnData.put("success", "false");
returnData.put("msg", "请求支付失败:" + e.getMessage());
}
if (null != responseData) {
if (!"SUCCESS".equals(responseData.get("return_code"))) {
returnData.put("success", "false");
returnData.put("msg", "请求支付失败:" + responseData.get("return_msg"));
} else if (!"SUCCESS".equals(responseData.get("result_code"))) {
returnData.put("success", "false");
returnData.put("msg", "请求支付失败:" + responseData.get("err_code") + "-" + responseData.get("err_code_des"));
} else {
returnData.put("code_url", responseData.get("code_url"));
userOrdersMapper.updatePrepayidById(order.getId(), responseData.get("prepay_id"));
returnData.put("success", "true");
}
}
log.debug("微信支付请求结果:{}", returnData);
return returnData;
}
如果接口调用成功 WX会返回code_url(微信付款二维码链接),把它返回给前端生成二维码即可
7:付款后需要接收微信回调(参数:notify_url,回调地址需要外网可以访问,如果你需要测试请用自己的服务器或者内网穿透工具)
回调接口:
@RequestMapping(value = "/web")
@ResponseBody
public String callBackWeb(HttpServletRequest req) throws Exception {
log.info("接收到微信回调");
StringBuffer xmlStr = new StringBuffer();
Scanner s = new Scanner(req.getInputStream(), "UTF-8");
while(s.hasNextLine()){
xmlStr.append(s.nextLine());
}
s.close();
log.debug("微信返回的数据XML: {}", xmlStr.toString());
if(!StringUtils.isEmpty(xmlStr.toString())){
Map<String, String> map = wxPayService.payCallbackHandle(xmlStr.toString());
if("true".equalsIgnoreCase(map.get("success"))){
//接收到微信回调主动去查支付是否成功
String result = wxPayService.validate(map.get("orderNum"));
if("OK".equalsIgnoreCase(result)){
//我自己的业务逻辑
List<UserOrders> orderNum = userOrdersService.queryUserOrderByOrderNum(map.get("orderNum"));
if(!orderNum.isEmpty()){
if(orderNum.get(0).getStatu()==0){
result = userOrdersService.payOrder(map.get("orderNum"));
//支付成功修改优惠券使用记录
if(orderNum.get(0).getDiscountId()!=0){
userOrdersService.updateDiscount(orderNum.get(0).getDiscountId(),map.get("orderNum"));
}
}
}
if("OK".equalsIgnoreCase(result)){
return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
}else{
log.error(result);
}
}else{
log.error(result);
}
}else{
log.error(map.get("msg"));
}
}else{
log.error("非法请求!");
}
return "ERROR";
}
8:wxPayService代码
/**
* 校验微信支付回调接口传来的数据
* @param xmlStr 微信支付回调接口返回的XML数据
* */
public Map<String, String> payCallbackHandle(String xmlStr) throws Exception {
WXPayConfig config = new WxPayConfig(properties);
WXPay wxpay = new WXPay(config);
Map<String, String> dataMap = wxpay.processResponseXml(xmlStr);
log.debug("微信支付回调-微信返回的数据dataMap={}", dataMap);
Map<String, String> returnData = new HashMap<>();
if(!"SUCCESS".equals(dataMap.get("return_code"))){
log.error("微信支付回调错误-{}", dataMap.get("return_msg"));
returnData.put("success", "false");
returnData.put("msg", dataMap.get("return_msg"));
}else if(!"SUCCESS".equals(dataMap.get("result_code"))){
log.error("微信支付回调错误-{}", dataMap.get("err_code") + "-" + dataMap.get("err_code_des"));
returnData.put("success", "false");
returnData.put("msg", dataMap.get("err_code") + "-" + dataMap.get("err_code_des"));
}else{
returnData.put("success", "true");
returnData.put("orderNum", dataMap.get("out_trade_no"));
}
return returnData;
}
/**
* 校验订单是否已支付
* @param orderNum 订单号
* @return 返回"OK"标示已支付,其他表示错误信息
*/
public String validate(String orderNum) {
Example example = new Example(UserOrders.class);
Example.Criteria criteria = example.createCriteria();
criteria.andEqualTo("orderNum",orderNum);
List<UserOrders> ordersList = userOrdersMapper.selectByExample(example);
UserOrders order = ordersList.get(0);
WXPayConfig config = new WxPayConfig(properties);
WXPay wxpay = new WXPay(config);
Map<String, String> data = new HashMap<>();
data.put("out_trade_no", order.getOrderNum());
try {
Map<String, String> resp = wxpay.orderQuery(data);
if(!"SUCCESS".equals(resp.get("return_code"))){
return resp.get("return_msg");
}else if(!"SUCCESS".equals(resp.get("result_code"))){
return resp.get("err_code") + " - " + resp.get("err_code_des");
}else{
if("SUCCESS".equals(resp.get("trade_state"))){
return "OK";
}else{
return "未支付";
}
}
} catch (Exception e) {
log.error("检验订单是否已支付出错", e);
return "校验支付状态出错";
}
}
9:工具类 ipUtils
private static Logger logger = LoggerFactory.getLogger(IPUtils.class);
/**
* 获取IP地址
*
* 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
* 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
*/
public static String getIpAddr(HttpServletRequest request) {
String ip = null;
try {
ip = request.getHeader("x-forwarded-for");
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
} catch (Exception e) {
logger.error("IPUtils ERROR ", e);
}
// 使用代理,则获取第一个IP地址
if (StringUtils.isEmpty(ip) && ip.length() > 15) {
if (ip.indexOf(",") > 0) {
ip = ip.substring(0, ip.indexOf(","));
}
}
return ip;
}
结束 (是不是很简单)
其他微信其他方式支付我也做过一些,老铁们有疑问可以评论或者私信我,咱一起学习共同进步
支付宝支付有时间我会更上
版权声明:本文为weixin_46421224原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。