Spring Boot训练营:Spring Boot + Dozer篇
这是Spring Boot训练营的系列之一,标题为Spring Boot + Dozer。
本次的目的
使用Spring Boot应用程序时,可以利用Dozer来进行Bean的复制。
本次使用的库
-
- spring-boot-starter:2.2.0.M4
-
- dozer-spring-boot-starter:6.5.0
-
- spring-boot-starter-test:2.2.0.M4
- lombok:1.18.8
Dozer是什么?
隐藏Java Bean的复制操作,使代码更简洁。
public Todo convert(TodoForm form) {
Todo todo = new Todo();
todo.setTodoId(form.getTodoId());
todo.setTodoTitle(form.getTodoTitle());
todo.setFinished(form.isFinished());
todo.setCreatedAt(form.getCreatedAt());
return todo;
}
这个可以变得更简洁如下。
public Todo convert(TodoForm form) {
Mapper dozerMapper = DozerBeanMapperBuilder.buildDefault();
return dozerMapper.map(form, Todo.class);
}
请务必查阅TERASOLUNA指南,了解如何使用Dozer。
使用杜泽斯普林特启动器
这是一个用于在Spring Boot中使用Dozer的启动器。
通过使用Spring Boot的自动配置机制,可以自动为Spring Boot应用程序定义使用Dozer的Bean。开发者只需添加dozer-spring-boot-starter作为依赖即可。
pom.xml文件
<dependencies>
<dependency>
<groupId>com.github.dozermapper</groupId>
<artifactId>dozer-spring-boot-starter</artifactId>
<version>6.5.0</version>
</dependency>
</dependencies>
src/main/java/*/Application.java的中文翻译
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
主类没有对Spring Boot应用程序的默认设置进行任何更改。
使用Dozer的类
这里将尝试在Controller中使用。
除了使用Dozer之外,尽可能省略其他元素。
src/main/java/*/web/TodoController.java的内容
@Controller
@RequestMapping("todo")
public class TodoController {
// (1)
@Autowired
private Mapper dozerMapper;
@Autowired
private TodoService todoService;
@PostMapping
public String create(TodoForm form) {
// (2)
Todo todo = dozerMapper.map(form, Todo.class);
todoService.create(todo);
// ommitted.
}
}
(1) 由于Mapper会自动设置,所以只需注入即可使用。
使用Mapper的map方法复制Bean。
自定义映射
在Dozer的默认设置中,会自动将源和目标中具有相同名称的属性进行复制。
若要复制具有不同名称的属性,则需要使用自定义映射。
Dozer的设置可以通过XML和Java配置来定义。您可以使用任何一种方式,但需要注意的是XML会提到后面的注意事项。
本次根据Spring Boot的Java Config设置,我们将使用Java Config来定义自定义映射。
- マッピング定義XML
DozerConfig.java 将位于 src/main/java 目录下。
@Configuration
public class DozerConfig {
@Bean
public BeanMappingBuilder mappingDestinationTodo() {
return new BeanMappingBuilder() {
@Override
protected void configure() {
mapping(type(TodoForm.class), type(Todo.class))
.fields(field("todiTitle"), field("title"));
}
};
}
}
为了进行自定义映射,定义BeanMappingBuilder中的Bean。BeanMappingBuilder一旦定义完成,将自动应用。
由于字段名称是以字符串指定的,所以我们必须在测试中确认指定是否正确。
注意。
您可以使用@Component而不是@Bean进行定义。
如果使用@Component,则一个自定义映射将对应一个类。
改变行为
通过定制Dozer的复制行为,可以实现更灵活的复制。在这里,我们尝试修改,当源属性为空时不进行复制。
src/main/resources/application.yml 可安排的程序文件位置在 src/main/resources/application.yml
dozer:
mapping-files:
- classpath:configuration.dozer.xml
src/main/resources/configuration.dozer.xml的自然语言转述:配置文件中的dozer.xml。
<?xml version="1.0" encoding="UTF-8"?>
<mappings xmlns="http://dozermapper.github.io/schema/bean-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mapping http://dozermapper.github.io/schema/bean-mapping.xsd">
<configuration>
<map-null>false</map-null>
</configuration>
</mappings>
在Dozer的设置中,从XML中加载了配置,当源属性为null时,将不会被复制。
刚才虽然说过要用Java Config来进行配置,但是自然而然地开始使用了XML。为什么要这样做呢…
Spring Boot + Dozer的注意事项
在XML的标签中没有对应的Java Config。
是的,没有其他选择。
唯一能够设定总体行为的方法就是使用XML的。
无法在dozer.mapping-files属性中使用通配符
勉強が必要であるにも関わらず、XMLを使用することとなった。
根据之前的TERASOLUNA指南的行为,如果尝试使用通配符读取多个XML文件,将会导致FileNotFoundException异常。
根据DozerMapper#702,由于Spring的@Value和Spring Boot的@ConfigurationProperties的行为差异,似乎在Boot中无法解析通配符。
在dozer.mapping-files属性中,需要逐个指定XML文件。因此,整体行为应该通过XML来定义,而个别映射则应该在Java Config中进行定义。
在参考文献和DozerProperties的Javadoc中,我已经用通配符指定了,但你没有测试过吗?
在Java 11中,用于解析XML的JAXB不再包含在JDK中。
在使用XML时不得已,…
由于Dozer现在使用JAXB来解析XML,因此在使用不包含Java 11及以上版本的JDK时需要注意。
注意。
您也可以使用传统的Dozer解析器来解析XML,但这样会增加更多的设置文件w。src/main/resources/dozer.properties
dozer.xml.use-jaxb-mapping-engine = false
虽然系统属性和环境变量也可以,但根据操作环境来确定是否应该设置是不现实的。
JUnit测试用例
在JUnit测试用例中,由于使用不同的测试用自动配置而导致配置有所不同,因此请注意。
如果使用@SpringBootTest
读取所有的Bean。
在这种情况下,没有必要考虑使用Dozer。
如果使用@WebMvcTest等工具
为了轻量化,只加载了有限的Bean,不会加载自定义的Auto-Config或@Configuration类等。
在这种情况下,需要进行一些配置才能使用Dozer。
@ImportAutoConfiguration -> DozerのAuto-Configを読み込みます。
@Import -> カスタムマッピングを読み込みます。
src/test/java/*/web/TodoControllerTest.java的中文翻译:
src/test/java/*/web/TodoControllerTest.java的中国式的中文。
@WebMvcTest
@ImportAutoConfiguration(DozerAutoConfiguration.class) // (1)
@Import(DozerConfig.class) // (2)
class TodoControllerTest {
@Autowired
MockMvc mvc;
@Test
void testCreate() throws Exception {
// execute & assert
mvc.perform(post("/todo").param("todoTitle", "sample"))
.andExpect(status().isOk());
}
(1) 使用@ImportAutoConfiguration在DozerAutoConfiguration类中进行Dozer的设置加载。
(2) 使用@Import导入自定义映射的@Configuration类。也可以使用数组导入多个类。
注意。
如果使用@Component创建自定义映射,则可以通过@ComponentScan来替代@Import来进行加载。
总结
由于Dozer的Starter被古老API所拖累,作为Boot的Starter,似乎缺少一些优化。
如果想要使用Java Config,在使用XML和Java Config并存的情况下,有些困扰的问题,但是在实际开发中使用Dozer时,可能需要考虑如何集中整体行为以及如何管理自定义映射等问题,所以从某种意义上说,可能更容易分开处理,这样可能更好。