6

这次我在一些 Spring Boot 应用程序中使用声明式 REST 客户端 Feign。

我想要实现的是调用我的 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) {

如您所见,API 接受使用 from 和 to 日期参数的调用,格式如下(yyyy-MM-dd)

为了调用该 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);
}

一般来说,几乎是复制粘贴。现在在我的启动应用程序的某个地方,我使用它:

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

而且,我得到的是

嵌套异常是 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';

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

所以,问题是,我对请求做错了什么,它在发送到我的 API 之前没有解析为“仅限日期”格式?或者它可能是一个纯粹的 Feign lib 问题?

4

5 回答 5

9

您应该创建并注册一个 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());
    }
}
于 2016-04-06T14:44:55.310 回答
1

feign 客户端现在(2020 年 12 月)使用上面原始问题中的语法和 ajava.time.LocalDate作为参数可以正常工作。也就是说,您可以使用:

  @FeignClient(name = "YOUR-SERVICE")
  interface ClientSpec {
    @RequestMapping(value = "/api/something", method = RequestMethod.GET)
    String doSomething(
        @RequestParam("startDate") 
        @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) 
        LocalDate startDate);
  }
于 2020-12-16T17:24:15.903 回答
0

这是一个线程安全的解决方案,并且不会在您的 Spring Universe 中注册默认日期格式化程序。但请记住,此格式化程序将作为新的默认值用于所有 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);
        }
    }
}
于 2019-12-12T08:30:15.577 回答
0

另一个简单的解决方案是使用默认接口方法进行日期到字符串的转换,例如

@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));
}
于 2017-09-20T16:45:42.200 回答
0

您可以只使用扩展器对象。

 /**
 * @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);
}
}
于 2020-05-20T21:47:34.047 回答