Tomcat下文件下载与上传的简单实现

实现下载

实现下载需要
- 修改Tomcat中的server.xml
- 修改web.xml

修改server.xml

<Host> </Host>中加入(一般在文件末尾可以找到)

<Context docBase="C://Download" path="/download" reloadable="true" />

其中docBase项是本地目录,path项是访问目录

修改web.xml
   <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>true</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

其中listings下确保值是true

这时在C://Download下存放文件,并打开相应的地址,就能看见文件目录了

实现上传

实现上传也是分两步

  • 实现客户端的上传
  • 实现服务端的处理
实现客户端的上传
post请求

我们都知道http常用的请求方式有getpost等,其中我们实现文件上传,就是模拟表单采用post方式上传文件

首先来看一下post报文的格式,以上传一张图片为例

POST/logsys/home/uploadIspeedLog!doDefault.html HTTP/1.1 

Accept: text/plain, */* 
Accept-Language: zh-cn 
Host: 192.168.24.56
Content-Type:multipart/form-data;boundary=【这里随意设置】
User-Agent: WinHttpClient 
Content-Length: 3693
Connection: Keep-Alive

以上部分是请求的参数,不需要我们完全实现,通过方法传参的方式自动构建

--【这里随意设置】
Content-Disposition: form-data;name="file1";filename="C://E//a.png"
Content-Type:application/octet-stream


<文件的二进制信息>
--【这里随意设置】--

这一部分是报文的内容,需要我们通过字符串或者字节流自行拼接,并且格式不能出错

注意,三处【这里随意设置】的部分必须完全相同

代码实现
public static void uploadFile(String fileName) {  
    try {  

        // 换行符  
        final String newLine = "\r\n";  
        //数据分隔线  
        final String BOUNDARY = "【这里随意设置】";//可以随意设置,一般是用  ---------------加一堆随机字符
        //文件结束标识
        final String boundaryPrefix = "--";  

        // 服务器的域名  
        URL url = new URL("http://localhost:8070/secondary/HandleFile");  
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();  
        // 设置为POST情  
        conn.setRequestMethod("POST");  
        // 发送POST请求必须设置如下两行  
        conn.setDoOutput(true);  
        //conn.setDoInput(true);/不必加,默认为true  
        //conn.setUseCaches(false);//用于设置缓存,默认为true,不改也没有影响(至少在传输单个文件这里没有)  

        // 设置请求头参数  
        //关于keep-alive的说明:https://www.kafan.cn/edu/5110681.html
        //conn.setRequestProperty("connection", "Keep-Alive");//现在的默认设置一般即为keep-Alive,因此此项为强调用,可以不加
        //conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows Nt 5.1; SV1)");//用于模拟浏览器,非必须

        //用于表示上传形式,必须
        conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);  
        //这里是Charset,网上大多都是Charsert???我的天,笑哭。不过好像没什么影响...不知道哪位大佬解释一下
        conn.setRequestProperty("Charset", "UTF-8");

        //获取conn的输出流用于向服务器输出信息
        OutputStream out = new DataOutputStream(conn.getOutputStream());  

        //构造文件的结构  
        //写参数头
        StringBuilder sb = new StringBuilder();  
        sb.append(boundaryPrefix)//表示报文开始
          .append(BOUNDARY)//添加文件分界线
          .append(newLine);//换行,换行方式必须严格约束
        //固定格式,其中name的参数名可以随意修改,只需要在后台有相应的识别就可以,filename填你想要被后台识别的文件名,可以包含路径
        sb.append("Content-Disposition: form-data;name=\"file\";")
            .append("filename=\"").append(fileName)
            .append("\"")
            .append(newLine);  
        sb.append("Content-Type:application/octet-stream");  
        //换行,为必须格式
        sb.append(newLine);  
        sb.append(newLine);  

        //将参数头的数据写入到输出流中  
        out.write(sb.toString().getBytes());  
        System.out.print(sb);

        //写文件数据(通过数据输入流)  
        File file = new File(fileName);
        DataInputStream in = new DataInputStream(new FileInputStream(  
                file));  
        byte[] bufferOut = new byte[1024];  
        int bytes = 0;  
        //每次读1KB数据,并且将文件数据写入到输出流中  
        while ((bytes = in.read(bufferOut)) != -1) {  
            out.write(bufferOut, 0, bytes);  
        }  
        in.close();

        //写参数尾  
        out.write(newLine.getBytes());  
        System.out.print(new String(newLine.getBytes()));

        // 定义最后数据分隔线,即--加上BOUNDARY再加上--。
        sb = new StringBuilder();
        sb.append(newLine)
            .append(boundaryPrefix)
            .append(BOUNDARY)
            .append(boundaryPrefix)
            .append(newLine);
        // 写上结尾标识  
        out.write(sb.toString().getBytes());  
        System.out.println(sb);
        //输出结束,关闭输出流
        out.flush();  
        out.close();  

        //定义BufferedReader输入流来读取URL的响应 ,注意必须接受来自服务器的返回,否则服务器不会对发送的post请求做处理!!这里坑了我好久
        BufferedReader reader = new BufferedReader(new InputStreamReader(  
                conn.getInputStream()));  
        String line = null;  
        while ((line = reader.readLine()) != null) {  
            System.out.println(line);  
        }  

    } catch (Exception e) {  
        System.out.println("发送POST请求出现异常!" + e);  
        e.printStackTrace();  
    }  
}  

注释很清楚,结合post请求的格式理解一下,就不一一解释了

实现服务端的处理

上述的代码会形成一个post请求到服务器,于是相应的接口的dopost()方法就会相应

dopost()中做了什么呢?

  • 获取报文中的文件信息
  • 处理文件信息,包括识别文件名,识别文件类型(由用户定义,而不是文件后缀)
  • 存储到本地(服务器端硬盘)

代码如下:

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
//注意导的包

/**
 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
 */
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    response.setCharacterEncoding("UTF-8");
    request.setCharacterEncoding("UTF-8");
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    //输出到客户端浏览器
    DiskFileItemFactory factory = new DiskFileItemFactory();
    ServletFileUpload sup = new ServletFileUpload(factory);//这里要将factory传入,否则会报NullPointerException: No FileItemFactory has been set.
    try{
        List<FileItem> list = sup.parseRequest(request);
        for(FileItem fileItem:list){
            System.out.println(fileItem.getFieldName()+"--"+fileItem.getName());
            if(!fileItem.isFormField()){
                if("file".equals(fileItem.getFieldName())){
                    //获取远程文件名
                    String remoteFilename = new String(fileItem.getName().getBytes(),"UTF-8");
                    File remoteFile = new File(remoteFilename);

                    //设置服务器端存放文件的位置
                    File locate = new File("C://E//download/",remoteFile.getName());

//                      locate.getParentFile().mkdirs();//用于确保文件目录存在,如果为单级目录可以去掉
                    locate.createNewFile(); //创建新文件

                    InputStream ins = fileItem.getInputStream();   //FileItem的内容
                    OutputStream ous = new FileOutputStream(locate); //输出
                    try{
                        byte[] buffer = new byte[1024]; //缓冲字节
                        int len = 0;
                        while((len = ins.read(buffer))>-1)
                            ous.write(buffer, 0, len);
                    }finally{
                        ous.close();
                        ins.close();
                    }
                }
            }       
        }
    }catch (FileUploadException e){}

    out.print("everything is ok");
    out.flush();
    out.close();

}

同样注释很清楚,不再解释了

小结

将上述过程理解清楚后,再结合post报文的格式,那么是否就可以处理多个文件同时上传了呢?如果对客户端的流做出一些大小限制,是不是就可以限制上传大小了?…一个小demo,帮助理解一下基础的实现。

  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
文件上传下载是Web开发常见的功能,而文件上传下载相关的jar主要有以下几个: 1. Apache Commons FileUpload:Apache Commons FileUpload是用于处理文件上传Java组件,可以轻松处理上传文件并保存到服务器指定的目录。它提供了上传进度监听、文件大小限制、文件类型限制等功能,使用方便且稳定。 2. Apache Commons IO:Apache Commons IO是一个开源的Java文件IO工具库,其包含了许多有关文件操作的实用方法,如文件复制、移动、删除、读写、遍历等。在文件上传下载功能,可以使用它来读取、写入、复制文件等操作。 3. Spring Web:Spring Web是Spring框架的一部分,提供了处理Web请求的功能。在文件上传下载,可以使用Spring Web的MultipartFile类来处理文件上传,通过其提供的方法可以获取文件的名称、大小、内容等信息,并进行相应的操作。 4. Servlet API:Servlet API是Java Servlet规范的一部分,包含了处理HTTP请求和响应的类和接口。在文件上传下载功能,可以使用Servlet API提供的Part类来处理文件上传,通过其提供的方法可以获取上传文件的相关信息,并进行相应的操作。 5. Tomcat Multipart Parser:Tomcat Multipart Parser是Apache Tomcat服务器的一个组件,用于解析multi-part/form-data格式的HTTP请求。在文件上传下载功能,它可以帮助解析和处理上传的文件,并提供简单的API用于获取文件信息和保存文件。 这些相关的jar可以帮助开发人员简化文件上传下载功能的实现,提供了丰富的功能和易于使用的API,使开发变得更加高效和便捷。使用这些jar可以避免重复造轮子,提高开发效率,实现更好的用户体验。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值