How Springboot closes the browser, restarts the service, shuts down and does not need to log in again, the session does not disappear

first of all:

When we deploy projects, we sometimes need cluster deployment to ensure that a single platform can continue to provide services to users after a single platform is offline, to ensure our online business, so we need nginx clusters to deploy. In this way, it can be ensured that after a server goes down, the online business will not cause us losses.

In our demonstration, three machines are the best, and two machines are also possible. Only two more virtual machines, deploy a project on each server, and then configure it in the nginxl cluster, configure the weight information of each server or its matching rules. After configuration, we need to configure session sharing, because the session between different services cannot be shared, we can serialize the session and store it in redis.

The first system to use is: windows 10, nginx try to choose a higher version, there are too many things that the lower version does not support.

The framework adopted by the project is: SpringBoot, Shiro.

Knowing that Shiro manages Session (session) in SessionManger, inject sessionDao in sessionManger, so we need to rewrite sessionDao.

Not much to say, the code:


import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;

import java.io.Serializable;
import java.util.Collection;

/**
 * created with IntelliJ IDEA
 *
 * @author: create by limu
 * Date: 2020/12/14
 * Time:21:47
 */
public class RedisSessionDao extends AbstractSessionDAO {

    @Override
    protected Serializable doCreate(Session session) {
        return null;
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
        return null;
    }

    @Override
    public void update(Session session) throws UnknownSessionException {

    }

    @Override
    public void delete(Session session) {

    }

    @Override
    public Collection<Session> getActiveSessions() {
        return null;
    }
}

We can see that there are five methods rewritten: doCreate (create session), doReadSession (read session), update (modify session), delete (delete session), getActiveSession (get session collection).

In fact, this is the same as adding, deleting, modifying and checking the database. This method is called every time the client and the server have a session operation. The reason for choosing redis is that redis reads and writes faster.

The entire code is as follows:


import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.zjxf.base.customer.SysConst;
import com.zjxf.cache.CacheKeys;
import com.zjxf.common.ShiroConst;
import com.zjxf.redis.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SimpleSession;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * created with IntelliJ IDEA
 *
 * @author: create by limu
 * Date: 2020/7/20
 * Time:11:58
 */
@Slf4j
@Service
public class RedisSessionDao extends AbstractSessionDAO {

    @Autowired
    private RedisService redisService;

    public RedisSessionDao() {
        super();
    }

    public RedisSessionDao(RedisService redisService) {
        super();
        this.redisService = redisService;
    }

    @Override
    protected Serializable doCreate(Session session) {
        log.debug("建立会话");
        Serializable sessionId = this.generateSessionId(session);
        this.assignSessionId(session, sessionId);

        JSONObject redisJson = new JSONObject();
        redisJson.put("session", sessionToByte(session));
        redisService.setContainExpire(CacheKeys.getSystemColonyRedisSession(String.valueOf(session.getId())), redisJson, ShiroConst.SHIRO_SESSION_SESSION_MAX_AGE, TimeUnit.SECONDS);
        return sessionId;
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
        if (Objects.nonNull(sessionId)) {
            Optional<JSONObject> redisJsonOptional = redisService.get(CacheKeys.getSystemColonyRedisSession(String.valueOf(sessionId)));
            return redisJsonOptional.map(item -> byteToSession(item.getBytes("session"))).orElse(null);
        } else {
            return null;
        }
    }

    @Override
    public void update(Session session) throws UnknownSessionException {
        if (Objects.nonNull(session) && Objects.nonNull(session.getId())) {
            JSONObject redisJson = new JSONObject();
            redisJson.put("session", sessionToByte(session));
            redisService.setContainExpire(CacheKeys.getSystemColonyRedisSession(String.valueOf(session.getId())), redisJson, ShiroConst.SHIRO_SESSION_SESSION_MAX_AGE, TimeUnit.SECONDS);
        }
    }

    @Override
    public void delete(Session session) {
        log.debug("删除会话");
        if (Objects.nonNull(session) && Objects.nonNull(session.getId())) {
            redisService.delete(CacheKeys.getSystemColonyRedisSession(String.valueOf(session.getId())));
        }
    }

    @Override
    public Collection<Session> getActiveSessions() {
        return redisService.keysValue(CacheKeys.getSystemColonyRedisSession(SysConst.EMPTY)).stream()
                .map(item -> byteToSession(item.getBytes("session"))).collect(Collectors.toCollection(Lists::newArrayList));
    }

    /**
     * session序列化问题处理
     *
     * @param session 会话
     * @return sessionToByte
     */
    public byte[] sessionToByte(Session session) {
        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        byte[] bytes = null;
        try {
            ObjectOutputStream oo = new ObjectOutputStream(bo);
            oo.writeObject(session);
            bytes = bo.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bytes;
    }

    /**
     * 字节转session
     *
     * @param bytes 字节流
     * @return Session
     */
    public Session byteToSession(byte[] bytes) {
        ByteArrayInputStream bi = new ByteArrayInputStream(bytes);
        ObjectInputStream in;
        SimpleSession session = null;
        try {
            in = new ObjectInputStream(bi);
            session = (SimpleSession) in.readObject();
        } catch (ClassNotFoundException | IOException e) {
            e.printStackTrace();
        }
        return session;
    }
}

The above I cached the session in redis. If you have the above serialization problem, you can send a message to me, so that if we restart the service, the session cached in redis has not expired, even if the server is restarted. There will be no need to log in again and so on.

 

 

Guess you like

Origin blog.csdn.net/qq_38821574/article/details/111186415