UserUtils.java

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);
        }
    }
}

HttpRequestUtil.java

package com.gree.ecommerce.utils;

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Optional;

/**
 * @author A80080
 * @createDate 2022/1/4
 */
public class HttpRequestUtil {


    /**
     * 获取当前请求session
     *
     * @return 返回request
     */
    public static Optional<HttpServletRequest> getHttpServletRequest() {
        return getServletRequestAttributes().map(ServletRequestAttributes::getRequest);
    }

    /**
     * 获取当前请求Attributes
     *
     * @return 返回Attributes
     */
    public static Optional<ServletRequestAttributes> getServletRequestAttributes() {
        return Optional.ofNullable(RequestContextHolder.getRequestAttributes())
                .map(s -> (ServletRequestAttributes) s);
    }

    /**
     * 设置请求Attributes inheritable参数为true
     *
     * @return 返回Attributes
     */
    public static Optional<ServletRequestAttributes> setInheritableServletRequestAttributes() {
        Optional<ServletRequestAttributes> attributesOpt = getServletRequestAttributes();
        attributesOpt.ifPresent(servletRequestAttributes -> RequestContextHolder.setRequestAttributes(servletRequestAttributes, true));
        return attributesOpt;
    }

    /**
     * 获取当前请求中指定的header
     *
     * @param name headerName
     * @return 指定headerName对应的值
     */
    public static Optional<String> getHttpHeader(String name) {
        return getHttpServletRequest().map(request -> request.getHeader(name));
    }
}