简体   繁体   English

spring-cloud-feign 客户端和 @RequestParam 与日期类型

[英]spring-cloud-feign Client and @RequestParam with Date type

This time I was working with Declarative REST Client, Feign in some Spring Boot App.这次我正在使用声明式 REST 客户端,在一些 Spring Boot 应用程序中使用 Feign。

What I wanted to achieve is to call one of my REST API's, which looks like:我想要实现的是调用我的 REST API 之一,如下所示:

@RequestMapping(value = "/customerslastvisit", method = RequestMethod.GET)
    public ResponseEntity customersLastVisit(
            @RequestParam(value = "from", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date from,
            @RequestParam(value = "to", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date to) {

As You can see, the API accepts calls with from and to Date params formatted like (yyyy-MM-dd)如您所见,API 接受格式为(yyyy-MM-dd) from 和 to 日期参数的调用

In order to call that API, I've prepared following piece of @FeignClient :为了调用该 API,我准备了以下一段@FeignClient

@FeignClient("MIIA-A")
public interface InboundACustomersClient {
    @RequestMapping(method = RequestMethod.GET, value = "/customerslastvisit")
    ResponseEntity customersLastVisit(
            @RequestParam(value = "from", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date from,
            @RequestParam(value = "to", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date to);
}

Generally, almost copy-paste.一般来说,几乎复制粘贴。 And now somewhere in my boot App, I use that:现在在我的启动应用程序的某个地方,我使用它:

DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
ResponseEntity response = inboundACustomersClient.customersLastVisit(formatter.parse(formatter.format(from)),
        formatter.parse(formatter.format(to)));

And, what I get back is that而且,我得到的是

nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.RequestParam @org.springframework.format.annotation.DateTimeFormat java.util.Date] for value 'Sun May 03 00:00:00 CEST 2015';嵌套异常是 org.springframework.core.convert.ConversionFailedException:无法从类型 [java.lang.String] 转换为类型 [@org.springframework.web.bind.annotation.RequestParam @org.springframework.format.annotation.DateTimeFormat java.util.Date] 值“Sun May 03 00:00:00 CEST 2015”;

nested exception is java.lang.IllegalArgumentException: Unable to parse 'Sun May 03 00:00:00 CEST 2015'嵌套异常是 java.lang.IllegalArgumentException: Unable to parse 'Sun May 03 00:00:00 CEST 2015'

So, the question is, what am I doing wrong with request, that it doesn't parse to "date-only" format before sending to my API?所以,问题是,我对请求做错了什么,它在发送到我的 API 之前没有解析为“仅日期”格式? Or maybe it is a pure Feign lib problem?或者它可能是一个纯粹的 Feign lib 问题?

You should create and register a feign formatter to customize the date format您应该创建并注册一个 feign 格式化程序来自定义日期格式

@Component
public class DateFormatter implements Formatter<Date> {

    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");

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

    @Override
    public String print(Date date, Locale locale) {
        return formatter.format(date);
    }
}


@Configuration
public class FeignFormatterRegister implements FeignFormatterRegistrar {

    @Override
    public void registerFormatters(FormatterRegistry registry) {
        registry.addFormatter(new DateFormatter());
    }
}

Another simple solution is to use default interface method for Date to String conversion like另一个简单的解决方案是使用默认接口方法进行日期到字符串的转换,例如

@RequestMapping(value = "/path", method = GET)
List<Entity> byDate(@RequestParam("date") String date);

default List<Entity> date(Date date) {
    return date(new SimpleDateFormat("dd.MM.yyyy").format(validityDate));
}

Here is a solution that is thread-safe and does not register a default date formatter in your spring universe.这是一个线程安全的解决方案,不会在您的 spring 宇宙中注册默认日期格式化程序。 Keep in mind though, that this formatter will be used for all feign clients as new default and that you should actually use joda date time or the new java date time instead:但请记住,此格式化程序将用于所有 feign 客户端作为新的默认值,并且您实际上应该使用 joda 日期时间或新的 java 日期时间:

@Configuration
public class FeignFormatterRegister implements FeignFormatterRegistrar {

    @Override
    public void registerFormatters(FormatterRegistry registry) {
        registry.addFormatter(new DateFormatter());
    }

    /*
     * SimpleDateFormat is not thread safe!
     * consider using joda time or java8 time instead
     */
    private static class DateFormatter implements Formatter<Date> {
        static final ThreadLocal<SimpleDateFormat> FORMAT = ThreadLocal.withInitial(
                () -> new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
        );

        @Override
        public Date parse(String text, Locale locale) throws ParseException {
            return FORMAT.get().parse(text);
        }

        @Override
        public String print(Date date, Locale locale) {
            return FORMAT.get().format(date);
        }
    }
}

You can just use an expander object instead.您可以只使用扩展器对象。

 /**
 * @see com.x.y.z.rest.configuration.SomeController#search(Integer, Integer, Date, Date)
 */
@RequestLine("GET /configuration/{customerId}?&startDate={startDate}")
Set<AnObject> searchSomething(@Param("customerId") Integer customerId, @Param(value = "startDate", expander = FeignDateExpander.class) Date startDate);


public class FeignDateExpander implements Param.Expander {

@Override
public String expand(Object value) {
    Date date = (Date)value;
    return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
}
}

The feign client now (Dec 2020) works fine using the syntax in the original question above and a java.time.LocalDate as the parameter. feign 客户端现在(2020 年 12 月)使用上述原始问题中的语法和java.time.LocalDate作为参数可以正常工作。 That is, you can use:也就是说,您可以使用:

  @FeignClient(name = "YOUR-SERVICE")
  interface ClientSpec {
    @RequestMapping(value = "/api/something", method = RequestMethod.GET)
    String doSomething(
        @RequestParam("startDate") 
        @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) 
        LocalDate startDate);
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM