-
Notifications
You must be signed in to change notification settings - Fork 3
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
Comments
11.12 终于发现,坑了那么久的问题: 原因竟然是该class不是public的
|
IllegalAccessException: Class A can not access a member of class B 的一种原因分析与解决 2016年12月24日 12:30:28 FserSuN 阅读数:4455 标签: java 异常 class 我在使用到一个java fluent api工具时遇到这个问题,出现异常后调用栈如下。
最后抛出了IllegalAccessException异常,这个异常的定义如下。
从异常定义可以看出,由于通过反射的机制创建实例,由于没有权限访问类,域,方法构造器而产生该异常。 通过抛出的异常可以看出,在调用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问题解决。可以想到,做这样的检查是为了确保对目标类有权限访问。 |
ribbon通过RestTemplate调用接口获取List时,应使用数组而不能直接使用List 足不出户能上网就能赚钱,月收入过万!! |
Spring Resttemplate post方法踩坑记录 项目中有处地方需要通过http post构造restful请求,且需要携带正确的header域, @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 = new RestTemplate(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
restTemplate.postForEntity(toUrl, httpEntity, String.class); 然后debug这两者之间的区别,发现第一种注入的restemplate是通过SimpleClientHttpRequestFactory获取实例的,第二种是通过BufferingClientHttpRequestFactory。 然后我推断是fastJson的原因,把fastJson注入移除,用第一种方法就好了!!! 总结 PS:找问题过程中,一直想抓包,试了fiddler,抓不到本地代码运行发出去的post请求,用了wireshark,抓的太底层了,抓 的是tcp/udp层的,目前还在寻找方案中~~ |
RestTemplate传递对象乱码问题及实例调用 重点: 重写了 StringHttpMessageConverter 这个类 2018年01月30日 18:59:47 xuxie13 阅读数:3466 服务端代码 @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());
} 客户端接收的返回值 这里写图片描述 服务器端接收到的数据展示 由此可以看到服务器端完全接收到了传递的参数和对象 ** 解决方案 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, |
spring cloud 做微服务时关于RestTemplate中的各种请求方法的使用总结 文中提到了一个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类型的返回就有点力不从心了, 最后剩下的2个exchange方法: 可以看到最后这2个exchange接口都只传2个参数,第一个都是RequestEntity<?> requestEntity, 看到RequestEntity的几个成员: private final HttpMethod method;
private final URI url;
private final Type type; 和他的这几个构造方法就知道,其实这里的RequestEntity<?>实际上就是将前面的几个exchange方法中的url、method、responseType等几个参数封装起来了,本质上还是一样的。 至此RestTemplate中的Http请求方法的使用就都介绍完了。 结: 请求参数中常用的url一般都是String,所以以url参数类型是URI的可以不管,用的少。 exchange方法可以发多种类型的Http请求,本质上与具体的某一类的请求没有太大差别, 作者:DWT_CCFK |
使用restTemplate处理modelAttribute
The text was updated successfully, but these errors were encountered: