feat: 增加access_token过滤器

This commit is contained in:
TS-QD1 2025-03-28 11:13:01 +08:00
parent dd56d1415f
commit a0353c62e6
27 changed files with 950 additions and 51 deletions

View File

@ -1,4 +1,17 @@
# 增加微信支付回调
# 20250325
## user_expand
```sql
ALTER TABLE `sys_user_expand`
ADD COLUMN `wx_miniapp_app_id` varchar(255) NULL COMMENT '微信-小程序-appid' AFTER `main_user_id`,
ADD COLUMN `wx_miniapp_open_id` varchar(255) NULL COMMENT '微信-小程序-openid' AFTER `wx_miniapp_app_id`,
ADD COLUMN `wx_miniapp_session_key` varchar(255) NULL COMMENT '微信-小程序-sessionkey' AFTER `wx_miniapp_open_id`,
ADD COLUMN `wx_official_account_app_id` varchar(255) NULL COMMENT '微信-公众号-appid' AFTER `wx_miniapp_session_key`,
ADD COLUMN `wx_official_account_open_id` varchar(255) NULL COMMENT '微信-公众号-openid' AFTER `wx_official_account_app_id`;
```
# 增加微信支付回调 (已上线)
微信支付增加支付成功后系统回调通知

View File

@ -0,0 +1,39 @@
package cn.com.tenlion.operator.controller.api.user.wx;
import cn.com.tenlion.operator.pojo.dtos.user.wx.UserWxLoginDTO;
import cn.com.tenlion.operator.pojo.vos.user.wx.UserWxLoginVO;
import cn.com.tenlion.operator.pojo.vos.user.wx.UserWxRegisterVO;
import cn.com.tenlion.operator.service.user.wx.UserWxMiniappService;
import ink.wgink.annotation.CheckRequestBodyAnnotation;
import ink.wgink.common.base.DefaultBaseController;
import ink.wgink.interfaces.consts.ISystemConstant;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@Api(tags = ISystemConstant.API_TAGS_SYSTEM_PREFIX + "微信用户接口")
@RestController
@RequestMapping(ISystemConstant.API_PREFIX + "/user/wx")
public class UserWxController extends DefaultBaseController {
@Autowired
private UserWxMiniappService userWxMiniappService;
@PostMapping("login")
@CheckRequestBodyAnnotation
public UserWxLoginDTO login(@RequestBody UserWxLoginVO userWxLoginVO) {
return userWxMiniappService.login(userWxLoginVO.getJsCode());
}
@PostMapping("register")
@CheckRequestBodyAnnotation
public UserWxLoginDTO register(@RequestBody UserWxRegisterVO userWxRegisterVO) {
return userWxMiniappService.register(userWxRegisterVO.getOpenid(), userWxRegisterVO.getCode());
}
}

View File

@ -27,6 +27,10 @@ public interface IUserExpandDao {
void updateRelationRebateRatio(Map<String, Object> params);
void updateWxMiniappOpenId(Map<String, Object> params);
void updateWxOfficialAccountOpenId(Map<String, Object> params);
UserExpandDTO get(Map<String, Object> params);
UserExpandPO getPO(Map<String, Object> params);

View File

@ -0,0 +1,62 @@
package cn.com.tenlion.operator.pojo.dtos.user.wx;
public class UserWxLoginDTO {
private String openid;
private String accessToken;
private Integer isNew;
private String phone;
public UserWxLoginDTO() {
}
public UserWxLoginDTO(String openid, Integer isNew) {
this.openid = openid;
this.isNew = isNew;
}
public UserWxLoginDTO(String openid, String accessToken, Integer isNew) {
this.openid = openid;
this.accessToken = accessToken;
this.isNew = isNew;
}
public UserWxLoginDTO(String openid, String accessToken, Integer isNew, String phone) {
this.openid = openid;
this.accessToken = accessToken;
this.isNew = isNew;
this.phone = phone;
}
public String getOpenid() {
return openid == null ? "" : openid.trim();
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getAccessToken() {
return accessToken == null ? "" : accessToken.trim();
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public Integer getIsNew() {
return isNew == null ? 0 : isNew;
}
public void setIsNew(Integer isNew) {
this.isNew = isNew;
}
public String getPhone() {
return phone == null ? "" : phone.trim();
}
public void setPhone(String phone) {
this.phone = phone;
}
}

View File

@ -35,6 +35,10 @@ public class UserExpandPO {
private Integer relationIcRebateRatio;
private String relationIcTime;
private String relationIcUserId;
private String subUserIds;
private String mainUserId;
private String wxMiniappOpenId;
private String wxOfficialAccountOpenId;
public String getUserId() {
return userId == null ? "" : userId.trim();
@ -227,4 +231,36 @@ public class UserExpandPO {
public void setRelationIcUserId(String relationIcUserId) {
this.relationIcUserId = relationIcUserId;
}
public String getWxMiniappOpenId() {
return wxMiniappOpenId == null ? "" : wxMiniappOpenId.trim();
}
public void setWxMiniappOpenId(String wxMiniappOpenId) {
this.wxMiniappOpenId = wxMiniappOpenId;
}
public String getSubUserIds() {
return subUserIds == null ? "" : subUserIds.trim();
}
public void setSubUserIds(String subUserIds) {
this.subUserIds = subUserIds;
}
public String getMainUserId() {
return mainUserId == null ? "" : mainUserId.trim();
}
public void setMainUserId(String mainUserId) {
this.mainUserId = mainUserId;
}
public String getWxOfficialAccountOpenId() {
return wxOfficialAccountOpenId == null ? "" : wxOfficialAccountOpenId.trim();
}
public void setWxOfficialAccountOpenId(String wxOfficialAccountOpenId) {
this.wxOfficialAccountOpenId = wxOfficialAccountOpenId;
}
}

View File

@ -39,6 +39,8 @@ public class UserExpandVO {
private Double icPriceAll;
private Double icPriceMaterial;
private Integer icRebateRatio;
private String wxMiniappOpenId;
private String wxOfficialAccountOpenId;
/**
* 子账号ID集合
@ -192,4 +194,20 @@ public class UserExpandVO {
public void setIcRebateRatio(Integer icRebateRatio) {
this.icRebateRatio = icRebateRatio;
}
public String getWxMiniappOpenId() {
return wxMiniappOpenId == null ? "" : wxMiniappOpenId.trim();
}
public void setWxMiniappOpenId(String wxMiniappOpenId) {
this.wxMiniappOpenId = wxMiniappOpenId;
}
public String getWxOfficialAccountOpenId() {
return wxOfficialAccountOpenId == null ? "" : wxOfficialAccountOpenId.trim();
}
public void setWxOfficialAccountOpenId(String wxOfficialAccountOpenId) {
this.wxOfficialAccountOpenId = wxOfficialAccountOpenId;
}
}

View File

@ -0,0 +1,20 @@
package cn.com.tenlion.operator.pojo.vos.user.wx;
import ink.wgink.annotation.CheckEmptyAnnotation;
import io.swagger.annotations.ApiModel;
@ApiModel
public class UserWxLoginVO {
@CheckEmptyAnnotation(name = "jsCode")
private String jsCode;
public String getJsCode() {
return jsCode == null ? "" : jsCode.trim();
}
public void setJsCode(String jsCode) {
this.jsCode = jsCode;
}
}

View File

@ -0,0 +1,29 @@
package cn.com.tenlion.operator.pojo.vos.user.wx;
import ink.wgink.annotation.CheckEmptyAnnotation;
import io.swagger.annotations.ApiModel;
@ApiModel
public class UserWxRegisterVO {
@CheckEmptyAnnotation(name = "openid")
private String openid;
@CheckEmptyAnnotation(name = "code")
private String code;
public String getOpenid() {
return openid == null ? "" : openid.trim();
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getCode() {
return code == null ? "" : code.trim();
}
public void setCode(String code) {
this.code = code;
}
}

View File

@ -0,0 +1,28 @@
package cn.com.tenlion.operator.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "wx-miniapp")
public class WxMiniappProperties {
private String appid;
private String appsecret;
public String getAppid() {
return appid == null ? "" : appid.trim();
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getAppsecret() {
return appsecret == null ? "" : appsecret.trim();
}
public void setAppsecret(String appsecret) {
this.appsecret = appsecret;
}
}

View File

@ -0,0 +1,59 @@
package cn.com.tenlion.operator.remote.wx;
import cn.com.tenlion.operator.remote.wx.entity.WxAccessToken;
import cn.com.tenlion.operator.remote.wx.entity.WxLoginResult;
import cn.com.tenlion.operator.remote.wx.entity.WxPhoneResult;
import ink.wgink.annotation.rpc.rest.RemoteService;
import ink.wgink.annotation.rpc.rest.method.RemoteGetMethod;
import ink.wgink.annotation.rpc.rest.method.RemotePostMethod;
import ink.wgink.annotation.rpc.rest.params.RemoteJsonBodyParams;
import ink.wgink.annotation.rpc.rest.params.RemoteQueryParams;
import ink.wgink.annotation.rpc.rest.params.RemoteServerParams;
import java.util.Map;
@RemoteService
public interface IWxMiniappRemoteService {
/**
* 获取access_token
*
* @param server
* @param params
* @return
*/
@RemotePostMethod("/cgi-bin/stable_token")
WxAccessToken getAccessToken(@RemoteServerParams String server,
@RemoteJsonBodyParams Map<String, Object> params);
/**
* 登录
*
* @param server
* @param appId
* @param secret
* @param jsCode
* @param grant_type
* @return
*/
@RemoteGetMethod("/sns/jscode2session")
WxLoginResult login(@RemoteServerParams String server,
@RemoteQueryParams("appid") String appId,
@RemoteQueryParams("secret") String secret,
@RemoteQueryParams("js_code") String jsCode,
@RemoteQueryParams("grant_type") String grant_type);
/**
* 获取手机号
*
* @param server
* @param accessToken
* @param params
* @return
*/
@RemotePostMethod("/wxa/business/getuserphonenumber")
WxPhoneResult getPhone(@RemoteServerParams String server,
@RemoteQueryParams("access_token") String accessToken,
@RemoteJsonBodyParams Map<String, Object> params);
}

View File

@ -0,0 +1,23 @@
package cn.com.tenlion.operator.remote.wx.entity;
public class WxAccessToken {
private String access_token;
private Integer expires_in;
public String getAccess_token() {
return access_token == null ? "" : access_token.trim();
}
public void setAccess_token(String access_token) {
this.access_token = access_token;
}
public Integer getExpires_in() {
return expires_in == null ? 0 : expires_in;
}
public void setExpires_in(Integer expires_in) {
this.expires_in = expires_in;
}
}

View File

@ -0,0 +1,32 @@
package cn.com.tenlion.operator.remote.wx.entity;
public class WxLoginResult extends WxResult {
private String openid;
private String unionid;
private String session_key;
public String getOpenid() {
return openid == null ? "" : openid.trim();
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getUnionid() {
return unionid == null ? "" : unionid.trim();
}
public void setUnionid(String unionid) {
this.unionid = unionid;
}
public String getSession_key() {
return session_key == null ? "" : session_key.trim();
}
public void setSession_key(String session_key) {
this.session_key = session_key;
}
}

View File

@ -0,0 +1,32 @@
package cn.com.tenlion.operator.remote.wx.entity;
public class WxMiniappAccessToken {
private WxAccessToken wxAccessToken;
private Long updateTime;
public WxMiniappAccessToken() {
}
public WxMiniappAccessToken(WxAccessToken wxAccessToken, Long updateTime) {
this.wxAccessToken = wxAccessToken;
this.updateTime = updateTime;
}
public WxAccessToken getWxAccessToken() {
return wxAccessToken;
}
public void setWxAccessToken(WxAccessToken wxAccessToken) {
this.wxAccessToken = wxAccessToken;
}
public Long getUpdateTime() {
return updateTime == null ? 0 : updateTime;
}
public void setUpdateTime(Long updateTime) {
this.updateTime = updateTime;
}
}

View File

@ -0,0 +1,54 @@
package cn.com.tenlion.operator.remote.wx.entity;
public class WxPhoneResult extends WxResult {
private PhoneInfo phone_info;
public PhoneInfo getPhone_info() {
return phone_info;
}
public void setPhone_info(PhoneInfo phone_info) {
this.phone_info = phone_info;
}
public static class PhoneInfo {
private String phoneNumber;
private String purePhoneNumber;
private String countryCode;
private Watermark watermark;
public String getPhoneNumber() {
return phoneNumber == null ? "" : phoneNumber.trim();
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPurePhoneNumber() {
return purePhoneNumber == null ? "" : purePhoneNumber.trim();
}
public void setPurePhoneNumber(String purePhoneNumber) {
this.purePhoneNumber = purePhoneNumber;
}
public String getCountryCode() {
return countryCode == null ? "" : countryCode.trim();
}
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
public Watermark getWatermark() {
return watermark;
}
public void setWatermark(Watermark watermark) {
this.watermark = watermark;
}
}
}

View File

@ -0,0 +1,44 @@
package cn.com.tenlion.operator.remote.wx.entity;
public class WxResult {
private Integer errcode;
private String errmsg;
public Integer getErrcode() {
return errcode == null ? 0 : errcode;
}
public void setErrcode(Integer errcode) {
this.errcode = errcode;
}
public String getErrmsg() {
return errmsg == null ? "" : errmsg.trim();
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
public static class Watermark {
private Long timestamp;
private String appid;
public Long getTimestamp() {
return timestamp == null ? 0 : timestamp;
}
public void setTimestamp(Long timestamp) {
this.timestamp = timestamp;
}
public String getAppid() {
return appid == null ? "" : appid.trim();
}
public void setAppid(String appid) {
this.appid = appid;
}
}
}

View File

@ -55,7 +55,9 @@ public class UserRegisterService implements IRegisterHandlerService, IRegisterWi
// 3.初始化个人信息
iAccountService.saveCreate(roleName, userId);
// 4.初始化用户拓展信息
userExpandService.saveOrUpdate(userId, new UserExpandVO());
UserExpandVO userExpandVO = new UserExpandVO();
userExpandVO.setWxMiniappOpenId(requestParams.get("wxMiniappOpenId") == null ? "" : requestParams.get("wxMiniappOpenId").toString());
userExpandService.saveOrUpdate(userId, userExpandVO);
}
@Override

View File

@ -0,0 +1,64 @@
package cn.com.tenlion.operator.service.accesstoken;
import com.alibaba.fastjson.JSONObject;
import ink.wgink.app.AppTokenManager;
import ink.wgink.app.impl.DefaultAppTokenServiceImpl;
import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.exceptions.SearchException;
import ink.wgink.exceptions.base.SystemException;
import ink.wgink.module.oauth2.filter.AccessTokenFilter;
import ink.wgink.pojo.app.AppToken;
import ink.wgink.pojo.app.AppTokenUser;
import ink.wgink.pojo.bos.UserInfoBO;
import ink.wgink.pojo.dtos.role.RoleSimpleDTO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.stream.Collectors;
@Service
public class AccessTokenService extends DefaultBaseService implements AccessTokenFilter.IAccessTokenCheckFilter {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
private DefaultAppTokenServiceImpl defaultAppTokenService;
@Override
public UserInfoBO getUserInfo(String accessToken) {
AppTokenUser appTokenUser = AppTokenManager.getInstance().parseToAppTokenUser(accessToken);
UserInfoBO userInfoBO = new UserInfoBO();
userInfoBO.setUserId(appTokenUser.getId());
userInfoBO.setUserUsername(appTokenUser.getUsername());
userInfoBO.setUserName(appTokenUser.getName());
userInfoBO.setUserPhone(appTokenUser.getPhone());
userInfoBO.setUserEmail(appTokenUser.getEmail());
userInfoBO.setRoles(appTokenUser.getRoles().stream().map(role -> {
RoleSimpleDTO roleSimpleDTO = new RoleSimpleDTO();
roleSimpleDTO.setRoleId(role.getRoleId());
roleSimpleDTO.setRoleName(role.getRoleName());
return roleSimpleDTO;
}).collect(Collectors.toList()));
// 先检查access_token是否过期
checkAccessToken(userInfoBO.getUserId());
// 在更新超时时间
set2Redis(userInfoBO.getUserId(), accessToken);
return userInfoBO;
}
public void checkAccessToken(String userId) {
String accessToken = redisTemplate.opsForValue().get("access_token:" + userId);
if (StringUtils.isBlank(accessToken)) {
throw new SystemException("access_token不存在请重新登录");
}
}
public void set2Redis(String userId, String accessToken) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("access_token", accessToken);
jsonObject.put("expired_time", System.currentTimeMillis() + 7200000);
redisTemplate.opsForValue().set("access_token:" + userId, jsonObject.toJSONString());
}
}

View File

@ -141,6 +141,9 @@ public class AccountServiceImpl extends DefaultBaseService implements IAccountSe
@Override
public AccountDTO get(Map<String, Object> params) {
AccountDTO accountDTO = accountDao.get(params);
if (accountDTO == null) {
return null;
}
accountDTO.setAccountMoneyDouble(PayUtil.buiderMoney(accountDTO.getAccountMoney()));
return accountDTO;
}

View File

@ -1,26 +1,32 @@
package cn.com.tenlion.operator.service.login.handler;
import cn.com.tenlion.operator.pojo.pos.user.expand.UserExpandPO;
import cn.com.tenlion.operator.service.accesstoken.AccessTokenService;
import cn.com.tenlion.operator.service.user.expand.UserExpandServiceImpl;
import ink.wgink.interfaces.expand.login.ILoginHandlerService;
import ink.wgink.interfaces.user.IUserExpandBaseService;
import ink.wgink.login.app.service.appsign.impl.AppSignServiceImpl;
import ink.wgink.login.base.service.BaseAppSignService;
import ink.wgink.pojo.bos.LoginUser;
import ink.wgink.service.user.pojo.pos.UserPO;
import ink.wgink.service.user.service.IUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class LoginHandlerServiceImpl implements ILoginHandlerService {
public class LoginHandlerServiceImpl extends BaseAppSignService implements ILoginHandlerService {
@Autowired
private UserExpandServiceImpl userExpandService;
@Autowired
private AccessTokenService accessTokenService;
@Override
public void handle(LoginUser loginUser) throws Exception {
userExpandService.updateRedis(loginUser.getUserId());
// UserExpandPO po = userExpandService.getPO(loginUser.getUserId());
// if (po == null) {
// po = new UserExpandPO();
// }
// loginUser.setExpandData(po);
UserPO userPO = new UserPO();
BeanUtils.copyProperties(loginUser, userPO);
accessTokenService.set2Redis(loginUser.getUserId(), getToken(userPO));
}
}

View File

@ -1,5 +1,6 @@
package cn.com.tenlion.operator.service.quick.login;
import cn.com.tenlion.operator.service.accesstoken.AccessTokenService;
import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.common.manager.env.EnvManager;
import ink.wgink.exceptions.base.SystemException;
@ -30,6 +31,9 @@ public class QuickLoginService extends DefaultBaseService {
private IRegisterService registerService;
@Autowired
private IAppSignService appSignService;
@Autowired
private AccessTokenService accessTokenService;
/**
* 新增和登录
@ -45,10 +49,13 @@ public class QuickLoginService extends DefaultBaseService {
registerService.registerPhone(registerPhoneVO, new HashMap<String, Object>() {{
put("userRole", EnvManager.value("NORMAL_USER_ROLE_ID"));
}});
userPO = userService.getPOByUsername(registerPhoneVO.getPhone());
}
AppLoginPhoneVO appLoginPhoneVO = new AppLoginPhoneVO();
appLoginPhoneVO.setUsername(registerPhoneVO.getPhone());
return appSignService.phoneSign(appLoginPhoneVO);
String token = appSignService.phoneSign(appLoginPhoneVO);
accessTokenService.set2Redis(userPO.getUserId(), token);
return token;
} catch (Exception e) {
LOG.error(e.getMessage(), e);
throw new SystemException("登录失败");

View File

@ -10,9 +10,7 @@ import cn.com.tenlion.operator.pojo.vos.user.expand.UserExpandVO;
import cn.com.tenlion.operator.pojo.vos.user.expand.ic.UserExpandRelationIcVO;
import cn.com.tenlion.operator.properties.SystemApiPathProperties;
import cn.com.tenlion.operator.remote.IOperatorPluginRemoteService;
import cn.com.tenlion.operator.util.pay.PayUtil;
import com.alibaba.fastjson.JSON;
import ink.wgink.app.AppTokenManager;
import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.exceptions.SaveException;
import ink.wgink.exceptions.SearchException;
@ -242,42 +240,36 @@ public class UserExpandServiceImpl extends DefaultBaseService implements IUserEx
params = HashMapUtil.beanToMap(userExpandVO);
params.put("userId", userId);
if (!StringUtils.isEmpty(userExpandVO.getMainUserId())) {
if (StringUtils.isNotBlank(userExpandVO.getIc())) {
params.put("icAssignUserId", securityComponent.getCurrentUser().getUserId());
params.put("icWayToGet", IcWayToGetEnum.ASSIGN);
params.put("icGetTime", DateUtil.getTime());
if (StringUtils.isNotBlank(userExpandVO.getIc())) {
params.put("icAssignUserId", securityComponent.getCurrentUser().getUserId());
params.put("icWayToGet", IcWayToGetEnum.ASSIGN);
params.put("icGetTime", DateUtil.getTime());
}
if (userExpandDTO == null) {
if (StringUtils.isNotBlank(userExpandVO.getIc()) && countIc(userExpandVO.getIc()) > 0) {
throw new SearchException("邀请码已存在,请重新生成");
}
if (userExpandDTO == null) {
userExpandDao.save(params);
} else {
if (StringUtils.isNotBlank(userExpandDTO.getRelationIc()) &&
StringUtils.equals("ACTIVE", userExpandVO.getPostpaid())) {
throw new SearchException("已经绑定邀请码的用户不能设置为后付费用户");
}
if (StringUtils.isNotBlank(userExpandDTO.getIc())) {
params.remove("ic");
params.remove("icGetTime");
params.remove("icAssignUserId");
params.remove("icPriceAll");
params.remove("icPriceMaterial");
} else {
if (StringUtils.isNotBlank(userExpandVO.getIc()) && countIc(userExpandVO.getIc()) > 0) {
throw new SearchException("邀请码已存在,请重新生成");
}
userExpandDao.save(params);
} else {
if (StringUtils.isNotBlank(userExpandDTO.getRelationIc()) &&
StringUtils.equals("ACTIVE", userExpandVO.getPostpaid())) {
throw new SearchException("已经绑定邀请码的用户不能设置为后付费用户");
}
if (StringUtils.isNotBlank(userExpandDTO.getIc())) {
params.remove("ic");
params.remove("icGetTime");
params.remove("icAssignUserId");
params.remove("icPriceAll");
params.remove("icPriceMaterial");
} else {
if (StringUtils.isNotBlank(userExpandVO.getIc()) && countIc(userExpandVO.getIc()) > 0) {
throw new SearchException("邀请码已存在,请重新生成");
}
}
userExpandDao.update(params);
}
updateRedis(userId);
updateBatchRelationRebateRatio(userId, userExpandDTO == null ? 0 : userExpandDTO.getIcRebateRatio(), userExpandVO.getIcRebateRatio());
}else{
userExpandDao.update(params);
}
updateRedis(userId);
updateBatchRelationRebateRatio(userId, userExpandDTO == null ? 0 : userExpandDTO.getIcRebateRatio(), userExpandVO.getIcRebateRatio());
}
public void saveOrUpdateWithIc(String userId, UserExpandVO userExpandVO) {
@ -420,4 +412,24 @@ public class UserExpandServiceImpl extends DefaultBaseService implements IUserEx
params.put("ic", ic);
return userExpandDao.getPO(params);
}
public UserExpandPO getPOByWxMiniappOpenId(String openid) {
Map<String, Object> params = getHashMap(4);
params.put("wxMiniappOpenId", openid);
return userExpandDao.getPO(params);
}
public UserExpandPO getPOByWxOfficialAccountOpenId(String openid) {
Map<String, Object> params = getHashMap(4);
params.put("wxOfficialAccountOpenId", openid);
return userExpandDao.getPO(params);
}
public void updateWxMiniappOpenId(String userId, String openid) {
Map<String, Object> params = getHashMap(4);
params.put("wxMiniappOpenId", openid);
params.put("userId", userId);
userExpandDao.updateWxMiniappOpenId(params);
updateRedis(userId);
}
}

View File

@ -0,0 +1,176 @@
package cn.com.tenlion.operator.service.user.wx;
import cn.com.tenlion.operator.pojo.dtos.user.wx.UserWxLoginDTO;
import cn.com.tenlion.operator.pojo.pos.user.expand.UserExpandPO;
import cn.com.tenlion.operator.properties.WxMiniappProperties;
import cn.com.tenlion.operator.remote.wx.IWxMiniappRemoteService;
import cn.com.tenlion.operator.remote.wx.entity.*;
import cn.com.tenlion.operator.service.accesstoken.AccessTokenService;
import cn.com.tenlion.operator.service.user.expand.UserExpandServiceImpl;
import ink.wgink.common.manager.env.EnvManager;
import ink.wgink.exceptions.base.SystemException;
import ink.wgink.login.app.pojo.vos.appsign.AppLoginPhoneVO;
import ink.wgink.login.app.service.appsign.IAppSignService;
import ink.wgink.register.base.pojo.vos.RegisterPhoneVO;
import ink.wgink.register.base.service.IRegisterService;
import ink.wgink.service.user.pojo.pos.UserPO;
import ink.wgink.service.user.service.IUserService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Service
public class UserWxMiniappService {
private static final Logger LOG = LoggerFactory.getLogger(UserWxMiniappService.class);
public static final String WX_API_BASE_URL = "https://api.weixin.qq.com";
private WxMiniappAccessToken miniappAccessToken = null;
@Autowired
private WxMiniappProperties wxMiniappProperties;
@Autowired
private IWxMiniappRemoteService wxMiniappRemoteService;
@Autowired
private IUserService userService;
@Autowired
private UserExpandServiceImpl userExpandService;
@Autowired
private AccessTokenService accessTokenService;
@Autowired
private IRegisterService registerService;
@Autowired
private IAppSignService appSignService;
/**
* 保存openid和session_key的映射关系需要创建用户时使用
*/
private final Map<String, String> openIdSessionKeyMap = new ConcurrentHashMap<>();
/**
* 刷新access_token
*/
public void refreshAccessToken() {
long currentTimeMillis = System.currentTimeMillis();
if (miniappAccessToken != null) {
long lastTime = miniappAccessToken.getWxAccessToken().getExpires_in() / 4 * 3;
if (currentTimeMillis - miniappAccessToken.getUpdateTime() < lastTime) {
LOG.debug("小程序 access_token 不需要刷新, 剩余时间: {}", lastTime);
}
return;
}
WxAccessToken wxAccessToken = wxMiniappRemoteService.getAccessToken(WX_API_BASE_URL, new HashMap<String, Object>() {{
put("grant_type", "client_credential");
put("appid", wxMiniappProperties.getAppid());
put("secret", wxMiniappProperties.getAppsecret());
}});
miniappAccessToken = new WxMiniappAccessToken(wxAccessToken, currentTimeMillis);
}
/**
* 完成小程序登录获取openid并检查是否是新用户
*
* @param code
* @return
*/
public UserWxLoginDTO login(String jsCode) {
if (miniappAccessToken == null) {
throw new SystemException("系统错误");
}
WxLoginResult wxLoginResult = wxMiniappRemoteService.login(WX_API_BASE_URL, wxMiniappProperties.getAppid(), wxMiniappProperties.getAppsecret(), jsCode, "authorization_code");
checkResult(wxLoginResult);
// 查看是否有账号
UserExpandPO userExpandPO = userExpandService.getPOByWxMiniappOpenId(wxLoginResult.getOpenid());
if (userExpandPO == null) {
openIdSessionKeyMap.put(wxLoginResult.getOpenid(), wxLoginResult.getSession_key());
return new UserWxLoginDTO(wxLoginResult.getOpenid(), 1);
}
try {
UserPO userPO = userService.getPO(userExpandPO.getUserId());
AppLoginPhoneVO appLoginPhoneVO = new AppLoginPhoneVO();
appLoginPhoneVO.setUsername(userPO.getUserUsername());
String token = appSignService.phoneSign(appLoginPhoneVO);
// 如果有账号返回accessToken
return new UserWxLoginDTO(wxLoginResult.getOpenid(), token, 0);
} catch (Exception e) {
LOG.error(e.getMessage(), e);
throw new SystemException("登录异常");
}
}
/**
* 注册账号
*
* @param openid
* @param code
* @return
* @throws Exception
*/
public UserWxLoginDTO register(String openid, String code) {
if (miniappAccessToken == null) {
throw new SystemException("系统错误");
}
if (StringUtils.isBlank(openid)) {
throw new SystemException("请先完成登录");
}
openIdSessionKeyMap.remove(openid);
String phone = getPhone(code);
try {
// 检查是否存在
UserPO poByUsername = userService.getPOByUsername(phone);
if (poByUsername != null) {
// 用户存在绑定userId
userExpandService.updateWxMiniappOpenId(poByUsername.getUserId(), openid);
AppLoginPhoneVO appLoginPhoneVO = new AppLoginPhoneVO();
appLoginPhoneVO.setUsername(poByUsername.getUserUsername());
String token = appSignService.phoneSign(appLoginPhoneVO);
accessTokenService.set2Redis(poByUsername.getUserId(), token);
return new UserWxLoginDTO(openid, token, 0);
}
// 执行注册
RegisterPhoneVO registerPhoneVO = new RegisterPhoneVO();
registerPhoneVO.setPhone(phone);
registerService.registerPhone(registerPhoneVO, new HashMap<String, Object>() {{
put("userRole", EnvManager.value("NORMAL_USER_ROLE_ID"));
put("wxMiniappOpenId", openid);
}});
poByUsername = userService.getPOByUsername(phone);
if (poByUsername == null) {
throw new SystemException("用户注册失败");
}
AppLoginPhoneVO appLoginPhoneVO = new AppLoginPhoneVO();
appLoginPhoneVO.setUsername(poByUsername.getUserUsername());
String token = appSignService.phoneSign(appLoginPhoneVO);
accessTokenService.set2Redis(poByUsername.getUserId(), token);
return new UserWxLoginDTO(openid, token, 0, phone);
} catch (Exception e) {
LOG.error(e.getMessage(), e);
throw new SystemException("注册异常");
}
}
/**
* 获取手机号
*
* @param code
* @return
*/
private String getPhone(String code) {
WxPhoneResult wxPhoneResult = wxMiniappRemoteService.getPhone(WX_API_BASE_URL, miniappAccessToken.getWxAccessToken().getAccess_token(), new HashMap<String, Object>() {{
put("code", code);
}});
checkResult(wxPhoneResult);
return wxPhoneResult.getPhone_info().getPurePhoneNumber();
}
private void checkResult(WxResult wxResult) {
if (wxResult.getErrcode() == -1) {
throw new SystemException(wxResult.getErrmsg());
}
}
}

View File

@ -4,10 +4,12 @@ import cn.com.tenlion.operator.enums.SysCallbackStatusEnum;
import cn.com.tenlion.operator.pojo.pos.sys.callback.SysCallbackPO;
import cn.com.tenlion.operator.service.sys.callback.SysCallbackService;
import cn.com.tenlion.operator.service.sys.task.SysTaskService;
import cn.com.tenlion.operator.service.user.wx.UserWxMiniappService;
import ink.wgink.interfaces.start.IApplicationStart;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.List;
@ -20,6 +22,8 @@ public class SystemStart implements IApplicationStart {
private SysCallbackService sysCallbackService;
@Autowired
private SysTaskService sysTaskService;
@Autowired
private UserWxMiniappService userWxMiniappService;
@Override
public void run() throws Exception {
@ -29,4 +33,9 @@ public class SystemStart implements IApplicationStart {
}
}
@Scheduled(fixedRate = 60 * 1000)
public void refreshWxMiniappAccessToken() {
userWxMiniappService.refreshAccessToken();
}
}

View File

@ -133,9 +133,10 @@ security:
api-path:
user-center: http://127.0.0.1:8091/operator/
copyright: http://127.0.0.1:7025/copyright/
copyright-external: http://192.168.0.103:7025/copyright/
copyright-external: http://192.168.0.15:7025/copyright/
operator-plugin: http://192.168.0.115:8099/operator-plugin/
#
#
# 短信验证码服务
@ -196,4 +197,11 @@ pay:
# 单笔最大金额
max-money: 20000
# 单笔最小金额
min-money: 0.1
min-money: 0.1
app-token:
has-role: true
wx-miniapp:
appid: wxe17874894f7ff27b
appsecret: 0c2b1371e4fb32514030233da4ef094d

View File

@ -568,7 +568,7 @@
AND t1.recharge_check = #{rechargeCheck}
</if>
<if test="queryOnline != null and queryOnline != ''">
AND (t1.recharge_check = '0' OR t1.recharge_check = '1' ) AND t1.recharge_type = '2' AND t1.third_party = #{queryOnline} AND t1.recharge_final_time >= NOW() - INTERVAL 3 MINUTE
AND (t1.recharge_check = '0' OR t1.recharge_check = '1' ) AND t1.recharge_type = '2' AND t1.third_party = #{queryOnline} AND t1.recharge_final_time >= NOW() - INTERVAL 10 MINUTE
</if>
<if test="accountRechargeIds != null and accountRechargeIds.size > 0">
AND

View File

@ -29,6 +29,8 @@
<result column="relation_ic_user_id" property="relationIcUserId"/>
<result column="sub_user_ids" property="subUserIds"/>
<result column="main_user_id" property="mainUserId"/>
<result column="wx_miniapp_open_id" property="wxMiniappOpenId"/>
<result column="wx_official_account_open_id" property="wxOfficialAccountOpenId"/>
</resultMap>
<resultMap id="userExpandPO" type="cn.com.tenlion.operator.pojo.pos.user.expand.UserExpandPO">
@ -56,6 +58,10 @@
<result column="relation_ic_rebate_ratio" property="relationIcRebateRatio"/>
<result column="relation_ic_time" property="relationIcTime"/>
<result column="relation_ic_user_id" property="relationIcUserId"/>
<result column="sub_user_ids" property="subUserIds"/>
<result column="main_user_id" property="mainUserId"/>
<result column="wx_miniapp_open_id" property="wxMiniappOpenId"/>
<result column="wx_official_account_open_id" property="wxOfficialAccountOpenId"/>
</resultMap>
<insert id="save" parameterType="map">
@ -81,7 +87,9 @@
ic_get_time,
ic_assign_user_id,
sub_user_ids,
main_user_id
main_user_id,
wx_miniapp_open_id,
wx_official_account_open_id
) VALUES (
#{userId},
#{priceAdditionalPkg},
@ -104,7 +112,9 @@
#{icGetTime},
#{icAssignUserId},
#{subUserIds},
#{mainUserId}
#{mainUserId},
#{wxMiniappOpenId},
#{wxOfficialAccountOpenId}
)
</insert>
@ -136,6 +146,12 @@
<if test="mainUserId != null">
main_user_id = #{mainUserId},
</if>
<if test="wxMiniappOpenId != null">
wx_miniapp_open_id = #{wxMiniappOpenId},
</if>
<if test="wxOfficialAccountOpenId != null">
wx_official_account_open_id = #{wxOfficialAccountOpenId},
</if>
price_additional_pkg = #{priceAdditionalPkg},
price_additional_video_demo = #{priceAdditionalVideoDemo},
price_additional_urgent = #{priceAdditionalUrgent},
@ -190,6 +206,25 @@
relation_ic_user_id = #{relationIcUserId}
</update>
<update id="updateWxMiniappOpenId">
UPDATE
sys_user_expand
SET
wx_miniapp_open_id = #{wxMiniappOpenId}
WHERE
user_id = #{userId}
</update>
<update id="updateWxOfficialAccountOpenId">
UPDATE
sys_user_expand
SET
wx_official_account_open_id = #{wxOfficialAccountOpenId}
WHERE
user_id = #{userId}
</update>
<select id="get" parameterType="map" resultMap="userExpandDTO">
SELECT
price_additional_pkg,
@ -216,13 +251,21 @@
relation_ic_time,
relation_ic_user_id,
sub_user_ids,
main_user_id
main_user_id,
wx_miniapp_open_id,
wx_official_account_open_id
FROM
sys_user_expand
WHERE
<if test="userId != null and userId != ''">
<if test="userId != null and userId != ''">
user_id = #{userId}
</if>
</if>
<if test="wxMiniappOpenId != null and wxMiniappOpenId != ''">
wx_miniapp_open_id = #{wxMiniappOpenId}
</if>
<if test="wxOfficialAccountOpenId != null and wxOfficialAccountOpenId != ''">
wx_official_account_open_id = #{wxOfficialAccountOpenId}
</if>
</select>
<select id="getPO" parameterType="map" resultMap="userExpandPO">
@ -252,7 +295,9 @@
relation_ic_time,
relation_ic_user_id,
sub_user_ids,
main_user_id
main_user_id,
wx_miniapp_open_id,
wx_official_account_open_id
FROM
sys_user_expand
WHERE
@ -262,6 +307,12 @@
<if test="ic != null and ic != ''">
ic = #{ic}
</if>
<if test="wxMiniappOpenId != null and wxMiniappOpenId != ''">
wx_miniapp_open_id = #{wxMiniappOpenId}
</if>
<if test="wxOfficialAccountOpenId != null and wxOfficialAccountOpenId != ''">
wx_official_account_open_id = #{wxOfficialAccountOpenId}
</if>
</select>
<select id="countIc" parameterType="java.lang.String" resultType="java.lang.Integer">

View File

@ -0,0 +1,68 @@
import cn.com.tenlion.operator.util.pay.PayResultDTO;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.model.TransactionAmount;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.QueryOrderByOutTradeNoRequest;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public class WxPayTest {
public static void main(String[] args) {
String mchId = "1609461201";
Config config =
new RSAAutoCertificateConfig.Builder()
.merchantId(mchId)
.privateKeyFromPath("D:\\WxCertUtils\\WXCertUtil\\cert\\1609461201_20240203_cert\\apiclient_key.pem")
.merchantSerialNumber("3492AF71B2FC29014997E16FF6499E27F7A0781B")
.apiV3Key("_TSKJ_0471_TSkj_0471_tsKJ_0471__")
.build();
NativePayService service = new NativePayService.Builder().config(config).build();
QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
request.setMchid(mchId);
String orderNo = "wx20250315134506349-116e6399ec2d";
request.setOutTradeNo(orderNo);
PayResultDTO dto = new PayResultDTO();
dto.setOrderStatus("0");
dto.setMoney(-1);
// 调用下单方法得到应答
try {
// 发送请求
Transaction response = service.queryOrderByOutTradeNo(request);
String order = response.getTransactionId(); // 第三方订单号
Transaction.TradeStateEnum status = response.getTradeState();
TransactionAmount amount = response.getAmount();
String time = response.getSuccessTime();
dto.setMoney(amount.getPayerTotal());
dto.setOrderNo(orderNo);
dto.setOrderSuccessTime(status.name().equals("SUCCESS") ? convertToFormattedString(time) : "");
dto.setOrderId(order);
dto.setOrderStatus(status.name().equals("SUCCESS") ? "1" : "0");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(dto.getOrderStatus());
}
/**
* 时间格式转换
*
* @param inputDateTime
* @return
*/
private static String convertToFormattedString(String inputDateTime) {
// 将字符串解析为ZonedDateTime对象
ZonedDateTime zonedDateTime = ZonedDateTime.parse(inputDateTime);
// 将ZonedDateTime对象转换为指定的格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return zonedDateTime.format(formatter);
}
}