通用框架平台,每个分支对应子通用框架平台,禁止Merge不同分支!! 分支版本区别见项目内readme.md
whycxzp
2021-01-23 f7f8e9cc7de686fe3e8ef424f1d50fa821255449
update
9个文件已修改
10个文件已添加
977 ■■■■■ 已修改文件
pom.xml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
readme.md 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/config/RedisConfig.java 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/config/RedisSessionDao.java 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/config/ShiroConfig.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/constant/SuperConstant.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/filter/KickedOutFilter.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/pojo/User.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/properties/RedisClusterProperties.java 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/properties/RedisPoolProperties.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/properties/RedisProperties.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/properties/RedisSentinelProperties.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/properties/RedisSingleProperties.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/properties/ShiroRedisProperties.java 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/service/LoginService.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/util/EmptyUtil.java 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/util/ShiroRedissionSerialize.java 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/config/application.yml 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/config/authentication.properties 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -123,6 +123,13 @@
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--redis缓存客户端-->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.5.0</version>
        </dependency>
    </dependencies>
    <build>
readme.md
@@ -3,7 +3,13 @@
* 最初始版框架,接口文档访问:{ip}:{port}/doc.html,例如:localhost:8090/doc.html
* 登录Session为JWT版本
* 登录Session为SessionCookie
* 集群技术主要考虑的是解决Session共享问题,对资源来说最好的方式是redis作为session的存储,也可以使用tomcat的提供的集群设置,实现Session在多个tomcat中的复制(这个本项目不适用,因为内嵌tomcat,不方便设置)
* 采取了分布式缓存,集成了redis单机版/哨兵/集群版本
* web转发采用nginx,配置示例如下
    ```yaml
    TODO
    ```
* 禁止在本通用架构上直接更新具体项目代码提交! 禁止本通用架构上Merge其他git分支!
***********
src/main/java/com/whyc/config/RedisConfig.java
New file
@@ -0,0 +1,105 @@
package com.whyc.config;
import com.whyc.properties.RedisClusterProperties;
import com.whyc.properties.RedisPoolProperties;
import com.whyc.properties.RedisProperties;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.util.StringUtils;
@Configuration
@EnableConfigurationProperties(RedisProperties.class)
@Slf4j
public class RedisConfig {
    @Autowired
    RedisProperties redisProperties;
    /**
     * redis单机
     */
    @Bean("redisClient")
    @ConditionalOnProperty(name = "redis.model", havingValue = "single")
    @Order(1)
    RedissonClient redissonClientSingle() {
        log.error("redis单机版client初始化了");
        Config config = new Config();
        String node = redisProperties.getSingle().getAddress();
        SingleServerConfig serverConfig = config.useSingleServer()
                .setAddress(node)
                .setTimeout(redisProperties.getTimeout())
                .setConnectionPoolSize(redisProperties.getPool().getSize())
                .setConnectionMinimumIdleSize(redisProperties.getPool().getMinIdle());
        if (!StringUtils.isEmpty(redisProperties.getPassword())) {
            serverConfig.setPassword(redisProperties.getPassword());
        }
        return Redisson.create(config);
    }
    /**
     * redis哨兵
     */
    @Bean("redisClient")
    @ConditionalOnProperty(name = "redis.model", havingValue = "sentinel")
    RedissonClient redissonClientSentinel() {
        log.error("redis单机版client初始化了");
        Config config = new Config();
        String[] nodes = redisProperties.getSentinel().getNodes().split(",");
        SentinelServersConfig serversConfig = config.useSentinelServers()
                .addSentinelAddress(nodes)
                .setMasterName(redisProperties.getSentinel().getMaster())
                .setReadMode(ReadMode.SLAVE)
                .setFailedAttempts(redisProperties.getSentinel().getFailMax())
                .setTimeout(redisProperties.getTimeout())
                .setMasterConnectionPoolSize(redisProperties.getPool().getSize())
                .setSlaveConnectionPoolSize(redisProperties.getPool().getSize());
        if (!StringUtils.isEmpty(redisProperties.getPassword())) {
            serversConfig.setPassword(redisProperties.getPassword());
        }
        return Redisson.create(config);
    }
    /**
     * 集群
     */
    @Bean("redisClient")
    @ConditionalOnProperty(name = "redis.model", havingValue = "cluster")
    RedissonClient redissonClientCluster() {
        log.error("redis单机版client初始化了");
        Config config = new Config();
        RedisClusterProperties cluster = redisProperties.getCluster();
        RedisPoolProperties pool = redisProperties.getPool();
        String[] nodes = cluster.getNodes().split(",");
        ClusterServersConfig serversConfig = config.useClusterServers()
                .addNodeAddress(nodes)
                .setScanInterval(cluster.getScanInterval())
                .setIdleConnectionTimeout(pool.getSoTimeout())
                .setConnectTimeout(pool.getConnTimeout())
                .setFailedAttempts(cluster.getFailedAttempts())
                .setRetryAttempts(cluster.getRetryAttempts())
                .setRetryInterval(cluster.getRetryInterval())
                .setMasterConnectionPoolSize(cluster.getMasterConnectionPoolSize())
                .setSlaveConnectionPoolSize(cluster.getSlaveConnectionPoolSize())
                .setTimeout(redisProperties.getTimeout());
        if (!StringUtils.isEmpty(redisProperties.getPassword())) {
            serversConfig.setPassword(redisProperties.getPassword());
        }
        return Redisson.create(config);
    }
}
src/main/java/com/whyc/config/RedisSessionDao.java
New file
@@ -0,0 +1,95 @@
package com.whyc.config;
import com.whyc.constant.SuperConstant;
import com.whyc.util.ShiroRedissionSerialize;
import io.swagger.annotations.ApiModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.DependsOn;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
/**
 * 实现Shiro session的memcached集中式管理
 */
@Slf4j
public class RedisSessionDao extends AbstractSessionDAO {
    /*@Resource(name = "redissonClient4Shiro")
    RedissonClient redissonClient;*/
    @Autowired
    RedissonClient redissonClient;
    private Long globalSessionTimeout;
    /**
     * 保存Session
     * @param session
     * @return
     */
    @Override
    protected Serializable doCreate(Session session) {
        Serializable sessionId = generateSessionId(session);
        assignSessionId(session,sessionId);
        //将Session存入redis
        RBucket<String> sessionIdBucket = redissonClient.getBucket(SuperConstant.GROUP_CAS + sessionId.toString());
        sessionIdBucket.trySet(ShiroRedissionSerialize.serialize(session),globalSessionTimeout, TimeUnit.SECONDS);
        return sessionId;
    }
    /**
     * 读取Session
     * @param sessionId
     * @return
     */
    @Override
    protected Session doReadSession(Serializable sessionId) {
        RBucket<String> sessionIdBucket = redissonClient.getBucket(SuperConstant.GROUP_CAS + sessionId.toString());
        Session session = (Session) ShiroRedissionSerialize.deserialize(sessionIdBucket.get());
        return session;
    }
    /**
     * 更新Session
     * @param session
     * @throws UnknownSessionException
     */
    @Override
    public void update(Session session) throws UnknownSessionException {
        RBucket<String> sessionIdBucket = redissonClient.getBucket(SuperConstant.GROUP_CAS + session.getId().toString());
        sessionIdBucket.set(ShiroRedissionSerialize.serialize(session),globalSessionTimeout,TimeUnit.SECONDS);
        log.info("修改为SessionId:{}",session.getId().toString());
    }
    /**
     * 清除Session
     * @param session
     */
    @Override
    public void delete(Session session) {
        RBucket<String> sessionIdBucket = redissonClient.getBucket(SuperConstant.GROUP_CAS + session.getId().toString());
        sessionIdBucket.delete();
        log.info("Session:{}被清除了",session);
    }
    @Override
    public Collection<Session> getActiveSessions() {
        return Collections.EMPTY_SET;
    }
    public RedisSessionDao(Long globalSessionTimeout) {
        this.globalSessionTimeout = globalSessionTimeout;
    }
}
src/main/java/com/whyc/config/ShiroConfig.java
@@ -3,17 +3,29 @@
import com.whyc.filter.KickedOutFilter;
import com.whyc.filter.RolesOrAuthorizationFilter;
import com.whyc.properties.PropertiesUtil;
import com.whyc.properties.RedisProperties;
import com.whyc.properties.ShiroRedisProperties;
import com.whyc.realm.CustomRealm;
import lombok.extern.log4j.Log4j;
import lombok.extern.log4j.Log4j2;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
@@ -27,17 +39,79 @@
 * 暂时提供权限管理,会话管理后续更新 TODO
 */
@Configuration
//@Log4j2
@Slf4j
@EnableConfigurationProperties({RedisProperties.class})
public class ShiroConfig {
    @Autowired
    CustomRealm customRealm;
    @Autowired
    RedisProperties redisProperties;
    /*================Session采用Redis分布式Session===================*/
    /**
     * Redisson客户端,初始化
     *//*
    @Bean(name = "redissonClient4Shiro")
    public RedissonClient redissonClient(){
        log.info("======初始化redissonClient4Shiro======");
        String[] nodeList = shiroRedisProperties.getNodes().split(",");
        Config config = new Config();
        if(nodeList.length==1){
            config.useSingleServer().setAddress(nodeList[0])
                .setConnectTimeout(shiroRedisProperties.getConnectTimeout())
                .setConnectionPoolSize(shiroRedisProperties.getConnectPoolSize())
                .setConnectionMinimumIdleSize(shiroRedisProperties.getConnectMinIdleSize())
                .setTimeout(shiroRedisProperties.getTimeout());
        }else{
            config.useClusterServers().addNodeAddress(nodeList)
                .setConnectTimeout(shiroRedisProperties.getConnectTimeout())
                .setMasterConnectionPoolSize(shiroRedisProperties.getConnectPoolSize())
                .setMasterConnectionMinimumIdleSize(shiroRedisProperties.getConnectMinIdleSize())
                .setTimeout(shiroRedisProperties.getTimeout());
        }
        RedissonClient redissonClient = Redisson.create(config);
        return redissonClient;
    }*/
    /**
     * 初始化RedisSessionDao
     */
    @Bean("redisSessionDao")
    @DependsOn("redisClient")
    public SessionDAO redisSessionDao(){
        RedisSessionDao redisSessionDao = new RedisSessionDao(redisProperties.getGlobalSessionTimeout());
        return redisSessionDao;
    }
    /**Session管理器*/
    @Bean("sessionManager")
    @DependsOn("redisSessionDao")
    public DefaultWebSessionManager shiroSessionManager(){
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        //设置Session参数
        sessionManager.setSessionDAO(redisSessionDao());
        sessionManager.setSessionValidationSchedulerEnabled(false);
        sessionManager.setSessionIdCookieEnabled(true);
        SimpleCookie simpleCookie = new SimpleCookie("ShiroSession");
        sessionManager.setSessionIdCookie(simpleCookie);
        sessionManager.setGlobalSessionTimeout(redisProperties.getGlobalSessionTimeout());
        return sessionManager;
    }
    /*====================权限管理=======================*/
    /**权限管理器*/
    @Bean(name = "securityManager")
    @DependsOn("sessionManager")
    public DefaultWebSecurityManager defaultWebSecurityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(customRealm);
        securityManager.setSessionManager(shiroSessionManager());
        return securityManager;
    }
src/main/java/com/whyc/constant/SuperConstant.java
@@ -6,12 +6,20 @@
public class SuperConstant {
    /**算法名*/
    public static String HASH_ALGORITHM = "SHA-1";
    public final static String HASH_ALGORITHM = "SHA-1";
    /**hash计算次数*/
    public static int HASH_INTERATIONS = 112;
    public final static  int HASH_INTERATIONS = 112;
    public static String SALT ="Yin";
    public final static String SALT ="Yin";
    /**缓存键值常量*/
    public final static String GROUP_CAS ="group_shiro:";
    public final static String ROLE_KEY =GROUP_CAS+"role_key:";
    public final static String RESOURCE_KEY =GROUP_CAS+"resource_key:";
    public final static String RESOURCE_KEY_IDS =GROUP_CAS+"resource_key_ids:";
    public final static String FIND_USER_BY_LOGIN_NAME =GROUP_CAS+"findUserByLoginName";
src/main/java/com/whyc/filter/KickedOutFilter.java
@@ -2,7 +2,10 @@
import com.whyc.pojo.User;
import com.whyc.util.ShiroUtil;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
@@ -15,6 +18,9 @@
@WebFilter(urlPatterns = "/*",filterName = "kickedOutFilter")
public class KickedOutFilter implements Filter {
    @Autowired
    RedissonClient redissonClient;
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpSession session = ((HttpServletRequest) request).getSession();
@@ -23,7 +29,7 @@
            User user = ShiroUtil.getUser();
            if (user.getId() != 0) {
                System.out.println("Filter过滤器中获取到的当前Session的SessionId为:" + session.getId());
                if (!request.getServletContext().getAttribute(user.getName()).equals(session.getId())) {
                if (!redissonClient.getBucket(user.getName()).get().equals(session.getId())) {
                    //如果当前Session所对应的SessionId与全局中用户对应的SessionId不一致,则清除当前Session
                    session.invalidate();
                    response.setContentType("text/html;charset=utf-8");
src/main/java/com/whyc/pojo/User.java
@@ -1,15 +1,14 @@
package com.whyc.pojo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.*;
import org.apache.ibatis.type.Alias;
import java.io.Serializable;
import java.util.Date;
@Alias("User")
@TableName( schema = "`db_3.5mw_web`",value = "tb_user")
public class User {
public class User implements Serializable {
    private Integer id;
    private String name;
    private String password;
src/main/java/com/whyc/properties/RedisClusterProperties.java
New file
@@ -0,0 +1,83 @@
package com.whyc.properties;
public class RedisClusterProperties {
    private Integer scanInterval;
    private String nodes;
    private String readMode;
    private Integer retryAttempts;
    private Integer failedAttempts;
    private Integer slaveConnectionPoolSize;
    private Integer masterConnectionPoolSize;
    private Integer retryInterval;
    public Integer getScanInterval() {
        return scanInterval;
    }
    public void setScanInterval(Integer scanInterval) {
        this.scanInterval = scanInterval;
    }
    public String getNodes() {
        return nodes;
    }
    public void setNodes(String nodes) {
        this.nodes = nodes;
    }
    public String getReadMode() {
        return readMode;
    }
    public void setReadMode(String readMode) {
        this.readMode = readMode;
    }
    public Integer getRetryAttempts() {
        return retryAttempts;
    }
    public void setRetryAttempts(Integer retryAttempts) {
        this.retryAttempts = retryAttempts;
    }
    public Integer getFailedAttempts() {
        return failedAttempts;
    }
    public void setFailedAttempts(Integer failedAttempts) {
        this.failedAttempts = failedAttempts;
    }
    public Integer getSlaveConnectionPoolSize() {
        return slaveConnectionPoolSize;
    }
    public void setSlaveConnectionPoolSize(Integer slaveConnectionPoolSize) {
        this.slaveConnectionPoolSize = slaveConnectionPoolSize;
    }
    public Integer getMasterConnectionPoolSize() {
        return masterConnectionPoolSize;
    }
    public void setMasterConnectionPoolSize(Integer masterConnectionPoolSize) {
        this.masterConnectionPoolSize = masterConnectionPoolSize;
    }
    public Integer getRetryInterval() {
        return retryInterval;
    }
    public void setRetryInterval(Integer retryInterval) {
        this.retryInterval = retryInterval;
    }
}
src/main/java/com/whyc/properties/RedisPoolProperties.java
New file
@@ -0,0 +1,69 @@
package com.whyc.properties;
public class RedisPoolProperties {
    private Integer size;
    private Integer maxIdle;
    private Integer minIdle;
    private Integer maxActive;
    private Integer maxWait;
    private Integer connTimeout;
    private Integer soTimeout;
    public Integer getSize() {
        return size;
    }
    public void setSize(Integer size) {
        this.size = size;
    }
    public Integer getMaxIdle() {
        return maxIdle;
    }
    public void setMaxIdle(Integer maxIdle) {
        this.maxIdle = maxIdle;
    }
    public Integer getMinIdle() {
        return minIdle;
    }
    public void setMinIdle(Integer minIdle) {
        this.minIdle = minIdle;
    }
    public Integer getMaxActive() {
        return maxActive;
    }
    public void setMaxActive(Integer maxActive) {
        this.maxActive = maxActive;
    }
    public Integer getMaxWait() {
        return maxWait;
    }
    public void setMaxWait(Integer maxWait) {
        this.maxWait = maxWait;
    }
    public Integer getConnTimeout() {
        return connTimeout;
    }
    public void setConnTimeout(Integer connTimeout) {
        this.connTimeout = connTimeout;
    }
    public Integer getSoTimeout() {
        return soTimeout;
    }
    public void setSoTimeout(Integer soTimeout) {
        this.soTimeout = soTimeout;
    }
}
src/main/java/com/whyc/properties/RedisProperties.java
New file
@@ -0,0 +1,87 @@
package com.whyc.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "redis",ignoreUnknownFields = true)
public class RedisProperties {
    private String mode;
    private Integer timeout;
    private Long globalSessionTimeout;
    private String password;
    private RedisPoolProperties pool;
    private RedisSingleProperties single;
    private RedisSentinelProperties sentinel;
    private RedisClusterProperties cluster;
    public String getMode() {
        return mode;
    }
    public void setMode(String mode) {
        this.mode = mode;
    }
    public Integer getTimeout() {
        return timeout;
    }
    public void setTimeout(Integer timeout) {
        this.timeout = timeout;
    }
    public Long getGlobalSessionTimeout() {
        return globalSessionTimeout;
    }
    public void setGlobalSessionTimeout(Long globalSessionTimeout) {
        this.globalSessionTimeout = globalSessionTimeout;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public RedisPoolProperties getPool() {
        return pool;
    }
    public void setPool(RedisPoolProperties pool) {
        this.pool = pool;
    }
    public RedisSingleProperties getSingle() {
        return single;
    }
    public void setSingle(RedisSingleProperties single) {
        this.single = single;
    }
    public RedisSentinelProperties getSentinel() {
        return sentinel;
    }
    public void setSentinel(RedisSentinelProperties sentinel) {
        this.sentinel = sentinel;
    }
    public RedisClusterProperties getCluster() {
        return cluster;
    }
    public void setCluster(RedisClusterProperties cluster) {
        this.cluster = cluster;
    }
}
src/main/java/com/whyc/properties/RedisSentinelProperties.java
New file
@@ -0,0 +1,43 @@
package com.whyc.properties;
public class RedisSentinelProperties {
    private String master;
    private String nodes;
    private String masterOnlyWrite;
    private Integer failMax;
    public String getMaster() {
        return master;
    }
    public void setMaster(String master) {
        this.master = master;
    }
    public String getNodes() {
        return nodes;
    }
    public void setNodes(String nodes) {
        this.nodes = nodes;
    }
    public String getMasterOnlyWrite() {
        return masterOnlyWrite;
    }
    public void setMasterOnlyWrite(String masterOnlyWrite) {
        this.masterOnlyWrite = masterOnlyWrite;
    }
    public Integer getFailMax() {
        return failMax;
    }
    public void setFailMax(Integer failMax) {
        this.failMax = failMax;
    }
}
src/main/java/com/whyc/properties/RedisSingleProperties.java
New file
@@ -0,0 +1,13 @@
package com.whyc.properties;
public class RedisSingleProperties {
    private String address;
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
}
src/main/java/com/whyc/properties/ShiroRedisProperties.java
New file
@@ -0,0 +1,79 @@
package com.whyc.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.io.Serializable;
/**
 * 属性类
 */
@ConfigurationProperties(prefix = "redis")
public class ShiroRedisProperties implements Serializable {
    /**redis连接地址*/
    private String nodes;
    /**连接超时时间*/
    private int connectTimeout;
    /**连接池大小*/
    private int connectPoolSize;
    /**最小空闲连接数*/
    private int connectMinIdleSize;
    /**数据返回超时时间*/
    private int timeout;
    /**全局超时时间*/
    private long globalSessionTimeout;
    public String getNodes() {
        return nodes;
    }
    public void setNodes(String nodes) {
        this.nodes = nodes;
    }
    public int getConnectTimeout() {
        return connectTimeout;
    }
    public void setConnectTimeout(int connectTimeout) {
        this.connectTimeout = connectTimeout;
    }
    public int getConnectPoolSize() {
        return connectPoolSize;
    }
    public void setConnectPoolSize(int connectPoolSize) {
        this.connectPoolSize = connectPoolSize;
    }
    public int getConnectMinIdleSize() {
        return connectMinIdleSize;
    }
    public void setConnectMinIdleSize(int connectMinIdleSize) {
        this.connectMinIdleSize = connectMinIdleSize;
    }
    public int getTimeout() {
        return timeout;
    }
    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }
    public long getGlobalSessionTimeout() {
        return globalSessionTimeout;
    }
    public void setGlobalSessionTimeout(long globalSessionTimeout) {
        this.globalSessionTimeout = globalSessionTimeout;
    }
}
src/main/java/com/whyc/service/LoginService.java
@@ -5,13 +5,22 @@
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.redisson.api.RBucket;
import org.redisson.api.RList;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@Service
public class LoginService {
    @Autowired
    RedissonClient redissonClient;
    public Response login(String userName, String password, HttpServletRequest request) {
        UsernamePasswordToken userToken = new UsernamePasswordToken(userName, password);
@@ -22,10 +31,13 @@
            return new Response<>().set(1,false);
        }
        if (subject.isAuthenticated()){
            //每个登录的用户都有一个全局变量,里面存着对应的SessionId;
            //每个登录的用户都有一个全局变量,里面存着对应的SessionId;redis存储,分布式,否则会报错
            //同一个账号,后面登录的,会挤掉之前登录的SessionId
            System.out.println("全局存储中当前SessionId为:"+request.getSession().getId());
            request.getServletContext().setAttribute(userName,request.getSession().getId());
            //System.out.println("全局存储中当前SessionId为:"+request.getSession().getId());
            //request.getServletContext().setAttribute(userName,request.getSession().getId());
            RBucket<String> bucket = redissonClient.getBucket(userName);
            bucket.set(request.getSession().getId());
            return new Response<>().set(1,true);
        }
        return new Response<>().set(1,false);
src/main/java/com/whyc/util/EmptyUtil.java
New file
@@ -0,0 +1,148 @@
package com.whyc.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
 * @Description 判断对象是否为空的工具类
 */
public abstract class EmptyUtil {
    /**
     *
     * @方法名:对于String类型的非空判断
     * @功能说明:对于String类型的非空判断
     * @author 束文奇
     * @date  Mar 28, 2013 9:26:09 AM
     * @param str
     * @return boolean true-为空,false-不为空
     */
    public static boolean isNullOrEmpty(String str) {
        if (str == null || "".equals(str.trim()) || "null".equalsIgnoreCase(str.trim()) || "undefined".equalsIgnoreCase(str.trim())) {
            return true;
        } else {
            return false;
        }
    }
    /**
     *
     * @方法名:对于StringBuffer类型的非空判断
     * @功能说明:对于StringBuffer类型的非空判断
     * @author 束文奇
     * @date  Mar 28, 2013 9:26:09 AM
     * @param str
     * @return boolean true-为空,false-不为空
     */
    public static boolean isNullOrEmpty(StringBuffer str) {
        return (str == null || str.length() == 0);
    }
    /**
     *
     * @方法名:对于string数组类型的非空判断
     * @功能说明:对于string数组类型的非空判断
     * @author 束文奇
     * @date  Mar 28, 2013 9:26:09 AM
     * @param str
     * @return boolean true-为空,false-不为空
     */
    public static boolean isNullOrEmpty(String[] str) {
        if (str == null || str.length == 0) {
            return true;
        } else {
            return false;
        }
    }
    /**
     *
     * @方法名:对于Object类型的非空判断
     * @功能说明:对于Object类型的非空判断
     * @author 束文奇
     * @date  Mar 28, 2013 9:26:09 AM
     * @param obj
     * @return boolean true-为空,false-不为空
     */
    public static boolean isNullOrEmpty(Object obj) {
        if (obj == null || "".equals(obj)) {
            return true;
        } else {
            return false;
        }
    }
    /**
     *
     * @方法名:对于Object数组类型的非空判断
     * @功能说明:对于Object数组类型的非空判断
     * @author 束文奇
     * @date  Mar 28, 2013 9:26:09 AM
     * @param obj
     * @return boolean true-为空,false-不为空
     */
    public static boolean isNullOrEmpty(Object[] obj) {
        if (obj == null || obj.length == 0) {
            return true;
        } else {
            return false;
        }
    }
    /**
     *
     * @方法名:对于Collection类型的非空判断
     * @功能说明:对于Collection类型的非空判断
     * @author 束文奇
     * @date  Mar 28, 2013 9:26:09 AM
     * @param str
     * @return boolean true-为空,false-不为空
     */
    @SuppressWarnings("rawtypes")
    public static boolean isNullOrEmpty(Collection collection) {
        if (collection == null || collection.isEmpty()) {
            return true;
        } else {
            return false;
        }
    }
    /**
     * @方法名:对于Map类型的非空判断
     * @功能说明:对于Map类型的非空判断
     * @author 束文奇
     *@param map
     *@return  传人参数
     * @throws
     */
    @SuppressWarnings("rawtypes")
    public static boolean isNullOrEmpty( Map map) {
        if (map == null || map.isEmpty()) {
            return true;
        } else {
            return false;
        }
    }
    /**
     *
     * @方法名:removeNullUnit
     * @功能说明: 删除集合中的空元素
     * @author 束文奇
     * @date  2014-6-16 上午8:50:14
     * @param xllxList
     * @return
     */
    public static <T> List<T> removeNullUnit(List<T> xllxList) {
        List<T> need = new ArrayList<T>();
        for (int i = 0; i < xllxList.size(); i++) {
            if (!isNullOrEmpty(xllxList.get(i))) {
                need.add(xllxList.get(i));
            }
        }
        return need;
    }
}
src/main/java/com/whyc/util/ShiroRedissionSerialize.java
New file
@@ -0,0 +1,78 @@
package com.whyc.util;
import com.alibaba.druid.util.StringUtils;
import lombok.extern.log4j.Log4j2;
import lombok.extern.slf4j.Slf4j;
import java.io.*;
/**
 * @Description:自定义序列化工具
 */
@Slf4j
public class ShiroRedissionSerialize {
    //序列化方法
    public static String serialize(Object object){
        //判断对象是否为空
        if (EmptyUtil.isNullOrEmpty(object)){
            return null;
        }
        //流的操作
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos =null;
        String encodeBase64 = null;
        bos = new ByteArrayOutputStream();
        try {
            oos = new ObjectOutputStream(bos);
            oos.writeObject(object);
            //转换字符串
            encodeBase64 = EncodesUtil.encodeBase64(bos.toByteArray());
        } catch (IOException e) {
            e.printStackTrace();
            log.error("流写入异常:{}",e);
        }finally {
            //关闭流
            try {
                bos.close();
                oos.close();
            } catch (IOException e) {
                e.printStackTrace();
                log.error("流写入异常:{}",e);
            }
        }
        return encodeBase64;
    }
    //反序列化方法
    public static Object deserialize(String str){
        //判断是否为空
        if (EmptyUtil.isNullOrEmpty(str)){
            return null;
        }
        //流从操作
        ByteArrayInputStream bis =null;
        ObjectInputStream ois = null;
        Object object = null;
        //转换对象
        bis = new ByteArrayInputStream(EncodesUtil.decodeBase64(str));
        try {
            ois = new ObjectInputStream(bis);
            object = ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("流读取异常:{}",e);
        }finally {
            //关闭流
            try {
                bis.close();
                ois.close();
            } catch (IOException e) {
                e.printStackTrace();
                log.error("流读取异常:{}",e);
            }
        }
        return object;
    }
}
src/main/resources/config/application.yml
@@ -59,3 +59,38 @@
knife:
  enable: true
#  enable: fase
redis:
  #模式 single/sentinel/cluster
  model: single
  timeout: 3000
  global-session-timeout: 360000
  password:
  #连接池配置
  pool:
    size: 10
    max-idle: 16
    min-idle: 8
    max-active: 8
    max-wait: 3000
    conn-timeout: 3000
    so-timeout: 3000
  #单机配置
  single:
    address: redis://localhost:6379
  #哨兵配置
  sentinel:
    master: business-master
    nodes: redis://localhost:6379,redis://localhost:6380
    master-onlyWrite: true
    fail-max: 3
  #集群配置
  cluster:
    scan-interval: 1000
    nodes: redis://localhost:6379
    read-mode: SLAVE
    retry-attempts: 3
    failed-attempts: 3
    slave-connection-pool-size: 64
    master-connection-pool-size: 64
    retry-interval: 1500
src/main/resources/config/authentication.properties
@@ -1,5 +1,5 @@
#dev接口调试时使用
/**=anon
#/**=anon
#静态资源不拦截
/static/**=anon
@@ -19,9 +19,9 @@
#/resource/**=roles-or[dev,SuperAdmin]
#设置需要permission的拦截
/WaterComm/**=perms["water:all"]
#/WaterComm/**=perms["water:all"]
#设置RolesOr拦截
#/WaterComm/**=rolesOr["admin","dev"]
#其他链接是需要登录的
#/**=authc
/**=authc