闲来无事,看下一下项目上,大部分的http请求类,发现。。都是一个方法,最后得到一个String,一般的方法都是,getStringForHttp(url),getJsonForHttp。那么在这样的方法上,我想实现一个getByteForHttp的话,就只能重新复制一份代码,然后再最后的io操作,再另外处理。
?
但。。这叫什么面向对象,所以抽了点时间,写了个http的请求项目,暂时没测试出什么问题。希望有需要的,可以拿过去用,及时反馈bug。
?
1.http请求主流程走向:
?
class="java">/**
* @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请求功能完成。
git路径:https://github.com/JavaRui/com.yt.tools/tree/master/com.yt.tools.http
?
?
?
?
?