http请求功能的封装实现

闲来无事,看下一下项目上,大部分的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:[email protected]
 * 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:[email protected]
 * 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

 

 

 

 

 

猜你喜欢

转载自1299020954.iteye.com/blog/2405136