Spring Boot implementation consistency Session application instance

Initialize project

1. Create a new Spring Boot project, add web by default, and wait for the completion of the construction. After the completion, the directory structure is as follows:

.
├── HELP.md
├── login-session-demo.iml
├── mvnw
├── mvnw.cmd
├── pom.xml
├── src
│   ├── main
│   │   ├── java
│   │   ├── resources
│   │   └── webapp
│   └── test
│       └── java
└── target

pom file

Where, POM The XML content is as follows

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.terwergreen</groupId>
    <artifactId>login-session-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>login-session-demo</name>
    <description>login-session-demo</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Create login controller

2. Create LoginController, add @ Controller annotation, and add corresponding methods

/**
 * Login controller
 *
 * @name: LoginController
 * @author: terwer
 * @date: 2022-01-24 16:36
 **/
@RequestMapping("/login")
@Controller
public class LoginController {

    @RequestMapping(value = "/toLogin", method = RequestMethod.GET)
    public String toLogin() {
        return "login";
    }

    @RequestMapping(value = "login", method = RequestMethod.POST)
    public String login(String username, String password) {
        if ("test".equals(username) && "test".equals(password)) {
            return "redirect:/result.jsp";
        }

        return "login";
    }
}

Configure template path mapping

3. Configure application Properties, set the port, and the jsp template prefix and suffix of spring MVC

server.port=8081

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

Then add the webapp/WEB-INF/jsp directory under main

Create a new login JSP file.

4. A problem occurs and access http://localhost:8081/login/toLogin Error 404 is reported and printed on the console

Reason: jsp is not supported by default. Need to be in POM XML add the following jar package to support jsp

<!--jsp Page usage jstl label -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
</dependency>

<!--For compilation jsp -->
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <scope>provided</scope>
</dependency>

Reload POM XML, then restart the project and access it again http://localhost:8081/login/toLogin , the page appears correctly

Hot deployment

5. Add hot deployment

In order to modify the file and see the effect in time, you can add a hot deployment plug-in.

<!-- Hot deployment -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
</dependency>

Add interceptor to realize login verification

6. Add interceptor for login verification

Create login interceptor

/**
 * Login interceptor
 *
 * @name: LoginInterceptor
 * @author: terwer
 * @date: 2022-01-24 17:46
 **/
@Component
public class LoginInterceptor implements HandlerInterceptor {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * Using Session to verify login status to realize login interception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.info("Enter login interceptor");
        HttpSession session = request.getSession();
        Object username = session.getAttribute(Constant.SESSION_USERNAME_KEY);
        if (null == username) {
            logger.info("No login or login failure");
            response.sendRedirect(request.getContextPath() + "/login/toLogin");
            return false;
        }

        logger.info("from Session Login name obtained in:" + username);
        return true;
    }
}

Register the login interceptor to Spring Boot

/**
 * Spring  MVC Custom configuration
 *
 * @name: MyWebMvcConfigAdaptor
 * @author: terwer
 * @date: 2022-01-24 17:51
 **/
@Configuration
public class MyWebMvcConfigAdaptor implements WebMvcConfigurer {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // Register interceptor
        // Block all by default
        // Exclude the login page itself and the error page
        registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/login/**", "/error");

        logger.info("Login interceptor added");
    }
}

Integrated mybatis

7. Integrated mybatis

mybatis integration

pom.xml is added to mybatis dependency and mysql database

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.1</version>
</dependency>

<!--mysql Driving coordinates-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.6</version>
    <scope>runtime</scope>
</dependency>

Configuration file configuration data source, mybatis

# mybatis
mybatis.mapper-locations=classpath:com/terwergreen/dao/*.xml

# mysql
spring.datasource.url=jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

Create Mapper

/**
 * User mapping class
 *
 * @name: UserMapper
 * @author: terwer
 * @date: 2022-01-24 21:44
 **/
public interface UserMapper{
    public User findByCondition(User user);
}

mapper mapping

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.terwergreen.dao.UserMapper">
    <select id="findByCondition" parameterType="com.terwergreen.pojo.User" resultType="com.terwergreen.pojo.User">
        select * from user where username=#{username} and password=#{password}
    </select>
</mapper>

service business processing

/**
 * Login service
 *
 * @name: LoginServiceImpl
 * @author: terwer
 * @date: 2022-01-24 22:06
 **/
@Service
public class LoginServiceImpl implements LoginService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private SqlSession session;

    public boolean doLogin(String username, String password) {
        logger.info("Start processing login");


        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        // User result = session.selectOne("findByCondition", user);

        UserMapper userMapper = session.getMapper(UserMapper.class);
        User result = userMapper.findByCondition(user);

        if (null != result) {
            logger.info("User information verification succeeded");
            return true;
        }

        logger.info("The user does not exist or the password is incorrect");
        return false;
    }
}

General implementation optimization and problems

controller login processing

    @RequestMapping(value = "login", method = RequestMethod.POST)
    public String login(String username, String password, HttpServletRequest request) {
        HttpSession session = request.getSession();

        if (loginService.doLogin(username, password)) {
            request.getSession().setAttribute(Constant.SESSION_USERNAME_KEY, username);
            session.setAttribute(Constant.SESSION_LOGIN_FAIL_MSG_KEY, "");
            return "redirect:/demo/result";
        }

        session.setAttribute(Constant.SESSION_LOGIN_FAIL_MSG_KEY, Constant.SESSION_LOGIN_FAIL_MSG);
        return "login";
    }

Use interceptor to intercept login

Interceptor implementation

Create a new LoginInterceptor to implement the HandlerInterceptor interface and intercept it in the preHandle

/**
 * Login interceptor
 *
 * @name: LoginInterceptor
 * @author: terwer
 * @date: 2022-01-24 17:46
 **/
@Component
public class LoginInterceptor implements HandlerInterceptor {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * Using Session to check login status to realize login interception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.info("Enter login interceptor");
        HttpSession session = request.getSession();
        Object username = session.getAttribute(Constant.SESSION_USERNAME_KEY);
        if (null == username) {
            logger.info("No login or login failure");
            // session.setAttribute( Constant.SESSION_LOGIN_FAIL_MSG_KEY, Constant.SESSION_LOGIN_FAIL_MSG);
            response.sendRedirect(request.getContextPath() + "/login/toLogin");
            return false;
        }

        session.setAttribute( Constant.SESSION_LOGIN_FAIL_MSG_KEY, "");
        logger.info("from Session Login name obtained in:" + username);
        return true;
    }
}

Register interceptor

/**
 * Spring  MVC Custom configuration
 *
 * @name: MyWebMvcConfigAdaptor
 * @author: terwer
 * @date: 2022-01-24 17:51
 **/
@Configuration
public class MyWebMvcConfigAdaptor implements WebMvcConfigurer {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // Register interceptor
        // Block all by default
        // Exclude the login page itself and the error page
        registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/login/**", "/error");

        logger.info("Login interceptor added");
    }
}

Save the session to redis to solve the problem

When the above implementation implements the Nginx polling policy, there will be inconsistent login sessions. The solution is to save the session to redis. The specific method is to add the corresponding starter to seamlessly integrate redis.

<!-- redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>

Deployment validation

nginx configuration

upstream loginServer{
   # For the convenience of testing, 127.0.0.1 is used
   server 127.0.0.1:8080;
   server 127.0.0.1:8081;
   # server 192.168.136.134:8080;
   # server 192.168.136.134:8081;
}

server {
    # Listening port
    listen       80;
    server_name  localhost;

    #charset koi8-r;

    #access_log  logs/host.access.log  main;

    # Default request
    location / {
	    proxy_pass http://loginServer/;
        # root   html;
        # index  index.html index.htm;
    }
}

Package with maven, and then put the war package into the webapps directory of tomcat.

Finally, access the test.

If it is a local deployment, it can be accessed

http://127.0.0.1:8081/logindemo/login/toLogin

Otherwise, replace 127.0.0.1 with server ip.

Refer to the video for details

https://www.bilibili.com/video/BV1xa411m7RC/

Complete code

https://github.com/terwer/login-session-demo

Keywords: Java Nginx Session Spring Boot Tomcat

Added by anon_login_001 on Wed, 26 Jan 2022 21:30:09 +0200