Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

11.8 使用restTemplate处理modelAttribute #54

Closed
vieyahn2017 opened this issue Nov 8, 2018 · 7 comments
Closed

11.8 使用restTemplate处理modelAttribute #54

vieyahn2017 opened this issue Nov 8, 2018 · 7 comments

Comments

@vieyahn2017
Copy link
Owner

使用restTemplate处理modelAttribute

@vieyahn2017
Copy link
Owner Author

vieyahn2017 commented Nov 8, 2018

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
Copy link
Owner Author

vieyahn2017 commented Nov 8, 2018

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
Copy link
Owner Author

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
Copy link
Owner Author

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
Copy link
Owner Author

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
Copy link
Owner Author

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
Copy link
Owner Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant