RestTemplate的请求参数传递问题
问题
使用RestTemplate传递参数的时候,RestTemplate默认传递的是json格式,将参数放在请求体中,这就导致使用@RequestParam接收不到参数.下面测试集中参数传递的方式
测试方法
1.先重现错误,使用RestTemplate传递json,同时使用@RequestParam接收参数.
2.更改RestTemplate参数传递方式,将参数使用占位符在请求行拼接.
3.测试使用@RequestBody接收请求体中的数据(对象/集合/字符串/json数据).
测试
构造几个接口
/**
* 测试restTemplate的数组型(List)数据的传递
*/
@RestController
public class UserController {
/**
* 接收一个json格式的字符串 数组转换为json字符串传递
*/
@RequestMapping(value = "/test01")
public String getRest01(@RequestParam("userList")String userList) {
//转为list
List<User> userList1 = JSONArray.parseArray(userList, User.class);
for (User user : userList1) {
System.out.println(user);
}
return "11111111111";
}
/**
* 测试直接传递单个对象
*/
@RequestMapping(value = "/test02")
public String getRest02(@RequestBody User user) {
System.out.println(user);
return "2222222222222";
}
/**
*测试使用list<>接收数组型的参数
*/
@RequestMapping(value = "/test03")
public String getRest03(@RequestBody List<User> userList) {
System.out.println(userList);
return "333333333333";
}
/**
* 使用String 接收请求体中数据
*/
@RequestMapping(value = "/test04")
public String getRest04(@RequestBody String userList) {
//转为list
List<User> userList1 = JSONArray.parseArray(userList, User.class);
for (User user : userList1) {
System.out.println(user);
}
return "444444444444444";
}
/**
* 使用JSONArray接收请求体中的数据
*/
@RequestMapping(value = "/test05")
public String getRest05(@RequestBody JSONArray jsonArray, HttpServletRequest request) {
//获取请求头中的数据
String key = request.getHeader("key");
System.out.println(key);
//转为list
List<User> userList = JSONArray.parseArray(jsonArray.toJSONString(), User.class);
for (User user : userList) {
System.out.println(user);
}
return "55555555555555";
}
}
使用单元测试测试接口
class ApplicationTests {
private RestTemplate restTemplate = new RestTemplate();
//构建两个使用的对象并使用list封装起来
private List<User> userList = new ArrayList<>();
private User oneUser;
private User twoUser;
{
//第一个对象
oneUser = new User();
oneUser.setName("第一个用户");
oneUser.setAge("第一个年龄");
oneUser.setAddress("第一个地址");
//第二个对象
twoUser = new User();
twoUser.setName("22222222第二个用户");
twoUser.setAge("2222222第二个年龄");
twoUser.setAddress("222222第二个地址");
//添加进list
userList.add(oneUser);
userList.add(twoUser);
}
/*
* 当服务端使用@RequestParam("tableList")String tableList这种方式时
* 方法异常:HttpClientErrorException$BadRequest: 400 Bad Request
* 原因:无法使用@RequestParam识别参数中的json格式的
* */
@Test
void test01() {
String url = "http://127.0.0.1:8080/test01";
//json格式的字符串
String jsonString = JSON.toJSONString(userList);
Map<String, String> map = new HashMap<>();
map.put("userList", jsonString);
String s = restTemplate.postForObject(url, map, String.class);
System.out.println(s);
}
/*
* 当服务端使用@RequestParam("tableList")String tableList这种方式时,改请求方式会成功
* 改变:使用了postForEntity方法(这个方法可以传递更多的请求信息,比如请求头等)
* 使用的占位符的方式拼接json字符串, 在第一个方法参数中,最后的参数Object...是一个可变形参,可以传递多个参数,位置从1开始
* 原因:restTemplate默认的是json格式的参数,会在请求体中放着数据,而@RequestParam只能获取请求行中的参数
* 将参数改在请求行发送就能接收到了.
* */
@Test
void test02() {
//使用占位符的方式
String url = "http://127.0.0.1:8080/test01?userList={1}";
String jsonString = JSON.toJSONString(userList);
//使用占位符拼接参数
//连接(带有占位符的) / HttpEntity对象(暂时不用,后边会有) / 返回值 / 拼接的数据
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, null, String.class, jsonString);
System.out.println(responseEntity.toString());
}
/*
* 当服务端使用(@RequestBody User user)这种方式时,会成功
* @RequestBody 将会从请求体(body)中取数据,此时可以取到已经转为json格式的User对象(resttemplate会自动转)
* 但是当传递的是数组型的数据时(List),服务端又改怎么样接收呢,使用test04测试一下.
* */
@Test
void test03() {
//使用服务端的test02接口
String url = "http://127.0.0.1:8080/test02";
//测试只传递一个对象, 使用httpEntity来封装一下对象.
HttpEntity<User> httpEntity = new HttpEntity<>(oneUser);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, httpEntity, String.class);
System.out.println(responseEntity.toString());
}
/*
* 传递的是数组型的数据的时候,服务端可以使用List<>这种形式来接收,也会成功
* */
@Test
void test04() {
//使用服务端的test03接口,用list<>接收
String url = "http://127.0.0.1:8080/test03";
//测试传递一个list对象
HttpEntity<List<User>> httpEntity = new HttpEntity<>(userList);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, httpEntity, String.class);
System.out.println(responseEntity.toString());
}
/*
* 传递的是数组型的数据的时候,服务端也可以使用String来接收json型的数据
* */
@Test
void test05() {
//使用服务端的test04接口,用String接收
String url = "http://127.0.0.1:8080/test04";
//测试传递一个list对象
HttpEntity<List<User>> httpEntity = new HttpEntity<>(userList);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, httpEntity, String.class);
System.out.println(responseEntity.toString());
}
/*
* 传递的是数组型的数据的时候,服务端也可以使用JsonArray来接收
* */
@Test
void test06() {
//使用服务端的test04接口,用JsonArray接收
String url = "http://127.0.0.1:8080/test05";
//传递的参数的同时,自定义请求头
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("key","value");
HttpEntity<List<User>> httpEntity = new HttpEntity<>(userList,httpHeaders);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, httpEntity, String.class);
System.out.println(responseEntity.toString());
}
/*
* 总结一下:
* 使用RestTemplate远程调用接口的时候,会默认将数据放在请求体中(body)
* 而使用@RequestBody才能接收请求体中的数据.
* @RequestParam只能接收请求行中的参数
* 根据位置选择使用的注解
*
* postForEntity 方法可以自定义请求头,以及进行请求行的参数拼接,功能全
* */
}
总结一下
使用RestTemplate远程调用接口的时候,会默认将数据放在请求体中(body)
使用@RequestBody才能接收请求体中的数据.
@RequestParam只能接收请求行中的
服务端应该根据参数位置选择使用的注解
另外:
postForEntity 方法可以自定义请求头,以及进行请求行的参数拼接,功能全