All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.lx.boot.OS Maven / Gradle / Ivy

package com.lx.boot;//说明:

/**
 * 创建人:游林夕/2019/4/28 09 04
 */

import com.lx.annotation.Note;
import com.lx.boot.web.AuthUtil;
import com.lx.entity.CustomDbInfo;
import com.lx.entity.ExpireCache;
import com.lx.entity.UserInfo;
import com.lx.entity.Var;
import com.lx.util.LX;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.util.StreamUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.lx.constant.DefaultBaseConstant.*;
import static com.lx.constant.DefaultRedisConstant.RedisPrefix.NUMBER_OF_LIMIT;

@Slf4j
@Configuration
public class OS implements BeanPostProcessor, ApplicationContextAware, EnvironmentAware {
    private static final ThreadLocal> tl = new ThreadLocal() {
        @Override
        protected Map initialValue() {
            return new HashMap(4);
        }
    };

    private static Environment environment;
    private static ApplicationContext applicationContext;
    private static StringRedisTemplate stringRedisTemplate;
    @Note("缓存系统配置,提高效率")
    private static ExpireCache expireCache = new ExpireCache();

    @Note("获取当前线程ThreadLocal里存储的数据")
    public static  T get(String key){
        return (T) tl.get().get(key);
    }
    @Note("当前线程ThreadLocal进行存储数据")
    public static void put(String key,Object obj){
        tl.get().put(key,obj);
    }
    @Note("删除当前线程ThreadLocal里存储的数据")
    public static void del(String key){
        tl.get().remove(key);
    }
    @Note("清理当前线程ThreadLocal里存储的所有数据")
    public static void remove(){
        tl.remove();
    }

    @Note("设置用户信息")
    public static void setUserInfo(UserInfo userInfo){
        put(USER_INFO, userInfo);
    }
    @Note("获取用户信息")
    public static UserInfo getUserInfo(){
        return LX.ifNull(get(USER_INFO), new UserInfo());
    }
    @Note("获取用户信息")
    public static UserInfo getRealUserInfo(){
        return get(USER_INFO);
    }
    @Note("获取用户信息, T为UserInfo的子类")
    public static T getUserInfo(Class t){
        return OS.getBean(AuthUtil.class).getUserInfo(t,getRequest());
    }
    @Note("获取用户ID")
    public static String getUserId(){
        return getUserInfo().getUserId();
    }
    @Note("获取用户类型")
    public static String getUserType(){
        return getUserInfo().getUserType();
    }
    @Note("设置自定义数据源链接")
    public static void setCustomDbInfo(CustomDbInfo customDbInfo){
        put(CUSTOM_DB_INFO, customDbInfo);
    }

    @Note("获取自定义数据源信息")
    public static CustomDbInfo getCustomDbInfo(){
        return get(CUSTOM_DB_INFO);
    }

    @Note("删除自定义数据源信息")
    public static void delCustomDbInfo(){
        del(CUSTOM_DB_INFO);
    }

    @Note("通过name获取 Bean对象")
    public static T getBean(String name){
        return (T)applicationContext.getBean(name);
    }

    @Note("通过Class类型获取 Bean对象")
    public static T getBean(Class t){
        return applicationContext.getBean(t);
    }

    @Note("设置公司ID")
    public static void setFirmId(String firmId){
        put(FIRM_ID, firmId);
    }

    @Note("获取公司ID")
    public static String getFirmId(){
        return get(FIRM_ID);
    }

    @Note("设置第三方接口appid")
    public static void setAppId(String appId){
        put(API_APPID, appId);
    }
    @Note("获取第三方接口appid")
    public static String getAppId(){
        return get(API_APPID);
    }

    @Note("获取配置文件中配置, 优先获取firmid.key 没有获取 key对应的配置信息")
    public static String getProperty(String key){
        if (environment == null){
            return null;
        }
        // 直接获取比较慢
        return expireCache.get(key, ()->{
            return LX.ifNull(environment.getProperty(OS.getFirmId()+"."+key),()->{return environment.getProperty(key);});
        });
    }
    @Note("获取配置文件中配置, 为null时取默认值")
    public static String getProperty(String key, String defaultValue){
        return LX.ifNull(getProperty(key) ,defaultValue);
    }
    @Note("获取配置文件中配置,转成int类型")
    public static int getIntProperty(String key, String defaultValue){
        return Integer.parseInt(getProperty(key, defaultValue));
    }
    @Note("获取配置文件中配置是否是1")
    public static boolean getPropertyEquals1(String key, String defaultValue){
        return "1".equals(getProperty(key,defaultValue));
    }
    @Note("获取配置文件中配置是否是true")
    public static boolean getPropertyIsTrue(String key, String defaultValue){
        return "true".equals(getProperty(key,defaultValue));
    }
    @Note("动态修改系统配置")
    public static void setProperty(Map map){
        addProperty("os.defaultProperty",map);
    }

    @Note("通过程序新增配置 name:配置信息标识, map:配置信息; 注意name名称相同时配置信息会被覆盖")
    public static void addProperty(String name , Map map){
        if (environment == null){
            environment = new StandardEnvironment();
        }
        ConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment) environment;
        MapPropertySource propertySource = new MapPropertySource(name,map);
        configurableEnvironment.getPropertySources().addFirst(propertySource);
    }

    @Note("获取当前服务名")
    public static String getApplicationName(){
        return getProperty("spring.application.name","");
    }

    @Note("获取当前环境, 配置信息中的spring.profiles.active")
    public static String getEnv(){
        return getProperty("spring.profiles.active");
    }

    @Note("判断当前环境是否为dev环境")
    public static boolean isDev(){
        return "dev".equals(getProperty("spring.profiles.active"));
    }

    @Note("判断当前环境是否为prod环境")
    public static boolean isProd(){
        return "prod".equals(getProperty("spring.profiles.active"));
    }

    @Note("设置日志追踪ID")
    public static void setLogTraceId(){
        setLogTraceId(LX.uuid32(10));
    }

    @Note("设置日志追踪ID")
    public static void setLogTraceId(String requestId){
        MDC.put("requestId", requestId);
    }

    @Note("获取日志追踪ID")
    public static String getLogTraceId(){
        return MDC.get("requestId");
    }

    @Note("设置指定包下的日志等级")
    public static void setLogLevel(String packageName , LogLevel logLevel){
        getBean(LoggingSystem.class).setLogLevel(packageName, logLevel);
    }

    @Note("获取当前线程的HttpServletRequest")
    public static HttpServletRequest getRequest(){
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    }

    @Note("获取请求头里的参数")
    public static String getHeader(String key) {
        return getRequest().getHeader(key);
    }

    private static final List POST_METHOD = Arrays.asList("POST","PUT");

    @Note("获取Request的参数")
    public static Var getParamter() throws IOException {
        HttpServletRequest request = getRequest();
        if (POST_METHOD.contains(request.getMethod().toUpperCase())) {
            return LX.toMap(StreamUtils.copyToString(request.getInputStream(), Charset.forName("UTF-8")));
        }else{
            Var res = new Var();
            request.getParameterMap().forEach((k,v)->{
                res.put(k, v[0]);
            });
            return res;
        }
    }

    @Note("单位时间内指定key调用次数; key:限制标识, callFrequency:次数/时间 [1-9]\\d{0,5}/([M,d]|([1-9]\\d{0,3}[H,m,s]))")
    public static boolean allowAccessByCallFrequency(String key, String callFrequency) {
        //次数/ 时间
        if (!callFrequency.matches("[1-9]\\d{0,5}/([M,d]|([1-9]\\d{0,3}[H,m,s]))")){
            LX.exMsg("接口限制次数配置有误!=> [1-9]\\d{0,5}/([M,d]|([1-9]\\d{0,3}[H,m,s]))");
        }
        String [] arr = callFrequency.split("/");
        switch (callFrequency.charAt(callFrequency.length()-1)){
            case 'M':
                return allowAccessTo(LX.getDate("yyyy-MM")+":"+key,arr[0], TimeUnit.DAYS.toSeconds(31)+"");
            case 'd':
                return allowAccessTo(LX.getDate("yyyy-MM-dd")+":"+key,arr[0], TimeUnit.DAYS.toSeconds(1)+"");
            case 'H':
                return allowAccessTo(key,arr[0],TimeUnit.HOURS.toSeconds(Integer.parseInt(arr[1].substring(0,arr[1].length()-1)))+"");
            case 'm':
                return allowAccessTo(key,arr[0],TimeUnit.MINUTES.toSeconds(Integer.parseInt(arr[1].substring(0,arr[1].length()-1)))+"");
            case 's':
                return allowAccessTo(key,arr[0],arr[1].substring(0,arr[1].length()-1)+"");
            default:
                return false;
        }
    }
    @Note("单位时间内指定key调用次数,limit:次数 , time:秒")
    public static boolean allowAccessTo(String key , String limit, String time){
        String lua = "local limit = tonumber(ARGV[1]);local time = tonumber(ARGV[2]);local ttl = redis.call(\"ttl\",KEYS[1]);local incr = redis.call(\"incr\",KEYS[1]);if (ttl > 0) then if incr > limit then return ttl;end;else redis.call(\"expire\",KEYS[1],ARGV[2]);end;return 0;";
        key = NUMBER_OF_LIMIT +key;
        DefaultRedisScript redisScript = new DefaultRedisScript<>();
        redisScript.setScriptText(lua);
        redisScript.setResultType(Long.class);
        return stringRedisTemplate.execute(redisScript, Arrays.asList(key),limit,time) == 0;
    }
    @Note("清除已记录单位时间内的key")
    public static void allowAccessKeyClear(String key){
        stringRedisTemplate.delete(NUMBER_OF_LIMIT +key);
    }

    @Note("判断当前ip是否匹配白名单")
    public static boolean allowAccessByIp(String ipWhiteList){
        String ip = OS.getIp(getRequest());
        return !(LX.isEmpty(ip) || LX.isEmpty(ipWhiteList) || !ip.matches(ipWhiteList));
    }
    @Note("获取当前调用者IP")
    public static String getIp() {
        return getIp(getRequest());
    }

    @Note("获取Request的IP")
    public static String getIp(HttpServletRequest request) {
        String ip = request.getHeader("x-real-ip");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("x-forwarded-for");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        if ("0:0:0:0:0:0:0:1".equals(ip)){
            return "127.0.0.1";
        }
        return ip;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        OS.applicationContext = applicationContext;
        stringRedisTemplate = getBean(StringRedisTemplate.class);
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    @Override
    public void setEnvironment(Environment environment) {
        OS.environment = environment;
    }

    public static Environment getEnvironment() {
        return environment;
    }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy