欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

http请求功能的封装实现

程序员文章站 2022-04-27 16:42:20
...

闲来无事,看下一下项目上,大部分的http请求类,发现。。都是一个方法,最后得到一个String,一般的方法都是,getStringForHttp(url),getJsonForHttp。那么在这样的方法上,我想实现一个getByteForHttp的话,就只能重新复制一份代码,然后再最后的io操作,再另外处理。

 

但。。这叫什么面向对象,所以抽了点时间,写了个http的请求项目,暂时没测试出什么问题。希望有需要的,可以拿过去用,及时反馈bug。

 

1.http请求主流程走向:

 

/**
 * @author lyen.wu
 * http请求主流程
 */
public interface IYtBaseConnection {

	/**
	 * 设置request的参数
	 * @param connectParam
	 */
	public void setConnectParam(IYtBaseConnectParam connectParam);
	/**设置url,自动生成baseConnectParam*/
	public void setConnectParam(String url);
	/**
	 * 获取返回的结果对象
	 * */
	public IYtBaseConnectResult getConnectResult() ;
	public void post() throws Exception;
	public void get() throws Exception;
	/**
	 * 获取结果对象的简略结果,比如string,比如filePath
	 * */
	public Object getResultObj();
	
}

 2.封装请求参数

 

 

/**
 * @author lyen.wu
 * urlConnect请求的参数
 */
public interface IYtBaseConnectParam {

	/**
	 * 获取url链接
	 * */
	public String getUrl() ;
	/**
	 * 获取property属性
	 * */
	public Map<String, String> getPropertyMap();
	/**
	 * 设置property属性
	 * */
	public void setPropertyMap( Map<String, String> propertyMap);
	/**
	 * 获取请求参数
	 * */
	public String getParam();
	/**获取编码*/
	public String getCharsetCode() ;
	/**设置cookieMap,每次请求完成之后,都会将cookie设置进来*/
	public void setCookieMap(Map<String, String> cookieMap);
	/**获取cookieMap*/
	public Map<String, String> getCookieMap();
	/**302自动跳转*/
	public boolean isAutoRedirect();
	/**
	 * 最终是以byte的方法发送请求参数
	 * */
	public byte[] getParamByte();
}

 

 

3.封装请求的结果

 

/**
 * @author lyen.wu
 * http请求的结果类
 */
public interface IYtBaseConnectResult {
	/**设置状态码*/
	public void setStateCode(int stateCode);
	/**设置inputstream*/
	public void setIn(InputStream in);
	/**获取状态码*/
	public int getStateCode() ;
	/**获取http请求得到的inputstream*/
	public InputStream getIn();
	/**处理inputream的流*/
	public  void dealIn()throws Exception;
	/**处理inputream的流*/
	public  void dealIn(String charset) throws Exception;
}

 

 

至此这个http的骨架已经基本完善,剩下的就是为这个骨架贴肉。

4.首先是主流程的肉

 

package com.yt.tools.http.connection;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;

import com.yt.tools.http.connection.call.AbstractCall;
import com.yt.tools.http.connection.call.SimpleCall;
import com.yt.tools.http.connection.face.IYtBaseConnection;
import com.yt.tools.http.param.YtBaseConnectParam;
import com.yt.tools.http.param.face.IYtBaseConnectParam;
import com.yt.tools.http.result.face.IYtBaseConnectResult;
import com.yt.tools.http.utils.propety.YtHttpProtetyUtils;
import com.yt.tools.log.IYtConnLog;
import com.yt.tools.log.YtConnLogFactory;

/**
 * 基础的网络请求类,封装了总体流程
 * 
 * @author lyen.wu
 * 
 */
public abstract class YtBaseConnection implements IYtBaseConnection {
	private static IYtConnLog log = null;

	protected IYtBaseConnectResult connectResult;
	protected IYtBaseConnectParam connectParam;

	private AbstractCall call;

	public YtBaseConnection() {
		log = YtConnLogFactory.getLogger(this.getClass());
	}

	@Override
	public void setConnectParam(IYtBaseConnectParam connectParam) {
		this.connectParam = connectParam;
	}

	@Override
	public void setConnectParam(String url) {
		setConnectParam(new YtBaseConnectParam(url));
	}


	@Override
	public void post() throws Exception {
		getOrPost(getCall(), "post");
	}

	@Override
	public void get() throws Exception {
		getOrPost(getCall(), "get");
	}

	protected void getOrPost(AbstractCall call, String type) throws Exception {

		connectResult = getConnectResult();
		InputStream in = null;
		try {
			HttpURLConnection conn = getConnByConnectParm();
			// 建立实际的连接
			if (type.equals("get")) {
				call.doGet(conn);
			} else if (type.equals("post")) {
				call.doPost(conn, connectParam.getParamByte());
			}
			// 设置流
			in = conn.getInputStream();
			setResult(conn);
			// 定义BufferedReader输入流来读取URL的响应
			String cookieValue = conn.getHeaderField("Set-Cookie");
			YtHttpProtetyUtils.setCookie(connectParam.getCookieMap(),
					cookieValue);
			conn.disconnect();
		} catch (Exception e) {
			log.error("发送  " + type + " 请求出现异常!" + e);
			throw e;
		}
		// 使用finally块来关闭输入流
		finally {
			try {
				if (in != null) {
					in.close();
				}
				call.finallyAction();
				afterRequest();
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
	}
	/**
	 * 复写该方法,在请求之后的finally释放那里执行
	 */
	protected void afterRequest() {

	}

	public AbstractCall getCall() {
		if (call == null) {
			call = new SimpleCall();
		}
		return call;
	}

	public void setCall(AbstractCall call) {
		this.call = call;
	}

	/**
	 * 设置请求结果
	 * @param result
	 * @param conn
	 * @throws Exception
	 */
	protected void setResult( HttpURLConnection conn) throws Exception {
		// 设置请求结果
		int state = conn.getResponseCode();
		connectResult.setIn(conn.getInputStream());
		connectResult.setStateCode(state);
		// 处理流
		connectResult.dealIn(connectParam.getCharsetCode());
	}

	/**
	 * 设置conn的property属性
	 * @param conn
	 */
	protected void setPropertyMap(HttpURLConnection conn){
		if (connectParam.getPropertyMap() == null
				|| connectParam.getPropertyMap().size() == 0) {
			connectParam.setPropertyMap(YtHttpProtetyUtils
					.getCommonProtety());
		}
		Map<String, String> map = connectParam.getPropertyMap();
		// 设置通用的请求属性
		YtHttpProtetyUtils.setRequestProperty(conn, map);
		// 设置cookie
		YtHttpProtetyUtils.setRequestProperty(conn,
				connectParam.getCookieMap());
	}
	
	/**
	 * 根据connectParam生成HttpURLConnection
	 * @return
	 * @throws Exception
	 */
	public HttpURLConnection getConnByConnectParm() throws Exception{
		URL realUrl = new URL(connectParam.getUrl());

		// 打开和URL之间的连接
		HttpURLConnection conn = (HttpURLConnection) realUrl
				.openConnection();
		// 设置302自动跳转
		conn.setInstanceFollowRedirects(connectParam.isAutoRedirect());
		setPropertyMap(conn);
		return conn;
	}
	
}

 此主流程只是封装了正常的http请求功能,但是并没有处理io流的功能,io流的处理,应该交由子实现类去实现,因为有的功能需要图片,有的功能需要byte,有的功能需要String,这时候,应该暴露适当的流程空间交由外部去实现。

 

5.先补一个param的实现类:

 

/**
 * urlConnect请求的参数
 * 
 * @author lyen.wu
 * 
 */
public class YtBaseConnectParam implements IYtBaseConnectParam{

	//表头参数设置
	private Map<String, String> propertyMap = new HashMap<String, String>();
	//get或者post的参数
	private String param = "";
	//byte数组的请求参数,param会转成paramByte
	private byte[] paramByte = null;
	//请求的链接
	private String url = "";

	// 设置 HttpURLConnection的字符编码
	private String charsetCode = "UTF-8";
	
	//cookie用以共用session
	private Map<String, String> cookieMap = new HashMap<String, String>();

	private boolean autoRedirect = true;

	public YtBaseConnectParam(String url, String param) {
		this(url,null,null,param);
	}
	public YtBaseConnectParam(String url) {
		this(url,"");
	}

	public YtBaseConnectParam(String url, Map<String, String> propertiesMap,
			Map<String, String> headerMap, String param) {
		super();
		this.url = url;
		if(propertiesMap != null){
			this.propertyMap = propertiesMap;
		}
		this.param = param;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	/**
	 * 设置通用的property属性
	 */
	public Map<String, String> setCommonProperty() {
		propertyMap = YtHttpProtetyUtils.getCommonProtety();
		return propertyMap;
	}

	@Override
	public String toString() {
		return "ConnectParam [propertiesMap=" + propertyMap + ", param="
				+ param + ", url=" + url + "]";
	}

	public Map<String, String> getPropertyMap() {
		return propertyMap;
	}

	public void setPropertyMap(Map<String, String> propertiesMap) {
		this.propertyMap = propertiesMap;
	}

	public String getParam() {
		return param;
	}

	public void setParam(String param) {
		this.param = param;
	}

	public String getCharsetCode() {
		return charsetCode;
	}

	public void setCharsetCode(String charsetCode) {
		this.charsetCode = charsetCode;
	}

	public Map<String, String> getCookieMap() {
		return cookieMap;
	}

	public void setCookieMap(Map<String, String> cookieMap) {
		this.cookieMap = cookieMap;
	}
	
	/**
	 * 设置cookie内容,会自动转成map
	 * 第一个属性同时会存入,only-sessionId
	 * @param cookieContent
	 */
	public void setCookie(String cookieContent){
		if(cookieContent == null){
			return ;
		}
		
		String[] cookies = cookieContent.split(";");
		for( int i = 0 ; i < cookies.length ; i ++ ){
			String[] cookie = cookies[i].split("=");
			String key = cookie[0];
			String value = "";
			if(cookie.length > 1){
				value = cookie[1];
			}
			cookieMap.put(key , value);
			if(i == 0){
				cookieMap.put("only-sessionId", value);
			}
		}
		
	}
	public boolean isAutoRedirect() {
		return autoRedirect;
	}
	public void setAutoRedirect(boolean autoRedirect) {
		this.autoRedirect = autoRedirect;
	}
	public byte[] getParamByte() {
		if(paramByte == null){
			try {
				paramByte = param.getBytes(getCharsetCode());
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		}
		return paramByte;
	}
	public void setParamByte(byte[] paramByte) {
		this.paramByte = paramByte;
	}
	
	

}

 

 

 

比如常用的获取字符串功能。

YtStringConnection.java

 

package com.yt.tools.http.connection;

import com.yt.tools.http.result.YtBaseConnectResult;
import com.yt.tools.http.result.YtStringConnectResult;

/**
 * 文本网络请求,获取网页的内容或者回包
 * @author lyen.wu
 *
 */
public class YtStringConnection extends YtBaseConnection{

	private YtStringConnectResult stringConnectResult = null ;
	@Override
	public YtBaseConnectResult getConnectResult() {
		if(stringConnectResult == null){
			stringConnectResult =  new YtStringConnectResult();
		}
		return stringConnectResult;
	}
	@Override
	public Object getResultObj() {
		return stringConnectResult.getContent();
	}
	
	
}

 result结果类:

 

 

/**
 * 文本回包
 * @author lyen.wu
 *
 */
public class YtStringConnectResult extends YtBaseConnectResult {

	private String content = "";

	@Override
	public void dealIn(String charsetCode) throws Exception {
		content = YtInputStream2OtherUtils.in2String(in, charsetCode);
	}

	public String getContent(){
		return content;
	}
	
}

 

 

又比如文件获取类:

 

/**
 * 获取文件的网络请求,保存到本地。
 * @author lyen.wu
 *
 */
public class YtFileConnection extends YtBaseConnection{
	
	private YtFileConnectResult fileConnectResult = new YtFileConnectResult();
	public YtFileConnection(String filePath) {
		fileConnectResult.setFilePath(filePath);
	}

	@Override
	public YtBaseConnectResult getConnectResult() {
		return fileConnectResult;
	}
	@Override
	public Object getResultObj() {
		
		return fileConnectResult.getFilePath();
	}
	
	
}

 

/**
 * 转换成file
 * 
 * @author lyen.wu
 * 
 */
public class YtFileConnectResult extends YtBaseConnectResult {

	/** 文件存放路径 */
	private String filePath = "";

	@Override
	public void dealIn(String charset) throws Exception {
		YtInputStream2OtherUtils.in2File(in, filePath);
	}

	public String getFilePath() {
		return filePath;
	}

	public void setFilePath(String filePath) {
		this.filePath = filePath;

	}

}

 

 

流程就已经完成,剩下缺少的类就是一些工具类。

 

public class YtHttpProtetyUtils {
	
	public static String defaultCode = "UTF-8";
	
	/**
	 * 获取通用的requestPropertity设置
	 * 
	 * @return
	 */
	public static Map<String, String> getCommonProtety() {
		Map<String, String> map = new HashMap<String, String>();
		map.put("accept", "*/*");
		map.put("connection", "Keep-Alive");
		map.put("user-agent",
				"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
		map.put("Content-Type",ContentTypeEnum.APP_DEFAULT.getValue());
		return map;
	}

	/**
	 * 设置request属性
	 * 
	 * @param conn
	 * @param map
	 */
	public static void setRequestProperty(HttpURLConnection conn,
			Map<String, String> map) {
		if (map == null) {
			return;
		}
		for (String key : map.keySet()) {
			conn.setRequestProperty(key, map.get(key));
		}
	}
	
	/**
	 * 设置cookie内容,会自动转成map
	 * 第一个属性同时会存入,only-sessionId
	 * @param cookieContent
	 */
	public static void setCookie(Map<String,String> cookieMap, String cookieContent){
		if(cookieContent == null){
			return ;
		}
		
		String[] cookies = cookieContent.split(";");
		for( int i = 0 ; i < cookies.length ; i ++ ){
			String[] cookie = cookies[i].split("=");
			String key = cookie[0];
			String value = "";
			if(cookie.length > 1){
				value = cookie[1];
			}
			cookieMap.put(key , value);
			if(i == 0){
				cookieMap.put("only-sessionId", value);
			}
		}
		
	}

}

 

 

 

/**
 * Content-Type中的常用请求枚举
 * @author lyen.wu
 * email:flash_rui@126.com
 * 2017-12-14
 */
public enum ContentTypeEnum {

	JSON("application/json; charset="+YtHttpProtetyUtils.defaultCode),TEXT_XML("text/xml; charset="+YtHttpProtetyUtils.defaultCode),
	TEXT_HTML("text/html; charset="+YtHttpProtetyUtils.defaultCode),
	APP_DEFAULT("application/x-www-form-urlencoded; charset="+YtHttpProtetyUtils.defaultCode),
	TEXT_PLAIN("text/plain; charset="+YtHttpProtetyUtils.defaultCode);
	
	private String value;
	
	private ContentTypeEnum(String value){
		this.value = value;
	}

	public String getValue() {
		return value;
	}

	public void setValue(String value) {
		this.value = value;
	}
	
	
}

 

 

 

/**
 * inputStream流处理方法
 * @author lyen.wu
 * email:flash_rui@126.com
 * 2017-7-17
 */
public class YtInputStream2OtherUtils {

	/**
	 * in流转string
	 * @param in
	 * @param charsetCode
	 * @return
	 * @throws Exception
	 */
	public static String in2String(InputStream in,String charsetCode) throws Exception{
		BufferedReader br = null;
		try{
			String result = "";
			br = new BufferedReader(new InputStreamReader(in,
					charsetCode ));
			String line;
			while ((line = br.readLine()) != null) {
				result += line + "\n";
			}
			return result;
		}catch(Exception e){
			throw e;
		}finally{
			//当br关闭,in也会关闭,不过还是一个个的来
			if(br != null){
				br.close();
			}
			if(in != null){
				in.close();
			}
		}
		
		
	}
	/**
	 * in流转文件,且自动关闭
	 * @param inputStream
	 * @param filePath
	 * @throws Exception
	 */
	public static void in2File(InputStream inputStream , String filePath ) throws Exception{
		in2File(inputStream,filePath,true);
	}
	
	/**
	 * in流转File,参数决定是否关闭in流
	 * @param inputStream
	 * @param filePath
	 * @param autoClose 自动关闭in流
	 * @throws Exception
	 */
	public static void in2File(InputStream inputStream , String filePath , boolean autoClose) throws Exception{
		byte[] data = new byte[1024];
		int len = 0;
		FileOutputStream fileOutputStream = null;
		try {
			fileOutputStream = new FileOutputStream(filePath);
			while ((len = inputStream.read(data)) != -1) {
				fileOutputStream.write(data, 0, len);

			}
		} catch (Exception e) {
			throw e;
		} finally {

			if (autoClose && inputStream != null) {
				try {
					inputStream.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if (fileOutputStream != null) {
				try {
					fileOutputStream.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}

		}
	}
	/**
     * 从输入流获取数据
     * @param inputStream
     * @return
     * @throws Exception
     */
    public static byte[] in2Byte(InputStream inputStream) throws Exception{
        byte[] buffer = new byte[1024];
        int len = -1;
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        while((len = inputStream.read(buffer)) != -1){
            outputStream.write(buffer, 0, len);
        }
        outputStream.close();
        inputStream.close();
        return outputStream.toByteArray();
    }
	
}

 

 

Demo 请求样例代码:

@Test
	public void testPost() throws Exception{
		//需要post的参数
		String param = "param=1";
		//创建一个请求参数的param
		YtBaseConnectParam connectParam = new YtBaseConnectParam(
				"http://localhost:8080/test/temp1.json");
		connectParam.setParam(param);
		//创建一个标准的字符串结果请求
		IYtBaseConnection connection = new YtStringConnection();
		//设置请求baseparam
		connection.setConnectParam(connectParam);
		//post
		connection.post();
		//返回结果
		log.info(connection.getResultObj() + "");
	}
	
	@Test
	public void testImgGet() throws Exception {
		//设置http请求的流程且具体实现类是ytFileConnection
		IYtBaseConnection connection = new YtFileConnection("d:\\da.jpg");
		//设置请求地址
		connection.setConnectParam("http://pic.qiantucdn.com/58pic/15/28/06/57458PIC5Zb_1024.jpg!/fw/780/watermark/url/L3dhdGVybWFyay12MS4zLnBuZw==/align/center");
		//get
		connection.get();
		//得到保存的地址
		log.info(connection.getResultObj() + "");
	}
	
	@Test
	public void testStringGet() throws Exception {
		//设置http请求的流程且具体实现类是YtStringConnection
		IYtBaseConnection connection = new YtStringConnection();
		//设置请求地址
		connection.setConnectParam("http://www.baidu.com");
		//get
		connection.get();
		//得到这个网页的源码
		log.info(connection.getResultObj() + "");
	}

	@Test
	public void testJSONPost() throws Exception {
		//json参数
		String param = "{\"order\": \"32221\",\"refoundAmt\":\"9.5\"}";
		YtBaseConnectParam connectParam = new YtBaseConnectParam(
				"http://localhost:8080/pay/refund.json");
		connectParam.setParam(param);
		//此接口需要设置content-type方能解析。
		connectParam.setCommonProperty().put("Content-Type", ContentTypeEnum.JSON.getValue());
		IYtBaseConnection connection = new YtStringConnection();
		connection.setConnectParam(connectParam);
		connection.post();
		log.info(connection.getResultObj() + "");
	}

 

至此http请求功能完成。

 

但是可以看出,我们要请求一个url却要写那么一大堆代码,也是很不合理的,所以,封装可以封装的代码,再重构一下,此时就是外观模式的实现了:

YtHttpContextUtils:

 

public class YtHttpContextUtils {

	/**
	 * 获取String
	 * 
	 * @param url
	 * @return
	 * @throws Exception
	 */
	public  static String getString(String url) throws Exception {
		// 设置http请求的流程且具体实现类是YtStringConnection
		IYtBaseConnection connection = new YtStringConnection();
		// 设置请求地址
		connection.setConnectParam(url);
		// get
		connection.get();
		// 得到这个网页的源码
		return connection.getResultObj() + "";
	}

	/**
	 * 请求网络文件,并保存到本地
	 * 
	 * @param url
	 * @param localPath
	 * @throws Exception
	 */
	public  static void getFile(String url, String localPath) throws Exception {
		// 设置http请求的流程且具体实现类是ytFileConnection
		IYtBaseConnection connection = new YtFileConnection(localPath);
		// 设置请求地址
		connection.setConnectParam(url);
		// get
		connection.get();

	}

	/**
	 * post json方式请求url
	 * 
	 * @param url
	 * @param param
	 *            json字符串
	 * @return
	 * @throws Exception
	 */
	public  static String postJson(String url, String param) throws Exception {
		return post(url,param,ContentTypeEnum.JSON.getValue());
	}

	/**
	 * post String方式请求url
	 * @param url
	 * @param param 字符串
	 * @return
	 * @throws Exception
	 */
	public  static String postString(String url, String param) throws Exception {
		return post(url,param,ContentTypeEnum.APP_DEFAULT.getValue());
	}
	
	/**
	 * post请求,且要设置property
	 * @param url
	 * @param param
	 * @param propertyString
	 * @return
	 * @throws Exception
	 */
	public static String post(String url, String param , String propertyString) throws Exception {
		// json参数
		YtBaseConnectParam connectParam = new YtBaseConnectParam(url);
		connectParam.setParam(param);
		// 此接口需要设置content-type方能解析。
		connectParam.setCommonProperty().put("Content-Type",propertyString);
		IYtBaseConnection connection = new YtStringConnection();
		connection.setConnectParam(connectParam);
		connection.post();
		return connection.getResultObj() + "";
	}
	

}
 

 

此时的demo就变成了:

static IYtConnLog log = YtConnLogFactory.getLogger(Demo.class);
	
	@Test
	public void testPost() throws Exception{
		//需要post的参数
		String param = "param=1";
		String url = "http://localhost:8080/test/temp1.json";
		
		String content = YtHttpContextUtils.postString(url, param);
		log.info(content);
	}
	
	@Test
	public void testStringGet() throws Exception {
		String url = "http://www.baidu.com";
		
		String content = YtHttpContextUtils.getString(url);
		log.info(content);
	}

	@Test
	public void testJSONPost() throws Exception {
		//json参数
		String param = "{\"order\": \"32221\",\"refoundAmt\":\"9.5\"}";
		String url = "http://localhost:8080/pay/refund.json";
		
		String result = YtHttpContextUtils.postJson(url, param);
		log.info(result);
		
	}

	
	@Test
	public void testFileGet() throws Exception {
		String url = "http://www.webxml.com.cn/files/WeatherWsHelp.pdf";
		String localPath = "d:\\WeatherWsHelp.pdf";
		
		YtHttpContextUtils.getFile(url, localPath);
	}

 

 

 

 

git路径:https://github.com/JavaRui/com.yt.tools/tree/master/com.yt.tools.http

 

 

 

 

 

相关标签: java http 封装