1、項目目錄結構
2、在pom.xml中引入相關依賴
<dependencies>
<!--微信支付相關依賴-->
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
//httpclient相關依賴
<!--httpclient-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<!--commons-io-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<!--gson-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
</dependencies>
3、PayInfoController
@RestController
@RequestMapping("/mallservice/payInfo")
@CrossOrigin(allowCredentials = "true", allowedHeaders = "*")
@Slf4j
public class PayInfoController {
@Autowired
private PayInfoService payInfoService;
/*生成微信支付二維碼接口*/
@GetMapping("/createPayCode/{orderId}")
public R createPayCode(@PathVariable String orderId) {
Map map = this.payInfoService.createPayCode(orderId);
log.info("生成二維碼" + map.toString());
return R.ok().data(map);
}
//檢查訂單狀態
@GetMapping(value = "/queryPayStatus/{orderId}")
public R queryPayStatus(@PathVariable String orderId) {
Map<String, String> map = this.payInfoService.queryPayStatus(orderId);
if (map == null) {
return R.error().message("支付出錯");
}
if (map.get("trade_state").equals("SUCCESS")) {
log.info("檢查訂單狀態" + map.get("trade_state"));
//更新訂單狀態
//更改訂單狀態
payInfoService.updateOrderStatus(map);
return R.ok().message("支付成功");
}
//前端響應過濾器 25000被攔截
return R.ok().code(25000).message("支付中。。。。。");
}
}
4、PayInfoServiceImpl
@Service
@Slf4j
public class PayInfoServiceImpl extends ServiceImpl<PayInfoMapper, PayInfo> implements PayInfoService {
@Autowired
private OrderService orderService;
/*生成微信支付二維碼*/
@Override
public Map createPayCode(String orderId) {
try {
//根據訂單id獲取訂單信息
QueryWrapper<Order> wrapper = new QueryWrapper<>();
wrapper.eq("id", orderId);
Order order = orderService.getOne(wrapper);
Map m = new HashMap();
//1、設置支付參數
m.put("appid", "wx74862e954");
m.put("mch_id", "15591"); //商戶號
m.put("nonce_str", WXPayUtil.generateNonceStr());
m.put("body", orderId); //.......
m.put("out_trade_no", orderId);
m.put("total_fee", order.getPaymentPrice().multiply(new BigDecimal("100")).longValue() + "");
m.put("spbill_create_ip", "127.0.0.1");
m.put("notify_url", "http://guli.shop/api/order/weixinPay/weixinNotify"); //回調地址
m.put("trade_type", "NATIVE");
//2、HTTPClient來根據URL訪問第三方接口並且傳遞參數
HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
//client設置參數
client.setXmlParam(WXPayUtil.generateSignedXml(m, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));
client.setHttps(true); //允許https請求
client.post();
//3、返回第三方的數據
String xml = client.getContent();
Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
//4、封裝返回結果集
Map map = new HashMap<>();
map.put("out_trade_no", orderId);
map.put("user_id", order.getUserId());
map.put("total_fee", order.getPaymentPrice());
map.put("result_code", resultMap.get("result_code")); //返回二維碼操作狀態碼
map.put("code_url", resultMap.get("code_url")); //二維碼地址
//微信支付二維碼2小時過期,可採取2小時未支付取消訂單
//redisTemplate.opsForValue().set(orderNo, map, 120, TimeUnit.MINUTES);
return map;
} catch (Exception e) {
e.printStackTrace();
return new HashMap<>();
}
}
//查詢訂單狀態
@Override
public Map queryPayStatus(String orderId) {
try {
//1、封裝參數
Map m = new HashMap<>();
m.put("appid", "wx74862e0dfc4");
m.put("mch_id", "150191");
m.put("out_trade_no", orderId);
m.put("nonce_str", WXPayUtil.generateNonceStr());
//2、設置請求
HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
client.setXmlParam(WXPayUtil.generateSignedXml(m, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));
client.setHttps(true);
client.post();
//3、返回第三方的數據
String xml = client.getContent();
//4、轉成Map並返回
Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
return resultMap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/*支付成功向支付表中添加記錄,同時更新訂單表中的支付狀態等信息*/
@Override
public void updateOrderStatus(Map<String, String> map) {
log.info("修改訂單狀態" + "開始");
//獲取訂單id
String orderId = map.get("out_trade_no");
//根據訂單id查詢訂單信息
QueryWrapper<Order> wrapper = new QueryWrapper<>();
wrapper.eq("id", orderId);
Order order = orderService.getOne(wrapper);
if (order.getStatus().intValue() == 1) return;
order.setStatus(CONSTANT.ORDER_SATAUS.HAS_PAIED);
order.setPaymentTime(new Date());
order.setPaymentType(1);
orderService.updateById(order);
//記錄支付日誌
PayInfo payInfo = new PayInfo();
payInfo.setOrderId(order.getId());//支付訂單號
payInfo.setPlatformStatus(CONSTANT.PLATFORM_STATUS.TRADE_SUCCESS);
payInfo.setPayPlatform(1);//支付類型
payInfo.setOrderId(order.getId());
payInfo.setUserId(map.get("user_id"));
payInfo.setTransactionId(map.get("transaction_id"));
// payLog.setAttr(JSONObject.toJSONString(map));
baseMapper.insert(payInfo);//插入到支付日誌表
log.info("修改訂單狀態" + "完成");
}
}
前端顯示支付二維碼:
(1)引入生成二維碼的js
(2)在HTML部分綁定一個id名爲QRCode的div
(3)在js中請求生成二維碼接口
/*測試生成微信支付二維碼*/
getCode(){
CSU.http.get("/mallservice/payInfo/createPayCode/1492089528889").then(res => {
this.payObj = res.data.data;
new QRCode("QRCode", {
text: this.payObj.code_url,
width: 128,
height: 128,
colorDark : "#000000",
colorLight : "#ffffff",
correctLevel : QRCode.CorrectLevel.H
});
})
}
(4)使用定時器定時查詢訂單狀態
// 開啓定時任務,查詢付款狀態
const taskId = setInterval(() => {
CSU.http.get("/mallservice/payInfo/queryPayStatus/" + this.orderId)
.then(res => {
if(res.data.code == 20000){
// 付款成功
clearInterval(taskId);
alert("支付成功")
// 跳轉到付款成功頁
location.href = "/paysuccess.html?orderId=" + this.orderId;
} else if(res.data.code != 25000){ //code=25000說明正在支付中
// 付款失敗
clearInterval(taskId);
alert("支付失敗")
// 跳轉到付款成功頁
location.href = "/payfail.html?orderId=" + this.orderId;
}
})
}, 3000);
},
(5)完整js代碼
<script type="text/javascript">
var payVm = new Vue({
el: "#payApp",
data: {
CSU: CSU,
orderId: "1492091083720",
payObj: {}
},
created() {
// ly.verify().then(res=>{
// //已經登錄
// this.orderId = ly.getUrlParam("orderId");
// this.shouldPay = ly.getUrlParam("shouldPay");
/*測試生成微信支付二維碼*/
CSU.http.get("/mallservice/payInfo/createPayCode/1492091083720").then(res => {
this.payObj = res.data.data;
new QRCode("QRCode", {
text: this.payObj.code_url,
width: 128,
height: 128,
colorDark: "#000000",
colorLight: "#ffffff",
correctLevel: QRCode.CorrectLevel.H
});
});
// 開啓定時任務,查詢付款狀態
const taskId = setInterval(() => {
CSU.http.get("/mallservice/payInfo/queryPayStatus/" + this.orderId)
.then(res => {
if(res.data.code == 20000){
// 付款成功
clearInterval(taskId);
alert("支付成功")
// 跳轉到付款成功頁
location.href = "/paysuccess.html?orderId=" + this.orderId;
} else if(res.data.code != 25000){ //code=25000說明正在支付中
// 付款失敗
clearInterval(taskId);
alert("支付失敗")
// 跳轉到付款成功頁
location.href = "/payfail.html?orderId=" + this.orderId;
}
})
}, 3000);
},
})
</script>
附訂單處理業務流程:
1、OrderController
@RestController
@RequestMapping("/mallservice/order")
@CrossOrigin
@Api("訂單服務接口")
public class OrderController {
@Autowired
private OrderService orderService;
// @Autowired
// private PayHelper payHelper;
/**
* 創建訂單
*
*/
@PostMapping("/createOrder")
@ApiOperation(value = "創建訂單接口,返回訂單編號", notes = "創建訂單")
public R createOrder(@RequestBody Order order, HttpSession session) {
User user = (User)session.getAttribute(CONSTANT.LOGIN_USER);
String id = this.orderService.createOrder(order,user);
return R.ok().data("orderId",id).message("創建訂單成功");
}
/**
* 根據訂單編號查詢訂單
*
*/
@GetMapping("selectOrderById/{orderId}")
@ApiOperation(value = "根據訂單編號查詢訂單,返回訂單對象", notes = "查詢訂單")
public R selectOrderById(@PathVariable("orderId") String orderId) {
Order order = this.orderService.queryById(orderId);
if (order == null) {
return R.error().message("訂單號不存在");
}
return R.ok().data("order",order);
}
/**
* 分頁查詢當前用戶訂單
*/
@GetMapping("list")
@ApiOperation(value = "分頁查詢當前用戶訂單,並且可以根據訂單狀態過濾", notes = "分頁查詢當前用戶訂單")
public R queryUserOrderList(
@RequestParam(value = "page", defaultValue = "1") Integer page,
@RequestParam(value = "limit", defaultValue = "5") Integer limit,
@RequestParam(value = "status", required = false,defaultValue = "2") Integer status) {
Map<String,Object> map = this.orderService.queryUserOrderList(page, limit, status);
if(CollectionUtils.isEmpty(map)){
return R.error().message("查詢用戶訂單失敗");
}
return R.ok().data("total",map.get("total")).data("orders",map.get("rows"));
}
/**
* 更新訂單狀態
*
* @param id
* @param status
* @return
*/
@PutMapping("/updateOrderStatus/{id}/{status}")
@ApiOperation(value = "更新訂單狀態", notes = "更新訂單狀態")
public R updateStatus(@PathVariable("id") Long id, @PathVariable("status") Integer status) {
this.orderService.updateStatus(id, status);
return R.ok();
}
}
OrderServiceImpl
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
@Autowired
private ShippingService shippingService;
@Autowired
private OrderItemService orderItemService;
//創建訂單
@Override
public String createOrder(Order order, User user) {
if(order == null){
throw new XmallException(20001,"創建訂單失敗");
}
if(user == null){
throw new XmallException(20001,"用戶未登錄");
}
//創建訂單編號
String orderId = UUID.randomUUID().toString();
order.setId(orderId);
order.setUserId(user.getId());
order.setStatus(CONSTANT.ORDER_SATAUS.NOT_PAY);
//根據用戶查詢收貨地址
QueryWrapper<Shipping> wrapper = new QueryWrapper<>();
wrapper.eq("id",user.getId());
Shipping shipping = shippingService.getOne(wrapper);
order.setShippingId(shipping.getId());
//設置支付類型
order.setPaymentType(CONSTANT.PAYMENT_TYPE.ONLINE);
// //設置訂單條目
// order.setOrderItems();
//插入訂單表
int insert = baseMapper.insert(order);
if(insert ==0 ){
throw new XmallException(20001,"創建訂單失敗");
}
//order_item表中插入訂單id(批量更新)
order.getOrderItems().forEach(orderItem -> {
orderItem.setOrderId(orderId);
});
orderItemService.saveBatch(order.getOrderItems());
return orderId;
}
//根據訂單編號查詢訂單
@Override
public Order queryById(String id) {
if(StringUtils.isBlank(id)){
throw new XmallException(20001,"訂單號有誤");
}
Order order = baseMapper.selectById(id);
QueryWrapper<OrderItem> wrapper = new QueryWrapper<>();
wrapper.eq("order_id",order.getId());
List<OrderItem> orderItemList = orderItemService.list(wrapper);
order.setOrderItems(orderItemList);
return order;
}
//分頁查詢當前用戶訂單
@Override
public Map<String,Object> queryUserOrderList(Integer page, Integer limit, Integer status) {
Page<Order> pageInfo = new Page<>(page,limit);
/*構造查詢條件*/
QueryWrapper<Order> wrapper = new QueryWrapper<>();
if(status != 2){
wrapper.eq("status",status);
}else {
wrapper = null;
}
baseMapper.selectPage(pageInfo,wrapper);
List<Order> records = pageInfo.getRecords();
long total = pageInfo.getTotal();
Map<String,Object> map = new HashMap<>();
map.put("total",total);
map.put("rows",records);
return map;
}
//更新訂單狀態
@Transactional
public void updateStatus(Long id, Integer status) {
Order order = baseMapper.selectById(id);
order.setStatus(status);
// 根據狀態判斷要修改的時間
switch (status) {
case 20:
order.setPaymentTime(new Date());// 付款
break;
case 30:
order.setSendTime(new Date());// 發貨
break;
case 40:
order.setEndTime(new Date());// 確認收穫,訂單結束
break;
case 50:
order.setCloseTime(new Date());// 交易失敗,訂單關閉
break;
}
int count = baseMapper.updateById(order);
if(count == 0 ){
throw new XmallException(20001,"更新訂單狀態失敗");
}
}
}