Spring Boot实现一致性Session应用实例

初始化项目

1、新建一个 Spring Boot 项目,默认添加 web,然后等待构建完成,完成后目录结构如下:

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

pom文件

其中,pom.xml内容如下

<?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>

创建登录控制器

2、创建 LoginController , 添加 @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";
    }
}

配置模板路径映射

3、配置 application.properties ,设置端口,springmvc的jsp模板前缀和后缀

server.port=8081

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

然后在main下面新增webapp/WEB-INF/jsp目录

再新建 login.jsp 文件。

4、此时会发生问题,访问 http://localhost:8081/login/toLogin 报错 404,控制台打印

原因:默认不支持jsp。需要在pom.xml加入下面的jar包以支持jsp

<!--jsp页面使用jstl标签 -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
</dependency>

<!--用于编译jsp -->
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <scope>provided</scope>
</dependency>

重新加载pom.xml,然后重启项目,再次访问 http://localhost:8081/login/toLogin ,正确出现页面

热部署

5、添加热部署

为了修改文件能够及时看到效果,可以添加热部署插件。

<!-- 热部署 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
</dependency>

添加拦截器实现登录验证

6、添加拦截器进行登录验证

创建登录拦截器

/**
 * 登录拦截器
 *
 * @name: LoginInterceptor
 * @author: terwer
 * @date: 2022-01-24 17:46
 **/
@Component
public class LoginInterceptor implements HandlerInterceptor {

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

    /**
     * 利用Session校验登录状态实现登录拦截
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.info("进入登录拦截器");
        HttpSession session = request.getSession();
        Object username = session.getAttribute(Constant.SESSION_USERNAME_KEY);
        if (null == username) {
            logger.info("未登录或者登录失效");
            response.sendRedirect(request.getContextPath() + "/login/toLogin");
            return false;
        }

        logger.info("从Session中获取的登录名:" + username);
        return true;
    }
}

注册登录拦截器到Spring Boot中去

/**
 * Spring  MVC自定义配置
 *
 * @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) {
        // 注册拦截器
        // 默认拦截所有
        // 排除登录页面本身还有错误页面
        registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/login/**", "/error");

        logger.info("登录拦截器已添加");
    }
}

集成mybatis

7、集成mybatis

mybatis集成

pom.xml加入mybatis依赖、mysql数据库

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

<!--mysql驱动坐标-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.6</version>
    <scope>runtime</scope>
</dependency>

配置文件配置数据源、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

创建Mapper

/**
 * 用户映射类
 *
 * @name: UserMapper
 * @author: terwer
 * @date: 2022-01-24 21:44
 **/
public interface UserMapper{
    public User findByCondition(User user);
}

mapper映射

<?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业务处理

/**
 * 登录业务
 *
 * @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("开始处理登录");


        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("用户信息校验成功");
            return true;
        }

        logger.info("用户不存在或者密码错误");
        return false;
    }
}

常规实现优化以及问题

controller登录处理

    @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";
    }

利用拦截器进行登录拦截

拦截器实现

新建 LoginInterceptor 实现 HandlerInterceptor 接口,在preHandle里面进行拦截

/**
 * 登录拦截器
 *
 * @name: LoginInterceptor
 * @author: terwer
 * @date: 2022-01-24 17:46
 **/
@Component
public class LoginInterceptor implements HandlerInterceptor {

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

    /**
     * 利用Session校验登录状态实现登录拦截
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.info("进入登录拦截器");
        HttpSession session = request.getSession();
        Object username = session.getAttribute(Constant.SESSION_USERNAME_KEY);
        if (null == username) {
            logger.info("未登录或者登录失效");
            // 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("从Session中获取的登录名:" + username);
        return true;
    }
}

注册拦截器

/**
 * Spring  MVC自定义配置
 *
 * @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) {
        // 注册拦截器
        // 默认拦截所有
        // 排除登录页面本身还有错误页面
        registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/login/**", "/error");

        logger.info("登录拦截器已添加");
    }
}

session保存到redis解决问题

上面的实现在Nginx轮询策略的时候,会出现登录session不一致问题。解决方案是把session保存到redis。具体方法就是加上对应的starter即可无缝集成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>

部署验证

nginx配置

upstream loginServer{
   # 为了测试方便,使用127.0.0.1
   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 {
    # 监听的端口
    listen       80;
    server_name  localhost;

    #charset koi8-r;

    #access_log  logs/host.access.log  main;

    # 默认请求
    location / {
	    proxy_pass http://loginServer/;
        # root   html;
        # index  index.html index.htm;
    }
}

利用maven打包,然后把war包放到tomcat的webapps目录下即可。

最后访问测试。

如果是本地部署可以访问

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

否则把127.0.0.1换成服务器ip即可。

具体细节可参考视频

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

完整的代码

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

posted @ 2022-01-24 17:10  灯塔下的守望者  阅读(137)  评论(0编辑  收藏  举报