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时,可能需要考虑如何集中整体行为以及如何管理自定义映射等问题,所以从某种意义上说,可能更容易分开处理,这样可能更好。

广告
将在 10 秒后关闭
bannerAds