From 49148072078220c92f94f2e7ea25cd79a6810fc7 Mon Sep 17 00:00:00 2001 From: zhibing.pu <393733352@qq.com> Date: 星期六, 24 八月 2024 15:31:37 +0800 Subject: [PATCH] 封装支付宝支付和完善充电支付功能 --- ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java | 49 + ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/vo/AliPaymentReq.java | 51 ++ ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/config/SignType.java | 39 + ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/factory/WxPaymentFallbackFactory.java | 4 ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/wx/config/WxConfig.java | 1 ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/config/AliProperties.java | 54 ++ ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/vo/AliPaymentResp.java | 24 + ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/RefundResp.java | 27 + ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/controller/WxPayController.java | 2 ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/wx/model/WeixinProperties.java | 2 ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TChargingOrderController.java | 25 ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/PaymentResp.java | 30 + ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/QueryResp.java | 48 ++ ruoyi-service/ruoyi-payment/pom.xml | 6 ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/AppletPayUtil.java | 228 +++++++++ ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/QueryRefundReq.java | 19 ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/controller/AliPayController.java | 86 +++ ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/QueryRefundResp.java | 43 + ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/factory/AliPaymentFallbackFactory.java | 45 + ruoyi-api/ruoyi-api-payment/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports | 3 ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/RefundReq.java | 27 + ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/vo/AliQueryOrder.java | 48 ++ ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/PaymentReq.java | 52 ++ ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java | 396 ++++++++-------- ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/feignClient/AliPaymentClient.java | 43 + 25 files changed, 1,123 insertions(+), 229 deletions(-) diff --git a/ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/factory/AliPaymentFallbackFactory.java b/ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/factory/AliPaymentFallbackFactory.java new file mode 100644 index 0000000..a552827 --- /dev/null +++ b/ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/factory/AliPaymentFallbackFactory.java @@ -0,0 +1,45 @@ +package com.ruoyi.payment.api.factory; + +import com.ruoyi.common.core.domain.R; +import com.ruoyi.payment.api.feignClient.AliPaymentClient; +import com.ruoyi.payment.api.vo.AliPaymentReq; +import com.ruoyi.payment.api.vo.AliPaymentResp; +import com.ruoyi.payment.api.vo.AliQueryOrder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.openfeign.FallbackFactory; +import org.springframework.stereotype.Component; + + +/** + * 充电订单服务降级处理 + * + * @author ruoyi + */ +@Component +public class AliPaymentFallbackFactory implements FallbackFactory<AliPaymentClient> +{ + private static final Logger log = LoggerFactory.getLogger(AliPaymentFallbackFactory.class); + + @Override + public AliPaymentClient create(Throwable throwable) { + log.error("支付宝支付调用失败:{}", throwable.getMessage()); + return new AliPaymentClient() { + + @Override + public R<AliPaymentResp> payment(AliPaymentReq req) { + throw new RuntimeException("调起支付宝小程序支付失败:" + throwable.getMessage()); + } + + @Override + public R<AliQueryOrder> query(String outTradeNo) { + throw new RuntimeException("查询支付订单失败:" + throwable.getMessage()); + } + + @Override + public void close(String outTradeNo) { + throw new RuntimeException("关闭支付订单失败:" + throwable.getMessage()); + } + }; + } +} diff --git a/ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/factory/WxPaymentFallbackFactory.java b/ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/factory/WxPaymentFallbackFactory.java index 6761b58..0938408 100644 --- a/ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/factory/WxPaymentFallbackFactory.java +++ b/ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/factory/WxPaymentFallbackFactory.java @@ -29,7 +29,7 @@ @Override public R<NotifyV3PayDecodeRespBody> queryOrderInfo(String orderId) { - return R.fail("查询支付订单信息失败:" + throwable.getMessage()); + throw new RuntimeException("查询支付订单信息失败:" + throwable.getMessage()); } @Override @@ -49,7 +49,7 @@ @Override public void close(String outTradeNo) { - + throw new RuntimeException("关闭支付订单失败:" + throwable.getMessage()); } }; } diff --git a/ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/feignClient/AliPaymentClient.java b/ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/feignClient/AliPaymentClient.java new file mode 100644 index 0000000..91e5014 --- /dev/null +++ b/ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/feignClient/AliPaymentClient.java @@ -0,0 +1,43 @@ +package com.ruoyi.payment.api.feignClient; + +import com.ruoyi.common.core.constant.ServiceNameConstants; +import com.ruoyi.common.core.domain.R; +import com.ruoyi.payment.api.factory.WxPaymentFallbackFactory; +import com.ruoyi.payment.api.vo.AliPaymentReq; +import com.ruoyi.payment.api.vo.AliPaymentResp; +import com.ruoyi.payment.api.vo.AliQueryOrder; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; + +/** + * @author zhibing.pu + * @Date 2024/8/24 14:39 + */ +@FeignClient(contextId = "AliPaymentClient", value = ServiceNameConstants.PAYMENT_SERVICE, fallbackFactory = WxPaymentFallbackFactory.class) +public interface AliPaymentClient { + + + /** + * 调起支付宝小程序支付 + * @param req + * @return + */ + @PostMapping("/ali/payment") + R<AliPaymentResp> payment(AliPaymentReq req); + + + /** + * 查询支付订单 + * @param outTradeNo + * @return + */ + @PostMapping("/ali/query") + R<AliQueryOrder> query(String outTradeNo); + + /** + * 关闭订单 + * @param outTradeNo + */ + @PostMapping("/ali/close") + void close(String outTradeNo); +} diff --git a/ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/vo/AliPaymentReq.java b/ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/vo/AliPaymentReq.java new file mode 100644 index 0000000..f2f0858 --- /dev/null +++ b/ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/vo/AliPaymentReq.java @@ -0,0 +1,51 @@ +package com.ruoyi.payment.api.vo; + +import lombok.Data; + + +/** + * @author zhibing.pu + * @Date 2024/8/23 16:52 + */ +@Data +public class AliPaymentReq { + /** + * 业务流水号 + */ + private String outTradeNo; + /** + * 支付总金额 + */ + private String totalAmount; + /** + * 订单标题 + */ + private String subject; + /** + * 支付用户支付宝openid + */ + private String buyerOpenId; + /** + * 订单附加信息 + */ + private String body; + /** + * 订单超时时间 + * 订单相对超时时间。从交易创建时间开始计算。 + * 该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 该参数数值不接受小数点, 如 1.5h,可转换为 90m。 + * 当面付场景默认值为3h + */ + private String timeoutExpress; + /** + * 回传参数 + * 如果请求时传递了该参数,支付宝会在异步通知时将该参数原样返回。 + */ + private String passbackParams; + /** + * 初始化默认数据 + */ + public AliPaymentReq() { + //订单超时默认30分钟 + this.timeoutExpress = "30m"; + } +} diff --git a/ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/vo/AliPaymentResp.java b/ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/vo/AliPaymentResp.java new file mode 100644 index 0000000..273a5fc --- /dev/null +++ b/ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/vo/AliPaymentResp.java @@ -0,0 +1,24 @@ +package com.ruoyi.payment.api.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author zhibing.pu + * @Date 2024/8/24 15:09 + */ +@Data +@ApiModel +public class AliPaymentResp { + /** + * 支付单号 + */ + @ApiModelProperty("支付单号") + private String tradeNo; + /** + * 回调通知地址 + */ + @ApiModelProperty("回调通知地址") + private String notifyUrl; +} diff --git a/ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/vo/AliQueryOrder.java b/ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/vo/AliQueryOrder.java new file mode 100644 index 0000000..67a8c23 --- /dev/null +++ b/ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/vo/AliQueryOrder.java @@ -0,0 +1,48 @@ +package com.ruoyi.payment.api.vo; + +import com.fasterxml.jackson.annotation.JsonSetter; +import lombok.Data; + +/** + * @author zhibing.pu + * @Date 2024/8/24 12:01 + */ +@Data +public class AliQueryOrder { + /** + * 支付宝交易号 + */ + @JsonSetter("trade_no") + private String tradeNo; + /** + * 业务流水号 + */ + @JsonSetter("out_trade_no") + private String outTradeNo; + /** + * 交易状态 + * WAIT_BUYER_PAY(交易创建,等待买家付款)、TRADE_CLOSED(未付款交易超时关闭,或支付完成后全额退款)、TRADE_SUCCESS(交易支付成功)、TRADE_FINISHED(交易结束,不可退款) + */ + @JsonSetter("trade_status") + private String tradeStatus; + /** + * 交易订单金额 + */ + @JsonSetter("total_amount") + private Double totalAmount; + /** + * 回传参数 + */ + @JsonSetter("passback_params") + private String passbackParams; + /** + * 订单标题 + */ + @JsonSetter("subject") + private String subject; + /** + * 订单描述 + */ + @JsonSetter("body") + private String body; +} diff --git a/ruoyi-api/ruoyi-api-payment/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-api/ruoyi-api-payment/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index fe686fc..ecbf4d6 100644 --- a/ruoyi-api/ruoyi-api-payment/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/ruoyi-api/ruoyi-api-payment/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1 +1,2 @@ -com.ruoyi.payment.api.factory.WxPaymentFallbackFactory \ No newline at end of file +com.ruoyi.payment.api.factory.WxPaymentFallbackFactory +com.ruoyi.payment.api.factory.AliPaymentFallbackFactory \ No newline at end of file diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java index 2cdbed5..4cce577 100644 --- a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java @@ -22,210 +22,200 @@ /** * token验证处理 - * + * * @author ruoyi */ @Component -public class TokenService -{ - @Autowired - private RedisService redisService; - - protected static final long MILLIS_SECOND = 1000; - - protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND; - - private final static long expireTime = CacheConstants.EXPIRATION; - private final static long expireAppletTime = CacheConstants.EXPIRATION_APPLET; - - private final static String ACCESS_TOKEN = CacheConstants.LOGIN_TOKEN_KEY; - - private final static Long MILLIS_MINUTE_TEN = CacheConstants.REFRESH_TIME * MILLIS_MINUTE; - - /** - * 创建令牌 - */ - public Map<String, Object> createToken(LoginUser loginUser) - { - String token = IdUtils.fastUUID(); - Long userId = loginUser.getSysUser().getUserId(); - String userName = loginUser.getSysUser().getUserName(); - loginUser.setToken(token); - loginUser.setUserid(userId); - loginUser.setUsername(userName); - loginUser.setIpaddr(IpUtils.getIpAddr()); - refreshToken(loginUser); - - // Jwt存储信息 - Map<String, Object> claimsMap = new HashMap<String, Object>(); - claimsMap.put(SecurityConstants.USER_KEY, token); - claimsMap.put(SecurityConstants.DETAILS_USER_ID, userId); - claimsMap.put(SecurityConstants.USER_TYPE, "system"); - claimsMap.put(SecurityConstants.DETAILS_USERNAME, userName); - - // 接口返回信息 - Map<String, Object> rspMap = new HashMap<String, Object>(); - rspMap.put("access_token", JwtUtils.createToken(claimsMap)); - rspMap.put("expires_in", expireTime); - return rspMap; - } - /** - * 创建小程序令牌 - */ - public Map<String, Object> createTokenApplet(LoginUserApplet loginUser) { - String token = IdUtils.fastUUID(); - Long userId = loginUser.getUserId(); - String name = loginUser.getName(); - loginUser.setToken(token); - loginUser.setIpaddr(IpUtils.getIpAddr()); - refreshToken1(loginUser); - // Jwt存储信息 - Map<String, Object> claimsMap = new HashMap<String, Object>(); - claimsMap.put(SecurityConstants.USER_APPLET_KEY, token); - claimsMap.put(SecurityConstants.DETAILS_USER_ID, userId); - claimsMap.put(SecurityConstants.USER_TYPE, "applet"); - claimsMap.put(SecurityConstants.DETAILS_USERNAME, name); - // 接口返回信息 - Map<String, Object> rspMap = new HashMap<String, Object>(); - rspMap.put("access_token", JwtUtils.createToken(claimsMap)); - rspMap.put("expires_in", expireAppletTime); - return rspMap; - } - public LoginUserApplet getLoginUserApplet() { - LoginUserApplet loginUserAppletToken = getLoginUserAppletToken(ServletUtils.getRequest()); - if (loginUserAppletToken == null){ - throw new UserAppletException("登录失效,请重新登录!", 401); - } - return loginUserAppletToken; - } - public LoginUserApplet getLoginUserAppletToken(HttpServletRequest request) { - // 获取请求携带的令牌 - String token = SecurityUtils.getToken(request); - return getLoginUserApplet(token); - } - /** - * 小程序 获取用户身份信息 - * - * @return 用户信息 - */ - public LoginUserApplet getLoginUserApplet(String token) { - LoginUserApplet user = null; - try { - if (StringUtils.isNotEmpty(token)) { - String userKey = JwtUtils.getUserKeyApplet(token); - user = redisService.getCacheObject(getTokenKey(userKey)); - return user; - } - } catch (Exception e) { - e.printStackTrace(); - } - return user; - } - /** - * 获取用户身份信息 - * - * @return 用户信息 - */ - public LoginUser getLoginUser() - { - return getLoginUser(ServletUtils.getRequest()); - } - - /** - * 获取用户身份信息 - * - * @return 用户信息 - */ - public LoginUser getLoginUser(HttpServletRequest request) - { - // 获取请求携带的令牌 - String token = SecurityUtils.getToken(request); - return getLoginUser(token); - } - - /** - * 获取用户身份信息 - * - * @return 用户信息 - */ - public LoginUser getLoginUser(String token) - { - LoginUser user = null; - try - { - if (StringUtils.isNotEmpty(token)) - { - String userkey = JwtUtils.getUserKey(token); - user = redisService.getCacheObject(getTokenKey(userkey)); - return user; - } - } - catch (Exception e) - { - } - return user; - } - - /** - * 设置用户身份信息 - */ - public void setLoginUser(LoginUser loginUser) - { - if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken())) - { - refreshToken(loginUser); - } - } - - /** - * 删除用户缓存信息 - */ - public void delLoginUser(String token) - { - if (StringUtils.isNotEmpty(token)) - { - String userkey = JwtUtils.getUserKey(token); - redisService.deleteObject(getTokenKey(userkey)); - } - } - - /** - * 验证令牌有效期,相差不足120分钟,自动刷新缓存 - * - * @param loginUser - */ - public void verifyToken(LoginUser loginUser) - { - long expireTime = loginUser.getExpireTime(); - long currentTime = System.currentTimeMillis(); - if (expireTime - currentTime <= MILLIS_MINUTE_TEN) - { - refreshToken(loginUser); - } - } - - /** - * 刷新令牌有效期 - * - * @param loginUser 登录信息 - */ - public void refreshToken(LoginUser loginUser) - { - loginUser.setLoginTime(System.currentTimeMillis()); - loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE); - // 根据uuid将loginUser缓存 - String userKey = getTokenKey(loginUser.getToken()); - redisService.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES); - } - public void refreshToken1(LoginUserApplet dto) { - dto.setLoginTime(System.currentTimeMillis()); - dto.setExpireTime(dto.getLoginTime() + expireTime * MILLIS_MINUTE); - // 根据uuid将loginUser缓存 - String userKey = getTokenKey(dto.getToken()); - redisService.setCacheObject(userKey, dto, expireTime, TimeUnit.MINUTES); - } - private String getTokenKey(String token) - { - return ACCESS_TOKEN + token; - } +public class TokenService { + @Autowired + private RedisService redisService; + + protected static final long MILLIS_SECOND = 1000; + + protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND; + + private final static long expireTime = CacheConstants.EXPIRATION; + private final static long expireAppletTime = CacheConstants.EXPIRATION_APPLET; + + private final static String ACCESS_TOKEN = CacheConstants.LOGIN_TOKEN_KEY; + + private final static Long MILLIS_MINUTE_TEN = CacheConstants.REFRESH_TIME * MILLIS_MINUTE; + + /** + * 创建令牌 + */ + public Map<String, Object> createToken(LoginUser loginUser) { + String token = IdUtils.fastUUID(); + Long userId = loginUser.getSysUser().getUserId(); + String userName = loginUser.getSysUser().getUserName(); + loginUser.setToken(token); + loginUser.setUserid(userId); + loginUser.setUsername(userName); + loginUser.setIpaddr(IpUtils.getIpAddr()); + refreshToken(loginUser); + + // Jwt存储信息 + Map<String, Object> claimsMap = new HashMap<String, Object>(); + claimsMap.put(SecurityConstants.USER_KEY, token); + claimsMap.put(SecurityConstants.DETAILS_USER_ID, userId); + claimsMap.put(SecurityConstants.USER_TYPE, "system"); + claimsMap.put(SecurityConstants.DETAILS_USERNAME, userName); + + // 接口返回信息 + Map<String, Object> rspMap = new HashMap<String, Object>(); + rspMap.put("access_token", JwtUtils.createToken(claimsMap)); + rspMap.put("expires_in", expireTime); + return rspMap; + } + + /** + * 创建小程序令牌 + */ + public Map<String, Object> createTokenApplet(LoginUserApplet loginUser) { + String token = IdUtils.fastUUID(); + Long userId = loginUser.getUserId(); + String name = loginUser.getName(); + loginUser.setToken(token); + loginUser.setIpaddr(IpUtils.getIpAddr()); + refreshToken1(loginUser); + // Jwt存储信息 + Map<String, Object> claimsMap = new HashMap<String, Object>(); + claimsMap.put(SecurityConstants.USER_APPLET_KEY, token); + claimsMap.put(SecurityConstants.DETAILS_USER_ID, userId); + claimsMap.put(SecurityConstants.USER_TYPE, "applet"); + claimsMap.put(SecurityConstants.DETAILS_USERNAME, name); + // 接口返回信息 + Map<String, Object> rspMap = new HashMap<String, Object>(); + rspMap.put("access_token", JwtUtils.createToken(claimsMap)); + rspMap.put("expires_in", expireAppletTime); + return rspMap; + } + + public LoginUserApplet getLoginUserApplet() { + LoginUserApplet loginUserAppletToken = getLoginUserAppletToken(ServletUtils.getRequest()); + if (loginUserAppletToken == null) { + throw new UserAppletException("登录失效,请重新登录!", 401); + } + return loginUserAppletToken; + } + + public LoginUserApplet getLoginUserAppletToken(HttpServletRequest request) { + // 获取请求携带的令牌 + String token = SecurityUtils.getToken(request); + return getLoginUserApplet(token); + } + + /** + * 小程序 获取用户身份信息 + * + * @return 用户信息 + */ + public LoginUserApplet getLoginUserApplet(String token) { + LoginUserApplet user = null; + try { + if (StringUtils.isNotEmpty(token)) { + String userKey = JwtUtils.getUserKeyApplet(token); + user = redisService.getCacheObject(getTokenKey(userKey)); + return user; + } + } catch (Exception e) { + e.printStackTrace(); + } + return user; + } + + /** + * 获取用户身份信息 + * + * @return 用户信息 + */ + public LoginUser getLoginUser() { + return getLoginUser(ServletUtils.getRequest()); + } + + /** + * 获取用户身份信息 + * + * @return 用户信息 + */ + public LoginUser getLoginUser(HttpServletRequest request) { + // 获取请求携带的令牌 + String token = SecurityUtils.getToken(request); + return getLoginUser(token); + } + + /** + * 获取用户身份信息 + * + * @return 用户信息 + */ + public LoginUser getLoginUser(String token) { + LoginUser user = null; + try { + if (StringUtils.isNotEmpty(token)) { + String userkey = JwtUtils.getUserKey(token); + user = redisService.getCacheObject(getTokenKey(userkey)); + return user; + } + } catch (Exception e) { + } + return user; + } + + /** + * 设置用户身份信息 + */ + public void setLoginUser(LoginUser loginUser) { + if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken())) { + refreshToken(loginUser); + } + } + + /** + * 删除用户缓存信息 + */ + public void delLoginUser(String token) { + if (StringUtils.isNotEmpty(token)) { + String userkey = JwtUtils.getUserKey(token); + redisService.deleteObject(getTokenKey(userkey)); + } + } + + /** + * 验证令牌有效期,相差不足120分钟,自动刷新缓存 + * + * @param loginUser + */ + public void verifyToken(LoginUser loginUser) { + long expireTime = loginUser.getExpireTime(); + long currentTime = System.currentTimeMillis(); + if (expireTime - currentTime <= MILLIS_MINUTE_TEN) { + refreshToken(loginUser); + } + } + + /** + * 刷新令牌有效期 + * + * @param loginUser 登录信息 + */ + public void refreshToken(LoginUser loginUser) { + loginUser.setLoginTime(System.currentTimeMillis()); + loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE); + // 根据uuid将loginUser缓存 + String userKey = getTokenKey(loginUser.getToken()); + redisService.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES); + } + + public void refreshToken1(LoginUserApplet dto) { + dto.setLoginTime(System.currentTimeMillis()); + dto.setExpireTime(dto.getLoginTime() + expireTime * MILLIS_MINUTE); + // 根据uuid将loginUser缓存 + String userKey = getTokenKey(dto.getToken()); + redisService.setCacheObject(userKey, dto, expireTime, TimeUnit.MINUTES); + } + + private String getTokenKey(String token) { + return ACCESS_TOKEN + token; + } } \ No newline at end of file diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TChargingOrderController.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TChargingOrderController.java index 6f39524..fd85e38 100644 --- a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TChargingOrderController.java +++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TChargingOrderController.java @@ -24,7 +24,9 @@ import com.ruoyi.order.service.TChargingOrderService; import com.ruoyi.order.service.TOrderEvaluateService; import com.ruoyi.order.service.TOrderEvaluateTagService; +import com.ruoyi.payment.api.feignClient.AliPaymentClient; import com.ruoyi.payment.api.feignClient.WxPaymentClient; +import com.ruoyi.payment.api.vo.AliQueryOrder; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; @@ -35,6 +37,7 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.io.PrintWriter; import java.util.List; import java.util.Map; import java.util.List; @@ -64,6 +67,9 @@ @Resource private RedisService redisService; + + @Resource + private AliPaymentClient aliPaymentClient; @@ -203,20 +209,23 @@ /** * 支付宝支付成功后的回调 - * @param request */ @ResponseBody @PostMapping(value = "/chargingOrderALICallback") - public void chargingOrderALICallback(HttpServletRequest request){ - Map<String, Object> data = wxPaymentClient.payNotify(request).getData(); - if(null != data){ - String out_trade_no = data.get("out_trade_no").toString(); - String transaction_id = data.get("transaction_id").toString(); - String attach = data.get("attach").toString(); + public void chargingOrderALICallback(@RequestBody AliQueryOrder aliQueryOrder, HttpServletResponse response){ + try { + String out_trade_no = aliQueryOrder.getOutTradeNo(); + String transaction_id = aliQueryOrder.getTradeNo(); + String attach = aliQueryOrder.getPassbackParams(); AjaxResult ajaxResult = chargingOrderService.chargingOrderCallback(2, out_trade_no, transaction_id, attach); if(ajaxResult.isSuccess()){ - + PrintWriter writer = response.getWriter(); + writer.println("success"); + writer.flush(); + writer.close(); } + }catch (Exception e){ + e.printStackTrace(); } } diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java index 425fe9e..51ec3ab 100644 --- a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java +++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java @@ -1,7 +1,5 @@ package com.ruoyi.order.service.impl; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.account.api.feignClient.AppUserCarClient; @@ -22,7 +20,6 @@ import com.ruoyi.common.core.web.page.PageInfo; import com.ruoyi.common.redis.service.RedisService; import com.ruoyi.common.security.service.TokenService; -import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.order.api.model.TChargingOrder; import com.ruoyi.order.api.model.TChargingOrderAccountingStrategy; import com.ruoyi.order.api.query.ChargingOrderQuery; @@ -32,13 +29,10 @@ import com.ruoyi.order.mapper.TChargingOrderMapper; import com.ruoyi.order.service.TChargingOrderAccountingStrategyService; import com.ruoyi.order.service.TChargingOrderService; -import com.ruoyi.other.api.domain.TCoupon; -import com.ruoyi.other.api.domain.TVip; +import com.ruoyi.payment.api.feignClient.AliPaymentClient; import com.ruoyi.payment.api.feignClient.WxPaymentClient; -import com.ruoyi.payment.api.vo.NotifyV3PayDecodeRespBody; -import com.ruoyi.payment.api.vo.PaymentOrder; +import com.ruoyi.payment.api.vo.*; import io.seata.spring.annotation.GlobalTransactional; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; @@ -48,7 +42,6 @@ import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.util.*; -import java.util.stream.Collectors; /** * <p> @@ -80,6 +73,9 @@ @Resource private WxPaymentClient wxPaymentClient; + + @Resource + private AliPaymentClient aliPaymentClient; @Resource private ChargingPileClient chargingPileClient; @@ -231,7 +227,14 @@ } } if(2 == rechargePaymentType){ - + AliQueryOrder data = aliPaymentClient.query(tChargingOrder.getCode()).getData(); + if(null != data){ + //支付失败,删除无效的订单 + String tradeStatus = data.getTradeStatus(); + if(tradeStatus.equals("TRADE_CLOSED")){ + this.removeById(tChargingOrder.getId()); + } + } } } @@ -261,7 +264,19 @@ } } if(2 == one.getRechargePaymentType()){ - + AliQueryOrder data = aliPaymentClient.query(one.getCode()).getData(); + if(null != data){ + String trade_state = data.getTradeStatus(); + //支付失败,删除无效的订单 + if(trade_state.equals("TRADE_CLOSED")){ + this.removeById(one.getId()); + } + if(trade_state.equals("WAIT_BUYER_PAY")){ + //结束第三方支付,删除订单 + aliPaymentClient.close(one.getCode()); + this.removeById(one.getId()); + } + } } } @@ -313,7 +328,17 @@ return AjaxResult.success(data); } if(2 == addChargingOrder.getPaymentType()){ - + AliPaymentReq req = new AliPaymentReq(); + req.setOutTradeNo(chargingOrder.getCode()); + req.setTotalAmount(chargingOrder.getPaymentAmount().toString()); + req.setSubject("充电充值"); + req.setBuyerOpenId(appUser.getAliOpenid()); + req.setBody("充电充值"); + AliPaymentResp data = aliPaymentClient.payment(req).getData(); + if(null != data){ + data.setNotifyUrl(data.getNotifyUrl() + "/t-charging-order/chargingOrderALICallback"); + return AjaxResult.success(data); + } } throw new RuntimeException("无效的支付方式"); } diff --git a/ruoyi-service/ruoyi-payment/pom.xml b/ruoyi-service/ruoyi-payment/pom.xml index eedddef..f5b4d41 100644 --- a/ruoyi-service/ruoyi-payment/pom.xml +++ b/ruoyi-service/ruoyi-payment/pom.xml @@ -128,6 +128,12 @@ <groupId>com.ruoyi</groupId> <artifactId>ruoyi-api-payment</artifactId> </dependency> + + <dependency> + <groupId>com.alipay.sdk</groupId> + <artifactId>alipay-sdk-java</artifactId> + <version>4.39.186.ALL</version> + </dependency> </dependencies> <build> diff --git a/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/config/AliProperties.java b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/config/AliProperties.java new file mode 100644 index 0000000..631dea4 --- /dev/null +++ b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/config/AliProperties.java @@ -0,0 +1,54 @@ +package com.ruoyi.payment.ali.config; + + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * @author zhibing.pu + * @Date 2024/8/23 16:08 + */ +@Data +@Component +@ConfigurationProperties(prefix = "payment.ali") +public class AliProperties { + /** + * appid + */ + private String appId; + /** + * 加签方式 + */ + private String signType; + /** + * 开发者私钥,由开发者自己生成 + */ + private String privateKey; + /** + * 支付宝公钥 + */ + private String alipayPublicKey; + /** + * 应用公钥证书文件本地路径 + */ + private String appCertPath; + /** + * 支付宝公钥证书文件本地路径 + */ + private String alipayPublicCertPath; + /** + * 支付宝根证书文件本地路径 + */ + private String rootCertPath; + /** + * 回调地址 + */ + private String notifyUrl; + /** + * V2接口地址 + */ + private String v2Path = "https://openapi.alipay.com/gateway.do"; + + +} diff --git a/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/config/SignType.java b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/config/SignType.java new file mode 100644 index 0000000..d044247 --- /dev/null +++ b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/config/SignType.java @@ -0,0 +1,39 @@ +package com.ruoyi.payment.ali.config; + +/** + * @author zhibing.pu + * @Date 2024/8/23 16:22 + */ +public enum SignType { + /** + * V2版本 + */ + RSA2("RSA2"), + /** + * V3版本 + */ + RSA3("RSA2"), + /** + * 秘钥 + */ + SECRET_KEY("secret"), + /** + * 证书 + */ + CERT("cert"); + + + private String type; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + SignType(String type) { + this.type = type; + } +} diff --git a/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/AppletPayUtil.java b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/AppletPayUtil.java new file mode 100644 index 0000000..c116fdc --- /dev/null +++ b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/AppletPayUtil.java @@ -0,0 +1,228 @@ +package com.ruoyi.payment.ali.v2; + +import com.alibaba.fastjson.JSON; +import com.alipay.api.AlipayClient; +import com.alipay.api.AlipayConfig; +import com.alipay.api.DefaultAlipayClient; +import com.alipay.api.domain.*; +import com.alipay.api.request.*; +import com.alipay.api.response.*; +import com.ruoyi.payment.ali.config.AliProperties; +import com.ruoyi.payment.ali.config.SignType; +import com.ruoyi.payment.ali.v2.model.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + + +/** + * 支付宝小程序支付 + * @author zhibing.pu + * @Date 2024/8/23 16:05 + */ +@Component +public class AppletPayUtil { + private static Logger log = LoggerFactory.getLogger(AppletPayUtil.class); + + @Resource + private AliProperties aliProperties; + + + /** + * 创建统一收单交易 + * @param pojo + */ + public PaymentResp payment(PaymentReq pojo){ + try { + // 初始化SDK + AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig()); + // 构造请求参数以调用接口 + AlipayTradeCreateRequest request = new AlipayTradeCreateRequest(); + AlipayTradeCreateModel model = new AlipayTradeCreateModel(); + // 设置商户订单号 + model.setOutTradeNo(pojo.getOutTradeNo()); + // 设置产品码 + model.setProductCode("JSAPI_PAY"); + // 设置小程序支付中 + model.setOpAppId(aliProperties.getAppId()); + // 设置订单总金额 + model.setTotalAmount(pojo.getTotalAmount()); + // 设置订单标题 + model.setSubject(pojo.getSubject()); + // 设置订单附加信息 + model.setBody(pojo.getBody()); + // 设置买家支付宝用户唯一标识 + model.setBuyerOpenId(pojo.getBuyerOpenId()); + //超时相对时间 + model.setTimeoutExpress(pojo.getTimeoutExpress()); + //异步返回参数 + model.setPassbackParams(pojo.getPassbackParams()); + request.setBizModel(model); + + AlipayTradeCreateResponse response = alipayClient.execute(request); + log.info("-----调起支付宝支付-----"); + log.info("请求参数:{}", pojo); + log.info("返回结果:{}", response.getBody()); + if (response.isSuccess()) { + return PaymentResp.build(response.getOutTradeNo(), response.getTradeNo()); + } + }catch (Exception e){ + e.printStackTrace(); + } + return null; + } + + + /** + * 查询支付订单 + * @param outTradeNo 业务流水号 + * @return + */ + public QueryResp query(String outTradeNo){ + try { + // 初始化SDK + AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig()); + // 构造请求参数以调用接口 + AlipayTradeQueryRequest request = new AlipayTradeQueryRequest(); + AlipayTradeQueryModel model = new AlipayTradeQueryModel(); + // 设置订单支付时传入的商户订单号 + model.setOutTradeNo(outTradeNo); + request.setBizModel(model); + AlipayTradeQueryResponse response = alipayClient.execute(request); + log.info("-----查询支付宝支付-----"); + log.info("请求参数:{}", outTradeNo); + log.info("返回结果:{}", response.getBody()); + if (response.isSuccess()) { + return JSON.parseObject(response.getBody(), QueryResp.class); + } + }catch (Exception e){ + e.printStackTrace(); + } + return null; + } + + + /** + * 交易退款 + * @param req + * @return + */ + public RefundResp refund(RefundReq req){ + try { + // 初始化SDK + AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig()); + // 构造请求参数以调用接口 + AlipayTradeRefundRequest request = new AlipayTradeRefundRequest(); + AlipayTradeRefundModel model = new AlipayTradeRefundModel(); + // 设置商户订单号 + model.setOutTradeNo(req.getOutTradeNo()); + // 设置退款商户订单号 + model.setOutRequestNo(req.getOutRequestNo()); + // 设置退款金额 + model.setRefundAmount(req.getRefundAmount()); + // 设置退款原因说明 + model.setRefundReason(req.getRefundReason()); + request.setBizModel(model); + AlipayTradeRefundResponse response = alipayClient.execute(request); + log.info("-----支付宝退款-----"); + log.info("请求参数:{}", req); + log.info("返回结果:{}", response.getBody()); + if (response.isSuccess()) { + return JSON.parseObject(response.getBody(), RefundResp.class); + } + }catch (Exception e){ + e.printStackTrace(); + } + return null; + } + + /** + * 退款查询 + * @param req + * @return + */ + public QueryRefundResp queryRefund(QueryRefundReq req){ + try { + // 初始化SDK + AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig()); + // 构造请求参数以调用接口 + AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest(); + AlipayTradeFastpayRefundQueryModel model = new AlipayTradeFastpayRefundQueryModel(); + // 设置商户订单号 + model.setOutTradeNo(req.getOutTradeNo()); + model.setOutRequestNo(req.getOutRequestNo()); + request.setBizModel(model); + AlipayTradeFastpayRefundQueryResponse response = alipayClient.execute(request); + log.info("-----查询支付宝退款-----"); + log.info("请求参数:{}", req); + log.info("返回结果:{}", response.getBody()); + if (response.isSuccess()) { + return JSON.parseObject(response.getBody(), QueryRefundResp.class); + } + }catch (Exception e){ + e.printStackTrace(); + } + return null; + } + + /** + * 支付宝关闭订单 + * @param outTradeNo 业务流水号 + * @return + */ + public boolean close(String outTradeNo){ + try { + AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig()); + AlipayTradeCloseRequest request = new AlipayTradeCloseRequest(); + AlipayTradeCloseModel model = new AlipayTradeCloseModel(); + model.setOutTradeNo(outTradeNo); + request.setBizModel(model); + AlipayTradeCloseResponse response = alipayClient.execute(request); + log.info("-----关闭支付宝支付订单-----"); + log.info("请求参数:{}", outTradeNo); + log.info("返回结果:{}", response.getBody()); + if(response.isSuccess()){ + return true; + } + }catch (Exception e){ + e.printStackTrace(); + } + return false; + } + + + + /** + * 构建配置数据 + * @return + */ + private AlipayConfig getAlipayConfig() throws Exception { + AlipayConfig alipayConfig = new AlipayConfig(); + alipayConfig.setServerUrl(aliProperties.getV2Path()); + alipayConfig.setAppId(aliProperties.getAppId()); + alipayConfig.setFormat("json"); + alipayConfig.setCharset("UTF-8"); + alipayConfig.setSignType(SignType.RSA2.getType()); + //判断加签方式 + String signType = aliProperties.getSignType(); + if(SignType.CERT.getType().equals(signType)){ + alipayConfig.setPrivateKey(aliProperties.getPrivateKey()); + alipayConfig.setAlipayPublicKey(aliProperties.getAlipayPublicKey()); + return alipayConfig; + } + if(SignType.SECRET_KEY.getType().equals(signType)){ + alipayConfig.setAppCertPath(aliProperties.getAppCertPath()); + alipayConfig.setAlipayPublicCertPath(aliProperties.getAlipayPublicCertPath()); + alipayConfig.setRootCertPath(aliProperties.getRootCertPath()); + return alipayConfig; + } + throw new RuntimeException("构建配置失败"); + } + + + + + +} diff --git a/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/PaymentReq.java b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/PaymentReq.java new file mode 100644 index 0000000..422f4b1 --- /dev/null +++ b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/PaymentReq.java @@ -0,0 +1,52 @@ +package com.ruoyi.payment.ali.v2.model; + +import lombok.Data; + + +/** + * @author zhibing.pu + * @Date 2024/8/23 16:52 + */ +@Data +public class PaymentReq { + /** + * 业务流水号 + */ + private String outTradeNo; + /** + * 支付总金额 + */ + private String totalAmount; + /** + * 订单标题 + */ + private String subject; + /** + * 支付用户支付宝openid + */ + private String buyerOpenId; + /** + * 订单附加信息 + */ + private String body; + /** + * 订单超时时间 + * 订单相对超时时间。从交易创建时间开始计算。 + * 该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 该参数数值不接受小数点, 如 1.5h,可转换为 90m。 + * 当面付场景默认值为3h + */ + private String timeoutExpress; + /** + * 回传参数 + * 如果请求时传递了该参数,支付宝会在异步通知时将该参数原样返回。 + */ + private String passbackParams; + + /** + * 初始化默认数据 + */ + public PaymentReq() { + //订单超时默认30分钟 + this.timeoutExpress = "30m"; + } +} diff --git a/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/PaymentResp.java b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/PaymentResp.java new file mode 100644 index 0000000..de77d29 --- /dev/null +++ b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/PaymentResp.java @@ -0,0 +1,30 @@ +package com.ruoyi.payment.ali.v2.model; + +import lombok.Data; + + +/** + * @author zhibing.pu + * @Date 2024/8/23 16:52 + */ +@Data +public class PaymentResp { + /** + * 业务流水号 + */ + private String outTradeNo; + /** + * 支付宝交易号 + */ + private String tradeNo; + + private PaymentResp(String outTradeNo, String tradeNo) { + this.outTradeNo = outTradeNo; + this.tradeNo = tradeNo; + } + + public static PaymentResp build(String outTradeNo, String tradeNo){ + PaymentResp info = new PaymentResp(outTradeNo, tradeNo); + return info; + } +} diff --git a/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/QueryRefundReq.java b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/QueryRefundReq.java new file mode 100644 index 0000000..bb74d63 --- /dev/null +++ b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/QueryRefundReq.java @@ -0,0 +1,19 @@ +package com.ruoyi.payment.ali.v2.model; + +import lombok.Data; + +/** + * @author zhibing.pu + * @Date 2024/8/24 14:00 + */ +@Data +public class QueryRefundReq { + /** + * 支付业务流水号 + */ + private String outTradeNo; + /** + * 退款业务流水号 + */ + private String outRequestNo; +} diff --git a/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/QueryRefundResp.java b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/QueryRefundResp.java new file mode 100644 index 0000000..ad4263f --- /dev/null +++ b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/QueryRefundResp.java @@ -0,0 +1,43 @@ +package com.ruoyi.payment.ali.v2.model; + +import com.fasterxml.jackson.annotation.JsonSetter; +import lombok.Data; + +/** + * @author zhibing.pu + * @Date 2024/8/24 13:58 + */ +@Data +public class QueryRefundResp { + /** + * 支付宝交易号 + */ + @JsonSetter("trade_no") + private String tradeNo; + /** + * 支付业务流水号 + */ + @JsonSetter("out_trade_no") + private String outTradeNo; + /** + * 退款业务流水号 + */ + @JsonSetter("out_request_no") + private String outRequestNo; + /** + * 交易金额 + */ + @JsonSetter("total_amount") + private Double totalAmount; + /** + * 本次退款金额 + */ + @JsonSetter("refund_amount") + private Double refundAmount; + /** + * 退款状态 + * REFUND_SUCCESS 退款处理成功; 未返回该字段表示退款请求未收到或者退款失败; 注:如果退款查询发起时间早于退款时间,或者间隔退款发起时间太短,可能出现退款查询时还没处理成功,后面又处理成功的情况,建议商户在退款发起后间隔10秒以上再发起退款查询请求。 + */ + @JsonSetter("refund_status") + private String refundStatus; +} diff --git a/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/QueryResp.java b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/QueryResp.java new file mode 100644 index 0000000..c09e509 --- /dev/null +++ b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/QueryResp.java @@ -0,0 +1,48 @@ +package com.ruoyi.payment.ali.v2.model; + +import com.fasterxml.jackson.annotation.JsonSetter; +import lombok.Data; + +/** + * @author zhibing.pu + * @Date 2024/8/24 12:01 + */ +@Data +public class QueryResp { + /** + * 支付宝交易号 + */ + @JsonSetter("trade_no") + private String tradeNo; + /** + * 业务流水号 + */ + @JsonSetter("out_trade_no") + private String outTradeNo; + /** + * 交易状态 + * WAIT_BUYER_PAY(交易创建,等待买家付款)、TRADE_CLOSED(未付款交易超时关闭,或支付完成后全额退款)、TRADE_SUCCESS(交易支付成功)、TRADE_FINISHED(交易结束,不可退款) + */ + @JsonSetter("trade_status") + private String tradeStatus; + /** + * 交易订单金额 + */ + @JsonSetter("total_amount") + private Double totalAmount; + /** + * 回传参数 + */ + @JsonSetter("passback_params") + private String passbackParams; + /** + * 订单标题 + */ + @JsonSetter("subject") + private String subject; + /** + * 订单描述 + */ + @JsonSetter("body") + private String body; +} diff --git a/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/RefundReq.java b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/RefundReq.java new file mode 100644 index 0000000..a887e52 --- /dev/null +++ b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/RefundReq.java @@ -0,0 +1,27 @@ +package com.ruoyi.payment.ali.v2.model; + +import lombok.Data; + +/** + * @author zhibing.pu + * @Date 2024/8/24 13:47 + */ +@Data +public class RefundReq { + /** + * 支付业务流水号 + */ + private String outTradeNo; + /** + * 退款业务流水号 + */ + private String outRequestNo; + /** + * 退款金额 + */ + private String refundAmount; + /** + * 退款原因 + */ + private String refundReason; +} diff --git a/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/RefundResp.java b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/RefundResp.java new file mode 100644 index 0000000..ed4697c --- /dev/null +++ b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/ali/v2/model/RefundResp.java @@ -0,0 +1,27 @@ +package com.ruoyi.payment.ali.v2.model; + +import com.fasterxml.jackson.annotation.JsonSetter; +import lombok.Data; + +/** + * @author zhibing.pu + * @Date 2024/8/24 13:50 + */ +@Data +public class RefundResp { + /** + * 支付宝交易号 + */ + @JsonSetter("trade_no") + private String tradeNo; + /** + * 业务流水号 + */ + @JsonSetter("out_trade_no") + private String outTradeNo; + /** + * 退款金额 + */ + @JsonSetter("refund_fee") + private Double refundFee; +} diff --git a/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/controller/AliPayController.java b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/controller/AliPayController.java new file mode 100644 index 0000000..4bd7ea5 --- /dev/null +++ b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/controller/AliPayController.java @@ -0,0 +1,86 @@ +package com.ruoyi.payment.controller; + +import com.ruoyi.common.core.domain.R; +import com.ruoyi.payment.ali.config.AliProperties; +import com.ruoyi.payment.ali.v2.AppletPayUtil; +import com.ruoyi.payment.ali.v2.model.PaymentReq; +import com.ruoyi.payment.ali.v2.model.PaymentResp; +import com.ruoyi.payment.ali.v2.model.QueryResp; +import com.ruoyi.payment.api.vo.AliPaymentReq; +import com.ruoyi.payment.api.vo.AliPaymentResp; +import com.ruoyi.payment.api.vo.AliQueryOrder; +import org.springframework.beans.BeanUtils; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +/** + * @author zhibing.pu + * @Date 2024/8/24 14:29 + */ +@RestController +@RequestMapping("/ali") +public class AliPayController { + + @Resource + private AppletPayUtil appletPayUtil; + + @Resource + private AliProperties aliProperties; + + + /** + * 调起支付宝小程序支付 + * @param req + * @return + */ + @ResponseBody + @PostMapping("/payment") + public R<AliPaymentResp> payment(@RequestBody AliPaymentReq req){ + PaymentReq pojo = new PaymentReq(); + BeanUtils.copyProperties(req, pojo); + PaymentResp payment = appletPayUtil.payment(pojo); + if(null != payment){ + AliPaymentResp aliPaymentResp = new AliPaymentResp(); + aliPaymentResp.setTradeNo(payment.getTradeNo()); + aliPaymentResp.setNotifyUrl(aliProperties.getNotifyUrl()); + return R.ok(aliPaymentResp); + } + return R.ok(); + } + + /** + * 查询订单 + * @param outTradeNo + * @return + */ + @ResponseBody + @PostMapping("/query") + public R<AliQueryOrder> query(@RequestParam("outTradeNo") String outTradeNo){ + QueryResp query = appletPayUtil.query(outTradeNo); + if(null != query){ + AliQueryOrder aliQueryOrder = new AliQueryOrder(); + BeanUtils.copyProperties(query, aliQueryOrder); + return R.ok(aliQueryOrder); + } + return R.ok(); + } + + /** + * 关闭订单 + * @param outTradeNo + */ + @ResponseBody + @PostMapping("/close") + public void close(@RequestParam("outTradeNo") String outTradeNo){ + boolean close = appletPayUtil.close(outTradeNo); + if(!close){ + throw new RuntimeException("关闭支付宝订单失败"); + } + } + + + + + +} diff --git a/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/wx/controller/WxPayController.java b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/controller/WxPayController.java similarity index 99% rename from ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/wx/controller/WxPayController.java rename to ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/controller/WxPayController.java index f3e7274..51b2238 100644 --- a/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/wx/controller/WxPayController.java +++ b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/controller/WxPayController.java @@ -1,4 +1,4 @@ -package com.ruoyi.payment.wx.controller; +package com.ruoyi.payment.controller; import com.fasterxml.jackson.core.type.TypeReference; import com.ruoyi.common.core.domain.R; diff --git a/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/wx/config/WxConfig.java b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/wx/config/WxConfig.java index 3aafb85..c5f4e17 100644 --- a/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/wx/config/WxConfig.java +++ b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/wx/config/WxConfig.java @@ -13,7 +13,6 @@ * * @author lihen */ -@ConditionalOnProperty(name = "wx.conf.enabled") @Configuration public class WxConfig { diff --git a/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/wx/model/WeixinProperties.java b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/wx/model/WeixinProperties.java index 5c1960b..a29040f 100644 --- a/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/wx/model/WeixinProperties.java +++ b/ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/wx/model/WeixinProperties.java @@ -12,7 +12,7 @@ */ @ToString @Component -@ConfigurationProperties(prefix = "wx.conf") +@ConfigurationProperties(prefix = "payment.wx") public class WeixinProperties { /** * 默认开启 -- Gitblit v1.7.1