使用HttpClient实现文件的上传下载

1 HTTP

    HTTP 协议可能是现在 Internet 上使用得最多、最重要的协议了,越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源。

    虽然在 JDK 的 java.net 包中已经提供了访问 HTTP 协议的基本功能,但是对于大部分应用程序来说,JDK 库本身提供的功能还不够丰富和灵活。HttpClient 用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。

    一般的情况下我们都是使用Chrome或者其他浏览器来访问一个WEB服务器,用来浏览页面查看信息或者提交一些数据、文件上传下载等等。所访问的这些页面有的仅仅是一些普通的页面,有的需要用户登录后方可使用,或者需要认证以及是一些通过加密方式传输,例如HTTPS。目前我们使用的浏览器处理这些情况都不会构成问题。但是一旦我们有需求不通过浏览器来访问服务器的资源呢?那该怎么办呢?

    下面以本地客户端发起文件的上传、下载为例做个小Demo。HttpClient有两种形式,一种是org.apache.http下的,一种是org.apache.commons.httpclient.HttpClient。

2 文件上传

    文件上传可以使用两种方式实现,一种是PostMethod方式,一种是HttpPost方式。两者的处理大同小异。PostMethod是使用FileBody将文件包装流包装起来,HttpPost是使用FilePart将文件流包装起来。在传递文件流给服务端的时候,都可以同时传递其他的参数。

2.1 客户端处理

2.1.1 PostMethod方式

     将文件封装到FilePart中,放入Part数组,同时,其他参数可以放入StringPart中,这里没有写,只是单纯的将参数以setParameter的方式进行设置。此处的HttpClient是org.apache.commons.httpclient.HttpClient。

public void upload(String localFile){
        File file = new File(localFile);
        PostMethod filePost = new PostMethod(URL_STR);
        HttpClient client = new HttpClient();
        
        try {
            // 通过以下方法可以模拟页面参数提交
            filePost.setParameter("userName", userName);
            filePost.setParameter("passwd", passwd);

            Part[] parts = { new FilePart(file.getName(), file) };
            filePost.setRequestEntity(new MultipartRequestEntity(parts, filePost.getParams()));
            
            client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
            
            int status = client.executeMethod(filePost);
            if (status == HttpStatus.SC_OK) {
                System.out.println("上传成功");
            } else {
                System.out.println("上传失败");
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            filePost.releaseConnection();
        }
    }


    记得搞完之后,要通过releaseConnection释放连接。 

2.1.2 HttpPost方式

     这种方式,与上面类似,只不过变成了FileBody。上面的Part数组在这里对应HttpEntity此处的HttpClient是org.apache.http.client.methods下的。

public void upload(String localFile){
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        try {
            httpClient = HttpClients.createDefault();
            
            // 把一个普通参数和文件上传给下面这个地址 是一个servlet
            HttpPost httpPost = new HttpPost(URL_STR);
            
            // 把文件转换成流对象FileBody
            FileBody bin = new FileBody(new File(localFile));

            StringBody userName = new StringBody("Scott", ContentType.create(
                    "text/plain", Consts.UTF_8));
            StringBody password = new StringBody("123456", ContentType.create(
                    "text/plain", Consts.UTF_8));

            HttpEntity reqEntity = MultipartEntityBuilder.create()
                    // 相当于<input type="file" name="file"/>
                    .addPart("file", bin)
                    
                    // 相当于<input type="text" name="userName" value=userName>
                    .addPart("userName", userName)
                    .addPart("pass", password)
                    .build();

            httpPost.setEntity(reqEntity);

            // 发起请求 并返回请求的响应
            response = httpClient.execute(httpPost);
            
            System.out.println("The response value of token:" + response.getFirstHeader("token"));
                
            // 获取响应对象
            HttpEntity resEntity = response.getEntity();
            if (resEntity != null) {
                // 打印响应长度
                System.out.println("Response content length: " + resEntity.getContentLength());
                // 打印响应内容
                System.out.println(EntityUtils.toString(resEntity, Charset.forName("UTF-8")));
            }
            
            // 销毁
            EntityUtils.consume(resEntity);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                if(response != null){
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            
            try {
                if(httpClient != null){
                    httpClient.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

2.2 服务端处理

     无论客户端是哪种上传方式,服务端的处理都是一样的。在通过HttpServletRequest获得参数之后,把得到的Item进行分类,分为普通的表单和File表单。    

     通过ServletFileUpload 可以设置上传文件的大小及编码格式等。

     总之,服务端的处理是把得到的参数当做HTML表单进行处理的。    

public void processUpload(HttpServletRequest request, HttpServletResponse response){
        File uploadFile = new File(uploadPath);
        if (!uploadFile.exists()) {
            uploadFile.mkdirs();
        }

        System.out.println("Come on, baby .......");
        
        request.setCharacterEncoding("utf-8");  
        response.setCharacterEncoding("utf-8");  
          
        //检测是不是存在上传文件  
        boolean isMultipart = ServletFileUpload.isMultipartContent(request);  
          
        if(isMultipart){  
            DiskFileItemFactory factory = new DiskFileItemFactory();  
            
            //指定在内存中缓存数据大小,单位为byte,这里设为1Mb  
            factory.setSizeThreshold(1024*1024);  
           
            //设置一旦文件大小超过getSizeThreshold()的值时数据存放在硬盘的目录   
            factory.setRepository(new File("D:\\temp"));  
            
            // Create a new file upload handler  
            ServletFileUpload upload = new ServletFileUpload(factory);  
           
            // 指定单个上传文件的最大尺寸,单位:字节,这里设为50Mb    
            upload.setFileSizeMax(50 * 1024 * 1024);    
            
            //指定一次上传多个文件的总尺寸,单位:字节,这里设为50Mb  
            upload.setSizeMax(50 * 1024 * 1024);     
            upload.setHeaderEncoding("UTF-8");
              
            List<FileItem> items = null;  
              
            try {  
                // 解析request请求  
                items = upload.parseRequest(request);  
            } catch (FileUploadException e) {  
                e.printStackTrace();  
            }  
            
            if(items!=null){  
                //解析表单项目  
                Iterator<FileItem> iter = items.iterator();  
                while (iter.hasNext()) {  
                    FileItem item = iter.next(); 
                    
                    //如果是普通表单属性  
                    if (item.isFormField()) {  
                        //相当于input的name属性   <input type="text" name="content">  
                        String name = item.getFieldName();
                        
                        //input的value属性  
                        String value = item.getString();
                        
                        System.out.println("属性:" + name + " 属性值:" + value);  
                    }  
                    //如果是上传文件  
                    else {  
                        //属性名  
                        String fieldName = item.getFieldName();  
                        
                        //上传文件路径  
                        String fileName = item.getName();  
                        fileName = fileName.substring(fileName.lastIndexOf("/") + 1);// 获得上传文件的文件名  
                        
                        try {  
                            item.write(new File(uploadPath, fileName));  
                        } catch (Exception e) {  
                            e.printStackTrace();  
                        }  
                    } 
                }  
            }  
        }  
        
        response.addHeader("token", "hello");
    }


    服务端在处理之后,可以在Header中设置返回给客户端的简单信息。如果返回客户端是一个流的话,流的大小必须提前设置

    response.setContentLength((int) file.length());

3 文件下载

     文件的下载可以使用HttpClient的GetMethod实现,还可以使用HttpGet方式、原始的HttpURLConnection方式。

3.1 客户端处理

 3.1.1 GetMethod方式

    此处的HttpClient是org.apache.commons.httpclient.HttpClient。

 

public void downLoad(String remoteFileName, String localFileName) {
        HttpClient client = new HttpClient();
        GetMethod get = null;
        FileOutputStream output = null;
        
        try {
            get = new GetMethod(URL_STR);
            get.setRequestHeader("userName", userName);
            get.setRequestHeader("passwd", passwd);
            get.setRequestHeader("fileName", remoteFileName);

            int i = client.executeMethod(get);

            if (SUCCESS == i) {
                System.out.println("The response value of token:" + get.getResponseHeader("token"));

                File storeFile = new File(localFileName);
                output = new FileOutputStream(storeFile);
                
                // 得到网络资源的字节数组,并写入文件
                output.write(get.getResponseBody());
            } else {
                System.out.println("DownLoad file occurs exception, the error code is :" + i);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if(output != null){
                    output.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            
            get.releaseConnection();
            client.getHttpConnectionManager().closeIdleConnections(0);
        }
    }

3.1.2 HttpGet方式

    此处的HttpClient是org.apache.http.client.methods下的。

public void downLoad(String remoteFileName, String localFileName) {
        DefaultHttpClient httpClient = new DefaultHttpClient();
        OutputStream out = null;
        InputStream in = null;
        
        try {
            HttpGet httpGet = new HttpGet(URL_STR);

            httpGet.addHeader("userName", userName);
            httpGet.addHeader("passwd", passwd);
            httpGet.addHeader("fileName", remoteFileName);

            HttpResponse httpResponse = httpClient.execute(httpGet);
            HttpEntity entity = httpResponse.getEntity();
            in = entity.getContent();

            long length = entity.getContentLength();
            if (length <= 0) {
                System.out.println("下载文件不存在!");
                return;
            }

            System.out.println("The response value of token:" + httpResponse.getFirstHeader("token"));

            File file = new File(localFileName);
            if(!file.exists()){
                file.createNewFile();
            }
            
            out = new FileOutputStream(file);  
            byte[] buffer = new byte[4096];
            int readLength = 0;
            while ((readLength=in.read(buffer)) > 0) {
                byte[] bytes = new byte[readLength];
                System.arraycopy(buffer, 0, bytes, 0, readLength);
                out.write(bytes);
            }
            
            out.flush();
            
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            try {
                if(in != null){
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            
            try {
                if(out != null){
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

3.1.3 HttpURLConnection方式
public void download3(String remoteFileName, String localFileName) {
        FileOutputStream out = null;
        InputStream in = null;
        
        try{
            URL url = new URL(URL_STR);
            URLConnection urlConnection = url.openConnection();
            HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
            
            // true -- will setting parameters
            httpURLConnection.setDoOutput(true);
            // true--will allow read in from
            httpURLConnection.setDoInput(true);
            // will not use caches
            httpURLConnection.setUseCaches(false);
            // setting serialized
            httpURLConnection.setRequestProperty("Content-type", "application/x-java-serialized-object");
            // default is GET                        
            httpURLConnection.setRequestMethod("POST");
            httpURLConnection.setRequestProperty("connection", "Keep-Alive");
            httpURLConnection.setRequestProperty("Charsert", "UTF-8");
            // 1 min
            httpURLConnection.setConnectTimeout(60000);
            // 1 min
            httpURLConnection.setReadTimeout(60000);

            httpURLConnection.addRequestProperty("userName", userName);
            httpURLConnection.addRequestProperty("passwd", passwd);
            httpURLConnection.addRequestProperty("fileName", remoteFileName);

            // connect to server (tcp)
            httpURLConnection.connect();

            in = httpURLConnection.getInputStream();// send request to
                                                                // server
            File file = new File(localFileName);
            if(!file.exists()){
                file.createNewFile();
            }

            out = new FileOutputStream(file);  
            byte[] buffer = new byte[4096];
            int readLength = 0;
            while ((readLength=in.read(buffer)) > 0) {
                byte[] bytes = new byte[readLength];
                System.arraycopy(buffer, 0, bytes, 0, readLength);
                out.write(bytes);
            }
            
            out.flush();
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            try {
                if(in != null){
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            
            try {
                if(out != null){
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
3.2 服务端处理

     尽管客户端的处理方式不同,但是服务端是一样的。

public void processDownload(HttpServletRequest request, HttpServletResponse response){
        int BUFFER_SIZE = 4096;
        InputStream in = null;
        OutputStream out = null;
        
        System.out.println("Come on, baby .......");
        
        try{
            request.setCharacterEncoding("utf-8");  
            response.setCharacterEncoding("utf-8");  
            response.setContentType("application/octet-stream");
            
            String userName = request.getHeader("userName");
            String passwd = request.getHeader("passwd");
            String fileName = request.getHeader("fileName");
            
            System.out.println("userName:" + userName);
            System.out.println("passwd:" + passwd);
            System.out.println("fileName:" + fileName);
            
            //可以根据传递来的userName和passwd做进一步处理,比如验证请求是否合法等             
            File file = new File(downloadPath + "\\" + fileName);
            response.setContentLength((int) file.length());
            response.setHeader("Accept-Ranges", "bytes");
            
            int readLength = 0;
            
            in = new BufferedInputStream(new FileInputStream(file), BUFFER_SIZE);
            out = new BufferedOutputStream(response.getOutputStream());
            
            byte[] buffer = new byte[BUFFER_SIZE];
            while ((readLength=in.read(buffer)) > 0) {
                byte[] bytes = new byte[readLength];
                System.arraycopy(buffer, 0, bytes, 0, readLength);
                out.write(bytes);
            }
            
            out.flush();
            
            response.addHeader("token", "hello 1");
             
        }catch(Exception e){
            e.printStackTrace();
             response.addHeader("token", "hello 2");
        }finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                }
            }
        }
    }

 4 小结

    HttpClient最基本的功能就是执行Http方法。一个Http方法的执行涉及到一个或者多个Http请求/Http响应的交互,通常这个过程都会自动被HttpClient处理,对用户透明。用户只需要提供Http请求对象,HttpClient就会将http请求发送给目标服务器,并且接收服务器的响应,如果http请求执行不成功,httpclient就会抛出异常。所以在写代码的时候注意finally的处理。    

    所有的Http请求都有一个请求列(request line),包括方法名、请求的URI和Http版本号。HttpClient支持HTTP/1.1这个版本定义的所有Http方法:GET,HEAD,POST,PUT,DELETE,TRACE和OPTIONS。上面的上传用到了Post,下载是Get

    目前来说,使用org.apache.commons.httpclient.HttpClient多一些。看自己了~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值