初始化项目
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