【HttpURLConnection】使用 HttpURLConnection 后台模拟实现 HTTP 请求
【HttpClient】在 SpringBoot 中使用 HttpClient 实现 HTTP 请求
【SpringBoot】使用 OkHttp 完成网络请求
在 SpringBoot 工程中,通过 HttpURLConnection
类来实现 HTTP 请求吧。
类 HttpURLConnection
是 JDK 自带的。
它的应用场景:在自己的工程中,你想调用第三方接口(外部接口)来获取数据,那么 HttpURLConnection
类就可以实现。接下来通过两个小案例来进行实现吧。
开发步骤:
HttpURLConnection
去调用外部接口为了测试方便,我这里就将外部接口、内部接口,全写在通过一个工程里面了哈。
1、新建一个 SpringBoot 工程
2、新开发 4 个接口:这4个接口就假定为外部接口。也就是说,是在我们工程中需要调用的接口
HttpController
:两个接口用于 GET
请求的无参请求、有参请求;另外两个接口用于 POST
请求的无参请求、有参请求
@RestController
@RequestMapping("/http")
public class HttpController {
@Autowired
private HttpService httpService;
/// GET 请求/
// 通过id获取用户信息
@GetMapping("/getUserById")
public UserVo getUserById(String id) {
return httpService.getUserById(id);
}
// 获取所有用户信息
@GetMapping("/listUsers")
public List<UserVo> listUsers() {
return httpService.listUsers();
}
/// POST 请求/
// 通过id获取用户信息
@PostMapping("/getUserVoById")
public UserVo getUserVoById(String id) {
return httpService.getUserById(id);
}
// 获取所有用户信息
@PostMapping("/listUserList")
public List<UserVo> listUserList() {
return httpService.listUsers();
}
}
说明:
get
、post
请求区分get/post
请求中的两个接口:无参:查询所有用户信息;有参:按照用户id查询用户信息HttpServiceImpl
:这里我没有连接数据库,直接使用了假数据。
@Service
@Slf4j
public class HttpServiceImpl implements HttpService {
private static Map<String, UserVo> userVoMap;
static {
userVoMap = new HashMap<>();
userVoMap.put("1", new UserVo("1", "zzc", "上海市"));
userVoMap.put("2", new UserVo("2", "wzc", "北京市"));
userVoMap.put("3", new UserVo("3", "wxc", "武汉市"));
}
@Override
public UserVo getUserById(@RequestParam("id") String id) {
return userVoMap.get(id);
}
@Override
public List<UserVo> listUsers() {
List<UserVo> userVos = new ArrayList<>();
for (Map.Entry<String, UserVo> userVoEntry : userVoMap.entrySet()) {
UserVo userVo = userVoEntry.getValue();
userVos.add(userVo);
}
return userVos;
}
}
好了,到这就完成了我们外部接口的开发,接下来,就要通过类 HttpURLConnection
来调用这些接口了。
在 HttpController
类中再开一个接口:用于 get
请求测试
@PostMapping("/httpUrlConnectionDoGet")
public void httpUrlConnectionDoGet(@RequestBody HttpUrlConnectionVo httpUrlConnectionVo) {
httpService.httpUrlConnectionDoGet(httpUrlConnectionVo);
}
HttpUrlConnectionVo
:请求Vo
@Data
public class HttpUrlConnectionVo {
// 请求地址
private String uri;
// 请求参数
private Map<String, String> params;
// 编码
private String encoding;
}
HttpServiceImpl
:
@Override
public void httpUrlConnectionDoGet(@RequestBody HttpUrlConnectionVo httpUrlConnectionVo) {
if (StringUtil.isBlank(httpUrlConnectionVo.getEncoding())) {
log.error("【发送GET请求】失败,字符编码不能为空!");
return;
}
HttpUrlConnectionUtil.doGet(httpUrlConnectionVo.getUri(), httpUrlConnectionVo.getParams(), httpUrlConnectionVo.getEncoding());
}
HttpUrlConnectionUtil
:URLConnection工具类
@Slf4j
@Component
public class HttpUrlConnectionUtil {
// 服务器ip
public static final String IP = "http://localhost";
// 端口
public static final String PORT = ":8080";
// GET请求接口带参数
public static final String GET_URL_PARAMS = IP + PORT + "/http/getUserById";
// GET请求接口不带参数
public static final String GET_URL_NO_PARAMS = IP + PORT + "/http/listUsers";
// POST请求接口带参数
public static final String POST_URL_PARAMS = IP + PORT + "/http/getUserVoById";
// POST请求接口不带参数
public static final String POST_URL_NO_PARAMS = IP + PORT + "/http/listUserList";
// 返回成功编码
public static final Integer RESPONSE_CODE_SUCCESS = 200;
// POST请求
public static final String METHOD_POST = "POST";
private static HttpUrlConnectionConfig httpUrlConnectionConfig = ApplicationContextHolder.getContext().getBean(HttpUrlConnectionConfig.class);
// 通过HttpUrlConnection发起Get请求
public static String doGet(String uri, Map<String, String> params, String encoding) {
byte[] bytes = null;
if (MapUtil.isEmpty(params)) {
uri = GET_URL_NO_PARAMS;
} else {
uri = GET_URL_PARAMS;
try {
// 拼接参数
bytes = transformRequestParams(params).getBytes(encoding);
uri = uri + "?" + new String(bytes);
} catch (UnsupportedEncodingException e) {
log.error("【发送GET请求】字符集转换失败,失败信息为:{}", e);
return null;
}
}
log.info("【发送GET请求】请求地址为:{}", uri);
URL url = null;
HttpURLConnection connection = null;
try {
url = new URL(uri);
// 建立连接
connection = (HttpURLConnection)url.openConnection();
httpUrlConnectionConfig.setConnectionProperty(connection);
// 请求服务器
connection.connect();
// 获取服务器返回结果
String responseData = getResponseData(connection, encoding);
return responseData;
} catch (MalformedURLException e) {
log.error("【发送GET请求】创建URL失败,失败信息为:{}", e);
} catch (IOException e) {
log.error("【发送GET请求】创建连接失败,失败信息为:{}", e);
}
return null;
}
}
说明:
localhost
。SpringBoot应用默认启动端口号为 8080get
、post
以及无参、有参httpUrlConnectionConfig.setConnectionProperty(connection);
MapUtil
:判断 Map 是否为空
public class MapUtil {
public static boolean isEmpty(Map map) {
return (map == null || map.isEmpty());
}
public static boolean isNotEmpty(Map map) {
return !isEmpty(map);
}
}
transformRequestParams()
:将 Map 格式的参数转换为字符串
// 转换请求参数
public static String transformRequestParams(Map<String, String> params) {
StringBuffer buffer = new StringBuffer();
for (Map.Entry<String, String> entry : params.entrySet()) {
buffer.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
}
if (buffer.length() > 0) {
buffer.deleteCharAt(buffer.length() - 1);
}
return buffer.toString();
}
HttpUrlConnectionConfig
:HttpUrlConnection配置
@Component
public class HttpUrlConnectionConfig {
public static final Integer CONNECTION_TIME_OUT = 10000;
public static final Integer READ_TIME_OUT = 10000;
// 设置连接时的属性
public void setConnectionProperty(HttpURLConnection connection) {
connection.setConnectTimeout(CONNECTION_TIME_OUT);
connection.setReadTimeout(READ_TIME_OUT);
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "close");
connection.setRequestProperty("user-agent",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36");
if (HttpUrlConnectionUtil.METHOD_POST.equals(connection.getRequestMethod())) {
// 设置连接输出流为true,默认false (post 请求是以流的方式隐式的传递参数)
connection.setDoOutput(true);
// 设置连接输入流为true
connection.setDoInput(true);
// 表单数据
connection.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
}
}
}
ApplicationContextHolder
:以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候中取出 ApplicaitonContext
@Component
public class ApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext getContext() {
return context;
}
public static Object getBean(String name) {
return context != null ? context.getBean(name) : null;
}
public static <T> T getBean(Class<T> clz) {
return context != null ? context.getBean(clz) : null;
}
public static <T> T getBean(String name, Class<T> clz) {
return context != null ? context.getBean(name, clz) : null;
}
public static void addApplicationListenerBean(String listenerBeanName) {
if (context != null) {
ApplicationEventMulticaster applicationEventMulticaster = (ApplicationEventMulticaster)context.getBean(ApplicationEventMulticaster.class);
applicationEventMulticaster.addApplicationListenerBean(listenerBeanName);
}
}
}
getResponseData()
:获取响应信息
// 获取响应信息
public static String getResponseData(HttpURLConnection connection, String encoding) {
BufferedReader in = null;
StringBuffer result = new StringBuffer();
StringBuffer errorMsg = new StringBuffer();
try {
// 调用成功
if (RESPONSE_CODE_SUCCESS.equals(connection.getResponseCode())) {
// 处理服务器响应
in = new BufferedReader(new InputStreamReader(connection.getInputStream(), encoding));
String line = null;
while ((line = in.readLine()) != null) {
result.append(line);
}
log.info("【发送GET请求】请求成功,返回结果为:{}", result.toString());
return result.toString();
} else {
in = new BufferedReader(new InputStreamReader(connection.getErrorStream(), encoding));
String line = null;
while ((line = in.readLine()) != null) {
errorMsg.append(line);
}
log.error("【发送GET请求】请求失败,失败信息为:{}", errorMsg.toString());
return errorMsg.toString();
}
} catch (IOException e) {
log.error("【发送GET请求】创建连接失败,失败信息为:{}", e);
} finally {
if (null != in) {
try {
in.close();
} catch (IOException e) {
log.error("【发送GET请求】关闭流失败,出现IO异常,异常信息为:{}", e);
}
}
}
return null;
}
POSTMAN 调用接口:
1、GET 请求的无参:
查看控制台打印日志:
2、GET 请求的带参:
查看控制台打印日志:
HttpController
:在 HttpController
类中再开一个接口:用于 post
请求测试
@PostMapping("/httpUrlConnectionDoPost")
public void httpUrlConnectionDoPost(@RequestBody HttpUrlConnectionVo httpUrlConnectionVo) {
httpService.httpUrlConnectionDoPost(httpUrlConnectionVo);
}
HttpServiceImpl
:
@Override
public void httpUrlConnectionDoPost(HttpUrlConnectionVo httpUrlConnectionVo) {
if (StringUtil.isBlank(httpUrlConnectionVo.getEncoding())) {
log.error("【发送POST请求】失败,字符编码不能为空!");
return;
}
HttpUrlConnectionUtil.doPost(httpUrlConnectionVo.getUri(), httpUrlConnectionVo.getParams(), httpUrlConnectionVo.getEncoding());
}
HttpUrlConnectionUtil.doPost()
:
public static String doPost(String uri, Map<String, String> params, String encoding) {
byte[] bytes = null;
if (MapUtil.isEmpty(params)) {
uri = POST_URL_NO_PARAMS;
} else {
uri = POST_URL_PARAMS;
try {
// 以字节的形式获取参数
param = transformRequestParams(params);
bytes = param.getBytes(encoding);
} catch (UnsupportedEncodingException e) {
log.error("【发送GET请求】字符集转换失败,失败信息为:{}", e);
return null;
}
}
log.info("【发送POST请求】请求地址为:{}", uri);
URL url = null;
HttpURLConnection connection = null;
try {
url = new URL(uri);
// 1.建立连接
connection = (HttpURLConnection)url.openConnection();
// 【注意】这里的 POST 必须是大写,否则,会报错
connection.setRequestMethod(METHOD_POST);
httpUrlConnectionConfig.setConnectionProperty(connection);
// 2.请求服务器
connection.connect();
// 3.拼接参数
if (null != bytes && bytes.length > 0) {
OutputStream out = connection.getOutputStream();
out.write(bytes);
out.close();
}
// 4.获取服务器返回结果
String responseData = getResponseData(connection, encoding);
return responseData;
} catch (MalformedURLException e) {
log.error("【发送POST请求】创建URL失败,失败信息为:{}", e);
} catch (IOException e) {
log.error("【发送POST请求】创建连接失败,失败信息为:{}", e);
}
return null;
}
post
的有参、无参调用,跟 get
的一样,就是接口不同而已,可以自己试试吧。
好了,使用 HttpURLConnection
后台模拟实现 HTTP 请求就到这了。