【HttpURLConnection】使用 HttpURLConnection 后台模拟实现 HTTP 请求

【HttpURLConnection】使用 HttpURLConnection 后台模拟实现 HTTP 请求
【HttpClient】在 SpringBoot 中使用 HttpClient 实现 HTTP 请求
【SpringBoot】使用 OkHttp 完成网络请求

在 SpringBoot 工程中,通过 HttpURLConnection 类来实现 HTTP 请求吧。

HttpURLConnection 是 JDK 自带的。

它的应用场景:在自己的工程中,你想调用第三方接口(外部接口)来获取数据,那么 HttpURLConnection 类就可以实现。接下来通过两个小案例来进行实现吧。

开发步骤:

  1. 先开发外部接口
  2. 再开发内部接口
  3. 在内部接口中,通过类 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<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();
    }

}

说明:

  1. 4个接口分别按照 getpost 请求区分
  2. 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 来调用这些接口了。

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<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;
    }

}

说明:

  1. 此类中的常量已经定义好了外部接口的 ip、端口号。由于是本机,所有是 localhost。SpringBoot应用默认启动端口号为 8080
  2. 此类中的常量也区分的 getpost 以及无参、有参
  3. 在静态方法中使用对象: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 请求的无参:

【HttpURLConnection】使用 HttpURLConnection 后台模拟实现 HTTP 请求_第1张图片
查看控制台打印日志:
在这里插入图片描述
2、GET 请求的带参:
【HttpURLConnection】使用 HttpURLConnection 后台模拟实现 HTTP 请求_第2张图片
查看控制台打印日志:
在这里插入图片描述

3. POST 请求

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 请求就到这了。

你可能感兴趣的:(SpringBoot,课外趣学,Java,java,开发语言,后端)