feat:修复已知问题,提升系统稳定性

This commit is contained in:
njydsz
2024-09-25 11:38:06 +08:00
parent bbed2aadbc
commit 8d094e48ac
493 changed files with 5108 additions and 22521 deletions

View File

@@ -0,0 +1,28 @@
package ai.remi.boot.server.exception;
import ai.remi.comm.exception.enums.ExceptionCode;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public enum IamExceptionCode implements ExceptionCode {
/**
* 业务异常code
*/
INVENTORY_CHECK_FAIL("B2006", "库存不足"),
QUERY_ORDER_FAIL("B2007", "查询订单失败"),
ORDER_STATUS_EXCEPTION("B2008", "订单状态不合法"),
ORDER_PRODUCT_EXCEPTION("B2010", "查询商品失败"),
ORDER_SHIPPING_RATE_PLAN_EXCEPTION("B2011", "邮费方案不存在"),
ORDER_VARIANTS_EXCEPTION("B2012", "库存扣减异常"),
PROMOTION_CODE_EXCEPTION("B2013", "优惠码错误"),
CUSTOMER_DISABLE("B2014", "用户被禁用"),
;
private String code;
private String key;
}

View File

@@ -0,0 +1,22 @@
package ai.remi.boot.server.exception;
import ai.remi.comm.exception.custom.BusinessException;
public class IamServiceException extends BusinessException {
public IamServiceException(String code, String message) {
super(code, message);
}
public IamServiceException(String code, Throwable cause) {
super(code, cause);
}
public IamServiceException(String code, String message, Throwable cause) {
super(code, message, cause);
}
public IamServiceException(String code, String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(code, message, cause, enableSuppression, writableStackTrace);
}
}

View File

@@ -0,0 +1,19 @@
package ai.remi.boot.server.service;
import com.baomidou.mybatisplus.extension.service.IService;
import ai.remi.boot.domain.entity.User;
import ai.remi.boot.domain.vo.UserVO;
/**
* @author DianJiu
* @email dianjiuxyz@gmail.com
* @desc 用户表(User)服务定义层
*/
public interface UserService extends IService<User> {
UserVO getLoginById(String id);
UserVO getUserById(String id);
User login(String username, String password);
}

View File

@@ -0,0 +1,176 @@
package ai.remi.boot.server.service.impl;
import ai.remi.boot.domain.entity.*;
import ai.remi.boot.domain.vo.UserVO;
import ai.remi.boot.infra.mapper.UserMapper;
import ai.remi.boot.server.service.*;
import ai.remi.comm.domain.tree.TreeBuild;
import ai.remi.comm.util.bean.BeanCopyUtils;
import ai.remi.comm.util.collection.CollectionUtils;
import ai.remi.comm.util.object.ObjectUtils;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author DianJiu
* @email dianjiuxyz@gmail.com
* @desc 用户表(User)服务实现层
*/
@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Resource
private UserMapper userMapper;
@Resource
private RoleService roleService;
@Resource
private UserRoleService userRoleService;
@Resource
private DeptUserService deptUserService;
@Resource
private CompanyDeptService companyDeptService;
@Resource
private CordRoleService cordRoleService;
@Resource
private UserPostService userPostService;
@Resource
private PostRoleService postRoleService;
@Resource
private GroupUserService groupUserService;
@Resource
private GroupRoleService groupRoleService;
@Resource
private RoleMenuService roleMenuService;
@Resource
private MenuMapper menuMapper;
@Resource
private ConfigService configService;
@Override
public UserVO getLoginById(String id) {
UserVO userVO = userMapper.selectOneById(id);
// 获取用户角色
List<RoleVO> userRoles = getUserRoles(id);
userVO.setUserRoles(userRoles);
// 获取用户菜单
List<AppMenuVO> userMenus = getUserMenus(userRoles);
userVO.setUserMenus(userMenus);
// 用户全局配置
List<Config> list = configService.list(Wrappers.<Config>lambdaQuery().eq(Config::getConfType, 1).eq(Config::getBindId, id));
userVO.setAppConfigs(BeanCopyUtils.coverList(list, ConfigVO.class));
return userVO;
}
@Override
public UserVO getUserById(String id) {
UserVO userVO = userMapper.selectOneById(id);
// 获取用户角色
List<RoleVO> userRoles = getUserRoles(id);
userVO.setUserRoles(userRoles);
// 获取用户菜单
//List<AppMenuVO> userMenus = getUserMenus(userRoles);
//userVO.setUserMenus(userMenus);
return userVO;
}
@Override
public User login(String username, String password) {
Wrapper<User> queryWrapper = Wrappers.<User>lambdaQuery().eq(User::getLoginName, username).eq(User::getPassword, password).eq(User::getStatus, 1).last("limit 1");
User user = userMapper.selectOne(queryWrapper);
return user;
}
private List<AppMenuVO> getUserMenus(List<RoleVO> userRoles) {
List<AppMenuVO> list = new ArrayList<>();
// 获取用户所有的菜单
List<RoleMenu> roleMenus = roleMenuService.list(Wrappers.<RoleMenu>lambdaQuery().in(RoleMenu::getRoleId, userRoles.stream().map(a -> a.getId()).collect(Collectors.toList())));
// 查询出所有菜单信息
List<MenuTree> menuTrees = menuMapper.selectMenuInIds(roleMenus.stream().map(a -> a.getMenuId()).collect(Collectors.toList()), 1);
Map<String, List<MenuTree>> collect = menuTrees.stream().collect(Collectors.groupingBy(menuTree -> menuTree.getAppId()));
collect.forEach((key, value) -> {
AppMenuVO appMenuVO = new AppMenuVO();
appMenuVO.setAppId(key);
if (CollectionUtils.isNotEmpty(value)) {
appMenuVO.setAppCode(value.get(0).getAppCode());
String rootId = "0";
// 创建树形结构并返回
TreeBuild treeBuild = new TreeBuild(rootId, value);
appMenuVO.setMenuTree(treeBuild.buildTree());
}
list.add(appMenuVO);
});
return list;
}
private List<RoleVO> getUserRoles(String userId) {
List<RoleVO> list = new ArrayList<>();
// 1、基础角色
List<UserRole> userRoles = userRoleService.list(Wrappers.<UserRole>lambdaQuery().eq(UserRole::getUserId, userId));
if (CollectionUtils.isNotEmpty(userRoles)) {
for (UserRole userRole : userRoles) {
Role one = roleService.getOne(Wrappers.<Role>lambdaQuery().eq(Role::getId, userRole.getRoleId()).eq(Role::getRoleType, 1).last("limit 1"));
list.add(RoleConverter.INSTANT.entityToVO(one));
}
}
// 组织角色
// 所在部门角色
DeptUser deptUser = deptUserService.getOne(Wrappers.<DeptUser>lambdaQuery().eq(DeptUser::getUserId, userId).last("limit 1"));
List<CordRole> deptRoles = cordRoleService.list(Wrappers.<CordRole>lambdaQuery().eq(CordRole::getCordId, deptUser.getDeptId()).eq(CordRole::getCordType, 2));
if (CollectionUtils.isNotEmpty(deptRoles)) {
for (CordRole cordRole : deptRoles) {
Role one = roleService.getOne(Wrappers.<Role>lambdaQuery().eq(Role::getId, cordRole.getRoleId()).eq(Role::getRoleType, 2).last("limit 1"));
list.add(RoleConverter.INSTANT.entityToVO(one));
}
}
// 所在公司角色
CompanyDept companyDept = companyDeptService.getOne(Wrappers.<CompanyDept>lambdaQuery().eq(CompanyDept::getDeptId, deptUser.getDeptId()).last("limit 1"));
List<CordRole> companyRoles = new ArrayList<>();
if (ObjectUtils.isNotEmpty(companyDept)) {
companyRoles = cordRoleService.list(Wrappers.<CordRole>lambdaQuery().eq(CordRole::getCordId, companyDept.getCompanyId()).eq(CordRole::getCordType, 1));
}
if (CollectionUtils.isNotEmpty(companyRoles)) {
for (CordRole cordRole : companyRoles) {
Role one = roleService.getOne(Wrappers.<Role>lambdaQuery().eq(Role::getId, cordRole.getRoleId()).eq(Role::getRoleType, 2).last("limit 1"));
list.add(RoleConverter.INSTANT.entityToVO(one));
}
}
// 业务角色
UserPost userPost = userPostService.getOne(Wrappers.<UserPost>lambdaQuery().eq(UserPost::getUserId, userId).last("limit 1"));
List<PostRole> postRoles = new ArrayList<>();
if (ObjectUtils.isNotEmpty(userPost)) {
postRoles = postRoleService.list(Wrappers.<PostRole>lambdaQuery().eq(PostRole::getPostId, userPost.getPositionId()));
}
if (CollectionUtils.isNotEmpty(postRoles)) {
for (PostRole postRole : postRoles) {
Role one = roleService.getOne(Wrappers.<Role>lambdaQuery().eq(Role::getId, postRole.getRoleId()).eq(Role::getRoleType, 3).last("limit 1"));
list.add(RoleConverter.INSTANT.entityToVO(one));
}
}
// 用户组角色
List<GroupUser> groupUsers = groupUserService.list(Wrappers.<GroupUser>lambdaQuery().eq(GroupUser::getUserId, userId));
List<GroupRole> groupRoles = new ArrayList<>();
if (CollectionUtils.isNotEmpty(groupUsers)) {
groupRoles = groupRoleService.list(Wrappers.<GroupRole>lambdaQuery().in(GroupRole::getGroupId, groupUsers.stream().map(a -> a.getGroupId()).collect(Collectors.toList())));
}
if (CollectionUtils.isNotEmpty(groupRoles)) {
for (GroupRole groupRole : groupRoles) {
Role one = roleService.getOne(Wrappers.<Role>lambdaQuery().eq(Role::getId, groupRole.getRoleId()).eq(Role::getRoleType, 4).last("limit 1"));
list.add(RoleConverter.INSTANT.entityToVO(one));
}
}
// 角色集合去重返回
if (CollectionUtils.isNotEmpty(list)) {
return list.stream().distinct().collect(Collectors.toList());
}
return list;
}
}

View File

@@ -0,0 +1,178 @@
package ai.remi.boot.server.util;
import ai.remi.comm.exception.util.MessageUtils;
import ai.remi.comm.redis.service.RedisService;
import ai.remi.comm.util.asserts.AssertUtils;
import ai.remi.comm.util.id.RandomUtils;
import ai.remi.comm.util.id.UUIDUtils;
import ai.remi.comm.util.security.AesUtils;
import ai.remi.boot.domain.enums.SsoCacheEnum;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.util.Arrays;
;
/**
* @author DianJiu
* @date 2021/12/8
* @Description 随机产生唯一的app_key和app_secret
*/
@Component
public class AppUtils {
@Resource
private RedisService redisService;
public static RedisService redisUtils;
@PostConstruct
public void init() {
redisUtils = this.redisService;
}
private final static String[] chars = new String[]{"a", "b", "c", "d", "e", "f",
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
"t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",
"J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
"W", "X", "Y", "Z"};
/**
* 最大重试次数
*/
public static final int MAX_RETRY_COUNT = 10;
/**
* 最大重试记录
*/
public static int maxCount = 0;
/**
* 生成规则 年份后两位【2位】 + 1年内第几天【3位】 + 随机数【5位】
* 理论上来说,一百年内不会重复
* 注意:1.前五位保证每天生成的id不重复,后五位会在redis缓存 set集合中进行碰撞校验,
* 2.请保证每天0时清除缓存,保证缓存中的短id数量较少提高性能,减少内存浪费
*/
public static String getAppCode() {
String year = String.valueOf(LocalDateTime.now().getYear()).substring(2);
String day = String.valueOf(LocalDateTime.now().getDayOfYear());
if (day.length() < 3) {
StringBuilder sb = new StringBuilder();
for (int i = day.length(); i < 3; i++) {
sb.append("0");
}
day = sb.append(day).toString();
}
String code = year + day;
int count = 0;
boolean exists = true;
while (exists) {
if (count > maxCount) {
maxCount = count;
}
String random = RandomUtils.generateNumberString(10 - code.length());
exists = redisUtils.sSet(SsoCacheEnum.APP_CODE.getKey(code, random), code + random) == 0L;
code = code + random;
count++;
AssertUtils.isFalse(count >= MAX_RETRY_COUNT, MessageUtils.getMessage("app.code.error"));
}
return code;
}
/**
* @Description: <p>
* 短8位UUID思想其实借鉴微博短域名的生成方式,但是其重复概率过高,而且每次生成4个,需要随即选取一个。
* 本算法利用62个可打印字符,通过随机生成32位UUID,由于UUID都为十六进制,所以将UUID分成8组,每4个为一组,然后通过模62操作,结果作为索引取出字符,
* 这样重复率大大降低。
* 经测试,在生成一千万个数据也没有出现重复,完全满足大部分需求。
* </p>
* @author DianJiu
* @date 2019/8/27 16:16
*/
public static String getAppKey() {
StringBuffer shortBuffer = new StringBuffer();
String uuid = UUIDUtils.simpleUuid();
for (int i = 0; i < 8; i++) {
String str = uuid.substring(i * 4, i * 4 + 4);
int x = Integer.parseInt(str, 16);
shortBuffer.append(chars[x % 0x3E]);
}
return shortBuffer.toString().toLowerCase();
}
/**
* <p>
* 通过appId和内置关键词生成APP Secret
* </P>
*
* @author DianJiu
* @date 2019/8/27 16:32
*/
public static String getAppSecret() {
return AesUtils.initHexKey();
}
public static Boolean validate(String appKey,String appSecret) {
return appSecret.equals(getAppSecret(appKey));
}
/**
* <p>
* 通过appId和内置关键词生成APP Secret
* </P>
*
* @author DianJiu
* @date 2019/8/27 16:32
*/
public static String getAppSecret(String appKey) {
try {
String[] array = new String[]{appKey};
StringBuffer sb = new StringBuffer();
// 字符串排序
Arrays.sort(array);
for (int i = 0; i < array.length; i++) {
sb.append(array[i]);
}
String str = sb.toString();
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(str.getBytes());
byte[] digest = md.digest();
StringBuffer hexstr = new StringBuffer();
String shaHex = "";
for (int i = 0; i < digest.length; i++) {
shaHex = Integer.toHexString(digest[i] & 0xFF);
if (shaHex.length() < 2) {
hexstr.append(0);
}
hexstr.append(shaHex);
}
return hexstr.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException();
}
}
public static void main(String[] args) {
//for (int i = 0; i < 10000; i++) {
// getAppCode();
//}
//System.out.println("最大碰撞次数为=>" + AppUtils.maxCount);
//String appCode = getAppCode();
String appKey = getAppKey();
String appSecret = getAppSecret(appKey);
//System.out.println("appCode: " + appCode);
System.out.println("appKey: " + appKey);
System.out.println("appSecret: " + appSecret);
}
}

View File

@@ -0,0 +1,21 @@
package ai.remi.boot.server.util;
import ai.remi.comm.util.security.Base64Utils;
import ai.remi.comm.util.string.StringUtils;
import org.springframework.util.DigestUtils;
import java.nio.charset.StandardCharsets;
public class AuthUtils {
public static String getAuthCode(String appKey, String state) {
String encode = Base64Utils.encode(appKey + state);
if (StringUtils.isNotBlank(encode)) {
return DigestUtils.md5DigestAsHex(encode.getBytes(StandardCharsets.UTF_8));
}
return "";
}
public static void main(String[] args) {
System.out.println(getAuthCode("AB123CE","123456"));
}
}