在 SpringBoot 工程中,通过 HttpURLConnection 类来实现 HTTP 请求吧。
类 HttpURLConnection 是 JDK 自带的。
它的应用场景:在自己的工程中,你想调用第三方接口(外部接口)来获取数据,那么 HttpURLConnection 类就可以实现。接下来通过两个小案例来进行实现吧。
开发步骤:
- 先开发外部接口
- 再开发内部接口
- 在内部接口中,通过类 HttpURLConnection 去调用外部接口
为了测试方便,我这里就将外部接口、内部接口,全写在通过一个工程里面了哈。
1. 开发外部接口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 listUsers() {
return httpService.listUsers();
}
/// POST 请求/
// 通过id获取用户信息
@PostMapping("/getUserVoById")
public UserVo getUserVoById(String id) {
return httpService.getUserById(id);
}
// 获取所有用户信息
@PostMapping("/listUserList")
public List listUserList() {
return httpService.listUsers();
}
}
说明:
- 4个接口分别按照 get、post 请求区分
- get/post 请求中的两个接口:无参:查询所有用户信息;有参:按照用户id查询用户信息
HttpServiceImpl:这里我没有连接数据库,直接使用了假数据。
@Service
@Slf4j
public class HttpServiceImpl implements HttpService {
private static Map 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 listUsers() {
List userVos = new ArrayList<>();
for (Map.Entry userVoEntry : userVoMap.entrySet()) {
UserVo userVo = userVoEntry.getValue();
userVos.add(userVo);
}
return userVos;
}
}
好了,到这就完成了我们外部接口的开发,接下来,就要通过类 HttpURLConnection 来调用这些接口了。
2. GET 请求在 HttpController 类中再开一个接口:用于 get 请求测试
@PostMapping("/httpUrlConnectionDoGet")
public void httpUrlConnectionDoGet(@RequestBody HttpUrlConnectionVo httpUrlConnectionVo) {
httpService.httpUrlConnectionDoGet(httpUrlConnectionVo);
}
HttpUrlConnectionVo:请求Vo
@Data
public class HttpUrlConnectionVo {
// 请求地址
private String uri;
// 请求参数
private Map 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 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;
}
}
说明:
- 此类中的常量已经定义好了外部接口的 ip、端口号。由于是本机,所有是 localhost。SpringBoot应用默认启动端口号为 8080
- 此类中的常量也区分的 get、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(Mapparams) { StringBuffer buffer = new StringBuffer(); for (Map.Entry 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 getBean(Class clz) {
return context != null ? context.getBean(clz) : null;
}
public static T getBean(String name, Class 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, Mapparams, 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 请求就到这了。



