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 updateRelationRebateRatio(Map<String, Object> params);
void updateWxMiniappOpenId(Map<String, Object> params);
void updateWxOfficialAccountOpenId(Map<String, Object> params);
UserExpandDTO get(Map<String, Object> params); UserExpandDTO get(Map<String, Object> params);
UserExpandPO getPO(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 Integer relationIcRebateRatio;
private String relationIcTime; private String relationIcTime;
private String relationIcUserId; private String relationIcUserId;
private String subUserIds;
private String mainUserId;
private String wxMiniappOpenId;
private String wxOfficialAccountOpenId;
public String getUserId() { public String getUserId() {
return userId == null ? "" : userId.trim(); return userId == null ? "" : userId.trim();
@ -227,4 +231,36 @@ public class UserExpandPO {
public void setRelationIcUserId(String relationIcUserId) { public void setRelationIcUserId(String relationIcUserId) {
this.relationIcUserId = 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 icPriceAll;
private Double icPriceMaterial; private Double icPriceMaterial;
private Integer icRebateRatio; private Integer icRebateRatio;
private String wxMiniappOpenId;
private String wxOfficialAccountOpenId;
/** /**
* 子账号ID集合 * 子账号ID集合
@ -192,4 +194,20 @@ public class UserExpandVO {
public void setIcRebateRatio(Integer icRebateRatio) { public void setIcRebateRatio(Integer icRebateRatio) {
this.icRebateRatio = 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.初始化个人信息 // 3.初始化个人信息
iAccountService.saveCreate(roleName, userId); iAccountService.saveCreate(roleName, userId);
// 4.初始化用户拓展信息 // 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 @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 @Override
public AccountDTO get(Map<String, Object> params) { public AccountDTO get(Map<String, Object> params) {
AccountDTO accountDTO = accountDao.get(params); AccountDTO accountDTO = accountDao.get(params);
if (accountDTO == null) {
return null;
}
accountDTO.setAccountMoneyDouble(PayUtil.buiderMoney(accountDTO.getAccountMoney())); accountDTO.setAccountMoneyDouble(PayUtil.buiderMoney(accountDTO.getAccountMoney()));
return accountDTO; return accountDTO;
} }

View File

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

View File

@ -1,5 +1,6 @@
package cn.com.tenlion.operator.service.quick.login; 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.base.DefaultBaseService;
import ink.wgink.common.manager.env.EnvManager; import ink.wgink.common.manager.env.EnvManager;
import ink.wgink.exceptions.base.SystemException; import ink.wgink.exceptions.base.SystemException;
@ -30,6 +31,9 @@ public class QuickLoginService extends DefaultBaseService {
private IRegisterService registerService; private IRegisterService registerService;
@Autowired @Autowired
private IAppSignService appSignService; private IAppSignService appSignService;
@Autowired
private AccessTokenService accessTokenService;
/** /**
* 新增和登录 * 新增和登录
@ -45,10 +49,13 @@ public class QuickLoginService extends DefaultBaseService {
registerService.registerPhone(registerPhoneVO, new HashMap<String, Object>() {{ registerService.registerPhone(registerPhoneVO, new HashMap<String, Object>() {{
put("userRole", EnvManager.value("NORMAL_USER_ROLE_ID")); put("userRole", EnvManager.value("NORMAL_USER_ROLE_ID"));
}}); }});
userPO = userService.getPOByUsername(registerPhoneVO.getPhone());
} }
AppLoginPhoneVO appLoginPhoneVO = new AppLoginPhoneVO(); AppLoginPhoneVO appLoginPhoneVO = new AppLoginPhoneVO();
appLoginPhoneVO.setUsername(registerPhoneVO.getPhone()); appLoginPhoneVO.setUsername(registerPhoneVO.getPhone());
return appSignService.phoneSign(appLoginPhoneVO); String token = appSignService.phoneSign(appLoginPhoneVO);
accessTokenService.set2Redis(userPO.getUserId(), token);
return token;
} catch (Exception e) { } catch (Exception e) {
LOG.error(e.getMessage(), e); LOG.error(e.getMessage(), e);
throw new SystemException("登录失败"); 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.pojo.vos.user.expand.ic.UserExpandRelationIcVO;
import cn.com.tenlion.operator.properties.SystemApiPathProperties; import cn.com.tenlion.operator.properties.SystemApiPathProperties;
import cn.com.tenlion.operator.remote.IOperatorPluginRemoteService; import cn.com.tenlion.operator.remote.IOperatorPluginRemoteService;
import cn.com.tenlion.operator.util.pay.PayUtil;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import ink.wgink.app.AppTokenManager;
import ink.wgink.common.base.DefaultBaseService; import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.exceptions.SaveException; import ink.wgink.exceptions.SaveException;
import ink.wgink.exceptions.SearchException; import ink.wgink.exceptions.SearchException;
@ -242,42 +240,36 @@ public class UserExpandServiceImpl extends DefaultBaseService implements IUserEx
params = HashMapUtil.beanToMap(userExpandVO); params = HashMapUtil.beanToMap(userExpandVO);
params.put("userId", userId); params.put("userId", userId);
if (!StringUtils.isEmpty(userExpandVO.getMainUserId())) { if (StringUtils.isNotBlank(userExpandVO.getIc())) {
if (StringUtils.isNotBlank(userExpandVO.getIc())) { params.put("icAssignUserId", securityComponent.getCurrentUser().getUserId());
params.put("icAssignUserId", securityComponent.getCurrentUser().getUserId()); params.put("icWayToGet", IcWayToGetEnum.ASSIGN);
params.put("icWayToGet", IcWayToGetEnum.ASSIGN); params.put("icGetTime", DateUtil.getTime());
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) { if (StringUtils.isNotBlank(userExpandVO.getIc()) && countIc(userExpandVO.getIc()) > 0) {
throw new SearchException("邀请码已存在,请重新生成"); 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); userExpandDao.update(params);
updateBatchRelationRebateRatio(userId, userExpandDTO == null ? 0 : userExpandDTO.getIcRebateRatio(), userExpandVO.getIcRebateRatio());
}else{
} }
updateRedis(userId);
updateBatchRelationRebateRatio(userId, userExpandDTO == null ? 0 : userExpandDTO.getIcRebateRatio(), userExpandVO.getIcRebateRatio());
} }
public void saveOrUpdateWithIc(String userId, UserExpandVO userExpandVO) { public void saveOrUpdateWithIc(String userId, UserExpandVO userExpandVO) {
@ -420,4 +412,24 @@ public class UserExpandServiceImpl extends DefaultBaseService implements IUserEx
params.put("ic", ic); params.put("ic", ic);
return userExpandDao.getPO(params); 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.pojo.pos.sys.callback.SysCallbackPO;
import cn.com.tenlion.operator.service.sys.callback.SysCallbackService; import cn.com.tenlion.operator.service.sys.callback.SysCallbackService;
import cn.com.tenlion.operator.service.sys.task.SysTaskService; 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 ink.wgink.interfaces.start.IApplicationStart;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
@ -20,6 +22,8 @@ public class SystemStart implements IApplicationStart {
private SysCallbackService sysCallbackService; private SysCallbackService sysCallbackService;
@Autowired @Autowired
private SysTaskService sysTaskService; private SysTaskService sysTaskService;
@Autowired
private UserWxMiniappService userWxMiniappService;
@Override @Override
public void run() throws Exception { 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: api-path:
user-center: http://127.0.0.1:8091/operator/ user-center: http://127.0.0.1:8091/operator/
copyright: http://127.0.0.1:7025/copyright/ 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/ operator-plugin: http://192.168.0.115:8099/operator-plugin/
# #
# #
# 短信验证码服务 # 短信验证码服务
@ -196,4 +197,11 @@ pay:
# 单笔最大金额 # 单笔最大金额
max-money: 20000 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} AND t1.recharge_check = #{rechargeCheck}
</if> </if>
<if test="queryOnline != null and queryOnline != ''"> <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>
<if test="accountRechargeIds != null and accountRechargeIds.size > 0"> <if test="accountRechargeIds != null and accountRechargeIds.size > 0">
AND AND

View File

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