redis通用缓存技术demo

需要回顾的技术:

redis热点缓存技术

springboot拦截器interceptor

自定义注解

解决问题,由于客户对查询的频繁操作,可以将查询的部分请求后的结果存入redis中,第二次查询是,就直接从redis中获取,减少sql的压力,从而提升性能.

配置类:

#是否开启数据缓存
tanhua.cache.enable=false

# Redis相关配置
spring.redis.jedis.pool.max-wait = 5000ms
spring.redis.jedis.pool.max-Idle = 100
spring.redis.jedis.pool.min-Idle = 10
spring.redis.timeout = 10s
spring.redis.cluster.nodes = 192.168.21.31:6379,192.168.81.85:6380,192.168.81.41:6381
spring.redis.cluster.max-redirects=5

配置类:

/**
 * 请求的拦截路径
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private RedisCacheInterceptor redisCacheInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(this.redisCacheInterceptor).addPathPatterns("/**");
    }
}

采用拦截器进行缓存命中

package com.tanhua.server.interceptor;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tanhua.common.utils.Cache;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;


/**
 * 请求拦截器
 */
@Component
public class RedisCacheInterceptor implements HandlerInterceptor {


    @Value("${tanhua.cache.enable}")
    private boolean enable;

    private static final ObjectMapper mapper = new ObjectMapper();

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //开启全局缓存
        if (!enable) {
            return true;
        }
        //controller中不是handlerMethod方法
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        //controller中的方法这不是get方法
        if (!((HandlerMethod) handler).hasMethodAnnotation(GetMapping.class)) {
            return true;
        }

        //判断是否加了自定义注解Cache

        if (!((HandlerMethod) handler).hasMethodAnnotation(Cache.class)) {
            return true;
        }

        //命中缓存
        String redisKey = createRedisKey(request);
        String CacheValue = this.redisTemplate.opsForValue().get(redisKey);
        if (StringUtils.isNotEmpty(CacheValue)) {
            //缓存未命中
            return true;
        }
        //命中.响应出去
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        response.getWriter().write(CacheValue);
        return false;

    }

    public static String createRedisKey(HttpServletRequest request) throws JsonProcessingException {
        //获取方法路径名
        String url = request.getRequestURI();
        //获取前端发过来的参数
        Map<String, String[]> parameterMap = request.getParameterMap();
        //转为json
        String params = mapper.writeValueAsString(parameterMap.getClass());
        //token
        String token = request.getHeader("Authorization");
        //拼接
        String data = url + "_" + params + "_" + token;
        //转为md5处理
        return "SERVER_CACHE_DATA_" + DigestUtils.md5Hex(data);
    }


}

响应结果写入到缓存

package com.tanhua.server.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.tanhua.common.utils.Cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.MethodParameter;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.concurrent.TimeUnit;

@ControllerAdvice  //该类是个通知类
public class MyResponseBodyAdvice implements ResponseBodyAdvice {

    @Value("tanhua.cache.enable")
    private boolean enable;

    private static final ObjectMapper MAPPER = new ObjectMapper();

    @Autowired
    private RedisTemplate<String, String> redisTemplate;


    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        //开关为true 是getMapping请求 包含Cache注解
        return enable && methodParameter.hasMethodAnnotation(GetMapping.class)
                && methodParameter.hasMethodAnnotation(Cache.class);
    }

    /**
     * 功能的增强 响应拦截器
     *
     * @param body      需要被增强的对象
     * @param methodParameter  被拦截的参数
     * @param mediaType
     * @param aClass
     * @param serverHttpRequest
     * @param serverHttpResponse
     * @return
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        //如果响应体为null
        if (body == null) {
            return null;
        }
        //响应体为String/duix
        String redisValue = null;
        try {
            //为string
            if (body instanceof String) {
                redisValue = (String) body;
            } else {
                //为对象
                redisValue = MAPPER.writeValueAsString(body);
            }
            //获取路径名+参数params+token作为key
            String redisKey = RedisCacheInterceptor.createRedisKey(((ServletServerHttpRequest) serverHttpRequest).getServletRequest());

            //存在redis中
            Cache cache = methodParameter.getMethodAnnotation(Cache.class);
            this.redisTemplate.opsForValue().set(redisKey, redisValue, Long.valueOf(cache.time()), TimeUnit.SECONDS);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return body;
    }
}

 

以上如果有问题,欢迎大家指出!!!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值