Spring4.X + Spring MVC + Mybatis3 零配置应用开发框架搭建详解(5) - Redis缓存配置

Spring4.X + Spring MVC + Mybatis3 零配置应用开发框架搭建详解(5) - Redis缓存配置

对于缓存管理,其实就是四个步骤

  • 第一,在【cache】组件中的pom.xml中加入redis的第三方java客户端jedis的jar包
  • 第二,通过编写一个缓存配置类,来管理连接池
  • 第三,编写缓存服务,提供缓存操作接口
  • 第四,在需要使用缓存服务的【back】服务中,加入项目依赖,其他任何服务需要使用缓存服务,都可以配置类似的依赖
  • 第五,在【back】服务启动配置中加入缓存配置类,以保障缓存服务能再服务启动的时候初始化
  • 第六,在需要使用缓存服务的模块中,编写业务代码,完成缓存操作。

1. 加入缓存jar包依赖配置

<?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">
    <parent>
        <artifactId>web</artifactId>
        <groupId>com.aitongyi.web</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cache</artifactId>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- CacheService缓存服务中需要用到的对象依赖    -->
        <dependency>
            <groupId>com.aitongyi.web</groupId>
            <artifactId>bean</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!-- Redis依赖    -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.7.2</version>
        </dependency>
    </dependencies>
</project>


2. 创建配置对象

  

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;


import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = {"com.aitongyi.web.cache"})
public class CacheConfig {
    /** redis缓存服务器地址    */
    @Value("${redis.host}")
    private String host;
    /** redis缓存服务器端口    */
    @Value("${redis.port}")
    private Integer port;
    /** redis缓存服务器连接超时时间    */
    @Value("${redis.timeout}")
    private Integer timeout;

    @Bean(name = "jedisPool")
    public JedisPool jedispool() {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxWaitMillis(30000); //  最大等待时间
        config.setMaxTotal(32);         //  最大连接数
        config.setMinIdle(6);           //  允许最小的空闲连接数
        config.setTestOnBorrow(false);  //  申请到连接时是否效验连接是否有效,对性能有影响,建议关闭
        config.setTestOnReturn(false);  //  使用完连接放回连接池时是否效验连接是否有效,对性能有影响,建议关闭
        config.setTestWhileIdle(true);  //  申请到连接时,如果空闲时间大于TimeBetweenEvictionRunsMillis时间,效验连接是否有效,建议开启,对性能有效不大
        config.setTimeBetweenEvictionRunsMillis(30000); //TestWhileIdle的判断依据
        return new JedisPool(config, host, port, timeout);
    }
}


3. 创建缓存服务

/**
 * 缓存服务
 * Created by admin on 16/8/18.
 */
@Component
public class CacheService {
    @Autowired
    private JedisPool jedisPool;

    /**
     * 设置缓存对象
     * @param key
     * @param value
     */
    public void set(String key,String value){
        Jedis jedis = null;
        try{
            jedis = jedisPool.getResource();
            jedis.set(key, value);
        }finally{
            if(jedis != null){
                jedis.close();
            }
        }
    }

    /**
     * 获取缓存对象
     * @param key
     * @return
     */
    public String get(String key){
        Jedis jedis = null;
        try{
            jedis = jedisPool.getResource();
            return jedis.get(key);
        }finally{
            if(jedis != null){
                jedis.close();
            }
        }
    }

    /**
     * 删除缓存对象
     * @param key
     */
    public void del(String key){
        Jedis jedis = null;
        try{
            jedis = jedisPool.getResource();
            jedis.del(key);
        }finally{
            if(jedis != null){
                jedis.close();
            }
        }
    }

}

4. 对缓存服务的依赖管理

在【back】服务中的pom.xml中加入【cache】模块的依赖

<dependencies>
        <dependency>
            <groupId>com.aitongyi.web</groupId>
            <artifactId>dao</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>com.aitongyi.web</groupId>
            <artifactId>bean</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>com.aitongyi.web</groupId>
            <artifactId>service</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>com.aitongyi.web</groupId>
            <artifactId>task</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--  缓存模块  -->
        <dependency>
            <groupId>com.aitongyi.web</groupId>
            <artifactId>cache</artifactId>
            <version>${project.version}</version>
        </dependency>

5. 缓存配置加入项目启动配置中

在【back】项目中的com.aitongyi.web.back.conf.WebApplicationInitializer类中加入缓存项目的配置类【CacheConfig.class】

import com.aitongyi.web.cache.conf.CacheConfig;
import com.aitongyi.web.dao.conf.DatabaseConfig;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import javax.servlet.Filter;

/**
 * 项目启动基类
 * -- 整个项目的入口
 */
public class WebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
	/**
	 * 获取配置信息
	 * @return
	 */
	@Override
	protected Class<?>[] getRootConfigClasses() {
		return new Class[] { BackConfig.class, DatabaseConfig.class, SecurityConfig.class, CacheConfig.class};
	}
	@Override
	protected Class<?>[] getServletConfigClasses() {
		return new Class[] { MvcConfig.class };
	}

	@Override
	protected String[] getServletMappings() {
		return new String[] { "/" };
	}

	@Override
	protected Filter[] getServletFilters() {
		return null;
	}
}


6. 缓存业务操作代码

在操作业务代码时,需要一些工具类,比如json操作的fastjson,需要在pom.xml中加入依赖,

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.6</version>
        </dependency>

然后在用户控制器中加入处理逻辑

import com.aitongyi.web.bean.User;
import com.aitongyi.web.cache.CacheService;
import com.aitongyi.web.service.UserService;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * 用户请求处理器
 * Created by admin on 16/8/6.
 */
@Controller
public class UserController {
    private static final Logger logger = LoggerFactory.getLogger(UserController.class);

    @Autowired
    private UserService userService;

    @Autowired
    private CacheService cacheService;

    @RequestMapping(value = "/home", method = RequestMethod.GET)
    @PreAuthorize("isAuthenticated()")// isAuthenticated 如果用户不是匿名用户就返回true
    public String showHomePage() {
        try {
            
            User user = userService.loadUserByUsername("admin");

//            测试缓存服务
//            缓存用户对象到redis,以用户ID区分
            cacheService.set("LOGIN_USER_" + user.getId(), JSON.toJSONString(user));
//            从缓存中取出
            String userStr = cacheService.get("LOGIN_USER_" + user.getId());
//            进行反序列化
            User u = JSON.parseObject(userStr, User.class);
            if(u != null){
                logger.info("user:{}", u);
            }
            logger.info("load user ");
        }catch (Exception e){
            logger.error(e.getLocalizedMessage(), e);
        }

        return "/index/index";
    }
}

当然,直接打印user会出现 @45sd3sdf这样的情况,需要重写User的toString方法

import java.util.Date;

/**
 * Created by admin on 16/8/8.
 */
public class User {
    private Integer id;
    private String username;
    private String password;
    private boolean enabled;
    private Date createDate;

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("User{");
        sb.append("id=").append(id);
        sb.append(", username='").append(username).append('\'');
        sb.append(", password='").append(password).append('\'');
        sb.append(", enabled=").append(enabled);
        sb.append(", createDate=").append(createDate);
        sb.append('}');
        return sb.toString();
    }
}

7. 加入数据库配置

在【back】项目的back.properties中,增加redis和mysql的连接配置

#redis
redis.host = 127.0.0.1
redis.port = 6380
redis.timeout = 2000

#========= Mysql ============
jdbc.driver = com.mysql.jdbc.Driver
db.url = jdbc:mysql://127.0.0.1/web?useUnicode=true&characterEncoding=UTF-8
db.username = web
db.password = 123456
db.maxtotal = 150
db.minidle = 40
db.maxidle = 60
这两个配置意味着你需要在本机安装一个redis服务器(默认端口6379),端口是6380,本机安装一个mysql,并创建一个名称为web的库,使用utf-8这个字符集,并且创建一个web的用户,密码是123456,另外需要在数据库中创建两张表,一个是【users】表,用来存储用户信息,另外一个是【authorities】表,用来存储权限信息

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;


# Dump of table authorities
# ------------------------------------------------------------

DROP TABLE IF EXISTS `authorities`;

CREATE TABLE `authorities` (
  `username` varchar(50) NOT NULL,
  `authority` varchar(50) NOT NULL,
  UNIQUE KEY `ix_auth_username` (`username`,`authority`),
  CONSTRAINT `fk_authorities_users` FOREIGN KEY (`username`) REFERENCES `users` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

LOCK TABLES `authorities` WRITE;
/*!40000 ALTER TABLE `authorities` DISABLE KEYS */;

INSERT INTO `authorities` (`username`, `authority`)
VALUES
	('admin','ROLE_ADMIN');

/*!40000 ALTER TABLE `authorities` ENABLE KEYS */;
UNLOCK TABLES;


# Dump of table users
# ------------------------------------------------------------

DROP TABLE IF EXISTS `users`;

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL,
  `password` varchar(50) NOT NULL,
  `enabled` tinyint(1) NOT NULL,
  `create_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ix_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

LOCK TABLES `users` WRITE;
/*!40000 ALTER TABLE `users` DISABLE KEYS */;

INSERT INTO `users` (`id`, `username`, `password`, `enabled`, `create_date`)
VALUES
	(1,'admin','e10adc3949ba59abbe56e057f20f883e',1,'2016-08-18 14:51:06');

/*!40000 ALTER TABLE `users` ENABLE KEYS */;
UNLOCK TABLES;

表创建完成,数据写入完成,启动服务器,运行back这个web项目,就可以看到登录页面,输入用户名admin,密码123456,登录,完成我们的操作。

然后看看日志,就可以看到存储缓存和打印缓存数据的日志了。如果你有兴趣,还可以在代码上打上断点,用debug模式启动,然后一步步的看运行状态!



8. 缓存KEY管理最佳实践

到此,缓存就说完了,这里要提一下这个redis的key,很多时候我们开发,定义redis中的缓存key很随意,也不规范,结果导致最终key管理混乱,代码管理难度加大。通过我们的项目,可以看到,每个功能基本是分模块的,在缓存中,需要定义一个公共的KEY管理类,所有的key都通过这个公共类来声明,如果要看缓存中定义了那些Key,就可以从这个类中一目了然。

下面我们就用【UserController】中的一个缓存KEY来做例子说明一下:

原来的key是这样的:

//            缓存用户对象到redis,以用户ID区分
            cacheService.set("LOGIN_USER_" + user.getId(), JSON.toJSONString(user));
//            从缓存中取出
            String userStr = cacheService.get("LOGIN_USER_" + user.getId());


通过统一管理,我们要再【cache】模块下创建一个CacheKey:

/**
 * 缓存Key统一管理类
 * Created by admin on 16/8/18.
 */
public class CacheKey {

    /**
     * <pre>
     * 登录用户缓存Key
     * 格式 :  str.login.user.{userId}
     * </pre>
     */
    public static final String LOGIN_USER_KEY = "str.login.user.";
}

然后将原来的代码改为:

//            缓存用户对象到redis,以用户ID区分
            cacheService.set(CacheKey.LOGIN_USER_KEY + user.getId(), JSON.toJSONString(user));
//            从缓存中取出
            String userStr = cacheService.get(CacheKey.LOGIN_USER_KEY + user.getId());

通过这样的管理,所有用户都统一的缓存Key的使用,如果要查看redis中用了那些缓存key,缓存中的key代表什么意思,就一目了然了。


目录

        (一)基本介绍    
        (二)基础框架搭建
        (三)实现最基本的登录处理        
        (四)任务调度管理   
        (五)Redis缓存配置
        (六)安全框架集成

        (七) git版本源代码下载


  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值