JAVAWeb文件上传下载

文章说明:
首先,为了方便读者体验,以下是一定能正常运行的所有代码.....相信你一定能正常运行。
然后,会讲解其中一些特别的注意事项。


结构图:

引入jar包:
   apache: commons-fileupload.jar组件,commons-fileupload.jar依赖 commons-io.jar。

jsp页面:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>											
		<form action="UploadServet"  method="post" enctype="multipart/form-data">
			学号:<input name="sno" /><br/>
			姓名:<input name="sname" /><br/>
			上传照片: <input type="file"  name="spicture"/>
			<br/>
			<input type="submit" value="注册"/>
		</form>
		
		
		
		
		<a href="DownloadServlet?filename=MIME.png">MIME</a>
		
</body>
</html>

上传功能UploadServlet.java(上传到upload文件夹内):

注:代码正常运行条件,在Web项目目录下建立upload、uploadTemp文件夹。


1.上传的Servlet基本步骤:
相关类:
工场:DiskFileItemFactory
解析器:ServletFileUpload
表单项:FileItem
1)创建工厂:DiskFileItemFactory factory = new DiskFileItemFactory();
2)创建解析器:ServletFileUpload upload = new ServletFileUpload(factory);
3)创建解析器来解析:List<FileItem> items = upload.parseRequest(request);

2.FileItem的相关主要方法
*boolean isFormField();是否为普通表单项!返回true为普通表单,如果为false即为表单项。
*String getFileName(); 返回当前表单项的名称。
*String getString(String charset);返回表单项的值。
*String getName();返回上传的文件名称。
*long getSize();返回上传文件的字节数。
*InputStream getInputStream();返回上传文件对应的输入流。
*void write(File destFile);把上传的文件内容保存到指定的文件中。
*String getContentType();获取type类型

package org.student.servlet;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
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.FileUploadBase;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;





/**
 * Servlet implementation class UploadServet
 */
@WebServlet("/UploadServet")
public class UploadServet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public UploadServet() {
		super();
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setCharacterEncoding("utf-8");
		response.setContentType("text/html; charset=UTF-8");
		// 上传
		// request.getParameter("sname")
		
		
		
		try {
			boolean isMultipart = ServletFileUpload.isMultipartContent(request);
			if (isMultipart) {// 判断前台的form是否有 mutipart属性
//				FileItemFact	ory factory = new DiskFileItemFactory();
				DiskFileItemFactory factory = new DiskFileItemFactory();
				
				ServletFileUpload upload = new ServletFileUpload(factory);
				
				//设置上传文件时 用到的临时文件的大小则用new DiskFileItemFactory();
				factory.setSizeThreshold(10240);//设置临时的缓冲文件大小为10kb
				String p=request.getSession().getServletContext().getRealPath("uploadTemp") ;
				factory.setRepository(new File(p));
				//factory.setRepository(new File("D:\\study\\uploadtemp"));//设置临时文件的目录
				//控制上传单个文件的大小  20KB ServletFileUpload
				upload.setSizeMax(204800);//200kb
				Thread.sleep(3000);
	
				// 通过parseRequest解析form中的所有请求字段,并保存到 items集合中(即前台传递的sno sname
				// spicture此时就保存在了items中)
				List<FileItem> items = upload.parseRequest(request);
				// 遍历items中的数据(item=sno sname spicture)
				Iterator<FileItem> iter = items.iterator();
				while (iter.hasNext()) {
					FileItem item = iter.next();
					String itemName = item.getFieldName();
					int sno = -1;
					String sname = null;
					// 判断前台字段 是普通form表单字段(sno sname),还是文件字段(spicture)

					// request.getParameter() -- iter.getString()
					if (item.isFormField()) {
						if (itemName.equals("sno")) {// 根据name属性 判断item是sno sname 还是spicture?
							sno = Integer.parseInt(item.getString("UTF-8"));
						} else if (itemName.equals("sname")) {
							sname = item.getString("UTF-8");
						} else {
							System.out.println("其他字段xxx.....");
						}
					} else {// spicture 123
							// 文件 上传
							// 文件名 getFieldName是获取 普通表单字段的Name值
							// getName()是获取 文件名
						String fileName = item.getName();//a.txt   a.docx   a.png
						String ext = fileName.substring(  fileName.lastIndexOf(".")+1 ) ;
						if(!(ext.equals("png") || ext.equals("gif") ||ext.equals("jpg"))) {
							System.out.println("图片类型有误!格式只能是 png gif  jpg");
							return ;//终止
						}
						// 获取文件内容 并上传
						// 定义文件路径:指定上传的位置(服务器路径)
						// 获取服务器路径D:\\study\\apache-tomcat-8.5.30\\wtpwebapps\\UpAndDown\\upload
						String path =request.getSession().getServletContext().getRealPath("upload") ;

						File file = new File(path, fileName);
						
					

						item.write(file);// 上传
						System.out.println(fileName + "上传成功!");
						return;
					}
				}

			}

		}
		catch (FileUploadBase.SizeLimitExceededException e) {//SizeLimitExceededException是FileUploadException的一个子类
			System.out.println("上传文件大小超过限制!最大20KB");
		}
		catch (FileUploadException e) 
		{
			e.printStackTrace();
			
		}
		
		// 解析请求
		catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

上传中的细节问题:
1.文件必须保存在WEB-INF下!(演示代码除外)

*目的是不让游览器直接访问到,例如:你上传了一个jsp文件,内部嵌有恶意代码,则很危险!
2.文件名称相关的问题
*有的游览器上传的文件名是绝对路径,需要切割!例如路径为:C:\files\baibing.jpg
解决方案:

String filename=fi2.getName();
int index=filename.lastIndexOf("\\");
if(index!=-1){
    filename=filename.substring(index+1);
}


*文件名乱码或者普通表单项乱码:request.setCharacterEncoding("UTF-8");
因为fileupload内部会调用request.getCharacterEncoding();
解决方案:

>request.setCharacterEncoding("UTF-8");//优先级低
>servletFileUpload.setHeaderEncoding("UTF-8");//优先级高

*文件同名问题:为每个文件添加唯一前缀uuid
解决方案:

>filename=CommonUtils.uuid()+"_"+filename;

3.目录打散(代码没有实现此功能)
*目的是提高服务器访问效率,文件过多不应不放在同一个目录下。
解决方案:

>首字母打散
>时间打散
>哈希打散
    *通过文件名称得到int值,调用hashCode()
    *它int值转换成16进制0-9,A-F
    *获取16进制的前两位用来生成目录,目录为二层!例如1B2C3D4E5F,/1/B保存文件


4.上传文件的大小限制
*单个文件大小限制

>upload.setFileSizeMax(1024);//10kb

如果超出限制,在parseRequest()方法执行时,会抛出异常!FileUploadBase.FileSizeLimitExceededException

*整个请求所有数据大小限制(整个表单)

>upload.setSizeMax(204800);//200kb

如果超出限制,在parseRequest()方法执行时,会抛出异常!FileUploadBase.SizeLimitExceededException

注意:上述方法需在解析之前(List<FileItem> items = upload.parseRequest(request);)调用

		catch (FileUploadException e) {
			if(e instanceof FileUploadBase.FileSizeLimitExceededException){
				System.out.println("上传的单个文件超出10kb");
			}
			if(e instanceof FileUploadBase.SizeLimitExceededException){
				System.out.println("整个文件超出200kb");
			}		
		}	


5.缓存大小与临时目录
6.上传地址的特殊情况!!
    1.如果修改代码,则在tomcat重新启动时 会被删除
        原因:当修改代码的时候,tomcat会重新编译一份class 并且重新部署(重新创建各种目录)   
    2.如果不修改代码,则不会删除
        原因: 没有修改代码,class仍然是之前的class
因此,为了防止 上传目录丢失: a.虚拟路径    b.直接更换上传目录 到非tomcat目录。 

 

 

下载 DownloadServlet.java(游览器直接下载):

注:代码正常运行条件,在Web项目目录下建立res文件夹,里面存储一个文件名为MIME.png的文件。

package org.student.servlet;

import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;

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 org.apache.tomcat.util.codec.binary.Base64;


/**
 * Servlet implementation class DownloadServlet
 */
@WebServlet("/DownloadServlet")
public class DownloadServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public DownloadServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		//获取需要下载的文件名
		String fileName = request.getParameter("filename") ;//form  、a  href、 ...Server?a=b
		
		//下载文件:需要设置 消息头
		response.addHeader("content-Type","application/octet-stream" );//MIME类型:二进制文件(任意文件)
		
		//对于大多数游览器:response.addHeader("content-Disposition","attachment;filename="+fileName );//fileName包含了文件后缀:abc.txt
		//对于不同游览器,进行不同的处理
		//获取客户端的user-agent信息
		String agent=request.getHeader("User-Agent");
		if(agent.toLowerCase().indexOf("firefox")!=-1){
			response.addHeader("content-Disposition","attachment;filename==?UTF-8?B"+new String(Base64.encodeBase64(fileName.getBytes("UTF-8")) )+"?=");
		}else if(agent.toLowerCase().indexOf("edge")!=-1){
			response.addHeader("content-Disposition","attachment;filename="+URLEncoder.encode(fileName, "UTF-8") );
		}else{
			response.addHeader("content-Disposition","attachment;filename="+fileName );
		}

		//Servlet通过文件的地址  将文件转为输入流 读到Servlet中
		InputStream in = getServletContext().getResourceAsStream("/res/MIME.png") ;
		
		//通过输出流 将 刚才已经转为输入流的文件  输出给用户
		ServletOutputStream out = response.getOutputStream() ;
		byte[] bs = new byte[10];
		int len=-1 ;
		while(  (len=in.read(bs)) != -1) {
			out.write(bs,0,len);
		}
		out.close();
		in.close();
		
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

 

下载的注意事项:

下载:不需要依赖任何jar    
    a.请求(地址a  form),请求Servlet    
    b.Servlet通过文件的地址  将文件转为输入流 读到Servlet中
    c.通过输出流 将 刚才已经转为输入流的文件  输出给用户
注意:下载文件 需要设置2个 响应头:
response.addHeader("content-Type","application/octet-stream" );//MIME类型:二进制文件(任意文件)
response.addHeader("content-Disposition","attachment;filename="+fileName );//fileName包含了文件后缀:abc.txt

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值