vieyahn2017 / javaway

java on the way
5 stars 3 forks source link

11.8 使用restTemplate处理modelAttribute #54

Closed vieyahn2017 closed 5 years ago

vieyahn2017 commented 6 years ago

使用restTemplate处理modelAttribute

vieyahn2017 commented 6 years ago

11.12 终于发现,坑了那么久的问题:

原因竟然是该class不是public的

2018-11-12 09:21:05.533 ERROR 10192 --- [http-nio-8080-exec-9] o.a.c.c.C.[.[.[.0].[dispatcherServlet]   : Servlet.service() for servlet [dispatcherServlet] in context with path [/fusion1.0] threw exception [Request processing failed; nested exception is org.springframework.beans.InvalidPropertyException: Invalid property 'edges[0]' of bean class [com.huawei.bigdata.algorithms.visualization.model.domain.EdgeDTOList]: Illegal attempt to get property 'edges' threw exception; nested exception is org.springframework.beans.NullValueInNestedPathException: Invalid property 'edges' of bean class [com.huawei.bigdata.algorithms.visualization.model.domain.EdgeDTOList]: Could not instantiate property type [com.huawei.bigdata.algorithms.visualization.model.domain.CapitalFlowEdgeDTO] to auto-grow nested property path; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.huawei.bigdata.algorithms.visualization.model.domain.CapitalFlowEdgeDTO]: Is the constructor accessible?; nested exception is java.lang.IllegalAccessException: Class org.springframework.beans.BeanUtils can not access a member of class com.huawei.bigdata.algorithms.visualization.model.domain.CapitalFlowEdgeDTO with modifiers ""] with root cause

java.lang.IllegalAccessException: Class org.springframework.beans.BeanUtils can not access a member of class com.huawei.bigdata.algorithms.visualization.model.domain.CapitalFlowEdgeDTO with modifiers ""
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102) ~[na:1.8.0_131]
    at java.lang.Class.newInstance(Class.java:436) ~[na:1.8.0_131]
    at org.springframework.beans.BeanUtils.instantiate(BeanUtils.java:77) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.AbstractNestablePropertyAccessor.newValue(AbstractNestablePropertyAccessor.java:928) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.AbstractNestablePropertyAccessor.growCollectionIfNecessary(AbstractNestablePropertyAccessor.java:796) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:665) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.AbstractNestablePropertyAccessor.getNestedPropertyAccessor(AbstractNestablePropertyAccessor.java:850) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyAccessorForPropertyPath(AbstractNestablePropertyAccessor.java:827) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:270) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:95) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.validation.DataBinder.applyPropertyValues(DataBinder.java:859) ~[spring-context-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.validation.DataBinder.doBind(DataBinder.java:755) ~[spring-context-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.web.bind.WebDataBinder.doBind(WebDataBinder.java:192) ~[spring-web-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.web.bind.ServletRequestDataBinder.bind(ServletRequestDataBinder.java:106) ~[spring-web-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.bindRequestParameters(ServletModelAttributeMethodProcessor.java:150) ~[spring-webmvc-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:114) ~[spring-web-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121) ~[spring-web-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:158) ~[spring-web-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128) ~[spring-web-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116) ~[spring-webmvc-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963) ~[spring-webmvc-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) ~[spring-webmvc-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872) ~[spring-webmvc-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:648) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123) ~[druid-1.0.26.jar:1.0.26]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105) ~[spring-web-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[spring-web-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:798) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1434) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_131]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_131]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_131]
vieyahn2017 commented 6 years ago

IllegalAccessException: Class A can not access a member of class B 的一种原因分析与解决

2016年12月24日 12:30:28 FserSuN 阅读数:4455 标签: java 异常 class 个人分类: Java 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Revivedsun/article/details/53858033 Caused by: java.lang.IllegalAccessException: Class A can not access a member of class B 的一种原因分析与解决

我在使用到一个java fluent api工具时遇到这个问题,出现异常后调用栈如下。

Caused by: java.lang.IllegalAccessException: Class com.fluentinterface.proxy.BuilderProxy can not access a member of class zk.curator.Person with modifiers "public"
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
    at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
    at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:413)
    at com.fluentinterface.proxy.BuilderProxy.createInstanceFromProperties(BuilderProxy.java:79)
    at com.fluentinterface.proxy.BuilderProxy.invoke(BuilderProxy.java:56)

最后抛出了IllegalAccessException异常,这个异常的定义如下。

An IllegalAccessException is thrown when an application tries to reflectively create an instance (other than an array), 
set or get a field, or invoke a method, but the currently executing method does not have access to the definition of the specified class, 
field, method or constructor.

从异常定义可以看出,由于通过反射的机制创建实例,由于没有权限访问类,域,方法构造器而产生该异常。

通过抛出的异常可以看出,在调用sun.reflect.Reflection.ensureMemberAccess检查访问权限时抛出异常。

if (!verifyMemberAccess(currentClass, memberClass, target, modifiers)) {
             throw new IllegalAccessException("Class " + currentClass.getName() +
                                             " can not access a member of class " +
                                             memberClass.getName() +
                                              " with modifiers \"" +
                                             Modifier.toString(modifiers) +
                                             "\"");
}

该方法内部由于调用verifyMemberAccess,且未满足条件时抛出了异常。

public static boolean  verifyMemberAccess(Class currentClass,
                                             // Declaring class of field
                                             // or method
                                             Class  memberClass,
                                             // May be NULL in case of statics
                                             Object target,
                                             int    modifiers)
{
        // Verify that currentClass can access a field, method, or
        // constructor of memberClass, where that member's access bits are
        // "modifiers".

        boolean gotIsSameClassPackage = false;
        boolean isSameClassPackage = false;

        if (currentClass == memberClass) {
            // Always succeeds
            return true;
        }

        if (!Modifier.isPublic(getClassAccessFlags(memberClass))) {
            isSameClassPackage = isSameClassPackage(currentClass, memberClass);
            gotIsSameClassPackage = true;
            if (!isSameClassPackage) {
                return false;
            }

        ......略
}

可以看到verifyMemberAccess会检查所创建的类是访问描述符是否是public,若不是public,那么检查所创建的类与调用类是否在同一个包下,如果不在同一个包下则返回false。而我在练习使用fluent api 工具时,所定义的类XXX为并不是public,而且和工具类不在一个包下,因此导致IllegalAccessException异常的产生。

class XXX{

}

最后将类修改为public问题解决。可以想到,做这样的检查是为了确保对目标类有权限访问。

vieyahn2017 commented 6 years ago

ribbon通过RestTemplate调用接口获取List时,应使用数组而不能直接使用List 2017年07月20日 10:22:30 书剑零落 阅读数:1209更多 个人分类: Ribbon spring cloud 学习总结 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/shunhua19881987/article/details/75472743

足不出户能上网就能赚钱,月收入过万!! 国化 · 燨燚 想对作者说点什么? 我来说一句 xd03122049 xd03122049: 博主,你这个问题怎么解决的?就是你虽然用了数组,但是还是会遇到序列化的问题. nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of com.kelan.entity.DataSourceConfig[] out of START_OBJECT token at [Source: java.io.PushbackInputStream@582ea164; line: 1, column: 1](1年前#1楼)

vieyahn2017 commented 6 years ago

Spring Resttemplate post方法踩坑记录 2017年11月27日 18:30:16 liubingyu12345 阅读数:5809 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liubingyu12345/article/details/78647709 Spring Resttemplate post方法踩坑记录

项目中有处地方需要通过http post构造restful请求,且需要携带正确的header域, 自然而然想到了用Spring自带的restTemplate,对应post,put,get,delete它都有对应的封装方法。 由于我用的项目框架是SpringBoot,所以使用restTemplate很简单,在启动类XXXApplication类上注入restTemplate即可,如下代码:

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

然后在业务类上注入这个bean即可:

    @Inject
    private RestTemplate restTemplate;
    public void sendPost() {
        .........
        //xxpojo是个pojo类,post请求中要放在http request body域中
        String requestBody = JSONObject.toJSONString(xxpojo);
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        HttpEntity<String> httpEntity = new HttpEntity<String>(requestBody, headers);
        restTemplate.postForEntity(toUrl, httpEntity, String.class);
        .............
    }

运行之后,对端服务报body域中的json解析失败,一脸懵逼。各种百度各种调试,中间的艰辛就不记录了(中途还换过java原生的Http Connection,是OK的) 后来换了另一种resttemplate注入来获得restTemplate实例:

RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
restTemplate.postForEntity(toUrl, httpEntity, String.class);

然后debug这两者之间的区别,发现第一种注入的restemplate是通过SimpleClientHttpRequestFactory获取实例的,第二种是通过BufferingClientHttpRequestFactory。 百度了下网上说SimpleClientHttpRequestFactory是ClientHttpRequestFactory的装饰器方法, 用来创建ClientHttpRequest。BufferingClientHttpRequestFactory用了JDK原生的方法(java.net包),不依赖于第三方库,例如Appache的Http相关的库。 然鹅 我还是没明白为什么第一种方式json会解析失败,最后在debug resttemplate.doWithRequest代码的时候,第一种方式比第二种多了一个fastjson转换器, 第一种有八个,第二种是七个(我在项目中用了fastJson注入到了HttpMessageConverters中): 这里写图片描述

然后我推断是fastJson的原因,把fastJson注入移除,用第一种方法就好了!!! 还有然后!!第一种方法中,HttpEntity构造方法中,直接传入pojo对象代替原先的json字符串也是可以的,不用JSONObject.toJSONString()方法转!

总结 归根结底的原因其实我还是没找到,一般情况下,如果要用restTemplate发restful post请求,且要携带header域, body中的内容是最好要转成json字符串的,然而~~如果项目中用了fastJson,restTemplate内部会用fastjson去转这个字符串作为http body域内容,这时发过去的body域内容就不对了。

PS:找问题过程中,一直想抓包,试了fiddler,抓不到本地代码运行发出去的post请求,用了wireshark,抓的太底层了,抓 的是tcp/udp层的,目前还在寻找方案中~~

vieyahn2017 commented 6 years ago

RestTemplate传递对象乱码问题及实例调用 https://blog.csdn.net/xuxie13/article/details/79209549

重点: 重写了 StringHttpMessageConverter 这个类

2018年01月30日 18:59:47 xuxie13 阅读数:3466 最近在优化项目,将里面的交易日志插入部分分离了出来,现在就要将主系统得到的日志发送到日志系统, 来减轻主项目对数据库的压力,现将日志发送给日志系统的方案有三个, 其一为RestTemplate发送,其二为kafka,其三为PostMethod。此处仅讲解RestTemplate的具体用法,以备后用。

服务端代码

    @RequestMapping("/json.do")
    public void myJson(@RequestParam("repo") String repo, HttpServletResponse po) throws Exception {
        System.out.println(repo);
        JSONObject jo = new JSONObject();
        jo.put("message",
                "{ringDialTime=\"1111122\", ringdialTimestamp=\"1513059248647\", establishedTimestamp=\"1513099248647\"}");
        po.getWriter().write(jo.toString());

    }

    @RequestMapping("/getEntity.do")
    public void getEntity(@RequestBody User user, HttpServletResponse po) throws Exception {
        System.out.println(user.getName());
        JSONObject jo = new JSONObject();
        jo.put("message",
                "{ringDialTime=\"1111122\", ringdialTimestamp=\"1513059248647\", establishedTimestamp=\"1513099248647\"}");
        po.getWriter().write(jo.toString());

    }

客户端代码

    public static void main(String[] args) throws HttpException, IOException {
        RestTemplate pp =new RestTemplate();
        User a = new User();
        a.setEmail("email");
        a.setName("ljp");
        ResponseEntity<String> postForEntity = pp.postForEntity("http://127.0.0.1:8081/SpringMVC-T/inde/getEntity.do",a,String.class);//传递实体
        ResponseEntity<String> postForEntity2 = pp.postForEntity("http://127.0.0.1:8081/SpringMVC-T/inde/json.do?repo=ljp",null,String.class);//传参
        System.out.println(postForEntity+"\n"+postForEntity2);
        System.out.println(postForEntity.getBody());
    }

客户端接收的返回值 可以看到服务器端返回的json串,可以通过postForEntity.getBody() 获取得到{"message":"{ringDialTime=\"1111122\"}"},具体返回的数据可以做交互验证之类的操作

这里写图片描述

服务器端接收到的数据展示

由此可以看到服务器端完全接收到了传递的参数和对象 这里写图片描述

**

解决方案 ** 跨域传输的对象参数之间难免有汉字,但是restTemplate 的请求默认的参数是iso-9958-1,这个时候就出现了乱码的问题,我在网上也找了不少方法,很多的都是如下

    RestTemplate restTemplate = new RestTemplateBuilder().additionalMessageConverters(m).build();
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());

        String jsonStr = JSONObject.toJSONString(params);

        HttpEntity formEntity = new HttpEntity( headers);
        String result = restTemplate.getForObject("http://www.baidu.com", String.class);

但是我的并不行,依然是乱码,然后只好用了个笨方法,重写了 StringHttpMessageConverter 这个类,这个效果是立竿见影,立马就好了

package org.springframework.http.converter;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;

import org.springframework.util.StreamUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

import java.nio.charset.Charset;

import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;

public class StringHttpMessageConverter extends AbstractHttpMessageConverter<String> {
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    private final Charset defaultCharset;
    private final List<Charset> availableCharsets;
    private boolean writeAcceptCharset = true;

    public StringHttpMessageConverter() {
        this(DEFAULT_CHARSET);
    }

    public StringHttpMessageConverter(Charset defaultCharset) {
        super(new MediaType[] {
                new MediaType("text", "plain", defaultCharset), MediaType.ALL
            });
        this.defaultCharset = defaultCharset;
        this.availableCharsets = new ArrayList(Charset.availableCharsets()
                                                      .values());
    }

    public void setWriteAcceptCharset(boolean writeAcceptCharset) {
        this.writeAcceptCharset = writeAcceptCharset;
    }

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

    protected String readInternal(Class<?extends String> clazz,
        HttpInputMessage inputMessage) throws IOException {
        Charset charset = getContentTypeCharset(inputMessage.getHeaders()
                                                            .getContentType());

        return StreamUtils.copyToString(inputMessage.getBody(), charset);
    }

    protected Long getContentLength(String s, MediaType contentType) {
        Charset charset = getContentTypeCharset(contentType);

        try {
            return Long.valueOf(s.getBytes(charset.name()).length);
        } catch (UnsupportedEncodingException ex) {
            throw new IllegalStateException(ex);
        }
    }

    protected void writeInternal(String s, HttpOutputMessage outputMessage)
        throws IOException {
        if (this.writeAcceptCharset) {
            outputMessage.getHeaders().setAcceptCharset(getAcceptedCharsets());
        }

        Charset charset = getContentTypeCharset(outputMessage.getHeaders()
                                                             .getContentType());
        StreamUtils.copy(s, charset, outputMessage.getBody());
    }

    protected List<Charset> getAcceptedCharsets() {
        return this.availableCharsets;
    }

    private Charset getContentTypeCharset(MediaType contentType) {
        if ((contentType != null) && (contentType.getCharSet() != null)) {
            return contentType.getCharSet();
        }

        return this.defaultCharset;
    }
}

我们知道,调用reseful接口传递的数据内容是json格式的字符串,返回的响应也是json格式的字符串。然而restTemplate.postForObject方法的请求参数RequestBean和返回参数ResponseBean却都是java类。是RestTemplate通过HttpMessageConverter自动帮我们做了转换的操作。想要详细了解的可以看看这篇:https://www.jianshu.com/p/c9644755dd5e

vieyahn2017 commented 6 years ago

spring cloud 做微服务时关于RestTemplate中的各种请求方法的使用总结 https://blog.csdn.net/u012843361/article/details/79893638

文中提到了一个ParameterizedTypeReference, 别处没涉及

再看中间的3个exchange方法:

可以看到中间的3个方法与前面的3个方法唯一不相同的就是指定返回类型了,前面3个方法都是Class responseType而此处的3个方法都是ParameterizedTypeReference responseType,其他的地方完全没有区别。这样的话我们就来看看这个ParameterizedTypeReference是个什么东西(将光标放到类上面,然后按F2键):

该类的目的是启用泛型类型的捕获和传递。为了捕获泛型类型并在运行时保留它,您需要创建一个子类如下:

ParameterizedTypeReference<List<String>> typeRef = new ParameterizedTypeReference<List<String>>(){};

顺便说一下ParameterizedTypeReference是一个抽象类,另外这个类根据名字我们其实可以大概可以猜到他的作用:参数化类型引用。于是我们可以这样写:

ParameterizedTypeReference<List<UserVO>> myBean = new ParameterizedTypeReference<List<UserVO>>() {};
ResponseEntity<List<UserVO>> exchange = restTemplate.exchange("http://www.xxx.com/testSend", HttpMethod.GET, null, myBean, 90,2019);

当要查询一个List类型的bean对象的时候,之前的Class responseType类型的返回就有点力不从心了, 因为我们在使用Class responseType的时候只能定义到List层面,不知道List里面的是什么结构。使用ResponseEntity<List>后, 我们可以在接收请求处定义一个与请求的bean数据结构一模一样的一个VO(value object), 例如此处是查询一个User的List,我们在发送请求处定义一个与User数据结构一模一样的UserVO来接收List,这样结果就更好处理。

最后剩下的2个exchange方法:

可以看到最后这2个exchange接口都只传2个参数,第一个都是RequestEntity<?> requestEntity, 第二个参数是Class responseType或ParameterizedTypeReference responseType。 第二个参数的区别与作用和前面的2组exchange方法的参数一样不用多说了。 而第一个参数,我们看他的说明:@param requestEntity the entity to write to the request是一个Http请求的entity。

看到RequestEntity的几个成员:

    private final HttpMethod method;
    private final URI url;
    private final Type type;

和他的这几个构造方法就知道,其实这里的RequestEntity<?>实际上就是将前面的几个exchange方法中的url、method、responseType等几个参数封装起来了,本质上还是一样的。

至此RestTemplate中的Http请求方法的使用就都介绍完了。 下面将这些方法大概的做一个总结,总结就根据实际需求来分类,分为4类查询,新增、修改、删除: 约定:所有的方法中只对url是String类型的方法做分类和总结,因为一个是请求过程中的url常见的都是String,二是String类型的url可以手动的转在URI. 所以所有的URI为参数的方法都当重复方法,不再做分类和总结。

结:

请求参数中常用的url一般都是String,所以以url参数类型是URI的可以不管,用的少。 可变参数Object... uriVariables和Map<String, ?> uriVariables里面传的参数都是url上的参数,本质上没有什么区别,重点是url上一定要占位。 请求参数Class responseType和ParameterizedTypeReference responseType都是用来指定返回数据的类型的,对于简单类型的用Class就可以了,但是如果返回类型太过复杂(如对象嵌套之类的) 可以用ParameterizedTypeReference来指定返回类型。 关于返回,XXXForObject的方法都只返回具体内容,不返回Http的头信息和状态信息,要返回头信息和状态信息的时候就要使用XXXForEntity, 这一类方法都是返回ResponseEntity

exchange方法可以发多种类型的Http请求,本质上与具体的某一类的请求没有太大差别, 唯一的是exchange方法中有可以参数化响应类型的请求参数:ParameterizedTypeReference,在特定的时候比较合用。


作者:DWT_CCFK 来源:CSDN 原文:https://blog.csdn.net/u012843361/article/details/79893638 版权声明:本文为博主原创文章,转载请附上博文链接!

vieyahn2017 commented 6 years ago

https://stackoverflow.com/questions/49416818/map-json-array-to-list-using-resttemplate