集群現在越來越常見,當我們項目搭建了集群,就會產生session共享問題。因為session是保存在服務器上面的。那么解決這一問題,大致有三個方案,1.通過nginx的負載均衡其中一種ip綁定來實現(通過ip綁定服務器其中一台,就沒有集群概念了);2.通過cookie備份session實現(因為cookie數據保存在客戶端,不推薦;3.通過redis備份session實現(推薦);
學習本章節之前,建議依次閱讀以下文章,更好的串聯全文內容,如已掌握以下列出知識點,請跳過:
vSpring Session概念
Spring Session 提供了一套創建和管理 Servlet HttpSession 的方案。Spring Session 提供了集群 Session(Clustered Sessions)功能,默認采用外置的 Redis 來存儲 Session 數據(不用手動存儲到redis中),以此來解決 Session 共享的問題。
Spring Session 為企業級 Java 應用的 session 管理帶來了革新,使得以下的功能更加容易實現:
關於更多Spring Session概念的介紹,可以看看官網Spring Session
vSpring Session整合
1.1 引入pmo.xml
<dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency>
1.2 創建useraccount表
CREATE TABLE `useraccount` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `username` varchar(255) NOT NULL, `age` int(10) NOT NULL, `phone` bigint NOT NULL, `email` varchar(255) NOT NULL, `account` varchar(100) NOT NULL UNIQUE, `pwd` varchar(255) NOT NULL, PRIMARY KEY (`id`) )ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; insert into `useraccount` values(1,'趙(dev)',23,158,'3658561548@qq.com','test001','test001'); insert into `useraccount` values(2,'錢(dev)',27,136,'3658561548@126.com','test002','test002'); insert into `useraccount` values(3,'孫(dev)',31,159,'3658561548@163.com','test003','test003'); insert into `useraccount` values(4,'李(dev)',35,130,'3658561548@sina.com','test004','test004'); select * from `useraccount`;
1.3 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.demo.dao.UserAccountMapper"> <resultMap id="BaseResultMap" type="com.demo.pojo.UserAccount"> <id column="id" jdbcType="INTEGER" property="id" /> <result column="username" jdbcType="VARCHAR" property="username" /> <result column="age" jdbcType="INTEGER" property="age" /> <result column="phone" jdbcType="BIGINT" property="phone" /> <result column="email" jdbcType="VARCHAR" property="email" /> <result column="account" jdbcType="VARCHAR" property="account" /> <result column="pwd" jdbcType="VARCHAR" property="pwd" /> </resultMap> <sql id="Base_Column_List"> id, username, age, phone, email, account, pwd </sql> <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap"> select <include refid="Base_Column_List" /> from useraccount where id = #{id,jdbcType=INTEGER} </select> <select id="getUserByAccount" parameterType="java.lang.String" resultMap="BaseResultMap"> select <include refid="Base_Column_List" /> from useraccount where account = #{account} </select> <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer"> delete from useraccount where id = #{id,jdbcType=INTEGER} </delete> <insert id="insert" parameterType="com.demo.pojo.UserAccount"> insert into useraccount (id, username, age, phone, email, account, pwd) values (#{id,jdbcType=INTEGER}, #{username,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER}, #{phone,jdbcType=BIGINT}, #{email,jdbcType=VARCHAR}, #{account,jdbcType=VARCHAR}, #{pwd,jdbcType=VARCHAR}) </insert> <insert id="insertSelective" parameterType="com.demo.pojo.UserAccount"> insert into useraccount <trim prefix="(" suffix=")" suffixOverrides=","> <if test="id != null"> id, </if> <if test="username != null"> username, </if> <if test="age != null"> age, </if> <if test="phone != null"> phone, </if> <if test="email != null"> email, </if> <if test="account != null"> account, </if> <if test="pwd != null"> pwd, </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides=","> <if test="id != null"> #{id,jdbcType=INTEGER}, </if> <if test="username != null"> #{username,jdbcType=VARCHAR}, </if> <if test="age != null"> #{age,jdbcType=INTEGER}, </if> <if test="phone != null"> #{phone,jdbcType=BIGINT}, </if> <if test="email != null"> #{email,jdbcType=VARCHAR}, </if> <if test="account != null"> #{account,jdbcType=VARCHAR}, </if> <if test="pwd != null"> #{pwd,jdbcType=VARCHAR}, </if> </trim> </insert> <update id="updateByPrimaryKeySelective" parameterType="com.demo.pojo.UserAccount"> update useraccount <set> <if test="username != null"> username = #{username,jdbcType=VARCHAR}, </if> <if test="age != null"> age = #{age,jdbcType=INTEGER}, </if> <if test="phone != null"> phone = #{phone,jdbcType=BIGINT}, </if> <if test="email != null"> email = #{email,jdbcType=VARCHAR}, </if> <if test="account != null"> account = #{account,jdbcType=VARCHAR}, </if> <if test="pwd != null"> pwd = #{pwd,jdbcType=VARCHAR}, </if> </set> where id = #{id,jdbcType=INTEGER} </update> <update id="updateByPrimaryKey" parameterType="com.demo.pojo.UserAccount"> update useraccount set username = #{username,jdbcType=VARCHAR}, age = #{age,jdbcType=INTEGER}, phone = #{phone,jdbcType=BIGINT}, email = #{email,jdbcType=VARCHAR}, account = #{account,jdbcType=VARCHAR}, pwd = #{pwd,jdbcType=VARCHAR} where id = #{id,jdbcType=INTEGER} </update> </mapper>

package com.demo.dao; import com.demo.pojo.UserAccount; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; @Mapper @Repository public interface UserAccountMapper { int deleteByPrimaryKey(Integer id); int insert(UserAccount record); int insertSelective(UserAccount record); UserAccount selectByPrimaryKey(Integer id); UserAccount getUserByAccount(@Param("account") String account); int updateByPrimaryKeySelective(UserAccount record); int updateByPrimaryKey(UserAccount record); }
1.4 實體類

package com.demo.pojo; import java.io.Serializable; public class UserAccount implements Serializable { private static final long serialVersionUID = 1L; private Integer id; private String username; private Integer age; private Long phone; private String email; private String account; private String pwd; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username == null ? null : username.trim(); } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Long getPhone() { return phone; } public void setPhone(Long phone) { this.phone = phone; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email == null ? null : email.trim(); } public String getAccount() { return account; } public void setAccount(String account) { this.account = account == null ? null : account.trim(); } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd == null ? null : pwd.trim(); } }
1.5 service層
Service
UserAccount getUserByAccount(String account);
ServiceImpl
@Override public UserAccount getUserByAccount(String account){ return userAccountMapper.getUserByAccount(account); }
1.6 添加session配置類
package com.demo.common; import org.springframework.context.annotation.Configuration; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; /** * Created by toutou on 2019/1/22. */ @Configuration @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800) /** * maxInactiveIntervalInSeconds: 設置 Session 失效時間,使用 Redis Session 之后,原 Boot 的 server.session.timeout 屬性不再生效。 */ public class SessionRedisConfig { }
1.7 設置攔截器
關於攔截器不懂的話,可以看我之前的一篇文章《SpringBoot(十一)過濾器和攔截器》
/* * 進入controller層之前攔截請求 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object obj) throws Exception { System.out.println("MyTestInterceptor 1111111111"); Object user= request.getSession().getAttribute("useraccount"); if (user==null){ // response.sendRedirect(request.getContextPath()+"/error"); response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=utf-8"); response.getWriter().write("請先登錄"); return false; } return true; }
@Override public void addInterceptors(InterceptorRegistry registry) { // 自定義攔截器,添加攔截路徑和排除攔截路徑 registry.addInterceptor(myTestInterceptor).addPathPatterns("/**").excludePathPatterns("/userlogin"); }
設置全局攔截
1.8 登錄/注銷
package com.demo.controller; import com.demo.pojo.UserAccount; import com.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; /** * Created by toutou on 2019/1/22. */ @RestController public class LoginController { @Autowired UserService userService; @RequestMapping(value = "/userlogin") public String Login(HttpServletRequest request, String account, String pwd) { UserAccount user= userService.getUserByAccount(account); if (user!=null && user.getPwd().equals(pwd)){ request.getSession().setAttribute("useraccount",user); return "登錄成功"; } return "登錄失敗"; } @RequestMapping(value = "/userlogout") public String logout (HttpServletRequest request){ HttpSession session=request.getSession(); session.removeAttribute("useraccount"); return "退出登錄"; } }
v效果演示
2.1 直接訪問頁面
提示:請先登錄
2.2 調用登錄接口
登錄以后再次訪問頁面,提示訪問成功。
2.3 退出登錄
v源碼地址
https://github.com/toutouge/javademosecond/tree/master/hellospringboot
作 者:請叫我頭頭哥
出 處:http://www.cnblogs.com/toutou/
關於作者:專注於基礎平台的項目開發。如有問題或建議,請多多賜教!
版權聲明:本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。
特此聲明:所有評論和私信都會在第一時間回復。也歡迎園子的大大們指正錯誤,共同進步。或者直接私信我
聲援博主:如果您覺得文章對您有幫助,可以點擊文章右下角【推薦】一下。您的鼓勵是作者堅持原創和持續寫作的最大動力!