Android使用Https协议与Tomcat服务器进行文件上下传,并将上传的文件上传至HDFS

来源:互联网 发布:剑灵小秦夕妍捏脸数据 编辑:程序博客网 时间:2024/06/05 23:57

最近使用了HTTPS协议在Android设备上进行文件上下传操作,这里做一下记录。

一、Android端代码

1.下面的代码是关于文件上传和下载需要使用的工具类。

这个代码是模仿表单的形式提交文件信息。

package com.example.justyoung.logintest;import android.content.SharedPreferences;import android.util.Log;import java.io.BufferedReader;import java.io.DataOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.net.URL;import java.security.KeyManagementException;import java.security.NoSuchAlgorithmException;import java.security.SecureRandom;import java.security.cert.CertificateException;import java.security.cert.X509Certificate;import java.util.List;import java.util.Map;import javax.net.ssl.HostnameVerifier;import javax.net.ssl.HttpsURLConnection;import javax.net.ssl.SSLContext;import javax.net.ssl.SSLSession;import javax.net.ssl.TrustManager;import javax.net.ssl.X509TrustManager;/** * Created by justyoung on 15/6/28. */public class HttpsHelper {    public static final String PREFIX = "--";    public static final String LINE_END = "\r\n";    public static final String BOUNDARY = "*****";    private HttpsURLConnection connection = null;    private StringBuilder response = null;    public void prepareHttpsConnection(String url) throws KeyManagementException, NoSuchAlgorithmException, IOException {        SSLContext sslContext = SSLContext.getInstance("TLS");        sslContext.init(null, new TrustManager[]{new MyTrustManager()}, new SecureRandom());        HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());        HttpsURLConnection.setDefaultHostnameVerifier(new MyHostnameVerifier());        connection = (HttpsURLConnection) new URL(url).openConnection();        connection.setDoOutput(true);        connection.setDoInput(true);        connection.setConnectTimeout(10000);    }    public int uploadFile(String filename) throws IOException {        int result = 0;        if (filename == null)            return result;        connection.setUseCaches(false);        connection.setRequestMethod("POST");        connection.setRequestProperty("Charset", "utf-8");        connection.setRequestProperty("Connection", "keep-alive");        connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDARY);        DataOutputStream dos = new DataOutputStream(connection.getOutputStream());        dos.writeBytes(PREFIX + BOUNDARY + LINE_END);        dos.writeBytes("Content-Disposition: form-data; " +                "name=\"file1\";filename=\"" +                filename.substring(filename.lastIndexOf("/")) + "\"" + LINE_END);        dos.writeBytes(LINE_END);        int len;        InputStream ins = new FileInputStream(new File(filename));        byte[] buffer = new byte[1024];        while ((len = ins.read(buffer)) != -1) {            dos.write(buffer, 0, len);        }        ins.close();        dos.writeBytes(LINE_END);        dos.writeBytes(PREFIX + BOUNDARY + PREFIX + LINE_END);        dos.close();        int responseCode = connection.getResponseCode();        if (responseCode == 200) {            ins = connection.getInputStream();            int ch;            StringBuffer b = new StringBuffer();            while ((ch = ins.read()) != -1) {                b.append((char) ch);            }            Log.i("bbb", b.toString());        }        return responseCode;    }    /**     *     * @param despath 存储的位置     * @throws IOException     */    public void downloadFile(String despath) throws IOException {        connection.connect();        InputStream ins = connection.getInputStream();        File file = new File(despath);        if (file.exists()){            IOException e = new IOException("File exists");            throw e;        }        OutputStream out = null;        byte[] buffer = new byte[1024];        int len;        try {            out = new FileOutputStream(file);            while ((len = ins.read(buffer)) != -1) {                out.write(buffer, 0, len);            }            out.flush();        } catch (Exception e){        } finally {            if (out != null) {                try {                    out.close();                } catch (Exception e){                }            }        }    }    private static class MyHostnameVerifier implements HostnameVerifier {        @Override        public boolean verify(String hostname, SSLSession session) {            return true;        }    }    private static class MyTrustManager implements X509TrustManager {        @Override        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {        }        @Override        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {        }        @Override        public X509Certificate[] getAcceptedIssuers() {            return null;        }    }}

如果不用表单的方式提交,可以将文件,直接以二进制的形式填入到HTTP报文的BODY部分,如下所示:

public int uploadFile(String filename) throws IOException {        int result = 0;        if (filename == null)            return result;        connection.setUseCaches(false);        connection.setRequestMethod("POST");        connection.setRequestProperty("Charset", "utf-8");        connection.setRequestProperty("Connection", "keep-alive");        connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDARY);        connection.setRequestProperty("Cookie", "SESSIONID=28e8795c46d736d6b39aadffb653e23c3d0802ba;USERNAME=ylh2");        connection.setChunkedStreamingMode(0);        InputStream ins = new BufferedInputStream(new FileInputStream(new File(filename)));        BufferedOutputStream bos = new BufferedOutputStream(connection.getOutputStream());        byte[] buffer = new byte[4096];        int len = 0;        while((len = ins.read(buffer)) != -1) {            bos.write(buffer, 0, len);        }        ins.close();        bos.flush();        bos.close();        int responseCode = connection.getResponseCode();        if (responseCode == 200) {            ins = connection.getInputStream();            int ch;            StringBuffer b = new StringBuffer();            while ((ch = ins.read()) != -1) {                b.append((char) ch);            }            Log.i("bbb", b.toString());        }        return responseCode;    }




2.下面的代码是进行文件上传和下载的线程类,因为Android上的网络操作不能使用UI线程,所以都需要使用其他线程进行。

文件上传的代码如下:

package com.example.justyoung.logintest;import java.io.IOException;import java.security.KeyManagementException;import java.security.NoSuchAlgorithmException;/** * Created by justyoung on 15/6/30. */public class uploadFile extends Thread {    String path;    String url;    public uploadFile(String path, String url) {        this.path = path;        this.url = url;    }    @Override    public void run() {        HttpsHelper httpsHelper = new HttpsHelper();        try {            httpsHelper.prepareHttpsConnection(url);            httpsHelper.uploadFile(path);        } catch (KeyManagementException e) {            e.printStackTrace();        } catch (NoSuchAlgorithmException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }    }}

上传的代码可以这样调用:

String https = "https://192.168.2.160:8443/CloudStorageServer/uploadfile";String path = "/sdcard/DCIM/Camera/20150429_115313.jpg";uploadFile uploadFile = new uploadFile(path, https);uploadFile.start();

文件下载的代码如下:

package com.example.justyoung.logintest;import java.io.IOException;import java.security.KeyManagementException;import java.security.NoSuchAlgorithmException;/** * Created by justyoung on 15/7/1. */public class DownloadFile extends Thread {    private String url;    private String despath;    public DownloadFile(String url, String filename, String despath) {        this.url = url + "?filename=" + filename;        this.despath = despath;    }    public void run(){        HttpsHelper httpsHelper = new HttpsHelper();        try {            httpsHelper.prepareHttpsConnection(url);            httpsHelper.downloadFile(despath);        } catch (KeyManagementException e) {            e.printStackTrace();        } catch (NoSuchAlgorithmException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }    }}

下载的代码可以这样调用:

String https = "https://192.168.2.139:8443/CloudStorageServer/download";String desPath = "/sdcard/DCIM/Camera/123.pdf";DownloadFile df = new DownloadFile(https, "xx.pdf", desPath);df.start();

这里需要注意一个问题:因为使用的是HTTP协议进行传输,所以HTTP报文是一次性做好再发送给服务器,所以大文件上传可能会出现问题,例如:Android读取文件到DataOutputStream中时,就可能会因为占用内存过大而导致程序被强制退出,所以要进行大文件上传时,可以将文件分块后进行上传。


二、服务器端代码

我这里使用的是如下的类来接收Android端上传的文件和向Android端发送的文件,只是,这里将Android上传的文件从内存中直接上传到HDFS上,向Android端发送文件时,直接将文件从HDFS上读取到内存中,然后发送给Android客户端。

下面这个代码是接收模仿表单上传的代码。

package com.cyber_space.businessLogic;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import javax.servlet.ServletOutputStream;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.tomcat.util.http.fileupload.FileItemIterator;import org.apache.tomcat.util.http.fileupload.FileItemStream;import org.apache.tomcat.util.http.fileupload.FileUploadException;import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;import com.cyber_space.HDFSManager.DownloadFromBytes;import com.cyber_space.HDFSManager.HDFSUpload;import com.cyber_space.HDFSManager.UploadFromBytes;import com.cyber_space.util.Log;import com.cyber_space.util.properties.SysProperties;public class FileLogic {public static String TEMP_PATH; // 文件临时目录public static int SIZE_THRESHOLD;public static long SIZE_MAX;static {init();}public static void init() {TEMP_PATH = SysProperties.getValue("file_temp_dir");SIZE_THRESHOLD = Integer.valueOf(SysProperties.getValue("SIZE_THRESHOLD"));SIZE_MAX = Integer.valueOf(SysProperties.getValue("file_size_max"));}public FileLogic() {}/** * 直接从内存中将数据上传至HDFS *  * @param request * @throws IOException * @throws FileUploadException */public static void uploadToHDFS(HttpServletRequest request)throws FileUploadException, IOException {DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();diskFileItemFactory.setSizeThreshold(SIZE_THRESHOLD); // 文件临界值diskFileItemFactory.setRepository(new File(TEMP_PATH));ServletFileUpload upload = new ServletFileUpload(diskFileItemFactory);upload.setSizeMax(SIZE_MAX);FileItemIterator items = upload.getItemIterator(request);FileItemStream fileItemStream = null;InputStream inputStream = null;String filename = null;BufferedInputStream bis = null;UploadFromBytes ufb = null;byte[] buffer = new byte[2048];int len = 0;while (items.hasNext()) {fileItemStream = items.next();inputStream = fileItemStream.openStream();if (fileItemStream.isFormField()) {return;}filename = fileItemStream.getName();ufb = new UploadFromBytes(filename);try {bis = new BufferedInputStream(inputStream);while ((len = bis.read(buffer)) != -1) {ufb.writeBytes(buffer, len);}} catch (Exception e) {Log.logException(e);return;} finally {bis.close();ufb.commit();}}}public static void downloadFromHDFS(HttpServletResponse response,String filename) throws IOException {if (response == null || filename == null || filename.equals(""))return;response.setContentType("application/x-msdownload");response.addHeader("Content-Disposition", "attachment;filename="+ filename);ServletOutputStream sos = response.getOutputStream();DownloadFromBytes dfb = null;try {dfb = new DownloadFromBytes(filename);byte[] buffer = new byte[1024];int len = 0;while ((len = dfb.download(buffer)) != -1) {sos.write(buffer, 0, len);}sos.flush();} catch (Exception e) {Log.logException(e);} finally{dfb.close();}}}

如果文件不是以表单的形式从Android端发送,而是直接将二进制信息写在HTTP报文的BODY部分,那么就可以像下面这样接收文件:

/** * 直接从内存中将数据上传至HDFS *  * @param request * @throws IOException * @throws FileUploadException */public static boolean upload2HDFS(HttpServletRequest request)throws FileUploadException, IOException {String filename = request.getParameter("filename");if (filename == null || filename.equals(""))return false;ServletInputStream is = null;byte[] buffer = new byte[10240];int totalLength = 0, len = 0;UploadFromBytes ufb = null;try {is = request.getInputStream();ufb = new UploadFromBytes(filename);try {while ((len = is.read(buffer)) != -1) {Log.logger.debug("read and write byte: " + len);ufb.writeBytes(buffer, len);totalLength += len;}} catch (Exception e) {Log.logException(e);DeleteFile deleteHDFSFile = new DeleteFile();deleteHDFSFile.delete(filename);} finally {ufb.commit();}if (totalLength < 1) {DeleteFile deleteHDFSFile = new DeleteFile();deleteHDFSFile.delete(filename);return false;}Log.logger.debug("write chunk byte: " + totalLength);} catch (Exception e) {Log.logException(e);return false;} finally {is.close();}return true;}



下面的代码是HDFS操作的一些基本配置类,将一些配置读取到内存中来,方便下次使用,因为Configration类初始化十分耗时,因此内存中有一份就好了。

package com.cyber_space.HDFSManager;import java.io.IOException;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.FileSystem;import org.apache.hadoop.fs.Path;import com.cyber_space.hdfs.HDFSManager;import com.cyber_space.util.Log;import com.cyber_space.util.properties.SysProperties;public class HDFSUpload {static Configuration conf = new Configuration();static String hdfs_path = SysProperties.getValue("hdfs_path"); // hdfs://namenode:50040static String user_path = SysProperties.getValue("user_path"); // /UserStorage ,这里根据实际情况来做static {conf.set("fs.defaultFS", hdfs_path);conf.set("fs.hdfs.impl",org.apache.hadoop.hdfs.DistributedFileSystem.class.getName());conf.set("fs.file.impl",org.apache.hadoop.fs.LocalFileSystem.class.getName());System.setProperty("hadoop.home.dir", SysProperties.getValue("hadoop_home"));  //hadoop_home=/Users/justyoung/Documents/workspace/hadoop-2.7.0}}

下面这段代码是将文件上传到HDFS的工具类。

package com.cyber_space.HDFSManager;import java.io.IOException;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.FSDataOutputStream;import org.apache.hadoop.fs.FileSystem;import org.apache.hadoop.fs.Path;import com.cyber_space.util.Log;public class UploadFromBytes {private FSDataOutputStream fsOutputStream = null;private FileSystem hadoopFS = null;private Configuration conf = null;public UploadFromBytes(String despath) throws IOException {despath = HDFSUpload.hdfs_path + HDFSUpload.user_path + despath;conf = HDFSUpload.conf;hadoopFS = FileSystem.get(conf);fsOutputStream = hadoopFS.create(new Path(despath));}public void writeBytes(byte[] bytes, int len) throws IOException {if (bytes == null) {return;}fsOutputStream.write(bytes, 0, len);}public void commit(){try {fsOutputStream.close();fsOutputStream = null;} catch (IOException e) {Log.logException(e);e.printStackTrace();}}}

下面的代码是从HDFS下载文件的工具类:

package com.cyber_space.HDFSManager;import java.io.IOException;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.FSDataInputStream;import org.apache.hadoop.fs.FileSystem;import org.apache.hadoop.fs.Path;import com.cyber_space.util.Log;public class DownloadFromBytes {private FileSystem hadoopFS = null;private Configuration conf = null;private FSDataInputStream fsInputStream = null;public DownloadFromBytes(String srcPath) throws IOException {srcPath = HDFSUpload.hdfs_path + HDFSUpload.user_path + "/" + srcPath;conf = HDFSUpload.conf;hadoopFS = FileSystem.get(conf);fsInputStream = hadoopFS.open(new Path(srcPath));}public int download(byte[] ioBuffer) throws IOException {if (ioBuffer == null){IOException e = new IOException("ioBuffer is null");throw e; }return fsInputStream.read(ioBuffer);}public void close() {if (fsInputStream != null) {try {fsInputStream.close();} catch (IOException e) {e.printStackTrace();Log.logException(e);}}}}

上面的代码可在Servlet中调用,例如:

FileLogic.uploadToHDFS(request);FileLogic.downloadFromHDFS(response, filename);

1 0
原创粉丝点击