文档地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1
封装的工具类
package com.qf.fmall.utils;import cn.hutool.core.util.XmlUtil;
import cn.hutool.http.HttpRequest;
import org.apache.shiro.crypto.hash.Md5Hash;import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;public class WeixinPayUtils {public static final String orderSubmit="https://api.mch.weixin.qq.com/pay/unifiedorder";public static final String orderQueryUrl="https://api.mch.weixin.qq.com/pay/orderquery";public static final String appkey="sbNCm1JnevqI36LrEaxFwcaT0hkGxFnC";public static void main(String[] args) {String s = weixinPay("sadsadasa", "wqeqweqeq");System.out.println(s);}public static String weixinPay(String oid,String describe){//1. 组织请求map,必传字段如下//这里可有序可以无序,但是计算签名的时候必须有序,规定!按Key排序TreeMap<String, String> treeMap = new TreeMap<>();treeMap.put("appid","wx632c8f211f8122c6");//商户的应用IDtreeMap.put("mch_id","1497984412"); //商户号treeMap.put("notify_url","http://47.118.45.73:8080/pay/callback"); // 商户提供的回调地址String randomstr = UUID.randomUUID().toString().replaceAll("-", ""); //生成随机数treeMap.put("nonce_str",randomstr); // 长度32个字符的随机字符串,干扰项treeMap.put("body",describe); // 订单描述信息treeMap.put("out_trade_no",oid); // 订单编号treeMap.put("total_fee","1"); // 1 分钱treeMap.put("trade_type","NATIVE"); // 支付类型treeMap.put("fee_type","CNY"); // 币种treeMap.put("sign_type","MD5"); // 签名算法//计算签名String tempString = treeMap.toString().replace("{", "").replace("}", "").replace(", ","&")+"&key="+appkey;String sign = new Md5Hash(tempString).toHex().toUpperCase();treeMap.put("sign",sign);//map转XML字符串String xml = XmlUtil.mapToXmlStr(treeMap);//用Hutool工具类发送post请求String result = HttpRequest.post(orderSubmit).body(xml).execute().body();// xml str ----> mapMap<String, Object> resultMap = XmlUtil.xmlToMap(result);String url = (String) resultMap.get("code_url");return url;}public static String queryStatus(String orderId) {//1. 组织请求map,必传字段如下//这里可有序可以无序,但是计算签名的时候必须有序,规定!按Key排序TreeMap<String, String> treeMap = new TreeMap<>();treeMap.put("appid","wx632c8f211f8122c6");//商户的应用IDtreeMap.put("mch_id","1497984412"); //商户号String randomstr = UUID.randomUUID().toString().replaceAll("-", ""); //生成随机数treeMap.put("nonce_str",randomstr); // 长度32个字符的随机字符串,干扰项treeMap.put("out_trade_no",orderId); // 订单编号treeMap.put("sign_type","MD5"); // 签名算法//计算签名String tempString = treeMap.toString().replace("{", "").replace("}", "").replace(", ","&")+"&key="+appkey;String sign = new Md5Hash(tempString).toHex().toUpperCase();treeMap.put("sign",sign);//map转XML字符串String xml = XmlUtil.mapToXmlStr(treeMap);//用Hutool工具类发送post请求String result = HttpRequest.post(orderQueryUrl).body(xml).execute().body();// xml str ----> mapMap<String, Object> resultMap = XmlUtil.xmlToMap(result);String trade_state = (String) resultMap.get("trade_state");return trade_state;}
}
controller
package com.qf.fmall.controller;import com.qf.fmall.common.ResultVo;
import com.qf.fmall.entity.Orders;
import com.qf.fmall.service.IOrdersService;
import com.qf.fmall.utils.FmallConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.Arrays;
import java.util.HashMap;/*** <p>* 订单 前端控制器* </p>** @author jmj* @since 2023-08-24*/
@RestController
@RequestMapping("/order")
@CrossOrigin
@Slf4j
public class OrdersController {@Autowiredprivate IOrdersService ordersService;@PostMapping("/add")public ResultVo add(Integer[] cids,@RequestBody Orders orders) throws Exception {log.info("入参为:cid={},orders={}", Arrays.toString(cids),orders);HashMap<String,Object> map= ordersService.addOrder(cids,orders);return ResultVo.vo(FmallConstants.SUCCESS_CODE,FmallConstants.SUCCESS_MSG,map);}@GetMapping("/status/{orderId}")public ResultVo status(@PathVariable("orderId") String orderId){log.info("入参为:orderId={}",orderId);String s= ordersService.status(orderId);log.info("传回来的状态:{}",s);return ResultVo.vo(FmallConstants.SUCCESS_CODE,FmallConstants.SUCCESS_MSG,s);}}
service
package com.qf.fmall.service.impl;import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qf.fmall.entity.*;
import com.qf.fmall.mapper.OrdersMapper;
import com.qf.fmall.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qf.fmall.utils.WeixinPayUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;/*** <p>* 订单 服务实现类* </p>** @author jmj* @since 2023-08-24*/
@Service
@Slf4j
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements IOrdersService {@Autowiredprivate IShoppingCartService shoppingCartService;@Autowiredprivate IProductSkuService iProductSkuService;@Autowiredprivate IProductService iProductService;@Autowiredprivate IOrderItemService iOrderItemService;@Transactional(rollbackFor = Exception.class)@Overridepublic synchronized HashMap<String, Object> addOrder(Integer[] cids, Orders orders) throws Exception {//1. 查询用户购物车中的对应的商品套餐库存量是否还足够List<Map<String, Object>> shoppingcars = shoppingCartService.listMaps(new QueryWrapper<ShoppingCart>().select("sku_id skuId, SUM(`cart_num`) `sum`").in("cart_id", cids).groupBy("sku_id"));log.info("查出来的购物车按ID分类计算的集合为{}",shoppingcars);TreeSet<String> productIds = new TreeSet<>();//查出购物车中所有的productIdfor (Map<String, Object> shoppingcar : shoppingcars) {ProductSku one = iProductSkuService.getOne(new QueryWrapper<ProductSku>().eq("sku_id", shoppingcar.get("skuId")));productIds.add(one.getProductId());Integer stock = one.getStock();Double cartNum = (Double) shoppingcar.get("sum");if (cartNum>stock){throw new Exception("库存不足,购买失败");}
// 减少库存one.setStock((stock-cartNum.intValue()));iProductSkuService.updateById(one);}//过了这个循环没有抛异常,就可以往下走,说明库存够//2. 生成唯一的订单编号String orderId = UUID.randomUUID().toString().replace("-", "");orders.setOrderId(orderId);//3. 生成订单主表(orders表)中的数据orders.setCreateTime(new Date());//创建时间orders.setUpdateTime(new Date());//修改时间// 产品名称:untitled用逗号隔开//先查Product产品IDStringBuilder builder = new StringBuilder();for (String productId : productIds) {//查出每个产品中的名字,放到字符串缓冲流中,并用逗号拼接builder.append(iProductService.getOne(new QueryWrapper<Product>().eq("product_id",productId)).getProductName());builder.append(",");}//删除最后一个逗号,拼接转化为字符串String untitled = builder.deleteCharAt(builder.length() - 1).toString();orders.setUntitled(untitled);// 订单的状态,初始值1,待付款 statusorders.setStatus("1");//待付款// 逻辑删除状态,初始值为0 delete_statusorders.setDeleteStatus(0);log.info("生成的order对象为:{}",orders);//将对象添加到订单表里this.save(orders);//4. 生成订单明细表的数据 (OrderItem表)//有几个cid就有几个定单ArrayList<OrderItem> orderItems = new ArrayList<>();for (Integer cartId : cids) {OrderItem orderItem = new OrderItem();String orderItemId = UUID.randomUUID().toString().replace("-", "");//设置32位随机数作为ItemId 放入orderItem对象里orderItem.setItemId(orderItemId);//订单Id注入orderItem.setOrderId(orders.getOrderId());//查一下购物车 idShoppingCart shoppingCart = shoppingCartService.getOne(new QueryWrapper<ShoppingCart>().eq("cart_id", cartId));ProductSku productSku = iProductSkuService.getOne(new QueryWrapper<ProductSku>().eq("sku_id", shoppingCart.getSkuId()));Product product = iProductService.getOne(new QueryWrapper<Product>().eq("product_id", productSku.getProductId()));//查一下产品对象//注入产品IDorderItem.setProductId(productSku.getProductId());orderItem.setProductName(product.getProductName());orderItem.setProductImg(productSku.getSkuImg());orderItem.setSkuId(productSku.getSkuId());orderItem.setSkuName(productSku.getSkuName());orderItem.setProductPrice(new BigDecimal(productSku.getSellPrice()));orderItem.setBuyCounts(Integer.parseInt(shoppingCart.getCartNum()));orderItem.setTotalAmount(new BigDecimal(productSku.getSellPrice()*Integer.parseInt(shoppingCart.getCartNum())));//转换时间SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");orderItem.setBasketDate(format.parse(shoppingCart.getCartTime()));orderItem.setIsComment(0);log.info("每个订单详情对象:{}",orderItem);//保存到集合orderItems.add(orderItem);}//5. 保存订单到数据库log.info("添加到数据库的订单集合对象:{}",orderItems);iOrderItemService.saveBatch(orderItems);//清空购物车List<Integer> list = Arrays.asList(cids);shoppingCartService.removeBatchByIds(list);//6. 跟微信支付平台交互,获取可以支付的urlString url = WeixinPayUtils.weixinPay(orders.getOrderId(),orders.getUntitled());log.info("url:{}",url);//7. 组织返回的map数据HashMap<String, Object> map = new HashMap<>();map.put("orderId",orders.getOrderId());map.put("productNames",orders.getUntitled());map.put("payUrl",url);return map;}@Overridepublic String status(String orderId) {//1.掉微信支付的查询订单状态接口,获取订单状态String status= WeixinPayUtils.queryStatus(orderId);//2.如果支付成功了,需要修改订单表中的订单状态和支付时间if (status.equals("SUCCESS")){Orders orders = new Orders();orders.setOrderId(orderId);orders.setStatus("2");updateById(orders);return "2";}return "-1";}}
封装工具类
pom
<!-- 微信支付 sdk (sdk用来简化调用的工具包) --><dependency><groupId>com.github.wxpay</groupId><artifactId>wxpay-sdk</artifactId><version>0.0.3</version></dependency></dependencies>
WxSdkUtils
package com.qf.fmall2302.wxpay;import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConfig;import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;public class WxSdkUtils {public String getPayUrl(String orderid,String desc,Long amount) throws Exception {// 创建sdk的核心对象WXPay wxPay = new WXPay(new MyWxConfig());HashMap<String, String> map = new HashMap<>();String randomstr = UUID.randomUUID().toString().replaceAll("-", "");map.put("nonce_str",randomstr); // 长度32个字符的随机字符串,干扰项map.put("body",desc); // 订单描述信息map.put("out_trade_no",orderid); // 订单编号map.put("total_fee","1"); // 1 分钱map.put("trade_type","NATIVE"); // 支付类型map.put("fee_type","CNY"); // 币种map.put("notify_url","http://47.118.45.73:8080/pay/callback"); // 商户提供的回调地址map.put("sign_type","MD5"); // 签名算法Map<String, String> result = wxPay.unifiedOrder(map);return result.get("code_url");}public static String queryStatus(String orderid) throws Exception {WXPay wxPay = new WXPay(new MyWxConfig());HashMap<String, String> map = new HashMap<>();map.put("out_trade_no",orderid);Map<String, String> result = wxPay.orderQuery(map);return result.get("trade_state");}public static void main(String[] args) throws Exception {String orderid = "202308241617987";WXPay wxPay = new WXPay(new MyWxConfig());HashMap<String, String> map = new HashMap<>();map.put("out_trade_no",orderid);Map<String, String> result = wxPay.orderQuery(map);System.out.println(result);}}
MyWxConfig implements WXPayConfig
package com.qf.fmall2302.wxpay;import com.github.wxpay.sdk.WXPayConfig;import java.io.InputStream;public class MyWxConfig implements WXPayConfig {public static final String appid = "wx632c8f211f8122c6";public static final String mch_id = "1497984412";public static final String appkey = "sbNCm1JnevqI36LrEaxFwcaT0hkGxFnC";@Overridepublic String getAppID() {return appid;}@Overridepublic String getMchID() {return mch_id;}@Overridepublic String getKey() {return appkey;}@Overridepublic InputStream getCertStream() {return null;}@Overridepublic int getHttpConnectTimeoutMs() {return 0;}@Overridepublic int getHttpReadTimeoutMs() {return 0;}
}