feat:修复已知问题,提升系统稳定性
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user