1、需求

当用户未登录时,只允许访问index/login资源,否则直接查询数据,会过滤到登录页面要求登录。
由于这里用到Redis做缓存数据库,包括保存token以及查询数据缓存等,所以需要提前安装好Redis,如果还没有安装的,可以参考一下这篇文章:Windows系统本地安装Redis并设置服务自启动(图文)

2、实现

2.1、创建数据库表,以及添加测试数据

User表

CREATE TABLE `user` (`uid` varchar(50) NOT NULL COMMENT '用户id',`username` varchar(50) NOT NULL COMMENT '用户名',`password` varchar(50) NOT NULL COMMENT '密码',`name` varchar(50) DEFAULT NULL COMMENT '姓名',PRIMARY KEY (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

插入数据:

INSERT INTO `user` VALUES ('1', 'lmf', 'lumingfei', '路明非');
INSERT INTO `user` VALUES ('10', 'hly', 'huiliyi', '绘梨衣');
INSERT INTO `user` VALUES ('2', 'lmz', 'lumingze', '路鸣泽');
INSERT INTO `user` VALUES ('3', 'czh', 'chuzihang', '楚子航');
INSERT INTO `user` VALUES ('30', 'xm', 'xiami', '夏弥');
INSERT INTO `user` VALUES ('31', 'sq', 'suqian', '苏茜');
INSERT INTO `user` VALUES ('8', 'yzs', 'yuanzhisheng', '源稚生');
INSERT INTO `user` VALUES ('80', 'yzn', 'yuanzhinv', '源稚女');
INSERT INTO `user` VALUES ('81', 'scy', 'shichuiying', '矢吹樱');
INSERT INTO `user` VALUES ('82', 'zblz', 'zuobolongzhi', '佐伯龙治');
INSERT INTO `user` VALUES ('9', 'ks', 'kaisa', '凯撒');
INSERT INTO `user` VALUES ('90', 'cmt', 'chenmotong', '陈墨瞳');

创建Movie表

CREATE TABLE `movie` (`movie_id` varchar(50) NOT NULL COMMENT '电影编号',`movie_name` varchar(20) DEFAULT NULL COMMENT '电影名称',`movie_price` decimal(10,2) DEFAULT NULL COMMENT '价格',`movie_release_time` varchar(20) DEFAULT NULL COMMENT '电影上映时间',`movie_shelf_time` varchar(20) DEFAULT NULL COMMENT '电影下架时间',`movie_recommended_level` int(11) DEFAULT NULL COMMENT '推荐等级',`movie_language` varchar(10) DEFAULT NULL COMMENT '电影语种',PRIMARY KEY (`movie_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

插入数据:

INSERT INTO `movie` VALUES ('1', '海上钢琴师', '99.90', '1900-09-09 09:09:09', '2020-20-20 20:20:20', '10', '英语');
INSERT INTO `movie` VALUES ('10', '鬼灭之刃', '99.90', '1909-09-09 19:29:59', '2020-20-20 20:20:20', '10', '日语');
INSERT INTO `movie` VALUES ('11', 'Fate', '77.90', '1907-07-19 17:07:27', '2020-20-20 20:20:20', '10', '日语');
INSERT INTO `movie` VALUES ('12', '哪吒之魔童降世', '80.90', '1980-11-29 23:00:23', '2020-20-20 20:20:20', '8', '汉语');
INSERT INTO `movie` VALUES ('13', '无双', '99.90', '1999-11-11 12:11:12', '2020-20-20 20:20:20', '10', '汉语');
INSERT INTO `movie` VALUES ('14', '三傻大闹宝莱坞', '89.90', '2000-01-11 12:00:00', '2020-20-20 20:20:20', '10', '印度语');
INSERT INTO `movie` VALUES ('15', '钢铁侠1', '99.90', '1900-09-09 09:09:09', '2020-20-20 20:20:20', '10', '英语');
INSERT INTO `movie` VALUES ('16', '钢铁侠2', '88.80', '1901-01-01 01:01:01', '2020-20-20 20:20:20', '8', '英语');
INSERT INTO `movie` VALUES ('17', '美国队长1', '99.90', '1909-09-09 19:29:59', '2020-20-20 20:20:20', '10', '英语');
INSERT INTO `movie` VALUES ('18', '美国队长2', '77.90', '1907-07-19 17:07:27', '2020-20-20 20:20:20', '9', '英语');
INSERT INTO `movie` VALUES ('19', '蜘蛛侠1', '80.90', '1980-11-29 23:00:23', '2020-20-20 20:20:20', '8', '英语');
INSERT INTO `movie` VALUES ('2', '阿甘正传', '88.80', '1901-01-01 01:01:01', '2020-20-20 20:20:20', '8', '英语');
INSERT INTO `movie` VALUES ('20', '蜘蛛侠2', '99.90', '1999-11-11 12:11:12', '2020-20-20 20:20:20', '10', '英语');
INSERT INTO `movie` VALUES ('21', '绿巨人', '89.90', '2000-01-11 12:00:00', '2020-20-20 20:20:20', '7', '英语');
INSERT INTO `movie` VALUES ('22', '复仇者联盟1', '99.90', '1900-09-09 09:09:09', '2020-20-20 20:20:20', '10', '英语');
INSERT INTO `movie` VALUES ('23', '复仇者联盟2', '88.80', '1901-01-01 01:01:01', '2020-20-20 20:20:20', '8', '英语');
INSERT INTO `movie` VALUES ('24', '金刚狼1', '99.90', '1909-09-09 19:29:59', '2020-20-20 20:20:20', '10', '英语');
INSERT INTO `movie` VALUES ('25', '金刚狼2', '77.90', '1907-07-19 17:07:27', '2020-20-20 20:20:20', '9', '英语');
INSERT INTO `movie` VALUES ('26', '侏罗纪公园', '80.90', '1980-11-29 23:00:23', '2020-20-20 20:20:20', '8', '英语');
INSERT INTO `movie` VALUES ('27', '猩球崛起', '99.90', '1999-11-11 12:11:12', '2020-20-20 20:20:20', '10', '英语');
INSERT INTO `movie` VALUES ('28', '金刚', '89.90', '2000-01-11 12:00:00', '2020-20-20 20:20:20', '7', '英语');
INSERT INTO `movie` VALUES ('29', '灵笼', '99.90', '1900-09-09 09:09:09', '2020-20-20 20:20:20', '10', '汉语');
INSERT INTO `movie` VALUES ('3', '当幸福来敲门', '99.90', '1909-09-09 19:29:59', '2020-20-20 20:20:20', '10', '英语');
INSERT INTO `movie` VALUES ('30', '秦时明月之百步飞剑', '88.80', '1901-01-01 01:01:01', '2020-20-20 20:20:20', '10', '汉语');
INSERT INTO `movie` VALUES ('31', '秦时明月之夜尽天明', '99.90', '1909-09-09 19:29:59', '2020-20-20 20:20:20', '10', '汉语');
INSERT INTO `movie` VALUES ('32', '秦时明月之诸子百家', '77.90', '1907-07-19 17:07:27', '2020-20-20 20:20:20', '10', '汉语');
INSERT INTO `movie` VALUES ('33', '秦时明月之万里长城', '80.90', '1980-11-29 23:00:23', '2020-20-20 20:20:20', '10', '汉语');
INSERT INTO `movie` VALUES ('34', '秦时明月至君临天下', '99.90', '1999-11-11 12:11:12', '2020-20-20 20:20:20', '10', '汉语');
INSERT INTO `movie` VALUES ('35', '天行九歌', '89.90', '2000-01-11 12:00:00', '2020-20-20 20:20:20', '10', '汉语');
INSERT INTO `movie` VALUES ('4', '肖申克的救赎', '77.90', '1907-07-19 17:07:27', '2020-20-20 20:20:20', '9', '英语');
INSERT INTO `movie` VALUES ('5', '看不见的客人', '80.90', '1980-11-29 23:00:23', '2020-20-20 20:20:20', '8', '印度语');
INSERT INTO `movie` VALUES ('6', '战狼2', '99.90', '1999-11-11 12:11:12', '2020-20-20 20:20:20', '10', '汉语');
INSERT INTO `movie` VALUES ('7', '大圣归来', '89.90', '2000-01-11 12:00:00', '2020-20-20 20:20:20', '7', '汉语');
INSERT INTO `movie` VALUES ('8', '犬夜叉', '99.90', '1900-09-09 09:09:09', '2020-20-20 20:20:20', '9', '日语');
INSERT INTO `movie` VALUES ('9', '刀剑神域', '88.80', '1901-01-01 01:01:01', '2020-20-20 20:20:20', '8', '日语');

2.2、创建Maven项目,并导入依赖

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.wnkj</groupId><artifactId>sso</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><name>sso Maven Webapp</name><!-- FIXME change it to the project's website --><url>http://www.example.com</url><build><plugins><!-- 设置项目的编译版本为本地jdk的版本 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><!-- 配置编译的默认编码类型为utf-8 --><configuration><target>1.8</target><source>1.8</source><encoding>utf-8</encoding></configuration></plugin><!-- 启动maven的内置tomcat7服务器 --><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.2</version></plugin><!-- Maven打包组件 --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build><!-- 导入SpringBoot的父工程 --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.7.RELEASE</version></parent><dependencies><!-- 导入web组件启动器,版本随父工程 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><!-- 移除嵌入式tomcat插件 --><!-- <exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>Spring-boot-start-tomcat</artifactId></exclusion></exclusions> --></dependency><!-- 导入SpringBoot整合mybatis的组件启动器 --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.0</version></dependency><!-- 导入SpringBoot整合Redis的驱动器类型,版本随父工程 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><version>1.5.22.RELEASE</version></dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.9.3</version></dependency><!-- 导入SpringBoot中的test组件启动器,版本随父工程 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><!-- 导入mysql驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.20</version></dependency><!-- 导入servlet-api依赖 --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope></dependency><!-- 导入jsp-api依赖 --><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2</version><scope>provided</scope></dependency><!-- 对jsp的支持的依赖 --><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId><scope>provided</scope></dependency><!-- 导入jstl标签库 --><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.68</version></dependency><!-- jackson,用于RESTful风格的请求url其中jackson-databind是主要,其他会作为辅助依赖自动加入--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.2</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.9.2</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.9.0</version></dependency><dependency><groupId>org.codehaus.jackson</groupId><artifactId>jackson-mapper-asl</artifactId><version>1.9.13</version></dependency><dependency><groupId>org.codehaus.jackson</groupId><artifactId>jackson-core-asl</artifactId><version>1.9.13</version></dependency><!-- 便捷封装表单数据到JavaBean的依赖 --><dependency><groupId>commons-beanutils</groupId><artifactId>commons-beanutils</artifactId><version>1.9.4</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency></dependencies>
</project>

2.3、准备配置文件

2.3.1、准备SpringBoot的核心配置文件

server:port: 8574spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false&allowMultiQueries=trueusername: rootpassword: dearestmvc:view:prefix: /suffix: .jspmybatis:config-location: classpath:mybatis/mybatis-config.xmlmapper-locations: classpath:mybatis/*/*.xmltype-aliases-package: com.wnkj.entity

2.3.2、准备Redis数据库的参数属性文件

# Redis服务器地址
redis.host=127.0.0.1
# Redis服务器连接端口
redis.port=6379
# Redis服务器连接密码(默认为空)
redis.password=dearest
redis.database=0
redis.timeout=30000
# 连接池最大连接数(使用负值表示没有限制)
redis.maxTotal=30
# 连接池中的最大空闲连接
redis.maxIdle=10
redis.minIdle=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
redis.maxWaitMillis=1500
redis.testOnBorrow=true

2.4、准备MyBatis框架的全局配置文件

在resources/mybatis目录下创建mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!-- 控制台打印sql语句 --><settings><setting name="logImpl" value="STDOUT_LOGGING"/></settings></configuration>

2.5、创建SpringBoot的引导类

package com.wnkj;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;@SpringBootApplication
@MapperScan(value = "com.wnkj.dao")
@ServletComponentScan
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);System.out.println("SSO认证中心开启");}}

2.6、创建实体类

get/set方法,toString(),构造函数自己添加。

2.6.1、创建User类

package com.wnkj.entity;import java.io.Serializable;public class User implements Serializable {private String uid;private String username;private String password;private String name;

2.6.2、创建Movie类

package com.wnkj.entity;import java.io.Serializable;public class Movie implements Serializable {private String movie_id;private String movie_name;private Double movie_price;private String movie_release_time;private String movie_shelf_time;private int movie_recommended_level;private String movie_language;
}

2.7、创建RedisConfig.java配置类

package com.wnkj.config;import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;@Configuration
@PropertySource(value = "classpath:redisConfig.properties")
public class RedisConfig {@Value(value = "${redis.host}")private String host;@Value(value = "${redis.port}")private int port;@Value(value = "${redis.password}")private String password;@Value(value = "${redis.database}")private int database;@Value(value = "${redis.maxTotal}")private int maxTotal;@Value(value = "${redis.maxIdle}")private int maxIdle;@Value(value = "${redis.minIdle}")private int minIdle;@Value(value = "${redis.maxWaitMillis}")private int maxWaitMillis;@Value(value = "${redis.timeout}")private int timeout;@Value(value = "${redis.testOnBorrow}")private boolean testOnBorrow;@Bean(name = "jedisPoolConfig")public JedisPoolConfig getJedisPoolConfig() {JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();jedisPoolConfig.setMaxTotal(maxTotal);jedisPoolConfig.setMaxIdle(maxIdle);jedisPoolConfig.setMinIdle(minIdle);jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);jedisPoolConfig.setTestOnBorrow(testOnBorrow);return jedisPoolConfig;}@Bean(name = "jedisPool")public JedisPool getJedisPool(@Qualifier(value = "jedisPoolConfig") JedisPoolConfig jedisPoolConfig) {return new JedisPool(jedisPoolConfig, host, port, timeout, password, database);}}

2.8、创建MyBatis框架的持久层映射文件

在resources/mybatis/mapper目录下创建映射文件

2.8.1、创建UserMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wnkj.dao.UserMapper"><sql id="tableName">user</sql><sql id="Field">uid,username,password,name</sql><sql id="FieldValue">#{uid},#{username},#{password},#{name}</sql><select id="findByUsername" parameterType="String" resultType="User">SELECT<include refid="Field" />FROM<include refid="tableName" />WHEREusername = #{username}</select></mapper>

2.8.2、创建MovieMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wnkj.dao.MovieMapper"><sql id="tableName">movie</sql><sql id="Field">movie_id,movie_name,movie_price,movie_release_time,movie_shelf_time,movie_recommended_level,movie_language</sql><sql id="FieldValue">#{movie_id},#{movie_name},#{movie_price},#{movie_release_time},#{movie_shelf_time},#{movie_recommended_level},#{movie_language}</sql><select id="listAll" resultType="Movie">SELECT<include refid="Field" />FROM<include refid="tableName" /></select></mapper>

2.9、创建持久层文件

2.9.1、创建用户模块持久层接口UserMapper.java

package com.wnkj.dao;import com.wnkj.entity.User;public interface UserMapper {User findByUsername(String username);
}

2.9.2、创建电影模块持久层MovieMapper.java

package com.wnkj.dao;import com.wnkj.entity.Movie;import java.util.List;public interface MovieMapper {List<Movie> listAll();
}

2.10、创建业务层文件

2.10.1、创建用户模块业务层接口:UserService.java

package com.wnkj.service;import com.wnkj.entity.User;public interface UserService {User findByUsername(String username);
}

2.10.2、创建用户模块业务层实现类:UserServiceImpl.java

package com.wnkj.service.impl;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wnkj.dao.UserMapper;
import com.wnkj.entity.User;
import com.wnkj.service.UserService;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;@Service(value = "userService")
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;@Autowiredprivate JedisPool jedisPool;@Overridepublic User findByUsername(String username) {Jedis jedis = null;User user = null;try {jedis = jedisPool.getResource();String userJsonString = jedis.get(username);// 如果查询缓存,等于空,则查询成User对象,并且不论查询结果是否为空,都保存到缓存if (userJsonString == null || "".equals(userJsonString) || userJsonString.trim().isEmpty()) {user = userMapper.findByUsername(username);jedis.set(username, JSON.toJSONString(user));} else if ("null".equals(userJsonString)) { // 当查询出空对象时会保存到数据库,由于保存的值会被序列化成字符串,因此是字符串的null值return user;} else { // 既不等于空也不等于“null”,说明是存在真实数据,解析为User对象并返回user = new User();JSONObject userJsonObject = JSON.parseObject(userJsonString);BeanUtils.populate(user, userJsonObject);}} catch (Exception e) {throw new RuntimeException(e);} finally {try {if (jedis != null) {jedis.close();}} catch (Exception e) {e.printStackTrace();}}return user;}
}

2.10.3、创建电影模块业务层接口:MovieService.java

package com.wnkj.service;import com.wnkj.entity.Movie;import java.util.List;public interface MovieService {List<Movie> listAll();
}

2.10.4、创建电影模块业务层实现类:MovieServiceImpl.java

package com.wnkj.service.impl;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.wnkj.dao.MovieMapper;
import com.wnkj.entity.Movie;
import com.wnkj.service.MovieService;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;import java.util.ArrayList;
import java.util.List;@Service(value = "movieService")
public class MovieServiceImpl implements MovieService {@Autowiredprivate MovieMapper movieMapper;@Autowiredprivate JedisPool jedisPool;@Overridepublic List<Movie> listAll() {List<Movie> movieList = null;Jedis jedis = null;try {jedis = jedisPool.getResource();String key = "MOVIE:listAll";String movieListJsonString = jedis.get(key);if (movieListJsonString == null || "".equals(movieListJsonString) || movieListJsonString.trim().isEmpty()) {movieList = movieMapper.listAll();System.out.println(JSON.toJSONString(movieList));jedis.set(key, JSON.toJSONString(movieList));} else if ("null".equals(movieListJsonString)) {return null;} else {movieList = new ArrayList<Movie>();JSONArray movieListJsonArray = JSON.parseArray(movieListJsonString);for (int i = 0; i < movieListJsonArray.size(); i++) {JSONObject movieJsonObject = (JSONObject) movieListJsonArray.get(i);Movie movie = new Movie();BeanUtils.populate(movie, movieJsonObject);movieList.add(movie);}}} catch (Exception e) {throw new RuntimeException(e);} finally {try {if (jedis != null) {jedis.close();}} catch (Exception e) {e.printStackTrace();}}return movieList;}
}

2.11、创建控制器文件

2.11.1、创建用户模块控制器:UserController.java

package com.wnkj.web.controller;import com.alibaba.fastjson.JSON;
import com.wnkj.entity.User;
import com.wnkj.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;@RestController
@RequestMapping(value = "/user")
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate JedisPool jedisPool;@PostMapping(value = "/login")public ModelAndView login(User user, HttpServletRequest request, HttpServletResponse response) throws Exception {ModelAndView mv = new ModelAndView();// 校验用户名非空String username = user.getUsername();if (username == null || "".equals(username) || username.trim().isEmpty()) {mv.setViewName("login");mv.addObject("user", user);mv.addObject("username_errormsg", "用户名不能为空");return mv;}// 校验密码非空String password = user.getPassword();if (password == null || "".equals(password) || password.trim().isEmpty()) {mv.setViewName("login");mv.addObject("user", user);mv.addObject("password_errormsg", "密码不能为空");return mv;}// 根据用户名查询数据库User checkUser = userService.findByUsername(username);// 校验查询结果是否为空if (checkUser == null) {mv.setViewName("login");mv.addObject("user", user);mv.addObject("user_errormsg", "用户不存在");return mv;}// 校验密码是否相等String checkPassword = checkUser.getPassword();if (! password.equals(checkPassword)) {mv.setViewName("login");mv.addObject("user", user);mv.addObject("password_errormsg", "密码错误");return mv;}// 把用户信息保存到session域中request.getSession().setAttribute("user", checkUser);// 生成tokenString token = UUID.randomUUID().toString().replace("-", "").toUpperCase();// 创建Cookie并将token保存其中Cookie cookie = new Cookie("token", token);// 设置Cookie路径cookie.setPath("/");// 保存Cookieresponse.addCookie(cookie);Jedis jedis = null;try {jedis = jedisPool.getResource();// 将token保存到redis缓存中jedis.set(token, JSON.toJSONString(checkUser));// 设置过期时间jedis.expire(token, 5 * 60);} catch (Exception e) {throw new RuntimeException(e);} finally {try {if (jedis != null) {jedis.close();}} catch (Exception e) {e.printStackTrace();}}// 获取重定向链接String path = request.getScheme() + "://" +  request.getServerName() + ":"+ request.getServerPort() + request.getContextPath() + "/";// 重定向response.sendRedirect(path.concat("movie/listAll"));return null;}
}

2.11.2、创建电影模块控制器:MovieController.java

package com.wnkj.web.controller;import com.wnkj.entity.Movie;
import com.wnkj.service.MovieService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import redis.clients.jedis.JedisPool;import javax.servlet.http.HttpServletRequest;
import java.util.List;@Controller
@RequestMapping(value = "/movie")
public class MovieController {@Autowiredprivate MovieService movieService;@GetMapping(value = "/listAll")public ModelAndView listAll (HttpServletRequest request) {List<Movie> movieList = movieService.listAll();ModelAndView mv = new ModelAndView();mv.addObject("movieList", movieList);mv.setViewName("/WEB-INF/jsp/movie/listAll");return mv;}
}

2.12、创建过滤器:LoginFilter.java

package com.wnkj.filter;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wnkj.entity.User;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;/*** 过滤器,过滤未登录用户*/
@WebFilter(urlPatterns = "/*", filterName = "loginFilter")
public class LoginFilter implements Filter {@Autowiredprivate JedisPool jedisPool;@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("LoginFilter启动");}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {// 强转类型HttpServletRequest httpServletRequest = (HttpServletRequest) request;HttpServletResponse httpServletResponse = (HttpServletResponse) response;// 得到请求的servlet路径String servletPath = httpServletRequest.getServletPath();System.out.println("servletPath = " + servletPath);// 定义path,用于重定向String path = httpServletRequest.getScheme() + "://" + httpServletRequest.getServerName() + ":" + httpServletRequest.getServerPort()+ httpServletRequest.getContextPath();// 如果包含index或loginif (servletPath.contains("index") || servletPath.contains("login")) {// 放行chain.doFilter(httpServletRequest, httpServletResponse);} else {// 否则获取CookieCookie[] cookies = httpServletRequest.getCookies();if (cookies != null) {String token = null;// 缓存遍历for (Cookie c : cookies) {// 得到每个cookie的名称String name = c.getName();// 如果cookie名称等于tokenif ("token".equals(name)) {// 获取到cookie的值token = c.getValue();}}// 判断token是否为空if (token != null && ! "".equals(token) && ! token.trim().isEmpty()) {Jedis jedis = null;String userJsonString = null;try {jedis = jedisPool.getResource();// 查询Redis缓存userJsonString = jedis.get(token);} catch (Exception e) {throw new RuntimeException(e);} finally {try {if (jedis != null) {jedis.close();}} catch (Exception e) {e.printStackTrace();}}// 判断Redis缓存中对应token的用户信息是否为空if (userJsonString != null && ! "".equals(userJsonString) && ! userJsonString.trim().isEmpty()) {// 将Json字符串的用户信息转化为JsonObject对象(可看作是Map集合)JSONObject userJsonObject = JSON.parseObject(userJsonString);User user = new User();try {// 利用apache提供的BeanUtils组件封装Map中的属性到User实例中BeanUtils.populate(user, userJsonObject);} catch (Exception e) {throw new RuntimeException(e);}// 得到SessionHttpSession session = httpServletRequest.getSession();// 保存用户信息到session域中session.setAttribute("user", user);// 放行chain.doFilter(httpServletRequest, httpServletResponse);} else {  // 如果Redis缓存中查询得到的用户信息为空,则要求重新登录获取用户信息httpServletResponse.sendRedirect(path.concat("/login.jsp"));}} else { // 如果Redis缓存中没有该token,说明登录状态失效httpServletResponse.sendRedirect(path.concat("/login.jsp"));}} else { // 不包含Cookie,则跳转到login.jsp要求完成登录httpServletResponse.sendRedirect(path.concat("/login.jsp"));}}}@Overridepublic void destroy() {System.out.println("LoginFilter停止");}
}

2.13、准备前端页面

2.13.1、修改index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<jsp:forward page="login.jsp" />

2.13.2、准备login.jsp

在webapps目录下创建login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%String path = request.getContextPath();String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE html>
<html>
<head><base href="<%=basePath%>"><meta charset="UTF-8"><title>Title</title>
</head>
<body><form action="<%=basePath%>user/login" method="post">username:<input type="text" name="username" id="username" value="${requestScope.user.username}" /><label>${requestScope.username_errormsg}</label><br/>password:<input type="password" name="password" id="password" value="${requestScope.user.password}" /><label>${requestScope.password_errormsg}</label><br/><input type="submit" value="login" /><label>${requestScope.user_errormsg}</label></form>
</body>
</html>

2.13.3、创建listAll.jsp

在webapps/WEB-INF/jsp/movie/listAll目录下创建listAll.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%String path = request.getContextPath();String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE html>
<html>
<head><base href="<%=basePath%>"><meta charset="UTF-8"><title>Title</title><style type="text/css">table, td {border:1px solid purple;}td {padding: 5px 10px;}table {text-align: center;border-collapse: collapse;}</style>
</head>
<body><h1>欢迎您,${sessionScope.user.name}</h1><table><tr><td>电影编号</td><td>电影名称</td><td>价格</td><td>电影上映时间</td><td>电影下架时间</td><td>推荐等级</td><td>电影语种</td></tr><c:forEach var="movie" items="${requestScope.movieList}"><tr><td>${pageScope.movie.movie_id}</td><td>${pageScope.movie.movie_name}</td><td><fmt:formatNumber pattern="0.00" value="${pageScope.movie.movie_price}" /></td><td>${pageScope.movie.movie_release_time}</td><td>${pageScope.movie.movie_shelf_time}</td><td>${pageScope.movie.movie_recommended_level}</td><td>${pageScope.movie.movie_language}</td></tr></c:forEach></table>
</body>
</html>

3、结果测试

3.1、Redis客户端查看Redis缓存

3.2、启动项目,测试


浏览器输入地址:http://localhost:8574/movie/listAll
查看控制台可知,servletPath不包含index/login,所以跳转到login.jsp要求完成登录

会跳转到如下页面:

输入用户名和密码登录之后,就可以查看到电影信息了

3.3、查看Redis缓存

有三个缓存:

随机字符串其实是token的值,用token做key,用户信息做value保存到缓存中:

lmf是我登录所使用的帐号,即当前登录的用户:

MOVIE:listAll是查询出来的电影数据:

未登录前,访问http://localhost:8574/movie/listAll是会被过滤掉请求的,登录后就可以直接访问这个链接了。
注意:由于代码中保存到redis缓存的token有效期为5分钟,5分钟后token会被删除,届时便无法直接查询电影数据,需要重新登录。

如下:

又需要登录才可以查询了:

SpringBoot结合Redis实现维护客户端登录状态相关推荐

  1. SpringBoot+MyBatis+Redis实现SSO单点登录系统(一)

    SpringBoot+MyBatis+Redis实现SSO单点登录系统(一) 一.SSO系统概述 SSO英文全称Single Sign On,单点登录.SSO是在多个应用系统中,用户只需要登录一次就可 ...

  2. SpringBoot+MyBatis+Redis实现SSO单点登录系统(二)

    SpringBoot+MyBatis+Redis实现SSO单点登录系统(二) 三.代码 配置文件配置数据库,redis等相关的信息. # See http://docs.spring.io/sprin ...

  3. java redis密码_Redis 设置密码登录

    前言 redis在生产环境中通常都会设置密码以保证一定的安全性,本篇文章就简单记录一下如何在redis中设置客户端登录密码. 修改redis.conf RT,打开redis.conf文件,搜索requ ...

  4. springboot+shiro+redis+jwt实现多端登录:PC端和移动端同时在线(不同终端可同时在线)

    前言 之前写了篇 springboot+shiro+redis多端登录:单点登录+移动端和PC端同时在线 的文章,但是token用的不是 jwt 而是 sessionID,虽然已经实现了区分pc端和移 ...

  5. java开发微信如何维护登录状态_微信小程序中做用户登录与登录态维护的实现详解...

    总结 大家都知道,在开发中提供用户登录以及维护用户的登录状态,是一个拥有用户系统的软件应用普遍需要做的事情.像微信这样的一个社交平台,如果做一个小程序应用,我们可能很少会去做一个完全脱离和舍弃连接用户 ...

  6. Springboot自定义注解实现用户登录状态校验(一)

    Springboot自定义注解实现用户登录状态校验(一) 拦截器方式 定义注解类 import java.lang.annotation.*;/*** @author:小飞猪* @date:2020/ ...

  7. SpringSecurity整合springBoot、redis——实现登录互踢

    背景 基于我的文章--<SpringSecurity整合springBoot.redis token动态url权限校验>.要实现的功能是要实现一个用户不可以同时在两台设备上登录,有两种思路 ...

  8. 微信小程序登录状态维护-java后台

    先上一张小程序官方的登录时序图(https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html) ...

  9. 十分钟写一个基于springboot+vue+redis+mysql的银行转账与用户后台管理系统,redis实现用户登录与缓存

    界面效果 用户管理界面 详情页面 编辑页面 删除功能 用户界面 查询余额 取出余额 存款 转账 后端包结构 bean包下代码 管理员类 package com.example.qqqundatabas ...

最新文章

  1. 区块链赚钱的9种方式
  2. 9.匿名函数:lambda表达式/filter()/map()
  3. AI和深度学习正在席卷医疗保健行业
  4. win7 能下node什么版本_微软从未公开的win10版本,3GB+极度精简,老爷机有救了
  5. java线程死锁_Java线程死锁实例及解决方法
  6. c++实现飞机大战小游戏
  7. c语言汉诺塔问题详解
  8. 行式 Excel 文件比对
  9. C盘深度清理(超快简单全面)
  10. 3*4的方格,有多少个长方形?
  11. Python 抓取淘宝联盟优惠券
  12. python列表两两相减_【数据分析入门】之:如何用Python代替Excel(1)
  13. 三人表决器与八人抢答器实验
  14. 云南省自然保护区分布及功能区划
  15. C++无名命名空间中定义的函数不使用造成“-Wunused-function”警告问题
  16. Java自学资料!靠着这份面试题跟答案
  17. 商品交易之---撮合系统架构探讨
  18. spring boot 使用redis作为cache 出现:A cannot be cast to A.使用fastJson序列化
  19. 数学建模—voronoi图
  20. 屏幕截图 take screenshot

热门文章

  1. 数据库模型设计——历史表与版本号设计
  2. c语言学生学籍管理修改,C语言课设之学生学籍管理系统.doc
  3. 每周分享第 47 期
  4. Android高级工程师面试实战,我的Android美团求职之路,3面直接拿到offer
  5. 感恩节,感谢大家的一路相伴
  6. linux 下动手实现bash -lR 命令
  7. 组件、插件、控件的区别
  8. 最新 2022 年云原生Kubernetes 高级面试题大全(持续更新中)
  9. 云原生kubernetes六:namespace和Resourcequota
  10. X86_64 GNU汇编、寄存器、内嵌汇编