Servlet+html实现文件上传与下载(踩坑+总结)


前言

JavaWeb在发展中不断衍生出更加强大,成熟,好用的框架,部分技术已经过时,学习研究它变得意义不是很大,所以笔者仅了解学习JavaWeb中的Servlet服务端技术,学习使用其实现上传和下载文件,仅以此篇博客记录,欢迎读者指正。

一 使用Servlet实现文件的下载

Servlet的下载相较于上传是较为容易实现的,首先,为了方便我们可以创建一个Meavn项目,然后配置pom.xml导入所需要的依赖以及web.xml实现Servlet的配置,编码后最后配置相应的Tomcat,具体步骤可以去其它博客中了解.

实现文件下载之前我们需要先想好如何实现文件的下载?

1.获取文件的下载路径
2.找到需要下载的文件(对应的文件名)
3.需要浏览器能够支持我们下载文件(环境)
4.开始下载文件(将文件转化成输入流)
5.将对应的输入流传入缓冲区
6.将缓冲区中的数据转为输出流
7.写入到文件中,实现下载

具体实现源码如下:

package com.hang;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;

//文件下载(注解形式或配置文件中装配)
//@WebServlet(name = "com.hang.FileServlet", urlPatterns = {"/down"})
public class FileServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.获取文件的下载路径
        String filePath="D:\\myProject\\servlet\\servlet-03\\src\\main\\resources\\icon.png";
        //2.获取下载的文件名
        String fileName=filePath.substring(filePath.lastIndexOf("\\")+1);
        System.out.println("文件下载路径:"+filePath);
        //3.设置浏览器能够支持我们下载我们所需要的东西
        resp.setHeader("Content-Disposition","attachment;filename="+fileName);
        //4.获取下载文件的输入流
        FileInputStream in=new FileInputStream(filePath);
        //5.创建缓冲区
        int len=0;
        byte[] buffer=new byte[1024];
        //6.获取OutputStream对象
        ServletOutputStream sos=resp.getOutputStream();
        //7.将FileOutputStream流写入到buffer缓冲区,使用OutputStream将缓冲区的流输出到客户端
        while ((len=in.read(buffer))>0){
            //当缓冲区中还有流时,不断读取并写入
            sos.write(buffer,0,len);
        }
        //关闭流
        in.close();
        sos.close();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

配置好Tomcat服务器后运行,结果如下:
在这里插入图片描述
控制台结果及项目结构:
在这里插入图片描述

其实使用Servlet实现文件的下载并不难理解,也比较容易实现。

二 使用Servlet实现文件的上传

使用Servlet实现文件上传有两种常见的方式,一种是使用Apache开源库类实现文件上传(commons.fileupload-x.jar和common.io-x.jar),另一种是使用Parts接口实现文件上传;这里我采用Parts接口来实现文件的上传~

使用Parts接口实现多文件的上传

要实现文件上传,首先要明白什么是文件上传?可以说它是和文件下载完全相反的过程。通过上述例子,我们可以知道,文件下载是将服务器上的数据下载到客户端的过程,而文件上传就是将客户端的文件数据上传到服务端的过程!

如何实现文件上传呢?我一开始想到的方法是也使用流的方法,将文件转换成流输入到请求中,然后上网看看其它的demo,哇,完全不是我所想的,可以使用part.write(savePath+"\\"+fileName)直接将文件写入服务器,具体实现步骤如下:

1.在web.xml中配置好相应的Servlet

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                            http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0"
         metadata-complete="true">
    <servlet>
        <servlet-name>FileDownload</servlet-name>
        <servlet-class>com.hang.FileServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>FileDownload</servlet-name>
        <url-pattern>/down</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>FileUpload</servlet-name>
        <servlet-class>com.hang.UploadServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>FileUpload</servlet-name>
        <url-pattern>/upload</url-pattern>
    </servlet-mapping>
</web-app>

2.在项目中创建一个文件夹store存储上传的文件

3.编写前端页面(上传文件的页面)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>upload</title>
</head>
<body>
<form name="uploadForm" method="post" enctype="multipart/form-data" action="upload">
    <table>
        <tr>
            <td><div align="right">username:</div></td>
            <td><input type="text" name="username" size="30"/></td>
        </tr>
        <tr>
            <td><div align="right">Upload file1:</div></td>
            <td><input type="file" name="file1" size="30"/></td>
        </tr>
        <tr>
            <td><div align="right">Upload file2:</div></td>
            <td><input type="file" name="file2" size="30"/></td>
        </tr>
        <tr>
            <td><input type="submit" name="submit" value="upload"></td>
            <td><input type="reset" name="reset" value="reset"></td>
        </tr>
    </table>
</form>
</body>
</html>

4.编写上传文件的Servlet

package com.hang;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Collections;

//使用该注解配置servlet的映射
//@WebServlet(name = "UploadServlet",urlPatterns = "/upload")
//使用该注解以支持文件上传
@MultipartConfig
public class UploadServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //将文件设置为纯文本的形式,浏览器在获取到这种文件时并不会对其进行处理
        resp.setContentType("text/plain;charset=utf-8");
        req.setCharacterEncoding("utf-8");
        //保存文件的路径
        String savePath="D:\\myProject\\servlet\\servlet-03\\store";
        PrintWriter out=resp.getWriter();
        Collection<Part> parts=req.getParts();
        //获取正文表单数据的每个部分
        for(Part part:parts){
            String header=part.getHeader("Content-Disposition");
            //在Tomcat服务端显示每个子部分的信息
            System.out.println("---------Part----------");
            System.out.println("type:"+part.getContentType());
            System.out.println("size:"+part.getSize());
            System.out.println("name:"+part.getName());
            System.out.println("header:"+header);

            //若为表单中的文本域,则显示文本域中的名字和取值
            if(part.getContentType()==null){
                String name=part.getName();
                String value=req.getParameter(name);
                out.println(name+":"+value+"\r\n");
            }else{
                //若为表单中的file1或file2文件域,那么进行文件上传
                //1.获取上传的文件名
                String fileName=getFileName(header);
                System.out.println(header);
                //2.将文件写到指定路径(为什么写不进去)
//                part.write(savePath+ File.pathSeparator+fileName);
                part.write(savePath+"\\"+fileName);
                out.println(fileName+"is saved");
                out.println("The size of "+fileName+" is "+part.getSize()+"byte. \r\n");
            }
            out.flush();
            out.close();
        }
    }

    public String getFileName(String header) {
        //若一个part的请求头header是:form-data;name="file1";filename="FromClient.rar",那么FromClient.rar就是这个的文件名
        String fileName=header.substring(header.lastIndexOf("=")+2,header.length()-1);
        return fileName;
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }
}

5.运行,项目结构及效果如下
在这里插入图片描述

运行成功后,访问对应的html网页,注意是upload.html而不是upload,否则会报服务器500错误
在这里插入图片描述
在这里插入图片描述

6.踩坑总结及经验教训

  • 遇到页面乱码或者下载的文件乱码,设置请求和相应的类型为"utf-8"即可解决
  • 遇到500—服务器内部错误,应该是访问的路径错了,若访问的不是页面,请求和响应内容都为空,自然是服务器内部错误了
  • 遇到404—客户端错误,html表单中的action=/upload,导致无法跳转到UploadServlet,页面丢失进而导致客户端错误!解决方法是将action=/upload改成 action=upload,与UploadServlet映射的路径一致

文件无法上传及请求头为空的问题,这个问题困扰了我很久,我是这样查看问题并尝试性去解决的:
①使用浏览器的检查功能,检查请求头的内容数据
在这里插入图片描述
当时的请求头也是和这个极为类似的,可以看出请求头并没有出问题,但是为什么在日志中会报下面的错误:

org.apache.tomcat.util.http.fileupload.impl.InvalidContentTypeException: the request doesn’t contain a multipart/form-data or multipart/mixed stream, content type header is null

②打印输出header
心细的盆友可以看到,我在源代码中穿插了一句上传文件时查看header请求头的语句,事实证明请求头正常

③文件的保存路径问题:既然文件信息和请求头都正常,那么只有可能是保存的文件路径或者写文件时出现问题了,我将文件的保存路径改成绝对路径,再修改写文件时的操作,后成功上传文件,Nice~


总结

还是在不该错误的问题上浪费太多的时间,被文件上传卡口了好久,主要是对Web知识掌握不足,或者说是经验不足,前期遇到服务器错误或者404,后面又发现文件无法正常上传,多次修改代码后终于ok了,留下了小白的泪水!
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
文件下载是Web开发中常见的功能,可以通过servlet+jsp实现。下面是一个简单的示例: 1. 文件 在jsp页面中,使用form表单向servlet提交文件: ```html <form method="post" action="UploadServlet" enctype="multipart/form-data"> <input type="file" name="file"> <input type="submit" value="上"> </form> ``` 在servlet中,使用Apache Commons FileUpload来处理文件: ```java protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 检查是否是文件请求 if (!ServletFileUpload.isMultipartContent(request)) { response.getWriter().println("不是文件请求"); return; } // 创建文件工厂 DiskFileItemFactory factory = new DiskFileItemFactory(); // 设置缓冲区大小,超过这个大小的文件将被写入临时文件 factory.setSizeThreshold(1024 * 1024 * 10); // 10MB // 设置临时文件存放目录 File tmpDir = new File("tmp"); if (!tmpDir.exists()) { tmpDir.mkdirs(); } factory.setRepository(tmpDir); // 创建文件处理器 ServletFileUpload upload = new ServletFileUpload(factory); // 设置上文件的大小限制 upload.setFileSizeMax(1024 * 1024 * 100); // 100MB // 解析上文件 try { List<FileItem> items = upload.parseRequest(request); for (FileItem item : items) { if (!item.isFormField()) { // 保存上文件 String fileName = item.getName(); String destPath = "upload/" + fileName; File destFile = new File(destPath); item.write(destFile); } } response.getWriter().println("上成功"); } catch (Exception e) { e.printStackTrace(); response.getWriter().println("上失败"); } } ``` 2. 文件下载 在jsp页面中,使用a标签指向servlet,并将要下载文件名作为参数: ```html <a href="DownloadServlet?fileName=test.txt">下载</a> ``` 在servlet中,读取要下载文件并将文件内容输出到response中: ```java protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String fileName = request.getParameter("fileName"); String filePath = "upload/" + fileName; File file = new File(filePath); if (!file.exists()) { response.getWriter().println("文件不存在"); return; } // 设置响应头,让浏览器下载文件 response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); response.setContentType("application/octet-stream"); // 输出文件内容 InputStream in = new FileInputStream(file); OutputStream out = response.getOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while ((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); } in.close(); out.close(); } ``` 以上就是一个简单的servlet+jsp文件下载实现。当然,这只是一个基础示例,实际应用中还需要考虑更多的情况,比如文件的安全性、文件的命名规则等等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Astronaut_001

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值