废话不多说,先上两个工具类:用作普通的网络请求使用,文件的下载单独抽取一个工具类.
public class HttpURLBuild {
private final String TAG = "HttpURLBuild";
private String requestUrl = "";
private final String requestMethod;
final String PREFIX = "--"; //前缀
final String BOUNDARY = UUID.randomUUID().toString(); //边界标识
final String CONTENT_TYPE = "multipart/form-data"; //内容类型
final String LINE_END = "\r\n"; //换行
private static final String CHARSET = "utf-8"; //编码格式
// private HttpClientUtils.OnRequestCallBack callBackListener;
private HttpClientUtils.OnRequestCallBackBase callBackListenerBase;
public HttpURLBuild(String requestUrl, String requestMethod) {
this.requestUrl = requestUrl;
this.requestMethod = requestMethod;
}
HashMap<String, String> headMap = new HashMap<>();
HashMap<String, File> fileMap = new HashMap<>();
public HttpURLBuild setHead(String key, String value) {
headMap.put(key, value);
return this;
}
public HttpURLBuild addFile(String key, File file) {
fileMap.put(key, file);
return this;
}
Map<String, String> bodyMap = new HashMap<>();
String rawJson = "";
public HttpURLBuild addParameter(String key, String value) {
bodyMap.put(key, value);
return this;
}
public HttpURLBuild addParameter(Map<String, String> parameterMap) {
bodyMap.putAll(parameterMap);
return this;
}
public HttpURLBuild addRawData(String rawJson) {
this.rawJson = rawJson;
return this;
}
public HttpURLBuild setCallBack(HttpClientUtils.OnRequestCallBack callBackListener) {
if (callBackListener == null) {
return this;
}
this.callBackListenerBase = new HttpClientUtils.OnRequestCallBackBase(callBackListener);
return this;
}
StringBuilder builder = new StringBuilder();
//调用这个方法就开始正真的网络请求了 之前都是参数的设置,你别管我,让我看看
public HttpURLBuild build() {
if (isCancel) {
LogUtil.e(TAG, "请求已取消: " + requestUrl);
return null;
}
if (TextUtils.isEmpty(requestUrl)) {
throw new NullPointerException("请求地址不能为空");
}
if (callBackListenerBase == null) {
throw new IllegalArgumentException("回调地址不能为空,请检查setCallBack()是否调用");
}
AppExecutors.getInstance().networkIO().execute(new Runnable() {
@Override
public void run() {
// 现将参数写入缓冲区等待发送
DataOutputStream out = null;
boolean isSuccess = false;
String message;
InputStream inputStream = null;
ByteArrayOutputStream baos = null;
try {
if ("get".equalsIgnoreCase(requestMethod) && bodyMap.size() > 0) {
requestUrl += "?";
for (String key : bodyMap.keySet()) {
requestUrl += key;
requestUrl += bodyMap.get(key);
}
}
URL url = new URL(requestUrl);
final HttpURLConnection httpURLConnection;
httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setConnectTimeout(60 * 1000);
// 设定请求的方法为"POST",默认是GET
httpURLConnection.setReadTimeout(60 * 1000);
if ("get".equalsIgnoreCase(requestMethod)) {
httpURLConnection.setRequestMethod("GET");
} else if ("post".equalsIgnoreCase(requestMethod)) {
httpURLConnection.setRequestMethod("POST");
// 设置是否向httpUrlConnection输出,如果是post请求,参数要放在http正文内,因此需要设为true, 默认是false;
httpURLConnection.setDoOutput(true);//这里设置成true就代表是post请求
}
/*
* 当我们要获取我们请求的http地址访问的数据时就是使用connection.getInputStream().read()方式时我们就需要setDoInput(true),
* 根据api文档我们可知doInput默认就是为true。我们可以不用手动设置了,如果不需要读取输入流的话那就setDoInput(false)。
* 当我们要采用非get请求给一个http网络地址传参 就是使用connection.getOutputStream().write() 方法时我们就需要setDoOutput(true), 默认是false
*/
// 设置是否从httpUrlConnection读入,默认情况下是true;
httpURLConnection.setDoInput(true);
//是否使用缓存
httpURLConnection.setUseCaches(false);
// httpURLConnection.setInstanceFollowRedirects(true); 刚加上的 瞎试的
httpURLConnection.setRequestProperty("accept", "*/*");//设置接收数据的格式
httpURLConnection.setRequestProperty("Connection", "Keep-Alive");//设置连接方式为长连接
httpURLConnection.setRequestProperty("Charset", "UTF-8");//设置编码字符格式
//设置发送数据的格式
httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");//关键代码post的表单提交 application/x-www-form-urlencoded
builder.append("请求地址为-> \n");
builder.append(requestUrl + "\n");
//不进行转码的gson
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
builder.append("请求头为->\n" + gson.toJson(headMap) + "\n");
addHeads(httpURLConnection);
if ("post".equalsIgnoreCase(requestMethod)) {
out = new DataOutputStream(httpURLConnection.getOutputStream());
//添加请求体 如果不传file的话是这种方式进去
if (fileMap.size() == 0) {
String params = addBodyParams(out);
}
addRawData(out);
if (fileMap.size() > 0) {
addFileData(out);
}
// out.flush();
}
Log.d(TAG, "请求参数为-->" + builder.toString());
// 发送请求params参数
// out.flush();
//这个时候才是真正的将参数发送给服务器的时候 可以不连接getInputStream的时候会自动连接
httpURLConnection.connect();
// int contentLength = httpURLConnection.getContentLength();
if (httpURLConnection.getResponseCode() == 200) {
// 会隐式调用connect()
inputStream = httpURLConnection.getInputStream();
baos = new ByteArrayOutputStream();
int readLen;
byte[] bytes = new byte[1024];
while ((readLen = inputStream.read(bytes)) != -1) {
baos.write(bytes, 0, readLen);
}
String backStr = baos.toString();
message = backStr;
Log.d(TAG, "请求结果为-->" + message);
isSuccess = true;
} else {
message = "请求失败 code:" + httpURLConnection.getResponseCode();
}
} catch (IOException e) {
message = e.getMessage();
if (!isCancel) {
callBackListenerBase.onError(message);
}
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
if (baos != null) {
baos.close();
}
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
message = e.getMessage();
if (!isCancel) {
callBackListenerBase.onError(message);
}
e.printStackTrace();
}
}
if (isCancel) {
LogUtil.e(TAG, "请求已取消:数据未回调 " + requestUrl);
return;
} else {
if (isSuccess) {
callBackListenerBase.onSuccess(message);
} else {
callBackListenerBase.onError(message);
}
}
}
});
return this;
}
private void addFileData(DataOutputStream out) throws IOException {
//这个是普通的参数
if (bodyMap.size() > 0) {
StringBuilder strParams = getStrParams(bodyMap);
out.write(strParams.toString().getBytes(CHARSET));
out.flush();
builder.append(strParams);
}
//这个是文件的参数
if (fileMap != null && fileMap.size() > 0) {
//文件上传
getStrParamsFile(out);
Log.d(TAG + "文件请求参数为", builder.toString());
}
}
private void getStrParamsFile(DataOutputStream out) throws IOException {
StringBuilder fileSb = new StringBuilder();
for (Map.Entry<String, File> fileEntry : fileMap.entrySet()) {
fileSb.append(PREFIX)
.append(BOUNDARY)
.append(LINE_END)
/**
* 这里重点注意: name里面的值为服务端需要的key 只有这个key 才可以得到对应的文件
* filename是文件的名字,包含后缀名的 比如:abc.png
*/
.append("Content-Disposition: form-data; name=\"image\"; filename=\"" + fileMap.get(fileEntry.getKey()).getName() + "\"" + LINE_END)
.append("Content-Type: image/jpg" + LINE_END) //此处的ContentType不同于 请求头 中Content-Type
.append("Content-Transfer-Encoding: 8bit" + LINE_END)
.append(LINE_END);// 参数头设置完以后需要两个换行,然后才是参数内容
out.write(fileSb.toString().getBytes(CHARSET));
out.flush();
InputStream is = new FileInputStream(fileEntry.getValue());
byte[] buffer = new byte[1024];
int len = 0;
while ((len = is.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
is.close();
out.writeBytes(LINE_END);
}
//请求结束标志
out.write((PREFIX + BOUNDARY + PREFIX + LINE_END).getBytes(CHARSET));
out.flush();
builder.append(fileSb);
}
/**
* 当传文件的时候的其他的普通参数设置
* 对post参数进行编码处理
*/
private StringBuilder getStrParams(Map<String, String> strParams) {
StringBuilder strSb = new StringBuilder();
for (Map.Entry<String, String> entry : strParams.entrySet()) {
strSb.append(PREFIX)
.append(BOUNDARY)
.append(LINE_END)
.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"" + LINE_END)
.append("Content-Type: text/plain; charset=" + CHARSET + LINE_END)
.append("Content-Transfer-Encoding: 8bit" + LINE_END)
.append(LINE_END)// 参数头设置完以后需要两个换行,然后才是参数内容
.append(entry.getValue())
.append(LINE_END);
}
return strSb;
}
/**
* raw请求方式的参数设置
*
* @param out
* @throws IOException
*/
private void addRawData(DataOutputStream out) throws IOException {
if (!TextUtils.isEmpty(rawJson)) {
out.write(rawJson.getBytes(CHARSET));
builder.append("raw参数Wie" + rawJson + "\n");
}
}
/**
* 这个是普通的表单数据用到的 如果有传递文件的就不用这个了 用的是下面那种拼接方式的
*
* @param out
* @return
* @throws IOException
*/
@NotNull
private String addBodyParams(DataOutputStream out) throws IOException {//别动了
String params = "";
if (bodyMap.size() > 0) {
for (String key : bodyMap.keySet()) {
params = params + key + "=" + bodyMap.get(key) + "&";
}
params = params.substring(0, params.length() - 1);
//需要进行URL的转码 这是我看着retorfit返回的结果自己写的转码 也不知道些全了没
//对一些特殊的字符需要进行转码操作,下面是我发现需要转码的字符,有没有其他的还有待检验
params = params
.replace("+", "%2B")
.replace("/", "%2F")
.replace("\\", "%5C")
.replace("\"", "%22")
.replace("{", "%7B")
.replace("|", "%7C")
.replace("}", "%7D")
.replace(":", "%3A");
builder.append("请求参数为 ->\n" + params + "\n");
//使用这个可以解决中文乱码的问题 使用 out.writeBytes();会有中文乱码的问题
out.write(params.getBytes(CHARSET));
}
return params;
}
private void addHeads(HttpURLConnection httpURLConnection) {
//添加head请求头
for (String key : headMap.keySet()) {
//如果是文件类型的后面追加一个边界值
if (TextUtils.equals(key, "Content-Type") && TextUtils.equals(headMap.get(key), CONTENT_TYPE)) {
httpURLConnection.setRequestProperty(key, headMap.get(key) + ";boundary=" + BOUNDARY);
} else {
httpURLConnection.setRequestProperty(key, headMap.get(key));
}
}
}
private volatile boolean isCancel = false;
/**
* 取消网络请求,其实并不是真正的取消
* 1.如果还未发起网络请求就不发起网络请求
* 2.如果已发起网络情趣,则不回调成功的方法,即不处理返回的数据
*/
public void cancel() {
isCancel = true;
}
private byte[] file2byte(File file) {
byte[] buffer = null;
try {
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int n;
while ((n = fis.read(b)) != -1) {
bos.write(b, 0, n);
}
bos.flush();
fis.close();
bos.close();
buffer = bos.toByteArray();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return buffer;
}
/**
* 传文件的代码示例
* <p>
* <p>
* public static void postRequest(final Map<String, String> strParams, final Map<String, File> fileParams) {
* new Thread(new Runnable() {
*
* @Override public void run() {
* HttpURLConnection conn = null;
* try {
* URL url = new URL(requestUrl);
* conn = (HttpURLConnection) url.openConnection();
* conn.setRequestMethod("POST");
* conn.setReadTimeout(TIME_OUT);
* conn.setConnectTimeout(TIME_OUT);
* conn.setDoOutput(true);
* conn.setDoInput(true);
* conn.setUseCaches(false);//Post 请求不能使用缓存
* //设置请求头参数
* conn.setRequestProperty("Connection", "Keep-Alive");
* conn.setRequestProperty("token", token);
* conn.setRequestProperty("Charset", "UTF-8");
* conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY);
* //上传参数
* DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
* //getStrParams()为一个
* dos.writeBytes(
*
* getStrParams(strParams).
*
* toString());
* dos.flush();
*
* //文件上传
* StringBuilder fileSb = new StringBuilder();
* for(
* Map.Entry<String, File> fileEntry :fileParams.entrySet())
*
* {
* fileSb.append(PREFIX)
* .append(BOUNDARY)
* .append(LINE_END)
* //
* //这里重点注意: name里面的值为服务端需要的key 只有这个key 才可以得到对应的文件
* //filename是文件的名字,包含后缀名的 比如:abc.png
* //
* .append("Content-Disposition: form-data; name=\"image\"; filename=\"" + fileParams.get(fileEntry.getKey()).getName() + "\"" + LINE_END)
* .append("Content-Type: image/jpg" + LINE_END) //此处的ContentType不同于 请求头 中Content-Type
* .append("Content-Transfer-Encoding: 8bit" + LINE_END)
* .append(LINE_END);// 参数头设置完以后需要两个换行,然后才是参数内容
* dos.writeBytes(fileSb.toString());
* dos.flush();
* InputStream is = new FileInputStream(fileEntry.getValue());
* byte[] buffer = new byte[1024];
* int len = 0;
* while ((len = is.read(buffer)) != -1) {
* dos.write(buffer, 0, len);
* }
* is.close();
* dos.writeBytes(LINE_END);
* }
* //请求结束标志
* dos.writeBytes(PREFIX +BOUNDARY +PREFIX +LINE_END);
* dos.flush();
* dos.close();
*
* Log.e(TAG,"postResponseCode() = "+conn.getResponseCode());
* //读取服务器返回信息
* if(conn.getResponseCode()==200)
*
* {
* InputStream in = conn.getInputStream();
* BufferedReader reader = new BufferedReader(new InputStreamReader(in));
* String line = null;
* StringBuilder response = new StringBuilder();
* while ((line = reader.readLine()) != null) {
* response.append(line);
* }
* Log.e(TAG, "run: " + response);
* }
* } catch(Exception e){
* e.printStackTrace();
* }finally{
* if(conn!=null){
* conn.disconnect();
* }
* }
* }
* }).start();
* }
*
*
* private static StringBuilder getStrParams(Map<String, String> strParams){
* StringBuilder strSb=new StringBuilder();
* for(Map.Entry<String, String> entry:strParams.entrySet()){
* strSb.append(PREFIX)
* .append(BOUNDARY)
* .append(LINE_END)
* .append("Content-Disposition: form-data; name=\""+entry.getKey()+"\""+LINE_END)
* .append("Content-Type: text/plain; charset="+CHARSET+LINE_END)
* .append("Content-Transfer-Encoding: 8bit"+LINE_END)
* .append(LINE_END)// 参数头设置完以后需要两个换行,然后才是参数内容
* .append(entry.getValue())
* .append(LINE_END);
* }
* return strSb;
* }
*
*/
}
工具类2 主要用作,数据的回调
public class HttpClientUtils {
/**
*
* 使用示例
* HttpClientUtils().post(Api.API_BASE_URL_2 + "sdk_face_alive")
* .setHead("token",XueGuMax.getToken())
* .addParameter("serviceName", "real_auth_sdk")
* .addParameter("platformNo", XueGuMax.getPlatformNo())
* .addParameter("reqData", reqData)
* .setCallBack(object : HttpClientUtils.OnRequestCallBack {
* override fun onSuccess(json: String?) {
* val data = Gson().fromJson(json, AuthResult::class.java)
*
* }
* override fun onError(errorMsg: String?) {
* Log.e("数据获取失败", errorMsg)
* }}).build
*/
private static final String TAG = "HttpClientUtils";
private Handler mHandler = new Handler(Looper.getMainLooper());
/**
* 我自己封住的
* 此方法为post请求,异步的网络请求,回调在主线程
**/
public HttpURLBuild post(final String requestUrl) {
HttpURLBuild httpURLBuild = new HttpURLBuild(requestUrl, "post");
return httpURLBuild;
}
public HttpURLBuild get(final String requestUrl) {
HttpURLBuild httpURLBuild = new HttpURLBuild(requestUrl, "get");
return httpURLBuild;
}
public interface OnRequestCallBack {
void onSuccess(String json);
void onError(String errorMsg);
}
public static class OnRequestCallBackBase {
public OnRequestCallBack OnRequestCallBack;
public OnRequestCallBackBase(OnRequestCallBack onRequestCallBack) {
this.OnRequestCallBack = onRequestCallBack;
}
public void onSuccess(String json) {
if (TextUtils.equals(json,"null")||TextUtils.isEmpty(json)) {
OnRequestCallBack.onError("数据为空");
return;
}
AppExecutors.getInstance().mainThread().execute(new Runnable() {
@Override
public void run() {
// Type type = getClass().getGenericSuperclass();
// Type trueType = ((ParameterizedType) type).getActualTypeArguments()[0];
OnRequestCallBack.onSuccess(json);
}
});
}
public void onError(String errorMsg) {
AppExecutors.getInstance().mainThread().execute(new Runnable() {
@Override
public void run() {
OnRequestCallBack.onError(errorMsg);
}
});
}
}
}
这里面的网络请求默认在子线程,回调在主线程所以使用到了一个线程的工具类也贴出来
public class AppExecutors {
private final Executor mDiskIO;
private final Executor mNetworkIO;
private final Executor mMainThread;
private final ScheduledThreadPoolExecutor schedule;
private static AppExecutors instance;
private static Object object = new Object();
public static AppExecutors getInstance() {
if (instance == null) {
synchronized (object) {
if (instance == null) {
instance = new AppExecutors();
}
}
}
return instance;
}
private AppExecutors() {
this.mDiskIO = Executors.newSingleThreadExecutor(new MyThreadFactory("single"));
this.mNetworkIO = Executors.newFixedThreadPool(3, new MyThreadFactory("fixed"));
this.mMainThread = new MainThreadExecutor();
this.schedule = new ScheduledThreadPoolExecutor(5, new MyThreadFactory("sc"), new ThreadPoolExecutor.AbortPolicy());
}
class MyThreadFactory implements ThreadFactory {
private final String name;
private int count = 0;
MyThreadFactory(String name) {
this.name = name;
}
@Override
public Thread newThread(@NonNull Runnable r) {
count++;
return new Thread(r, name + "-" + count + "-Thread");
}
}
public Executor diskIO() {
return mDiskIO;
}
public ScheduledThreadPoolExecutor schedule() {
return schedule;
}
public Executor networkIO() {
return mNetworkIO;
}
public Executor mainThread() {
return mMainThread;
}
private static class MainThreadExecutor implements Executor {
private Handler mainThreadHandler = new Handler(Looper.getMainLooper());
@Override
public void execute(@NonNull Runnable command) {
mainThreadHandler.post(command);
}
}
}
下面是使用的示例 (示例代码用的是kotlin编写的)
get请求
HttpClientUtils().get(url)
.setCallBack(object : HttpClientUtils.OnRequestCallBack {
override fun onSuccess(json: String?) {
Log.i("token获取成功", json.toString())
val fromJson = Gson().fromJson(json, TokenBean::class.java)
}
}
override fun onError(errorMsg: String?) {
Log.i("获取失败", errorMsg)
}
}).build()
post请求(默认使用的格式是表单,如果是其他的文件类型,raw类型等请重新设置.setHead(“Content-Type”, “multipart/form-data”)//设置发送数据的格式)
post请求上传文件+一些参数
HttpClientUtils().post(Api.API_BASE_URL_2 + "gauss/api/vrc_ocr_sdk.json")
.setHead("token", XueGuMax.getToken())
.setHead("Content-Type", "multipart/form-data")//设置发送数据的格式
.addParameter("serviceName", serviceName)
.addParameter("platformNo", platformNo)
.addParameter("reqData", reqData)
.addParameter("type", type)
.addFile("image", image)
.setCallBack(object : HttpClientUtils.OnRequestCallBack {
override fun onSuccess(json: String?) {
val data = Gson().fromJson(json, OcrNoResult::class.java)
Log.i("PCarInfo", "请求结果:${data.toString()}")
}
override fun onError(errorMsg: String?) {
Log.e("数据获取失败", errorMsg)
}
}).build()
正常的表单数据提交
HttpClientUtils().post(Api.API_BASE_URL_2 + "gauss/vrc_ocr/finalResult.json")
.setHead("token", XueGuMax.getToken())
.addParameter("no", no)
.addParameter("platformNo", platformNo)
.setCallBack(object : HttpClientUtils.OnRequestCallBack {
override fun onSuccess(json: String?) {
val data = Gson().fromJson(json, CarOcrResult::class.java)
Log.i("PCarInfo", "请求结果:${data.toString()}")
}
}
override fun onError(errorMsg: String?) {
Log.e("数据获取失败", errorMsg)
}
}).build()
raw请求
val gson = Gson()
val params = HashMap<String, String>()
params.put("name", "")
params.put("idCard", "")
params.put("backUrl", "")
params.put("time", time)
params.put("sign", sign)
params.put("global", "")
params.put("action", "")
val strEntity = gson.toJson(params)
val url = "https://xxxxxx.com/set/identity_verify"
HttpClientUtils().post(url)
.setHead("Content-Type", "application/json")
.addRawData(strEntity)
.setCallBack(object : HttpClientUtils.OnRequestCallBack {
override fun onSuccess(json: String?) {
Log.i("获取成功", json.toString())
val fromJson = Gson().fromJson(json, ParamUrl::class.java)
getToken(fromJson.data, type)
}
override fun onError(errorMsg: String?) {
Log.i("获取失败", errorMsg)
}
}).build()
写的不咋好,网络能请求通,可以暂时先将就着用,如果不满意那就自行封装吧
版权声明:本文为MYNAMEQI原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。