Java调用接口进行获取对方服务器的数据在开发中特别常见,在实际开发过程中,很多项目都会封装规定好本身项目的接口规范,所以大多数需要去调用对方提供的接口或第三方接口(短信、天气等)或者测试自己写的接口。
那么Java如何调用接口?==》通过 HttpURLConnection建立实际的连接,交换数据。
URLEncoder 和 URLDecoder用于完成普通字符串和 application/x-www-form-urlencoded MIME字符串之间的相互转换.
在发送端端,这样设置参数:编码:"UTF-8"
String content = "字段名1=" + URLEncoder.encode("字符串值1", "编码")+"&字段名2=" + URLEncoder.encode("字符串值2", "编码");
在接收端,这样获取参数:
String name = request.getParameter("account");
String pswd = request.getParameter("pswd");
System.out.println(new String(name.getBytes("iso-8859-1"),"UTF-8"));
System.out.println(new String(pswd.getBytes("iso-8859-1"),"UTF-8"));
这里简单创建两个springboot的项目 ,编码使用UTF-8,做测试,对于使用输入流和输出流的那种处理流,自己选择。
1、HttpURLUtil的模板工具类
步骤:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Map;
public class HttpURLUtil {
/**
* 向指定URL发送GET方法的请求
*
* @param url 发送请求的URL
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return URL 所代表远程资源的响应结果
*/
public static String sendGet(String url, String param) {
String result = "";
BufferedReader in = null;
HttpURLConnection connection = null;
try {
URL getUrl = new URL(url + "?" + param);
// 打开和URL之间的连接
connection = (HttpURLConnection) getUrl.openConnection();
// 在connect之前,设置通用的请求属性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
connection.setRequestProperty("Charsert", "UTF-8");
// 配置本次连接的Content-type,form表单是"application/x-www-form-urlencoded",json是"application/json"等
// 根据需求自己调整Content-type
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
// 设置连接主机服务器的超时时间:15000毫秒
connection.setConnectTimeout(15000);
// 设置读取远程返回的数据时间:60000毫秒
connection.setReadTimeout(60000);
// 设置连接方式:get
connection.setRequestMethod("GET");
// 建立实际的连接,可不写,注意connection.getOutputStream会隐含的进行connect。
connection.connect();
// 获取所有响应头字段
Map> map = connection.getHeaderFields();
// 遍历所有的响应头字段
for (String key : map.keySet()) {
System.out.println(key + "--->" + map.get(key));
}
// 定义BufferedReader输入流来读取URL的响应
if (connection.getResponseCode() == 200) {
in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
}
} catch (Exception e) {
System.out.println("发送GET请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输入流
finally {
try {
if (in != null) {
in.close();
}
if (connection != null) {
//关闭连接
connection.disconnect();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
/**
* 向指定 URL 发送POST方法的请求
*
* @param url 发送请求的 URL
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param) {
String result = "";
PrintWriter out = null;
BufferedReader in = null;
HttpURLConnection connection = null;
try {
URL postUrl = new URL(url);
// 打开和URL之间的连接
connection = (HttpURLConnection) postUrl.openConnection();
// 在connect之前,设置通用的请求属性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
connection.setRequestProperty("Charsert", "UTF-8");
connection.setConnectTimeout(15000);
connection.setReadTimeout(60000);
// 发送POST请求必须设置如下两行,参数要放在http正文内
connection.setDoOutput(true);
connection.setDoInput(true);
// 默认是 GET方式
connection.setRequestMethod("POST");
// Post 请求不使用缓存
connection.setUseCaches(false);
// 配置本次连接的Content-type,form表单是"application/x-www-form-urlencoded",json是"application/json"等
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.connect();
// 参数要放在http正文内
//1.获取URLConnection对象对应的输出流
out = new PrintWriter(connection.getOutputStream());
//2.中文有乱码的需要将PrintWriter改为如下
//out=new OutputStreamWriter(conn.getOutputStream(),"UTF-8")
out.print(param);
out.flush();
//也可以使用DataOutputStream
// DataOutputStream dos=new DataOutputStream(httpConn.getOutputStream());
// dos.writeBytes(param);
// dos.flush();
// dos.close();
// 定义BufferedReader输入流来读取URL的响应
if (connection.getResponseCode() == 200) {
in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!" + e);
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
if (connection != null) {
//关闭连接
connection.disconnect();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}
}
2、两个项目中的controller测试:
中文乱码这里也做了数据
@GetMapping("/sendHttpURL")
@ResponseBody
public String sendHttpURL() throws UnsupportedEncodingException {
//发送 GET 请求
String paramGet = "v1=123456"+"&v2=" + URLEncoder.encode("发送 GET 请求", StandardCharsets.UTF_8.name());
String s = HttpURLUtil.sendGet("http://127.0.0.1/sbt_javademo/receiveURLGet", paramGet);
System.out.println(s);
//发送 POST 请求
// String paramPost = "v3=45678"+"&v4=" + URLEncoder.encode("发送 POST 请求", StandardCharsets.UTF_8.name());
String paramPost = "v3=45678"+"&v4=发送 POST 请求";
String sr = HttpURLUtil.sendPost("http://127.0.0.1/sbt_javademo/receiveURLPost", paramPost);
System.out.println(sr);
return s + "\n" + sr;
}
@GetMapping("/receiveURLGet")
@ResponseBody
public ResponseEntity
3、结果内容:
这里 Content-Type的类型,都使用的是表单“application/x-www-form-urlencoded”,根据需求自己调整
4、参数不是八大基本类型时
一般我会使用标准json字符串(map封装)来传参,接受端通过request获取流的形式处理。 post提交为例
1)传参为List
List list= new ArrayList<>();
list.add("123人");
list.add("ren人");
list.add("人14周岁");
Map tagNameMap = new HashMap<>();
tagNameMap.put("list", list);
String jsonString = JSON.toJSONString(tagNameMap);
String result= this.sendPost(url, jsonString);
2)接收端:
@PostMapping(value = "/getList")
@ResponseBody
public ResponseEntity getList(HttpServletRequest request){
try (
BufferedReader in = new BufferedReader(new InputStreamReader(request.getInputStream()));
){
StringBuilder data = new StringBuilder();
String line;
while ((line = in.readLine()) != null) {
data.append(line);
}
if(data != null){
Map map = (Map) JSON.parse(data.toString());
String listStr= map.get("tagNames").toString();
System.out.println(listStr);
List list = JSONObject.parseArray(listStr, String.class);
list.forEach(System.out::println);
}
} catch (IOException e) {
e.printStackTrace();
}
return ResponseEntity.ok("success");
}
对于一些知识点进行整理和归纳,这样容易对比加深记忆,总结:
1)HttpURLConnection的connect()函数,实际上只是建立了一个与服务器的tcp连接,并没有实际发送http请求。
无论是post还是get,实际上直到HttpURLConnection的getInputStream()这个函数调用时才正式发送出去。
2)设置请求属性必须在connect()方法执行之前完成。
对于post中,将参数放入http正文中(outputStream的写操作)必须要在inputStream()方法读操作之前完成。
这些顺序实际上是由http请求的格式决定的。
http请求实际上由两部分组成,
一个是http头,所有关于此次http请求的配置都在http头里面定义。
一个是正文content。
connect()函数会根据HttpURLConnection对象的配置值生成http头部信息,因此在调用connect函数之前,就必须把所有的配置准备好。
在http头后面紧跟着的是http请求的正文,正文的内容是通过outputStream流写入的, 实际上outputStream不是一个网络流,充其量是个字符串流,往里面写入的东西不会立即发送到网络,而是存在于内存缓冲区中,直到outputStream流关闭时或者显示调用flush()方法,才会生成http正文。至此,http请求的东西已经全部准备就绪。
在调用getInputStream()方法时,就会把准备好的http请求(包括http头和正文)正式发送到服务器,然后返回一个输入流,用于读取服务器对于此次http请求的返回信息。
1、HttpServletRequset和HttpServletResponse的知识点:
Servlet的继承体系与HttpServletRequset和HttpServletResponse
2、Request的相关方法:
getContextPath():这个方法返回的是web应用映射的虚拟目录地址:如ServletDemo应用的虚拟目录是:/ServletDemo
getCookies():这个方法返回的是一个Cookies[],因为用户在请求的时候会携带很多的cookie,关于Cookie的相关知识
getHeader(String name)/getIntHeader(String name)/getDateHeader(String name):
这些方法是获取请求头信息的,只是针对不同的类型的,有字符串类型的,时间类型,数值类型的
getHeaderNames():这个方法是获取所有请求头的字段名称
getHeaders(String name):这个方法是获取一个请求头字段的所有值,因为有时候可能会有相同请求头字段信息,不会覆盖的
getMethod():这个方法是获取客户机的请求方法
getQueryString():这个方法是获取用户请求时的查询参数的,即url后面携带的参数
getRequestSessionId():这个方法是获取客户机在请求的时候携带的sessionid值,有关session的相关知识,后面会详解
getRequestURL():这个方法是获取客户机请求的url
getServletPath():这个方法返回的是请求的Servlet的映射路径,比如:ServletRequest映射的是是/ServletRequest
getServerName()/getServerPort():这两个方法是获取服务器的名称和端口号,比如localhost,8080
getSession()/getSession(boolean mode):这两个方法是获取一个session对象,相关之后在session篇会说到
getAttribute(String name):这个方法是从Request域中获取值
getAttributeNames():这个方法是获取Request域中获取所有的字段名称
getParameter(String name):这个方法是获取用户使用get/post方式携带的参数值
getParameterNames():这个方法是获取用户请求时携带的所有参数名称
getParameterMap():这个方法是获取用户请求时携带的参数名称和参数值,并将其组装成一个Map对象
getParameterValues():这个方法是获取用户请求携带的参数值,因为有时候一个参数名称可能对应多个值
setAttribute(String name,Object value):这个方法是设置Request域中的属性值
removeAttribute(String name):这个方法是删除Request域中的属性值
getInputStream()/getReader():
这个方法是获取用户请求的时候上传的输入流,比如我们在处理用户上传文件的时候。需要用到这个输入流
setCharacterEncoding(String name):这个方法是设置Request容器的编码
getRemoteAddr()/getRemoteHost():获取客户机的IP地址和主机名
getProctocol():获取协议名称
getRequestDispatcher(String path):获取一个转发对象RequestDispatcher,进行转发操作
ends~