You've already forked FrameTour-BE
微信支付、回调、订单查询;
微信用户登录、用户信息查询、修改用户信息、同意用户协议; 文件OSS上传、删除接口;
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
package com.ycwl.basic.service.impl.mobile;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ycwl.basic.config.WechatConfig;
|
||||
import com.ycwl.basic.constant.BaseContextHandler;
|
||||
import com.ycwl.basic.constant.NumberConstant;
|
||||
import com.ycwl.basic.constant.WeiXinConstant;
|
||||
import com.ycwl.basic.enums.AgreementEnum;
|
||||
import com.ycwl.basic.enums.BizCodeEnum;
|
||||
import com.ycwl.basic.enums.WechatErrorCodeEnum;
|
||||
import com.ycwl.basic.exception.AppException;
|
||||
import com.ycwl.basic.mapper.pc.MemberMapper;
|
||||
import com.ycwl.basic.model.jwt.JwtInfo;
|
||||
import com.ycwl.basic.model.mobile.DTO.WeChatUserInfoDTO;
|
||||
import com.ycwl.basic.model.mobile.DTO.WeChatUserInfoUpdateDTO;
|
||||
import com.ycwl.basic.model.pc.member.entity.MemberEntity;
|
||||
import com.ycwl.basic.model.pc.member.req.MemberReqQuery;
|
||||
import com.ycwl.basic.model.pc.member.resp.MemberRespVO;
|
||||
import com.ycwl.basic.service.HttpService;
|
||||
import com.ycwl.basic.service.mobile.AppMemberService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.BeanCopierUtils;
|
||||
import com.ycwl.basic.utils.JwtTokenUtil;
|
||||
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author:songmingsong
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class AppMemberServiceImpl implements AppMemberService {
|
||||
@Autowired
|
||||
private WechatConfig config;
|
||||
|
||||
@Autowired
|
||||
private HttpService httpService;
|
||||
|
||||
@Autowired
|
||||
private MemberMapper memberMapper;
|
||||
|
||||
@Autowired
|
||||
private JwtTokenUtil jwtTokenUtil;
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getOpenId(String code) {
|
||||
Map<String, String> paramMap = new HashMap<>(NumberConstant.FOUR);
|
||||
paramMap.put("appid", config.getMiniProgramAppId());
|
||||
paramMap.put("secret", config.getMiniProgramSecret());
|
||||
paramMap.put("js_code", code);
|
||||
paramMap.put("grant_type", config.getGrandType());
|
||||
try {
|
||||
String response = httpService.doHttpsPost(WeiXinConstant.GET_OPEN_ID, paramMap, "UTF-8");
|
||||
if (StringUtils.isBlank(response)) {
|
||||
return null;
|
||||
}
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
return mapper.readValue(response, Map.class);
|
||||
} catch (Exception e) {
|
||||
log.error("getOpenId", e);
|
||||
throw new AppException(BizCodeEnum.SERVER_INTERNAL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ApiResponse login(String code, WeChatUserInfoDTO userInfoDTO) throws Exception {
|
||||
Map<String, Object> weixinResponse = this.getOpenId(code);
|
||||
if (CollectionUtils.isEmpty(weixinResponse)) {
|
||||
throw new AppException(BizCodeEnum.SERVER_INTERNAL_ERROR);
|
||||
}
|
||||
Object errcode = weixinResponse.get("errcode");
|
||||
if (errcode != null) {
|
||||
WechatErrorCodeEnum errorCode = WechatErrorCodeEnum.getErrorCode(errcode.toString());
|
||||
throw new AppException(BizCodeEnum.PARAM_ERROR.getCode(), errorCode.getDetail());
|
||||
}
|
||||
|
||||
// 获取openId
|
||||
Object openId = weixinResponse.get("openid");
|
||||
if (openId == null) {
|
||||
log.warn("warning={}", "未获取到当前用户openId");
|
||||
throw new AppException(BizCodeEnum.SERVER_UNKONWN_ERROR, "未获取到当前用户openId");
|
||||
}
|
||||
|
||||
MemberRespVO memberRespVO = new MemberRespVO();
|
||||
JwtInfo jwtInfo = new JwtInfo();
|
||||
// 根据返回的openId,判断用户是否是新用户,是的话,将用户信息存到数据库;
|
||||
MemberReqQuery memberReqQuery = new MemberReqQuery();
|
||||
memberReqQuery.setOpenId(openId.toString());
|
||||
List<MemberRespVO> list = memberMapper.list(memberReqQuery);
|
||||
if (list.isEmpty()) {
|
||||
MemberEntity memberEntity = new MemberEntity();
|
||||
memberEntity.setId(SnowFlakeUtil.getLongId());
|
||||
BeanCopierUtils.copyProperties(userInfoDTO, memberEntity);
|
||||
memberMapper.add(memberEntity);
|
||||
BeanCopierUtils.copyProperties(memberEntity, memberRespVO);
|
||||
} else {
|
||||
BeanCopierUtils.copyProperties(list.get(NumberConstant.ZERO), memberRespVO);
|
||||
}
|
||||
jwtInfo.setUserId(memberRespVO.getId().toString());
|
||||
jwtInfo.setName(memberRespVO.getNickname());
|
||||
jwtInfo.setPhone(memberRespVO.getPhone());
|
||||
|
||||
String jwt = jwtTokenUtil.generateToken(jwtInfo);
|
||||
Map<String, Object> resMap = new HashMap<>();
|
||||
resMap.put("token", jwt);
|
||||
resMap.put("user", memberRespVO);
|
||||
|
||||
return ApiResponse.success(resMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResponse<MemberRespVO> getUserInfo() {
|
||||
MemberRespVO respVO = memberMapper.getById(Long.parseLong(BaseContextHandler.getUserId()));
|
||||
return ApiResponse.success(respVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResponse<?> update(WeChatUserInfoUpdateDTO userInfoUpdateDTO) {
|
||||
MemberEntity memberEntity = new MemberEntity();
|
||||
memberEntity.setId(Long.parseLong(BaseContextHandler.getUserId()));
|
||||
BeanCopierUtils.copyProperties(userInfoUpdateDTO, memberEntity);
|
||||
return ApiResponse.success(memberMapper.update(memberEntity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResponse<?> agreement() {
|
||||
MemberEntity memberEntity = new MemberEntity();
|
||||
memberEntity.setId(Long.parseLong(BaseContextHandler.getUserId()));
|
||||
memberEntity.setAgreement(AgreementEnum.AGREE.getType());
|
||||
return ApiResponse.success(memberMapper.update(memberEntity));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
package com.ycwl.basic.service.impl.mobile;
|
||||
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.wechat.pay.java.core.Config;
|
||||
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
|
||||
import com.wechat.pay.java.core.exception.ServiceException;
|
||||
import com.wechat.pay.java.core.notification.NotificationConfig;
|
||||
import com.wechat.pay.java.core.notification.NotificationParser;
|
||||
import com.wechat.pay.java.core.notification.RequestParam;
|
||||
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
|
||||
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.*;
|
||||
import com.wechat.pay.java.service.payments.model.TransactionAmount;
|
||||
import com.ycwl.basic.config.WechatConfig;
|
||||
import com.ycwl.basic.constant.WeiXinConstant;
|
||||
import com.ycwl.basic.enums.BizCodeEnum;
|
||||
import com.ycwl.basic.enums.OrderStateEnum;
|
||||
import com.ycwl.basic.exception.AppException;
|
||||
import com.ycwl.basic.mapper.pc.OrderMapper;
|
||||
import com.ycwl.basic.model.wxPay.WXPayOrderReqVO;
|
||||
import com.ycwl.basic.model.wxPay.WxPayRespVO;
|
||||
import com.ycwl.basic.model.wxPay.WxchatCallbackSuccessData;
|
||||
import com.ycwl.basic.service.mobile.WxPayService;
|
||||
import com.ycwl.basic.service.pc.OrderService;
|
||||
import com.ycwl.basic.utils.WXPayUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.wechat.pay.java.core.http.Constant.*;
|
||||
|
||||
/**
|
||||
* @Author: songmingsong
|
||||
* @CreateTime: 2024-12-05
|
||||
* @Description: 微信支付实现
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class WxPayServiceImpl implements WxPayService {
|
||||
|
||||
@Autowired
|
||||
private WechatConfig wechatConfig;
|
||||
@Autowired
|
||||
private OrderMapper orderMapper;
|
||||
@Autowired
|
||||
private OrderService orderService;
|
||||
|
||||
@Override
|
||||
public WxPayRespVO createOrder(WXPayOrderReqVO req) {
|
||||
try {
|
||||
// 使用自动更新平台证书的RSA配置
|
||||
// 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
|
||||
Config config =
|
||||
new RSAAutoCertificateConfig.Builder()
|
||||
.merchantId(wechatConfig.getMchId())
|
||||
.privateKeyFromPath(wechatConfig.getKeyPath())
|
||||
.merchantSerialNumber(wechatConfig.getMchSerialNo())
|
||||
.apiV3Key(wechatConfig.getApiV3())
|
||||
.build();
|
||||
// 构建service
|
||||
JsapiService service = new JsapiService.Builder().config(config).build();
|
||||
|
||||
// request.setXxx(val)设置所需参数,具体参数可见Request定义
|
||||
PrepayRequest request = new PrepayRequest();
|
||||
Amount amount = new Amount();
|
||||
amount.setTotal(req.getTotalPrice());
|
||||
request.setAmount(amount);
|
||||
request.setAppid(wechatConfig.getAppId());
|
||||
request.setMchid(wechatConfig.getMchId());
|
||||
request.setDescription(req.getGoodsName());
|
||||
request.setNotifyUrl(wechatConfig.getNotifyUrl());
|
||||
request.setOutTradeNo(req.getOrderSn().toString());
|
||||
|
||||
Payer payer = new Payer();
|
||||
payer.setOpenid(req.getOpenId());
|
||||
request.setPayer(payer);
|
||||
|
||||
// 调用下单方法,得到应答
|
||||
PrepayResponse response = service.prepay(request);
|
||||
WxPayRespVO vo = new WxPayRespVO();
|
||||
Long timeStamp = System.currentTimeMillis() / 1000;
|
||||
vo.setTimeStamp(timeStamp);
|
||||
String substring = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
|
||||
vo.setNonceStr(substring);
|
||||
String signatureStr = Stream.of(wechatConfig.getAppId(), String.valueOf(timeStamp), substring, "prepay_id=" + response.getPrepayId())
|
||||
.collect(Collectors.joining("\n", "", "\n"));
|
||||
String sign = WXPayUtil.getSign(signatureStr, wechatConfig.getKeyPath());
|
||||
vo.setPaySign(sign);
|
||||
vo.setPrepayId("prepay_id=" + response.getPrepayId());
|
||||
return vo;
|
||||
} catch (ServiceException e) {
|
||||
JSONObject parse = JSONObject.parseObject(e.getResponseBody());
|
||||
throw new AppException(BizCodeEnum.ADVANCE_PAYMENT_FAILED, parse.getString("message"));
|
||||
} catch (Exception e) {
|
||||
throw new AppException(BizCodeEnum.ADVANCE_PAYMENT_FAILED, e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void payNotify(HttpServletRequest request) {
|
||||
try {
|
||||
// 读取请求体的信息
|
||||
ServletInputStream inputStream = request.getInputStream();
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
String s;
|
||||
// 读取回调请求体
|
||||
while ((s = bufferedReader.readLine()) != null) {
|
||||
stringBuffer.append(s);
|
||||
}
|
||||
String s1 = stringBuffer.toString();
|
||||
String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);
|
||||
String nonce = request.getHeader(WECHAT_PAY_NONCE);
|
||||
String signType = request.getHeader(WeiXinConstant.WECHATPAY_SIGNATURE_TYPE);
|
||||
String serialNo = request.getHeader(WECHAT_PAY_SERIAL);
|
||||
String signature = request.getHeader(WECHAT_PAY_SIGNATURE);
|
||||
|
||||
NotificationConfig config = new RSAAutoCertificateConfig.Builder()
|
||||
.merchantId(wechatConfig.getMchId())
|
||||
.privateKeyFromPath(wechatConfig.getKeyPath())
|
||||
.merchantSerialNumber(wechatConfig.getMchSerialNo())
|
||||
.apiV3Key(wechatConfig.getApiV3())
|
||||
.build();
|
||||
// 初始化 NotificationParser
|
||||
NotificationParser parser = new NotificationParser(config);
|
||||
RequestParam requestParam = new RequestParam.Builder()
|
||||
.serialNumber(serialNo)
|
||||
.nonce(nonce)
|
||||
.signature(signature)
|
||||
.timestamp(timestamp)
|
||||
// 若未设置signType,默认值为 WECHATPAY2-SHA256-RSA2048
|
||||
.signType(signType)
|
||||
.body(s1)
|
||||
.build();
|
||||
Transaction parse = parser.parse(requestParam, Transaction.class);
|
||||
log.info("[微信支付]parse = {}", parse);
|
||||
|
||||
// 更新订单信息
|
||||
new Thread(() -> {
|
||||
Transaction.TradeStateEnum tradeState = parse.getTradeState();
|
||||
OrderStateEnum OrderStateEnum = null;
|
||||
if (Transaction.TradeStateEnum.SUCCESS == tradeState) {
|
||||
OrderStateEnum = OrderStateEnum.PAID;
|
||||
}
|
||||
if (Objects.nonNull(OrderStateEnum)) {
|
||||
orderService.updateOrderState(Long.parseLong(parse.getOutTradeNo()), OrderStateEnum, null);
|
||||
}
|
||||
}).start();
|
||||
} catch (Exception e) {
|
||||
throw new AppException(BizCodeEnum.ADVANCE_PAYMENT_CALLBACK_FAILED, e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxchatCallbackSuccessData queryPay(Long orderId) {
|
||||
WxchatCallbackSuccessData wxchatCallbackSuccessData = new WxchatCallbackSuccessData();
|
||||
QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
|
||||
queryRequest.setMchid(wechatConfig.getMchId());
|
||||
queryRequest.setOutTradeNo(orderId.toString());
|
||||
// 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
|
||||
Config config =
|
||||
new RSAAutoCertificateConfig.Builder()
|
||||
.merchantId(wechatConfig.getMchId())
|
||||
.privateKeyFromPath(wechatConfig.getKeyPath())
|
||||
.merchantSerialNumber(wechatConfig.getMchSerialNo())
|
||||
.apiV3Key(wechatConfig.getApiV3())
|
||||
.build();
|
||||
// 构建service
|
||||
JsapiService service = new JsapiService.Builder().config(config).build();
|
||||
try {
|
||||
com.wechat.pay.java.service.payments.model.Transaction transaction = service.queryOrderByOutTradeNo(queryRequest);
|
||||
String successTime = transaction.getSuccessTime();
|
||||
|
||||
|
||||
wxchatCallbackSuccessData.setOrderId(orderId.toString());
|
||||
wxchatCallbackSuccessData.setSuccessTime(successTime);
|
||||
wxchatCallbackSuccessData.setTradetype(WeiXinConstant.getDescriptionType(transaction.getTradeType()));
|
||||
wxchatCallbackSuccessData.setTradestate(WeiXinConstant.getDescriptionState(transaction.getTradeState()));
|
||||
TransactionAmount amount = transaction.getAmount();
|
||||
Integer total = amount.getTotal();
|
||||
wxchatCallbackSuccessData.setTotalMoney(new BigDecimal(total).movePointLeft(2));
|
||||
} catch (ServiceException e) {
|
||||
// API返回失败, 例如ORDER_NOT_EXISTS
|
||||
log.error("code={}, message={}", e.getErrorCode(), e.getErrorMessage());
|
||||
log.error("reponse body={}", e.getResponseBody());
|
||||
}
|
||||
return wxchatCallbackSuccessData;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package com.ycwl.basic.service.impl.pc;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ycwl.basic.constant.NumberConstant;
|
||||
import com.ycwl.basic.enums.OrderStateEnum;
|
||||
import com.ycwl.basic.mapper.pc.OrderMapper;
|
||||
import com.ycwl.basic.model.pc.order.entity.OrderItemEntity;
|
||||
import com.ycwl.basic.model.pc.order.req.OrderAddOrUpdateReq;
|
||||
@@ -18,6 +20,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -82,4 +85,28 @@ public class OrderServiceImpl implements OrderService {
|
||||
}
|
||||
return ApiResponse.success(update);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新订单支付状态
|
||||
*
|
||||
* @param orderSn 订单编号也就是订单的ID
|
||||
*/
|
||||
@Override
|
||||
public void updateOrderState(Long orderSn, OrderStateEnum orderStateEnum, String refundReason) {
|
||||
OrderAddOrUpdateReq orderAddOrUpdateReq = new OrderAddOrUpdateReq();
|
||||
orderAddOrUpdateReq.setId(orderSn);
|
||||
if (orderStateEnum.getType() == NumberConstant.ONE) {
|
||||
orderAddOrUpdateReq.setRefundStatus(orderStateEnum.getState());
|
||||
orderAddOrUpdateReq.setRefundAt(new Date());
|
||||
orderAddOrUpdateReq.setRefundReason(refundReason);
|
||||
} else if (orderStateEnum.getType() == NumberConstant.TWO) {
|
||||
int state = orderStateEnum.getState();
|
||||
orderAddOrUpdateReq.setPayAt(new Date());
|
||||
orderAddOrUpdateReq.setStatus(orderStateEnum.getState());
|
||||
if (state == OrderStateEnum.CANCELED.getState()) {
|
||||
orderAddOrUpdateReq.setCancelAt(new Date());
|
||||
}
|
||||
}
|
||||
orderMapper.update(orderAddOrUpdateReq);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user