spring中最长见得两种请求方式:Get与Post
有些时候我们需要跨域去访问其他服务上的接口,此时就用到HtppClient与RestTemplate;重点讲一下RestTemplate
一、HttpClient
1、引入相关依赖包
maven:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.5</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
2、主要类HttpClientService
package com.sinotn.service;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
/**
* HttpClient发送GET、POST请求
* @Author libin
* @CreateDate 2018.5.28 16:56
*/
public class HttpClientService {
private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientService.class);
/**
* 返回成功状态码
*/
private static final int SUCCESS_CODE = 200;
/**
* 发送GET请求
* @param url 请求url
* @param nameValuePairList 请求参数
* @return JSON或者字符串
* @throws Exception
*/
public static Object sendGet(String url, List<NameValuePair> nameValuePairList) throws Exception{
JSONObject jsonObject = null;
CloseableHttpClient client = null;
CloseableHttpResponse response = null;
try{
/**
* 创建HttpClient对象
*/
client = HttpClients.createDefault();
/**
* 创建URIBuilder
*/
URIBuilder uriBuilder = new URIBuilder(url);
/**
* 设置参数
*/
uriBuilder.addParameters(nameValuePairList);
/**
* 创建HttpGet
*/
HttpGet httpGet = new HttpGet(uriBuilder.build());
/**
* 设置请求头部编码
*/
httpGet.setHeader(new BasicHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"));
/**
* 设置返回编码
*/
httpGet.setHeader(new BasicHeader("Accept", "text/plain;charset=utf-8"));
/**
* 请求服务
*/
response = client.execute(httpGet);
/**
* 获取响应吗
*/
int statusCode = response.getStatusLine().getStatusCode();
if (SUCCESS_CODE == statusCode){
/**
* 获取返回对象
*/
HttpEntity entity = response.getEntity();
/**
* 通过EntityUitls获取返回内容
*/
String result = EntityUtils.toString(entity,"UTF-8");
/**
* 转换成json,根据合法性返回json或者字符串
*/
try{
jsonObject = JSONObject.parseObject(result);
return jsonObject;
}catch (Exception e){
return result;
}
}else{
LOGGER.error("HttpClientService-line: {}, errorMsg{}", 97, "GET请求失败!");
}
}catch (Exception e){
LOGGER.error("HttpClientService-line: {}, Exception: {}", 100, e);
} finally {
response.close();
client.close();
}
return null;
}
/**
* 发送POST请求
* @param url
* @param nameValuePairList
* @return JSON或者字符串
* @throws Exception
*/
public static Object sendPost(String url, List<NameValuePair> nameValuePairList) throws Exception{
JSONObject jsonObject = null;
CloseableHttpClient client = null;
CloseableHttpResponse response = null;
try{
/**
* 创建一个httpclient对象
*/
client = HttpClients.createDefault();
/**
* 创建一个post对象
*/
HttpPost post = new HttpPost(url);
/**
* 包装成一个Entity对象
*/
StringEntity entity = new UrlEncodedFormEntity(nameValuePairList, "UTF-8");
/**
* 设置请求的内容
*/
post.setEntity(entity);
/**
* 设置请求的报文头部的编码
*/
post.setHeader(new BasicHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"));
/**
* 设置请求的报文头部的编码
*/
post.setHeader(new BasicHeader("Accept", "text/plain;charset=utf-8"));
/**
* 执行post请求
*/
response = client.execute(post);
/**
* 获取响应码
*/
int statusCode = response.getStatusLine().getStatusCode();
if (SUCCESS_CODE == statusCode){
/**
* 通过EntityUitls获取返回内容
*/
String result = EntityUtils.toString(response.getEntity(),"UTF-8");
/**
* 转换成json,根据合法性返回json或者字符串
*/
try{
jsonObject = JSONObject.parseObject(result);
return jsonObject;
}catch (Exception e){
return result;
}
}else{
LOGGER.error("HttpClientService-line: {}, errorMsg:{}", 146, "POST请求失败!");
}
}catch (Exception e){
LOGGER.error("HttpClientService-line: {}, Exception:{}", 149, e);
}finally {
response.close();
client.close();
}
return null;
}
/**
* 组织请求参数{参数名和参数值下标保持一致}
* @param params 参数名数组
* @param values 参数值数组
* @return 参数对象
*/
public static List<NameValuePair> getParams(Object[] params, Object[] values){
/**
* 校验参数合法性
*/
boolean flag = params.length>0 && values.length>0 && params.length == values.length;
if (flag){
List<NameValuePair> nameValuePairList = new ArrayList<>();
for(int i =0; i<params.length; i++){
nameValuePairList.add(new BasicNameValuePair(params[i].toString(),values[i].toString()));
}
return nameValuePairList;
}else{
LOGGER.error("HttpClientService-line: {}, errorMsg:{}", 197, "请求参数为空且参数长度不一致");
}
return null;
}
}
3、调用方法
package com.sinotn.service.impl;
import com.sinotn.service.HttpClientService;
import org.apache.http.NameValuePair;
import java.util.List;
/**
* 发送post/get 测试类
*/
public class Test {
public static void main(String[] args) throws Exception{
String url = "要请求的url地址";
/**
* 参数值
*/
Object [] params = new Object[]{"param1","param2"};
/**
* 参数名
*/
Object [] values = new Object[]{"value1","value2"};
/**
* 获取参数对象
*/
List<NameValuePair> paramsList = HttpClientService.getParams(params, values);
/**
* 发送get
*/
Object result = HttpClientService.sendGet(url, paramsList);
/**
* 发送post
*/
Object result2 = HttpClientService.sendPost(url, paramsList);
System.out.println("GET返回信息:" + result);
System.out.println("POST返回信息:" + result2);
}
}
4、对于发送https
为了避免需要证书,所以用一个类继承DefaultHttpClient类,忽略校验过程。
写一个SSLClient类,继承至HttpClient
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
//用于进行Https请求的HttpClient
public class SSLClient extends DefaultHttpClient{
public SSLClient() throws Exception{
super();
SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
ctx.init(null, new TrustManager[]{tm}, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ClientConnectionManager ccm = this.getConnectionManager();
SchemeRegistry sr = ccm.getSchemeRegistry();
sr.register(new Scheme("https", 443, ssf));
}
}
5、对于https调用
二、RestTemplate
RestTemplate 是从 Spring3.0 开始支持的一个 Http 请求工具,这个请求工具和 Spring Boot 无关,更
和 Spring Cloud 无关。RestTemplate 提供了常见的 REST 请求方法模板,例如 GET、POST、PUT、
DELETE 请求以及一些通用的请求执行方法 exchange 和 execute 方法。
这里的execute类似于
.
p
o
s
t
(
)
与
.post() 与
.post()与.ajax();的区别,前者是简写,写好的用来post请求,后者是需要我们来自定义的;
RestTemplate 本身实现了 RestOperations 接口,而在 RestOperations 接口中,定义了常见的
RESTful 操作,这些操作在 RestTemplate 中都得到了很好地实现;
1、Get
首先我们在 provider(自己测试的生产者服务) 中定义一个 hello2 接口:
@GetMapping("/hello2")
public String hello2(String name) {
return "hello " + name;
}
接下来,我们在 consumer 去访问这个接口,这个接口是一个 GET 请求,所以,访问方式,就是调用 RestTemplate 中的 GET 请求。 可以看到,在 RestTemplate 中,关于 GET 请求,一共有如下两大类方法:
这两大类方法实际上是重载的,唯一不同的,就是返回值类型。 getForObject 返回的是一个对象,这个对象就是服务端返回的具体值。getForEntity 返回的是一个 ResponseEntity,这个ResponseEntity 中除了服务端返回的具体数据外,还保留了 Http 响应头的数据。
@GetMapping("/hello4")
public void hello4() {
String s1 = restTemplate.getForObject("http://provider/hello2?name={1}", String.class, "javaboy");
System.out.println(s1);
ResponseEntity<String> responseEntity =
restTemplate.getForEntity("http://provider/hello2", String.class, "javaboy");
String body = responseEntity.getBody();
System.out.println("body:" + body);
HttpStatus statusCode = responseEntity.getStatusCode();
System.out.println("HttpStatus:" + statusCode);
int statusCodeValue = responseEntity.getStatusCodeValue();
System.out.println("statusCodeValue:"+statusCodeValue);
HttpHeaders headers = responseEntity.getHeaders();
Set<String> keySet = headers.keySet();
System.out.println("--------------header-----------");
for (String s : keySet) {
System.out.println(s+":"+headers.get(s));
}
}
执行打印:
这里大家可以看到,getForObject 直接拿到了服务的返回值,getForEntity 不仅仅拿到服务的返回值, 还拿到 http 响应的状态码。然后,启动 Eureka Server、provider 以及 consumer ,访问 consumer 中的 hello4 接口,既可以看到请求结果。 看清楚两者的区别之后,接下来看下两个各自的重载方法,getForObject 和 getForEntity 分别有三个 重载方法,两者的三个重载方法基本都是一致的。所以,这里,我们主要看其中一种。三个重载方法, 其实代表了三种不同的传参方式。
@GetMapping("/hello5")
public void hello5() throws UnsupportedEncodingException {
//第一种
String s1 = restTemplate.getForObject("http://provider/hello2?name={1}",
String.class, "javaboy");
System.out.println(s1);
//第二种
Map<String, Object> map = new HashMap<>();
map.put("name", "zhangsan");
s1 = restTemplate.getForObject("http://provider/hello2?name={name}",
String.class, map);
System.out.println(s1);
//第三种
String url = "http://provider/hello2?name=" + URLEncoder.encode("张三", "UTF8");
URI uri = URI.create(url);
s1 = restTemplate.getForObject(uri, String.class);
System.out.println(s1);
}
执行:
这就是我们说的三种不同的传参方式
2、Post
首先在 provider 中提供两个 POST 接口,同时,因为 POST 请求可能需要传递 JSON,所以,这里我们 创建一个普通的 Maven 项目作为 commons 模块,然后这个 commons 模块被 provider 和 consumer 共同引用,这样我们就可以方便的传递 JSON 了。 (其实就是为了传参user)
commons 模块创建成功后,首先在 commons 模块中添加 User 对象,然后该模块分别被 provider 和 consumer 引用。 然后,我们在 provider 中,提供和两个 POST 接口:
@PostMapping("/user1")
public User addUser1(User user) {
return user;
}
@PostMapping("/user2")
public User addUser2(@RequestBody User user) {
return user;
}
这里定义了两个 User 添加的方法,两个方法代表了两种不同的传参方式。
第一种方法是以 key/value 形式来传参,
第二种方法是以 JSON 形式来传参。
定义完成后,接下来,我们在 consumer 中调用这两个 POST 接口。
可以看到,这里的 post 和前面的 get 非常像,只是多出来了三个方法,就是 postForLocation,另外 两个 postForObject 和 postForEntiy 和前面 get 基本一致,所以这里我们主要来看 postForObject, 看完之后,我们再来看这个额外的 postForLocation。
@GetMapping("/hello6")
public void hello6() {
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("username", "javaboy");
map.add("password", "123");
map.add("id", 99);
User user = restTemplate.postForObject("http://provider/user1", map,
User.class);
System.out.println(user);
user.setId(98);
user = restTemplate.postForObject("http://provider/user2", user,
User.class);
System.out.println(user);
}
运行:
post 参数到底是 key/value 形式还是 json 形式,主要看第二个参数,如果第二个参数是 MultiValueMap ,则参数是以 key/value 形式来传递的,如果是一个普通对象,则参数是以 json 形式 来传递的。
最后再看看一下 postForLocation 。有的时候,当我执行完一个 post 请求之后,立马要进行重定向, 一个非常常见的场景就是注册,注册是一个 post 请求,注册完成之后,立马重定向到登录页面去登 录。
对于这种场景,我们就可以使用 postForLocation。 首先我们在 provider 上提供一个用户注册接口:
@Controller
public class RegisterController {
@PostMapping("/register")
public String register(User user) {
return "redirect:http://provider/loginPage?username=" +
user.getUsername();
}
@GetMapping("/loginPage")
@ResponseBody
public String loginPage(String username) {
return "loginPage:" + username;
}
}
注意,这里的 post 接口,响应一定是 302,否则 postForLocation 无效。
注意,重定向的地址,一定要写成绝对路径,不要写相对路径,否则在 consumer 中调用时会出问题
@GetMapping("/hello7")
public void hello7() {
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("username", "javaboy");
map.add("password", "123");
map.add("id", 99);
URI uri = restTemplate.postForLocation("http://provider/register", map);
String s = restTemplate.getForObject(uri, String.class);
System.out.println(s);
}
运行:
这就是 postForLocation ,调用该方法返回的是一个 Uri,这个 Uri 就是重定向的地址(里边也包含了 重定向的参数),拿到 Uri 之后,就可以直接发送新的请求了
3、Put
PUT 请求比较简单,重载的方法也比较少。(PUT是没有返回值的)
我们首先在 provider 中提供一个 PUT 接口:
@PutMapping("/user1")
public void updateUser1(User user) {
System.out.println(user);
}
@PutMapping("/user2")
public void updateUser2(@RequestBody User user) {
System.out.println(user);
}
注意,PUT 接口传参其实和 POST 很像,也接受两种类型的参数,key/value 形式以及 JSON 形式。
在 consumer 中,我们来调用该接口:
@GetMapping("/hello8")
public void hello8() {
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("username", "javaboy");
map.add("password", "123");
map.add("id", 99);
restTemplate.put("http://provider/user1", map);
User user = new User();
user.setId(98);
user.setUsername("zhangsan");
user.setPassword("456");
restTemplate.put("http://provider/user2", user);
}
运行:
consumer 中的写法基本和 post 类似,也是两种方式,可以传递两种不同类型的参数
4、Delete
DELETE 也比较容易,我们有两种方式来传递参数,key/value 形式或者 PathVariable(参数放在路径 中),首先我们在 provider 中定义两个 DELETE 方法:
@DeleteMapping("/user1")
public void deleteUser1(Integer id) {
System.out.println(id);
}
@DeleteMapping("/user2/{id}")
public void deleteUser2(@PathVariable Integer id) {
System.out.println(id);
}
然后在 consumer 中调用这两个删除的接口:
@GetMapping("/hello9")
public void hello9() {
restTemplate.delete("http://provider/user1?id={1}", 99);
restTemplate.delete("http://provider/user2/{1}", 99);
}
delete 中参数的传递,也支持 map,这块实际上和 get 是一样的。
三、RestTemplate拓展
1、手动指定转换器(HttpMessageConverter)
我们知道,调用reseful接口传递的数据内容是json格式的字符串,返回的响应也是json格式的字符串。
然而restTemplate.postForObject方法的请求参数RequestBean和返回参数ResponseBean却都是java类。是RestTemplate通过HttpMessageConverter自动帮我们做了转换的操作。
默认情况下RestTemplate自动帮我们注册了一组HttpMessageConverter用来处理一些不同的contentType的请求。
如StringHttpMessageConverter来处理text/plain;MappingJackson2HttpMessageConverter来处理application/json;
MappingJackson2XmlHttpMessageConverter来处理application/xml。
你可以在org.springframework.http.converter包下找到所有spring帮我们实现好的转换器。
如果现有的转换器不能满足你的需求,你还可以实现org.springframework.http.converter.HttpMessageConverter接口自己写一个。详情参考官方api。
选好了HttpMessageConverter后怎么把它注册到我们的RestTemplate中呢
RestTemplate restTemplate = new RestTemplate();
//获取RestTemplate默认配置好的所有转换器
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
//默认的MappingJackson2HttpMessageConverter在第7个 先把它移除掉
messageConverters.remove(6);
//添加上GSON的转换器
messageConverters.add(6, new GsonHttpMessageConverter());
这个简单的例子展示了如何使用GsonHttpMessageConverter替换掉默认用来处理application/json的MappingJackson2HttpMessageConverter。
2、设置底层连接方式
要创建一个RestTemplate的实例,您可以像上述例子中简单地调用默认的无参数构造函数。这将使用java.net包中的标准Java类作为底层实现来创建HTTP请求。
但很多时候我们需要像传统的 HttpClient那样设置HTTP请求的一些属性。RestTemplate使用了一种很偷懒的方式实现了这个需求,那就是直接使用一个HttpClient作为底层实现…
//生成一个设置了连接超时时间、请求超时时间、异常最大重试次数的httpClient
RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(10000).setConnectTimeout(10000).setSocketTimeout(30000).build();
HttpClientBuilder builder = HttpClientBuilder.create().setDefaultRequestConfig(config).setRetryHandler(new DefaultHttpRequestRetryHandler(5, false));
HttpClient httpClient = builder.build();
//使用httpClient创建一个ClientHttpRequestFactory的实现
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
//ClientHttpRequestFactory作为参数构造一个使用作为底层的RestTemplate
RestTemplate restTemplate = new RestTemplate(requestFactory);
3、设置拦截器(ClientHttpRequestInterceptor)
有时候我们需要对请求做一些通用的拦截设置,这就可以使用拦截器进行处理。拦截器需要我们实现org.springframework.http.client.ClientHttpRequestInterceptor接口自己写。
举个简单的例子,写一个在header中根据请求内容和地址添加令牌的拦截器。
public class TokenInterceptor implements ClientHttpRequestInterceptor
{
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException
{
//请求地址
String checkTokenUrl = request.getURI().getPath();
//token有效时间
int ttTime = (int) (System.currentTimeMillis() / 1000 + 1800);
//请求方法名 POST、GET等
String methodName = request.getMethod().name();
//请求内容
String requestBody = new String(body);
//生成令牌 此处调用一个自己写的方法,有兴趣的朋友可以自行google如何使用ak/sk生成token,此方法跟本教程无关,就不贴出来了
String token = TokenHelper.generateToken(checkTokenUrl, ttTime, methodName, requestBody);
//将令牌放入请求header中
request.getHeaders().add("X-Auth-Token",token);
return execution.execute(request, body);
}
}
创建RestTemplate实例的时候可以这样向其中添加拦截器
RestTemplate restTemplate = new RestTemplate();
//向restTemplate中添加自定义的拦截器
restTemplate.getInterceptors().add(new TokenInterceptor());
spring cloud消费者根据生产者名称进行url调用时,在restTemplate上源码使用此种拦截器对uri进行了重构,将uri指向具体可访问的地址;
四、结尾
以上就是对HttpClient与RestTemplate的使用方法总结,最后附属一下自己做的一些调用测试代码:
package com.cn.testpost;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
public class TestController {
private static final Logger LOGGER = LoggerFactory.getLogger(TestController.class);
@Autowired
RestTemplate restTemplate;
@GetMapping("/testPost")
public String testPost(){
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("name", "%xiaoming");
map.add("age", 27);
String user = restTemplate.postForObject("http://127.0.0.1:8081/test", map,
String.class);
System.out.println(user);
return user;
}
@GetMapping("/testPost2")
public String testPost2(){
Map<String, Object> map = new HashMap<>();
map.put("name", "%xiaoming");
map.put("age", 27);
String s = JSON.toJSONString(map);
String s1 = sendPost("http://127.0.0.1:8081/test", s, false);
System.out.println(s1);
return s1;
}
@GetMapping("/testPost3")
public String testPost3(){
Map<String, Object> map = new HashMap<>();
map.put("app_id", "qianfsHis001");
map.put("method", "060001");
map.put("formatter", "json");
map.put("version", "1.0.1");
map.put("message_id", "123");
map.put("message", "{\"version_code\":\"%1.0.1\"}");
map.put("is_secret", "0");
map.put("passKey", "843491CC879BDF2AFB2C20BDB387F546D54DCDC8");
map.put("time", "12526");
map.put("nonceStr", "85269");
String s = JSON.toJSONString(map);
String s1 = sendPost("http://127.0.0.1:8099/central/app/", s, false);
System.out.println(s1);
return s1;
}
@GetMapping("/testPost4")
public String testPost4(){
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("app_id", "qianfsHis001");
map.add("method", "060001");
map.add("formatter", "json");
map.add("version", "1.0.1");
map.add("message_id", "123");
map.add("message", "{\"version_code\":\"%1.0.1\"}");
map.add("is_secret", "0");
map.add("passKey", "843491CC879BDF2AFB2C20BDB387F546D54DCDC8");
map.add("time", "12526");
map.add("nonceStr", "85269");
String s = restTemplate.postForObject("http://127.0.0.1:8099/central/app/", map,
String.class);
System.out.println(s);
return s;
}
@GetMapping("/testPost5")
public String testPost5() throws Exception {
String url = "http://127.0.0.1:8099/central/app/";
/**
* 参数值
*/
Object [] params = new Object[]{"app_id","method","formatter","version","message_id","message","is_secret","passKey"
, "time","nonceStr"};
/**
* 参数名
*/
Object [] values = new Object[]{"qianfsHis001","060001","json","1.0.1",
"123","{\"version_code\":\"%251.0.1\"}","0","843491CC879BDF2AFB2C20BDB387F546D54DCDC8","12526","85269"};
/**
* 获取参数对象
*/
List<NameValuePair> paramsList = getParams(params, values);
/**
* 发送post
*/
Object result2 = sendHpptPost(url, paramsList);
System.out.println("POST返回信息:" + result2);
return String.valueOf(result2);
}
public static String sendPost(String url, String param, boolean isproxy) {
OutputStreamWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
HttpURLConnection conn = null;
if (isproxy) {//使用代理模式
@SuppressWarnings("static-access")
Proxy proxy = new Proxy(Proxy.Type.DIRECT.HTTP, new InetSocketAddress("127.0.0.1", 8080));
conn = (HttpURLConnection) realUrl.openConnection(proxy);
} else {
conn = (HttpURLConnection) realUrl.openConnection();
}
// 打开和URL之间的连接
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST"); // POST方法
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
//conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
conn.connect();
// 获取URLConnection对象对应的输出流
out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
// 发送请求参数
out.write(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!" + e);
e.printStackTrace();
}
//使用finally块来关闭输出流、输入流
finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}
/**
* 发送POST请求
* @param url
* @param nameValuePairList
* @return JSON或者字符串
* @throws Exception
*/
public static Object sendHpptPost(String url, List<NameValuePair> nameValuePairList) throws Exception{
JSONObject jsonObject = null;
CloseableHttpClient client = null;
CloseableHttpResponse response = null;
try{
/**
* 创建一个httpclient对象
*/
client = HttpClients.createDefault();
/**
* 创建一个post对象
*/
HttpPost post = new HttpPost(url);
/**
* 包装成一个Entity对象
*/
StringEntity entity = new UrlEncodedFormEntity(nameValuePairList, "UTF-8");
/**
* 设置请求的内容
*/
post.setEntity(entity);
/**
* 设置请求的报文头部的编码
*/
post.setHeader(new BasicHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"));
/**
* 设置请求的报文头部的编码
*/
post.setHeader(new BasicHeader("Accept", "text/plain;charset=utf-8"));
/**
* 执行post请求
*/
response = client.execute(post);
/**
* 获取响应码
*/
int statusCode = response.getStatusLine().getStatusCode();
if (200 == statusCode){
/**
* 通过EntityUitls获取返回内容
*/
String result = EntityUtils.toString(response.getEntity(),"UTF-8");
/**
* 转换成json,根据合法性返回json或者字符串
*/
try{
jsonObject = JSONObject.parseObject(result);
return jsonObject;
}catch (Exception e){
return result;
}
}else{
LOGGER.error("HttpClientService-line: {}, errorMsg:{}", 146, "POST请求失败!");
}
}catch (Exception e){
LOGGER.error("HttpClientService-line: {}, Exception:{}", 149, e);
}finally {
response.close();
client.close();
}
return null;
}
/**
* 组织请求参数{参数名和参数值下标保持一致}
* @param params 参数名数组
* @param values 参数值数组
* @return 参数对象
*/
public static List<NameValuePair> getParams(Object[] params, Object[] values){
/**
* 校验参数合法性
*/
boolean flag = params.length>0 && values.length>0 && params.length == values.length;
if (flag){
List<NameValuePair> nameValuePairList = new ArrayList<>();
for(int i =0; i<params.length; i++){
nameValuePairList.add(new BasicNameValuePair(params[i].toString(),values[i].toString()));
}
return nameValuePairList;
}else{
LOGGER.error("HttpClientService-line: {}, errorMsg:{}", 197, "请求参数为空且参数长度不一致");
}
return null;
}
}
附:添加消息请求头
//headers
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("api-version", "1.0");
//body
MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<>();
requestBody.add("roundid", "1");
//HttpEntity
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<MultiValueMap>(requestBody, requestHeaders);
RestTemplate restTemplate = new RestTemplate();
//post
ResponseEntity<String> responseEntity = restTemplate.postForEntity("http://xxx", requestEntity, String.class);
System.out.println(responseEntity.getBody());
参考文章:
https://www.cnblogs.com/klslb/p/9121276.html
https://www.jianshu.com/p/90ec27b3b518