feat:微信支付
This commit is contained in:
1 parent
f2b185b731
commit
bce4bf9ee3
27 files changed
+1224
-68
No files matched your search
+19
@@ -0,0 +1,19 @@
|
||||
package com.bsd.pjcloud.app.api.dto;
|
||||
|
||||
import com.bsd.pjcloud.app.api.constant.AppUserTypeEnum;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class AppAdminSyncDto {
|
||||
|
||||
private String uniqueCode;
|
||||
|
||||
private AppUserTypeEnum userTypeEnum;
|
||||
|
||||
private Long adminUserId;
|
||||
|
||||
private String username;
|
||||
|
||||
private String avatarImage;
|
||||
|
||||
}
|
||||
+9
-1
@@ -19,6 +19,7 @@
|
||||
|
||||
package com.bsd.pjcloud.app.api.feign;
|
||||
|
||||
import com.bsd.pjcloud.app.api.dto.AppAdminSyncDto;
|
||||
import com.bsd.pjcloud.app.api.dto.AppUserInfo;
|
||||
import com.bsd.pjcloud.common.core.constant.ServiceNameConstants;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
@@ -26,6 +27,8 @@ import com.bsd.pjcloud.common.feign.annotation.NoToken;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
|
||||
@FeignClient(contextId = "remoteAppUserService", value = ServiceNameConstants.APP_SERVER)
|
||||
@@ -49,5 +52,10 @@ public interface RemoteAppUserService {
|
||||
@GetMapping("/appsocial/info/{inStr}")
|
||||
R<AppUserInfo> social(@PathVariable("inStr") String inStr);
|
||||
|
||||
|
||||
/**
|
||||
* 同步admin账户信息为app账户
|
||||
*/
|
||||
@NoToken
|
||||
@PostMapping("/appsocial/info/sync-admin-account-info")
|
||||
R<AppUserInfo> syncAdminAccountInfo(@RequestBody AppAdminSyncDto appAdminSyncDto);
|
||||
}
|
||||
+15
@@ -20,6 +20,8 @@ package com.bsd.pjcloud.app.controller;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.bsd.pjcloud.app.api.dto.AppAdminSyncDto;
|
||||
import com.bsd.pjcloud.app.api.dto.AppUserInfo;
|
||||
import com.bsd.pjcloud.app.api.entity.AppSocialDetails;
|
||||
import com.bsd.pjcloud.app.service.AppSocialDetailsService;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
@@ -49,6 +51,19 @@ public class AppSocialDetailsController {
|
||||
|
||||
private final AppSocialDetailsService appSocialDetailsService;
|
||||
|
||||
/* ************************************* start 设备端 start ************************************* */
|
||||
|
||||
/**
|
||||
* 同步admin账户信息为app账户
|
||||
*/
|
||||
@PostMapping("/sync-admin-account-info")
|
||||
public R<AppUserInfo> syncAdminAccountInfo(@RequestBody AppAdminSyncDto dto) {
|
||||
return R.ok(appSocialDetailsService.syncAdminAccountInfo(dto));
|
||||
}
|
||||
|
||||
/* ************************************* end 设备端 end ************************************* */
|
||||
|
||||
|
||||
/**
|
||||
* 社交登录账户简单分页查询
|
||||
*/
|
||||
|
||||
+14
-16
@@ -18,30 +18,28 @@
|
||||
package com.bsd.pjcloud.app.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.bsd.pjcloud.app.api.dto.AppAdminSyncDto;
|
||||
import com.bsd.pjcloud.app.api.dto.AppUserInfo;
|
||||
import com.bsd.pjcloud.app.api.entity.AppSocialDetails;
|
||||
|
||||
/**
|
||||
* 系统社交登录账号表
|
||||
*
|
||||
* @author pjcloud
|
||||
* @date 2018-08-16 21:30:41
|
||||
*/
|
||||
public interface AppSocialDetailsService extends IService<AppSocialDetails> {
|
||||
|
||||
/**
|
||||
* 绑定社交账号
|
||||
* @param state 类型
|
||||
* @param code code
|
||||
* @return
|
||||
*/
|
||||
Boolean bindSocial(String state, String code);
|
||||
|
||||
/**
|
||||
* 根据入参查询用户信息
|
||||
* @param inStr
|
||||
* @return
|
||||
*/
|
||||
AppUserInfo getUserInfo(String inStr);
|
||||
/**
|
||||
* 同步admin账户信息为app账户
|
||||
*/
|
||||
AppUserInfo syncAdminAccountInfo(AppAdminSyncDto dto);
|
||||
|
||||
/**
|
||||
* 绑定社交账号
|
||||
*/
|
||||
Boolean bindSocial(String state, String code);
|
||||
|
||||
/**
|
||||
* 根据入参查询用户信息
|
||||
*/
|
||||
AppUserInfo getUserInfo(String inStr);
|
||||
}
|
||||
+56
-34
@@ -17,8 +17,12 @@
|
||||
|
||||
package com.bsd.pjcloud.app.service.impl;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringPool;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.bsd.pjcloud.app.api.constant.AppUserTypeEnum;
|
||||
import com.bsd.pjcloud.app.api.dto.AppAdminSyncDto;
|
||||
import com.bsd.pjcloud.app.api.dto.AppUserInfo;
|
||||
import com.bsd.pjcloud.app.api.entity.AppSocialDetails;
|
||||
import com.bsd.pjcloud.app.api.entity.AppUser;
|
||||
@@ -26,6 +30,7 @@ import com.bsd.pjcloud.app.handler.LoginHandler;
|
||||
import com.bsd.pjcloud.app.mapper.AppSocialDetailsMapper;
|
||||
import com.bsd.pjcloud.app.mapper.AppUserMapper;
|
||||
import com.bsd.pjcloud.app.service.AppSocialDetailsService;
|
||||
import com.bsd.pjcloud.app.service.AppUserService;
|
||||
import com.bsd.pjcloud.common.core.constant.CacheConstants;
|
||||
import com.bsd.pjcloud.common.security.util.SecurityUtils;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -42,45 +47,62 @@ import java.util.Map;
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
@Service("appSocialDetailsService")
|
||||
public class AppSocialDetailsServiceImpl extends ServiceImpl<AppSocialDetailsMapper, AppSocialDetails>
|
||||
implements AppSocialDetailsService {
|
||||
public class AppSocialDetailsServiceImpl extends ServiceImpl<AppSocialDetailsMapper, AppSocialDetails> implements AppSocialDetailsService {
|
||||
|
||||
private final Map<String, LoginHandler> loginHandlerMap;
|
||||
private final Map<String, LoginHandler> loginHandlerMap;
|
||||
|
||||
private final CacheManager cacheManager;
|
||||
private final CacheManager cacheManager;
|
||||
|
||||
private final AppUserMapper appUserMapper;
|
||||
private final AppUserMapper appUserMapper;
|
||||
|
||||
/**
|
||||
* 绑定社交账号
|
||||
* @param type type
|
||||
* @param code code
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Boolean bindSocial(String type, String code) {
|
||||
LoginHandler loginHandler = loginHandlerMap.get(type);
|
||||
// 绑定逻辑
|
||||
String identify = loginHandler.identify(code);
|
||||
AppUser user = appUserMapper.selectById(SecurityUtils.getUser().getId());
|
||||
loginHandler.bind(user, identify);
|
||||
private final AppUserService appUserService;
|
||||
|
||||
// 更新緩存
|
||||
cacheManager.getCache(CacheConstants.USER_DETAILS_MINI).evict(user.getUsername());
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
@Override
|
||||
public AppUserInfo syncAdminAccountInfo(AppAdminSyncDto dto) {
|
||||
AppUser user = appUserService.getOne(Wrappers.<AppUser>query().lambda()
|
||||
.eq(AppUser::getOpenid, dto.getUniqueCode())
|
||||
.eq(AppUser::getUserType, dto.getUserTypeEnum().getType())
|
||||
);
|
||||
if (ObjectUtil.isNotEmpty(user)) {
|
||||
return appUserService.findUserInfo(user);
|
||||
}
|
||||
AppUser appUser = new AppUser();
|
||||
appUser.setOpenid(dto.getUniqueCode());
|
||||
appUser.setUserType(AppUserTypeEnum.MINI_ALIPAY.getType());
|
||||
appUser.setUsername(dto.getUsername());
|
||||
appUser.setName(dto.getUsername());
|
||||
appUser.setAvatar(dto.getAvatarImage());
|
||||
appUser.setCreateBy(dto.getUniqueCode());
|
||||
appUser.setUpdateBy(dto.getUniqueCode());
|
||||
appUserService.saveOrUpdate(appUser);
|
||||
return appUserService.findUserInfo(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据入参查询用户信息
|
||||
* @param inStr TYPE@code
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public AppUserInfo getUserInfo(String inStr) {
|
||||
String[] inStrs = inStr.split(StringPool.AT);
|
||||
String type = inStrs[0];
|
||||
String loginStr = inStr.substring(type.length() + 1);
|
||||
return loginHandlerMap.get(type).handle(loginStr);
|
||||
}
|
||||
/**
|
||||
* 绑定社交账号
|
||||
*/
|
||||
@Override
|
||||
public Boolean bindSocial(String type, String code) {
|
||||
LoginHandler loginHandler = loginHandlerMap.get(type);
|
||||
// 绑定逻辑
|
||||
String identify = loginHandler.identify(code);
|
||||
AppUser user = appUserMapper.selectById(SecurityUtils.getUser().getId());
|
||||
loginHandler.bind(user, identify);
|
||||
|
||||
// 更新緩存
|
||||
cacheManager.getCache(CacheConstants.USER_DETAILS_MINI).evict(user.getUsername());
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据入参查询用户信息
|
||||
*/
|
||||
@Override
|
||||
public AppUserInfo getUserInfo(String inStr) {
|
||||
String[] inStrs = inStr.split(StringPool.AT);
|
||||
String type = inStrs[0];
|
||||
String loginStr = inStr.substring(type.length() + 1);
|
||||
return loginHandlerMap.get(type).handle(loginStr);
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -14,7 +14,7 @@ import java.util.Arrays;
|
||||
@Getter
|
||||
public enum MiniPlatformTypeEnum {
|
||||
|
||||
WECAHT("10", "微信小程序"),
|
||||
WECHAT("10", "微信小程序"),
|
||||
ALI_PAY("20", "支付宝"),
|
||||
;
|
||||
|
||||
|
||||
+6
-1
@@ -6,7 +6,7 @@ import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ThirdMinAppOAth2LoginDto {
|
||||
public class ThirdMiniAppGetUniqueDto {
|
||||
|
||||
/**
|
||||
* 小程序平台
|
||||
@@ -17,4 +17,9 @@ public class ThirdMinAppOAth2LoginDto {
|
||||
@NotEmpty(message = "code不能为空")
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.bsd.pjcloud.thirdparty.dto.oathmini;
|
||||
|
||||
import com.bsd.pjcloud.thirdparty.constant.miniplatform.MiniPlatformTypeEnum;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ThirdMiniAppOAth2LoginDto {
|
||||
|
||||
/**
|
||||
* 小程序平台
|
||||
*/
|
||||
@NotNull(message = "小程序平台标识不能为空")
|
||||
private MiniPlatformTypeEnum miniPlatformType;
|
||||
|
||||
@NotEmpty(message = "phoneCode不能为空")
|
||||
private String phoneCode;
|
||||
|
||||
@NotEmpty(message = "userCode不能为空")
|
||||
private String userCode;
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 撤销订单入参
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ThirdMiniWechantReverseDto {
|
||||
|
||||
private Long orderId;
|
||||
|
||||
private String wechantOrderId;
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 查询订单入参
|
||||
*/
|
||||
@Data
|
||||
public class ThirdMiniWechatQueryDto {
|
||||
|
||||
/**
|
||||
* 微信订单号
|
||||
*/
|
||||
private String wechantOrderId;
|
||||
|
||||
/**
|
||||
* 商户订单号
|
||||
*/
|
||||
private String orderId;
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 退款入参
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ThirdMiniWechatRefundDto {
|
||||
|
||||
private Long orderId;
|
||||
|
||||
private String wechantOrderId;
|
||||
|
||||
private Long refundId;
|
||||
|
||||
private Integer orderPrice;
|
||||
|
||||
private Integer refundPrice;
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 微信退款查询入参
|
||||
*/
|
||||
@Data
|
||||
public class ThirdMiniWechatRefundQueryDto {
|
||||
|
||||
/**
|
||||
* 退款id
|
||||
*/
|
||||
private String refundId;
|
||||
|
||||
}
|
||||
+2
@@ -9,4 +9,6 @@ public class ThirdMinAppOAth2LoginVo {
|
||||
|
||||
private String refreshToken;
|
||||
|
||||
private String errorCode;
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 微信退款回调加密的返回参数
|
||||
*/
|
||||
@Data
|
||||
public class ThirdMiniWechantRefunCallbackSoureVo {
|
||||
|
||||
/**
|
||||
* 公众账号ID
|
||||
*/
|
||||
private String appid;
|
||||
|
||||
/**
|
||||
* 退款的商户号
|
||||
*/
|
||||
private String mch_id;
|
||||
|
||||
/**
|
||||
* 随机字符串
|
||||
*/
|
||||
private String nonce_str;
|
||||
|
||||
/**
|
||||
* 加密信息
|
||||
*/
|
||||
private String req_info;
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 微信退款回调返回参数
|
||||
*/
|
||||
@Data
|
||||
public class ThirdMiniWechantRefunCallbackVo {
|
||||
|
||||
public static final String SUCCESS_CODE = "SUCCESS";
|
||||
|
||||
/**
|
||||
* 微信订单号
|
||||
*/
|
||||
private String transaction_id;
|
||||
|
||||
/**
|
||||
* 商户订单号
|
||||
*/
|
||||
private String out_trade_no;
|
||||
|
||||
/**
|
||||
* 微信退款单号
|
||||
*/
|
||||
private String refund_id;
|
||||
|
||||
/**
|
||||
* 商户退款单号
|
||||
*/
|
||||
private String out_refund_no;
|
||||
|
||||
/**
|
||||
* 订单金额
|
||||
*/
|
||||
private String total_fee;
|
||||
|
||||
/**
|
||||
* 应结订单金额
|
||||
*/
|
||||
private String settlement_total_fee;
|
||||
|
||||
/**
|
||||
* 申请退款金额
|
||||
*/
|
||||
private String refund_fee;
|
||||
|
||||
/**
|
||||
* 退款金额
|
||||
*/
|
||||
private String settlement_refund_fee;
|
||||
|
||||
/**
|
||||
* 退款状态
|
||||
*/
|
||||
private String refund_status;
|
||||
|
||||
public boolean isAllSuccess() {
|
||||
return ObjectUtil.equals(refund_status, SUCCESS_CODE);
|
||||
}
|
||||
|
||||
public static String wechantError() {
|
||||
return "<xml>" +
|
||||
"<return_code><![CDATA[FAIL]]></return_code>" +
|
||||
"<return_msg><![CDATA[FAIL]]></return_msg>" +
|
||||
"</xml>";
|
||||
}
|
||||
|
||||
public static String wechantSuccess() {
|
||||
return "<xml>" +
|
||||
" <return_code><![CDATA[SUCCESS]]></return_code>" +
|
||||
" <return_msg><![CDATA[OK]]></return_msg>\n" +
|
||||
"</xml>";
|
||||
}
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 撤销订单返回
|
||||
*/
|
||||
@Data
|
||||
public class ThirdMiniWechantReverseVo {
|
||||
public static final String SUCCESS = "SUCCESS";
|
||||
|
||||
private String return_code;
|
||||
|
||||
private String return_msg;
|
||||
|
||||
private String appid;
|
||||
|
||||
private String mch_id;
|
||||
|
||||
private String nonce_str;
|
||||
|
||||
private String sign;
|
||||
|
||||
private String result_code;
|
||||
|
||||
private String err_code;
|
||||
|
||||
private String err_code_des;
|
||||
|
||||
private String recall;
|
||||
|
||||
public boolean isHttpSucess() {
|
||||
return ObjectUtil.equals(ThirdMiniWechantReverseVo.SUCCESS, return_code);
|
||||
}
|
||||
|
||||
public boolean isPaySucess() {
|
||||
return ObjectUtil.equals(ThirdMiniWechantReverseVo.SUCCESS, result_code);
|
||||
}
|
||||
|
||||
public boolean isAllSuccess() {
|
||||
return isHttpSucess() && isPaySucess();
|
||||
}
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
package com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 查询订单返回
|
||||
*/
|
||||
@Data
|
||||
public class ThirdMiniWechatQueryVo {
|
||||
public static final String SUCCESS = "SUCCESS";
|
||||
|
||||
private String return_code;
|
||||
|
||||
private String return_msg;
|
||||
|
||||
private String appid;
|
||||
|
||||
private String mch_id;
|
||||
|
||||
private String nonce_str;
|
||||
|
||||
private String sign;
|
||||
|
||||
private String result_code;
|
||||
|
||||
private String err_code;
|
||||
|
||||
private String err_code_des;
|
||||
|
||||
private String device_info;
|
||||
|
||||
/**
|
||||
* 用户标识
|
||||
*/
|
||||
private String openid;
|
||||
|
||||
/**
|
||||
* 是否关注公众账号
|
||||
*/
|
||||
private String is_subscribe;
|
||||
|
||||
/**
|
||||
* 交易类型
|
||||
*/
|
||||
private String trade_type;
|
||||
|
||||
/**
|
||||
* 交易状态
|
||||
*/
|
||||
private String trade_state;
|
||||
|
||||
/**
|
||||
* 付款银行
|
||||
*/
|
||||
private String bank_type;
|
||||
|
||||
/**
|
||||
* 标价金额
|
||||
*/
|
||||
private String total_fee;
|
||||
|
||||
/**
|
||||
* 应结订单金额
|
||||
*/
|
||||
private String settlement_total_fee;
|
||||
|
||||
/**
|
||||
* 标价币种
|
||||
*/
|
||||
private String fee_type;
|
||||
|
||||
/**
|
||||
* 现金支付金额
|
||||
*/
|
||||
private String cash_fee;
|
||||
|
||||
/**
|
||||
* 现金支付币种
|
||||
*/
|
||||
private String cash_fee_type;
|
||||
|
||||
/**
|
||||
* 代金券金额
|
||||
*/
|
||||
private String coupon_fee;
|
||||
|
||||
/**
|
||||
* 代金券使用数量
|
||||
*/
|
||||
private String coupon_count;
|
||||
|
||||
/**
|
||||
* 微信支付订单号
|
||||
*/
|
||||
private String transaction_id;
|
||||
|
||||
/**
|
||||
* 商户订单号
|
||||
*/
|
||||
private String out_trade_no;
|
||||
|
||||
/**
|
||||
* 附加数据
|
||||
*/
|
||||
private String attach;
|
||||
|
||||
/**
|
||||
* 支付完成时间
|
||||
*/
|
||||
private String time_end;
|
||||
|
||||
/**
|
||||
* 交易状态描述
|
||||
*/
|
||||
private String trade_state_desc;
|
||||
|
||||
public boolean isHttpSucess() {
|
||||
return ObjectUtil.equals(ThirdMiniWechatQueryVo.SUCCESS, return_code);
|
||||
}
|
||||
|
||||
public boolean isPaySucess() {
|
||||
return ObjectUtil.equals(ThirdMiniWechatQueryVo.SUCCESS, result_code);
|
||||
}
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
package com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 退款返回
|
||||
*/
|
||||
@Data
|
||||
public class ThirdMiniWechatRefundQueryVo {
|
||||
|
||||
public static final String SUCCESS = "SUCCESS";
|
||||
|
||||
/**
|
||||
* 业务结果
|
||||
*/
|
||||
private String result_code;
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private String err_code;
|
||||
|
||||
/**
|
||||
* 错误描述
|
||||
*/
|
||||
private String err_code_des;
|
||||
|
||||
/**
|
||||
* 公众账号ID
|
||||
*/
|
||||
private String appid;
|
||||
|
||||
/**
|
||||
* 商户号
|
||||
*/
|
||||
private String mch_id;
|
||||
|
||||
/**
|
||||
* 随机字符串
|
||||
*/
|
||||
private String nonce_str;
|
||||
|
||||
/**
|
||||
* 签名
|
||||
*/
|
||||
private String sign;
|
||||
|
||||
/**
|
||||
* 订单总退款次数
|
||||
*/
|
||||
private Long total_refund_count;
|
||||
|
||||
/**
|
||||
* 微信订单号
|
||||
*/
|
||||
private String transaction_id;
|
||||
|
||||
/**
|
||||
* 商户订单号
|
||||
*/
|
||||
private String out_trade_no;
|
||||
|
||||
/**
|
||||
* 订单金额
|
||||
*/
|
||||
private Long total_fee;
|
||||
|
||||
/**
|
||||
* 应结订单金额
|
||||
*/
|
||||
private Long settlement_total_fee;
|
||||
|
||||
/**
|
||||
* 货币种类
|
||||
*/
|
||||
private String fee_type;
|
||||
|
||||
/**
|
||||
* 现金支付金额
|
||||
*/
|
||||
private Long cash_fee;
|
||||
|
||||
/**
|
||||
* 退款笔数
|
||||
*/
|
||||
private Long refund_count;
|
||||
|
||||
/**
|
||||
* 退款总金额
|
||||
*/
|
||||
private Long refund_fee;
|
||||
|
||||
public boolean isHttpSucess() {
|
||||
return ObjectUtil.equals(ThirdMiniWechatRefundQueryVo.SUCCESS, err_code);
|
||||
}
|
||||
|
||||
public boolean isPaySucess() {
|
||||
return ObjectUtil.equals(ThirdMiniWechatRefundQueryVo.SUCCESS, result_code);
|
||||
}
|
||||
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 退款返回
|
||||
*/
|
||||
@Data
|
||||
public class ThirdMiniWechatRefundVo {
|
||||
|
||||
public static final String SUCCESS = "SUCCESS";
|
||||
|
||||
private String return_code;
|
||||
|
||||
private String return_msg;
|
||||
|
||||
private String result_code;
|
||||
|
||||
private String err_code;
|
||||
|
||||
private String err_code_des;
|
||||
|
||||
private String appid;
|
||||
|
||||
private String mch_id;
|
||||
|
||||
private String nonce_str;
|
||||
|
||||
|
||||
private String sign;
|
||||
|
||||
/**
|
||||
* 微信支付订单号
|
||||
*/
|
||||
private String transaction_id;
|
||||
|
||||
/**
|
||||
* 商户订单号
|
||||
*/
|
||||
private String out_trade_no;
|
||||
|
||||
/**
|
||||
* 商户退款单号
|
||||
*/
|
||||
private String out_refund_no;
|
||||
|
||||
/**
|
||||
* 微信退款单号
|
||||
*/
|
||||
private String refund_id;
|
||||
|
||||
/**
|
||||
* 退款金额
|
||||
*/
|
||||
private String refund_fee;
|
||||
|
||||
/**
|
||||
* 应结退款金额
|
||||
*/
|
||||
private String settlement_refund_fee;
|
||||
|
||||
/**
|
||||
* 标价金额
|
||||
*/
|
||||
private String total_fee;
|
||||
|
||||
/**
|
||||
* 应结订单金额
|
||||
*/
|
||||
private String settlement_total_fee;
|
||||
|
||||
public boolean isHttpSucess() {
|
||||
return ObjectUtil.equals(ThirdMiniWechatRefundVo.SUCCESS, return_code);
|
||||
}
|
||||
|
||||
public boolean isPaySucess() {
|
||||
return ObjectUtil.equals(ThirdMiniWechatRefundVo.SUCCESS, result_code);
|
||||
}
|
||||
|
||||
public boolean isAllSuccess() {
|
||||
return isHttpSucess() && isPaySucess();
|
||||
}
|
||||
}
|
||||
+36
@@ -21,10 +21,46 @@ public class MiniAppConfig {
|
||||
@Data
|
||||
public static class WechatConfig {
|
||||
|
||||
/**
|
||||
* 微信公共平台 appId
|
||||
*/
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* 微信公共平台 appSecret
|
||||
*/
|
||||
private String appSecret;
|
||||
|
||||
/**
|
||||
* 商户号
|
||||
*/
|
||||
private String merchantId;
|
||||
|
||||
/**
|
||||
* 商户证书序列path
|
||||
*/
|
||||
private String merchantSerialPath;
|
||||
|
||||
/**
|
||||
* 商户APIV2密钥
|
||||
*/
|
||||
private String apiV2Key;
|
||||
|
||||
/**
|
||||
* 退款回调地址
|
||||
*/
|
||||
private String refundCallbackUrl;
|
||||
|
||||
/**
|
||||
* 调用ip
|
||||
*/
|
||||
private String spbillCreateIp;
|
||||
|
||||
/**
|
||||
* 微信支付接口地址
|
||||
*/
|
||||
private String baseUrl;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
+12
-3
@@ -1,7 +1,9 @@
|
||||
package com.bsd.pjcloud.thirdparty.controller.oathmini;
|
||||
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMinAppOAth2LoginDto;
|
||||
import com.bsd.pjcloud.common.security.annotation.Inner;
|
||||
import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMiniAppGetUniqueDto;
|
||||
import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMiniAppOAth2LoginDto;
|
||||
import com.bsd.pjcloud.thirdparty.service.ThirdMiniAppService;
|
||||
import com.bsd.pjcloud.thirdparty.vo.oathmini.ThirdMinAppOAth2LoginVo;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@@ -20,11 +22,18 @@ public class ThirdMinAppOAth2Cotroller {
|
||||
|
||||
private final ThirdMiniAppService thirdMiniAppService;
|
||||
|
||||
@Operation(summary = "微信小程序登录")
|
||||
@Operation(summary = "小程序登录")
|
||||
@PostMapping("/auto-admin-login")
|
||||
public R<ThirdMinAppOAth2LoginVo> wechatLogin(@RequestBody ThirdMinAppOAth2LoginDto dto) {
|
||||
@Inner(value = false)
|
||||
public R<ThirdMinAppOAth2LoginVo> autoAdminLogin(@RequestBody ThirdMiniAppOAth2LoginDto dto) {
|
||||
return R.ok(thirdMiniAppService.adminLogin(dto));
|
||||
}
|
||||
|
||||
@Operation(summary = "小程序获取用户唯一编码")
|
||||
@PostMapping("/get-unique")
|
||||
@Inner(value = false)
|
||||
public R<String> getUniqueCode(@RequestBody ThirdMiniAppGetUniqueDto dto) {
|
||||
return R.ok(thirdMiniAppService.getUniqueCode(dto));
|
||||
}
|
||||
|
||||
}
|
||||
+11
-3
@@ -1,11 +1,19 @@
|
||||
package com.bsd.pjcloud.thirdparty.service;
|
||||
|
||||
|
||||
import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMinAppOAth2LoginDto;
|
||||
import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMiniAppGetUniqueDto;
|
||||
import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMiniAppOAth2LoginDto;
|
||||
import com.bsd.pjcloud.thirdparty.vo.oathmini.ThirdMinAppOAth2LoginVo;
|
||||
|
||||
public interface ThirdMiniAppService {
|
||||
|
||||
ThirdMinAppOAth2LoginVo adminLogin(ThirdMinAppOAth2LoginDto dto);
|
||||
/**
|
||||
* 小程序登录
|
||||
*/
|
||||
ThirdMinAppOAth2LoginVo adminLogin(ThirdMiniAppOAth2LoginDto dto);
|
||||
|
||||
/**
|
||||
* 小程序获取用户唯一编码
|
||||
*/
|
||||
String getUniqueCode(ThirdMiniAppGetUniqueDto dto);
|
||||
|
||||
}
|
||||
+37
@@ -2,6 +2,18 @@ package com.bsd.pjcloud.thirdparty.service;
|
||||
|
||||
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
|
||||
import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechantReverseDto;
|
||||
import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechatQueryDto;
|
||||
import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechatRefundDto;
|
||||
import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechatRefundQueryDto;
|
||||
import com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat.ThirdMiniWechantReverseVo;
|
||||
import com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat.ThirdMiniWechatQueryVo;
|
||||
import com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat.ThirdMiniWechatRefundQueryVo;
|
||||
import com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat.ThirdMiniWechatRefundVo;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface ThirdMiniAppWechatService {
|
||||
|
||||
@@ -15,4 +27,29 @@ public interface ThirdMiniAppWechatService {
|
||||
*/
|
||||
WxMaPhoneNumberInfo getPhone(String code);
|
||||
|
||||
/**
|
||||
* 查询订单
|
||||
*/
|
||||
ThirdMiniWechatQueryVo query(ThirdMiniWechatQueryDto dto);
|
||||
|
||||
/**
|
||||
* 撤销订单
|
||||
*/
|
||||
ThirdMiniWechantReverseVo reverse(ThirdMiniWechantReverseDto dto);
|
||||
|
||||
/**
|
||||
* 申请退款
|
||||
*/
|
||||
ThirdMiniWechatRefundVo refund(ThirdMiniWechatRefundDto dto);
|
||||
|
||||
/**
|
||||
* 查询退款
|
||||
*/
|
||||
ThirdMiniWechatRefundQueryVo refundQuery(ThirdMiniWechatRefundQueryDto dto);
|
||||
|
||||
/**
|
||||
* 退款回调
|
||||
*/
|
||||
String refundCallback(HttpEntity<String> httpEntity, @RequestHeader Map<String, String> headers);
|
||||
|
||||
}
|
||||
+52
-8
@@ -6,10 +6,14 @@ import com.bsd.pjcloud.admin.api.dto.UserInfo;
|
||||
import com.bsd.pjcloud.admin.api.dto.UserTokenDTO;
|
||||
import com.bsd.pjcloud.admin.api.feign.RemoteTokenService;
|
||||
import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.app.api.constant.AppUserTypeEnum;
|
||||
import com.bsd.pjcloud.app.api.dto.AppAdminSyncDto;
|
||||
import com.bsd.pjcloud.app.api.dto.AppUserInfo;
|
||||
import com.bsd.pjcloud.app.api.feign.RemoteAppUserService;
|
||||
import com.bsd.pjcloud.thirdparty.constant.miniplatform.MiniPlatformLoginErrorEnum;
|
||||
import com.bsd.pjcloud.thirdparty.constant.miniplatform.MiniPlatformTypeEnum;
|
||||
import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMinAppOAth2LoginDto;
|
||||
import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMiniAppGetUniqueDto;
|
||||
import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMiniAppOAth2LoginDto;
|
||||
import com.bsd.pjcloud.thirdparty.service.ThirdMiniAppAliPayService;
|
||||
import com.bsd.pjcloud.thirdparty.service.ThirdMiniAppService;
|
||||
import com.bsd.pjcloud.thirdparty.service.ThirdMiniAppWechatService;
|
||||
@@ -19,6 +23,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -35,28 +40,53 @@ public class ThirdMiniAppServiceImpl implements ThirdMiniAppService {
|
||||
|
||||
private final RemoteUserService remoteUserService;
|
||||
private final RemoteTokenService remoteTokenService;
|
||||
private final RemoteAppUserService remoteAppUserService;
|
||||
|
||||
/**
|
||||
* 小程序登录
|
||||
*/
|
||||
@Override
|
||||
public ThirdMinAppOAth2LoginVo adminLogin(ThirdMinAppOAth2LoginDto dto) {
|
||||
public ThirdMinAppOAth2LoginVo adminLogin(ThirdMiniAppOAth2LoginDto dto) {
|
||||
ThirdMinAppOAth2LoginVo vo = new ThirdMinAppOAth2LoginVo();
|
||||
// 微信小程序
|
||||
if (ObjectUtil.equals(dto.getMiniPlatformType().getType(), MiniPlatformTypeEnum.WECAHT.getType())) {
|
||||
if (ObjectUtil.equals(dto.getMiniPlatformType().getType(), MiniPlatformTypeEnum.WECHAT.getType())) {
|
||||
// 获取手机号
|
||||
WxMaPhoneNumberInfo phoneInfo = thirdMiniAppWechatService.getPhone(dto.getCode());
|
||||
WxMaPhoneNumberInfo phoneInfo = thirdMiniAppWechatService.getPhone(dto.getPhoneCode());
|
||||
if (ObjectUtil.isEmpty(phoneInfo)) {
|
||||
throw new RuntimeException(MiniPlatformLoginErrorEnum.GET_PHONE_ERROR.getType());
|
||||
vo.setErrorCode(MiniPlatformLoginErrorEnum.GET_PHONE_ERROR.getType());
|
||||
return vo;
|
||||
}
|
||||
// 根据手机号查询用户
|
||||
UserInfo userInfo = remoteUserService.getInnerByPhone(phoneInfo.getPurePhoneNumber()).getData();
|
||||
if (ObjectUtil.isEmpty(userInfo)) {
|
||||
throw new RuntimeException(MiniPlatformLoginErrorEnum.USER_NOT_EXIST.getType());
|
||||
vo.setErrorCode(MiniPlatformLoginErrorEnum.USER_NOT_EXIST.getType());
|
||||
return vo;
|
||||
}
|
||||
// 获取用户唯一编号
|
||||
ThirdMiniAppGetUniqueDto getUniqueDto = new ThirdMiniAppGetUniqueDto();
|
||||
getUniqueDto.setMiniPlatformType(MiniPlatformTypeEnum.WECHAT);
|
||||
getUniqueDto.setCode(dto.getPhoneCode());
|
||||
getUniqueDto.setUserId(userInfo.getSysUser().getUserId());
|
||||
String uniqueCode = getUniqueCode(getUniqueDto);
|
||||
// 同步到社交用户
|
||||
AppAdminSyncDto appAdminSyncDto = new AppAdminSyncDto();
|
||||
appAdminSyncDto.setUniqueCode(uniqueCode);
|
||||
appAdminSyncDto.setUserTypeEnum(AppUserTypeEnum.MINI_WECHAT);
|
||||
appAdminSyncDto.setAdminUserId(userInfo.getSysUser().getUserId());
|
||||
appAdminSyncDto.setUsername(userInfo.getSysUser().getUsername());
|
||||
appAdminSyncDto.setAvatarImage(userInfo.getSysUser().getAvatar());
|
||||
AppUserInfo appUserInfo = remoteAppUserService.syncAdminAccountInfo(appAdminSyncDto).getData();
|
||||
if (ObjectUtil.isEmpty(appUserInfo)) {
|
||||
vo.setErrorCode(MiniPlatformLoginErrorEnum.LOGIN_ERROR.getType());
|
||||
return vo;
|
||||
}
|
||||
// 执行登录
|
||||
UserTokenDTO userTokenDTO = new UserTokenDTO();
|
||||
userTokenDTO.setSysUser(userInfo.getSysUser());
|
||||
Map<String, Object> dataMap = (Map<String, Object>) remoteTokenService.generateToken(userTokenDTO).getData();
|
||||
if (ObjectUtil.isEmpty(dataMap)) {
|
||||
throw new RuntimeException(MiniPlatformLoginErrorEnum.LOGIN_ERROR.getType());
|
||||
vo.setErrorCode(MiniPlatformLoginErrorEnum.LOGIN_ERROR.getType());
|
||||
return vo;
|
||||
}
|
||||
vo.setAccessToken(String.valueOf(dataMap.getOrDefault("accessToken", "")));
|
||||
vo.setRefreshToken(String.valueOf(dataMap.getOrDefault("refreshToken", "")));
|
||||
@@ -68,4 +98,18 @@ public class ThirdMiniAppServiceImpl implements ThirdMiniAppService {
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 小程序获取用户唯一编码
|
||||
*/
|
||||
@Override
|
||||
public String getUniqueCode(ThirdMiniAppGetUniqueDto dto) {
|
||||
String uniqueCode = null;
|
||||
if (ObjectUtil.equals(dto.getMiniPlatformType().getType(), MiniPlatformTypeEnum.WECHAT.getType())) {
|
||||
uniqueCode = thirdMiniAppWechatService.getOpenId(dto.getCode());
|
||||
} else if (ObjectUtil.equals(dto.getMiniPlatformType().getType(), MiniPlatformTypeEnum.ALI_PAY.getType())) {
|
||||
|
||||
}
|
||||
return uniqueCode;
|
||||
}
|
||||
|
||||
}
|
||||
+311
-1
@@ -3,14 +3,37 @@ package com.bsd.pjcloud.thirdparty.service.impl.miniapp;
|
||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.XmlUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.bsd.pjcloud.thirdparty.config.MiniAppConfig;
|
||||
import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechantReverseDto;
|
||||
import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechatQueryDto;
|
||||
import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechatRefundDto;
|
||||
import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechatRefundQueryDto;
|
||||
import com.bsd.pjcloud.thirdparty.service.ThirdMiniAppWechatService;
|
||||
import com.bsd.pjcloud.thirdparty.utils.miniapp.pay.wechat.ThirdMiniWechantPayConstant;
|
||||
import com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.net.ssl.*;
|
||||
import java.io.FileInputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.KeyStore;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* 微信小程序(小程序版本)
|
||||
*/
|
||||
@@ -20,7 +43,7 @@ import org.springframework.validation.annotation.Validated;
|
||||
@RequiredArgsConstructor
|
||||
public class ThirdMiniAppWechatServiceImpl implements ThirdMiniAppWechatService {
|
||||
|
||||
private final String TAG = "微信小程序(小程序版本)";
|
||||
private final String TAG = "微信小程序支付(小程序版本)";
|
||||
|
||||
private final MiniAppConfig miniAppConfig;
|
||||
|
||||
@@ -62,4 +85,291 @@ public class ThirdMiniAppWechatServiceImpl implements ThirdMiniAppWechatService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询订单
|
||||
*/
|
||||
@Override
|
||||
public ThirdMiniWechatQueryVo query(ThirdMiniWechatQueryDto dto) {
|
||||
MiniAppConfig.WechatConfig wechatConfig = miniAppConfig.getWechatConfig();
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
// 公众账号ID
|
||||
params.put("appid", wechatConfig.getAppId());
|
||||
// 商户号
|
||||
params.put("mch_id", wechatConfig.getMerchantId());
|
||||
// 微信订单号
|
||||
params.put("transaction_id", dto.getWechantOrderId());
|
||||
// 商户订单号
|
||||
params.put("out_trade_no", dto.getOrderId());
|
||||
// 随机字符串
|
||||
params.put("nonce_str", getNonceStr());
|
||||
// 签名
|
||||
params.put("sign", "");
|
||||
// 签名类型
|
||||
params.put("sign_type", "MD5");
|
||||
// 生成签名
|
||||
params.put("sign", generateSign(params));
|
||||
ThirdMiniWechantPayConstant.Api api = initApi(ThirdMiniWechantPayConstant.QUERY);
|
||||
String res = api.getHttpRequest().body(XmlUtil.mapToXmlStr(params)).execute().body();
|
||||
log.debug("查询订单,json,xml|{}", res);
|
||||
if (ObjectUtil.isEmpty(res)) {
|
||||
log.error("查询订单,res为空");
|
||||
return null;
|
||||
}
|
||||
ThirdMiniWechatQueryVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(res)), ThirdMiniWechatQueryVo.class);
|
||||
log.debug("|{}|查询订单,json,res|{}", TAG, JSONUtil.toJsonStr(vo));
|
||||
if (!vo.isHttpSucess()) {
|
||||
return null;
|
||||
}
|
||||
return vo;
|
||||
} catch (Exception e) {
|
||||
log.error("|{}|查询订单,异常", TAG, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤销订单
|
||||
*/
|
||||
@Override
|
||||
public ThirdMiniWechantReverseVo reverse(ThirdMiniWechantReverseDto dto) {
|
||||
MiniAppConfig.WechatConfig wechatConfig = miniAppConfig.getWechatConfig();
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
// 公众账号ID
|
||||
params.put("appid", wechatConfig.getAppId());
|
||||
// 商户号
|
||||
params.put("mch_id", wechatConfig.getMerchantId());
|
||||
// 微信订单号
|
||||
params.put("transaction_id", dto.getWechantOrderId());
|
||||
// 商户订单号
|
||||
params.put("out_trade_no", dto.getOrderId());
|
||||
// 随机字符串
|
||||
params.put("nonce_str", getNonceStr());
|
||||
// 签名
|
||||
params.put("sign", "");
|
||||
// 签名类型
|
||||
params.put("sign_type", "MD5");
|
||||
// 生成签名
|
||||
params.put("sign", generateSign(params));
|
||||
ThirdMiniWechantPayConstant.Api api = initApi(ThirdMiniWechantPayConstant.REVERSE);
|
||||
api.setSslSocketFactory(createSSLSocketFactory());
|
||||
String res = api.getHttpRequest().body(XmlUtil.mapToXmlStr(params)).execute().body();
|
||||
log.debug("|{}|撤销订单,json,xml|{}", TAG, res);
|
||||
if (ObjectUtil.isEmpty(res)) {
|
||||
log.error("|{}|撤销订单,res为空", TAG);
|
||||
return null;
|
||||
}
|
||||
ThirdMiniWechantReverseVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(res)), ThirdMiniWechantReverseVo.class);
|
||||
log.debug("|{}|撤销订单,json,res|{}", TAG, JSONUtil.toJsonStr(vo));
|
||||
if (!vo.isHttpSucess()) {
|
||||
return null;
|
||||
}
|
||||
return vo;
|
||||
} catch (Exception e) {
|
||||
log.error("|{}|撤销订单,异常", TAG, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 申请退款
|
||||
*/
|
||||
@Override
|
||||
public ThirdMiniWechatRefundVo refund(ThirdMiniWechatRefundDto dto) {
|
||||
MiniAppConfig.WechatConfig wechatConfig = miniAppConfig.getWechatConfig();
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
// 公众账号ID
|
||||
params.put("appid", wechatConfig.getAppId());
|
||||
// 商户号
|
||||
params.put("mch_id", wechatConfig.getMerchantId());
|
||||
// 随机字符串
|
||||
params.put("nonce_str", getNonceStr());
|
||||
// 签名
|
||||
params.put("sign", "");
|
||||
// 签名类型
|
||||
params.put("sign_type", "MD5");
|
||||
// 微信支付订单号
|
||||
params.put("transaction_id", dto.getWechantOrderId());
|
||||
// 商户订单号
|
||||
params.put("out_trade_no", dto.getOrderId());
|
||||
// 商户退款单号
|
||||
params.put("out_refund_no", dto.getRefundId());
|
||||
// 订单金额
|
||||
params.put("total_fee", dto.getOrderPrice());
|
||||
// 退款金额
|
||||
params.put("refund_fee", dto.getRefundPrice());
|
||||
// 退款结果通知url
|
||||
params.put("notify_url", wechatConfig.getRefundCallbackUrl());
|
||||
// 生成签名
|
||||
params.put("sign", generateSign(params));
|
||||
ThirdMiniWechantPayConstant.Api api = initApi(ThirdMiniWechantPayConstant.REFUND);
|
||||
api.setSslSocketFactory(createSSLSocketFactory());
|
||||
String res = api.getHttpRequest().body(XmlUtil.mapToXmlStr(params)).execute().body();
|
||||
log.debug("|{}|申请退款,json,xml|{}", TAG, res);
|
||||
if (ObjectUtil.isEmpty(res)) {
|
||||
log.error("|{}|申请退款,res为空", TAG);
|
||||
return null;
|
||||
}
|
||||
ThirdMiniWechatRefundVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(res)), ThirdMiniWechatRefundVo.class);
|
||||
log.debug("|{}|申请退款,json,res|{}", TAG, JSONUtil.toJsonStr(vo));
|
||||
if (!vo.isHttpSucess()) {
|
||||
return null;
|
||||
}
|
||||
return vo;
|
||||
} catch (Exception e) {
|
||||
log.error("|{}|申请退款,异常", TAG, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询退款
|
||||
*/
|
||||
@Override
|
||||
public ThirdMiniWechatRefundQueryVo refundQuery(ThirdMiniWechatRefundQueryDto dto) {
|
||||
MiniAppConfig.WechatConfig wechatConfig = miniAppConfig.getWechatConfig();
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
// 公众账号ID
|
||||
params.put("appid", wechatConfig.getAppId());
|
||||
// 商户号
|
||||
params.put("mch_id", wechatConfig.getMerchantId());
|
||||
// 随机字符串
|
||||
params.put("nonce_str", getNonceStr());
|
||||
// 签名
|
||||
params.put("sign", "");
|
||||
// 签名类型
|
||||
params.put("sign_type", "MD5");
|
||||
// 签名类型
|
||||
params.put("out_refund_no", dto.getRefundId());
|
||||
// 生成签名
|
||||
params.put("sign", generateSign(params));
|
||||
ThirdMiniWechantPayConstant.Api api = initApi(ThirdMiniWechantPayConstant.REFUND_QUERY);
|
||||
String res = api.getHttpRequest().body(XmlUtil.mapToXmlStr(params)).execute().body();
|
||||
log.debug("|{}|查询退款,json,xml|{}", TAG, res);
|
||||
if (ObjectUtil.isEmpty(res)) {
|
||||
log.error("|{}|查询退款,res为空", TAG);
|
||||
return null;
|
||||
}
|
||||
ThirdMiniWechatRefundQueryVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(res)), ThirdMiniWechatRefundQueryVo.class);
|
||||
log.debug("|{}|查询退款,json,res|{}", TAG, JSONUtil.toJsonStr(vo));
|
||||
if (!vo.isHttpSucess()) {
|
||||
return null;
|
||||
}
|
||||
return vo;
|
||||
} catch (Exception e) {
|
||||
log.error("|{}|查询退款,异常", TAG, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款回调
|
||||
*/
|
||||
@Override
|
||||
public String refundCallback(HttpEntity<String> httpEntity, Map<String, String> headers) {
|
||||
String body = httpEntity.getBody();
|
||||
ThirdMiniWechantRefunCallbackVo decrypt = decrypt(body);
|
||||
if (ObjectUtil.isEmpty(decrypt)) {
|
||||
// 告诉微信错误
|
||||
return ThirdMiniWechantRefunCallbackVo.wechantError();
|
||||
}
|
||||
boolean isSuccess = true;
|
||||
return isSuccess ? ThirdMiniWechantRefunCallbackVo.wechantSuccess() : ThirdMiniWechantRefunCallbackVo.wechantError();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密回调信息解密
|
||||
*/
|
||||
private ThirdMiniWechantRefunCallbackVo decrypt(String xml) {
|
||||
MiniAppConfig.WechatConfig wechatConfig = miniAppConfig.getWechatConfig();
|
||||
try {
|
||||
ThirdMiniWechantRefunCallbackSoureVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(xml)), ThirdMiniWechantRefunCallbackSoureVo.class);
|
||||
String reqInfo = vo.getReq_info();
|
||||
// 1 对加密串A做base64解码,得到加密串B
|
||||
byte[] encryptedBytes = Base64.decode(reqInfo);
|
||||
// 2 对商户key做md5,得到32位小写key
|
||||
String md5Key = DigestUtils.md5Hex(wechatConfig.getApiV2Key()).toLowerCase();
|
||||
// 3. AES-256-ECB 解密
|
||||
SecretKeySpec secretKey = new SecretKeySpec(md5Key.getBytes(StandardCharsets.UTF_8), "AES");
|
||||
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey);
|
||||
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
|
||||
String json = new String(decryptedBytes, StandardCharsets.UTF_8);
|
||||
ThirdMiniWechantRefunCallbackVo entity = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(json)), ThirdMiniWechantRefunCallbackVo.class);
|
||||
log.debug("|{}|解密回调信息,json|{}", TAG, JSONUtil.toJsonStr(entity));
|
||||
return entity;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error("|{}|解密回调信息解密异常", TAG, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成微信支付签名
|
||||
*/
|
||||
public String generateSign(Map<String, Object> params) {
|
||||
String apiKey = miniAppConfig.getWechatConfig().getApiV2Key();
|
||||
Map<String, String> filtered = new TreeMap<>();
|
||||
for (Map.Entry<String, Object> entry : params.entrySet()) {
|
||||
if (ObjectUtil.isEmpty(entry.getValue()) || ObjectUtil.equals("sign", entry.getKey())) {
|
||||
continue;
|
||||
}
|
||||
filtered.put(entry.getKey(), String.valueOf(entry.getValue()));
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : filtered.entrySet()) {
|
||||
sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
|
||||
}
|
||||
sb.append("key=").append(apiKey);
|
||||
try {
|
||||
String sign = DigestUtils.md5Hex(String.valueOf(sb));
|
||||
return sign.toUpperCase();
|
||||
} catch (Exception e) {
|
||||
log.error("|{}|微信支付签名生成失败", TAG, e);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private ThirdMiniWechantPayConstant.Api initApi(ThirdMiniWechantPayConstant.Api api) {
|
||||
api.setBaseUrl(miniAppConfig.getWechatConfig().getBaseUrl());
|
||||
return api;
|
||||
}
|
||||
|
||||
private String getNonceStr() {
|
||||
int length = 32;
|
||||
return RandomUtil.randomString(length);
|
||||
}
|
||||
|
||||
private SSLSocketFactory createSSLSocketFactory() throws Exception {
|
||||
KeyStore keyStore = KeyStore.getInstance("PKCS12");
|
||||
FileInputStream certStream = new FileInputStream(miniAppConfig.getWechatConfig().getMerchantSerialPath());
|
||||
keyStore.load(certStream, miniAppConfig.getWechatConfig().getMerchantId().toCharArray());
|
||||
certStream.close();
|
||||
// 创建KeyManagerFactory
|
||||
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
keyManagerFactory.init(keyStore, miniAppConfig.getWechatConfig().getMerchantId().toCharArray());
|
||||
// 创建TrustManagerFactory(信任所有证书)
|
||||
TrustManager[] trustManagers = new TrustManager[]{
|
||||
new X509TrustManager() {
|
||||
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
|
||||
}
|
||||
|
||||
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
|
||||
}
|
||||
}
|
||||
};
|
||||
// 创建SSLContext
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagers, new SecureRandom());
|
||||
return sslContext.getSocketFactory();
|
||||
}
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package com.bsd.pjcloud.thirdparty.utils.miniapp.pay.wechat;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
/**
|
||||
* 微信支付api
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ThirdMiniWechantPayConstant {
|
||||
|
||||
public static final Api APY = Api.builder().summary("付款码支付").url("/pay/micropay").method(HttpMethod.POST).isNeedCertificate(false).build();
|
||||
|
||||
public static final Api QUERY = Api.builder().summary("查询订单").url("/pay/orderquery").method(HttpMethod.POST).isNeedCertificate(false).build();
|
||||
|
||||
public static final Api REVERSE = Api.builder().summary("撤销订单").url("/secapi/pay/reverse").method(HttpMethod.POST).isNeedCertificate(true).build();
|
||||
|
||||
public static final Api REFUND = Api.builder().summary("申请退款").url("/secapi/pay/refund").method(HttpMethod.POST).isNeedCertificate(true).build();
|
||||
|
||||
public static final Api REFUND_QUERY = Api.builder().summary("查询退款").url("/pay/refundquery").method(HttpMethod.POST).isNeedCertificate(false).build();
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
static public class Api {
|
||||
|
||||
private String summary;
|
||||
|
||||
private String baseUrl;
|
||||
|
||||
private String url;
|
||||
|
||||
private String fullUrl;
|
||||
|
||||
private HttpMethod method;
|
||||
|
||||
private boolean isNeedCertificate = false;
|
||||
|
||||
private SSLSocketFactory sslSocketFactory;
|
||||
|
||||
public HttpRequest getHttpRequest() {
|
||||
String fullUrl = baseUrl + url;
|
||||
HttpRequest req = switch (method.name()) {
|
||||
case "GET" -> HttpRequest.get(fullUrl);
|
||||
case "POST" -> HttpRequest.post(fullUrl);
|
||||
default -> null;
|
||||
};
|
||||
if (ObjectUtil.isNotEmpty(req) && ObjectUtil.isNotEmpty(sslSocketFactory) && isNeedCertificate) {
|
||||
req.setSSLSocketFactory(sslSocketFactory);
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -179,5 +179,11 @@ mini-platform:
|
||||
wechat-config:
|
||||
app-id: wx11771c7bf2913cb2
|
||||
app-secret: a6b0d036b229117595687a7c1705d332
|
||||
merchant-id: 1106210589
|
||||
api-v2-key: qr0w9WkAu6GG3uuxPjDT7bcdIVoBr0rw
|
||||
merchant-serial-path: /Users/dengzhangchen/Desktop/backups/pay/cert/apiclient_cert.p12
|
||||
refund-callback-url: https://rj4jv5rwqs.by.takin.cc/hard/hard-wechant-pay/callback/refund
|
||||
spbill-create-ip: 59.202.170.152
|
||||
base-url: https://api.mch.weixin.qq.com
|
||||
ali-pay-config:
|
||||
app-id:
|
||||
Reference in new issue
Block a user