文章目录

  • 1文件上传概述
    • 1.1文件上传的作用
    • 1.2文件上传对页面的要求
    • 1.3 比对文件上传表单和普通文本表单的区别
    • 1.4 对普通文本表单的测试
    • 1.5 文件上传对Servlet的要求
  • 2 commons-fileupload
    • 2.1 fileupload概述
    • 2.2 fileupload简单应用
    • 2.3 简单上传示例
      • 2.3.1 index.jsp
      • 2.3.2 FileUploadServlet
  • 3 文件上传之细节
    • 3.1 把上传的文件放到WEB-INF目录下
    • 3.2 文件名称(完整路径、文件名称)
    • 3.3 中文乱码问题
      • 3.3.1 文件名称中包含中文时
      • 3.3.2 文件内容中包含中文时
    • 3.3 上传文件同名问题(文件重命名)
      • 3.5 一个目录不能存放过多的文件(存放目录打散)
      • 3.7 上传的单个文件的大小限制
      • 3.8 缓存大小与临时目录
  • 4 文件下载
  • 5 实现一个图片外链网站
    • 5.1 项目结构
    • 5.2 具体步骤
      • 5.2.1 在项目中导入`commons-fileupload-1.3.2.jar`和`commons-io-2.5.jar`
      • 5.2.1 在src下创建`com.zxy97.img.servlet`包
      • 5.2.2 在该包下创建UploadServlet.java
      • 5.2.3 创建`webroot/WEB-INF/web.xml`,用来配置servlet
      • 5.2.4 创建`webroot/index.jsp`
  • 6 实现一个资源托管网站
    • 6.1 创建`webroot/WEB-INF/config.properties`
    • 6.2 创建`com/zxy97/img/GetPath.java`
    • 6.3 创建`com.zxy97.img/UploadServlet.java`
    • 6.4 创建`webroot/WEB-INF/web.xml`
    • 6.5 创建webroot/index.jsp

今天傍晚看了李宏利老师的PPT,感触很深,自己很早就实现了文件上传下载,可是一直没有机会梳理,看了他的PPT后,花了三小时写下此文。本文1-3参照老师的PPT,4-6贴出自己的项目。

1文件上传概述

1.1文件上传的作用

例如网盘就是用来上传下载文件的,填写一个完整的简历还需要上传照片。

1.2文件上传对页面的要求

上传文件的要求比较多,需要记一下:

  1. 必须使用表单,而不能是超链接;
  2. 表单的method必须是POST,而不能是GET;
  3. 表单的enctype必须是multipart/form-data;
  4. 在表单中添加file表单字段,即<input type=”file”/>

例如:

<form action="${pageContext.request.contextPath}/FileUploadServlet" method="post" enctype="multipart/form-data">用户名:<input type="text" name="username"/><br/>文件1:<input type="file" name="file1"/><br/>文件2:<input type="file" name="file2"/><br/><input type="submit" value="提交"/>
</form>

1.3 比对文件上传表单和普通文本表单的区别

通过 httpWatch 查看 文件上传表单普通文本表单 的区别。

  • 文件上传表单的enctype="multipart/form-data",表示多部件表单数据;
  • 普通文本表单可以不设置enctype属性:
    • method="post" 时,enctype的默认值为 application/x-www-form-urlencoded ,表示使用url编码正文;
    • method="get" 时,enctype的默认值为 null ,没有正文,所以就不需要enctype了。

1.4 对普通文本表单的测试

通过httpWatch测试,查看表单的请求数据正文,我们发现请求中只有文件名称,而没有文件内容。也就是说,当表单的 enctype不是multipart/form-data 时,请求中不包含文件内容,而只有文件的名称,这说明普通文本表单中 input:fileinput:text 没什么区别了。



测试-前端页面



测试-请求正文



测试-请求头


1.5 文件上传对Servlet的要求

当提交的表单是文件上传表单时,那么对Servlet也是有要求的。

首先要肯定一点,文件上传表单的数据也是被封装到request对象中的。

request.getParameter(String) 方法获取指定的表单字段字符内容,但文件上传表单已经不在是字符内容,而是字节内容,所以失效。

这时可以使用request的getInputStream()方法获取ServletInputStream对象,它是InputStream的子类,这个ServletInputStream对象对应整个表单的正文部分(从第一个分隔线开始,到最后),这说明我们需要的解析流中的数据。当然解析它是很麻烦的一件事情,而Apache已经帮我们提供了解析它的工具:commons-fileupload


可以尝试把request.getInputStream()这个流中的内容打印出来,再对比httpWatch中的请求数据。

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {InputStream in = request.getInputStream();String s = IOUtils.toString(in); System.out.println(s);
}
/*
-----------------------------7ddd3370ab2
Content-Disposition: form-data; name="username"
hello
-----------------------------7ddd3370ab2
Content-Disposition: form-data; name="file1"; filename="a.txt"
Content-Type: text/plain
aaa
-----------------------------7ddd3370ab2
Content-Disposition: form-data; name="file2"; filename="b.txt"
Content-Type: text/plain
bbb
-----------------------------7ddd3370ab2--
*/

2 commons-fileupload

为什么使用fileupload?

上传文件的要求比较多,需要记一下:

  • 必须是POST表单;
  • 表单的enctype必须是multipart/form-data
  • 在表单中添加file表单字段,即 <input type="file"/>

Servlet的要求:

  • 不能再使用request.getParameter()来获取表单数据;
  • 可以使用request.getInputStream()得到所有的表单数据,而不是一个表单项的数据;

这说明不使用fileupload,我们需要自己来对request.getInputStream()的内容进行解析

2.1 fileupload概述

fileupload是由apache的commons组件提供的上传组件。它最主要的工作就是帮我们解析request.getInputStream()。

fileupload组件需要的JAR包有:

  1. commons-fileupload.jar,核心包;
  2. commons-io.jar,依赖包。

下载地址:http://cdn.zxy97.com/s/20180930194932.zip

2.2 fileupload简单应用

fileupload的核心类有:DiskFileItemFactoryServletFileUploadFileItem

使用fileupload组件的步骤如下:

  1. 创建工厂类DiskFileItemFactory对象:
  2. 使用工厂创建解析器对象:
  3. 使用解析器来解析request对象:

DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload fileUpload = new ServletFileUpload(factory);
List<FileItem> list = fileUpload.parseRequest(request);

介绍FileItem类,它才是我们最终要的结果

一个FileItem对象对应一个表单项(表单字段)。一个表单中存在文件字段和普通字段,可以使用FileItem类的isFormField()方法来判断表单字段是否为普通字段,如果不是普通字段,那么就是文件字段了。

  • String getName():获取文件字段的文件名称;
  • String getString():获取字段的内容,如果是文件字段,那么获取的是文件内容,当然上传的文件必须是文本文件;
  • String getFieldName():获取字段名称,例如:,返回的是username;
  • String getContentType():获取上传的文件的类型,例如:text/plain。
  • int getSize():获取上传文件的大小;
  • boolean isFormField():判断当前表单字段是否为普通文本字段,如果返回false,说明是文件字段;
  • InputStream getInputStream():获取上传文件对应的输入流;
  • void write(File):把上传的文件保存到指定文件中。

2.3 简单上传示例

现在写一个简单的上传示例:

  • 表单包含一个用户名字段,以及一个文件字段;
  • Servlet保存上传的文件到uploads目录,显示用户名,文件名,文件大小,文件类型。

2.3.1 index.jsp

第一步:完成 index.jsp,只需要一个表单。注意表单必须是post的,而且enctype必须是mulitpart/form-data的。

<form action="${pageContext.request.contextPath }/FileUploadServlet" method="post" enctype="multipart/form-data">用户名:<input type="text" name="username"/><br/>文件1:<input type="file" name="file1"/><br/><input type="submit" value="提交"/>
</form>

2.3.2 FileUploadServlet

第二步:完成FileUploadServlet

public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 因为要使用response打印,所以设置其编码response.setContentType("text/html;charset=utf-8");// 创建工厂DiskFileItemFactory dfif = new DiskFileItemFactory();// 使用工厂创建解析器对象ServletFileUpload fileUpload = new ServletFileUpload(dfif);try {// 使用解析器对象解析request,得到FileItem列表List<FileItem> list = fileUpload.parseRequest(request);// 遍历所有表单项for(FileItem fileItem : list) {// 如果当前表单项为普通表单项if(fileItem.isFormField()) {// 获取当前表单项的字段名称String fieldName = fileItem.getFieldName();// 如果当前表单项的字段名为usernameif(fieldName.equals("username")) {// 打印当前表单项的内容,即用户在username表单项中输入的内容response.getWriter().print("用户名:" + fileItem.getString() + "<br/>");}} else {//如果当前表单项不是普通表单项,说明就是文件字段String name = fileItem.getName();//获取上传文件的名称// 如果上传的文件名称为空,即没有指定上传文件if(name == null || name.isEmpty()) {continue;}// 获取真实路径,对应${项目目录}/uploads,当然,这个目录必须存在String savepath = this.getServletContext().getRealPath("/uploads");// 通过uploads目录和文件名称来创建File对象File file = new File(savepath, name);// 把上传文件保存到指定位置fileItem.write(file);// 打印上传文件的名称response.getWriter().print("上传文件名:" + name + "<br/>");// 打印上传文件的大小response.getWriter().print("上传文件大小:" + fileItem.getSize() + "<br/>");// 打印上传文件的类型response.getWriter().print("上传文件类型:" + fileItem.getContentType() + "<br/>");}}} catch (Exception e) {throw new ServletException(e);}
}

3 文件上传之细节

3.1 把上传的文件放到WEB-INF目录下

如果没有把用户上传的文件存放到WEB-INF目录下,那么用户就可以可能通过浏览器直接访问上传的文件,这是非常危险的。

假如说用户上传了一个a.jsp文件,然后用户在通过浏览器去访问这个a.jsp文件,那么就会执行a.jsp中的内容,如果在a.jsp中有如下语句:Runtime.getRuntime().exec("shutdown –s –t 1"); 那么你就会…

通常我们会在WEB-INF目录下创建一个uploads目录来存放上传的文件,而在Servlet中找到这个目录需要使用ServletContext的getRealPath(String)方法。

例如在我的upload1项目中有如下语句:

   ServletContext servletContext = this.getServletContext();String savepath = servletContext.getRealPath("/WEB-INF/uploads");/*savepath为:F:\tomcat6_1\webapps\upload1\WEB-INF\uploads*/

3.2 文件名称(完整路径、文件名称)

IE6获取的上传文件名称是完整路径,而其他浏览器获取的上传文件名称只是文件名称而已。浏览器差异的问题我们还是需要处理一下的。

   String name = file1FileItem.getName();response.getWriter().print(name);

使用不同浏览器测试,其中IE6就会返回上传文件的完整路径,不知道IE6在搞什么,这给我们带来了很大的麻烦,就是需要处理这一问题。

处理这一问题也很简单,无论是否为完整路径,我们都去截取最后一个“\”后面的内容就可以了。

   String name = file1FileItem.getName();int lastIndex = name.lastIndexOf("\\");//获取最后一个“\”的位置if(lastIndex != -1) {//注意,如果不是完整路径,那么就不会有“\”的存在。name = name.substring(lastIndex + 1);//获取文件名称}response.getWriter().print(name);

3.3 中文乱码问题

3.3.1 文件名称中包含中文时

需要设置编码,commons-fileupload组件为我们提供了两种设置编码的方式:

  • request.setCharacterEncoding(String):这种方式是我们最为熟悉的方式了;
  • fileUpload.setHeaderEncdoing(String):这种方式的优先级高于前一种。

3.3.2 文件内容中包含中文时

通常我们不需关心上传文件的内容,因为我们会把上传文件保存到硬盘上。

也就是说,文件原来是什么样子,到服务器这边还是什么样子,但是如果你有这样的需求,非要在控制台显示上传的文件内容,那么你可以使用fileItem.getString("utf-8")来处理编码。

即:文本文件内容和普通表单项内容使用FileItem类的getString("utf-8")来处理编码。

3.3 上传文件同名问题(文件重命名)

通常我们会把用户上传的文件保存到uploads目录下,但如果用户上传了同名文件呢?这会出现覆盖的现象。处理这一问题的手段是使用UUID生成唯一名称,然后再使用“_”连接文件上传的原始名称。

例如用户上传的文件是我的一寸照片.jpg,在通过处理后,文件名称为:891b3881395f4175b969256a3f7b6e10_我的一寸照片.jpg,这种手段不会使文件丢失扩展名,并且因为UUID唯一性,上传的文件同名,但在服务器端是不会出现同名问题的。

public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {request.setCharacterEncoding("utf-8");DiskFileItemFactory dfif = new DiskFileItemFactory();ServletFileUpload fileUpload = new ServletFileUpload(dfif);try {List<FileItem> list = fileUpload.parseRequest(request);//获取第二个表单项,因为第一个表单项是username,第二个才是file表单项FileItem fileItem = list.get(1);String name = fileItem.getName();//获取文件名称// 如果客户端使用的是IE6,那么需要从完整路径中获取文件名称int lastIndex = name.lastIndexOf("\\");if(lastIndex != -1) {name = name.substring(lastIndex + 1);}// 获取上传文件的保存目录String savepath = this.getServletContext().getRealPath("/WEB-INF/uploads");String uuid = CommonUtils.uuid();//生成uuidString filename = uuid + "_" + name;//新的文件名称为uuid + 下划线 + 原始名称//创建file对象,下面会把上传文件保存到这个file指定的路径//savepath,即上传文件的保存目录//filename,文件名称File file = new File(savepath, filename);// 保存文件fileItem.write(file);} catch (Exception e) {throw new ServletException(e);} }

3.5 一个目录不能存放过多的文件(存放目录打散)

一个目录下不应该存放过多的文件,一般一个目录存放1000个文件就是上限了,如果在多,那么打开目录时就会很“卡”。你可以尝试打印C:\WINDOWS\system32目录,你会感觉到的。

也就是说,我们需要把上传的文件放到不同的目录中。但是也不能为每个上传的文件一个目录,这种方式会导致目录过多。所以我们应该采用某种算法来“打散”!

打散的方法有很多,例如使用日期来打散,每天生成一个目录。也可以使用文件名的首字母来生成目录,相同首字母的文件放到同一目录下。

  • 日期打散算法:如果某一天上传的文件过多,那么也会出现一个目录文件过多的情况;
  • 首字母打散算法:如果文件名是中文的,因为中文过多,所以会导致目录过多的现象。

我们这里使用hash算法来打散:
获取文件名称的hashCode
获取hCode的低4位,然后转换成16进制字符;
获取hCode的5~8位,然后转换成16进制字符;
使用这两个16进制的字符生成目录链。例如低4位字符为5

   //获取文件名的hashCodeint hCode = name.hashCode();//获取hCode的低4位,并转换成16进制字符串String dir1 = Integer.toHexString(hCode & 0xF);//获取hCode的低5~8位,并转换成16进制字符串String dir2 = Integer.toHexString(hCode >>> 4 & 0xF);//与文件保存目录连接成完整路径savepath = savepath + "/" + dir1 + "/" + dir2;//因为这个路径可能不存在,所以创建成File对象,再创建目录链,确保目录在保存文件之前已经存在new File(savepath).mkdirs();

3.7 上传的单个文件的大小限制

有时我们需要限制一个请求的大小。也就是说这个请求的最大字节数(所有表单项之和)!实现这一功能也很简单,只需要调用ServletFileUpload类的setSizeMax(long)方法即可。

例如fileUpload.setSizeMax(1024 * 10);,则设置整个请求的上限为10KB。当请求大小超出10KB时,ServletFileUpload类的parseRequest()方法会抛出FileUploadBase.SizeLimitExceededException异常。

3.8 缓存大小与临时目录

大家想一想,如果我上传一个蓝光电影,先把电影保存到内存中,然后再通过内存copy到服务器硬盘上,那么你的内存能吃的消么?

所以fileupload组件不可能把文件都保存在内存中,fileupload会判断文件大小是否超出10KB,如果是那么就把文件保存到硬盘上,如果没有超出,那么就保存在内存中。

10KB是fileupload默认的值,我们可以来设置它。

当文件保存到硬盘时,fileupload是把文件保存到系统临时目录,当然你也可以去设置临时目录。

public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {request.setCharacterEncoding("utf-8");DiskFileItemFactory dfif = new DiskFileItemFactory(1024*20, new File("F:\\temp"));ServletFileUpload fileUpload = new ServletFileUpload(dfif);try {List<FileItem> list = fileUpload.parseRequest(request);FileItem fileItem = list.get(1);String name = fileItem.getName();String savepath = this.getServletContext().getRealPath("/WEB-INF/uploads");// 保存文件fileItem.write(path(savepath, name));} catch (Exception e) {throw new ServletException(e);}
}

4 文件下载

文件下载的核心代码就三行:

   response.addHeader("Content-Disposition", "attachment;filename=" + childFileName);response.addHeader("Content-Length", childFileLength);response.setContentType("application/octet-stream");

下面给出一个文件下载的方法实现:

 /*** @param filePath* @param request* @param response* @return * @throws java.io.FileNotFoundException* @throws java.io.UnsupportedEncodingException* @描述 文件下载*/public static boolean downloadFile(String filePath, HttpServletRequest request, HttpServletResponse response)throws FileNotFoundException, UnsupportedEncodingException, IOException {boolean isDownload = false;File childFile = new File(filePath);if (!childFile.exists()) {System.out.println("文件不存在或者已删除-下载失败!" + childFile.getAbsolutePath());} else {try (InputStream fis = new FileInputStream(childFile); OutputStream os = response.getOutputStream()) {String childFileName = URLEncoder.encode(childFile.getName(), "utf-8");String childFileLength = childFile.length() + "";response.addHeader("Content-Disposition", "attachment;filename=" + childFileName);response.addHeader("Content-Length", childFileLength);response.setContentType("application/octet-stream");int data;while ((data = fis.read()) != -1) {os.write(data);}isDownload =true;}}return isDownload;}

5 实现一个图片外链网站

单就文件上传功能,现在你就可以来实现一个资源托管网站(http://cdn.zxy97.com)或者一个图片外链网站(http://img.zxy97.com),以下我将介绍实现图片外链网站的步骤。

5.1 项目结构

5.2 具体步骤

5.2.1 在项目中导入commons-fileupload-1.3.2.jarcommons-io-2.5.jar

commons-fileupload-1.3.2.jarcommons-io-2.5.jar的下载地址:http://cdn.zxy97.com/s/20180930194932.zip
下载好后解压得到两个jar文件,在webroot/WEB-INF下创建lib文件夹,复制进去。
然后再用IDE工具导入到项目中。

5.2.1 在src下创建com.zxy97.img.servlet

com.zxy97是我的域名(zxy97.com)的反写,如果你想把项目直接跑起来,按照该步骤进行即可。

5.2.2 在该包下创建UploadServlet.java


package com.zxy97.img.servlet;import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;public class UploadServlet extends HttpServlet {static final String IMG_FOLDER = "img";//默认的存放img的根文件夹/*** @描述 上传数据及保存文件* @param request* @param response* @return 上传结果*/public static String upload(HttpServletRequest request, HttpServletResponse response) {try {//设置上传的文件大小final int MEMORY_THRESHOLD = 1024 * 1024 * 512;final int MAX_FILE_SIZE = 1024 * 1024 * 1024;final int MAX_REQUEST_SIZE = 1024 * 1024 * 1024;request.setCharacterEncoding("utf-8");response.setCharacterEncoding("utf-8");if (!ServletFileUpload.isMultipartContent(request)) {//检测是否为多媒体上传,如果不是则停止PrintWriter writer = response.getWriter();writer.println("错误:表单必须包含 enctype=multipart/form-data");writer.flush();return null;}DiskFileItemFactory factory = new DiskFileItemFactory();// 实例化,开始配置上传参数factory.setSizeThreshold(MEMORY_THRESHOLD);// 设置内存临界值 - 超过后将产生临时文件并存储于临时目录中factory.setRepository(new File(System.getProperty("java.io.tmpdir")));// 设置临时存储目录ServletFileUpload upload = new ServletFileUpload(factory);upload.setFileSizeMax(MAX_FILE_SIZE);// 设置最大文件上传值upload.setSizeMax(MAX_REQUEST_SIZE);// 设置最大请求值 (包含文件和表单数据)upload.setHeaderEncoding("UTF-8");// 防止中文乱码// 解析请求的内容提取文件数据List<FileItem> formItems = upload.parseRequest(request);if (formItems != null && formItems.size() > 0) {for (FileItem item : formItems) {// 处理不在表单中的字段if (!item.isFormField()) {String itemName = item.getName();//获取文件名,进行验证if(checkFileName(itemName)){//验证通过java.util.Date date = new java.util.Date();//保存当时的系统时间,也可以用别的命名方式String path = "/" + IMG_FOLDER + new java.text.SimpleDateFormat("/yyyyMMddHHmmss").format(date) + getFileSuffix(itemName);//相对路径/*推荐几种:SimpleDateFormat("/yyyy/MM/dd/HH/mm/ss/")   在img文件夹下创建多个文件夹保存文件SimpleDateFormat("/yyyyMMddHHmmss_")    在img文件夹下将文件名改成这种形式*/String filePath = request.getSession().getServletContext().getRealPath("/") + path;File file = new File(filePath);//要保存的文件file.getParentFile().mkdirs();//为要保存的文件创建文件夹,否则无法保存item.write(file);return path;}}}}return null;}catch (Exception ex) {return null;}}/*** @描述 获取文件后缀名 */private static String getFileSuffix(final String fileName){int index = fileName.lastIndexOf(".");if(index >= 0){return fileName.substring(index);}return fileName;}//     private String createFolder(String path){//        File folder = new File(path);
//        if(!folder.exists()){//            if(folder.mkdirs()){//                return folder.getAbsolutePath();
//            }
//        }
//        if(folder.isDirectory()){//            return folder.getAbsolutePath();
//        }
//        return null;
//    }/*** @描述 允许上传的文件后缀*/private static final String []arrSuffix = {".jpg",".png",".bmp",".ico",".jpge",".gif"};public static String arrSuffixToString(){String str = "";for(String s:arrSuffix){str += s + " ";}return str;}/*** @描述 根据允许上传的文件后缀,进行文件判断 */private static boolean checkFileName(final String fileName){String name = fileName.toLowerCase();//转小写for(String suffix:arrSuffix){if(name.endsWith(suffix)){return true;}}return false;}/*** @描述 去掉Servlet带来的冗余路径* */private static String getURL(String requestURL){int index = requestURL.lastIndexOf("/");return requestURL.substring(0, index);}protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String path = upload(request, response);//上传if(path == null){path = "上传失败!支持的文件类型:" + arrSuffixToString() ;}else{path = getURL(request.getRequestURL().toString()) + path;}request.getSession().setAttribute("path", path);response.sendRedirect(getURL(request.getRequestURL().toString()));}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {processRequest(request, response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {processRequest(request, response);}@Overridepublic String getServletInfo() {return "Short description";}
}

5.2.3 创建webroot/WEB-INF/web.xml,用来配置servlet

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"><servlet><servlet-name>UploadServlet</servlet-name><servlet-class>com.zxy97.img.servlet.UploadServlet</servlet-class></servlet><servlet-mapping><servlet-name>UploadServlet</servlet-name><url-pattern>/upload</url-pattern></servlet-mapping><session-config><session-timeout>30</session-timeout></session-config><welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list>
</web-app>

5.2.4 创建webroot/index.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%String path =(String) session.getAttribute("path");if(path == null){path ="";}
%>
<!DOCTYPE html>
<html><head><title>zxy97_免费图片托管</title><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"></head><body><h4><a href="http://zxy97.com/">Zxy97</a> | 图片托管网站</h4><form action="upload" method="post" enctype="multipart/form-data"><input type="file" name="uploadfile" title="请选择您的文件"><button type="submit" class="btn">上传文件 </button></form><p><%=path %></p></body>
</html>

6 实现一个资源托管网站

如果你已经成功地将图片外链网站跑起来了,那么现在你可以对上面的那个项目稍加修改,动态地设置文件扩展名,用来实现一个资源托管网站:http://cdn.zxy97.com。
你在src下写的java代码会编译成class文件存放到webroot/WEB-INF/classes下,发布项目时只需要打包webroot文件夹,当时设置的文件扩展名便无法修改了,所以你可以将文件扩展名写到配置文件中,由程序读取,到时候只需要修改配置文件即可设置网站的文件上传类型、表单最大值、文件最大值、缓存最大值、保存的文件夹等等参数。

首先你需要在webroot/WEB-INF文件夹下创建一个名为config.properties的配置文件。

6.1 创建webroot/WEB-INF/config.properties

目前webroot/WEB-INF/config.properties的内容只有一行,就是用空格分隔的文件扩展名:

suffixArray=.jpg .png .bmp .ico .jpge .gif .zip .rar .7z .mp3 .txt .html .xml

6.2 创建com/zxy97/img/GetPath.java


package com.zxy97.img.servlet;import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Properties;public class GetPath {public String[] getSuffixArray() throws IOException{String str = getValueByKey("suffixArray");return str.split(" ");}private String getValueByKey(String key) throws IOException{return getValueByKey(getWebRootPath()+"/WEB-INF/config.properties",key);}private String getValueByKey(String configFilePath, String key) throws FileNotFoundException, IOException{String value;Properties prop = new Properties();InputStream in = new BufferedInputStream (new FileInputStream(configFilePath));prop.load(in);value = prop.getProperty(key);return value;        }/*** @return WebRoot的绝对路径,在src和jsp中通用的方法*/public String getWebRootPath() {final String strClassName = getClass().getName();String strPackageName = "";if (getClass().getPackage() != null) {strPackageName = getClass().getPackage().getName();}String strClassFileName;if ("".equals(strPackageName)) {strClassFileName = strClassName;} else {strClassFileName = strClassName.substring(strPackageName.length() + 1, strClassName.length());}URL url = getClass().getResource(strClassFileName + ".class");String strURL = url.toString();strURL = strURL.substring(strURL.indexOf("/") + 1, strURL.lastIndexOf("WEB-INF"));return strURL;}
}

6.3 创建com.zxy97.img/UploadServlet.java


package com.zxy97.img.servlet;import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;public class UploadServlet extends HttpServlet {static final String IMG_FOLDER = "s";//默认的存放文件的根文件夹/*** @描述 上传数据及保存文件* @param request* @param response* @return 上传结果*/public static String upload(HttpServletRequest request, HttpServletResponse response) {try {//设置上传的文件大小final int MEMORY_THRESHOLD = 1024 * 1024 * 512;final int MAX_FILE_SIZE = 1024 * 1024 * 1024;final int MAX_REQUEST_SIZE = 1024 * 1024 * 1024;request.setCharacterEncoding("utf-8");response.setCharacterEncoding("utf-8");if (!ServletFileUpload.isMultipartContent(request)) {//检测是否为多媒体上传,如果不是则停止PrintWriter writer = response.getWriter();writer.println("错误:表单必须包含 enctype=multipart/form-data");writer.flush();return null;}DiskFileItemFactory factory = new DiskFileItemFactory();// 实例化,开始配置上传参数factory.setSizeThreshold(MEMORY_THRESHOLD);// 设置内存临界值 - 超过后将产生临时文件并存储于临时目录中factory.setRepository(new File(System.getProperty("java.io.tmpdir")));// 设置临时存储目录ServletFileUpload upload = new ServletFileUpload(factory);upload.setFileSizeMax(MAX_FILE_SIZE);// 设置最大文件上传值upload.setSizeMax(MAX_REQUEST_SIZE);// 设置最大请求值 (包含文件和表单数据)upload.setHeaderEncoding("UTF-8");// 防止中文乱码// 解析请求的内容提取文件数据List<FileItem> formItems = upload.parseRequest(request);if (formItems != null && formItems.size() > 0) {for (FileItem item : formItems) {// 处理不在表单中的字段if (!item.isFormField()) {String itemName = item.getName();//获取文件名,进行验证if(checkFileName(itemName)){//验证通过java.util.Date date = new java.util.Date();//保存当时的系统时间,也可以用别的命名方式String path = "/" + IMG_FOLDER + new java.text.SimpleDateFormat("/yyyyMMddHHmmss").format(date) + getFileSuffix(itemName);//相对路径/*推荐几种:SimpleDateFormat("/yyyy/MM/dd/HH/mm/ss/")   在img文件夹下创建多个文件夹保存文件SimpleDateFormat("/yyyyMMddHHmmss_")    在img文件夹下将文件名改成这种形式*/String filePath = request.getSession().getServletContext().getRealPath("/") + path;File file = new File(filePath);//要保存的文件file.getParentFile().mkdirs();//为要保存的文件创建文件夹,否则无法保存item.write(file);return path;}}}}return null;}catch (Exception ex) {return null;}}/*** @描述 获取文件后缀名 */private static String getFileSuffix(final String fileName){int index = fileName.lastIndexOf(".");if(index >= 0){return fileName.substring(index);}return fileName;}//     private String createFolder(String path){//        File folder = new File(path);
//        if(!folder.exists()){//            if(folder.mkdirs()){//                return folder.getAbsolutePath();
//            }
//        }
//        if(folder.isDirectory()){//            return folder.getAbsolutePath();
//        }
//        return null;
//    }/*** @描述 允许上传的文件后缀*/private static String []arrSuffix;public static String arrSuffixToString(String []strs){String str = "";for(String s:strs){str += s + " ";}return str;}/*** @描述 根据允许上传的文件后缀,进行文件判断 */private static boolean checkFileName(final String fileName) throws IOException{String name = fileName.toLowerCase();//转小写arrSuffix = new GetPath().getSuffixArray();for(String suffix:arrSuffix){if(name.endsWith(suffix)){return true;}}return false;}/*** @描述 去掉Servlet带来的冗余路径* */private static String getURL(String requestURL){int index = requestURL.lastIndexOf("/");return requestURL.substring(0, index);}protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String path = upload(request, response);//上传if(path == null){path = "上传失败!支持的文件类型:" + arrSuffixToString(arrSuffix) ;}else{path = getURL(request.getRequestURL().toString()) + path;}request.getSession().setAttribute("path", path);response.sendRedirect(getURL(request.getRequestURL().toString()));}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {processRequest(request, response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {processRequest(request, response);}@Overridepublic String getServletInfo() {return "Short description";}
}

6.4 创建webroot/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"><servlet><servlet-name>UploadServlet</servlet-name><servlet-class>com.zxy97.img.servlet.UploadServlet</servlet-class></servlet><servlet-mapping><servlet-name>UploadServlet</servlet-name><url-pattern>/upload</url-pattern></servlet-mapping><session-config><session-timeout>30</session-timeout></session-config><welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list>
</web-app>

6.5 创建webroot/index.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%String path =(String) session.getAttribute("path");if(path == null){path ="";}
%>
<!DOCTYPE html>
<html><head><title>zxy97_免费资源托管</title><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"></head><body><h4><a href="http://zxy97.com/">Zxy97</a> | 资源托管网站</h4><form action="upload" method="post" enctype="multipart/form-data"><input type="file" name="uploadfile" title="请选择您的文件"><button type="submit" class="btn">上传文件 </button></form><p><%=path %></p></body>
</html>

Java Web 文件上传下载相关推荐

  1. centos nfs java_CentOS下安装配置NFS并通过Java进行文件上传下载

    1:安装NFS (1)安装 yum install nfs-utils rpcbind (2)启动rpcbind服务 systemctl restart rpcbind.service 查看服务状态 ...

  2. java web文件上传所需要的commons-fileupload和 commons-io jar包

    文章目录 一.官网获取 二.百度网盘分享 三.分享与热爱 一.官网获取 学习java web文件上传时需要用到两个必备的jar包: commons-fileupload commons-io jar ...

  3. java文件流 m.jb51.net_FasfDFS整合Java实现文件上传下载功能实例详解

    今天使用Java代码实现文件的上传和下载.对此作者提供了Java API支持,下载fastdfs-client-java将源码添加到项目中.或者在Maven项目pom.xml文件中添加依赖 org.c ...

  4. SpringMVC整合fastdfs-client-java实现web文件上传下载

    为什么80%的码农都做不了架构师?>>>    版权声明:本文为博主原创文章,转载请标明出处(http://blog.csdn.net/wlwlwlwl015)Thanks. 目录( ...

  5. 文件上传 java web_JavaWeb 文件上传下载

    1. 文件上传下载概述 1.1. 什么是文件上传下载 所谓文件上传下载就是将本地文件上传到服务器端,从服务器端下载文件到本地的过程.例如目前网站需要上传头像.上传下载图片或网盘等功能都是利用文件上传下 ...

  6. web文件上传下载原理浅析

    一.web文件上传浅析 现在有很多Web程序都有上传功能,实现上传功能的组件或框架也很多,如基于java的Commons FileUpload.还有Struts1.x和Struts2中带的上传文件功能 ...

  7. java web文件上传详解_java web图片上传和文件上传实例详解

    java web图片上传和文件上传 图片上传和文件上传本质上是一样的,图片本身也是文件.文件上传就是将图片上传到服务器,方式虽然有很多,但底层的实现都是文件的读写操作. 注意事项 1.form表单一定 ...

  8. java web 文件上传和下载

     在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直 ...

  9. java web 文件上传_Javaweb学习笔记10—文件上传与下载

    今天来讲javaweb的第10阶段学习.文件的上传与下载,今天主要说的是这个功能的实现,不用说了,听名字就是外行人也知道肯定很重要啦. 老规矩,首先先用一张思维导图来展现今天的博客内容. ps:我的思 ...

最新文章

  1. AI 一分钟 | 微软推出全新人工智能平台;多名用户反映亚马逊 Echo 智能音箱突然发笑
  2. golang 关闭制定名称的 tomcat_Tomcat原理详解及请求过程
  3. 解决ecilpse插件安装速度变得很慢
  4. sdut 2107 DFS
  5. oracle原始数据类型,Oracle基本数据类型存储格式浅析——RAW类型
  6. 退出循环:break 跳过当前的这次循环,直接开始下一次循环:continue
  7. 字符串的方法、注释及示例1.
  8. android opencv 水印,关于opencv对图片添加水印
  9. 学习笔记(04):MySQL数据库运维与管理-02-二进制日志及其管理
  10. ftp ---- vsftpd安装卸载
  11. Mybatis Generator的使用 1
  12. c语言从入门到精通真垃圾,从入门到精通的C语言(吐血量)
  13. mysql 间隙锁 作用_关于Mysql 间隙锁的理解
  14. 低功耗STM32L151+RTC唤醒应用总结
  15. 做了三年开发后,我选择回家创业
  16. 将计算机屏幕,iPad化身显示器!一款能让平板变电脑屏幕的神器
  17. 干货! IT项目管理过程详解(资料下载)
  18. linux实训分析与体会,linux实训总结与体会
  19. Unity制作自己的Project Template
  20. java百度天气接口解析_Java调用天气接口(百度天气)解析返回的JSON数据

热门文章

  1. 2020年你用哪一款远程桌面工具?
  2. Java五子棋小游戏(控制台纯Ai算法)
  3. EA周报 | 滴滴回应或被下架APP;腾讯视频回应“push线团队全部被开”;外媒确认iPhone 11 9月10日发布...
  4. STM32中TIM对应的引脚
  5. 利用python,将python语法代码翻译成js语法代码
  6. 二叉树的深度优先搜索, 前序中序后序
  7. 水手猴子和椰子程序matlab,[转载]水手分椰子类型题通解公式及推导(中英对照修改版)...
  8. 蜜蜂、黄蜂以及其他昆虫分类数据集
  9. 武汉火神山医院紧急招募 IT 运维志愿者需求
  10. 弹性布局多列换行居左布局