自己动手实现一个控制层出入参日志切面

导言:在Spring MVC的项目中,记录控制层的出入参数是很常见的需求,下面我将记录下这一实现过程.并实现日志存入redis.可开关接口记录日志.

  1. 利用Controller的增强注解-------@RestControllerAdvice,还可以利用该注解实现全局异常捕获.详细用法请百度.

  2. 首先实现两个接口,分别是RequestBodyAdvice和ResponseBodyAdvice.

    1. 记录入参日志:

    2. package com.hdstcloud.hdst_admin.common.aspect;
      
      import com.alibaba.fastjson.JSON;
      import com.hdstcloud.hdst_admin.common.utils.RedisUtil;
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.core.MethodParameter;
      import org.springframework.http.MediaType;
      import org.springframework.http.server.ServerHttpRequest;
      import org.springframework.http.server.ServerHttpResponse;
      import org.springframework.web.bind.annotation.RestControllerAdvice;
      import org.springframework.web.context.request.RequestContextHolder;
      import org.springframework.web.context.request.ServletRequestAttributes;
      import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
      
      import java.time.LocalDateTime;
      import java.time.format.DateTimeFormatter;
      import java.util.Arrays;
      
      /**
       * @author js
       */
      @Slf4j
      @RestControllerAdvice
      public class ResponseAopLogComponent implements ResponseBodyAdvice {
      
      	@Autowired
      	private LogAspectConfig logAspectConfig;
      
      	@Autowired
      	private RedisUtil redisUtil;
      
      	@Override
      	public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
      	                              Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
      
      		ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
      		String requestUri = requestAttributes.getRequest().getRequestURI();
      		String sessionId = requestAttributes.getRequest().getSession().getId();
      
      		//如果在忽略的接口中,不要记录返回日志
      		if (!Arrays.stream(logAspectConfig.getIgnoreUri()).anyMatch(it -> it.equals(request.getURI().getPath()))) {
      			log.debug("请求的方法路径是:{}\n返回的结果是:{}\n请求的ip是:{}\nsessionId是:{}", requestUri, JSON.toJSONString(body), request.getRemoteAddress(), sessionId);
      
      			if (logAspectConfig.getRedisOff()) {
      				//当前时间转换成固定格式,会和日志打印时间有一点点差距,可以忽略
      				String time = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS").format(LocalDateTime.now());
      				//接口路径加上时间做主键,存储对象
      				IoLog ioLog = new IoLog();
      				ioLog.setRequestUri(requestUri);
      				ioLog.setIp(requestAttributes.getRequest().getRemoteAddr());
      				ioLog.setDataTime(time);
      				ioLog.setSessionId(sessionId);
      				ioLog.setResponseBody(JSON.toJSONString(body));
      				redisUtil.set(requestUri + time, ioLog);
      			}
      		}
      		return body;
      	}
      }
      
    3. 记录返回日志:

    4. package com.hdstcloud.hdst_admin.common.aspect;
      
      import com.alibaba.fastjson.JSON;
      import com.hdstcloud.hdst_admin.common.utils.RedisUtil;
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.core.MethodParameter;
      import org.springframework.http.MediaType;
      import org.springframework.http.server.ServerHttpRequest;
      import org.springframework.http.server.ServerHttpResponse;
      import org.springframework.web.bind.annotation.RestControllerAdvice;
      import org.springframework.web.context.request.RequestContextHolder;
      import org.springframework.web.context.request.ServletRequestAttributes;
      import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
      
      import java.time.LocalDateTime;
      import java.time.format.DateTimeFormatter;
      import java.util.Arrays;
      
      /**
       * @author js
       */
      @Slf4j
      @RestControllerAdvice
      public class ResponseAopLogComponent implements ResponseBodyAdvice {
      
      	@Autowired
      	private LogAspectConfig logAspectConfig;
      
      	@Autowired
      	private RedisUtil redisUtil;
      
      	@Override
      	public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
      	                              Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
      
      		ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
      		String requestUri = requestAttributes.getRequest().getRequestURI();
      		String sessionId = requestAttributes.getRequest().getSession().getId();
      
      		//如果在忽略的接口中,不要记录返回日志
      		if (!Arrays.stream(logAspectConfig.getIgnoreUri()).anyMatch(it -> it.equals(request.getURI().getPath()))) {
      			log.debug("请求的方法路径是:{}\n返回的结果是:{}\n请求的ip是:{}\nsessionId是:{}", requestUri, JSON.toJSONString(body), request.getRemoteAddress(), sessionId);
      
      			if (logAspectConfig.getRedisOff()) {
      				//当前时间转换成固定格式,会和日志打印时间有一点点差距,可以忽略
      				String time = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS").format(LocalDateTime.now());
      				//接口路径加上时间做主键,存储对象
      				IoLog ioLog = new IoLog();
      				ioLog.setRequestUri(requestUri);
      				ioLog.setIp(requestAttributes.getRequest().getRemoteAddr());
      				ioLog.setDataTime(time);
      				ioLog.setSessionId(sessionId);
      				ioLog.setResponseBody(JSON.toJSONString(body));
      				redisUtil.set(requestUri + time, ioLog);
      			}
      		}
      		return body;
      	}
      }
      
    5. 日志参数的实体类如下:

    6. package com.hdstcloud.hdst_admin.common.aspect;
      
      import lombok.Data;
      
      /**
       * @author :js
       * @date :Created in 2021-06-08 17:02
       * @description: io日志对象
       * @version: 1.0
       */
      @Data
      public class IoLog {
      
      	/**
      	 * 请求路径
      	 */
      	private String requestUri;
      
      	private String sessionId;
      
      	/**
      	 * 请求参数
      	 */
      	private String param;
      
      	/**
      	 * ip地址
      	 */
      	private String ip;
      
      	/**
      	 * 返回的数据
      	 */
      	private String responseBody;
      
      	/**
      	 * 数据时间
      	 */
      	private String dataTime;
      }
      
    7. 读取配置文件的类,该类主要是读取 resource/config/logAspect.properties 下的参数的值,参数分为: 不要记录的接口以及是否开启redis存储:

    8. image-20210609153015903

    9. LogAspectConfig.java如下:

      package com.hdstcloud.hdst_admin.common.aspect;
      
      import lombok.Data;
      import org.springframework.boot.context.properties.ConfigurationProperties;
      import org.springframework.context.annotation.PropertySource;
      import org.springframework.stereotype.Component;
      
      /**
       * @author :js
       * @date :Created in 2021-06-09 9:09
       * @description:
       * @version:
       */
      @Data
      @ConfigurationProperties(prefix = "log", ignoreUnknownFields = false)
      @PropertySource(value = "classpath:config/logAspect.properties")
      @Component
      public class LogAspectConfig {
      
      	/**
      	 * 忽略记录的接口
      	 */
      	private String[] ignoreUri;
      
      	/**
      	 * 是否存入redis
      	 */
      	private Boolean redisOff;
      }
      
    10. logAspect.properties如下:

      #要被忽略的接口
      log.ignoreUri[0]=/admin/position/create  
      #开启redis存储
      log.redisOff=true
      
    11. 当然我们也要把springboot整合redis的配置类和工具类准备好:

      1. 第一步先导入依赖:

                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-data-redis</artifactId>
                    <version>你自己的版本</version>
                </dependency>
        
      2. redis配置

        package com.hdstcloud.hdst_admin.config;
        
        
        import org.springframework.cache.CacheManager;
        import org.springframework.cache.annotation.EnableCaching;
        import org.springframework.context.annotation.Bean;
        import org.springframework.context.annotation.Configuration;
        import org.springframework.data.redis.cache.RedisCacheConfiguration;
        import org.springframework.data.redis.cache.RedisCacheManager;
        import org.springframework.data.redis.connection.RedisConnectionFactory;
        import org.springframework.data.redis.core.RedisTemplate;
        import org.springframework.data.redis.serializer.RedisSerializationContext;
        import org.springframework.data.redis.serializer.RedisSerializer;
        import org.springframework.data.redis.serializer.StringRedisSerializer;
        
        import java.time.Duration;
        
        @Configuration
        @EnableCaching
        public class RedisConfig {
        
            @Bean
            public RedisSerializer fastJson2JsonRedisSerialize(){
                return new FastJson2JsonRedisSerialize<>(Object.class);
            }
        
            @Bean
            public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory, RedisSerializer fastJson2JsonRedisSerialize){
                RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
                redisTemplate.setConnectionFactory(redisConnectionFactory);
                //设置Key的序列化采用StringRedisSerializer
                redisTemplate.setKeySerializer(new StringRedisSerializer());
                redisTemplate.setHashKeySerializer(new StringRedisSerializer());
                //设置值的序列化采用FastJsonRedisSerializer
                redisTemplate.setValueSerializer(fastJson2JsonRedisSerialize);
                redisTemplate.setHashValueSerializer(fastJson2JsonRedisSerialize);
        
                redisTemplate.afterPropertiesSet();
                return redisTemplate;
            }
        
            @Bean
            public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
                // 生成一个默认配置,通过config对象即可对缓存进行自定义配置
                RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
                // 设置缓存的默认过期时间,也是使用Duration设置
                config = config.entryTtl(Duration.ofMinutes(5))
                        // 设置 key为string序列化
                        .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                        // 设置value为fastJson序列化
        //                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJson2JsonRedisSerialize()))
                        // 不缓存空值
                        .disableCachingNullValues();
                // 使用自定义的缓存配置初始化一个cacheManager
                return RedisCacheManager
                        .builder(redisConnectionFactory)
                        .cacheDefaults(config)
                        .transactionAware()
                        .build();
            }
        }
        
      3. fastjson序列化配置

        package com.hdstcloud.hdst_admin.config;
        
        import com.alibaba.fastjson.JSON;
        import com.alibaba.fastjson.serializer.SerializerFeature;
        import org.springframework.data.redis.serializer.RedisSerializer;
        import org.springframework.data.redis.serializer.SerializationException;
        
        import java.nio.charset.Charset;
        import java.nio.charset.StandardCharsets;
        
        /**
         * @author :js
         * @date :Created in 2020-10-29 11:15
         * @description:
         * @version: 1.0
         */
        public class FastJson2JsonRedisSerialize<T> implements RedisSerializer<T> {
        
            public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
        
            private final Class<T> clazz;
        
            static {
        //        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
                //如果遇到反序列化autoType is not support错误,请添加并修改一下包名到bean文件路径
        //        ParserConfig.getGlobalInstance().addAccept("com.example.redisdemo.domain");
            }
        
            public FastJson2JsonRedisSerialize(Class clazz){
                super();
                this.clazz = clazz;
            }
        
        
            /**
             * 序列化
             * @param t
             * @return
             * @throws SerializationException
             */
            @Override
            public byte[] serialize(T t) throws SerializationException {
                if (null == t){
                    return new byte[0];
                }
                return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
            }
        
            /**
             * 反序列化
             * @param bytes
             * @return
             * @throws SerializationException
             */
            @Override
            public T deserialize(byte[] bytes) throws SerializationException {
                if (null == bytes || bytes.length <= 0){
                    return null;
                }
                String str = new String(bytes,DEFAULT_CHARSET);
                return (T) JSON.parseObject(str,clazz);
            }
        }
        
      4. redis工具类

        package com.hdstcloud.hdst_admin.common.utils;
        
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.data.redis.core.RedisTemplate;
        import org.springframework.stereotype.Component;
        import org.springframework.util.CollectionUtils;
        
        import java.util.List;
        import java.util.Map;
        import java.util.Set;
        import java.util.concurrent.TimeUnit;
        
        @Component
        @SuppressWarnings("all")
        public final class RedisUtil {
        
        	@Autowired
        	private RedisTemplate<String, Object> redisTemplate;
        
        	/**
        	 * 指定缓存失效时间
        	 *
        	 * @param key  键
        	 * @param time 时间(秒)
        	 */
        
        	public boolean expire(String key, long time) {
        		try {
        			if (time > 0) {
        				redisTemplate.expire(key, time, TimeUnit.SECONDS);
        			}
        			return true;
        		} catch (Exception e) {
        			e.printStackTrace();
        			return false;
        		}
        	}
        
        	/**
        	 * 根据key 获取过期时间
        	 *
        	 * @param key 键 不能为null
        	 * @return 时间(秒) 返回0代表为永久有效
        	 */
        	public long getExpire(String key) {
        		return redisTemplate.getExpire(key, TimeUnit.SECONDS);
        	}
        
        
        	/**
        	 * 判断key是否存在
        	 *
        	 * @param key 键
        	 * @return true 存在 false不存在
        	 */
        	public boolean hasKey(String key) {
        		try {
        			return redisTemplate.hasKey(key);
        		} catch (Exception e) {
        			e.printStackTrace();
        			return false;
        		}
        	}
        
        
        	/**
        	 * 删除缓存
        	 *
        	 * @param key 可以传一个值 或多个
        	 */
        	@SuppressWarnings("unchecked")
        	public boolean del(String... key) {
        		if (key != null && key.length > 0) {
        			if (key.length == 1) {
        				return redisTemplate.delete(key[0]);
        			} else {
        				return key.length == redisTemplate.delete(CollectionUtils.arrayToList(key));
        			}
        		}
        		return false;
        	}
        
        	/**
        	 * 普通缓存获取
        	 *
        	 * @param key 键
        	 * @return 值
        	 */
        	public Object get(String key) {
        		return key == null ? null : redisTemplate.opsForValue().get(key);
        	}
        
        	/**
        	 * 普通缓存放入
        	 *
        	 * @param key   键
        	 * @param value 值
        	 * @return true成功 false失败
        	 */
        
        	public boolean set(String key, Object value) {
        		try {
        			redisTemplate.opsForValue().set(key, value);
        			return true;
        		} catch (Exception e) {
        			e.printStackTrace();
        			return false;
        		}
        	}
        
        
        	/**
        	 * 普通缓存放入并设置时间
        	 *
        	 * @param key   键
        	 * @param value 值
        	 * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
        	 * @return true成功 false 失败
        	 */
        
        	public boolean set(String key, Object value, long time) {
        		try {
        			if (time > 0) {
        				redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
        			} else {
        				set(key, value);
        			}
        			return true;
        		} catch (Exception e) {
        			e.printStackTrace();
        			return false;
        		}
        	}
        
        
        	/**
        	 * 递增
        	 *
        	 * @param key   键
        	 * @param delta 要增加几(大于0)
        	 */
        	public long incr(String key, long delta) {
        		if (delta < 0) {
        			throw new RuntimeException("递增因子必须大于0");
        		}
        		return redisTemplate.opsForValue().increment(key, delta);
        	}
        
        
        	/**
        	 * 递减
        	 *
        	 * @param key   键
        	 * @param delta 要减少几(小于0)
        	 */
        	public long decr(String key, long delta) {
        		if (delta < 0) {
        			throw new RuntimeException("递减因子必须大于0");
        		}
        		return redisTemplate.opsForValue().increment(key, -delta);
        	}
        
        
        	// ================================Map=================================
        
        	/**
        	 * HashGet
        	 *
        	 * @param key  键 不能为null
        	 * @param item 项 不能为null
        	 */
        	public Object hget(String key, String item) {
        		return redisTemplate.opsForHash().get(key, item);
        	}
        
        	/**
        	 * 获取hashKey对应的所有键值
        	 *
        	 * @param key 键
        	 * @return 对应的多个键值
        	 */
        	public Map<Object, Object> hmget(String key) {
        		return redisTemplate.opsForHash().entries(key);
        	}
        
        	/**
        	 * HashSet
        	 *
        	 * @param key 键
        	 * @param map 对应多个键值
        	 */
        	public boolean hmset(String key, Map<String, Object> map) {
        		try {
        			redisTemplate.opsForHash().putAll(key, map);
        			return true;
        		} catch (Exception e) {
        			e.printStackTrace();
        			return false;
        		}
        	}
        
        
        	/**
        	 * HashSet 并设置时间
        	 *
        	 * @param key  键
        	 * @param map  对应多个键值
        	 * @param time 时间(秒)
        	 * @return true成功 false失败
        	 */
        	public boolean hmset(String key, Map<String, Object> map, long time) {
        		try {
        			redisTemplate.opsForHash().putAll(key, map);
        			if (time > 0) {
        				expire(key, time);
        			}
        			return true;
        		} catch (Exception e) {
        			e.printStackTrace();
        			return false;
        		}
        	}
        
        
        	/**
        	 * 向一张hash表中放入数据,如果不存在将创建
        	 *
        	 * @param key   键
        	 * @param item  项
        	 * @param value 值
        	 * @return true 成功 false失败
        	 */
        	public boolean hset(String key, String item, Object value) {
        		try {
        			redisTemplate.opsForHash().put(key, item, value);
        			return true;
        		} catch (Exception e) {
        			e.printStackTrace();
        			return false;
        		}
        	}
        
        	/**
        	 * 向一张hash表中放入数据,如果不存在将创建
        	 *
        	 * @param key   键
        	 * @param item  项
        	 * @param value 值
        	 * @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
        	 * @return true 成功 false失败
        	 */
        	public boolean hset(String key, String item, Object value, long time) {
        		try {
        			redisTemplate.opsForHash().put(key, item, value);
        			if (time > 0) {
        				expire(key, time);
        			}
        			return true;
        		} catch (Exception e) {
        			e.printStackTrace();
        			return false;
        		}
        	}
        
        
        	/**
        	 * 删除hash表中的值
        	 *
        	 * @param key  键 不能为null
        	 * @param item 项 可以使多个 不能为null
        	 */
        	public void hdel(String key, Object... item) {
        		redisTemplate.opsForHash().delete(key, item);
        	}
        
        
        	/**
        	 * 判断hash表中是否有该项的值
        	 *
        	 * @param key  键 不能为null
        	 * @param item 项 不能为null
        	 * @return true 存在 false不存在
        	 */
        	public boolean hHasKey(String key, String item) {
        		return redisTemplate.opsForHash().hasKey(key, item);
        	}
        
        
        	/**
        	 * hash递增 如果不存在,就会创建一个 并把新增后的值返回
        	 *
        	 * @param key  键
        	 * @param item 项
        	 * @param by   要增加几(大于0)
        	 */
        	public double hincr(String key, String item, double by) {
        		return redisTemplate.opsForHash().increment(key, item, by);
        	}
        
        
        	/**
        	 * hash递减
        	 *
        	 * @param key  键
        	 * @param item 项
        	 * @param by   要减少记(小于0)
        	 */
        	public double hdecr(String key, String item, double by) {
        		return redisTemplate.opsForHash().increment(key, item, -by);
        	}
        
        
        	// ============================set=============================
        
        	/**
        	 * 根据key获取Set中的所有值
        	 *
        	 * @param key 键
        	 */
        	public Set<Object> sGet(String key) {
        		try {
        			return redisTemplate.opsForSet().members(key);
        		} catch (Exception e) {
        			e.printStackTrace();
        			return null;
        		}
        	}
        
        
        	/**
        	 * 根据value从一个set中查询,是否存在
        	 *
        	 * @param key   键
        	 * @param value 值
        	 * @return true 存在 false不存在
        	 */
        	public boolean sHasKey(String key, Object value) {
        		try {
        			return redisTemplate.opsForSet().isMember(key, value);
        		} catch (Exception e) {
        			e.printStackTrace();
        			return false;
        		}
        	}
        
        
        	/**
        	 * 将数据放入set缓存
        	 *
        	 * @param key    键
        	 * @param values 值 可以是多个
        	 * @return 成功个数
        	 */
        	public long sSet(String key, Object... values) {
        		try {
        			return redisTemplate.opsForSet().add(key, values);
        		} catch (Exception e) {
        			e.printStackTrace();
        			return 0;
        		}
        	}
        
        
        	/**
        	 * 将set数据放入缓存
        	 *
        	 * @param key    键
        	 * @param time   时间(秒)
        	 * @param values 值 可以是多个
        	 * @return 成功个数
        	 */
        	public long sSetAndTime(String key, long time, Object... values) {
        		try {
        			Long count = redisTemplate.opsForSet().add(key, values);
        			if (time > 0) {
        				expire(key, time);
        			}
        			return count;
        		} catch (Exception e) {
        			e.printStackTrace();
        			return 0;
        		}
        	}
        
        
        	/**
        	 * 获取set缓存的长度
        	 *
        	 * @param key 键
        	 */
        	public long sGetSetSize(String key) {
        		try {
        			return redisTemplate.opsForSet().size(key);
        		} catch (Exception e) {
        			e.printStackTrace();
        			return 0;
        		}
        	}
        
        
        	/**
        	 * 移除值为value的
        	 *
        	 * @param key    键
        	 * @param values 值 可以是多个
        	 * @return 移除的个数
        	 */
        
        	public long setRemove(String key, Object... values) {
        		try {
        			Long count = redisTemplate.opsForSet().remove(key, values);
        			return count;
        		} catch (Exception e) {
        			e.printStackTrace();
        			return 0;
        		}
        	}
        
        	// ===============================list=================================
        
        	/**
        	 * 获取list缓存的内容
        	 *
        	 * @param key   键
        	 * @param start 开始
        	 * @param end   结束 0 到 -1代表所有值
        	 */
        	public List<Object> lGet(String key, long start, long end) {
        		try {
        			return redisTemplate.opsForList().range(key, start, end);
        		} catch (Exception e) {
        			e.printStackTrace();
        			return null;
        		}
        	}
        
        
        	/**
        	 * 获取list缓存的长度
        	 *
        	 * @param key 键
        	 */
        	public long lGetListSize(String key) {
        		try {
        			return redisTemplate.opsForList().size(key);
        		} catch (Exception e) {
        			e.printStackTrace();
        			return 0;
        		}
        	}
        
        
        	/**
        	 * 通过索引 获取list中的值
        	 *
        	 * @param key   键
        	 * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
        	 */
        	public Object lGetIndex(String key, long index) {
        		try {
        			return redisTemplate.opsForList().index(key, index);
        		} catch (Exception e) {
        			e.printStackTrace();
        			return null;
        		}
        	}
        
        
        	/**
        	 * 将list放入缓存
        	 *
        	 * @param key   键
        	 * @param value 值
        	 */
        	public boolean lSet(String key, Object value) {
        		try {
        			redisTemplate.opsForList().rightPush(key, value);
        			return true;
        		} catch (Exception e) {
        			e.printStackTrace();
        			return false;
        		}
        	}
        
        
        	/**
        	 * 将list放入缓存
        	 *
        	 * @param key   键
        	 * @param value 值
        	 * @param time  时间(秒)
        	 */
        	public boolean lSet(String key, Object value, long time) {
        		try {
        			redisTemplate.opsForList().rightPush(key, value);
        			if (time > 0) {
        				expire(key, time);
        			}
        			return true;
        		} catch (Exception e) {
        			e.printStackTrace();
        			return false;
        		}
        
        	}
        
        
        	/**
        	 * 将list放入缓存
        	 *
        	 * @param key   键
        	 * @param value 值
        	 * @return
        	 */
        	public boolean lSet(String key, List<Object> value) {
        		try {
        			redisTemplate.opsForList().rightPushAll(key, value);
        			return true;
        		} catch (Exception e) {
        			e.printStackTrace();
        			return false;
        		}
        
        	}
        
        
        	/**
        	 * 将list放入缓存
        	 *
        	 * @param key   键
        	 * @param value 值
        	 * @param time  时间(秒)
        	 * @return
        	 */
        	public boolean lSet(String key, List<Object> value, long time) {
        		try {
        			redisTemplate.opsForList().rightPushAll(key, value);
        			if (time > 0) {
        				expire(key, time);
        			}
        			return true;
        		} catch (Exception e) {
        			e.printStackTrace();
        			return false;
        		}
        	}
        
        
        	/**
        	 * 根据索引修改list中的某条数据
        	 *
        	 * @param key   键
        	 * @param index 索引
        	 * @param value 值
        	 * @return
        	 */
        
        	public boolean lUpdateIndex(String key, long index, Object value) {
        		try {
        			redisTemplate.opsForList().set(key, index, value);
        			return true;
        		} catch (Exception e) {
        			e.printStackTrace();
        			return false;
        		}
        	}
        
        
        	/**
        	 * 移除N个值为value
        	 *
        	 * @param key   键
        	 * @param count 移除多少个
        	 * @param value 值
        	 * @return 移除的个数
        	 */
        
        	public long lRemove(String key, long count, Object value) {
        		try {
        			Long remove = redisTemplate.opsForList().remove(key, count, value);
        			return remove;
        		} catch (Exception e) {
        			e.printStackTrace();
        			return 0;
        		}
        	}
        }
        
      5. 在yml文件中配置你的redis

        spring:
          application:
            name: admin
          redis:
            host: 127.0.0.1
            port: 6379
        
    12. 当然如果你不要保存日志到redis中,可以不添加上一步的redis相关代码,代码的运行效果如下:

      ​ 1. 请求如下:

      image-20210609154813167

      1. 请求日志:

      image-20210609154829753

      1. 返回日志:image-20210609154915247

      2. redis存储的数据为:

        image-20210609155134976

        image-20210609155158605

    13. 上述的方法比较复杂,由于想把上面代码做成jar包,给其他人使用时,使用者可以自己编写 logAspect.properties 文件来适应自己的业务需求,这样的话在jar包中的代码想读到使用者工程的配置文件就做成这个样子了.下面提供一个简单的日志切面

    14. package com.hdstcloud.device.common.aspect;
      
      import lombok.extern.slf4j.Slf4j;
      import org.aspectj.lang.JoinPoint;
      import org.aspectj.lang.annotation.*;
      import org.springframework.stereotype.Component;
      import org.springframework.web.context.request.RequestContextHolder;
      import org.springframework.web.context.request.ServletRequestAttributes;
      
      import javax.servlet.http.HttpServletRequest;
      import java.util.Arrays;
      
      /**
       * @author :js
       * @date :Created in 2020-11-26 13:18
       * @description: Controller层日志切面
       * @version: 1.0
       */
      @Aspect
      @Component
      @Slf4j
      public class LogAspect {
      
          /**
           * 切面的范围是com.hdstcloud.device.controller.impl包及其子包下所有类的所有方法
           */
          @Pointcut("execution(* com.hdstcloud.device.controller.impl..*.*(..))")
          public void log() {
          }
      
          @Before("log()")
          public void doBefore(JoinPoint joinPoint) {
              ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
              assert attributes != null;
              HttpServletRequest request = attributes.getRequest();
              String url = request.getRequestURL().toString();
              String ip = request.getRemoteAddr();
              String classMethod = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
              Object[] args = joinPoint.getArgs();
              RequestLog requestLog = new RequestLog(url, ip, classMethod, args);
              log.info("Request : {}", requestLog);
          }
      
          @After("log()")
          public void doAfter() {
      //        log.info("--------doAfter--------");
          }
      
          @AfterReturning(returning = "result", pointcut = "log()")
          public void doAfterReturn(Object result) {
              log.info("Result : {}", result);
          }
      
          private static class RequestLog {
              private final String url;
              private final String ip;
              private final String classMethod;
              private final Object[] args;
      
              public RequestLog(String url, String ip, String classMethod, Object[] args) {
                  this.url = url;
                  this.ip = ip;
                  this.classMethod = classMethod;
                  this.args = args;
              }
      
              @Override
              public String toString() {
                  return "{" +
                          "url='" + url + '\'' +
                          ", ip='" + ip + '\'' +
                          ", classMethod='" + classMethod + '\'' +
                          ", args=" + Arrays.toString(args) +
                          '}';
              }
          }
      }
      
      

posted @ 2021-06-09 15:59  蒋月生  阅读(121)  评论(0编辑  收藏  举报