pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--freemarker-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.10.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.61</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!--redis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!--自定义注解-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<dependencies>
<!-- spring热部署 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.6.RELEASE</version>
</dependency>
</dependencies>
<configuration><fork>true</fork></configuration>
</plugin>
</plugins>
</build>
application.properties
server.port=1234
server.servlet.context-path=/redis_freemarker
# 开启热部署
spring.devtools.restart.enabled=true
spring.mvc.view.suffix=.ftl
spring.mvc.static-path-pattern: /**
# freemarker静态资源配置
# 设定ftl文件路径
spring.freemarker.tempalte-loader-path=classpath:/templates
# 关闭缓存,及时刷新,上线生产环境需要修改为true
spring.freemarker.cache=false
spring.freemarker.charset=UTF-8
spring.freemarker.check-template-location=true
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=true
spring.freemarker.expose-session-attributes=true
spring.freemarker.request-context-attribute=request
spring.freemarker.suffix=.ftl
# 空值不报错
spring.freemarker.settings.classic_compatible=true
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.timeout=3
spring.redis.password=123456
spring.redis.jedis.pool.max-wait=3
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.max-total=10
redis 注册类
RedisConfig
package com.example.redis_freemarker;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
@Component
@PropertySource(value = {"classpath:application.properties"})
public class RedisConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.timeout}")
private int timeout;//秒
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.jedis.pool.max-total}")
private int poolMaxTotal;
@Value("${spring.redis.jedis.pool.max-idle}")
private int poolMaxIdle;
@Value("${spring.redis.jedis.pool.max-wait}")
private int poolMaxWait;//秒
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getPoolMaxTotal() {
return poolMaxTotal;
}
public void setPoolMaxTotal(int poolMaxTotal) {
this.poolMaxTotal = poolMaxTotal;
}
public int getPoolMaxIdle() {
return poolMaxIdle;
}
public void setPoolMaxIdle(int poolMaxIdle) {
this.poolMaxIdle = poolMaxIdle;
}
public int getPoolMaxWait() {
return poolMaxWait;
}
public void setPoolMaxWait(int poolMaxWait) {
this.poolMaxWait = poolMaxWait;
}
@Bean
public JedisPool jedisPoolFactory() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(poolMaxIdle);
jedisPoolConfig.setMaxTotal(poolMaxTotal);
jedisPoolConfig.setMaxWaitMillis(poolMaxWait * 1000);
JedisPool jedisPool = new JedisPool(jedisPoolConfig,
host,
port,
timeout * 1000,
password);
return jedisPool;
}
}
redis 工具类
RedisService
package com.example.redis_freemarker;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
@Service
public class RedisService {
@Autowired
private JedisPool jedisPool;
/**
* 获取存储对象
* @param key
* @param clazz
* @param <T>
* @return
*/
public <T> T get(String key, Class<T> clazz) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
String str = jedis.get(key);
T t = stringToBean(str, clazz);
return t;
} finally {
returnToPool(jedis);
}
}
/**
* 设置对象
* @param key
* @param expireSeconds
* @param value
* @param <T>
* @return
*/
public <T> boolean set(String key, int expireSeconds, T value) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
String str = beanToString(value);
if (null == str) {
return false;
}
if (expireSeconds <= 0) {
jedis.set(key, str);
} else {
jedis.setex(key, expireSeconds, str);
}
return true;
} finally {
returnToPool(jedis);
}
}
/**
* 判断key是否存在
* */
public <T> boolean exists(String key) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
return jedis.exists(key);
}finally {
returnToPool(jedis);
}
}
/**
* 增加值
* */
public <T> Long incr(String key) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
return jedis.incr(key);
}finally {
returnToPool(jedis);
}
}
/**
* 减少值
* */
public <T> Long decr(String key) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
return jedis.decr(key);
}finally {
returnToPool(jedis);
}
}
private <T> String beanToString(T value) {
if (null == value) {
return null;
}
if (value instanceof Integer || value instanceof Long) {
return "" + value;
} else if (value instanceof String) {
return (String) value;
} else {
return JSON.toJSONString(value);
}
}
private <T> T stringToBean(String str, Class<T> clazz) {
if (StringUtils.isEmpty(str) || clazz==null) {
return null;
}
if (clazz==int.class || clazz==Integer.class) {
return (T) Integer.valueOf(str);
} else if (clazz == String.class) {
return (T) str;
} else if (clazz==long.class || clazz==Long.class) {
return (T)Long.valueOf(str);
} else {
return JSON.toJavaObject(JSON.parseObject(str), clazz);
}
}
private void returnToPool(Jedis jedis) {
if (null != jedis) {
jedis.close();
}
}
}
freemaker 工具类
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Map;
public class FreemarkerUtils {
public static String getTemplate(String template, Map<String,Object> map) throws IOException, TemplateException {
Configuration cfg = new Configuration(Configuration.VERSION_2_3_28);
String templatePath = FreemarkerUtils.class.getResource("/").getPath()+"/templates";
cfg.setDirectoryForTemplateLoading(new File(templatePath));
cfg.setDefaultEncoding("UTF-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
cfg.setLogTemplateExceptions(false);
cfg.setWrapUncheckedExceptions(true);
cfg.setClassicCompatible(true);// 空值不报错
Template temp = cfg.getTemplate(template);
StringWriter stringWriter = new StringWriter();
temp.process(map, stringWriter);
return stringWriter.toString();
}
}
新建一个自定义注解 AutoRedis
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface AutoRedis {
String key(); // redis key 值
String returnFtl(); // 返回的ftl页面路径
int expireSeconds() default 86400; // 缓存过期时间,默认24小时
boolean soutIfTrue() default true; // 是否打印信息
}
新建一个 AOP
RedisAspect
package com.example.redis_freemarker;
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import java.lang.reflect.Method;
import java.util.Map;
@Aspect
@Configuration
public class RedisAspect {
@Autowired
private RedisService redisService;
//定义切点方法
@Pointcut("@annotation(com.example.redis_freemarker.AutoRedis)")
public void pointCut(){}
//环绕通知
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable,Exception {
//1.获取到所有的参数值的数组
Object[] args = joinPoint.getArgs();
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
//2.获取到方法的所有参数名称的字符串数组
String[] parameterNames = methodSignature.getParameterNames();
Method method = methodSignature.getMethod();
Class<?> returnType = method.getReturnType(); // 返回类型
Class<?> classTarget = joinPoint.getTarget().getClass();
AutoRedis redis=(AutoRedis)method.getAnnotation(AutoRedis.class);
boolean soutIfTrue=redis.soutIfTrue();
soutIfTrue(soutIfTrue,"■■■■■■■■■■■■■■■■■■■■■-AutoRedis注解开始-■■■■■■■■■■■■■■■■■■■■■");
String key=redis.key();
String returnFtl=redis.returnFtl();
int expireSeconds=redis.expireSeconds();
soutIfTrue(soutIfTrue,"自定义注解 key:" + key);
soutIfTrue(soutIfTrue,"自定义注解 returnFtl:" + returnFtl);
soutIfTrue(soutIfTrue,"自定义注解 expireSeconds:" + expireSeconds);
soutIfTrue(soutIfTrue,"---------------参数列表开始-------------------------");
for (int i =0 ,len=parameterNames.length;i < len ;i++){
soutIfTrue(soutIfTrue,"参数名:"+ parameterNames[i] + " = " +args[i]);
key=redis.key().replaceAll("【"+parameterNames[i]+"】",args[i].toString());
}
soutIfTrue(soutIfTrue,"---------------参数列表结束-------------------------");
soutIfTrue(soutIfTrue,"自定义注解解析后 key:" + key);
// String html = redisService.get(key, String.class);
Map<String,Object> map = redisService.get(key, Map.class);
/*
1.这里有两种方式存储,可以存储整个HTML代码放进redis,这种数据库压力较大
2.也可以把 Object result 放进redis,这样redis库不会浪费空间,然后读缓存的时候用freemarker 转换一下,这种服务器压力较大。
*/
// 1.
/*
if (!StringUtils.isEmpty(html)) {
soutIfTrue(soutIfTrue,"有缓存,返回缓存数据");
soutIfTrue(soutIfTrue,"■■■■■■■■■■■■■■■■■■■■■-AutoRedis注解结束-■■■■■■■■■■■■■■■■■■■■■\n\n\n");
return html;
}else{
Object result=joinPoint.proceed(args);
String cmtTpl= null;
cmtTpl = FreemarkerUtils.getTemplate(returnFtl, (Map<String,Object>)JSON.parseObject(result.toString()));
// 存入缓存
if(!StringUtils.isEmpty(cmtTpl)){
soutIfTrue(soutIfTrue,"没有缓存,返回刚查询的数据,并且存入redis");
redisService.set(key, expireSeconds, cmtTpl);
}
soutIfTrue(soutIfTrue,"■■■■■■■■■■■■■■■■■■■■■-AutoRedis注解结束-■■■■■■■■■■■■■■■■■■■■■\n\n\n");
return cmtTpl;
}
*/
// 2.
if (map!=null) {
soutIfTrue(soutIfTrue,"有缓存,返回缓存数据");
String cmtTpl= null;
cmtTpl = FreemarkerUtils.getTemplate(returnFtl,map);
soutIfTrue(soutIfTrue,"■■■■■■■■■■■■■■■■■■■■■-AutoRedis注解结束-■■■■■■■■■■■■■■■■■■■■■\n\n\n");
return cmtTpl;
}else{
Object result=joinPoint.proceed(args);
String cmtTpl= null;
cmtTpl = FreemarkerUtils.getTemplate(returnFtl, (Map<String,Object>)JSON.parseObject(result.toString()));
// 存入缓存
if(!StringUtils.isEmpty(cmtTpl)){
soutIfTrue(soutIfTrue,"没有缓存,返回刚查询的数据,并且存入redis");
redisService.set(key, expireSeconds, (Map)JSON.parseObject(result.toString()));
}
soutIfTrue(soutIfTrue,"■■■■■■■■■■■■■■■■■■■■■-AutoRedis注解结束-■■■■■■■■■■■■■■■■■■■■■\n\n\n");
return cmtTpl;
}
}
public void soutIfTrue(Boolean flag,String str){
if(flag){
System.out.println(str);
}
}
}
最后来实验一下
package com.example.redis_freemarker;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;
@Controller
public class test {
@Autowired
private RedisService redisService;
@RequestMapping(value = "/test")
@ResponseBody
public String test(String page) {
if(StringUtils.isEmpty(page)){
return "page参数不能为空";
}
//判断redis是否有缓存
String html = redisService.get(page, String.class);
if (!StringUtils.isEmpty(html)) {
System.out.println("有缓存,返回缓存数据");
//System.out.println(html);
return html;
}
// 这里模拟一下查询数据,浪费时间3秒
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Map<String,Object> map=new HashMap<>();
map.put("NAME","吴彦祖");
map.put("ID","14567");
map.put("AGE","18");
map.put("PAGE",page);
String cmtTpl= null;
try {
cmtTpl = FreemarkerUtils.getTemplate("/test/test.ftl",map);
} catch (Exception e) {
e.printStackTrace();
}
// 存入缓存
if(!StringUtils.isEmpty(cmtTpl)){
System.out.println("没有缓存,返回刚查询的数据,并且存入redis");
redisService.set(page, 86400, cmtTpl);
}
return cmtTpl;
}
@RequestMapping("/test2")
@ResponseBody
@AutoRedis(key = "HELLO_【page】",returnFtl = "/test/test.ftl",expireSeconds = 86400,soutIfTrue = true)
public String test2(String page){
if(StringUtils.isEmpty(page)){
return "page参数不能为空";
}
// 这里模拟一下查询数据,浪费时间3秒
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Map<String,Object> map=new HashMap<>();
map.put("NAME","吴彦祖");
map.put("ID","14567");
map.put("AGE","18");
map.put("PAGE",page);
return JSON.toJSONString(map);
}
}
test.ftl
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
</head>
<body>
<table border="1">
<thead>
<tr>
<th>PAGE</th>
<th>NAME</th>
<th>ID</th>
<th>AGE</th>
</tr>
</thead>
<tbody>
<tr>
<td>${PAGE}</td>
<td>${NAME}</td>
<td>${ID}</td>
<td>${AGE}</td>
</tr>
</tbody>
</table>
</body>
</html>
版权声明:本文为qq_40341527原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。