介绍
简化Spring应用开发的一个框架、整个Spring技术栈的一个大整合。
Spring Framework架构图
IOC 和 AOP
IOC 控制反转 和 DI 依赖注入
IOC (Inversion of Controller) 控制反转。Spring提供一个IOC容器,使用对象从手动new方式替换成Spring容器来提供对象。这种对象创建控制权由自己手动创建转移到Spring创建即为控制反转。 IOC容器负责对象的创建、初始化等一些列操作。被创建或被管理的对象在IOC容器中称为Bean
DI (Dependency Injection) 依赖注入。在容器中建立bean与bean之间的依赖关系整个过程称为依赖注入。

定义bean
xml配置
xml
<bean id="person" class="com.zjx.test.Person" ></bean>
注解配置
java
@ComponentScan
@Component 一般用在公共组件上
- @Controller 一般用在控制层
- @Service 一般用在业务层
- @Repository 一般用在数据层
通过这种
@Component
扫描注解的方式定义bean的前提是:需要先配置扫描路径
设置依赖注入
1、构造器方式
默认使用了无参构造器创建bean
xml
<bean id="person" class="com.zjx.test.Person">
</bean>
使用有参的构造器,通过<constructor-arg>
标签来完成配置
xml
<bean id="person" class="com.zjx.test.Person">
<constructor-arg index="0" value="zjx"></constructor-arg>
<constructor-arg index="1" ref="anotherPerson"></constructor-arg>
</bean>
index
表示下标,从0开始。value
表示常量值ref
表示引用另一个bean
2、Setter注入方式
spring还提供了另外一种思路:通过setter方法设置bean所需参数,这种方式耦合性相对较低,比有参构造器使用更为广泛。
java
@Data
public class Person {
private String name;
private int age;
}
然后在bean.xml文件中配置bean时,加上<property>
标签设置bean所需参数。
xml
<bean id="person" class="com.zjx.test.Person">
<property name="name" value="zjx"></constructor-arg>
<property name="age" value="18"></constructor-arg>
</bean>
3、@Autowired 配合 @Qualifer
注意@Qualifer不能独立使用,必须搭配@Autowired
java
public class MyBeanConfiguration {
@Bean
public User user() {
return new User("markus", 24);
}
}
java
@Import({
com.zjx.test.MyBeanConfiguration.class
})
public class AutowiredDemo {
@Autowired
private User user;
}
当Spring容器中有多个相同类型的Bean
时,它还可以与@Qualifier
配合使用来指定某一特定的Bean
java
public class SameTypeBeanConfiguration {
@Bean
public User user1() {
return new User("markus", 24);
}
@Bean
public User user2() {
return new User("Luna", 23);
}
}
java
public class QualifierAnnotationUseDemo {
@Autowired
@Qualifier(value = "user1")
private User user;
}
4、@Value
@Value
是 Spring 提供的一个注解,用于从配置文件或其他来源(如系统环境变量、SpEL 表达式)中读取值并注入到 Bean 的字段或方法参数中。
yml
app:
name: Spring Boot Demo
version: 1.0.0
java
@Component
public class AppConfig {
@Value("${app.name}")
private String appName;
@Value("${app.version}")
private String appVersion;
public void printConfig() {
System.out.println("Application Name: " + appName);
System.out.println("Application Version: " + appVersion);
}
}
@Value
注解支持 Spring 表达式语言(SpEL),可用于动态计算值。
java
@Component
public class SpELExample {
@Value("#{2 * 5}")
private int result;
public void printResult() {
System.out.println("Result: " + result);
}
}
@ConfigurationProperties
java
person
name:zjx
age:18
@Configuration
@ConfigurationProperties(prefix = "person")
public class PersonProperties {
private String name;
private Integer age;
// getter & setter
}
@Value
和 @ConfigurationProperties
对比
5、@Resouce
@Resource和@Autowired两个注解的区别及说明
@Autowired是Spring 里面提供的一个注解,它默认是根据类型 来实现Bean的依赖注入。@Autowired里面有一个required属性,默认值是true 表示强制要求bean实例的一个注入,在应用启动的时候,如果IOC容器中不存在对应类型的bean,那么启动就会报错;如果我们不希望实现依赖注入就可以把这个属性设置为false。
- @Primary表示主要的Bean,当存在多个相同类型的Bean的时候,会优先使用声明了@Primary注解的一个Bean
- @Qualifier 相当于条件筛选,可以根据Bean的名字可以去找到需要装配的目标Bean
@Resource是JDK中提供的一个注解。最大的区别就是@Resource可以支持ByName 和 ByType两种注入方式;
- 如果使用name属性,spring会根据bean的名字来进行依赖注入;
- 如果使用type属性,spring会根据bean的类型来进行依赖注入,如果两个属性都没有进行设置,@Resource默认是根据定义的属性名字去容器中进行匹配,如果没有匹配成功,再根据类型来匹配;
- 如果两个都没有匹配到就会报错
配置第三方Bean(引入外部配置Bean)
1、静态工厂
这种方式的关键是需要定义一个工厂类,它里面包含一个创建bean的静态方法。例如:
java
public class MyBeanFactory {
public static Person createPerson(String name, int age) {
return new Person(name, age);
}
}
java
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Person {
private String name;
private int age;
}
在bean.xml文件中配置bean时,通过factory-method
参数指定静态工厂方法,同时通过<constructor-arg>
设置相关参数。
xml
<bean class="com.zjx.test.MyBeanFactory" factory-method="createPerson">
<constructor-arg index="0" value="zjx"></constructor-arg>
<constructor-arg index="1" value="18"></constructor-arg>
</bean>
2、实例工厂
这种方式也需要定义一个工厂类,但里面包含非静态的创建bean的方法。
java
public class MyBeanFactory {
public Person createPerson(String name, int age) {
return new Person(name, age);
}
}
然后bean.xml文件中配置bean时,需要先配置工厂bean。然后在配置实例bean时,通过factory-bean
参数指定该工厂bean的引用。
java
<bean id="myBeanFactory" class="com.zjx.test.MyBeanFactory">
</bean>
<bean factory-bean="myBeanFactory" factory-method="createPerson">
<constructor-arg index="0" value="zjx"></constructor-arg>
<constructor-arg index="1" value="18"></constructor-arg>
</bean>
3、FactoryBean
上面的实例工厂方法每次都需要创建一个工厂类,不方面统一管理。这时我们可以使用FactoryBean
接口。
java
public class UserFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
在它的getObject方法中可以实现我们自己的逻辑创建对象,并且在getObjectType方法中我们可以定义对象的类型。
xml
<bean id="userFactoryBean" class="com.sue.async.service.UserFactoryBean">
</bean>
注意:getBean("userFactoryBean");获取的是getObject方法中返回的对象。而getBean("&userFactoryBean");获取的才是真正的UserFactoryBean对象。
4、@Bean
@Component系列注解虽说使用起来非常方便,但是bean的创建过程完全交给spring容器来完成,我们没办法自己控制。
spring从3.0以后,开始支持JavaConfig的方式定义bean。它可以看做spring的配置文件,但并非真正的配置文件,我们需要通过编码java代码的方式创建bean。例如:
java
@Configuration
public class MyConfiguration {
@Bean
public Person person() {
return new Person();
}
}
在JavaConfig类上加@Configuration
注解,相当于配置了<beans>
标签。而在方法上加@Bean
注解,相当于配置了<bean>
标签。
5、@Conditional注解
springboot还引入了一些列的@Conditional
注解,用来控制bean的创建。
java
@Configuration
public class MyConfiguration {
@ConditionalOnClass(Country.class)
@Bean
public Person person() {
return new Person();
}
}
@ConditionalOnClass注解的功能是当项目中存在Country类时,才实例化Person类。换句话说就是,如果项目中不存在Country类,就不实例化Person类。
这个功能非常有用,相当于一个开关控制着Person类,只有满足一定条件才能实例化。
spring中使用比较多的Conditional还有:
- ConditionalOnBean
- ConditionalOnProperty
- ConditionalOnMissingClass
- ConditionalOnMissingBean
- ConditionalOnWebApplication
6、@Import
通过前面介绍的@Configuration和@Bean相结合的方式,我们可以通过代码定义bean。但这种方式有一定的局限性,它只能创建该类中定义的bean实例,不能创建其他类的bean实例,如果我们想创建其他类的bean实例该怎么办呢?
这时可以使用@Import
注解导入。
java
@Data
public class Role {
private Long id;
private String name;
}
使用@Import注解导入Role类
java
@Import(Role.class)
@Configuration
public class MyConfig {
}
然后在调用的地方通过@Autowired
注解注入所需的bean。
java
@RequestMapping("/")
@RestController
public class TestController {
@Autowired
private Role role;
@GetMapping("/test")
public String test() {
System.out.println(role);
return "test";
}
}
聪明的你可能会发现,我没有在任何地方定义过Role的bean,但spring却能自动创建该类的bean实例,这是为什么呢?
这也许正是@Import注解的强大之处。
此时,有些朋友可能会问:@Import注解能定义单个类的bean,但如果有多个类需要定义bean该怎么办呢?
恭喜你,这是个好问题,因为@Import注解也支持。
java
@Import({Role.class, User.class})
@Configuration
public class MyConfig {
}
@Import参数需要的是一个数组,可以引入多个配置类。 @Import注解在配置类中只能写一次。下面方式不允许的。
java@Import(Role.class) @Import(User.class) @Configuration public class Myconfig { }
作用范围
@Scope 定义bean作用范围,默认值singleton(单例)、可选值prototype(非单例)、requestweb(请求)、sessionweb(会话)
作用域范围
- singleton单例范围,Spring中bean的实例默认都是单例的。
- prototype原型范围,这个使用较少,这种作用域的bean,每次注入调用,Spring都会创建返回不同的实例,但是,需要注意的是,如果未指明代理类型,即不使用代理的情况下,将会在容器启动时创建bean,那么每次并不会返回不同的实例,只有在指明作用域代理类型例如TARGET_CLASS后,才会在注入调用每次创建不同的实例。
- requestweb请求范围,当使用该作用域范围时(包括下面的session作用域),必须指定proxyMode作用域代理类型,否则将会报错,对于request作用域的bean,Spring容器将会创建一个代理用作依赖注入,只有在请求时并且请求的处理中需要调用到它,才会实例化该目标bean。
- sessionweb会话范围,这个和request类似,同样必须指定proxyMode,而且也是Spring容器创建一个代理用作依赖注入,当有会话创建时,并且在会话中请求的处理中需要调用它,才会实例话该目标bean,由于是会话范围,生命依赖于session。
生命周期

java
@Component
public class MyBean {
@PostConstruct
public void init() {
// 初始化逻辑
System.out.println("Bean 初始化完成,执行 @PostConstruct 方法");
}
@PreDestroy
public void init() {
// 销毁
System.out.println("执行 @PreDestroy 方法");
}
}
AOP 面向切面编程
AOP(Aspect Oriented Programming)即面向切面编程,是对某一类事件的集中处理。面向切面编程(AOP)是一种编程范式,旨在将横切关注点(如日志记录、事务管理、权限验证等)从业务逻辑代码中分离出来,从而提高代码的可重用性、可维护性和模块性。
Spring AOP 通过代理模式在运行时动态地将横切关注点织入到目标对象中。
AOP 的组成:切面(Aspect)、切点(Pointcut)、通知(Advice)。AOP 的主要核心概念有:
切面(Aspect):
定义:切面是一个模块,它封装了横切关注点,包含了定义切点和通知的代码。 作用:将横切关注点模块化,便于复用和管理
连接点(Join Point):
定义:程序执行过程中能够插入切面的点,如方法调用、异常抛出等。 在Spring AOP中:连接点通常是方法的调用。
切点(Pointcut):
定义:切点定义了一组连接点,用于确定通知应该在哪些连接点上执行。 表示方式:通常使用表达式来匹配连接点,如AspectJ表达式。
通知(Advice):
定义:通知是切面在某个连接点执行的动作,它包含了在连接点执行的代码。 类型:
- 前置通知(Before):在目标方法执行前执行。
- 后置通知(After):在目标方法执行后执行。
- 返回通知(After Returning):在目标方法成功执行后执行。
- 异常通知(After Throwing):在目标方法抛出异常后执行。
- 环绕通知(Around):在目标方法执行前后执行,并可以控制目标方法的执行。
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
java
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/getuser")
public String getUser() {
System.out.println("hello user");
return "hello user";
}
}
对UserController下的所有方法进行增强
java
//定义切面 一个切面类可以有多个切入点
@Aspect
@Component
public class UserAspect {
//定义切点
@Pointcut("execution(* com.zjx.demo.controller.UserController.* (..))")
public void myPointCut(){
//@Pointcut注解不用定义方法内容,myPointCut方法不会执行
};
//定义前置通知
@Before("myPointCut()")
public void before(){
System.out.println("执行了前置通知");
};
//定义后置通知
@After("myPointCut()")
public void after() {
System.out.println("执行了后置通知");
}
//环绕通知
@Around("myPointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前通知");
Object ret = joinPoint.proceed();
System.out.println("环绕后通知");
return ret;
}
//返回之前通知
@AfterReturning("myPointCut()")
public void afterReturning() {
System.out.println("执行return之前的通知");
}
//返回之前通知 带返回值
@AfterReturning(value = "myPointCut()", returning = "result")
public void afterReturning2(JoinPoint jp, Object result) {
String name = jp.getSignature().getName();
System.out.println(name + "方法返回值为:" + result);
}
// 异常通知
@AfterThrowing(value = "myPointCut()", throwing = "e")
public void afterThrowing(JoinPoint jp, Exception e) {
String name = jp.getSignature().getName();
System.out.println(name + "方法抛异常了,异常是:" + e.getMessage());
}
}
注解说明:
@Aspect
:表明这是一个切面类。@Pointcut
:表明这是一个切入点。- execution 中的第一个 * 表示方法返回任意值
- 第二个 * 表示 service 包下的任意类
- 第三个 * 表示类中的任意方法,括号中的两个点表示方法参数任意,即这里描述的切入点为service 包下所有类中的所有方法。
@Before
:表示这是一个前置通知,该方法在目标方法之前执行。通过 JoinPoint 参数可以获取目标方法的方法名、修饰符等信息。@After
:表示这是一个后置通知,该方法在目标执行之后执行。@AfterReturning
:表示这是一个返回通知,在该方法中可以获取目标方法的返回值。- returning 参数是指返回值的变量名,对应方法的参数。
- 注意:本样例在方法参数中定义 result 的类型为 Object,表示目标方法的返回值可以是任意类型。若 result 参数的类型为 Long,则该方法只能处理目标方法返回值为 Long 的情况。
@AfterThrowing
:表示这是一个异常通知,即当目标方法发生异常,该方法会被调用。- 样例中设置的异常类型为 Exception 表示所有的异常都会进入该方法中执行。
- 若异常类型为 ArithmeticException 则表示只有目标方法抛出的 ArithmeticException 异常才会进入该方法的处理。
@Around
:表示这是一个环绕通知。环绕通知是所有通知里功能最为强大的通知,可以实现前置通知、后置通知、异常通知以及返回通知的功能。- 目标方法进入环绕通知后,通过调用 ProceedingJointPoint 对象的 proceed 方法使目标方法继续执行,开发者可以在次修改目标方法的执行参数、返回值值,并且可以在此目标方法的异常。
基础配置
不使用spring-boot-starter-parent
- 通常使用spring-boot-starter-parent提供默认以下配置
- Java版本默认使用1.8
- 编码格式使用UTF-8
- 提供Dependency Management进行项目依赖的版本管理
- 默认的资源过滤与插件配置
xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
使用spring-boot-starter-parent虽然方便,但是一般开发微服务项目或多模块项目一般使用公司自己的parent,这时还想项目依赖统一的版本管理,需要使用dependencyManagement
来实现。
xml
<properties>
<java.version>8</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR9</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependencies>
<dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version> <!-- 使用适合您项目的版本 -->
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
</plugins>
</build>
@SpringApplication
@SpringBootApplication是一个3合一注解
java
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {
}
定制Banner
Web容器配置
Tomcat配置
yml
server:
# Web容器端口号
port: 8080
# 项目出错跳转页面
error:
path: /error
servlet:
# 项目名称路径,不配做时默认 / ,如果配置了,就要在访问路径加上配置的项目名称路径
context-path: /myproject
# session失效时间,默认单位秒
session:
timeout: 30ms
tomcat:
# Tomcat请求编码
uri-encoding: UTF-8
# Tomcat最大线程数
threads:
max: 200
# 存放Tomcat运行日志和临时文件的目录,若不配置,则默认使用系统的临时目录
basedir: /home/basedir
HTTPS配置
Properties配置
加载优先级
Profile
每个运行环境(开发、测试、上线)都配置成一个对应profile,这样以后只要修改一下活动profile,应用就可以轻易地在不同的运行环境之间自由切换。就是通过 配置的 profile 快速切换开发环境。
通用配置文件: application.properties或者application.yml
profile相关: application-{profile名}.properties
或者application-{profile名}.yml
profile相关的配置文件的优先级更高(后加载,后加载的会覆盖前面加载的)
yml
spring:
profiles:
active: prod
@Profile("prod")
注解作用:表示这个控制器仅对dev作为活动profile时才生效(就是把开发环境切换成 dev ,这个控制器才生效) application.yml配置文件中使用 spring.profiles.active 属性,用于切换活动profile,意味着最终最多时能有一个活动profile,就是最终只能有一个开发环境,要么正式,要么测试,要么其他,只能有一个开发环境。
整合Web开发
返回Json数据
@RestController
自定义JSON转换器
第一种:默认的 jackson-databind
默认情况下,类上使用 @Controller 注解,方法上使用 @ResponseBody 注解,返回的对象会默认被转换成 JSON 格式;
另外,@RestController 注解是 @Controller 注解 和 @ResponseBody 注解的组合,是等效的!
第二种:使用 Gson
1、Gson简介 GSON 是 Google 提供的用来在 Java 对象和 JSON 数据之间进行映射的 Java 类库。可以将一个JSON 字符转成一个 Java 对象,或者将一个 Java对象 转化为 JSON 字符串。
特点: 快速、高效;代码量少、简洁;面向对象;数据传递和解析方便
2、使用步骤
第一步:在 pom.xml 中移除默认的 jackson-databind ,引入 Gson 依赖
xml
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--gson-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
第二步:自定义 HttpMessageConverter
Spring Boot 已经默认提供了 Gson 的自动转换类 GsonHttpMessageConvertersConfigurations,因此 Gson 的以来添加之后,可以直接像使用 jackson-databind 那样直接使用 gson 。但是在 Gson 进行转换时,如果相对日期进行格式化,那么需要开发者自定义 HttpMessageConverter !
java
package com.zibo.api.config;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import java.lang.reflect.Modifier;
@Configuration
public class GSONConfig {
@Bean
GsonHttpMessageConverter gsonHttpMessageConverter(){
// 自己提供一个 GSONHttpMessageConverter 实例
GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
GsonBuilder builder = new GsonBuilder();
// 设置解析式日期的格式
builder.setDateFormat("yyyy-MM-dd");
// 设置解析时修饰符为 protected 的字段被过滤掉
builder.excludeFieldsWithModifiers(Modifier.PROTECTED);
// 创建 Gson 对象,放入 converter 实例并返回
Gson gson = builder.create();
converter.setGson(gson);
return converter;
}
}
第三种:使用 fastjson
1、简介
fastjson 是阿里巴巴 的一个开源的 JSON 解析框架,是目前 JSON 解析速度最快 的开源框架,该框架也可以集成到 Spring Boot 中,大但并不能立即使用!需要提供相应的 HttpMessageConverter 后才能使用!
2、使用步骤
第一步:在 pom.xml 中移除默认的 jackson-databind ,引入 fastjson 依赖
xml
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--fast json-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
第二步:自定义 HttpMessageConverter
java
package com.zibo.api.config;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.nio.charset.StandardCharsets;
@Configuration
public class MyFastJsonConfig {
@Bean
FastJsonHttpMessageConverter fastJsonHttpMessageConverter(){
// 自己提供一个 FastJsonHttpMessageConverter 实例
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
FastJsonConfig config = new FastJsonConfig();
// 设置解析式日期的格式
config.setDateFormat("yyyy-MM-dd");
// 设置解析时编码格式为 UTF-8
config.setCharset(StandardCharsets.UTF_8);
config.setSerializerFeatures(
SerializerFeature.WriteClassName,
SerializerFeature.WriteMapNullValue,
SerializerFeature.PrettyFormat,
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.WriteNullStringAsEmpty
);
converter.setFastJsonConfig(config);
return converter;
}
}
另一种配置方式
java
package com.zibo.api.config;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.nio.charset.StandardCharsets;
import java.util.List;
public class MyWebMvcConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
// 自己提供一个 FastJsonHttpMessageConverter 实例
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
FastJsonConfig config = new FastJsonConfig();
// 设置解析式日期的格式
config.setDateFormat("yyyy-MM-dd");
// 设置解析时编码格式为 UTF-8
config.setCharset(StandardCharsets.UTF_8);
config.setSerializerFeatures(
SerializerFeature.WriteClassName,
SerializerFeature.WriteMapNullValue,
SerializerFeature.PrettyFormat,
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.WriteNullStringAsEmpty
);
converter.setFastJsonConfig(config);
converters.add(converter);
}
}