Merge branch 'feature/bug-829' into test

This commit is contained in:
曹鹏飞 2025-10-16 09:42:51 +08:00
commit 6970a7c58f
19 changed files with 382 additions and 5 deletions

View File

@ -16,10 +16,6 @@
<groupId>com.nflg</groupId>
<artifactId>nflg-mobilebroken-repository</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.alibaba.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
@ -62,6 +58,11 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>4.7.0</version>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,24 @@
package com.nflg.mobilebroken.auth.config;
import com.nflg.mobilebroken.auth.weixin.CustomWxMpConfigStorage;
import com.nflg.mobilebroken.auth.weixin.ExternalTokenService;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
@Configuration
public class WxMpConfig {
@Resource
private ExternalTokenService externalTokenService;
@Bean
public WxMpService wxMpService() {
WxMpService service = new WxMpServiceImpl();
service.setWxMpConfigStorage(new CustomWxMpConfigStorage(externalTokenService));
return service;
}
}

View File

@ -0,0 +1,174 @@
package com.nflg.mobilebroken.auth.controller;
import cn.dev33.satoken.stp.SaLoginConfig;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.hutool.core.util.StrUtil;
import com.nflg.mobilebroken.common.constant.Constant;
import com.nflg.mobilebroken.common.constant.STATE;
import com.nflg.mobilebroken.common.exception.NflgException;
import com.nflg.mobilebroken.common.pojo.ApiResult;
import com.nflg.mobilebroken.common.pojo.request.UserBindWXRequest;
import com.nflg.mobilebroken.common.pojo.vo.AppLoginVO;
import com.nflg.mobilebroken.common.pojo.vo.RoleVO;
import com.nflg.mobilebroken.common.util.IdUtil;
import com.nflg.mobilebroken.common.util.SaTokenAdminUtil;
import com.nflg.mobilebroken.common.util.SaTokenAppUtil;
import com.nflg.mobilebroken.common.util.VUtils;
import com.nflg.mobilebroken.repository.entity.AdminUser;
import com.nflg.mobilebroken.repository.entity.AppUser;
import com.nflg.mobilebroken.repository.service.IAdminUserRoleMapService;
import com.nflg.mobilebroken.repository.service.IAdminUserService;
import com.nflg.mobilebroken.repository.service.IAppUserService;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 微信
*/
@RestController
@RequestMapping("/weixin")
public class WeiXinController extends ControllerBase {
@Resource
private WxMpService wxMpService;
@Resource
private IAppUserService appUserService;
@Resource
private IAdminUserService adminUserService;
@Resource
private IAdminUserRoleMapService adminUserRoleMapService;
/**
* 获取微信授权地址
* @param redirectUri 回调地址
*/
@GetMapping("getAuthUrl")
public ApiResult<String> getAuthUrl(@Valid @RequestParam @NotBlank String redirectUri) {
String url = wxMpService.getOAuth2Service().buildAuthorizationUrl(
redirectUri,
WxConsts.OAuth2Scope.SNSAPI_BASE,
IdUtil.getIdStr()
);
return ApiResult.success(url);
}
/**
* 获取登录token
* @param code 微信授权码
* @param state state
*/
@GetMapping("getToken")
public ApiResult<AppLoginVO> getToken(@Valid @RequestParam @NotBlank String code
, @Valid @RequestParam @NotBlank String state) throws WxErrorException {
WxOAuth2AccessToken token = wxMpService.getOAuth2Service().getAccessToken(code);
String openId = token.getOpenId();
AppLoginVO vo = getAppUserToken(openId);
vo = Objects.nonNull(vo) ? vo : getAdminUserToken(openId);
if (Objects.isNull(vo)) {
return ApiResult.success(new AppLoginVO().setWxOpenId(openId));
} else {
return ApiResult.success(vo);
}
}
private AppLoginVO getAppUserToken(String openId) {
AppUser user = appUserService.getByWxOpenId(openId);
if (Objects.nonNull(user)) {
return buildAppLoginVO(user);
}
return null;
}
private AppLoginVO buildAppLoginVO(AppUser user) {
SaTokenAppUtil.login(user.getId(), SaLoginConfig
.setExtra("from", Constant.FROM_APP)
.setExtra("name", user.getName())
.setExtra("email", user.getEmail())
.setExtra("companyIds", StrUtil.split(user.getCompanyId(), ",").stream().map(Integer::valueOf).collect(Collectors.toList()))
.setExtra("isPrimary", user.getIsPrimary()));
user.setLastLoginTime(LocalDateTime.now());
appUserService.updateById(user);
SaTokenInfo tokenInfo = SaTokenAppUtil.getTokenInfo();
return new AppLoginVO()
.setUserId(user.getId())
.setToken(tokenInfo.getTokenValue())
.setExpire(tokenInfo.getTokenTimeout())
.setLanguageCode(user.getLanguageCode())
.setPlatform(Constant.FROM_APP);
}
private AppLoginVO getAdminUserToken(String openId) {
AdminUser adminUser = adminUserService.getByWxOpenId(openId);
if (Objects.nonNull(adminUser)) {
return buildAdminLoginVO(adminUser);
}
return null;
}
private AppLoginVO buildAdminLoginVO(AdminUser adminUser) {
List<RoleVO> roleCodes = adminUserRoleMapService.getRoleList(adminUser.getId());
SaTokenAdminUtil.login(adminUser.getId(), SaLoginConfig
.setExtra("from", Constant.FROM_ADMIN)
.setExtra("name", adminUser.getUserName())
.setExtra("code", adminUser.getUserCode())
.setExtra("email", adminUser.getEmail())
.setExtra("roles", roleCodes.stream().map(RoleVO::getCode).collect(Collectors.toList())));
String adminToken = SaTokenAdminUtil.getTokenInfo().getTokenValue();
SaTokenAppUtil.login(adminUser.getId(), SaLoginConfig
.setExtra("from", Constant.FROM_ADMIN)
.setExtra("name", adminUser.getUserName())
.setExtra("email", adminUser.getEmail()));
SaTokenInfo tokenInfo = SaTokenAppUtil.getTokenInfo();
return new AppLoginVO()
.setUserId(adminUser.getId())
.setToken(tokenInfo.getTokenValue())
.setAdminToken(adminToken)
.setExpire(tokenInfo.getTokenTimeout())
.setLanguageCode(Constant.DEFAULT_LANGUAGE_CODE)
.setPlatform(Constant.FROM_ADMIN);
}
/**
* 绑定用户
* @param request 请求参数
*/
@PostMapping("bindUser")
public ApiResult<AppLoginVO> bindUser(@Valid @RequestBody @NotNull UserBindWXRequest request) {
AppUser appUser = appUserService.getByWxOpenId(request.getOpenId());
AdminUser adminUser = adminUserService.getByWxOpenId(request.getOpenId());
VUtils.trueThrowBusinessError(Objects.nonNull(appUser) || Objects.nonNull(adminUser))
.throwMessage("请勿重复绑定");
appUser = appUserService.getUser(request.getLoginName(), request.getPwd());
if (Objects.nonNull(appUser)) {
VUtils.trueThrowBusinessError(StrUtil.isNotBlank(appUser.getWxOpenId())).throwMessage("该账号已绑定了微信");
appUser.setWxOpenId(request.getOpenId());
appUser.setUpdateTime(LocalDateTime.now());
return ApiResult.success(buildAppLoginVO(appUser));
} else {
adminUser = adminUserService.getUser(request.getLoginName(), request.getPwd());
if (Objects.nonNull(adminUser)) {
VUtils.trueThrowBusinessError(StrUtil.isNotBlank(adminUser.getWxOpenId())).throwMessage("该账号已绑定了微信");
adminUser.setWxOpenId(request.getOpenId());
adminUser.setUpdateTime(LocalDateTime.now());
adminUserService.updateById(adminUser);
return ApiResult.success(buildAdminLoginVO(adminUser));
}
throw new NflgException(STATE.PassportErr, "用户名或密码错误");
}
}
}

View File

@ -0,0 +1,27 @@
package com.nflg.mobilebroken.auth.weixin;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
public class CustomWxMpConfigStorage extends WxMpDefaultConfigImpl {
private final ExternalTokenService externalTokenService;
public CustomWxMpConfigStorage(ExternalTokenService externalTokenService) {
this.externalTokenService = externalTokenService;
}
@Override
public String getAccessToken() {
return externalTokenService.fetchGlobalAccessToken();
}
@Override
public String getAppId() {
return externalTokenService.getAppId();
}
@Override
public String getSecret() {
return externalTokenService.getAppSecret();
}
}

View File

@ -0,0 +1,10 @@
package com.nflg.mobilebroken.auth.weixin;
public interface ExternalTokenService {
String fetchGlobalAccessToken();
String getAppId();
String getAppSecret();
}

View File

@ -0,0 +1,18 @@
package com.nflg.mobilebroken.auth.weixin;
import cn.hutool.core.annotation.Alias;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class TokenCache {
private String appId;
@Alias("appSecre")
private String appSecret;
@Alias("token")
private String accessToken;
}

View File

@ -0,0 +1,56 @@
package com.nflg.mobilebroken.auth.weixin.impl;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.nflg.mobilebroken.auth.weixin.ExternalTokenService;
import com.nflg.mobilebroken.auth.weixin.TokenCache;
import com.nflg.mobilebroken.common.constant.STATE;
import com.nflg.mobilebroken.common.exception.NflgException;
import com.nflg.mobilebroken.common.util.VUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class ExternalTokenServiceImpl implements ExternalTokenService {
private TokenCache token;
@Value("${wx.mp.accessTokenUrl}")
private String weixinAccessTokenUrl;
@Override
public String fetchGlobalAccessToken() {
refreshToken();
return token.getAccessToken();
}
@Override
public String getAppId() {
refreshToken();
return token.getAppId();
}
@Override
public String getAppSecret() {
refreshToken();
return token.getAppSecret();
}
private void refreshToken() {
try {
String content = HttpUtil.get(weixinAccessTokenUrl, 10000);
log.info("获取微信AccessToken结果:{}", content);
JSONObject oj = JSONUtil.parseObj(content);
VUtils.trueThrowBusinessError(!StrUtil.equals(oj.getStr("status"), "success"))
.throwMessage(oj.getStr("message"));
token = JSONUtil.toBean(oj.getStr("message"), TokenCache.class);
log.debug("Token数据:{}", JSONUtil.toJsonStr(token));
} catch (Exception e) {
throw new NflgException(STATE.ServiceConnectRefused, "获取微信AccessToken失败:" + e.getMessage());
}
}
}

View File

@ -145,7 +145,7 @@ public class TicketController extends ControllerBase {
* @param request 工单信息
**/
@PostMapping("/addTiket")
public ApiResult<Void> addTiket(@Valid @RequestBody TicketAddRequest request) {
public ApiResult<Void> addTicket(@Valid @RequestBody TicketAddRequest request) {
Ticket ticket = ticketService.add(request, AppUserUtil.getUserId());
ticketChatService.add(new TicketChatDTO()
.setTicketId(ticket.getId())

View File

@ -39,4 +39,9 @@ public class TicketAddRequest {
//设备地址
@Size(max = 300, message = "设备地址长度不能超过300")
private String deviceAddress;
/**
* 来源
*/
private String source;
}

View File

@ -0,0 +1,27 @@
package com.nflg.mobilebroken.common.pojo.request;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@Data
public class UserBindWXRequest {
/**
* 微信openId
*/
@NotBlank
private String openId;
/**
* 登录名
*/
@NotBlank
private String loginName;
/**
* 密码
*/
@NotBlank
private String pwd;
}

View File

@ -23,4 +23,9 @@ public class AppLoginVO {
//平台app或者admin
private String platform;
/**
* 微信openId
*/
private String wxOpenId;
}

View File

@ -108,4 +108,9 @@ public class AdminUser implements Serializable {
* 删除状态0未删除1已删除
*/
private Boolean isDel;
/**
* 微信openid
*/
private String wxOpenId;
}

View File

@ -134,4 +134,9 @@ public class AppUser implements Serializable {
* 删除状态0未删除1已删除
*/
private Boolean isDel;
/**
* 微信openid
*/
private String wxOpenId;
}

View File

@ -146,4 +146,9 @@ public class Ticket implements Serializable {
* 最后更新时间
*/
private LocalDateTime updateTime;
/**
* 来源
*/
private String source;
}

View File

@ -54,4 +54,6 @@ public interface IAdminUserService extends IService<AdminUser> {
List<Integer> getTickerMangagers();
List<Integer> getCQMIds();
AdminUser getByWxOpenId(String openId);
}

View File

@ -68,4 +68,6 @@ public interface IAppUserService extends IService<AppUser> {
void authorizeRole(@Valid AuthorizeRoleRequest request);
Integer getPrimaryByChild(Integer userId);
AppUser getByWxOpenId(String openId);
}

View File

@ -358,6 +358,11 @@ public class AdminUserServiceImpl extends ServiceImpl<AdminUserMapper, AdminUser
return baseMapper.getCQMIds(Constant.DICTIONARY_TYPE_TITLE_CQM);
}
@Override
public AdminUser getByWxOpenId(String openId) {
return lambdaQuery().eq(AdminUser::getWxOpenId, openId).one();
}
private String getDepartmentName(Long departmentId) {
TBaseDepartment department = departmentService.lambdaQuery()
.eq(TBaseDepartment::getId, departmentId)

View File

@ -312,6 +312,11 @@ public class AppUserServiceImpl extends ServiceImpl<AppUserMapper, AppUser> impl
return primaryUser.getId();
}
@Override
public AppUser getByWxOpenId(String openId) {
return lambdaQuery().eq(AppUser::getWxOpenId, openId).one();
}
private void bindChildren1(AreaSimpleVO vo) {
List<AppArea> datas = appAreaService.lambdaQuery().eq(AppArea::getParentId, vo.getId()).eq(AppArea::getEnable, true).list();
List<AreaSimpleVO> vos = datas.stream().map(d -> new AreaSimpleVO().setId(d.getId()).setName(d.getName())).collect(Collectors.toList());

View File

@ -81,6 +81,7 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
.setTitle(request.getTitle())
.setDescription(request.getDescription())
.setState(TicketState.PendingProcessing.getState())
.setSource(request.getSource())
.setUserId(userId)
.setUserPlatform(AppUserUtil.getFrom())
.setCreateTime(LocalDateTime.now());