5.1. 定义接口
(1)创建 WxPayController
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@CrossOrigin
@RestController
@RequestMapping("/api/wx-pay")
@Api(tags = "网站微信支付")
@Slf4j
public class WxPayController {
}
(2)创建 WxPayService 接口和实现类
//接口
public interface WxPayService {
}
//实现类
import com.atguigu.paymentdemo.service.WxPayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {
}
(3)在 WxPayController 中注入 WxPayService,定义接口方法
用日志对象打印日志,方便调试
前端:获取商品信息,通过商品 ID 传给后端
@Resource
private WxPayService wxPayService;
/**
* Native下单
* @param productId
* @return
* @throws Exception
*/
@ApiOperation("调用统一下单API,生成支付二维码")
@PostMapping("/native/{productId}")
public R nativePay(@PathVariable Long productId) throws Exception {
log.info("发起支付请求");
//返回支付二维码连接和订单号
Map<String, Object> map = wxPayService.nativePay(productId);
return R.ok().setData(map);
}
R 对象中添加@Accessors 注解,使其可以链式操作
5.2. 定义业务层 WxPayServiceImpl 方法
(1)生成订单-创建临时订单对象
(2)调用下单 API,组装接口参数并发送请求
请求方式:POST
传参格式:json
调用方法:http 远程请求
注入 WxPayConfig 获取微信服务器地址
面向接口配置请求体 json 格式的参数
请求参数:公众号 id、商户号、商品描述、商户订单号、商户回调地址、订单金额(总金额+货币类型)
注入获取 httpClient 对象的方法,完成签名并执行请求
处理结果并展示支付二维码
@Resource
private WxPayConfig wxPayConfig;
@Resource
private CloseableHttpClient wxPayClient;
/**
* 创建订单,调用Native支付接口
* @param productId
* @return code_url 和 订单号
* @throws Exception
*/
@Override
public Map<String, Object> nativePay(Long productId) throws Exception {
log.info("生成订单");
//生成订单
OrderInfo orderInfo = new OrderInfo();
orderInfo.setTitle("test");
orderInfo.setOrderNo(OrderNoUtils.getOrderNo()); //订单号
orderInfo.setProductId(productId);
orderInfo.setTotalFee(1); //分
orderInfo.setOrderStatus(OrderStatus.NOTPAY.getType());
//TODO:存入数据库
log.info("调用统一下单API");
//调用统一下单API
HttpPost httpPost = new
HttpPost(wxPayConfig.getDomain().concat(WxApiType.NATIVE_PAY.getType()));
// 请求body参数
Gson gson = new Gson();
Map paramsMap = new HashMap();
paramsMap.put("appid", wxPayConfig.getAppid());
paramsMap.put("mchid", wxPayConfig.getMchId());
paramsMap.put("description", orderInfo.getTitle());
paramsMap.put("out_trade_no", orderInfo.getOrderNo());
paramsMap.put("notify_url",
wxPayConfig.getNotifyDomain().concat(WxNotifyType.NATIVE_NOTIFY.getType()));
Map amountMap = new HashMap();
amountMap.put("total", orderInfo.getTotalFee());
amountMap.put("currency", "CNY");
paramsMap.put("amount", amountMap);
//将参数转换成json字符串
String jsonParams = gson.toJson(paramsMap);
log.info("请求参数:" + jsonParams);
StringEntity entity = new StringEntity(jsonParams,"utf-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
//完成签名并执行请求
CloseableHttpResponse response = wxPayClient.execute(httpPost);
try {
String bodyAsString = EntityUtils.toString(response.getEntity());//响应体
int statusCode = response.getStatusLine().getStatusCode();//响应状态码
if (statusCode == 200) { //处理成功
log.info("成功, 返回结果 = " + bodyAsString);
} else if (statusCode == 204) { //处理成功,无返回Body
log.info("成功");
} else {
log.info("Native下单失败,响应码 = " + statusCode+ ",返回结果 = " + bodyAsString);
throw new IOException("request failed");
}
//响应结果
Map<String, String> resultMap = gson.fromJson(bodyAsString,
HashMap.class);
//二维码
String codeUrl = resultMap.get("code_url");
Map<String, Object> map = new HashMap<>();
map.put("codeUrl", codeUrl);
map.put("orderNo", orderInfo.getOrderNo());
return map;
} finally {
response.close();
}
}
}
最后在 WxPayController 中抛出异常
启动项目,进入 swagger 页面测试
启动前端测试
(3)添加日志打印
5.3. 前端代码解析
(1)商品列表
脚本定义商品列表
create 方法获取商品列表:调用后端接口,获取对应数据属性为商品列表赋值
productApi 模块定义:远程调用接口
前端遍历
对应后端 ProductController 接口
(跳过)