返回

使用Spring Boot全局配置LocalDateTime、LocalDate的入参转换

后端

Spring Boot中处理LocalDateTime和LocalDate参数的指南

简介

Spring Boot是一个流行的Java框架,它简化了RESTful API和Web应用程序的开发。Spring Boot原生不支持将LocalDateTime和LocalDate作为参数传递给应用程序。本文将提供三种方法来解决这一限制:HTTP消息转换器、转换器和自定义注解。

HTTP消息转换器

HTTP消息转换器可以将HTTP请求和响应中的数据转换为Java对象。我们可以实现一个自定义的消息转换器来处理LocalDateTime和LocalDate。以下是实现的代码示例:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

public class LocalDateTimeHttpMessageConverter implements HttpMessageConverter<LocalDateTime> {

    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    public boolean canRead(Class<?> clazz, MediaType mediaType) {
        return LocalDateTime.class.equals(clazz);
    }

    @Override
    public boolean canWrite(Class<?> clazz, MediaType mediaType) {
        return false;
    }

    @Override
    public List<MediaType> getSupportedMediaTypes() {
        return Collections.singletonList(MediaType.APPLICATION_JSON);
    }

    @Override
    public LocalDateTime read(Class<? extends LocalDateTime> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        String dateString = new String(inputMessage.getBody());
        return LocalDateTime.parse(dateString, DATE_TIME_FORMATTER);
    }

    @Override
    public void write(LocalDateTime localDateTime, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        throw new UnsupportedOperationException("LocalDateTimeHttpMessageConverter does not support write operations.");
    }
}

转换器

Spring Boot还提供了转换器,可以将字符串转换为Java对象。我们可以实现一个自定义的转换器来处理LocalDateTime和LocalDate。以下是实现的代码示例:

import java.time.LocalDateTime;

import org.springframework.format.Formatter;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LocalDateTimeConverterController {

    @GetMapping("/api/local-date-time")
    public LocalDateTime getLocalDateTime(@RequestParam LocalDateTime localDateTime) {
        return localDateTime;
    }

    @Bean
    public Formatter<LocalDateTime> localDateTimeFormatter() {
        return new LocalDateTimeFormatter();
    }

    private static class LocalDateTimeFormatter implements Formatter<LocalDateTime> {

        private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        @Override
        public LocalDateTime parse(String text, Locale locale) throws ParseException {
            return LocalDateTime.parse(text, DATE_TIME_FORMATTER);
        }

        @Override
        public String print(LocalDateTime localDateTime, Locale locale) {
            return localDateTime.format(DATE_TIME_FORMATTER);
        }
    }
}

自定义注解

我们还可以创建一个自定义的注解来处理LocalDateTime和LocalDate。以下是实现的代码示例:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import java.time.LocalDateTime;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.FIELD})
public @interface LocalDateTimeParam {

    String format() default "yyyy-MM-dd HH:mm:ss";
}
import java.time.LocalDateTime;

import javax.validation.constraints.NotNull;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.format.Formatter;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class LocalDateTimeConverterApplication {

    public static void main(String[] args) {
        SpringApplication.run(LocalDateTimeConverterApplication.class, args);
    }

    @GetMapping("/api/local-date-time")
    public LocalDateTime getLocalDateTime(@NotNull @LocalDateTimeParam LocalDateTime localDateTime) {
        return localDateTime;
    }

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.addValidators(new LocalDateTimeValidator());
    }

    @Bean
    public Formatter<LocalDateTime> localDateTimeFormatter() {
        return new LocalDateTimeFormatter();
    }

    private static class LocalDateTimeFormatter implements Formatter<LocalDateTime> {

        private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        @Override
        public LocalDateTime parse(String text, Locale locale) throws ParseException {
            return LocalDateTime.parse(text, DATE_TIME_FORMATTER);
        }

        @Override
        public String print(LocalDateTime localDateTime, Locale locale) {
            return localDateTime.format(DATE_TIME_FORMATTER);
        }
    }

    private static class LocalDateTimeValidator implements Validator {

        @Override
        public boolean supports(Class<?> clazz) {
            return LocalDateTime.class.equals(clazz);
        }

        @Override
        public void validate(Object target, Errors errors) {
            LocalDateTime localDateTime = (LocalDateTime) target;
            if (localDateTime == null) {
                errors.rejectValue("localDateTime", "localDateTime.null", "LocalDateTime cannot be null.");
            }
        }
    }
}

结论

通过使用HTTP消息转换器、转换器或自定义注解,我们可以轻松地在Spring Boot应用程序中处理LocalDateTime和LocalDate作为参数。本文提供了所有三种方法的完整代码示例,以及详细的解释。开发人员可以根据他们的特定需求选择最合适的解决方案。

常见问题解答

  1. 为什么Spring Boot原生不支持LocalDateTime和LocalDate参数?
    由于历史原因,Spring Boot原生不支持LocalDateTime和LocalDate参数。这些类型在Java 8中引入,而Spring Boot在Java 7和Java 8环境中运行。

  2. 哪种方法最适合处理LocalDateTime和LocalDate参数?
    这取决于应用程序的具体需求。对于需要对LocalDateTime和LocalDate进行特定格式化或验证的应用程序,自定义注解是最灵活的方法。对于不需要额外处理的简单应用程序,HTTP消息转换器或转换器可能就足够了。

  3. 是否可以自定义HTTP消息转换器的格式?
    是的,可以通过覆盖supportsread方法来自定义HTTP消息转换器的格式。

  4. 是否可以自定义转换器的格式?
    是的,可以通过覆盖parseprint方法来自定义转换器的格式。

  5. 自定义注解是否需要额外的配置?
    是的,自定义注解需要在@InitBinder方法中注册,以将其添加到Web数据绑定器。