SpringBoot实现JSON数据重复读取
写在前面最近遇到一个很尴尬的问题,前端传给后端的JSON数据,如果开发者对此进行了拦截并进行了消费,那么后续在controller中就无法再次获取对应数据。原因在于服务端是通过IO流来解析JSON数据,而流是一种特殊的结构,只要读完就没有了,而在某些场景下往往希望可以多次读取。
举一个非常简单的例子,接口幂等性实现,即同一个接口在规定时间内多次接收到相同参数的请求,那么此时需要拒绝这些相同请求。我们在具体实现的时候,可能会先将请求中的参数提取出来,如果参数是JOSN数据,那么由于流已经读取了,因此后续在接口是无法再次获取JSON数据的。
问题再现第一步,新建一个名为many-json的SpringBoot项目,并在其中新增Web依赖。
第二步,新建一个interceptor包,并在该包内新建一个RequestInterceptor类,这个类需要实现HandlerInterceptor接口并重写其中的preHandle方法:
123456789public class RequestInterceptor implements HandlerInterceptor { p ...
SpringBoot实现定时任务
写在前面在实际工作中,定时任务是一个很常见的功能,如定时统计订单数、数据库备份、定时发送短信和邮件、定时统计博客访客等等,简单的定时任务可以直接通过Spring提供的@Scheduled注解来实现,复杂一点的定时任务则可以通过集成Quartz([kwɔːts])来实现,本篇将分别介绍如何使用这两种方式实现定时任务。
项目初始化新建一个名为time-task的SpringBoot项目,后续将在该项目中进行定时任务的实现。
@Scheduled注解方式小试牛刀第一步,添加依赖。在项目的POM文件中新增Web依赖:
1234<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency>
第二步,开启定时任务。在项目启动类上添加@EnableScheduling注解,相应的代码为:
1234567@EnableScheduling@Spri ...
SpringBoot+Vue实现一个代码生成器
写在前面在前面我们学习了SpringBoot+Vue这一套前后端分离的优秀架构,接下来我们尝试基于此实现一个代码生成器。在平时工作中,可能我们使用比较多的还是Mybatis Generate生成器,以此来根据数据表逆向生成对应的Dao层和Mapper层代码。其实生成器的核心,是使用JDBC来获取数据库中的各种元数据信息,并基于此来实现各种功能。本篇要实现的代码生成器不仅可以生成Dao层和Mapper层代码,还可以生成Service和Controller层代码,涵盖了一些基本操作,开发者要是实现一个简单的项目,几乎可以做到不写任何一行代码。
用法介绍
用户在序号1/2/3分别输入数据库用户名,密码、连接地址,然后点击序号4,如果数据库可以连接得上,那么序号5就会展示连接成功的提示信息,否则展示连接失败;如果成功接着在序号6中输入要生成的包的名称,也就是${groupId}.${artifactId},接着点击序号7来生成配置,如果成功那么序号8处就会生成对应的数据表名称、实体类名称、mapper文件名称、service名称和controller名称 ...
关于Freemarker模板引擎,需要知道这些
写在前面尽管在目前企业级的应用开发中,前后端分离是趋势,但是视图层技术还是占用一席之地。SpringBoot对视图层技术也提供了很好的支持,官方推荐使用的模板引擎是Thymeleaf,但是FreeMaker也支持,当然你可以像SSM中使用JSP等,但是非常不推荐使用。
FreeMarkerFreeMarker简介FreeMarker是一个非常古老的Java模板引擎,可以用在Web或者非Web环境中。与Thymeleaf不同的是FreeMarker需要经过解析才能够在浏览器中展示出来。FreeMarker不仅可以用来配置HTML页面模板,也可以作为电子邮箱模板、配置文件模板以及源码模板等。正是由于它可以适应不同的应用场景,因此它虽然古老但是依旧还是有人愿意使用它。
下面是一张摘自FreeMarker官网的图片:
可以看到FreeMarker可以将模板(Template)和数据(Java Objects)进行渲染为HTML页面。
FreeMarker模板文件及存放位置查看一下这个spring-boot-autoconfigure依赖的META-INF文件夹下面的spring.factor ...
自定义SpringBoot中的Starter场景启动器
写在前面在前面我们对SpringBoot的自动装配原理有了一个较为深刻的研究,那么接下来我们就分析一下其中的场景启动器(starter),并尝试自定义一个属于自己的场景启动器(starter)。
场景启动器简介场景启动器(starter),其实就是一个个的功能。SpringBoot会将用户常用的一些功能抽离出来,做成一个个的场景启动器,这些场景启动器会导入实现这些功能所需的全部依赖组件,这样开发者只需在项目中引入这些场景启动器,那么相应的依赖就会加载进来。开发者只需通过修改配置文件,就能实现使用相应功能这一目的。
父场景启动器介绍当我们新建一个SpringBoot项目时,POM文件中会自动添加一个父依赖,该依赖名称为spring-boot-starter-parent:
123456<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <versio ...
聊一聊SpringBoot的自动装配原理
写在前面最近在重构一个日志模块,需要将其从项目中抽离出来,于是考虑将其做成一个starter便于后续使用。本篇就来聊聊SpringBoot的自动装配原理,只有了解原理才知道如何将自己的项目制作为starter。
管中窥豹当你新建一个SpringBoot项目的时候,项目入口类中自动会添加@SpringBootApplication,那么问题来了,这个@SpringBootApplication注解的作用是什么呢,查看一下该注解的源码:
1234567891011121314151617@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilte ...
SpringBoot自定义参数解析器
写在前面今天我们来聊一聊SpringBoot中的参数解析器,这在某些场景下非常有用。一般来说,在一个Web请求里面参数要么是放在请求地址,要么就是放在请求体里面,极个别的会放在请求头中。
如果请求参数放在请求地址中,那么通常会采用@RequestParam/@PathVariable或者如下方式来获取参数:
1String username = request.getParameter("username");
如果请求参数放在请求体里面,那么通常会采用@RequestBody或者如下方式来获取参数:
1String username = request.getParameter("username");
如果请求参数放在请求头里面,那么通常会采用@RequestHeader或者如下方式来获取参数:
1String username = request.getHeader("username");
如果参数是JSON形式的,那么会从输入流中获取并解析成JSON字符串,再通过JSON工具转化为POJO对象:
1234Buffer ...
一个注解配合Redis实现接口限流
写在前面最近发现线上发送验证码的接口被莫名刷了,1天就把上周刚充值的1万条用完了,我内心其实是崩溃的,于是决定对该接口实现限流,这里选择使用拦截器配合Redis来实现。
实战项目初始化第一步,新建一个名为limit-redis的SpringBoot项目,然后在POM文件中添加如下依赖:
123456789101112131415161718<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency>&l ...
可视化多数据源动态切换
写在前面在实际工作中我们希望实现多数据源的动态切换,而这一点我们在前面一篇文章中就已经进行了实现,但是对于业务人员来说,更多的则是希望可以通过可视化界面的方式来自己决定使用哪个数据源,进而获取对应的数据。
几个思考前面我们多次提到AbstractRoutingDataSource抽象类定义了抽象的determineCurrentLookupKey方法,子类只需实现此方法,就可以通过一个Key从Map中获取对应的数据源实例,并执行对应的数据库操作。查看一下之前我们的dynamic-multiple-ds项目,本篇将在此基础上进行实现。由于我们将数据源名称存在DynamicMultipleDataSourceContextHolder这一ThreadLocal中,因此只需修改该变量的值就能实现这个目的。
也就是说首先我们要定义一个方法用于传入新的数据源名称,然后我们可以将这个数据源名称放在Session、Redis或者数据库中,最后在修改DynamicMultipleDataSourceContextHolder的时候从里面取出数据并更新ThreadLocal的值即可。
其次,用户通过页面 ...
多数据源动态切换
写在前面在前一篇文章中我们介绍了如何在SpringBoot中整合Jdbc Template、Mybatis和Spring Data JPA的多数据源配置,但是很明显这些思路都是设置多个Dao层,然后手动选择使用的实例,在实际工作中可能会有需要动态切换数据源的情况,因此本篇来学习如何利用AOP来实现多数据源的动态切换功能。
知识回顾AbstractRoutingDataSource是Spring2.0.1版本引入的一个抽象类,它提供了多数据源的支持能力。AbstractRoutingDataSource抽象类定义了抽象的determineCurrentLookupKey方法,子类只需实现此方法,进而动态确定要使用的数据源。
查看一下这个AbstractRoutingDataSource抽象类的源码,如下所示:
1234567891011121314151617181920212223242526272829303132public abstract class AbstractRoutingDataSource extends AbstractDataSource implements ...