一,在一般项目中,涉及第三方接口调用,一般是采用webService或者httpClient。
基于项目要求,我这边做一个httpClient请求文件上传,是先从数据库表中读取二进制流,然后转存到本地服务器上面,最后调用httpClient上传至文件服务器上面,具体代码如下
package com.hxzq.s0026.my168.service.impl;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import com.google.gson.Gson;
import com.hxzq.commons.db.mapper.SQLQueryMapResult;
import com.hxzq.commons.ioc.HxSpringUtil;
import com.hxzq.s0026.my168.constants.Constants;
import com.hxzq.s0026.my168.dao.My168PhotoInitMapper;
import com.hxzq.s0026.my168.service.My168PhotoInitService;
import com.thinkive.base.config.Configuration;
import com.thinkive.base.exception.CommonException;
import com.thinkive.base.jdbc.DataRow;
import com.thinkive.base.util.JsonHelper;
import com.thinkive.base.util.StringHelper;
import com.thinkive.server.exception.BusinessException;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
@Service
public class My168PhotoInitServiceImpl implements My168PhotoInitService {
static Logger logger=Logger.getLogger(My168PhotoInitServiceImpl.class);
private static RequestConfig requestConfig;
private static String photoUrl;
// private static List<String> localPaths;//用于删除本地文件
static
{
//request配置超时时间
requestConfig = RequestConfig.custom()
.setConnectTimeout(60000)//设置连接超时时间,单位毫秒
.setConnectionRequestTimeout(1000)//设置从connect Manager获取Connection 超时时间,单位毫秒。这个属性是新加的属性,因为目前版本是可以共享连接池的
.setSocketTimeout(60000)//请求获取数据的超时时间,单位毫秒。 如果访问一个接口,多少时间内无法返回数据,就直接放弃此次调用
.build();
photoUrl=Configuration.getString("my168.photo_url");//获取文件上传文件服务器
}
@Override
public void initPhoto() {
// TODO Auto-generated method stub
My168PhotoInitMapper my168PhotoInitMapper = HxSpringUtil.getBean(Constants.sysNo, My168PhotoInitMapper.class);
SQLQueryMapResult rs = my168PhotoInitMapper.queryPhoto();
List<DataRow> list = rs.getDataList();
if (list.size() == 0) {
throw new CommonException(1, "头像不存在");
}
BASE64Encoder encoder = null;
String fileName = null;
String absolutePath = null;
// String
// location=request.getSession().getServletContext().getRealPath("/upload");
// 循环读取对应的图像二进制流,转换成图片上传进文件服务器
for (int i = 0; i < list.size(); i++) {
try {
byte[] bytes = (byte[]) list.get(i).get("avatar");
if (bytes==null) {
continue;
}
String userid = (String) list.get(i).get("userid");
fileName = userid + ".jpg";
encoder = new BASE64Encoder();
String avatarStr = encoder.encode(bytes);
BASE64Decoder decoder = new BASE64Decoder();
byte[] bytes1 = decoder.decodeBuffer(avatarStr);
InputStream bais = new ByteArrayInputStream(bytes1);
// 使用imageIo文件流出现类型异常,推荐使用二进制流
// JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(new
// InputStream(bais));
// BufferedImage sourceImg = decoder.decodeAsBufferedImage();
// BufferedImage bi1 = ImageIO.read(bais);
// File f1 = new File(fileName);
// ImageIO.write(bi1, "jpg", f1);
File file = new File(fileName);// 可以是任何图片格式.jpg,.png等
FileOutputStream fos = new FileOutputStream(file);
byte[] b = new byte[1024];
int nRead = 0;
while ((nRead = bais.read(b)) != -1) {
fos.write(b, 0, nRead);
}
fos.flush();
fos.close();
bais.close();
absolutePath = file.getAbsolutePath();// 获取真实路径
DataRow data = (DataRow) this.updateFile(absolutePath);
absolutePath = (String) data.get("file_path");
// 同步更新对应的数据库
my168PhotoInitMapper.updatePhotoAddrs(absolutePath, userid);
} catch (IOException e) {
throw new CommonException(2, "处理图片失败");
}
}
}
/**
*
* @说明: 打开一个httpClient连接,然后进行单个文件上传,后续可以考虑提供批量上传
* @方法名称: updateFile
* @参数 @param filePath 本地服务器上面的真实路径
* @参数 @return
* @返回类型 Object
* @修改时间: 2018年10月23日 下午1:57:21
*/
@SuppressWarnings("all")
private Object updateFile(String filePath) {
if (com.thinkive.base.util.StringUtil.isEmpty(filePath)) {
throw new BusinessException(1, "文件上传失败,附件为空!");
}
CloseableHttpClient httpClient = null;
HttpPost httpPost = null;
try {
httpClient = HttpClients.createDefault();
httpPost = new HttpPost(photoUrl);
httpPost.setConfig(requestConfig);//设置访问参数
Map<String,Object> dataMap = new HashMap<String,Object>();
dataMap.put("business_code", "png_upload");
//请求参数
String data=new Gson().toJson(dataMap);
//转成base64字符串
data= new BASE64Encoder().encode(data.getBytes());
//时间戳
String timestamp=String.valueOf(System.currentTimeMillis());
//签名结果值
String sign= encryptToMD5(signStr);
//设置访问入参
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setCharset(Charset.forName(HTTP.UTF_8));// 设置请求编码格式
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);// 设置浏览器兼容模式
builder.addBinaryBody("upfile", new File(filePath));//设置上传路径
builder.addTextBody("timestamp",timestamp);
builder.addTextBody("data", data);
builder.addTextBody("merchant_id", merchant_id);
builder.addTextBody("sign", sign);
HttpEntity entity = builder.build();
httpPost.setEntity(entity);
//执行http访问
HttpResponse response = httpClient.execute(httpPost);
int statusCode = response.getStatusLine().getStatusCode();//获取访问状态吗
if (statusCode == HttpStatus.SC_OK) {
HttpEntity resEntity = response.getEntity();
String jsonStr = EntityUtils.toString(resEntity);// httpClient自带的工具类读取返回数据
EntityUtils.consume(resEntity);
if (StringHelper.isEmpty(jsonStr)) {
throw new BusinessException(1, "文件上传异常,响应结果为空!");
}
// 解析响应结果
DataRow dataRow = JsonHelper.getObjectByJSON(jsonStr, DataRow.class);
if (dataRow.getInt("error_no") != 0) {
throw new BusinessException(dataRow.getInt("error_no"), dataRow.getString("error_info"));
}
//获取数据然后封装给对应的datarow
List<Map> list = (List<Map>) dataRow.get("results");
List<DataRow> newList = null;
if (null != list) {
newList = new ArrayList<DataRow>();
for (Map map : list) {
DataRow row = new DataRow();
row.putAll(map);
newList.add(row);
}
logger.info("服务端返回地址:"+newList.get(0));
return newList.get(0);
}
} else {
throw new BusinessException(1, "文件上传失败!状态码:" + statusCode);
}
} catch (Exception e) {
// TODO: handle exception
throw new BusinessException(1,"文件下载异常!");
} finally {
if (null != httpPost) {
try {
httpPost.clone();
} catch (CloneNotSupportedException e) {
}
}
if (null != httpClient) {
try {
httpClient.close();
} catch (IOException e) {
}
}
}
return null;
}
//设置模板加密,加密为MD5
public String encryptToMD5(String info)
{
byte[] digesta = null;
try
{
MessageDigest mDigest = MessageDigest.getInstance("MD5");
mDigest.update(info.getBytes());
digesta = mDigest.digest();
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
return bytesToHex(digesta);
}
//格式转换
private String bytesToHex(byte[] bytes)
{
String hex = "";
String temp = "";
for (int i = 0; i < bytes.length; i++)
{
temp = Integer.toHexString(bytes[i] & 0xFF);
if (temp.length() == 1) {
hex = hex + "0" + temp;
} else {
hex = hex + temp;
}
}
return hex;
}
//上传成功后删除本地图片,暂时未开发
private void deleteLocalPath(List<String> paths){
File file=null;
for (String path : paths) {
file=new File(path);
if (file.isDirectory()) {
throw new BusinessException(-1, "不允许删除文件夹");
}else{
file.delete();
}
}
}
}
ps:这边有一部分代码调用是调用本地库,传入的url是读取的配置文件。