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: 8574
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false&allowMultiQueries=true
username: root
password: dearest
mvc:
view:
prefix: /
suffix: .jsp
mybatis:
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/*/*.xml
type-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 configuration
PUBLIC "-//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 mapper
PUBLIC "-//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" />
WHERE
username = #{username}
</select>
</mapper>
2.8.2、创建MovieMapper.xml
<?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.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 {
@Autowired
private UserMapper userMapper;
@Autowired
private JedisPool jedisPool;
@Override
public 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 {
@Autowired
private MovieMapper movieMapper;
@Autowired
private JedisPool jedisPool;
@Override
public 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 {
@Autowired
private UserService userService;
@Autowired
private 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);
// 生成token
String token = UUID.randomUUID().toString().replace("-", "").toUpperCase();
// 创建Cookie并将token保存其中
Cookie cookie = new Cookie("token", token);
// 设置Cookie路径
cookie.setPath("/");
// 保存Cookie
response.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 {
@Autowired
private 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 {
@Autowired
private JedisPool jedisPool;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("LoginFilter启动");
}
@Override
public 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或login
if (servletPath.contains("index") || servletPath.contains("login")) {
// 放行
chain.doFilter(httpServletRequest, httpServletResponse);
} else {
// 否则获取Cookie
Cookie[] cookies = httpServletRequest.getCookies();
if (cookies != null) {
String token = null;
// 缓存遍历
for (Cookie c : cookies) {
// 得到每个cookie的名称
String name = c.getName();
// 如果cookie名称等于token
if ("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);
}
// 得到Session
HttpSession 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"));
}
}
}
@Override
public 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会被删除,届时便无法直接查询电影数据,需要重新登录。
如下:
又需要登录才可以查询了: