Spring 框架中的数据转换和格式化:使用 Converter 和 Formatter 进行数据处理
Spring 框架中的数据转换和格式化:使用 Converter 和 Formatter 进行数据处理
在开发 Java Web 应用时,特别是使用 Spring Framework 进行后端开发时,数据的格式化和转换是常见的需求。例如,数据可能需要从字符串转换为日期,或者将对象从一个类型转换为另一个类型。Spring 提供了两种重要机制来处理这类需求:Converter 和 Formatter。它们分别用于不同的场景,但本质上都涉及到数据类型的转换和格式化。本文将详细介绍如何在 Spring 中使用 Converter 和 Formatter 来进行数据处理。
- 数据转换和格式化的概述
数据转换:将一种类型的数据转换为另一种类型的数据。在 Spring 中,Converter 和 Formatter 提供了用于转换的机制。
数据格式化:将数据从一个特定的格式转换为另一种格式(通常是字符串)。比如,将日期类型转换为字符串类型,或者将字符串类型转化为指定格式的日期。
在 Spring 应用程序中,常常会遇到类似的需求,如:
将用户输入的字符串日期转换为 Java 的 LocalDate 或 Date 类型。
将日期对象格式化为用户友好的字符串形式。
将枚举类型转换为字符串表示。
2. Spring 中的 Converter
Converter 是 Spring 中用于类型转换的接口。它通常用于两个类型之间的转换,比如将一个 String 转换为 Date 或者将 Integer 转换为 Double 等。
2.1. Converter 接口
Converter 是一个泛型接口,定义了一个方法 convert(S source),用于将源对象 S 转换为目标类型 T。
public interface Converter<S, T> {
T convert(S source);
}
2.2. 自定义 Converter
假设我们有一个场景:用户输入的字符串日期 “2025-01-19” 需要转换为 LocalDate 类型。我们可以实现 Converter 接口来自定义转换逻辑。
import org.springframework.core.convert.converter.Converter;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class StringToLocalDateConverter implements Converter<String, LocalDate> {
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
@Override
public LocalDate convert(String source) {
return LocalDate.parse(source, formatter);
}
}
2.3. 注册 Converter
为了让 Spring 识别并使用这个自定义的 Converter,我们需要将其注册到 Spring 的 ConversionService 中。通常,我们可以在一个配置类中进行注册。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.support.FormattingConversionService;
import org.springframework.format.support.DefaultFormattingConversionService;
@Configuration
public class ConverterConfig {
@Bean
public FormattingConversionService conversionService() {
FormattingConversionService conversionService = new DefaultFormattingConversionService();
conversionService.addConverter(new StringToLocalDateConverter());
return conversionService;
}
}
2.4. 使用 Converter
一旦注册了转换器,我们就可以通过注入 ConversionService 来使用它进行数据转换。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.core.convert.ConversionService;
@Service
public class DateService {
@Autowired
private ConversionService conversionService;
public LocalDate convertStringToDate(String dateString) {
return conversionService.convert(dateString, LocalDate.class);
}
}
- Spring 中的 Formatter
Formatter 接口与 Converter 类似,但它主要用于对象的格式化(通常是字符串格式化)和解析。它通常用于支持用户输入的格式化、Web 表单数据的解析等。
3.1. Formatter 接口
Formatter 是一个接口,定义了两个方法:
parse(String text, Locale locale):用于将字符串解析为对象。
print(T object, Locale locale):用于将对象转换为字符串。
public interface Formatter<T> {
T parse(String text, Locale locale) throws ParseException;
String print(T object, Locale locale);
}
3.2. 自定义 Formatter
假设我们需要格式化 LocalDate 类型的数据,将其转换为 yyyy-MM-dd 格式的字符串,并且支持将格式化字符串转换回 LocalDate。
import org.springframework.format.Formatter;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class LocalDateFormatter implements Formatter<LocalDate> {
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
@Override
public LocalDate parse(String text, Locale locale) throws ParseException {
return LocalDate.parse(text, formatter);
}
@Override
public String print(LocalDate object, Locale locale) {
return object != null ? object.format(formatter) : "";
}
}
3.3. 注册 Formatter
类似于 Converter,我们需要将 Formatter 注册到 Spring 的 FormatterRegistry 中。可以通过 @EnableWebMvc 注解启用 Web MVC 配置,或者在配置类中进行注册。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class FormatterConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new LocalDateFormatter());
}
}
3.4. 使用 Formatter
在控制器中,可以通过使用 @RequestParam 或 @PathVariable 自动将格式化的字符串绑定到 LocalDate 类型。
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
@RestController
public class DateController {
@GetMapping("/parseDate")
public String parseDate(@RequestParam LocalDate date) {
return "Parsed date is: " + date;
}
}
- Converter 与 Formatter 的区别
特性 Converter Formatter
用途 类型之间的转换(如 String 转 Date) 格式化和解析对象,通常用于字符串和对象之间的转换
方法 convert(S source) parse(String text, Locale locale) 和 print(T object, Locale locale)
主要用途 转换不同类型的数据(如 String 转 Integer) 格式化对象(如将日期格式化为字符串) - 小结
Spring 提供的 Converter 和 Formatter 接口为我们提供了强大的数据处理功能。通过 Converter,我们可以轻松地将一种类型的数据转换为另一种类型;而通过 Formatter,我们能够灵活地格式化和解析对象数据。在实际开发中,使用这些工具不仅可以简化代码,还能提高应用的可维护性和扩展性。
使用 Converter:当需要在不同数据类型之间转换时使用。
使用 Formatter:当需要在用户输入与对象之间进行格式化或解析时使用。
通过这两者,Spring 可以帮助我们处理大量的数据转换和格式化操作,提升开发效率和代码质量。
在 Spring 中,Converter 和 Formatter 是常见的工具,用于处理数据转换和格式化。以下是几个具体的使用案例,展示了如何在不同场景中使用这些工具。
- 使用 Converter 进行日期格式的转换
假设我们有一个用户输入的字符串表示日期,例如 “2025-01-19”,我们希望将它转换为 LocalDate 类型。
1.1. 自定义 Converter
import org.springframework.core.convert.converter.Converter;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class StringToLocalDateConverter implements Converter<String, LocalDate> {
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
@Override
public LocalDate convert(String source) {
return LocalDate.parse(source, formatter);
}
}
1.2. 注册 Converter 到 Spring
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.format.support.FormattingConversionService;
@Configuration
public class ConverterConfig {
@Bean
public FormattingConversionService conversionService() {
FormattingConversionService conversionService = new DefaultFormattingConversionService();
conversionService.addConverter(new StringToLocalDateConverter());
return conversionService;
}
}
1.3. 使用 Converter 进行转换
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.core.convert.ConversionService;
@Service
public class DateService {
@Autowired
private ConversionService conversionService;
public LocalDate convertStringToDate(String dateString) {
return conversionService.convert(dateString, LocalDate.class);
}
}
1.4. 调用案例
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
@RestController
public class DateController {
@Autowired
private DateService dateService;
@GetMapping("/convertDate")
public String convertDate(@RequestParam String date) {
LocalDate localDate = dateService.convertStringToDate(date);
return "Converted Date: " + localDate;
}
}
使用场景:当用户输入字符串表示的日期时,我们使用 Converter 将其转换为 LocalDate 类型。
- 使用 Formatter 进行对象的格式化和解析
假设我们要将 LocalDate 类型的对象转换为字符串,并能够将用户输入的日期字符串解析回 LocalDate。
2.1. 自定义 Formatter
import org.springframework.format.Formatter;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class LocalDateFormatter implements Formatter<LocalDate> {
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
@Override
public LocalDate parse(String text, Locale locale) throws ParseException {
return LocalDate.parse(text, formatter);
}
@Override
public String print(LocalDate object, Locale locale) {
return object != null ? object.format(formatter) : "";
}
}
2.2. 注册 Formatter 到 Spring
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class FormatterConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new LocalDateFormatter());
}
}
2.3. 使用 Formatter 进行格式化
在控制器中,可以通过 Spring 自动将 LocalDate 格式化为字符串,并解析用户输入的日期字符串。
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
@RestController
public class DateController {
@GetMapping("/formattedDate")
public String formattedDate(@RequestParam LocalDate date) {
return "Formatted Date: " + date;
}
}
使用场景:当用户输入 yyyy-MM-dd 格式的字符串日期时,Spring 自动将其解析为 LocalDate 对象。同时,我们也能将 LocalDate 对象格式化为字符串返回给前端。
- 使用 Converter 和 Formatter 结合进行复杂数据转换
假设我们有一个 Product 类,它包含 Date 类型的字段,而我们需要将日期字段从字符串转换为 LocalDate,并返回格式化的字符串。
3.1. Product 类定义
public class Product {
private String name;
private LocalDate releaseDate;
// getters and setters
}
3.2. 自定义 Converter 用于字符串转换为 LocalDate
import org.springframework.core.convert.converter.Converter;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class StringToLocalDateConverter implements Converter<String, LocalDate> {
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
@Override
public LocalDate convert(String source) {
return LocalDate.parse(source, formatter);
}
}
3.3. 自定义 Formatter 用于格式化 LocalDate
import org.springframework.format.Formatter;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class LocalDateFormatter implements Formatter<LocalDate> {
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
@Override
public LocalDate parse(String text, Locale locale) throws ParseException {
return LocalDate.parse(text, formatter);
}
@Override
public String print(LocalDate object, Locale locale) {
return object != null ? object.format(formatter) : "";
}
}
3.4. 配置 Spring 注册 Converter 和 Formatter
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.format.support.FormattingConversionService;
import org.springframework.core.convert.converter.Converter;
@Configuration
public class ProductConfig {
@Bean
public FormattingConversionService conversionService() {
FormattingConversionService conversionService = new DefaultFormattingConversionService();
conversionService.addConverter(new StringToLocalDateConverter());
conversionService.addFormatter(new LocalDateFormatter());
return conversionService;
}
}
3.5. 使用案例
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
@RestController
public class ProductController {
@Autowired
private ConversionService conversionService;
@GetMapping("/addProduct")
public String addProduct(@RequestParam String name, @RequestParam String releaseDate) {
Product product = new Product();
product.setName(name);
product.setReleaseDate(conversionService.convert(releaseDate, LocalDate.class));
return "Product Name: " + product.getName() + ", Release Date: " + product.getReleaseDate();
}
}
使用场景:在表单提交时,用户输入的日期字符串 “2025-01-19” 将被自动转换为 LocalDate 类型,并且可以通过 Formatter 将日期格式化为不同的输出格式。
- 使用 Converter 转换枚举类型
假设我们有一个 OrderStatusEnum 枚举类,需要将字符串状态 “WAITING_PAYMENT” 转换为对应的枚举类型 OrderStatusEnum.WAITING_PAYMENT。
4.1. 枚举类
public enum OrderStatusEnum {
WAITING_PAYMENT("WAITING_PAYMENT"),
WAITING_DELIVERY("WAITING_DELIVERY");
private final String value;
OrderStatusEnum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
4.2. 自定义 Converter
import org.springframework.core.convert.converter.Converter;
public class StringToOrderStatusEnumConverter implements Converter<String, OrderStatusEnum> {
@Override
public OrderStatusEnum convert(String source) {
for (OrderStatusEnum status : OrderStatusEnum.values()) {
if (status.getValue().equals(source)) {
return status;
}
}
return null;
}
}
4.3. 注册 Converter
@Configuration
public class ConverterConfig {
@Bean
public FormattingConversionService conversionService() {
FormattingConversionService conversionService = new DefaultFormattingConversionService();
conversionService.addConverter(new StringToOrderStatusEnumConverter());
return conversionService;
}
}
4.4. 使用 Converter
@RestController
public class OrderController {
@Autowired
private ConversionService conversionService;
@GetMapping("/orderStatus")
public String getOrderStatus(@RequestParam String status) {
OrderStatusEnum orderStatus = conversionService.convert(status, OrderStatusEnum.class);
return "Converted Order Status: " + orderStatus;
}
}
使用场景:当用户通过字符串输入订单状态时,Spring 自动将其转换为对应的枚举值。
这些案例展示了如何在 Spring 框架中使用 Converter 和 Formatter 来处理各种常见的数据转换和格式化需求。通过自定义转换器和格式化器,我们可以灵活地控制数据的格式化和转换行为,从而提升应用程序的灵活性和可维护性。