深入浅出springboot阅读学习(三)

一、Redis,redis默认序列化器是JdkSerializationRedisSerializer,这样会使二进制不具有可读性,如果我们可以自定义配置redis为StringRedisSerializer。如果是对象的话我们还可以配置成JacksonJsonRedisSerializer。redis最常用的是redisTemplate.opsForValue()字符串操作接口,但是也提供了其他的比如opsForList/opsForHash/opsForSet等直接操作这种集合、hashMap、set的方法类似一对多,opsForValue是一对一;平时我们的基本操作比如直接删除再新增写作两行其实是不同的redis连接,这样比较消耗资源,因此我们可以通过RedisCallback和SessionCallback来实现一个连接多次操作,第一个不常用这个可以改写底层更强大,第二个常用接口友好优先使用,使用以上两个时可以直接在代码里编写调用也可以在redis配置中直接配置使用;redis的一些特殊用法,1、使用redis事务,redis是具有一定事务能力的NOsql也可以实现事务操作使用watch multi…exec。2、redis流水线,可以实现像数据库一样的batchInsert类似的操作,而不是一条条操作。3、Redis发布订阅,消息总线功能通过实现MessageListener接口的onMessage来定义监听到消息后的动作,然后再启动类上通过创建RedisMessageListenerContainer类配置其属性指定监听的topic,最后发送的时候通过redistemplate.converAndsent(topic,message)来发送消息。4、redis的计算能力,redis用于内存级别缓存,计算能力差,但是可以通过Lua脚本提高计算能力;接下来是使用SpringBoot注解来操作Redis,这个应用较多,其底层原理spring的aop,由此也可以引发其失效场景,就是比如我们在updateUser之前为了防止有脏读,我们可以在其中使用getUser真正的去数据库查询,虽然说getUser上也打了@Cacheenalle注解,但是类的自调用不会,使得缓存注解不生效,也就不存在有些人担心的更新前查询的也是缓存里面的问题。那么怎么解决同类调用呢?,AOP失效问题呢?https://blog.csdn.net/erica_1230/article/details/46003779   AServiceImpl 类实现ApplicationContextAware接口自己通过容器获取对象实例。这是一个方法。介绍下注解:@Cacheput(value='rediscache',key="'redis_user_'+#id")表示将方法结果返回存放到缓存中,一般insert,update方法上加入,其中value是我们配置文件中的缓存名,key配置的是redis中的缓存key是固定字符串加上id这个属性拼接而成,这也就要求我们的参数中存在id,但是也可以通过arg[0]/arg[1]取对应第几个参数,后面注解里面都需要配置value属性key看情况使用。@Cacheable表示先从缓存中通过定义的建查询,如果可以查到数据则返回,否则执行方法返回数据,并将结果保存到缓存中,这个注解就是查询方法上使用。@CacheEvict通过定义的键移除缓存,它有一个beforeInvocation的配置项控制先清除缓存还是先删除数据库再清缓存,默认是false先清库再删缓存。应用:第一步,应用的时候我们可以直接在配置文件配置redis缓存管理器的配置信息重点是缓存类型redis以及缓存名字这俩是基础的,在我们应用上面的注解的时候要指定缓存配置名称的,用于区分不同的配置信息。第二步,启动类上@EnableCaching 启用缓存机制。第三步就是开发了,在我的serviceimpl中加上上面介绍的是哪个注解分别应用,应用是注解首先value对应的是配置的缓存名称,key为redis中存储是的key,condition="#result !='null'"来控制如果数据为null则不缓存,其中#result,就是我们方法返回结果,同时就是需要存的结果。同时呢,高并发下面应用缓存也会存在脏读现象,这个时候我们就要在配置redis缓存信息的时候配置失效时间啥的,防止永久性脏读,比如10分钟,还有其他的比如配置我们redis中key存储的前缀啥的都可以配置。
二、MongoDB,MongoDB由C++语言开发,将数据存储为一个文档,数据结构由键值对组成,类似JSON数据集,很方便转为java的pojo对象。依赖引入spring-boot-starter-data-mongodb。我们使用mongodb时候一般试用MongoTemplate实例进行操作,他不用我们创建,直接autowired引入即可,在操作的类上@Document标识此类为mongodb的文档,@Id标识主键,@Field标识字段对应数据库的驼峰@Field("user_name")对应,然后我们就可以在serviceImpl类中使用其默认集成的findById(id)、find(query,User.Class)其中query为构造的查询条件。还可以使用JPA类似mybatisPlus的继承接口实现扩展的功能。同时注意SpringDataMongo为我们提供了一个注解@EnableMongoRepositories指定扫描对应的接口,直接指向我们的Dao层,包括后面的自定义查询此处不再介绍。
三、SpringMVC,MVC(Model-View-Controller)分层思想
1、基础注解:@RestController相当于@Controller+@ResponseBody,@ResponseBody的作用其实是将java对象转为json格式的数据。@responseBody注解的作用是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML数据。如果直接返回内容则用@Controller,比如直接返回某个页面;SpringBoot默认包扫描机制: 从启动类所在包开始,扫描当前包及其子级包下的所有文件。@ComponentScan 用于指定springboot扫描的路径,当然类上打上此注解也会被扫描。@MapperScan和@ComponentScan的区别:@ComponentScan是组件扫描注解,用来扫描@Controller  @Service  @Repository这类,主要就是定义扫描的路径从中找出标志了需要装配的类到Spring容器中,而@MapperScan 是扫描mapper类的注解,就不用在每个mapper类上加@MapperScan了这两个注解是可以同时使用的。Controller层一般基础的注解@RestController/@RequestMapping/@Slf4j/@Api/@CrossOrigin,进入方法上@Post/Get/Put/DeleteMapping/@ApiOperation/@ApiParam。进入service层在Impl层@Service。进入Dao层@Repository这都是很基本的注解。其实我们通过@Requestmapping暴露对外提供的路径本质是通过拦截器进行对应指向的;
2、参数接收:@RequestParam注解,当前后端参数不一致的时候@RequestParam就生效了比如get请求前端参数为int_val后端为intVal我们在这样定义@RequestParam(value="int_val",required =false)int intVal。同时如果不指定required=false的话,如果此参数没传则会报错,所以正规的编写应当指定required的属性,尤其是一些可选项时候。前后端数组传递,后端正常指定int[] intArr前端传值时用逗号隔开即可?intArr=1,2,3;前后端传递Json使用@RequestBody;对于REST风格的传参,通过path传参,比如请求URL是/user/1我们需要用@PathVariable("id" ) Long id 来接收参数。方法上@GetMapping("/id") 占位符获取参数。甚至还有其他的一些格式化参数使用@DateTimeFormat等注解对参数进行转换。
3、参数校验:使用hibernae validator校验,一些@NotNull@min@max@range@Email@size@Future标识日期只能是将来的等多样化校验。详细应用可以参考https://blog.csdn.net/yrsg666/article/details/108868836 
4、拦截器,通过拦截器我们可以实现增强接口功能,所有的拦截器需要实现HandlerInterceptor接口,实现其三个方法preHandle处理器执行前方法postHandle处理器处理后方法afterCompletion处理器完成后方法,下面开始自定义拦截器:拦截器interceptor1 implements HandlerInterceptor接口。注意这个接口下自带三个方法都已经用default默认给了实现,我们要主动去实现下。然后我们将interceptor1注册到容器中在启动类上 implements WebMvcConfigurer接口重写里面的addInterceptors方法,同样此方法也是default修饰,使用其自带的registry.addInterceptor(new Interceptor1())注册后,返回对象ir.addPathPatterns("/user/*")就简单实现了拦截包含user的url请求。注意后面的执行顺序,我们会发现如果preHandle方法返回true则执行顺序为preHandle,被拦截方法业务,postHandle,afterCompletion。但是如果preHandle返回false或者执行业务当中发生了异常则postHandle不执行,但是afterCompletion一定会最后执行,类似于try-catch-finally一样。多拦截器场景,多个拦截器定义方式与单个一样,至于执行顺序则是对于preHandle先注册先执行,而postHandle则是先注册后执行,afterCompletion也是先注册后执行,但是需要注意先统一执行pre然后是post最后是after,这与之前的AOP多切面还不太一样,上个是同一个对象的后两个方法after afterReturning紧挨执行的。这个拦截器是执行完一类方法再执行下一类方法。
5、springMvc小知识,@RequestHeader注解用于接收请求头参数属性值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值