美文网首页小技巧Android知识
Android OKHttp3.2文件上传 + Tomcat 8

Android OKHttp3.2文件上传 + Tomcat 8

作者: heguorui | 来源:发表于2016-05-25 21:10 被阅读7061次

    版权所有,转载注明。


    结构示意图.png

    1. Tomcat Servler接收数据

    引入依赖jar包

            <!-- http://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
            <dependency>
                <groupId>commons-fileupload</groupId>
                <artifactId>commons-fileupload</artifactId>
                <version>1.3.1</version>
            </dependency>
            <!-- http://mvnrepository.com/artifact/commons-io/commons-io -->
            <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>2.5</version>
            </dependency>
    

    上传文件接收处理的Controller

    package com.hgr.web.filesresolver;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.InputStream;
    import java.text.DecimalFormat;
    import java.util.List;
    import java.util.UUID;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.commons.fileupload.FileItem;
    import org.apache.commons.fileupload.FileUploadBase;
    import org.apache.commons.fileupload.ProgressListener;
    import org.apache.commons.fileupload.disk.DiskFileItemFactory;
    import org.apache.commons.fileupload.servlet.ServletFileUpload;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @Controller
    @RequestMapping(value = "/files")
    public class FileUploadController {
    
        @RequestMapping(value="/upload")
        public @ResponseBody void fileupload(final HttpServletRequest request,
                HttpServletResponse response) throws Exception {
            
            //得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
            String savePath = request.getSession().getServletContext().getRealPath("/WEB-INF/upload");
            //上传时生成的临时文件保存目录
            String tempPath = request.getSession().getServletContext().getRealPath("/WEB-INF/temp");
            File tmpFile = new File(tempPath);
            if (!tmpFile.exists()) {
                //创建临时目录
                tmpFile.mkdir();
            }
            
            //消息提示
            String message = "";
            try{
                //使用Apache文件上传组件处理文件上传步骤:
                //1、创建一个DiskFileItemFactory工厂
                DiskFileItemFactory factory = new DiskFileItemFactory();
                //设置工厂的缓冲区的大小,当上传的文件大小超过缓冲区的大小时,就会生成一个临时文件存放到指定的临时目录当中。
                factory.setSizeThreshold(1024*100);//设置缓冲区的大小为100KB,如果不指定,那么缓冲区的大小默认是10KB
                //设置上传时生成的临时文件的保存目录
                factory.setRepository(tmpFile);
                //2、创建一个文件上传解析器
                ServletFileUpload upload = new ServletFileUpload(factory);
                //监听文件上传进度
                final DecimalFormat df = new DecimalFormat("#00.0");
                upload.setProgressListener(new ProgressListener(){
                    public void update(long pBytesRead, long pContentLength, int arg2) {
                        System.out.println("文件大小为:" + pContentLength + ",当前已处理:" + pBytesRead);
                        /**
                         * 文件大小为:14608,当前已处理:4096
                                            文件大小为:14608,当前已处理:7367
                                            文件大小为:14608,当前已处理:11419
                                            文件大小为:14608,当前已处理:14608
                         */
                        double percent= (double)pBytesRead*100/(double)pContentLength;  
                        System.out.println(df.format(percent));  
                        request.getSession().setAttribute("UPLOAD_PERCENTAGE", df.format(percent));  
                    }
                });
                 //解决上传文件名的中文乱码
                upload.setHeaderEncoding("UTF-8"); 
                //3、判断提交上来的数据是否是上传表单的数据
                if(!ServletFileUpload.isMultipartContent(request)){
                    //按照传统方式获取数据
                    return;
                }
                
                //设置上传单个文件的大小的最大值,目前是设置为1024*1024*1024*2字节,也就是2GB
                long data_unit = 1024;
                
                upload.setFileSizeMax(data_unit*data_unit*data_unit*2);//直接写1024,会出现问题,因为1024是整型,int,-2147483648 至 2147483647之间。
                //设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10GB
                upload.setSizeMax(data_unit*data_unit*data_unit*10);
                //4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
                List<FileItem> list = upload.parseRequest(request);
                for(FileItem item : list){
                    //如果fileitem中封装的是普通输入项的数据
                    if(item.isFormField()){
                        String name = item.getFieldName();
                        //解决普通输入项的数据的中文乱码问题
                        String value = item.getString("UTF-8");
                        //value = new String(value.getBytes("iso8859-1"),"UTF-8");
                        System.out.println(name + "=" + value);
                    }else{//如果fileitem中封装的是上传文件
                        //得到上传的文件名称,
                        String filename = item.getName();
                        System.out.println(filename);
                        if(filename==null || filename.trim().equals("")){
                            continue;
                        }
                        //注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如:  c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt
                        //处理获取到的上传文件的文件名的路径部分,只保留文件名部分
                        filename = filename.substring(filename.lastIndexOf("\\")+1);
                        //得到上传文件的扩展名
                        String fileExtName = filename.substring(filename.lastIndexOf(".")+1);
                        //如果需要限制上传的文件类型,那么可以通过文件的扩展名来判断上传的文件类型是否合法
                        System.out.println("上传的文件的扩展名是:"+fileExtName);
                        //获取item中的上传文件的输入流
                        InputStream in = item.getInputStream();
                        //得到文件保存的名称
                        String saveFilename = makeFileName(filename);
                        //得到文件的保存目录
                        String realSavePath = makePath(saveFilename, savePath);
                        //创建一个文件输出流
                        FileOutputStream out = new FileOutputStream(realSavePath + "\\" + saveFilename);
                        //创建一个缓冲区
                        byte buffer[] = new byte[1024];
                        //判断输入流中的数据是否已经读完的标识
                        int len = 0;
                        //循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据
                        while((len=in.read(buffer))>0){
                            //使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中
                            out.write(buffer, 0, len);
                        }
                        //关闭输入流
                        in.close();
                        //关闭输出流
                        out.close();
                        //删除处理文件上传时生成的临时文件
                        //item.delete();
                        message = "文件上传成功!";
                    }
                }
            }catch (FileUploadBase.FileSizeLimitExceededException e) {
                e.printStackTrace();
                request.setAttribute("message", "单个文件超出最大值!!!");
                request.getRequestDispatcher("/message.jsp").forward(request, response);
                return;
            }catch (FileUploadBase.SizeLimitExceededException e) {
                e.printStackTrace();
                request.setAttribute("message", "上传文件的总的大小超出限制的最大值!!!");
                request.getRequestDispatcher("/message.jsp").forward(request, response);
                return;
            }catch (Exception e) {
                //message= "文件上传失败!未知错误" + e.toString();
                e.printStackTrace();
                request.getRequestDispatcher("/message.jsp").forward(request, response);
            }
            request.setAttribute("message",message);
            request.getRequestDispatcher("/message.jsp").forward(request, response);
        }
    
    

    前部分代码中,使用的文件名生成器,避免重复上传时同名文件覆盖:

    
        /**
            * @Method: makeFileName
            * @Description: 生成上传文件的文件名,文件名以:uuid+"_"+文件的原始名称
            * @Anthor:孤傲苍狼
            * @param filename 文件的原始名称
            * @return uuid+"_"+文件的原始名称
            */ 
            private String makeFileName(String filename){  //2.jpg
                //为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名
                return UUID.randomUUID().toString() + "_" + filename;
            }
    

    前部分代码中,使用的文件分散存储算法,hash计算,使得每个目录中存储的文件hash分散:

            /**
             * 为防止一个目录下面出现太多文件,要使用hash算法打散存储
            * @Method: makePath
            * @Description: 
            * @Anthor:孤傲苍狼
            *
            * @param filename 文件名,要根据文件名生成存储目录
            * @param savePath 文件存储路径
            * @return 新的存储目录
            */ 
            private String makePath(String filename,String savePath){
                //得到文件名的hashCode的值,得到的就是filename这个字符串对象在内存中的地址
                int hashcode = filename.hashCode();
                int dir1 = hashcode&0xf;  //0--15
                int dir2 = (hashcode&0xf0)>>4;  //0-15
                //构造新的保存目录
                String dir = savePath + "\\" + dir1 + "\\" + dir2;  //upload\2\3  upload\3\5
                //File既可以代表文件也可以代表目录
                File file = new File(dir);
                //如果目录不存在
                if(!file.exists()){
                    //创建目录
                    file.mkdirs();
                }
                return dir;
            }
    }
    
    

    2. Android Activity

    String filepath = "";
    String filename = "";
    
     private static final int FILE_SELECT_CODE = 0;
    
    

    选择文件,使用Android自带的文件选择器:

        /** 调用文件选择软件来选择文件 **/
        private void showFileChooser() {
            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
            intent.setType("*/*");
            intent.addCategory(Intent.CATEGORY_OPENABLE);
            try {
                startActivityForResult(Intent.createChooser(intent, "请选择一个要上传的文件"),
                        FILE_SELECT_CODE);
            } catch (android.content.ActivityNotFoundException ex) {
                // Potentially direct the user to the Market with a Dialog
                Toast.makeText(this, "请安装文件管理器", Toast.LENGTH_SHORT)
                        .show();
            }
        }
    
    

    获取文件选择器返回的文件路径:

        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            switch (requestCode) {
                case FILE_SELECT_CODE:
                    if (resultCode == RESULT_OK) {
                        // Get the Uri of the selected file
                        Uri uri = data.getData();
                        Log.d(TAG, "File Uri: " + uri.toString());
    
                        // Get the path
                        String path = null;
                        try {
                            path = FileUtils.getPath(this, uri);
    
                            filename = path.substring(path.lastIndexOf("/") + 1);
                            textView1.setText(path);
                        } catch (URISyntaxException e) {
                            Log.e("TAG", e.toString());
                            //e.printStackTrace();
                            path = "";
                        }
                        filepath = path;
                        Log.d(TAG, "File Path: " + path);
                        // Get the file instance
                        // File file = new File(path);
                        // Initiate the upload
                    }
                    break;
            }
            super.onActivityResult(requestCode, resultCode, data);
        }
    
    

    使用OKHtpp进行文件上传:
    上传时,创建MultipartBody下的Builder对象,在OKHttp2.4.0中为MultipartBuilder,现在改为MultipartBody.Builder,这个需要注意。

    //上传文件:
                    File file = new File(filepath);
                    RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
                    RequestBody requestBody = new MultipartBody.Builder()
                            .setType(MultipartBody.FORM)
                            .addPart(Headers.of(
                                    "Content-Disposition",
                                    "form-data; name=\"username\""),
                                    RequestBody.create(null, "HGR"))
                            .addPart(Headers.of(
                                    "Content-Disposition",
                                    "form-data; name=\"mFile\"; filename=\"" + filename + "\""), fileBody)
                            .build();
                    Request request = new Request.Builder()
                            .url("http://192.168.0.103/NewWebProject/servlet/UploadHandleServlet")
                            .post(requestBody)
                            .build();
                    Call call = okHttpClient.newCall(request);
                    call.enqueue(new Callback() {
                        @Override
                        public void onFailure(Call call, IOException e) {
    
                            Log.e(TAG, "failure upload!");
                        }
    
                        @Override
                        public void onResponse(Call call, Response response) throws IOException {
    
                            Log.i(TAG, "success upload!");
                        }
                    });
    
    //获取文件路径:
    package com.guoruihe.okhttptestprj;
    
    import android.content.Context;
    import android.database.Cursor;
    import android.net.Uri;
    
    import java.net.URISyntaxException;
    
    /**
     * Created by guorui.he on 2016/5/23.
     */
    public class FileUtils {
    
        public static String getPath(Context context, Uri uri) throws URISyntaxException {
            if ("content".equalsIgnoreCase(uri.getScheme())) {
                String[] projection = { "_data" };
                Cursor cursor = null;
    
                try {
                    cursor = context.getContentResolver().query(uri, projection, null, null, null);
                    int column_index = cursor.getColumnIndexOrThrow("_data");
                    if (cursor.moveToFirst()) {
                        return cursor.getString(column_index);
                    }
                } catch (Exception e) {
                    // Eat it
                }
            }
            else if ("file".equalsIgnoreCase(uri.getScheme())) {
                return uri.getPath();
            }
    
            return null;
        }
    }
    
    

    参考:
    http://blog.csdn.net/lmj623565791/article/details/47911083 OKHttp文件上传
    http://www.cnblogs.com/xdp-gacl/p/4200090.html Java文件上传

    相关文章

      网友评论

        本文标题:Android OKHttp3.2文件上传 + Tomcat 8

        本文链接:https://www.haomeiwen.com/subject/rxbtdttx.html