mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 12:18:42 +08:00 
			
		
		
		
	若依 3.0
This commit is contained in:
		@@ -0,0 +1,165 @@
 | 
			
		||||
package com.ruoyi.framework.aspectj;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.Method;
 | 
			
		||||
import org.aspectj.lang.JoinPoint;
 | 
			
		||||
import org.aspectj.lang.Signature;
 | 
			
		||||
import org.aspectj.lang.annotation.Aspect;
 | 
			
		||||
import org.aspectj.lang.annotation.Before;
 | 
			
		||||
import org.aspectj.lang.annotation.Pointcut;
 | 
			
		||||
import org.aspectj.lang.reflect.MethodSignature;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import com.ruoyi.common.annotation.DataScope;
 | 
			
		||||
import com.ruoyi.common.core.domain.BaseEntity;
 | 
			
		||||
import com.ruoyi.common.core.domain.entity.SysRole;
 | 
			
		||||
import com.ruoyi.common.core.domain.entity.SysUser;
 | 
			
		||||
import com.ruoyi.common.core.domain.model.LoginUser;
 | 
			
		||||
import com.ruoyi.common.utils.ServletUtils;
 | 
			
		||||
import com.ruoyi.common.utils.StringUtils;
 | 
			
		||||
import com.ruoyi.common.utils.spring.SpringUtils;
 | 
			
		||||
import com.ruoyi.framework.web.service.TokenService;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 数据过滤处理
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Aspect
 | 
			
		||||
@Component
 | 
			
		||||
public class DataScopeAspect
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * 全部数据权限
 | 
			
		||||
     */
 | 
			
		||||
    public static final String DATA_SCOPE_ALL = "1";
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 自定数据权限
 | 
			
		||||
     */
 | 
			
		||||
    public static final String DATA_SCOPE_CUSTOM = "2";
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 部门数据权限
 | 
			
		||||
     */
 | 
			
		||||
    public static final String DATA_SCOPE_DEPT = "3";
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 部门及以下数据权限
 | 
			
		||||
     */
 | 
			
		||||
    public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 仅本人数据权限
 | 
			
		||||
     */
 | 
			
		||||
    public static final String DATA_SCOPE_SELF = "5";
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 数据权限过滤关键字
 | 
			
		||||
     */
 | 
			
		||||
    public static final String DATA_SCOPE = "dataScope";
 | 
			
		||||
 | 
			
		||||
    // 配置织入点
 | 
			
		||||
    @Pointcut("@annotation(com.ruoyi.common.annotation.DataScope)")
 | 
			
		||||
    public void dataScopePointCut()
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Before("dataScopePointCut()")
 | 
			
		||||
    public void doBefore(JoinPoint point) throws Throwable
 | 
			
		||||
    {
 | 
			
		||||
        handleDataScope(point);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void handleDataScope(final JoinPoint joinPoint)
 | 
			
		||||
    {
 | 
			
		||||
        // 获得注解
 | 
			
		||||
        DataScope controllerDataScope = getAnnotationLog(joinPoint);
 | 
			
		||||
        if (controllerDataScope == null)
 | 
			
		||||
        {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        // 获取当前的用户
 | 
			
		||||
        LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());
 | 
			
		||||
        SysUser currentUser = loginUser.getUser();
 | 
			
		||||
        if (currentUser != null)
 | 
			
		||||
        {
 | 
			
		||||
            // 如果是超级管理员,则不过滤数据
 | 
			
		||||
            if (!currentUser.isAdmin())
 | 
			
		||||
            {
 | 
			
		||||
                dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),
 | 
			
		||||
                        controllerDataScope.userAlias());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 数据范围过滤
 | 
			
		||||
     * 
 | 
			
		||||
     * @param joinPoint 切点
 | 
			
		||||
     * @param user 用户
 | 
			
		||||
     * @param alias 别名
 | 
			
		||||
     */
 | 
			
		||||
    public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias)
 | 
			
		||||
    {
 | 
			
		||||
        StringBuilder sqlString = new StringBuilder();
 | 
			
		||||
 | 
			
		||||
        for (SysRole role : user.getRoles())
 | 
			
		||||
        {
 | 
			
		||||
            String dataScope = role.getDataScope();
 | 
			
		||||
            if (DATA_SCOPE_ALL.equals(dataScope))
 | 
			
		||||
            {
 | 
			
		||||
                sqlString = new StringBuilder();
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            else if (DATA_SCOPE_CUSTOM.equals(dataScope))
 | 
			
		||||
            {
 | 
			
		||||
                sqlString.append(StringUtils.format(
 | 
			
		||||
                        " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias,
 | 
			
		||||
                        role.getRoleId()));
 | 
			
		||||
            }
 | 
			
		||||
            else if (DATA_SCOPE_DEPT.equals(dataScope))
 | 
			
		||||
            {
 | 
			
		||||
                sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
 | 
			
		||||
            }
 | 
			
		||||
            else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))
 | 
			
		||||
            {
 | 
			
		||||
                sqlString.append(StringUtils.format(
 | 
			
		||||
                        " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
 | 
			
		||||
                        deptAlias, user.getDeptId(), user.getDeptId()));
 | 
			
		||||
            }
 | 
			
		||||
            else if (DATA_SCOPE_SELF.equals(dataScope))
 | 
			
		||||
            {
 | 
			
		||||
                if (StringUtils.isNotBlank(userAlias))
 | 
			
		||||
                {
 | 
			
		||||
                    sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId()));
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    // 数据权限为仅本人且没有userAlias别名不查询任何数据
 | 
			
		||||
                    sqlString.append(" OR 1=0 ");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (StringUtils.isNotBlank(sqlString.toString()))
 | 
			
		||||
        {
 | 
			
		||||
            BaseEntity baseEntity = (BaseEntity) joinPoint.getArgs()[0];
 | 
			
		||||
            baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否存在注解,如果存在就获取
 | 
			
		||||
     */
 | 
			
		||||
    private DataScope getAnnotationLog(JoinPoint joinPoint)
 | 
			
		||||
    {
 | 
			
		||||
        Signature signature = joinPoint.getSignature();
 | 
			
		||||
        MethodSignature methodSignature = (MethodSignature) signature;
 | 
			
		||||
        Method method = methodSignature.getMethod();
 | 
			
		||||
 | 
			
		||||
        if (method != null)
 | 
			
		||||
        {
 | 
			
		||||
            return method.getAnnotation(DataScope.class);
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,72 @@
 | 
			
		||||
package com.ruoyi.framework.aspectj;
 | 
			
		||||
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import org.aspectj.lang.ProceedingJoinPoint;
 | 
			
		||||
import org.aspectj.lang.annotation.Around;
 | 
			
		||||
import org.aspectj.lang.annotation.Aspect;
 | 
			
		||||
import org.aspectj.lang.annotation.Pointcut;
 | 
			
		||||
import org.aspectj.lang.reflect.MethodSignature;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
import org.springframework.core.annotation.AnnotationUtils;
 | 
			
		||||
import org.springframework.core.annotation.Order;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import com.ruoyi.common.annotation.DataSource;
 | 
			
		||||
import com.ruoyi.common.utils.StringUtils;
 | 
			
		||||
import com.ruoyi.framework.datasource.DynamicDataSourceContextHolder;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 多数据源处理
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Aspect
 | 
			
		||||
@Order(1)
 | 
			
		||||
@Component
 | 
			
		||||
public class DataSourceAspect
 | 
			
		||||
{
 | 
			
		||||
    protected Logger logger = LoggerFactory.getLogger(getClass());
 | 
			
		||||
 | 
			
		||||
    @Pointcut("@annotation(com.ruoyi.common.annotation.DataSource)"
 | 
			
		||||
            + "|| @within(com.ruoyi.common.annotation.DataSource)")
 | 
			
		||||
    public void dsPointCut()
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Around("dsPointCut()")
 | 
			
		||||
    public Object around(ProceedingJoinPoint point) throws Throwable
 | 
			
		||||
    {
 | 
			
		||||
        DataSource dataSource = getDataSource(point);
 | 
			
		||||
 | 
			
		||||
        if (StringUtils.isNotNull(dataSource))
 | 
			
		||||
        {
 | 
			
		||||
            DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            return point.proceed();
 | 
			
		||||
        }
 | 
			
		||||
        finally
 | 
			
		||||
        {
 | 
			
		||||
            // 销毁数据源 在执行方法之后
 | 
			
		||||
            DynamicDataSourceContextHolder.clearDataSourceType();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取需要切换的数据源
 | 
			
		||||
     */
 | 
			
		||||
    public DataSource getDataSource(ProceedingJoinPoint point)
 | 
			
		||||
    {
 | 
			
		||||
        MethodSignature signature = (MethodSignature) point.getSignature();
 | 
			
		||||
        DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);
 | 
			
		||||
        if (Objects.nonNull(dataSource))
 | 
			
		||||
        {
 | 
			
		||||
            return dataSource;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,217 @@
 | 
			
		||||
package com.ruoyi.framework.aspectj;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.Method;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import org.aspectj.lang.JoinPoint;
 | 
			
		||||
import org.aspectj.lang.Signature;
 | 
			
		||||
import org.aspectj.lang.annotation.AfterReturning;
 | 
			
		||||
import org.aspectj.lang.annotation.AfterThrowing;
 | 
			
		||||
import org.aspectj.lang.annotation.Aspect;
 | 
			
		||||
import org.aspectj.lang.annotation.Pointcut;
 | 
			
		||||
import org.aspectj.lang.reflect.MethodSignature;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import org.springframework.web.multipart.MultipartFile;
 | 
			
		||||
import org.springframework.web.servlet.HandlerMapping;
 | 
			
		||||
import com.alibaba.fastjson.JSON;
 | 
			
		||||
import com.ruoyi.common.annotation.Log;
 | 
			
		||||
import com.ruoyi.common.core.domain.model.LoginUser;
 | 
			
		||||
import com.ruoyi.common.enums.BusinessStatus;
 | 
			
		||||
import com.ruoyi.common.enums.HttpMethod;
 | 
			
		||||
import com.ruoyi.common.utils.ServletUtils;
 | 
			
		||||
import com.ruoyi.common.utils.StringUtils;
 | 
			
		||||
import com.ruoyi.common.utils.ip.IpUtils;
 | 
			
		||||
import com.ruoyi.common.utils.spring.SpringUtils;
 | 
			
		||||
import com.ruoyi.framework.manager.AsyncManager;
 | 
			
		||||
import com.ruoyi.framework.manager.factory.AsyncFactory;
 | 
			
		||||
import com.ruoyi.framework.web.service.TokenService;
 | 
			
		||||
import com.ruoyi.system.domain.SysOperLog;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 操作日志记录处理
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Aspect
 | 
			
		||||
@Component
 | 
			
		||||
public class LogAspect
 | 
			
		||||
{
 | 
			
		||||
    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
 | 
			
		||||
 | 
			
		||||
    // 配置织入点
 | 
			
		||||
    @Pointcut("@annotation(com.ruoyi.common.annotation.Log)")
 | 
			
		||||
    public void logPointCut()
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 处理完请求后执行
 | 
			
		||||
     *
 | 
			
		||||
     * @param joinPoint 切点
 | 
			
		||||
     */
 | 
			
		||||
    @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
 | 
			
		||||
    public void doAfterReturning(JoinPoint joinPoint, Object jsonResult)
 | 
			
		||||
    {
 | 
			
		||||
        handleLog(joinPoint, null, jsonResult);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 拦截异常操作
 | 
			
		||||
     * 
 | 
			
		||||
     * @param joinPoint 切点
 | 
			
		||||
     * @param e 异常
 | 
			
		||||
     */
 | 
			
		||||
    @AfterThrowing(value = "logPointCut()", throwing = "e")
 | 
			
		||||
    public void doAfterThrowing(JoinPoint joinPoint, Exception e)
 | 
			
		||||
    {
 | 
			
		||||
        handleLog(joinPoint, e, null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult)
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            // 获得注解
 | 
			
		||||
            Log controllerLog = getAnnotationLog(joinPoint);
 | 
			
		||||
            if (controllerLog == null)
 | 
			
		||||
            {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // 获取当前的用户
 | 
			
		||||
            LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());
 | 
			
		||||
 | 
			
		||||
            // *========数据库日志=========*//
 | 
			
		||||
            SysOperLog operLog = new SysOperLog();
 | 
			
		||||
            operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
 | 
			
		||||
            // 请求的地址
 | 
			
		||||
            String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
 | 
			
		||||
            operLog.setOperIp(ip);
 | 
			
		||||
            // 返回参数
 | 
			
		||||
            operLog.setJsonResult(JSON.toJSONString(jsonResult));
 | 
			
		||||
 | 
			
		||||
            operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());
 | 
			
		||||
            if (loginUser != null)
 | 
			
		||||
            {
 | 
			
		||||
                operLog.setOperName(loginUser.getUsername());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (e != null)
 | 
			
		||||
            {
 | 
			
		||||
                operLog.setStatus(BusinessStatus.FAIL.ordinal());
 | 
			
		||||
                operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
 | 
			
		||||
            }
 | 
			
		||||
            // 设置方法名称
 | 
			
		||||
            String className = joinPoint.getTarget().getClass().getName();
 | 
			
		||||
            String methodName = joinPoint.getSignature().getName();
 | 
			
		||||
            operLog.setMethod(className + "." + methodName + "()");
 | 
			
		||||
            // 设置请求方式
 | 
			
		||||
            operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
 | 
			
		||||
            // 处理设置注解上的参数
 | 
			
		||||
            getControllerMethodDescription(joinPoint, controllerLog, operLog);
 | 
			
		||||
            // 保存数据库
 | 
			
		||||
            AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception exp)
 | 
			
		||||
        {
 | 
			
		||||
            // 记录本地异常日志
 | 
			
		||||
            log.error("==前置通知异常==");
 | 
			
		||||
            log.error("异常信息:{}", exp.getMessage());
 | 
			
		||||
            exp.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取注解中对方法的描述信息 用于Controller层注解
 | 
			
		||||
     * 
 | 
			
		||||
     * @param log 日志
 | 
			
		||||
     * @param operLog 操作日志
 | 
			
		||||
     * @throws Exception
 | 
			
		||||
     */
 | 
			
		||||
    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog) throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        // 设置action动作
 | 
			
		||||
        operLog.setBusinessType(log.businessType().ordinal());
 | 
			
		||||
        // 设置标题
 | 
			
		||||
        operLog.setTitle(log.title());
 | 
			
		||||
        // 设置操作人类别
 | 
			
		||||
        operLog.setOperatorType(log.operatorType().ordinal());
 | 
			
		||||
        // 是否需要保存request,参数和值
 | 
			
		||||
        if (log.isSaveRequestData())
 | 
			
		||||
        {
 | 
			
		||||
            // 获取参数的信息,传入到数据库中。
 | 
			
		||||
            setRequestValue(joinPoint, operLog);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取请求的参数,放到log中
 | 
			
		||||
     * 
 | 
			
		||||
     * @param operLog 操作日志
 | 
			
		||||
     * @throws Exception 异常
 | 
			
		||||
     */
 | 
			
		||||
    private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog) throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        String requestMethod = operLog.getRequestMethod();
 | 
			
		||||
        if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod))
 | 
			
		||||
        {
 | 
			
		||||
            String params = argsArrayToString(joinPoint.getArgs());
 | 
			
		||||
            operLog.setOperParam(StringUtils.substring(params, 0, 2000));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            Map<?, ?> paramsMap = (Map<?, ?>) ServletUtils.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
 | 
			
		||||
            operLog.setOperParam(StringUtils.substring(paramsMap.toString(), 0, 2000));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否存在注解,如果存在就获取
 | 
			
		||||
     */
 | 
			
		||||
    private Log getAnnotationLog(JoinPoint joinPoint) throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        Signature signature = joinPoint.getSignature();
 | 
			
		||||
        MethodSignature methodSignature = (MethodSignature) signature;
 | 
			
		||||
        Method method = methodSignature.getMethod();
 | 
			
		||||
 | 
			
		||||
        if (method != null)
 | 
			
		||||
        {
 | 
			
		||||
            return method.getAnnotation(Log.class);
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 参数拼装
 | 
			
		||||
     */
 | 
			
		||||
    private String argsArrayToString(Object[] paramsArray)
 | 
			
		||||
    {
 | 
			
		||||
        String params = "";
 | 
			
		||||
        if (paramsArray != null && paramsArray.length > 0)
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < paramsArray.length; i++)
 | 
			
		||||
            {
 | 
			
		||||
                if (!isFilterObject(paramsArray[i]))
 | 
			
		||||
                {
 | 
			
		||||
                    Object jsonObj = JSON.toJSON(paramsArray[i]);
 | 
			
		||||
                    params += jsonObj.toString() + " ";
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return params.trim();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 判断是否需要过滤的对象。
 | 
			
		||||
     * 
 | 
			
		||||
     * @param o 对象信息。
 | 
			
		||||
     * @return 如果是需要过滤的对象,则返回true;否则返回false。
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isFilterObject(final Object o)
 | 
			
		||||
    {
 | 
			
		||||
        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,30 @@
 | 
			
		||||
package com.ruoyi.framework.config;
 | 
			
		||||
 | 
			
		||||
import java.util.TimeZone;
 | 
			
		||||
import org.mybatis.spring.annotation.MapperScan;
 | 
			
		||||
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 程序注解配置
 | 
			
		||||
 *
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Configuration
 | 
			
		||||
// 表示通过aop框架暴露该代理对象,AopContext能够访问
 | 
			
		||||
@EnableAspectJAutoProxy(exposeProxy = true)
 | 
			
		||||
// 指定要扫描的Mapper类的包的路径
 | 
			
		||||
@MapperScan("com.ruoyi.**.mapper")
 | 
			
		||||
public class ApplicationConfig
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * 时区配置
 | 
			
		||||
     */
 | 
			
		||||
    @Bean
 | 
			
		||||
    public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization()
 | 
			
		||||
    {
 | 
			
		||||
        return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,126 @@
 | 
			
		||||
package com.ruoyi.framework.config;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import javax.servlet.Filter;
 | 
			
		||||
import javax.servlet.FilterChain;
 | 
			
		||||
import javax.servlet.ServletException;
 | 
			
		||||
import javax.servlet.ServletRequest;
 | 
			
		||||
import javax.servlet.ServletResponse;
 | 
			
		||||
import javax.sql.DataSource;
 | 
			
		||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 | 
			
		||||
import org.springframework.boot.context.properties.ConfigurationProperties;
 | 
			
		||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.context.annotation.Primary;
 | 
			
		||||
import com.alibaba.druid.pool.DruidDataSource;
 | 
			
		||||
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
 | 
			
		||||
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
 | 
			
		||||
import com.alibaba.druid.util.Utils;
 | 
			
		||||
import com.ruoyi.common.enums.DataSourceType;
 | 
			
		||||
import com.ruoyi.common.utils.spring.SpringUtils;
 | 
			
		||||
import com.ruoyi.framework.config.properties.DruidProperties;
 | 
			
		||||
import com.ruoyi.framework.datasource.DynamicDataSource;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * druid 配置多数据源
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Configuration
 | 
			
		||||
public class DruidConfig
 | 
			
		||||
{
 | 
			
		||||
    @Bean
 | 
			
		||||
    @ConfigurationProperties("spring.datasource.druid.master")
 | 
			
		||||
    public DataSource masterDataSource(DruidProperties druidProperties)
 | 
			
		||||
    {
 | 
			
		||||
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
 | 
			
		||||
        return druidProperties.dataSource(dataSource);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    @ConfigurationProperties("spring.datasource.druid.slave")
 | 
			
		||||
    @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
 | 
			
		||||
    public DataSource slaveDataSource(DruidProperties druidProperties)
 | 
			
		||||
    {
 | 
			
		||||
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
 | 
			
		||||
        return druidProperties.dataSource(dataSource);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Bean(name = "dynamicDataSource")
 | 
			
		||||
    @Primary
 | 
			
		||||
    public DynamicDataSource dataSource(DataSource masterDataSource)
 | 
			
		||||
    {
 | 
			
		||||
        Map<Object, Object> targetDataSources = new HashMap<>();
 | 
			
		||||
        targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
 | 
			
		||||
        setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");
 | 
			
		||||
        return new DynamicDataSource(masterDataSource, targetDataSources);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * 设置数据源
 | 
			
		||||
     * 
 | 
			
		||||
     * @param targetDataSources 备选数据源集合
 | 
			
		||||
     * @param sourceName 数据源名称
 | 
			
		||||
     * @param beanName bean名称
 | 
			
		||||
     */
 | 
			
		||||
    public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName)
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            DataSource dataSource = SpringUtils.getBean(beanName);
 | 
			
		||||
            targetDataSources.put(sourceName, dataSource);
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception e)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 去除监控页面底部的广告
 | 
			
		||||
     */
 | 
			
		||||
    @SuppressWarnings({ "rawtypes", "unchecked" })
 | 
			
		||||
    @Bean
 | 
			
		||||
    @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true")
 | 
			
		||||
    public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties)
 | 
			
		||||
    {
 | 
			
		||||
        // 获取web监控页面的参数
 | 
			
		||||
        DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
 | 
			
		||||
        // 提取common.js的配置路径
 | 
			
		||||
        String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
 | 
			
		||||
        String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
 | 
			
		||||
        final String filePath = "support/http/resources/js/common.js";
 | 
			
		||||
        // 创建filter进行过滤
 | 
			
		||||
        Filter filter = new Filter()
 | 
			
		||||
        {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void init(javax.servlet.FilterConfig filterConfig) throws ServletException
 | 
			
		||||
            {
 | 
			
		||||
            }
 | 
			
		||||
            @Override
 | 
			
		||||
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
 | 
			
		||||
                    throws IOException, ServletException
 | 
			
		||||
            {
 | 
			
		||||
                chain.doFilter(request, response);
 | 
			
		||||
                // 重置缓冲区,响应头不会被重置
 | 
			
		||||
                response.resetBuffer();
 | 
			
		||||
                // 获取common.js
 | 
			
		||||
                String text = Utils.readFromResource(filePath);
 | 
			
		||||
                // 正则替换banner, 除去底部的广告信息
 | 
			
		||||
                text = text.replaceAll("<a.*?banner\"></a><br/>", "");
 | 
			
		||||
                text = text.replaceAll("powered.*?shrek.wang</a>", "");
 | 
			
		||||
                response.getWriter().write(text);
 | 
			
		||||
            }
 | 
			
		||||
            @Override
 | 
			
		||||
            public void destroy()
 | 
			
		||||
            {
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
 | 
			
		||||
        registrationBean.setFilter(filter);
 | 
			
		||||
        registrationBean.addUrlPatterns(commonJsPattern);
 | 
			
		||||
        return registrationBean;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,71 @@
 | 
			
		||||
package com.ruoyi.framework.config;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.fastjson.JSON;
 | 
			
		||||
import com.alibaba.fastjson.serializer.SerializerFeature;
 | 
			
		||||
import com.fasterxml.jackson.databind.JavaType;
 | 
			
		||||
import com.fasterxml.jackson.databind.ObjectMapper;
 | 
			
		||||
import com.fasterxml.jackson.databind.type.TypeFactory;
 | 
			
		||||
import org.springframework.data.redis.serializer.RedisSerializer;
 | 
			
		||||
import org.springframework.data.redis.serializer.SerializationException;
 | 
			
		||||
import com.alibaba.fastjson.parser.ParserConfig;
 | 
			
		||||
import org.springframework.util.Assert;
 | 
			
		||||
import java.nio.charset.Charset;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Redis使用FastJson序列化
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
 | 
			
		||||
{
 | 
			
		||||
    @SuppressWarnings("unused")
 | 
			
		||||
    private ObjectMapper objectMapper = new ObjectMapper();
 | 
			
		||||
 | 
			
		||||
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
 | 
			
		||||
 | 
			
		||||
    private Class<T> clazz;
 | 
			
		||||
 | 
			
		||||
    static
 | 
			
		||||
    {
 | 
			
		||||
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public FastJson2JsonRedisSerializer(Class<T> clazz)
 | 
			
		||||
    {
 | 
			
		||||
        super();
 | 
			
		||||
        this.clazz = clazz;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public byte[] serialize(T t) throws SerializationException
 | 
			
		||||
    {
 | 
			
		||||
        if (t == null)
 | 
			
		||||
        {
 | 
			
		||||
            return new byte[0];
 | 
			
		||||
        }
 | 
			
		||||
        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public T deserialize(byte[] bytes) throws SerializationException
 | 
			
		||||
    {
 | 
			
		||||
        if (bytes == null || bytes.length <= 0)
 | 
			
		||||
        {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        String str = new String(bytes, DEFAULT_CHARSET);
 | 
			
		||||
 | 
			
		||||
        return JSON.parseObject(str, clazz);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setObjectMapper(ObjectMapper objectMapper)
 | 
			
		||||
    {
 | 
			
		||||
        Assert.notNull(objectMapper, "'objectMapper' must not be null");
 | 
			
		||||
        this.objectMapper = objectMapper;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected JavaType getJavaType(Class<?> clazz)
 | 
			
		||||
    {
 | 
			
		||||
        return TypeFactory.defaultInstance().constructType(clazz);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,60 @@
 | 
			
		||||
package com.ruoyi.framework.config;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import javax.servlet.DispatcherType;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value;
 | 
			
		||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import com.ruoyi.common.filter.RepeatableFilter;
 | 
			
		||||
import com.ruoyi.common.filter.XssFilter;
 | 
			
		||||
import com.ruoyi.common.utils.StringUtils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Filter配置
 | 
			
		||||
 *
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Configuration
 | 
			
		||||
public class FilterConfig
 | 
			
		||||
{
 | 
			
		||||
    @Value("${xss.enabled}")
 | 
			
		||||
    private String enabled;
 | 
			
		||||
 | 
			
		||||
    @Value("${xss.excludes}")
 | 
			
		||||
    private String excludes;
 | 
			
		||||
 | 
			
		||||
    @Value("${xss.urlPatterns}")
 | 
			
		||||
    private String urlPatterns;
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings({ "rawtypes", "unchecked" })
 | 
			
		||||
    @Bean
 | 
			
		||||
    public FilterRegistrationBean xssFilterRegistration()
 | 
			
		||||
    {
 | 
			
		||||
        FilterRegistrationBean registration = new FilterRegistrationBean();
 | 
			
		||||
        registration.setDispatcherTypes(DispatcherType.REQUEST);
 | 
			
		||||
        registration.setFilter(new XssFilter());
 | 
			
		||||
        registration.addUrlPatterns(StringUtils.split(urlPatterns, ","));
 | 
			
		||||
        registration.setName("xssFilter");
 | 
			
		||||
        registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
 | 
			
		||||
        Map<String, String> initParameters = new HashMap<String, String>();
 | 
			
		||||
        initParameters.put("excludes", excludes);
 | 
			
		||||
        initParameters.put("enabled", enabled);
 | 
			
		||||
        registration.setInitParameters(initParameters);
 | 
			
		||||
        return registration;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings({ "rawtypes", "unchecked" })
 | 
			
		||||
    @Bean
 | 
			
		||||
    public FilterRegistrationBean someFilterRegistration()
 | 
			
		||||
    {
 | 
			
		||||
        FilterRegistrationBean registration = new FilterRegistrationBean();
 | 
			
		||||
        registration.setFilter(new RepeatableFilter());
 | 
			
		||||
        registration.addUrlPatterns("/*");
 | 
			
		||||
        registration.setName("repeatableFilter");
 | 
			
		||||
        registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);
 | 
			
		||||
        return registration;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,108 @@
 | 
			
		||||
package com.ruoyi.framework.config;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import javax.sql.DataSource;
 | 
			
		||||
import org.apache.ibatis.io.VFS;
 | 
			
		||||
import org.apache.ibatis.session.SqlSessionFactory;
 | 
			
		||||
import org.mybatis.spring.SqlSessionFactoryBean;
 | 
			
		||||
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.core.env.Environment;
 | 
			
		||||
import org.springframework.core.io.DefaultResourceLoader;
 | 
			
		||||
import org.springframework.core.io.Resource;
 | 
			
		||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
 | 
			
		||||
import org.springframework.core.io.support.ResourcePatternResolver;
 | 
			
		||||
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
 | 
			
		||||
import org.springframework.core.type.classreading.MetadataReader;
 | 
			
		||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
 | 
			
		||||
import org.springframework.util.ClassUtils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Mybatis支持*匹配扫描包
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Configuration
 | 
			
		||||
public class MyBatisConfig
 | 
			
		||||
{
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private Environment env;
 | 
			
		||||
 | 
			
		||||
    static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
 | 
			
		||||
 | 
			
		||||
    public static String setTypeAliasesPackage(String typeAliasesPackage)
 | 
			
		||||
    {
 | 
			
		||||
        ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver();
 | 
			
		||||
        MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver);
 | 
			
		||||
        List<String> allResult = new ArrayList<String>();
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            for (String aliasesPackage : typeAliasesPackage.split(","))
 | 
			
		||||
            {
 | 
			
		||||
                List<String> result = new ArrayList<String>();
 | 
			
		||||
                aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
 | 
			
		||||
                        + ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN;
 | 
			
		||||
                Resource[] resources = resolver.getResources(aliasesPackage);
 | 
			
		||||
                if (resources != null && resources.length > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    MetadataReader metadataReader = null;
 | 
			
		||||
                    for (Resource resource : resources)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (resource.isReadable())
 | 
			
		||||
                        {
 | 
			
		||||
                            metadataReader = metadataReaderFactory.getMetadataReader(resource);
 | 
			
		||||
                            try
 | 
			
		||||
                            {
 | 
			
		||||
                                result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName());
 | 
			
		||||
                            }
 | 
			
		||||
                            catch (ClassNotFoundException e)
 | 
			
		||||
                            {
 | 
			
		||||
                                e.printStackTrace();
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                if (result.size() > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    HashSet<String> hashResult = new HashSet<String>(result);
 | 
			
		||||
                    allResult.addAll(hashResult);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (allResult.size() > 0)
 | 
			
		||||
            {
 | 
			
		||||
                typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0]));
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                throw new RuntimeException("mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        catch (IOException e)
 | 
			
		||||
        {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
        return typeAliasesPackage;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");
 | 
			
		||||
        String mapperLocations = env.getProperty("mybatis.mapperLocations");
 | 
			
		||||
        String configLocation = env.getProperty("mybatis.configLocation");
 | 
			
		||||
        typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
 | 
			
		||||
        VFS.addImplClass(SpringBootVFS.class);
 | 
			
		||||
 | 
			
		||||
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
 | 
			
		||||
        sessionFactory.setDataSource(dataSource);
 | 
			
		||||
        sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
 | 
			
		||||
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
 | 
			
		||||
        sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
 | 
			
		||||
        return sessionFactory.getObject();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,43 @@
 | 
			
		||||
package com.ruoyi.framework.config;
 | 
			
		||||
 | 
			
		||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
 | 
			
		||||
import org.springframework.cache.annotation.EnableCaching;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
 | 
			
		||||
import org.springframework.data.redis.core.RedisTemplate;
 | 
			
		||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
 | 
			
		||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
 | 
			
		||||
import com.fasterxml.jackson.databind.ObjectMapper;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * redis配置
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Configuration
 | 
			
		||||
@EnableCaching
 | 
			
		||||
public class RedisConfig extends CachingConfigurerSupport
 | 
			
		||||
{
 | 
			
		||||
    @Bean
 | 
			
		||||
    @SuppressWarnings(value = { "unchecked", "rawtypes" })
 | 
			
		||||
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
 | 
			
		||||
    {
 | 
			
		||||
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
 | 
			
		||||
        template.setConnectionFactory(connectionFactory);
 | 
			
		||||
 | 
			
		||||
        FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
 | 
			
		||||
 | 
			
		||||
        ObjectMapper mapper = new ObjectMapper();
 | 
			
		||||
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
 | 
			
		||||
        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
 | 
			
		||||
        serializer.setObjectMapper(mapper);
 | 
			
		||||
 | 
			
		||||
        template.setValueSerializer(serializer);
 | 
			
		||||
        // 使用StringRedisSerializer来序列化和反序列化redis的key值
 | 
			
		||||
        template.setKeySerializer(new StringRedisSerializer());
 | 
			
		||||
        template.afterPropertiesSet();
 | 
			
		||||
        return template;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,42 @@
 | 
			
		||||
package com.ruoyi.framework.config;
 | 
			
		||||
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 | 
			
		||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
 | 
			
		||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 | 
			
		||||
import com.ruoyi.common.config.RuoYiConfig;
 | 
			
		||||
import com.ruoyi.common.constant.Constants;
 | 
			
		||||
import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 通用配置
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Configuration
 | 
			
		||||
public class ResourcesConfig implements WebMvcConfigurer
 | 
			
		||||
{
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RepeatSubmitInterceptor repeatSubmitInterceptor;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void addResourceHandlers(ResourceHandlerRegistry registry)
 | 
			
		||||
    {
 | 
			
		||||
        /** 本地文件上传路径 */
 | 
			
		||||
        registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + RuoYiConfig.getProfile() + "/");
 | 
			
		||||
 | 
			
		||||
        /** swagger配置 */
 | 
			
		||||
        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
 | 
			
		||||
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 自定义拦截规则
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void addInterceptors(InterceptorRegistry registry)
 | 
			
		||||
    {
 | 
			
		||||
        registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,135 @@
 | 
			
		||||
package com.ruoyi.framework.config;
 | 
			
		||||
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.http.HttpMethod;
 | 
			
		||||
import org.springframework.security.authentication.AuthenticationManager;
 | 
			
		||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
 | 
			
		||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
 | 
			
		||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 | 
			
		||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 | 
			
		||||
import org.springframework.security.config.http.SessionCreationPolicy;
 | 
			
		||||
import org.springframework.security.core.userdetails.UserDetailsService;
 | 
			
		||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 | 
			
		||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
 | 
			
		||||
import com.ruoyi.framework.security.filter.JwtAuthenticationTokenFilter;
 | 
			
		||||
import com.ruoyi.framework.security.handle.AuthenticationEntryPointImpl;
 | 
			
		||||
import com.ruoyi.framework.security.handle.LogoutSuccessHandlerImpl;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * spring security配置
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
 | 
			
		||||
public class SecurityConfig extends WebSecurityConfigurerAdapter
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * 自定义用户认证逻辑
 | 
			
		||||
     */
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private UserDetailsService userDetailsService;
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * 认证失败处理类
 | 
			
		||||
     */
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private AuthenticationEntryPointImpl unauthorizedHandler;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 退出处理类
 | 
			
		||||
     */
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private LogoutSuccessHandlerImpl logoutSuccessHandler;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * token认证过滤器
 | 
			
		||||
     */
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private JwtAuthenticationTokenFilter authenticationTokenFilter;
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * 解决 无法直接注入 AuthenticationManager
 | 
			
		||||
     *
 | 
			
		||||
     * @return
 | 
			
		||||
     * @throws Exception
 | 
			
		||||
     */
 | 
			
		||||
    @Bean
 | 
			
		||||
    @Override
 | 
			
		||||
    public AuthenticationManager authenticationManagerBean() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        return super.authenticationManagerBean();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * anyRequest          |   匹配所有请求路径
 | 
			
		||||
     * access              |   SpringEl表达式结果为true时可以访问
 | 
			
		||||
     * anonymous           |   匿名可以访问
 | 
			
		||||
     * denyAll             |   用户不能访问
 | 
			
		||||
     * fullyAuthenticated  |   用户完全认证可以访问(非remember-me下自动登录)
 | 
			
		||||
     * hasAnyAuthority     |   如果有参数,参数表示权限,则其中任何一个权限可以访问
 | 
			
		||||
     * hasAnyRole          |   如果有参数,参数表示角色,则其中任何一个角色可以访问
 | 
			
		||||
     * hasAuthority        |   如果有参数,参数表示权限,则其权限可以访问
 | 
			
		||||
     * hasIpAddress        |   如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
 | 
			
		||||
     * hasRole             |   如果有参数,参数表示角色,则其角色可以访问
 | 
			
		||||
     * permitAll           |   用户可以任意访问
 | 
			
		||||
     * rememberMe          |   允许通过remember-me登录的用户访问
 | 
			
		||||
     * authenticated       |   用户登录后可访问
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void configure(HttpSecurity httpSecurity) throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        httpSecurity
 | 
			
		||||
                // CRSF禁用,因为不使用session
 | 
			
		||||
                .csrf().disable()
 | 
			
		||||
                // 认证失败处理类
 | 
			
		||||
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
 | 
			
		||||
                // 基于token,所以不需要session
 | 
			
		||||
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
 | 
			
		||||
                // 过滤请求
 | 
			
		||||
                .authorizeRequests()
 | 
			
		||||
                // 对于登录login 验证码captchaImage 允许匿名访问
 | 
			
		||||
                .antMatchers("/login", "/captchaImage").anonymous()
 | 
			
		||||
                .antMatchers(
 | 
			
		||||
                        HttpMethod.GET,
 | 
			
		||||
                        "/*.html",
 | 
			
		||||
                        "/**/*.html",
 | 
			
		||||
                        "/**/*.css",
 | 
			
		||||
                        "/**/*.js"
 | 
			
		||||
                ).permitAll()
 | 
			
		||||
                .antMatchers("/profile/**").anonymous()
 | 
			
		||||
                .antMatchers("/common/download**").anonymous()
 | 
			
		||||
                .antMatchers("/common/download/resource**").anonymous()
 | 
			
		||||
                .antMatchers("/swagger-ui.html").anonymous()
 | 
			
		||||
                .antMatchers("/swagger-resources/**").anonymous()
 | 
			
		||||
                .antMatchers("/webjars/**").anonymous()
 | 
			
		||||
                .antMatchers("/*/api-docs").anonymous()
 | 
			
		||||
                .antMatchers("/druid/**").anonymous()
 | 
			
		||||
                // 除上面外的所有请求全部需要鉴权认证
 | 
			
		||||
                .anyRequest().authenticated()
 | 
			
		||||
                .and()
 | 
			
		||||
                .headers().frameOptions().disable();
 | 
			
		||||
        httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
 | 
			
		||||
        // 添加JWT filter
 | 
			
		||||
        httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * 强散列哈希加密实现
 | 
			
		||||
     */
 | 
			
		||||
    @Bean
 | 
			
		||||
    public BCryptPasswordEncoder bCryptPasswordEncoder()
 | 
			
		||||
    {
 | 
			
		||||
        return new BCryptPasswordEncoder();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 身份认证接口
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void configure(AuthenticationManagerBuilder auth) throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,32 @@
 | 
			
		||||
package com.ruoyi.framework.config;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import com.ruoyi.common.utils.ServletUtils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 服务相关配置
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class ServerConfig
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取完整的请求路径,包括:域名,端口,上下文访问路径
 | 
			
		||||
     * 
 | 
			
		||||
     * @return 服务地址
 | 
			
		||||
     */
 | 
			
		||||
    public String getUrl()
 | 
			
		||||
    {
 | 
			
		||||
        HttpServletRequest request = ServletUtils.getRequest();
 | 
			
		||||
        return getDomain(request);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String getDomain(HttpServletRequest request)
 | 
			
		||||
    {
 | 
			
		||||
        StringBuffer url = request.getRequestURL();
 | 
			
		||||
        String contextPath = request.getServletContext().getContextPath();
 | 
			
		||||
        return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,62 @@
 | 
			
		||||
package com.ruoyi.framework.config;
 | 
			
		||||
 | 
			
		||||
import java.util.concurrent.ScheduledExecutorService;
 | 
			
		||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
 | 
			
		||||
import java.util.concurrent.ThreadPoolExecutor;
 | 
			
		||||
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 | 
			
		||||
import com.ruoyi.common.utils.Threads;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 线程池配置
 | 
			
		||||
 *
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 **/
 | 
			
		||||
@Configuration
 | 
			
		||||
public class ThreadPoolConfig
 | 
			
		||||
{
 | 
			
		||||
    // 核心线程池大小
 | 
			
		||||
    private int corePoolSize = 50;
 | 
			
		||||
 | 
			
		||||
    // 最大可创建的线程数
 | 
			
		||||
    private int maxPoolSize = 200;
 | 
			
		||||
 | 
			
		||||
    // 队列最大长度
 | 
			
		||||
    private int queueCapacity = 1000;
 | 
			
		||||
 | 
			
		||||
    // 线程池维护线程所允许的空闲时间
 | 
			
		||||
    private int keepAliveSeconds = 300;
 | 
			
		||||
 | 
			
		||||
    @Bean(name = "threadPoolTaskExecutor")
 | 
			
		||||
    public ThreadPoolTaskExecutor threadPoolTaskExecutor()
 | 
			
		||||
    {
 | 
			
		||||
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
 | 
			
		||||
        executor.setMaxPoolSize(maxPoolSize);
 | 
			
		||||
        executor.setCorePoolSize(corePoolSize);
 | 
			
		||||
        executor.setQueueCapacity(queueCapacity);
 | 
			
		||||
        executor.setKeepAliveSeconds(keepAliveSeconds);
 | 
			
		||||
        // 线程池对拒绝任务(无线程可用)的处理策略
 | 
			
		||||
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
 | 
			
		||||
        return executor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 执行周期性或定时任务
 | 
			
		||||
     */
 | 
			
		||||
    @Bean(name = "scheduledExecutorService")
 | 
			
		||||
    protected ScheduledExecutorService scheduledExecutorService()
 | 
			
		||||
    {
 | 
			
		||||
        return new ScheduledThreadPoolExecutor(corePoolSize,
 | 
			
		||||
                new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build())
 | 
			
		||||
        {
 | 
			
		||||
            @Override
 | 
			
		||||
            protected void afterExecute(Runnable r, Throwable t)
 | 
			
		||||
            {
 | 
			
		||||
                super.afterExecute(r, t);
 | 
			
		||||
                Threads.printException(r, t);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,77 @@
 | 
			
		||||
package com.ruoyi.framework.config.properties;
 | 
			
		||||
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import com.alibaba.druid.pool.DruidDataSource;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * druid 配置属性
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Configuration
 | 
			
		||||
public class DruidProperties
 | 
			
		||||
{
 | 
			
		||||
    @Value("${spring.datasource.druid.initialSize}")
 | 
			
		||||
    private int initialSize;
 | 
			
		||||
 | 
			
		||||
    @Value("${spring.datasource.druid.minIdle}")
 | 
			
		||||
    private int minIdle;
 | 
			
		||||
 | 
			
		||||
    @Value("${spring.datasource.druid.maxActive}")
 | 
			
		||||
    private int maxActive;
 | 
			
		||||
 | 
			
		||||
    @Value("${spring.datasource.druid.maxWait}")
 | 
			
		||||
    private int maxWait;
 | 
			
		||||
 | 
			
		||||
    @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}")
 | 
			
		||||
    private int timeBetweenEvictionRunsMillis;
 | 
			
		||||
 | 
			
		||||
    @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}")
 | 
			
		||||
    private int minEvictableIdleTimeMillis;
 | 
			
		||||
 | 
			
		||||
    @Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}")
 | 
			
		||||
    private int maxEvictableIdleTimeMillis;
 | 
			
		||||
 | 
			
		||||
    @Value("${spring.datasource.druid.validationQuery}")
 | 
			
		||||
    private String validationQuery;
 | 
			
		||||
 | 
			
		||||
    @Value("${spring.datasource.druid.testWhileIdle}")
 | 
			
		||||
    private boolean testWhileIdle;
 | 
			
		||||
 | 
			
		||||
    @Value("${spring.datasource.druid.testOnBorrow}")
 | 
			
		||||
    private boolean testOnBorrow;
 | 
			
		||||
 | 
			
		||||
    @Value("${spring.datasource.druid.testOnReturn}")
 | 
			
		||||
    private boolean testOnReturn;
 | 
			
		||||
 | 
			
		||||
    public DruidDataSource dataSource(DruidDataSource datasource)
 | 
			
		||||
    {
 | 
			
		||||
        /** 配置初始化大小、最小、最大 */
 | 
			
		||||
        datasource.setInitialSize(initialSize);
 | 
			
		||||
        datasource.setMaxActive(maxActive);
 | 
			
		||||
        datasource.setMinIdle(minIdle);
 | 
			
		||||
 | 
			
		||||
        /** 配置获取连接等待超时的时间 */
 | 
			
		||||
        datasource.setMaxWait(maxWait);
 | 
			
		||||
 | 
			
		||||
        /** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */
 | 
			
		||||
        datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
 | 
			
		||||
 | 
			
		||||
        /** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */
 | 
			
		||||
        datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
 | 
			
		||||
        datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。
 | 
			
		||||
         */
 | 
			
		||||
        datasource.setValidationQuery(validationQuery);
 | 
			
		||||
        /** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */
 | 
			
		||||
        datasource.setTestWhileIdle(testWhileIdle);
 | 
			
		||||
        /** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
 | 
			
		||||
        datasource.setTestOnBorrow(testOnBorrow);
 | 
			
		||||
        /** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
 | 
			
		||||
        datasource.setTestOnReturn(testOnReturn);
 | 
			
		||||
        return datasource;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,26 @@
 | 
			
		||||
package com.ruoyi.framework.datasource;
 | 
			
		||||
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import javax.sql.DataSource;
 | 
			
		||||
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 动态数据源
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
public class DynamicDataSource extends AbstractRoutingDataSource
 | 
			
		||||
{
 | 
			
		||||
    public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources)
 | 
			
		||||
    {
 | 
			
		||||
        super.setDefaultTargetDataSource(defaultTargetDataSource);
 | 
			
		||||
        super.setTargetDataSources(targetDataSources);
 | 
			
		||||
        super.afterPropertiesSet();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected Object determineCurrentLookupKey()
 | 
			
		||||
    {
 | 
			
		||||
        return DynamicDataSourceContextHolder.getDataSourceType();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,45 @@
 | 
			
		||||
package com.ruoyi.framework.datasource;
 | 
			
		||||
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 数据源切换处理
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
public class DynamicDataSourceContextHolder
 | 
			
		||||
{
 | 
			
		||||
    public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
 | 
			
		||||
     *  所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
 | 
			
		||||
     */
 | 
			
		||||
    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 设置数据源的变量
 | 
			
		||||
     */
 | 
			
		||||
    public static void setDataSourceType(String dsType)
 | 
			
		||||
    {
 | 
			
		||||
        log.info("切换到{}数据源", dsType);
 | 
			
		||||
        CONTEXT_HOLDER.set(dsType);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得数据源的变量
 | 
			
		||||
     */
 | 
			
		||||
    public static String getDataSourceType()
 | 
			
		||||
    {
 | 
			
		||||
        return CONTEXT_HOLDER.get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 清空数据源变量
 | 
			
		||||
     */
 | 
			
		||||
    public static void clearDataSourceType()
 | 
			
		||||
    {
 | 
			
		||||
        CONTEXT_HOLDER.remove();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
package com.ruoyi.framework.interceptor;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.Method;
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import org.springframework.web.method.HandlerMethod;
 | 
			
		||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 | 
			
		||||
import com.alibaba.fastjson.JSONObject;
 | 
			
		||||
import com.ruoyi.common.annotation.RepeatSubmit;
 | 
			
		||||
import com.ruoyi.common.core.domain.AjaxResult;
 | 
			
		||||
import com.ruoyi.common.utils.ServletUtils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 防止重复提交拦截器
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter
 | 
			
		||||
{
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        if (handler instanceof HandlerMethod)
 | 
			
		||||
        {
 | 
			
		||||
            HandlerMethod handlerMethod = (HandlerMethod) handler;
 | 
			
		||||
            Method method = handlerMethod.getMethod();
 | 
			
		||||
            RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
 | 
			
		||||
            if (annotation != null)
 | 
			
		||||
            {
 | 
			
		||||
                if (this.isRepeatSubmit(request))
 | 
			
		||||
                {
 | 
			
		||||
                    AjaxResult ajaxResult = AjaxResult.error("不允许重复提交,请稍后再试");
 | 
			
		||||
                    ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult));
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            return super.preHandle(request, response, handler);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 验证是否重复提交由子类实现具体的防重复提交的规则
 | 
			
		||||
     * 
 | 
			
		||||
     * @param httpServletRequest
 | 
			
		||||
     * @return
 | 
			
		||||
     * @throws Exception
 | 
			
		||||
     */
 | 
			
		||||
    public abstract boolean isRepeatSubmit(HttpServletRequest request);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,107 @@
 | 
			
		||||
package com.ruoyi.framework.interceptor.impl;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import com.alibaba.fastjson.JSONObject;
 | 
			
		||||
import com.ruoyi.common.core.redis.RedisCache;
 | 
			
		||||
import com.ruoyi.common.filter.RepeatedlyRequestWrapper;
 | 
			
		||||
import com.ruoyi.common.utils.StringUtils;
 | 
			
		||||
import com.ruoyi.common.utils.http.HttpHelper;
 | 
			
		||||
import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 判断请求url和数据是否和上一次相同,
 | 
			
		||||
 * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
 | 
			
		||||
{
 | 
			
		||||
    public final String REPEAT_PARAMS = "repeatParams";
 | 
			
		||||
 | 
			
		||||
    public final String REPEAT_TIME = "repeatTime";
 | 
			
		||||
 | 
			
		||||
    public final String CACHE_REPEAT_KEY = "repeatData";
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RedisCache redisCache;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 间隔时间,单位:秒 默认10秒
 | 
			
		||||
     * 
 | 
			
		||||
     * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据
 | 
			
		||||
     */
 | 
			
		||||
    private int intervalTime = 10;
 | 
			
		||||
 | 
			
		||||
    public void setIntervalTime(int intervalTime)
 | 
			
		||||
    {
 | 
			
		||||
        this.intervalTime = intervalTime;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("unchecked")
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean isRepeatSubmit(HttpServletRequest request)
 | 
			
		||||
    {
 | 
			
		||||
        RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
 | 
			
		||||
        String nowParams = HttpHelper.getBodyString(repeatedlyRequest);
 | 
			
		||||
 | 
			
		||||
        // body参数为空,获取Parameter的数据
 | 
			
		||||
        if (StringUtils.isEmpty(nowParams))
 | 
			
		||||
        {
 | 
			
		||||
            nowParams = JSONObject.toJSONString(request.getParameterMap());
 | 
			
		||||
        }
 | 
			
		||||
        Map<String, Object> nowDataMap = new HashMap<String, Object>();
 | 
			
		||||
        nowDataMap.put(REPEAT_PARAMS, nowParams);
 | 
			
		||||
        nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());
 | 
			
		||||
 | 
			
		||||
        // 请求地址(作为存放cache的key值)
 | 
			
		||||
        String url = request.getRequestURI();
 | 
			
		||||
 | 
			
		||||
        Object sessionObj = redisCache.getCacheObject(CACHE_REPEAT_KEY);
 | 
			
		||||
        if (sessionObj != null)
 | 
			
		||||
        {
 | 
			
		||||
            Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;
 | 
			
		||||
            if (sessionMap.containsKey(url))
 | 
			
		||||
            {
 | 
			
		||||
                Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url);
 | 
			
		||||
                if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap))
 | 
			
		||||
                {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        Map<String, Object> cacheMap = new HashMap<String, Object>();
 | 
			
		||||
        cacheMap.put(url, nowDataMap);
 | 
			
		||||
        redisCache.setCacheObject(CACHE_REPEAT_KEY, cacheMap, intervalTime, TimeUnit.SECONDS);
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 判断参数是否相同
 | 
			
		||||
     */
 | 
			
		||||
    private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)
 | 
			
		||||
    {
 | 
			
		||||
        String nowParams = (String) nowMap.get(REPEAT_PARAMS);
 | 
			
		||||
        String preParams = (String) preMap.get(REPEAT_PARAMS);
 | 
			
		||||
        return nowParams.equals(preParams);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 判断两次间隔时间
 | 
			
		||||
     */
 | 
			
		||||
    private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap)
 | 
			
		||||
    {
 | 
			
		||||
        long time1 = (Long) nowMap.get(REPEAT_TIME);
 | 
			
		||||
        long time2 = (Long) preMap.get(REPEAT_TIME);
 | 
			
		||||
        if ((time1 - time2) < (this.intervalTime * 1000))
 | 
			
		||||
        {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
package com.ruoyi.framework.manager;
 | 
			
		||||
 | 
			
		||||
import java.util.TimerTask;
 | 
			
		||||
import java.util.concurrent.ScheduledExecutorService;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
import com.ruoyi.common.utils.Threads;
 | 
			
		||||
import com.ruoyi.common.utils.spring.SpringUtils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 异步任务管理器
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
public class AsyncManager
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * 操作延迟10毫秒
 | 
			
		||||
     */
 | 
			
		||||
    private final int OPERATE_DELAY_TIME = 10;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 异步操作任务调度线程池
 | 
			
		||||
     */
 | 
			
		||||
    private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 单例模式
 | 
			
		||||
     */
 | 
			
		||||
    private AsyncManager(){}
 | 
			
		||||
 | 
			
		||||
    private static AsyncManager me = new AsyncManager();
 | 
			
		||||
 | 
			
		||||
    public static AsyncManager me()
 | 
			
		||||
    {
 | 
			
		||||
        return me;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 执行任务
 | 
			
		||||
     * 
 | 
			
		||||
     * @param task 任务
 | 
			
		||||
     */
 | 
			
		||||
    public void execute(TimerTask task)
 | 
			
		||||
    {
 | 
			
		||||
        executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 停止任务线程池
 | 
			
		||||
     */
 | 
			
		||||
    public void shutdown()
 | 
			
		||||
    {
 | 
			
		||||
        Threads.shutdownAndAwaitTermination(executor);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,39 @@
 | 
			
		||||
package com.ruoyi.framework.manager;
 | 
			
		||||
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import javax.annotation.PreDestroy;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 确保应用退出时能关闭后台线程
 | 
			
		||||
 *
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class ShutdownManager
 | 
			
		||||
{
 | 
			
		||||
    private static final Logger logger = LoggerFactory.getLogger("sys-user");
 | 
			
		||||
 | 
			
		||||
    @PreDestroy
 | 
			
		||||
    public void destroy()
 | 
			
		||||
    {
 | 
			
		||||
        shutdownAsyncManager();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 停止异步执行任务
 | 
			
		||||
     */
 | 
			
		||||
    private void shutdownAsyncManager()
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            logger.info("====关闭后台任务任务线程池====");
 | 
			
		||||
            AsyncManager.me().shutdown();
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception e)
 | 
			
		||||
        {
 | 
			
		||||
            logger.error(e.getMessage(), e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,101 @@
 | 
			
		||||
package com.ruoyi.framework.manager.factory;
 | 
			
		||||
 | 
			
		||||
import java.util.TimerTask;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
import com.ruoyi.common.constant.Constants;
 | 
			
		||||
import com.ruoyi.common.utils.LogUtils;
 | 
			
		||||
import com.ruoyi.common.utils.ServletUtils;
 | 
			
		||||
import com.ruoyi.common.utils.ip.AddressUtils;
 | 
			
		||||
import com.ruoyi.common.utils.ip.IpUtils;
 | 
			
		||||
import com.ruoyi.common.utils.spring.SpringUtils;
 | 
			
		||||
import com.ruoyi.system.domain.SysLogininfor;
 | 
			
		||||
import com.ruoyi.system.domain.SysOperLog;
 | 
			
		||||
import com.ruoyi.system.service.ISysLogininforService;
 | 
			
		||||
import com.ruoyi.system.service.ISysOperLogService;
 | 
			
		||||
import eu.bitwalker.useragentutils.UserAgent;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 异步工厂(产生任务用)
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
public class AsyncFactory
 | 
			
		||||
{
 | 
			
		||||
    private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 记录登陆信息
 | 
			
		||||
     * 
 | 
			
		||||
     * @param username 用户名
 | 
			
		||||
     * @param status 状态
 | 
			
		||||
     * @param message 消息
 | 
			
		||||
     * @param args 列表
 | 
			
		||||
     * @return 任务task
 | 
			
		||||
     */
 | 
			
		||||
    public static TimerTask recordLogininfor(final String username, final String status, final String message,
 | 
			
		||||
            final Object... args)
 | 
			
		||||
    {
 | 
			
		||||
        final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
 | 
			
		||||
        final String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
 | 
			
		||||
        return new TimerTask()
 | 
			
		||||
        {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void run()
 | 
			
		||||
            {
 | 
			
		||||
                String address = AddressUtils.getRealAddressByIP(ip);
 | 
			
		||||
                StringBuilder s = new StringBuilder();
 | 
			
		||||
                s.append(LogUtils.getBlock(ip));
 | 
			
		||||
                s.append(address);
 | 
			
		||||
                s.append(LogUtils.getBlock(username));
 | 
			
		||||
                s.append(LogUtils.getBlock(status));
 | 
			
		||||
                s.append(LogUtils.getBlock(message));
 | 
			
		||||
                // 打印信息到日志
 | 
			
		||||
                sys_user_logger.info(s.toString(), args);
 | 
			
		||||
                // 获取客户端操作系统
 | 
			
		||||
                String os = userAgent.getOperatingSystem().getName();
 | 
			
		||||
                // 获取客户端浏览器
 | 
			
		||||
                String browser = userAgent.getBrowser().getName();
 | 
			
		||||
                // 封装对象
 | 
			
		||||
                SysLogininfor logininfor = new SysLogininfor();
 | 
			
		||||
                logininfor.setUserName(username);
 | 
			
		||||
                logininfor.setIpaddr(ip);
 | 
			
		||||
                logininfor.setLoginLocation(address);
 | 
			
		||||
                logininfor.setBrowser(browser);
 | 
			
		||||
                logininfor.setOs(os);
 | 
			
		||||
                logininfor.setMsg(message);
 | 
			
		||||
                // 日志状态
 | 
			
		||||
                if (Constants.LOGIN_SUCCESS.equals(status) || Constants.LOGOUT.equals(status))
 | 
			
		||||
                {
 | 
			
		||||
                    logininfor.setStatus(Constants.SUCCESS);
 | 
			
		||||
                }
 | 
			
		||||
                else if (Constants.LOGIN_FAIL.equals(status))
 | 
			
		||||
                {
 | 
			
		||||
                    logininfor.setStatus(Constants.FAIL);
 | 
			
		||||
                }
 | 
			
		||||
                // 插入数据
 | 
			
		||||
                SpringUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 操作日志记录
 | 
			
		||||
     * 
 | 
			
		||||
     * @param operLog 操作日志信息
 | 
			
		||||
     * @return 任务task
 | 
			
		||||
     */
 | 
			
		||||
    public static TimerTask recordOper(final SysOperLog operLog)
 | 
			
		||||
    {
 | 
			
		||||
        return new TimerTask()
 | 
			
		||||
        {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void run()
 | 
			
		||||
            {
 | 
			
		||||
                // 远程查询操作地点
 | 
			
		||||
                operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
 | 
			
		||||
                SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,44 @@
 | 
			
		||||
package com.ruoyi.framework.security.filter;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import javax.servlet.FilterChain;
 | 
			
		||||
import javax.servlet.ServletException;
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 | 
			
		||||
import org.springframework.security.core.context.SecurityContextHolder;
 | 
			
		||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import org.springframework.web.filter.OncePerRequestFilter;
 | 
			
		||||
import com.ruoyi.common.core.domain.model.LoginUser;
 | 
			
		||||
import com.ruoyi.common.utils.SecurityUtils;
 | 
			
		||||
import com.ruoyi.common.utils.StringUtils;
 | 
			
		||||
import com.ruoyi.framework.web.service.TokenService;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * token过滤器 验证token有效性
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
 | 
			
		||||
{
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private TokenService tokenService;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
 | 
			
		||||
            throws ServletException, IOException
 | 
			
		||||
    {
 | 
			
		||||
        LoginUser loginUser = tokenService.getLoginUser(request);
 | 
			
		||||
        if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication()))
 | 
			
		||||
        {
 | 
			
		||||
            tokenService.verifyToken(loginUser);
 | 
			
		||||
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
 | 
			
		||||
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
 | 
			
		||||
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
 | 
			
		||||
        }
 | 
			
		||||
        chain.doFilter(request, response);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,34 @@
 | 
			
		||||
package com.ruoyi.framework.security.handle;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import org.springframework.security.core.AuthenticationException;
 | 
			
		||||
import org.springframework.security.web.AuthenticationEntryPoint;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import com.alibaba.fastjson.JSON;
 | 
			
		||||
import com.ruoyi.common.constant.HttpStatus;
 | 
			
		||||
import com.ruoyi.common.core.domain.AjaxResult;
 | 
			
		||||
import com.ruoyi.common.utils.ServletUtils;
 | 
			
		||||
import com.ruoyi.common.utils.StringUtils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 认证失败处理类 返回未授权
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, Serializable
 | 
			
		||||
{
 | 
			
		||||
    private static final long serialVersionUID = -8970718410437077606L;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
 | 
			
		||||
            throws IOException
 | 
			
		||||
    {
 | 
			
		||||
        int code = HttpStatus.UNAUTHORIZED;
 | 
			
		||||
        String msg = StringUtils.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI());
 | 
			
		||||
        ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(code, msg)));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,53 @@
 | 
			
		||||
package com.ruoyi.framework.security.handle;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import javax.servlet.ServletException;
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.security.core.Authentication;
 | 
			
		||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
 | 
			
		||||
import com.alibaba.fastjson.JSON;
 | 
			
		||||
import com.ruoyi.common.constant.Constants;
 | 
			
		||||
import com.ruoyi.common.constant.HttpStatus;
 | 
			
		||||
import com.ruoyi.common.core.domain.AjaxResult;
 | 
			
		||||
import com.ruoyi.common.core.domain.model.LoginUser;
 | 
			
		||||
import com.ruoyi.common.utils.ServletUtils;
 | 
			
		||||
import com.ruoyi.common.utils.StringUtils;
 | 
			
		||||
import com.ruoyi.framework.manager.AsyncManager;
 | 
			
		||||
import com.ruoyi.framework.manager.factory.AsyncFactory;
 | 
			
		||||
import com.ruoyi.framework.web.service.TokenService;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 自定义退出处理类 返回成功
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Configuration
 | 
			
		||||
public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler
 | 
			
		||||
{
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private TokenService tokenService;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 退出处理
 | 
			
		||||
     * 
 | 
			
		||||
     * @return
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
 | 
			
		||||
            throws IOException, ServletException
 | 
			
		||||
    {
 | 
			
		||||
        LoginUser loginUser = tokenService.getLoginUser(request);
 | 
			
		||||
        if (StringUtils.isNotNull(loginUser))
 | 
			
		||||
        {
 | 
			
		||||
            String userName = loginUser.getUsername();
 | 
			
		||||
            // 删除用户缓存记录
 | 
			
		||||
            tokenService.delLoginUser(loginUser.getToken());
 | 
			
		||||
            // 记录用户退出日志
 | 
			
		||||
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "退出成功"));
 | 
			
		||||
        }
 | 
			
		||||
        ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(HttpStatus.SUCCESS, "退出成功")));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,240 @@
 | 
			
		||||
package com.ruoyi.framework.web.domain;
 | 
			
		||||
 | 
			
		||||
import java.net.UnknownHostException;
 | 
			
		||||
import java.util.LinkedList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Properties;
 | 
			
		||||
import com.ruoyi.common.utils.Arith;
 | 
			
		||||
import com.ruoyi.common.utils.ip.IpUtils;
 | 
			
		||||
import com.ruoyi.framework.web.domain.server.Cpu;
 | 
			
		||||
import com.ruoyi.framework.web.domain.server.Jvm;
 | 
			
		||||
import com.ruoyi.framework.web.domain.server.Mem;
 | 
			
		||||
import com.ruoyi.framework.web.domain.server.Sys;
 | 
			
		||||
import com.ruoyi.framework.web.domain.server.SysFile;
 | 
			
		||||
import oshi.SystemInfo;
 | 
			
		||||
import oshi.hardware.CentralProcessor;
 | 
			
		||||
import oshi.hardware.CentralProcessor.TickType;
 | 
			
		||||
import oshi.hardware.GlobalMemory;
 | 
			
		||||
import oshi.hardware.HardwareAbstractionLayer;
 | 
			
		||||
import oshi.software.os.FileSystem;
 | 
			
		||||
import oshi.software.os.OSFileStore;
 | 
			
		||||
import oshi.software.os.OperatingSystem;
 | 
			
		||||
import oshi.util.Util;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 服务器相关信息
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
public class Server
 | 
			
		||||
{
 | 
			
		||||
    private static final int OSHI_WAIT_SECOND = 1000;
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * CPU相关信息
 | 
			
		||||
     */
 | 
			
		||||
    private Cpu cpu = new Cpu();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 內存相关信息
 | 
			
		||||
     */
 | 
			
		||||
    private Mem mem = new Mem();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * JVM相关信息
 | 
			
		||||
     */
 | 
			
		||||
    private Jvm jvm = new Jvm();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 服务器相关信息
 | 
			
		||||
     */
 | 
			
		||||
    private Sys sys = new Sys();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 磁盘相关信息
 | 
			
		||||
     */
 | 
			
		||||
    private List<SysFile> sysFiles = new LinkedList<SysFile>();
 | 
			
		||||
 | 
			
		||||
    public Cpu getCpu()
 | 
			
		||||
    {
 | 
			
		||||
        return cpu;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setCpu(Cpu cpu)
 | 
			
		||||
    {
 | 
			
		||||
        this.cpu = cpu;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Mem getMem()
 | 
			
		||||
    {
 | 
			
		||||
        return mem;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setMem(Mem mem)
 | 
			
		||||
    {
 | 
			
		||||
        this.mem = mem;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Jvm getJvm()
 | 
			
		||||
    {
 | 
			
		||||
        return jvm;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setJvm(Jvm jvm)
 | 
			
		||||
    {
 | 
			
		||||
        this.jvm = jvm;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Sys getSys()
 | 
			
		||||
    {
 | 
			
		||||
        return sys;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSys(Sys sys)
 | 
			
		||||
    {
 | 
			
		||||
        this.sys = sys;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<SysFile> getSysFiles()
 | 
			
		||||
    {
 | 
			
		||||
        return sysFiles;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSysFiles(List<SysFile> sysFiles)
 | 
			
		||||
    {
 | 
			
		||||
        this.sysFiles = sysFiles;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void copyTo() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        SystemInfo si = new SystemInfo();
 | 
			
		||||
        HardwareAbstractionLayer hal = si.getHardware();
 | 
			
		||||
 | 
			
		||||
        setCpuInfo(hal.getProcessor());
 | 
			
		||||
 | 
			
		||||
        setMemInfo(hal.getMemory());
 | 
			
		||||
 | 
			
		||||
        setSysInfo();
 | 
			
		||||
 | 
			
		||||
        setJvmInfo();
 | 
			
		||||
 | 
			
		||||
        setSysFiles(si.getOperatingSystem());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 设置CPU信息
 | 
			
		||||
     */
 | 
			
		||||
    private void setCpuInfo(CentralProcessor processor)
 | 
			
		||||
    {
 | 
			
		||||
        // CPU信息
 | 
			
		||||
        long[] prevTicks = processor.getSystemCpuLoadTicks();
 | 
			
		||||
        Util.sleep(OSHI_WAIT_SECOND);
 | 
			
		||||
        long[] ticks = processor.getSystemCpuLoadTicks();
 | 
			
		||||
        long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];
 | 
			
		||||
        long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];
 | 
			
		||||
        long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];
 | 
			
		||||
        long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];
 | 
			
		||||
        long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];
 | 
			
		||||
        long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];
 | 
			
		||||
        long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];
 | 
			
		||||
        long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];
 | 
			
		||||
        long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
 | 
			
		||||
        cpu.setCpuNum(processor.getLogicalProcessorCount());
 | 
			
		||||
        cpu.setTotal(totalCpu);
 | 
			
		||||
        cpu.setSys(cSys);
 | 
			
		||||
        cpu.setUsed(user);
 | 
			
		||||
        cpu.setWait(iowait);
 | 
			
		||||
        cpu.setFree(idle);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 设置内存信息
 | 
			
		||||
     */
 | 
			
		||||
    private void setMemInfo(GlobalMemory memory)
 | 
			
		||||
    {
 | 
			
		||||
        mem.setTotal(memory.getTotal());
 | 
			
		||||
        mem.setUsed(memory.getTotal() - memory.getAvailable());
 | 
			
		||||
        mem.setFree(memory.getAvailable());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 设置服务器信息
 | 
			
		||||
     */
 | 
			
		||||
    private void setSysInfo()
 | 
			
		||||
    {
 | 
			
		||||
        Properties props = System.getProperties();
 | 
			
		||||
        sys.setComputerName(IpUtils.getHostName());
 | 
			
		||||
        sys.setComputerIp(IpUtils.getHostIp());
 | 
			
		||||
        sys.setOsName(props.getProperty("os.name"));
 | 
			
		||||
        sys.setOsArch(props.getProperty("os.arch"));
 | 
			
		||||
        sys.setUserDir(props.getProperty("user.dir"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 设置Java虚拟机
 | 
			
		||||
     */
 | 
			
		||||
    private void setJvmInfo() throws UnknownHostException
 | 
			
		||||
    {
 | 
			
		||||
        Properties props = System.getProperties();
 | 
			
		||||
        jvm.setTotal(Runtime.getRuntime().totalMemory());
 | 
			
		||||
        jvm.setMax(Runtime.getRuntime().maxMemory());
 | 
			
		||||
        jvm.setFree(Runtime.getRuntime().freeMemory());
 | 
			
		||||
        jvm.setVersion(props.getProperty("java.version"));
 | 
			
		||||
        jvm.setHome(props.getProperty("java.home"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 设置磁盘信息
 | 
			
		||||
     */
 | 
			
		||||
    private void setSysFiles(OperatingSystem os)
 | 
			
		||||
    {
 | 
			
		||||
        FileSystem fileSystem = os.getFileSystem();
 | 
			
		||||
        OSFileStore[] fsArray = fileSystem.getFileStores();
 | 
			
		||||
        for (OSFileStore fs : fsArray)
 | 
			
		||||
        {
 | 
			
		||||
            long free = fs.getUsableSpace();
 | 
			
		||||
            long total = fs.getTotalSpace();
 | 
			
		||||
            long used = total - free;
 | 
			
		||||
            SysFile sysFile = new SysFile();
 | 
			
		||||
            sysFile.setDirName(fs.getMount());
 | 
			
		||||
            sysFile.setSysTypeName(fs.getType());
 | 
			
		||||
            sysFile.setTypeName(fs.getName());
 | 
			
		||||
            sysFile.setTotal(convertFileSize(total));
 | 
			
		||||
            sysFile.setFree(convertFileSize(free));
 | 
			
		||||
            sysFile.setUsed(convertFileSize(used));
 | 
			
		||||
            sysFile.setUsage(Arith.mul(Arith.div(used, total, 4), 100));
 | 
			
		||||
            sysFiles.add(sysFile);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 字节转换
 | 
			
		||||
     * 
 | 
			
		||||
     * @param size 字节大小
 | 
			
		||||
     * @return 转换后值
 | 
			
		||||
     */
 | 
			
		||||
    public String convertFileSize(long size)
 | 
			
		||||
    {
 | 
			
		||||
        long kb = 1024;
 | 
			
		||||
        long mb = kb * 1024;
 | 
			
		||||
        long gb = mb * 1024;
 | 
			
		||||
        if (size >= gb)
 | 
			
		||||
        {
 | 
			
		||||
            return String.format("%.1f GB", (float) size / gb);
 | 
			
		||||
        }
 | 
			
		||||
        else if (size >= mb)
 | 
			
		||||
        {
 | 
			
		||||
            float f = (float) size / mb;
 | 
			
		||||
            return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f);
 | 
			
		||||
        }
 | 
			
		||||
        else if (size >= kb)
 | 
			
		||||
        {
 | 
			
		||||
            float f = (float) size / kb;
 | 
			
		||||
            return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            return String.format("%d B", size);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,101 @@
 | 
			
		||||
package com.ruoyi.framework.web.domain.server;
 | 
			
		||||
 | 
			
		||||
import com.ruoyi.common.utils.Arith;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * CPU相关信息
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
public class Cpu
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * 核心数
 | 
			
		||||
     */
 | 
			
		||||
    private int cpuNum;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * CPU总的使用率
 | 
			
		||||
     */
 | 
			
		||||
    private double total;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * CPU系统使用率
 | 
			
		||||
     */
 | 
			
		||||
    private double sys;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * CPU用户使用率
 | 
			
		||||
     */
 | 
			
		||||
    private double used;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * CPU当前等待率
 | 
			
		||||
     */
 | 
			
		||||
    private double wait;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * CPU当前空闲率
 | 
			
		||||
     */
 | 
			
		||||
    private double free;
 | 
			
		||||
 | 
			
		||||
    public int getCpuNum()
 | 
			
		||||
    {
 | 
			
		||||
        return cpuNum;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setCpuNum(int cpuNum)
 | 
			
		||||
    {
 | 
			
		||||
        this.cpuNum = cpuNum;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public double getTotal()
 | 
			
		||||
    {
 | 
			
		||||
        return Arith.round(Arith.mul(total, 100), 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTotal(double total)
 | 
			
		||||
    {
 | 
			
		||||
        this.total = total;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public double getSys()
 | 
			
		||||
    {
 | 
			
		||||
        return Arith.round(Arith.mul(sys / total, 100), 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSys(double sys)
 | 
			
		||||
    {
 | 
			
		||||
        this.sys = sys;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public double getUsed()
 | 
			
		||||
    {
 | 
			
		||||
        return Arith.round(Arith.mul(used / total, 100), 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setUsed(double used)
 | 
			
		||||
    {
 | 
			
		||||
        this.used = used;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public double getWait()
 | 
			
		||||
    {
 | 
			
		||||
        return Arith.round(Arith.mul(wait / total, 100), 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setWait(double wait)
 | 
			
		||||
    {
 | 
			
		||||
        this.wait = wait;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public double getFree()
 | 
			
		||||
    {
 | 
			
		||||
        return Arith.round(Arith.mul(free / total, 100), 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setFree(double free)
 | 
			
		||||
    {
 | 
			
		||||
        this.free = free;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,122 @@
 | 
			
		||||
package com.ruoyi.framework.web.domain.server;
 | 
			
		||||
 | 
			
		||||
import java.lang.management.ManagementFactory;
 | 
			
		||||
import com.ruoyi.common.utils.Arith;
 | 
			
		||||
import com.ruoyi.common.utils.DateUtils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * JVM相关信息
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
public class Jvm
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * 当前JVM占用的内存总数(M)
 | 
			
		||||
     */
 | 
			
		||||
    private double total;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * JVM最大可用内存总数(M)
 | 
			
		||||
     */
 | 
			
		||||
    private double max;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * JVM空闲内存(M)
 | 
			
		||||
     */
 | 
			
		||||
    private double free;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * JDK版本
 | 
			
		||||
     */
 | 
			
		||||
    private String version;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * JDK路径
 | 
			
		||||
     */
 | 
			
		||||
    private String home;
 | 
			
		||||
 | 
			
		||||
    public double getTotal()
 | 
			
		||||
    {
 | 
			
		||||
        return Arith.div(total, (1024 * 1024), 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTotal(double total)
 | 
			
		||||
    {
 | 
			
		||||
        this.total = total;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public double getMax()
 | 
			
		||||
    {
 | 
			
		||||
        return Arith.div(max, (1024 * 1024), 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setMax(double max)
 | 
			
		||||
    {
 | 
			
		||||
        this.max = max;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public double getFree()
 | 
			
		||||
    {
 | 
			
		||||
        return Arith.div(free, (1024 * 1024), 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setFree(double free)
 | 
			
		||||
    {
 | 
			
		||||
        this.free = free;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public double getUsed()
 | 
			
		||||
    {
 | 
			
		||||
        return Arith.div(total - free, (1024 * 1024), 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public double getUsage()
 | 
			
		||||
    {
 | 
			
		||||
        return Arith.mul(Arith.div(total - free, total, 4), 100);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取JDK名称
 | 
			
		||||
     */
 | 
			
		||||
    public String getName()
 | 
			
		||||
    {
 | 
			
		||||
        return ManagementFactory.getRuntimeMXBean().getVmName();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getVersion()
 | 
			
		||||
    {
 | 
			
		||||
        return version;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setVersion(String version)
 | 
			
		||||
    {
 | 
			
		||||
        this.version = version;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getHome()
 | 
			
		||||
    {
 | 
			
		||||
        return home;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setHome(String home)
 | 
			
		||||
    {
 | 
			
		||||
        this.home = home;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * JDK启动时间
 | 
			
		||||
     */
 | 
			
		||||
    public String getStartTime()
 | 
			
		||||
    {
 | 
			
		||||
        return DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.getServerStartDate());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * JDK运行时间
 | 
			
		||||
     */
 | 
			
		||||
    public String getRunTime()
 | 
			
		||||
    {
 | 
			
		||||
        return DateUtils.getDatePoor(DateUtils.getNowDate(), DateUtils.getServerStartDate());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,61 @@
 | 
			
		||||
package com.ruoyi.framework.web.domain.server;
 | 
			
		||||
 | 
			
		||||
import com.ruoyi.common.utils.Arith;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 內存相关信息
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
public class Mem
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * 内存总量
 | 
			
		||||
     */
 | 
			
		||||
    private double total;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 已用内存
 | 
			
		||||
     */
 | 
			
		||||
    private double used;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 剩余内存
 | 
			
		||||
     */
 | 
			
		||||
    private double free;
 | 
			
		||||
 | 
			
		||||
    public double getTotal()
 | 
			
		||||
    {
 | 
			
		||||
        return Arith.div(total, (1024 * 1024 * 1024), 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTotal(long total)
 | 
			
		||||
    {
 | 
			
		||||
        this.total = total;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public double getUsed()
 | 
			
		||||
    {
 | 
			
		||||
        return Arith.div(used, (1024 * 1024 * 1024), 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setUsed(long used)
 | 
			
		||||
    {
 | 
			
		||||
        this.used = used;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public double getFree()
 | 
			
		||||
    {
 | 
			
		||||
        return Arith.div(free, (1024 * 1024 * 1024), 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setFree(long free)
 | 
			
		||||
    {
 | 
			
		||||
        this.free = free;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public double getUsage()
 | 
			
		||||
    {
 | 
			
		||||
        return Arith.mul(Arith.div(used, total, 4), 100);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,84 @@
 | 
			
		||||
package com.ruoyi.framework.web.domain.server;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 系统相关信息
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
public class Sys
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * 服务器名称
 | 
			
		||||
     */
 | 
			
		||||
    private String computerName;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 服务器Ip
 | 
			
		||||
     */
 | 
			
		||||
    private String computerIp;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 项目路径
 | 
			
		||||
     */
 | 
			
		||||
    private String userDir;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 操作系统
 | 
			
		||||
     */
 | 
			
		||||
    private String osName;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 系统架构
 | 
			
		||||
     */
 | 
			
		||||
    private String osArch;
 | 
			
		||||
 | 
			
		||||
    public String getComputerName()
 | 
			
		||||
    {
 | 
			
		||||
        return computerName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setComputerName(String computerName)
 | 
			
		||||
    {
 | 
			
		||||
        this.computerName = computerName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getComputerIp()
 | 
			
		||||
    {
 | 
			
		||||
        return computerIp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setComputerIp(String computerIp)
 | 
			
		||||
    {
 | 
			
		||||
        this.computerIp = computerIp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getUserDir()
 | 
			
		||||
    {
 | 
			
		||||
        return userDir;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setUserDir(String userDir)
 | 
			
		||||
    {
 | 
			
		||||
        this.userDir = userDir;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getOsName()
 | 
			
		||||
    {
 | 
			
		||||
        return osName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setOsName(String osName)
 | 
			
		||||
    {
 | 
			
		||||
        this.osName = osName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getOsArch()
 | 
			
		||||
    {
 | 
			
		||||
        return osArch;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setOsArch(String osArch)
 | 
			
		||||
    {
 | 
			
		||||
        this.osArch = osArch;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,114 @@
 | 
			
		||||
package com.ruoyi.framework.web.domain.server;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 系统文件相关信息
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
public class SysFile
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * 盘符路径
 | 
			
		||||
     */
 | 
			
		||||
    private String dirName;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 盘符类型
 | 
			
		||||
     */
 | 
			
		||||
    private String sysTypeName;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 文件类型
 | 
			
		||||
     */
 | 
			
		||||
    private String typeName;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 总大小
 | 
			
		||||
     */
 | 
			
		||||
    private String total;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 剩余大小
 | 
			
		||||
     */
 | 
			
		||||
    private String free;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 已经使用量
 | 
			
		||||
     */
 | 
			
		||||
    private String used;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 资源的使用率
 | 
			
		||||
     */
 | 
			
		||||
    private double usage;
 | 
			
		||||
 | 
			
		||||
    public String getDirName()
 | 
			
		||||
    {
 | 
			
		||||
        return dirName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setDirName(String dirName)
 | 
			
		||||
    {
 | 
			
		||||
        this.dirName = dirName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getSysTypeName()
 | 
			
		||||
    {
 | 
			
		||||
        return sysTypeName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSysTypeName(String sysTypeName)
 | 
			
		||||
    {
 | 
			
		||||
        this.sysTypeName = sysTypeName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getTypeName()
 | 
			
		||||
    {
 | 
			
		||||
        return typeName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTypeName(String typeName)
 | 
			
		||||
    {
 | 
			
		||||
        this.typeName = typeName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getTotal()
 | 
			
		||||
    {
 | 
			
		||||
        return total;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTotal(String total)
 | 
			
		||||
    {
 | 
			
		||||
        this.total = total;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getFree()
 | 
			
		||||
    {
 | 
			
		||||
        return free;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setFree(String free)
 | 
			
		||||
    {
 | 
			
		||||
        this.free = free;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getUsed()
 | 
			
		||||
    {
 | 
			
		||||
        return used;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setUsed(String used)
 | 
			
		||||
    {
 | 
			
		||||
        this.used = used;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public double getUsage()
 | 
			
		||||
    {
 | 
			
		||||
        return usage;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setUsage(double usage)
 | 
			
		||||
    {
 | 
			
		||||
        this.usage = usage;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,117 @@
 | 
			
		||||
package com.ruoyi.framework.web.exception;
 | 
			
		||||
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
import org.springframework.security.access.AccessDeniedException;
 | 
			
		||||
import org.springframework.security.authentication.AccountExpiredException;
 | 
			
		||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
 | 
			
		||||
import org.springframework.validation.BindException;
 | 
			
		||||
import org.springframework.web.bind.MethodArgumentNotValidException;
 | 
			
		||||
import org.springframework.web.bind.annotation.ExceptionHandler;
 | 
			
		||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
 | 
			
		||||
import org.springframework.web.servlet.NoHandlerFoundException;
 | 
			
		||||
import com.ruoyi.common.constant.HttpStatus;
 | 
			
		||||
import com.ruoyi.common.core.domain.AjaxResult;
 | 
			
		||||
import com.ruoyi.common.exception.BaseException;
 | 
			
		||||
import com.ruoyi.common.exception.CustomException;
 | 
			
		||||
import com.ruoyi.common.exception.DemoModeException;
 | 
			
		||||
import com.ruoyi.common.utils.StringUtils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 全局异常处理器
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@RestControllerAdvice
 | 
			
		||||
public class GlobalExceptionHandler
 | 
			
		||||
{
 | 
			
		||||
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 基础异常
 | 
			
		||||
     */
 | 
			
		||||
    @ExceptionHandler(BaseException.class)
 | 
			
		||||
    public AjaxResult baseException(BaseException e)
 | 
			
		||||
    {
 | 
			
		||||
        return AjaxResult.error(e.getMessage());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 业务异常
 | 
			
		||||
     */
 | 
			
		||||
    @ExceptionHandler(CustomException.class)
 | 
			
		||||
    public AjaxResult businessException(CustomException e)
 | 
			
		||||
    {
 | 
			
		||||
        if (StringUtils.isNull(e.getCode()))
 | 
			
		||||
        {
 | 
			
		||||
            return AjaxResult.error(e.getMessage());
 | 
			
		||||
        }
 | 
			
		||||
        return AjaxResult.error(e.getCode(), e.getMessage());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ExceptionHandler(NoHandlerFoundException.class)
 | 
			
		||||
    public AjaxResult handlerNoFoundException(Exception e)
 | 
			
		||||
    {
 | 
			
		||||
        log.error(e.getMessage(), e);
 | 
			
		||||
        return AjaxResult.error(HttpStatus.NOT_FOUND, "路径不存在,请检查路径是否正确");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ExceptionHandler(AccessDeniedException.class)
 | 
			
		||||
    public AjaxResult handleAuthorizationException(AccessDeniedException e)
 | 
			
		||||
    {
 | 
			
		||||
        log.error(e.getMessage());
 | 
			
		||||
        return AjaxResult.error(HttpStatus.FORBIDDEN, "没有权限,请联系管理员授权");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ExceptionHandler(AccountExpiredException.class)
 | 
			
		||||
    public AjaxResult handleAccountExpiredException(AccountExpiredException e)
 | 
			
		||||
    {
 | 
			
		||||
        log.error(e.getMessage(), e);
 | 
			
		||||
        return AjaxResult.error(e.getMessage());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ExceptionHandler(UsernameNotFoundException.class)
 | 
			
		||||
    public AjaxResult handleUsernameNotFoundException(UsernameNotFoundException e)
 | 
			
		||||
    {
 | 
			
		||||
        log.error(e.getMessage(), e);
 | 
			
		||||
        return AjaxResult.error(e.getMessage());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ExceptionHandler(Exception.class)
 | 
			
		||||
    public AjaxResult handleException(Exception e)
 | 
			
		||||
    {
 | 
			
		||||
        log.error(e.getMessage(), e);
 | 
			
		||||
        return AjaxResult.error(e.getMessage());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 自定义验证异常
 | 
			
		||||
     */
 | 
			
		||||
    @ExceptionHandler(BindException.class)
 | 
			
		||||
    public AjaxResult validatedBindException(BindException e)
 | 
			
		||||
    {
 | 
			
		||||
        log.error(e.getMessage(), e);
 | 
			
		||||
        String message = e.getAllErrors().get(0).getDefaultMessage();
 | 
			
		||||
        return AjaxResult.error(message);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 自定义验证异常
 | 
			
		||||
     */
 | 
			
		||||
    @ExceptionHandler(MethodArgumentNotValidException.class)
 | 
			
		||||
    public Object validExceptionHandler(MethodArgumentNotValidException e)
 | 
			
		||||
    {
 | 
			
		||||
        log.error(e.getMessage(), e);
 | 
			
		||||
        String message = e.getBindingResult().getFieldError().getDefaultMessage();
 | 
			
		||||
        return AjaxResult.error(message);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 演示模式异常
 | 
			
		||||
     */
 | 
			
		||||
    @ExceptionHandler(DemoModeException.class)
 | 
			
		||||
    public AjaxResult demoModeException(DemoModeException e)
 | 
			
		||||
    {
 | 
			
		||||
        return AjaxResult.error("演示模式,不允许操作");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,169 @@
 | 
			
		||||
package com.ruoyi.framework.web.service;
 | 
			
		||||
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import org.springframework.util.CollectionUtils;
 | 
			
		||||
import com.ruoyi.common.core.domain.entity.SysRole;
 | 
			
		||||
import com.ruoyi.common.core.domain.model.LoginUser;
 | 
			
		||||
import com.ruoyi.common.utils.ServletUtils;
 | 
			
		||||
import com.ruoyi.common.utils.StringUtils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * RuoYi首创 自定义权限实现,ss取自SpringSecurity首字母
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Service("ss")
 | 
			
		||||
public class PermissionService
 | 
			
		||||
{
 | 
			
		||||
    /** 所有权限标识 */
 | 
			
		||||
    private static final String ALL_PERMISSION = "*:*:*";
 | 
			
		||||
 | 
			
		||||
    /** 管理员角色权限标识 */
 | 
			
		||||
    private static final String SUPER_ADMIN = "admin";
 | 
			
		||||
 | 
			
		||||
    private static final String ROLE_DELIMETER = ",";
 | 
			
		||||
 | 
			
		||||
    private static final String PERMISSION_DELIMETER = ",";
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private TokenService tokenService;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 验证用户是否具备某权限
 | 
			
		||||
     * 
 | 
			
		||||
     * @param permission 权限字符串
 | 
			
		||||
     * @return 用户是否具备某权限
 | 
			
		||||
     */
 | 
			
		||||
    public boolean hasPermi(String permission)
 | 
			
		||||
    {
 | 
			
		||||
        if (StringUtils.isEmpty(permission))
 | 
			
		||||
        {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
 | 
			
		||||
        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
 | 
			
		||||
        {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return hasPermissions(loginUser.getPermissions(), permission);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 验证用户是否不具备某权限,与 hasPermi逻辑相反
 | 
			
		||||
     *
 | 
			
		||||
     * @param permission 权限字符串
 | 
			
		||||
     * @return 用户是否不具备某权限
 | 
			
		||||
     */
 | 
			
		||||
    public boolean lacksPermi(String permission)
 | 
			
		||||
    {
 | 
			
		||||
        return hasPermi(permission) != true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 验证用户是否具有以下任意一个权限
 | 
			
		||||
     *
 | 
			
		||||
     * @param permissions 以 PERMISSION_NAMES_DELIMETER 为分隔符的权限列表
 | 
			
		||||
     * @return 用户是否具有以下任意一个权限
 | 
			
		||||
     */
 | 
			
		||||
    public boolean hasAnyPermi(String permissions)
 | 
			
		||||
    {
 | 
			
		||||
        if (StringUtils.isEmpty(permissions))
 | 
			
		||||
        {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
 | 
			
		||||
        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
 | 
			
		||||
        {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        Set<String> authorities = loginUser.getPermissions();
 | 
			
		||||
        for (String permission : permissions.split(PERMISSION_DELIMETER))
 | 
			
		||||
        {
 | 
			
		||||
            if (permission != null && hasPermissions(authorities, permission))
 | 
			
		||||
            {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 判断用户是否拥有某个角色
 | 
			
		||||
     * 
 | 
			
		||||
     * @param role 角色字符串
 | 
			
		||||
     * @return 用户是否具备某角色
 | 
			
		||||
     */
 | 
			
		||||
    public boolean hasRole(String role)
 | 
			
		||||
    {
 | 
			
		||||
        if (StringUtils.isEmpty(role))
 | 
			
		||||
        {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
 | 
			
		||||
        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
 | 
			
		||||
        {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        for (SysRole sysRole : loginUser.getUser().getRoles())
 | 
			
		||||
        {
 | 
			
		||||
            String roleKey = sysRole.getRoleKey();
 | 
			
		||||
            if (SUPER_ADMIN.contains(roleKey) || roleKey.contains(StringUtils.trim(role)))
 | 
			
		||||
            {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 验证用户是否不具备某角色,与 isRole逻辑相反。
 | 
			
		||||
     *
 | 
			
		||||
     * @param role 角色名称
 | 
			
		||||
     * @return 用户是否不具备某角色
 | 
			
		||||
     */
 | 
			
		||||
    public boolean lacksRole(String role)
 | 
			
		||||
    {
 | 
			
		||||
        return hasRole(role) != true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 验证用户是否具有以下任意一个角色
 | 
			
		||||
     *
 | 
			
		||||
     * @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表
 | 
			
		||||
     * @return 用户是否具有以下任意一个角色
 | 
			
		||||
     */
 | 
			
		||||
    public boolean hasAnyRoles(String roles)
 | 
			
		||||
    {
 | 
			
		||||
        if (StringUtils.isEmpty(roles))
 | 
			
		||||
        {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
 | 
			
		||||
        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
 | 
			
		||||
        {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        for (String role : roles.split(ROLE_DELIMETER))
 | 
			
		||||
        {
 | 
			
		||||
            if (hasRole(role))
 | 
			
		||||
            {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 判断是否包含权限
 | 
			
		||||
     * 
 | 
			
		||||
     * @param permissions 权限列表
 | 
			
		||||
     * @param permission 权限字符串
 | 
			
		||||
     * @return 用户是否具备某权限
 | 
			
		||||
     */
 | 
			
		||||
    private boolean hasPermissions(Set<String> permissions, String permission)
 | 
			
		||||
    {
 | 
			
		||||
        return permissions.contains(ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,88 @@
 | 
			
		||||
package com.ruoyi.framework.web.service;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.security.authentication.AuthenticationManager;
 | 
			
		||||
import org.springframework.security.authentication.BadCredentialsException;
 | 
			
		||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 | 
			
		||||
import org.springframework.security.core.Authentication;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import com.ruoyi.common.constant.Constants;
 | 
			
		||||
import com.ruoyi.common.core.domain.model.LoginUser;
 | 
			
		||||
import com.ruoyi.common.core.redis.RedisCache;
 | 
			
		||||
import com.ruoyi.common.exception.CustomException;
 | 
			
		||||
import com.ruoyi.common.exception.user.CaptchaException;
 | 
			
		||||
import com.ruoyi.common.exception.user.CaptchaExpireException;
 | 
			
		||||
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
 | 
			
		||||
import com.ruoyi.common.utils.MessageUtils;
 | 
			
		||||
import com.ruoyi.framework.manager.AsyncManager;
 | 
			
		||||
import com.ruoyi.framework.manager.factory.AsyncFactory;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 登录校验方法
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class SysLoginService
 | 
			
		||||
{
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private TokenService tokenService;
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private AuthenticationManager authenticationManager;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RedisCache redisCache;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 登录验证
 | 
			
		||||
     * 
 | 
			
		||||
     * @param username 用户名
 | 
			
		||||
     * @param password 密码
 | 
			
		||||
     * @param code 验证码
 | 
			
		||||
     * @param uuid 唯一标识
 | 
			
		||||
     * @return 结果
 | 
			
		||||
     */
 | 
			
		||||
    public String login(String username, String password, String code, String uuid)
 | 
			
		||||
    {
 | 
			
		||||
        String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
 | 
			
		||||
        String captcha = redisCache.getCacheObject(verifyKey);
 | 
			
		||||
        redisCache.deleteObject(verifyKey);
 | 
			
		||||
        if (captcha == null)
 | 
			
		||||
        {
 | 
			
		||||
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
 | 
			
		||||
            throw new CaptchaExpireException();
 | 
			
		||||
        }
 | 
			
		||||
        if (!code.equalsIgnoreCase(captcha))
 | 
			
		||||
        {
 | 
			
		||||
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
 | 
			
		||||
            throw new CaptchaException();
 | 
			
		||||
        }
 | 
			
		||||
        // 用户验证
 | 
			
		||||
        Authentication authentication = null;
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
 | 
			
		||||
            authentication = authenticationManager
 | 
			
		||||
                    .authenticate(new UsernamePasswordAuthenticationToken(username, password));
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception e)
 | 
			
		||||
        {
 | 
			
		||||
            if (e instanceof BadCredentialsException)
 | 
			
		||||
            {
 | 
			
		||||
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
 | 
			
		||||
                throw new UserPasswordNotMatchException();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
 | 
			
		||||
                throw new CustomException(e.getMessage());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
 | 
			
		||||
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
 | 
			
		||||
        // 生成token
 | 
			
		||||
        return tokenService.createToken(loginUser);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,66 @@
 | 
			
		||||
package com.ruoyi.framework.web.service;
 | 
			
		||||
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import com.ruoyi.common.core.domain.entity.SysUser;
 | 
			
		||||
import com.ruoyi.system.service.ISysMenuService;
 | 
			
		||||
import com.ruoyi.system.service.ISysRoleService;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用户权限处理
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class SysPermissionService
 | 
			
		||||
{
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private ISysRoleService roleService;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private ISysMenuService menuService;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取角色数据权限
 | 
			
		||||
     * 
 | 
			
		||||
     * @param user 用户信息
 | 
			
		||||
     * @return 角色权限信息
 | 
			
		||||
     */
 | 
			
		||||
    public Set<String> getRolePermission(SysUser user)
 | 
			
		||||
    {
 | 
			
		||||
        Set<String> roles = new HashSet<String>();
 | 
			
		||||
        // 管理员拥有所有权限
 | 
			
		||||
        if (user.isAdmin())
 | 
			
		||||
        {
 | 
			
		||||
            roles.add("admin");
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            roles.addAll(roleService.selectRolePermissionByUserId(user.getUserId()));
 | 
			
		||||
        }
 | 
			
		||||
        return roles;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取菜单数据权限
 | 
			
		||||
     * 
 | 
			
		||||
     * @param user 用户信息
 | 
			
		||||
     * @return 菜单权限信息
 | 
			
		||||
     */
 | 
			
		||||
    public Set<String> getMenuPermission(SysUser user)
 | 
			
		||||
    {
 | 
			
		||||
        Set<String> perms = new HashSet<String>();
 | 
			
		||||
        // 管理员拥有所有权限
 | 
			
		||||
        if (user.isAdmin())
 | 
			
		||||
        {
 | 
			
		||||
            perms.add("*:*:*");
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            perms.addAll(menuService.selectMenuPermsByUserId(user.getUserId()));
 | 
			
		||||
        }
 | 
			
		||||
        return perms;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,219 @@
 | 
			
		||||
package com.ruoyi.framework.web.service;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import com.ruoyi.common.constant.Constants;
 | 
			
		||||
import com.ruoyi.common.core.domain.model.LoginUser;
 | 
			
		||||
import com.ruoyi.common.core.redis.RedisCache;
 | 
			
		||||
import com.ruoyi.common.utils.ServletUtils;
 | 
			
		||||
import com.ruoyi.common.utils.StringUtils;
 | 
			
		||||
import com.ruoyi.common.utils.ip.AddressUtils;
 | 
			
		||||
import com.ruoyi.common.utils.ip.IpUtils;
 | 
			
		||||
import com.ruoyi.common.utils.uuid.IdUtils;
 | 
			
		||||
import eu.bitwalker.useragentutils.UserAgent;
 | 
			
		||||
import io.jsonwebtoken.Claims;
 | 
			
		||||
import io.jsonwebtoken.Jwts;
 | 
			
		||||
import io.jsonwebtoken.SignatureAlgorithm;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * token验证处理
 | 
			
		||||
 * 
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class TokenService
 | 
			
		||||
{
 | 
			
		||||
    // 令牌自定义标识
 | 
			
		||||
    @Value("${token.header}")
 | 
			
		||||
    private String header;
 | 
			
		||||
 | 
			
		||||
    // 令牌秘钥
 | 
			
		||||
    @Value("${token.secret}")
 | 
			
		||||
    private String secret;
 | 
			
		||||
 | 
			
		||||
    // 令牌有效期(默认30分钟)
 | 
			
		||||
    @Value("${token.expireTime}")
 | 
			
		||||
    private int expireTime;
 | 
			
		||||
 | 
			
		||||
    protected static final long MILLIS_SECOND = 1000;
 | 
			
		||||
 | 
			
		||||
    protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
 | 
			
		||||
 | 
			
		||||
    private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RedisCache redisCache;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取用户身份信息
 | 
			
		||||
     * 
 | 
			
		||||
     * @return 用户信息
 | 
			
		||||
     */
 | 
			
		||||
    public LoginUser getLoginUser(HttpServletRequest request)
 | 
			
		||||
    {
 | 
			
		||||
        // 获取请求携带的令牌
 | 
			
		||||
        String token = getToken(request);
 | 
			
		||||
        if (StringUtils.isNotEmpty(token))
 | 
			
		||||
        {
 | 
			
		||||
            Claims claims = parseToken(token);
 | 
			
		||||
            // 解析对应的权限以及用户信息
 | 
			
		||||
            String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
 | 
			
		||||
            String userKey = getTokenKey(uuid);
 | 
			
		||||
            LoginUser user = redisCache.getCacheObject(userKey);
 | 
			
		||||
            return user;
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 设置用户身份信息
 | 
			
		||||
     */
 | 
			
		||||
    public void setLoginUser(LoginUser loginUser)
 | 
			
		||||
    {
 | 
			
		||||
        if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken()))
 | 
			
		||||
        {
 | 
			
		||||
            refreshToken(loginUser);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 删除用户身份信息
 | 
			
		||||
     */
 | 
			
		||||
    public void delLoginUser(String token)
 | 
			
		||||
    {
 | 
			
		||||
        if (StringUtils.isNotEmpty(token))
 | 
			
		||||
        {
 | 
			
		||||
            String userKey = getTokenKey(token);
 | 
			
		||||
            redisCache.deleteObject(userKey);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 创建令牌
 | 
			
		||||
     * 
 | 
			
		||||
     * @param loginUser 用户信息
 | 
			
		||||
     * @return 令牌
 | 
			
		||||
     */
 | 
			
		||||
    public String createToken(LoginUser loginUser)
 | 
			
		||||
    {
 | 
			
		||||
        String token = IdUtils.fastUUID();
 | 
			
		||||
        loginUser.setToken(token);
 | 
			
		||||
        setUserAgent(loginUser);
 | 
			
		||||
        refreshToken(loginUser);
 | 
			
		||||
 | 
			
		||||
        Map<String, Object> claims = new HashMap<>();
 | 
			
		||||
        claims.put(Constants.LOGIN_USER_KEY, token);
 | 
			
		||||
        return createToken(claims);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 验证令牌有效期,相差不足20分钟,自动刷新缓存
 | 
			
		||||
     * 
 | 
			
		||||
     * @param token 令牌
 | 
			
		||||
     * @return 令牌
 | 
			
		||||
     */
 | 
			
		||||
    public void verifyToken(LoginUser loginUser)
 | 
			
		||||
    {
 | 
			
		||||
        long expireTime = loginUser.getExpireTime();
 | 
			
		||||
        long currentTime = System.currentTimeMillis();
 | 
			
		||||
        if (expireTime - currentTime <= MILLIS_MINUTE_TEN)
 | 
			
		||||
        {
 | 
			
		||||
            refreshToken(loginUser);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 刷新令牌有效期
 | 
			
		||||
     * 
 | 
			
		||||
     * @param loginUser 登录信息
 | 
			
		||||
     */
 | 
			
		||||
    public void refreshToken(LoginUser loginUser)
 | 
			
		||||
    {
 | 
			
		||||
        loginUser.setLoginTime(System.currentTimeMillis());
 | 
			
		||||
        loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
 | 
			
		||||
        // 根据uuid将loginUser缓存
 | 
			
		||||
        String userKey = getTokenKey(loginUser.getToken());
 | 
			
		||||
        redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * 设置用户代理信息
 | 
			
		||||
     * 
 | 
			
		||||
     * @param loginUser 登录信息
 | 
			
		||||
     */
 | 
			
		||||
    public void setUserAgent(LoginUser loginUser)
 | 
			
		||||
    {
 | 
			
		||||
        UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
 | 
			
		||||
        String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
 | 
			
		||||
        loginUser.setIpaddr(ip);
 | 
			
		||||
        loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
 | 
			
		||||
        loginUser.setBrowser(userAgent.getBrowser().getName());
 | 
			
		||||
        loginUser.setOs(userAgent.getOperatingSystem().getName());
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * 从数据声明生成令牌
 | 
			
		||||
     *
 | 
			
		||||
     * @param claims 数据声明
 | 
			
		||||
     * @return 令牌
 | 
			
		||||
     */
 | 
			
		||||
    private String createToken(Map<String, Object> claims)
 | 
			
		||||
    {
 | 
			
		||||
        String token = Jwts.builder()
 | 
			
		||||
                .setClaims(claims)
 | 
			
		||||
                .signWith(SignatureAlgorithm.HS512, secret).compact();
 | 
			
		||||
        return token;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 从令牌中获取数据声明
 | 
			
		||||
     *
 | 
			
		||||
     * @param token 令牌
 | 
			
		||||
     * @return 数据声明
 | 
			
		||||
     */
 | 
			
		||||
    private Claims parseToken(String token)
 | 
			
		||||
    {
 | 
			
		||||
        return Jwts.parser()
 | 
			
		||||
                .setSigningKey(secret)
 | 
			
		||||
                .parseClaimsJws(token)
 | 
			
		||||
                .getBody();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 从令牌中获取用户名
 | 
			
		||||
     *
 | 
			
		||||
     * @param token 令牌
 | 
			
		||||
     * @return 用户名
 | 
			
		||||
     */
 | 
			
		||||
    public String getUsernameFromToken(String token)
 | 
			
		||||
    {
 | 
			
		||||
        Claims claims = parseToken(token);
 | 
			
		||||
        return claims.getSubject();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取请求token
 | 
			
		||||
     *
 | 
			
		||||
     * @param request
 | 
			
		||||
     * @return token
 | 
			
		||||
     */
 | 
			
		||||
    private String getToken(HttpServletRequest request)
 | 
			
		||||
    {
 | 
			
		||||
        String token = request.getHeader(header);
 | 
			
		||||
        if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX))
 | 
			
		||||
        {
 | 
			
		||||
            token = token.replace(Constants.TOKEN_PREFIX, "");
 | 
			
		||||
        }
 | 
			
		||||
        return token;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String getTokenKey(String uuid)
 | 
			
		||||
    {
 | 
			
		||||
        return Constants.LOGIN_TOKEN_KEY + uuid;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,60 @@
 | 
			
		||||
package com.ruoyi.framework.web.service;
 | 
			
		||||
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.security.core.userdetails.UserDetails;
 | 
			
		||||
import org.springframework.security.core.userdetails.UserDetailsService;
 | 
			
		||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import com.ruoyi.common.core.domain.entity.SysUser;
 | 
			
		||||
import com.ruoyi.common.core.domain.model.LoginUser;
 | 
			
		||||
import com.ruoyi.common.enums.UserStatus;
 | 
			
		||||
import com.ruoyi.common.exception.BaseException;
 | 
			
		||||
import com.ruoyi.common.utils.StringUtils;
 | 
			
		||||
import com.ruoyi.system.service.ISysUserService;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用户验证处理
 | 
			
		||||
 *
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
@Service
 | 
			
		||||
public class UserDetailsServiceImpl implements UserDetailsService
 | 
			
		||||
{
 | 
			
		||||
    private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private ISysUserService userService;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private SysPermissionService permissionService;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
 | 
			
		||||
    {
 | 
			
		||||
        SysUser user = userService.selectUserByUserName(username);
 | 
			
		||||
        if (StringUtils.isNull(user))
 | 
			
		||||
        {
 | 
			
		||||
            log.info("登录用户:{} 不存在.", username);
 | 
			
		||||
            throw new UsernameNotFoundException("登录用户:" + username + " 不存在");
 | 
			
		||||
        }
 | 
			
		||||
        else if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
 | 
			
		||||
        {
 | 
			
		||||
            log.info("登录用户:{} 已被删除.", username);
 | 
			
		||||
            throw new BaseException("对不起,您的账号:" + username + " 已被删除");
 | 
			
		||||
        }
 | 
			
		||||
        else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
 | 
			
		||||
        {
 | 
			
		||||
            log.info("登录用户:{} 已被停用.", username);
 | 
			
		||||
            throw new BaseException("对不起,您的账号:" + username + " 已停用");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return createLoginUser(user);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public UserDetails createLoginUser(SysUser user)
 | 
			
		||||
    {
 | 
			
		||||
        return new LoginUser(user, permissionService.getMenuPermission(user));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user