RestTemplate——解决Date类型值自动转为时间戳问题

RestTemplate——解决Date类型值自动转为时间戳问题

1. 问题描述

使用RestTemplate发送post请求,传参为pojo类集合,pojo类中有Date数据类型的字段。原本时间值为yyyy-MM-dd HH:mm:ss格式,但接收端收到的是时间戳格式。

@Autowired
protected RestTemplate restTemplate;

List<User> list = new ArrayList<>();
User user = new User();
user.setCreateTime(new Date());
list.add(user);
restTemplate.postForObject(url, list, JSONObject.class);

2. 网上答案

  1. 加配置

    spring:
      jackson:
        time-zone: GMT+8
        date-format: yyyy-MM-dd HH:mm:ss
    

    配置原本就存在了,所以这个答案无效。

  2. 在字段上添加@JSONField(format = "yyyy-MM-dd HH:mm:ss")

    这个字段的作用是在转换成JSON的时候规定时间格式,跟当前问题无直接关系。

    但是可以通过先转换为JSON字符串,然后将JSON字符串做为参数去请求,这样是可以解决自动转时间戳问题的

    String params = JSON.toJSONString(list);
    restTemplate.postForObject(url, params, JSONObject.class);
    

    但这样就需要在每个pojo类的Date数据类型字段上面添加注解,并不是很好的解决方法,这里寻找可以全局设定的解决方案。

3. 解决路程

  1. 确定是发送端还是接收端转换成时间戳的

    restTemplate.postForObject()发送请求时打断点,可以看到参数已经是时间戳了,所以确定是在发送端将参数转换成了时间戳。

  2. restTemplate.postForObject()打断点分析是哪里改成了时间戳

    源码关键代码:

    @Nullable
    public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables) throws RestClientException {
        RequestCallback requestCallback = this.httpEntityCallback(request, responseType);
        HttpMessageConverterExtractor<T> responseExtractor = new HttpMessageConverterExtractor(responseType, this.getMessageConverters(), this.logger);
        return this.execute(url, HttpMethod.POST, requestCallback, responseExtractor, (Object[])uriVariables);
    }
    
    
    public HttpEntityRequestCallback(@Nullable Object requestBody, @Nullable Type responseType) {
        super(responseType);
        if (requestBody instanceof HttpEntity) {
            this.requestEntity = (HttpEntity)requestBody;
        } else if (requestBody != null) {
            this.requestEntity = new HttpEntity(requestBody);
        } else {
            this.requestEntity = HttpEntity.EMPTY;
        }
    
    }
    
    @Nullable
    protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
        Assert.notNull(url, "URI is required");
        Assert.notNull(method, "HttpMethod is required");
        ClientHttpResponse response = null;
    
        Object var14;
        try {
            ClientHttpRequest request = this.createRequest(url, method);
            if (requestCallback != null) {
                requestCallback.doWithRequest(request);
            }
    
            response = request.execute();
            this.handleResponse(url, method, response);
            var14 = responseExtractor != null ? responseExtractor.extractData(response) : null;
        } catch (IOException var12) {
            String resource = url.toString();
            String query = url.getRawQuery();
            resource = query != null ? resource.substring(0, resource.indexOf(63)) : resource;
            throw new ResourceAccessException("I/O error on " + method.name() + " request for \"" + resource + "\": " + var12.getMessage(), var12);
        } finally {
            if (response != null) {
                response.close();
            }
    
        }
    
        return var14;
    }
    
    
    public void doWithRequest(ClientHttpRequest httpRequest) throws IOException {
        super.doWithRequest(httpRequest);
        Object requestBody = this.requestEntity.getBody();
        if (requestBody == null) {
            HttpHeaders httpHeaders = httpRequest.getHeaders();
            HttpHeaders requestHeaders = this.requestEntity.getHeaders();
            if (!requestHeaders.isEmpty()) {
                requestHeaders.forEach((key, values) -> {
                    httpHeaders.put(key, new LinkedList(values));
                });
            }
    
            if (httpHeaders.getContentLength() < 0L) {
                httpHeaders.setContentLength(0L);
            }
    
        } else {
            Class<?> requestBodyClass = requestBody.getClass();
            Type requestBodyType = this.requestEntity instanceof RequestEntity ? ((RequestEntity)this.requestEntity).getType() : requestBodyClass;
            HttpHeaders httpHeadersx = httpRequest.getHeaders();
            HttpHeaders requestHeadersx = this.requestEntity.getHeaders();
            MediaType requestContentType = requestHeadersx.getContentType();
            Iterator var8 = RestTemplate.this.getMessageConverters().iterator();
    
            while(var8.hasNext()) {
                HttpMessageConverter<?> messageConverter = (HttpMessageConverter)var8.next();
                if (messageConverter instanceof GenericHttpMessageConverter) {
                    GenericHttpMessageConverter<Object> genericConverter = (GenericHttpMessageConverter)messageConverter;
                    if (genericConverter.canWrite((Type)requestBodyType, requestBodyClass, requestContentType)) {
                        if (!requestHeadersx.isEmpty()) {
                            requestHeadersx.forEach((key, values) -> {
                                httpHeadersx.put(key, new LinkedList(values));
                            });
                        }
    
                        this.logBody(requestBody, requestContentType, genericConverter);
                        genericConverter.write(requestBody, (Type)requestBodyType, requestContentType, httpRequest);
                        return;
                    }
                } else if (messageConverter.canWrite(requestBodyClass, requestContentType)) {
                    if (!requestHeadersx.isEmpty()) {
                        requestHeadersx.forEach((key, values) -> {
                            httpHeadersx.put(key, new LinkedList(values));
                        });
                    }
    
                    this.logBody(requestBody, requestContentType, messageConverter);
                    messageConverter.write(requestBody, requestContentType, httpRequest);
                    return;
                }
            }
    
            String message = "No HttpMessageConverter for " + requestBodyClass.getName();
            if (requestContentType != null) {
                message = message + " and content type \"" + requestContentType + "\"";
            }
    
            throw new RestClientException(message);
        }
    }
    

    从源码可以看出,在发送之前会进行参数转换

    Iterator var8 = RestTemplate.this.getMessageConverters().iterator();
    
    while(var8.hasNext()) {
        HttpMessageConverter<?> messageConverter = (HttpMessageConverter)var8.next();
        if (messageConverter instanceof GenericHttpMessageConverter) {
            GenericHttpMessageConverter<Object> genericConverter = (GenericHttpMessageConverter)messageConverter;
            if (genericConverter.canWrite((Type)requestBodyType, requestBodyClass, requestContentType)) {
                if (!requestHeadersx.isEmpty()) {
                    requestHeadersx.forEach((key, values) -> {
                        httpHeadersx.put(key, new LinkedList(values));
                    });
                }
    
                this.logBody(requestBody, requestContentType, genericConverter);
                genericConverter.write(requestBody, (Type)requestBodyType, requestContentType, httpRequest);
                return;
            }
        } else if (messageConverter.canWrite(requestBodyClass, requestContentType)) {
            if (!requestHeadersx.isEmpty()) {
                requestHeadersx.forEach((key, values) -> {
                    httpHeadersx.put(key, new LinkedList(values));
                });
            }
    
            this.logBody(requestBody, requestContentType, messageConverter);
            messageConverter.write(requestBody, requestContentType, httpRequest);
            return;
        }
    }
    

    而这里转换器实现类为MappingJackson2HttpMessageConverter,而一开始的配置就是配置该类的,那就是说配置没有生效。

    于是,使用Java代码配置MappingJackson2HttpMessageConverter

    @Bean
    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        ObjectMapper mapper = new ObjectMapper();
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        converter.setObjectMapper(mapper);
        return converter;
    }
    

    结果还是不生效,这时候可以将注意力转到RestTemplate配置了;

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
    

    这样初始化RestTemplate,会重新创建一个MappingJackson2HttpMessageConverter对象

    public RestTemplate() {
        this.messageConverters = new ArrayList();
        this.errorHandler = new DefaultResponseErrorHandler();
        this.headersExtractor = new RestTemplate.HeadersExtractor();
        this.messageConverters.add(new ByteArrayHttpMessageConverter());
        this.messageConverters.add(new StringHttpMessageConverter());
        this.messageConverters.add(new ResourceHttpMessageConverter(false));
    
        try {
            this.messageConverters.add(new SourceHttpMessageConverter());
        } catch (Error var2) {
        }
    
        this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
        if (romePresent) {
            this.messageConverters.add(new AtomFeedHttpMessageConverter());
            this.messageConverters.add(new RssChannelHttpMessageConverter());
        }
    
        if (jackson2XmlPresent) {
            this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
        } else if (jaxb2Present) {
            this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
        }
    
        if (jackson2Present) {
            this.messageConverters.add(new MappingJackson2HttpMessageConverter());
        } else if (gsonPresent) {
            this.messageConverters.add(new GsonHttpMessageConverter());
        } else if (jsonbPresent) {
            this.messageConverters.add(new JsonbHttpMessageConverter());
        }
    
        if (jackson2SmilePresent) {
            this.messageConverters.add(new MappingJackson2SmileHttpMessageConverter());
        }
    
        if (jackson2CborPresent) {
            this.messageConverters.add(new MappingJackson2CborHttpMessageConverter());
        }
    
        this.uriTemplateHandler = initUriTemplateHandler();
    }
    

    所以问题转化为RestTemplate怎样初始化可以用到当前的MappingJackson2HttpMessageConverter对象

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder.build();
    }
    

4. 总结

application.yaml中设置jackson时间格式是全局解决该问题的方法,但是要RestTemplate初始化正确,也就是使用到了当前的MappingJackson2HttpMessageConverter,而不是重新初始化。



世界那么大,感谢遇见,未来可期…

欢迎同频共振的那一部分人

作者公众号:Tarzan写bug

在这里插入图片描述

淘宝店:提供一元解决Java问题和其他方面的解决方案,欢迎咨询

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值