package com.gree.ecommerce.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gree.ecommerce.config.InheritableThreadPoolTaskExecutor;
import com.gree.ecommerce.constant.Constant;
import com.gree.ecommerce.constant.ServerResultCode;
import com.gree.ecommerce.exception.BusinessException;
import com.gree.ecommerce.module.user.BaseUserRedisVO;
import com.gree.ecommerce.module.user.EocLoginUserRedisVO;
import com.gree.ecommerce.module.user.LoginUserRedisVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 用户数据相关工具类
*
* @createDate 2021/12/15
*/
@Slf4j
public class UserUtils {
static RedisUtil redisUtil = new RedisUtil();
public UserUtils(RedisUtil ru) {
redisUtil = ru;
}
static Supplier<BusinessException> resultUserNotLoginEx = () -> new BusinessException(ServerResultCode.USER_NOT_LOGGED_IN);
/**
* 从请求头中获得token => 再通过redis获取用户信息
*
* @return 用户基础信息
* @throws BusinessException token不存在则会抛出 , 返回码为 {@link ServerResultCode#USER_NOT_LOGGED_IN }
* @createDate 2021/12/20
*/
public static BaseUserRedisVO getBaseUserRedisInfo() {
return HttpRequestUtil.getHttpHeader(Constant.AUTHORIZATION)
.map(authStr -> redisUtil.get(authStr))
.map(str -> JSON.parseObject(str, BaseUserRedisVO.class))
.orElseGet(() -> Optional.ofNullable(
JSON.parseObject(InheritableThreadPoolTaskExecutor.THREAD_USER_INFO_CACHE.get(), BaseUserRedisVO.class))
.orElseThrow(resultUserNotLoginEx)
);
}
/**
* 从请求头中获得token => 再通过redis获取用户信息
*
* @return 商城用户信息
* @throws BusinessException token不存在则会抛出 , 返回码为 {@link ServerResultCode#USER_NOT_LOGGED_IN }
* @createDate 2021/12/20
*/
public static LoginUserRedisVO getMallUserInfo() {
return HttpRequestUtil.getHttpHeader(Constant.AUTHORIZATION)
.map(authStr -> redisUtil.get(authStr))
.map(str -> JSON.parseObject(str, LoginUserRedisVO.class))
.orElseGet(()->
Optional.ofNullable(JSON.parseObject(InheritableThreadPoolTaskExecutor.THREAD_USER_INFO_CACHE.get(), LoginUserRedisVO.class))
.orElseThrow(resultUserNotLoginEx));
}
/**
* 更新商城用户登录的redis信息
*
* @param modify 需要修改的属性
* @author zhouMJ
**/
public static void modifyMallUserRedisInfo(LoginUserRedisVO modify) {
Stream.of(getPlatAllXflagTokenGroup(Constant.PLATFORM_FLAG_SELLER, modify.getUserId()),
getPlatAllXflagTokenGroup(Constant.PLATFORM_FLAG_MALL, modify.getUserId()),
getPlatAllXflagTokenGroup(Constant.PLATFORM_FLAG_ALL_SALES, modify.getUserId()))
.filter(CollectionUtils::isNotEmpty)
.flatMap(Collection::stream)
.filter(StringUtils::isNotBlank)
//查出商城用户的token
.forEach(key -> {
String redisStr = redisUtil.get(key);
if (StringUtils.isNotEmpty(redisStr)) {
LoginUserRedisVO redisVO = generateMallModifyVO(redisStr, modify);
//修改属性值
redisUtil.setEx(key, JSONObject.toJSONString(redisVO), Constant.REDIS_MALL_USER_LOGIN_TOKEN_TTL, TimeUnit.MINUTES);
}
});
}
/**
* 生成商城用户的redis信息修改后的属性对象
*
* @param redisStr redis的json串
* @param modify 需要修改的属性
* @return LoginUserRedisVO 商城用户的redis信息修改后的属性对象
**/
private static LoginUserRedisVO generateMallModifyVO(String redisStr, LoginUserRedisVO modify) {
LoginUserRedisVO vo = JSONObject.parseObject(redisStr, LoginUserRedisVO.class);
if (StringUtils.isNotEmpty(modify.getUserAcc())) {
vo.setUserAcc(modify.getUserAcc());
}
if (StringUtils.isNotEmpty(modify.getNickName())) {
vo.setNickName(modify.getNickName());
}
if (StringUtils.isNotEmpty(modify.getMobile())) {
vo.setMobile(modify.getMobile());
}
if (StringUtils.isNotEmpty(modify.getType())) {
vo.setType(modify.getType());
}
return vo;
}
/**
* eoc退出登录
*/
public static void eocLoginOut() {
//删除token信息
redisUtil.delete(getToken());
//删除token群组中的token值
String tokenGroupKey = String.format(Constant.REDIS_USER_TOKEN_LIST_KEY, getBaseUserRedisInfo().getUserId(), getPlatformFlag(), getXFlag());
redisUtil.lRemove(tokenGroupKey, Constant.ONE, getToken());
//删除用户的权限变化标识
delSignUserPower();
}
/**
* 商城退出登录
*/
public static void mallLoginOut() {
//删除token信息
redisUtil.delete(getToken());
//删除token群组中的token值
String tokenGroupKey = String.format(Constant.REDIS_USER_TOKEN_LIST_KEY, getBaseUserRedisInfo().getUserId(), getPlatformFlag(), getXFlag());
redisUtil.lRemove(tokenGroupKey, Constant.ONE, getToken());
//如果是卖家中心的,删除用户的权限变化标识
if (getPlatformFlag().equals(Constant.PLATFORM_FLAG_SELLER)) {
delSignUserPower();
}
}
/**
* 从请求头中获得token
*
* @return 请求头token,不存在会返回空字符串
*/
public static String getToken() {
return HttpRequestUtil.getHttpHeader(Constant.AUTHORIZATION).orElse("");
}
/**
* 从请求头中获得权限菜单路由
*
* @return 请求头权限菜单路由,不存在会返回空字符串
*/
public static String getPowerMenuPath() {
return HttpRequestUtil.getHttpHeader(Constant.POWER_MENU_PATH).orElse("");
}
/**
* 从请求头中获得端标识
*
* @return 请求头端标识 不存在会返回空字符串
*/
public static String getXFlag() {
return HttpRequestUtil.getHttpHeader(Constant.X_FLAG).orElse("");
}
/**
* 从请求头中获得端标识
*
* @return 请求头端标识,不存在会返回空字符串
*/
public static String getPlatformFlag() {
return HttpRequestUtil.getHttpHeader(Constant.PLATFORM_FLAG).orElse("");
}
/**
* 从请求头中获得token => 再通过redis获取用户信息
*
* @return eoc用户信息
* @throws BusinessException token不存在则会抛出 , 返回码为 {@link ServerResultCode#USER_NOT_LOGGED_IN }
* @createDate 2021/12/20
*/
public static EocLoginUserRedisVO getEocUserInfo() {
return HttpRequestUtil.getHttpHeader(Constant.AUTHORIZATION)
.map(authStr -> redisUtil.get(authStr))
.map(str -> JSON.parseObject(str, EocLoginUserRedisVO.class))
.orElseGet(()->
Optional.ofNullable(JSON.parseObject(InheritableThreadPoolTaskExecutor.THREAD_USER_INFO_CACHE.get(), EocLoginUserRedisVO.class))
.orElseThrow(resultUserNotLoginEx));
}
/**
* 更新eoc用户登录的redis信息
*
* @param modify 需要修改的属性
* @author zhouMJ
**/
public static void modifyEocUserRedisInfo(EocLoginUserRedisVO modify) {
//查询eoc的token的key集合
List<String> tokenKeys = getPlatAllXflagTokenGroup(getPlatformFlag(), modify.getUserId());
tokenKeys.forEach(key -> {
String redisStr = redisUtil.get(key);
if (StringUtils.isNotEmpty(redisStr)) {
EocLoginUserRedisVO redisVO = generateEocModifyVO(redisStr, modify);
//修改属性值
redisUtil.setEx(key, JSONObject.toJSONString(redisVO), Constant.REDIS_SYS_USER_LOGIN_TOKEN_TTL, TimeUnit.MINUTES);
}
});
}
/**
* 生成eoc用户的redis信息修改后的属性对象
*
* @param redisStr redis的json串
* @param modify 需要修改的属性
* @return LoginUserRedisVO 用户的redis信息修改后的属性对象
**/
private static EocLoginUserRedisVO generateEocModifyVO(String redisStr, EocLoginUserRedisVO modify) {
EocLoginUserRedisVO vo = JSONObject.parseObject(redisStr, EocLoginUserRedisVO.class);
if (StringUtils.isNotEmpty(modify.getUserAcc())) {
vo.setUserAcc(modify.getUserAcc());
}
if (StringUtils.isNotEmpty(modify.getEmpName())) {
vo.setEmpName(modify.getEmpName());
}
if (StringUtils.isNotEmpty(modify.getMobile())) {
vo.setMobile(modify.getMobile());
}
return vo;
}
/**
* eoc强制清空用户token
*
* @param userId 用户id
**/
public static void eocClearUserToken(Long userId) {
redisUtil.delete(getPlatAllXflagTokenGroup(Constant.PLATFORM_FLAG_EOC, userId));
}
/**
* eoc标识用户权限变化
*
* @param userIds 用户ids
**/
public static void eocSignUserPowerUpdate(List<Long> userIds) {
List<String> signUserKeys = userIds.stream()
//拿到用户下的token组
.map(userId -> getPlatAndXflagTokenGroup(Constant.PLATFORM_FLAG_EOC, Constant.X_REQ_PC, userId))
.flatMap(Collection::stream)
//按照token的维度标识权限变化
.map(UserUtils::getSignUserPowerKey)
.collect(Collectors.toList());
log.info("eoc标识用户权限变化eocSignUserPowerUpdate,keys:{}", signUserKeys);
for (String key: signUserKeys) {
redisUtil.setEx(key, Constant.TRUE_STR, 7, TimeUnit.HOURS);
}
}
/**
* 卖家中心标识用户权限变化
*
* @param userIds 用户ids
**/
public static void sellerSignUserPowerUpdate(List<Long> userIds) {
List<String> signUserKeys = userIds.stream()
//拿到用户下的token组
.map(userId -> getPlatAndXflagTokenGroup(Constant.PLATFORM_FLAG_SELLER, Constant.X_REQ_PC, userId))
.flatMap(Collection::stream)
//按照token的维度标识权限变化
.map(UserUtils::getSignUserPowerKey)
.collect(Collectors.toList());
log.info("卖家中心标识用户权限变化sellerSignUserPowerUpdate,keys:{}", signUserKeys);
for (String key: signUserKeys) {
redisUtil.setEx(key, Constant.TRUE_STR, 7, TimeUnit.HOURS);
}
}
public static String getSignUserPowerKey(String token) {
return String.format(Constant.REDIS_USER_TOKEN_POWER_UPDATE_SIGN_KEY,
getPlatformFlag(),
getXFlag(),
token);
}
/**
* 删除用户权限变化标识
**/
public static void delSignUserPower() {
redisUtil.delete(getSignUserPowerKey(getToken()));
}
/**
* 卖家中心强制清空用户token
*
* @param userId 用户id
**/
public static void sellerClearUserToken(Long userId) {
redisUtil.delete(getPlatAllXflagTokenGroup(Constant.PLATFORM_FLAG_SELLER, userId));
}
/**
* 得到平台所有端的token群组
*
* @param platform 平台标识
* @param userId 用户id
* @return java.util.List<java.lang.String> 平台所有端的token集合
* @author gree
**/
public static List<String> getPlatAllXflagTokenGroup(String platform, Long userId) {
return Stream.of(getPlatAndXflagTokenGroup(platform, Constant.X_REQ_H5, userId),
getPlatAndXflagTokenGroup(platform, Constant.X_REQ_MINI, userId),
getPlatAndXflagTokenGroup(platform, Constant.X_REQ_ANDROID, userId),
getPlatAndXflagTokenGroup(platform, Constant.X_REQ_IOS, userId),
getPlatAndXflagTokenGroup(platform, Constant.X_REQ_PC, userId))
.filter(CollectionUtils::isNotEmpty)
.flatMap(Collection::stream)
.filter(StringUtils::isNotBlank)
.collect(Collectors.toList());
}
/**
* 得到平台对应端的token群组
*
* @param platform 平台标识
* @param xflag 端标识
* @param userId 用户id
* @return java.util.List<java.lang.String> 平台对应端的token群组
* @author gree
**/
public static List<String> getPlatAndXflagTokenGroup(String platform, String xflag, Long userId) {
String key = String.format(Constant.REDIS_USER_TOKEN_LIST_KEY, userId, platform, xflag);
return redisUtil.lRange(key, Constant.ZERO, Constant.NEGATIVE_NUMBER_ONE);
}
/**
* 董店注销用户 退出董店、pc商城、全员销售、卖家中心的系统
**/
public static void mallDelUser(Long userId) {
List<String> mallUserAllToken = Stream.of(getPlatAllXflagTokenGroup(Constant.PLATFORM_FLAG_SELLER, userId),
getPlatAllXflagTokenGroup(Constant.PLATFORM_FLAG_MALL, userId),
getPlatAllXflagTokenGroup(Constant.PLATFORM_FLAG_ALL_SALES, userId))
.flatMap(Collection::stream)
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(mallUserAllToken)) {
redisUtil.delete(mallUserAllToken);
}
}
}