Aop
1.引入Aop对应依赖
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2. 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String value() default "";
}
3. 注册切面、切点
@Aspect
@Component
public class LogAspect {
@Autowired
private SysLogDao sysLogDao;
@Pointcut("@annotation(com.example.aoptest.myinterface.Log)")
public void pointcut(){};
@Around("pointcut()")
public Object around(ProceedingJoinPoint point){
Object result = null;
long beginTime = System.currentTimeMillis();
try{
result = point.proceed();
}catch (Throwable e){
e.printStackTrace();
}
long time = System.currentTimeMillis() - beginTime;
saveLogs(point,time);
return result;
}
private void saveLogs(ProceedingJoinPoint point, long time){
SysLog log = new SysLog();
//获取method
MethodSignature methodSignature = (MethodSignature) point.getSignature();
Method method = methodSignature.getMethod();
//获取注解对象
Log logAnnotation = method.getAnnotation(Log.class);
//获取注解的描述
if (logAnnotation != null){
log.setOperation(logAnnotation.value());
}
String className = point.getTarget().getClass().getName();
log.setMethod(className + "." + method.getName());
//获取参数信息
Object[] args = point.getArgs();
LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
String[] paramNames = u.getParameterNames(method);
if (args != null && paramNames != null){
StringBuilder params = new StringBuilder();
for (int i=0; i<args.length; i++){
params.append(args[i] + ": " + paramNames[i]+" ");
}
log.setParams(params.toString());
}
//获取request
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String ip = IPUtils.getIpAddress(request);
log.setIp(ip);
log.setUsername("qiang");
log.setCreateTime(new Date());
log.setTime((int)time);
sysLogDao.saveSysLog(log);
}
}
4.使用
@RestController
public class AopController {
@Log("执行方法一")
@GetMapping("/one")
public void methodOne(String name) { }
@Log("执行方法二")
@GetMapping("/two")
public void methodTwo() throws InterruptedException {
Thread.sleep(2000);
}
@Log("执行方法三")
@GetMapping("/three")
public void methodThree(String name, String age) { }
}
Cache
1.开启缓存支持
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
接着在Spring Boot入口类中加入@EnableCaching注解开启缓存功能:
@SpringBootApplication
@EnableCaching
public class CachetestApplication {
2.配置redis(或其他缓存工具 Ehcache)
在application.yml中设置redis连接信息
spring:
redis:
# Redis数据库索引(默认为0)
database: 0
# Redis服务器地址
host: localhost
# Redis服务器连接端口
port: 6379
jedis:
pool:
# 连接池最大连接数(使用负值表示没有限制)
max-active: 8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1
# 连接池中的最大空闲连接
max-idle: 8
# 连接池中的最小空闲连接
min-idle: 4
# 连接超时时间(毫秒)
timeout: 10000
编写redis配置类
@Configuration
public class RedisConfiguration extends CachingConfigurerSupport {
@Bean
@ConditionalOnBean
public ObjectMapper objectMapper() {
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); //补上
return om;
}
@Bean
public Jackson2JsonRedisSerializer jackson2JsonRedisSerializer (ObjectMapper om) {
Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
serializer.setObjectMapper(om);
return serializer;
}
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory,
Jackson2JsonRedisSerializer serializer) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
RedisSerializer stringSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);//key序列化
redisTemplate.setValueSerializer(serializer);//value序列化
redisTemplate.setHashKeySerializer(stringSerializer);//Hash key序列化
redisTemplate.setHashValueSerializer(serializer);//Hash value序列化
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofHours(1)); // 设置缓存有效期一小时
return RedisCacheManager
.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
.cacheDefaults(redisCacheConfiguration).build();
}
@Bean
@Override
public KeyGenerator keyGenerator() {
return (target, method, objects) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append("::" + method.getName() + ":");
for (Object obj : objects) {
sb.append(obj.toString());
}
return sb.toString();
};
}
}
3.使用
在service层中缓存数据查询结果
@CacheConfig(cacheNames = "student")
public interface StudentService {
@CachePut(key = "#p0.id")
Student update(Student student);
@CacheEvict(key = "#p0")
void deleteStudentBySno(int id);
@Cacheable(key = "#p0")
Student queryStudentBySno(int id);
}
缓存注解
-
@CacheConfig:主要用于配置该类中会用到的一些共用的缓存配置。在这里@CacheConfig(cacheNames = “student”):配置了该数据访问对象中返回的内容将存储于名为student的缓存对象中,我们也可以不使用该注解,直接通过@Cacheable自己配置缓存集的名字来定义;
-
@Cacheable:配置了queryStudentBySno函数的返回值将被加入缓存。同时在查询时,会先从缓存中获取,若不存在才再发起对数据库的访问。该注解主要有下面几个参数:
- value、cacheNames:两个等同的参数(cacheNames为Spring 4新增,作为value的别名),用于指定缓存存储的集合名。由于Spring 4中新增了@CacheConfig,因此在Spring 3中原本必须有的value属性,也成为非必需项了;
- key:缓存对象存储在Map集合中的key值,非必需,缺省按照函数的所有参数组合作为key值,若自己配置需使用SpEL表达式,比如:@Cacheable(key = “#p0”):使用函数第一个参数作为缓存的key值,更多关于SpEL表达式的详细内容可参考https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#cache;
- condition:缓存对象的条件,非必需,也需使用SpEL表达式,只有满足表达式条件的内容才会被缓存,比如:@Cacheable(key = “#p0”, condition = “#p0.length() < 3”),表示只有当第一个参数的长度小于3的时候才会被缓存;
- unless:另外一个缓存条件参数,非必需,需使用SpEL表达式。它不同于condition参数的地方在于它的判断时机,该条件是在函数被调用之后才做判断的,所以它可以通过对result进行判断;
- keyGenerator:用于指定key生成器,非必需。若需要指定一个自定义的key生成器,我们需要去实现org.springframework.cache.interceptor.KeyGenerator接口,并使用该参数来指定;
- cacheManager:用于指定使用哪个缓存管理器,非必需。只有当有多个时才需要使用;
- cacheResolver:用于指定使用那个缓存解析器,非必需。需通过org.springframework.cache.interceptor.CacheResolver接口来实现自己的缓存解析器,并用该参数指定;
-
@CachePut:配置于函数上,能够根据参数定义条件来进行缓存,其缓存的是方法的返回值,它与@Cacheable不同的是,它每次都会真实调用函数,所以主要用于数据新增和修改操作上。它的参数与@Cacheable类似,具体功能可参考上面对@Cacheable参数的解析;
-
@CacheEvict:配置于函数上,通常用在删除方法上,用来从缓存中移除相应数据。除了同@Cacheable一样的参数之外,它还有下面两个参数:
- allEntries:非必需,默认为false。当为true时,会移除所有数据;
- beforeInvocation:非必需,默认为false,会在调用方法之后移除数据。当为true时,会在调用方法之前移除数据。
Swagger2
引入Swagger依赖
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
配置SwaggerConfig
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket buildDocket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(buildApiInf())
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.demo.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo buildApiInf() {
return new ApiInfoBuilder()
.title("系统RESTful API文档")
.contact(new Contact("mrbird", "https://mrbird.cc", "852252810@qq.com"))
.version("1.0")
.build();
}
}
Swagger常用注解
- @Api:修饰整个类,描述Controller的作用;
- @ApiOperation:描述一个类的一个方法,或者说一个接口;
- @ApiParam:单个参数描述;
- @ApiModel:用对象来接收参数;
- @ApiProperty:用对象接收参数时,描述对象的一个字段;
- @ApiResponse:HTTP响应其中1个描述;
- @ApiResponses:HTTP响应整体描述;
- @ApiIgnore:使用该注解忽略这个API;
- @ApiError :发生错误返回的信息;
- @ApiImplicitParam:一个请求参数;
- @ApiImplicitParams:多个请求参数。
使用
@Api(value = "用户Controller")
@Controller
@RequestMapping("user")
public class UserController {
@ApiIgnore
@GetMapping("hello")
public @ResponseBody String hello() {
return "hello";
}
@ApiOperation(value = "获取用户信息", notes = "根据用户id获取用户信息")
@ApiImplicitParam(name = "id", value = "用户id", required = true, dataType = "Long", paramType = "path")
@GetMapping("/{id}")
public @ResponseBody User getUserById(@PathVariable(value = "id") Long id) {
User user = new User();
user.setId(id);
user.setName("mrbird");
user.setAge(25);
return user;
}
@ApiOperation(value = "获取用户列表", notes = "获取用户列表")
@GetMapping("/list")
public @ResponseBody List<User> getUserList() {
List<User> list = new ArrayList<>();
User user1 = new User();
user1.setId(1l);
user1.setName("mrbird");
user1.setAge(25);
list.add(user1);
User user2 = new User();
user2.setId(2l);
user2.setName("scott");
user2.setAge(29);
list.add(user2);
return list;
}
@ApiOperation(value = "新增用户", notes = "根据用户实体创建用户")
@ApiImplicitParam(name = "user", value = "用户实体", required = true, dataType = "User")
@PostMapping("/add")
public @ResponseBody Map<String, Object> addUser(@RequestBody User user) {
Map<String, Object> map = new HashMap<>();
map.put("result", "success");
return map;
}
@ApiOperation(value = "删除用户", notes = "根据用户id删除用户")
@ApiImplicitParam(name = "id", value = "用户id", required = true, dataType = "Long", paramType = "path")
@DeleteMapping("/{id}")
public @ResponseBody Map<String, Object> deleteUser(@PathVariable(value = "id") Long id) {
Map<String, Object> map = new HashMap<>();
map.put("result", "success");
return map;
}
@ApiOperation(value = "更新用户", notes = "根据用户id更新用户")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "用户id", required = true, dataType = "Long", paramType = "path"),
@ApiImplicitParam(name = "user", value = "用户实体", required = true, dataType = "User") })
@PutMapping("/{id}")
public @ResponseBody Map<String, Object> updateUser(@PathVariable(value = "id") Long id, @RequestBody User user) {
Map<String, Object> map = new HashMap<>();
map.put("result", "success");
return map;
}
}
本文介绍如何在Spring Boot项目中整合AOP、缓存管理和Swagger文档生成,包括自定义AOP切面、配置缓存策略及使用Swagger2生成RESTful API文档。
216

被折叠的 条评论
为什么被折叠?



