웹 응용 프로그램 개발에서, 파일 업로드 및 다운로드 기능은 매우 일반적으로 사용되는 기능은 다음과 같습니다.
파일 업로드, 브라우저, 그것은 일반적 아파치를 사용하여 더 번잡 선택되는 직접 사용 서블릿 입력을 업로드 된 파일 스트림을 획득 한 다음 요청 파라미터 안에 분석하는 경우 서버에 스트림 전송 한 파일을 업로드하는 과정에 오픈 소스 도구 공통 파일 업로드이 파일 업로드 컴포넌트. 이 공통 파일 업로드 항아리 패키지 업로드 컴포넌트 아파치의 공식 얼굴을 다운로드 온라인으로 갈 수 있습니다. 이 패키지를 다운로드해야하므로 공통 파일 업로드는 공통 IO 패키지에 따라 달라집니다.
개발 환경 구축
그림과 같이 프로젝트, 관련 항아리 패키지 아파치 평민 - 파일 업로드 파일 업로드 구성 요소의 추가를 만들 FileUploadAndDownload.
도 항아리 패키지 (20) 가져 오기
업로드 파일
다음과 같이 ● 쓰기 파일 업로드 페이지는 upload.jsp 페이지 코드는 다음과 같습니다
<% @ 페이지 언어 = "자바"의 contentType = "text / html과; 문자셋 = UTF-8"
pageEncoding = "UTF-8"%>
<! DOCTYPE html로>
<HTML>
<head>
<메타 캐릭터 = "UTF-8">
<제목> 밴드 브라더스의 IT 교육 </ 제목>
</ head>
<body>
<양식 액션 = "$ {pageContext.request.contextPath} / 업로드"
에 enctype = "multipart / form-data"에있어서 = "POST">
업로드 사용자 : <입력 유형 = "텍스트"이름 = "사용자 이름"> /> <br
업로드 파일 1 : <입력 유형 = "파일"이름 = "파일 1"> /> <br
업로드 파일 2 : <입력 유형 = "파일"이름 = "파일 2"> /> <br
<input 타입 = "제출"값 = "提交">
</ FORM>
</ body>
</ HTML>
● 메시지를 작성 다음과 같이 페이지, message.jsp 페이지 코드는 메시지를 표시합니다
<% @ 페이지 언어 = "자바"의 contentType = "text / html과; 문자셋 = UTF-8"
pageEncoding = "UTF-8"%>
<! DOCTYPE html로>
<HTML>
<head>
<메타 캐릭터 = "UTF-8">
<제목> 밴드 브라더스의 IT 교육 </ 제목>
</ head>
<body>
$ {메시지}
</ body>
</ HTML>
● 쓰기 처리 파일 업로드 서블릿
패키지 com.xdl.servlet;
수입 java.io.File에;
수입 java.io.FileOutputStream의;
수입 때 java.io.IOException;
수입 java.io.InputStream를;
수입은 java.util.List;
수입 javax.servlet.ServletException;
수입 인 javax.servlet.http.HttpServlet;
수입 나오는 javax.servlet.http.HttpServletRequest;
수입의 javax.servlet.http.HttpServletResponse;
수입 org.apache.commons.fileupload.FileItem;
수입 org.apache.commons.fileupload.disk.DiskFileItemFactory;
수입 org.apache.commons.fileupload.servlet.ServletFileUpload;
공용 클래스에서 UploadServelt는 HttpServlet을 확장 {
개인 정적 최종 길이의 serialVersionUID = 1L;
공공 무효 서비스 (HttpServletRequest의 요청,
HttpServletResponse를 응답) ServletException을, IOException가 {던졌습니다
당신은 파일 업로드를 저장 한 위치 디렉토리를 얻을 //의 WEB-INF 디렉토리에 저장된 파일을 업로드,
// 업로드 된 파일의 안전을 보장하기 위해 외부 세계에 직접 액세스를 허용하지 않습니다
문자열 savePath = this.getServletContext ().
getRealPath ( "/ WEB-INF / 업로드");
파일 파일 = 새로운 파일 (savePath);
당신이 존재 업로드 할 파일을 저장 한 디렉토리를 판별 //
만약 (! file.exists () &&! file.isDirectory ()) {
에서 System.out.println (savePath + "디렉토리는 생성 할 필요가 존재하지 않는");
디렉토리를 생성 //
file.mkdir ();
}
// 메시지 프롬프트
문자열 메시지 = "";
{시도
// 아파치 파일 업로드 컴포넌트 파일 업로드 프로세스 단계를 사용 :
1 // 공장을 만들기 DiskFileItemFactory
DiskFileItemFactory 공장 = 새로운 DiskFileItemFactory ();
// 2, 파일 업로드 파서를 만들
ServletFileUpload 업로드 = 새로운 ServletFileUpload (공장);
중국 깨진 업로드 파일 이름을 해결 //
upload.setHeaderEncoding ( "UTF-8");
// 3까지 제출 된 데이터는 데이터가 업로드 양식입니다 여부를 확인하는 방법
만약 (! ServletFileUpload.isMultipartContent (요청)) {
// 전통적인 방법으로 데이터를 얻을
반환;
}
// 4, ServletFileUpload 파서 업로드 데이터,
//은 해상도 결과가 목록 <FileItem> 모음입니다 반환
// 각 양식 FileItem 폼 엔트리에 대응
목록 <FileItem> = upload.parseRequest리스트 (요청);
{(목록 FileItem 항목)에 대한
// fileitem는 일반 데이터 입력에 캡슐화되어있는 경우
경우 (item.isFormField ()) {
문자열 이름 = item.getFieldName ();
// 일반 중국어 데이터 입력 쓰레기 문제를 해결하기
문자열 값 = item.getString ( "UTF-8");
에서 System.out.println (이름 + "="+ 값);
} 그밖에 {// 패키지는 fileitem 업로드하는 경우
// 파일의 이름을 업로드 할 수,
문자열 파일명 = item.getName ();
에서 System.out.println (이름);
경우 (파일 이름 == null의 || filename.trim (). 등호 ( "")) {
잇다;
}
// 핸들은 파일 이름의 일부만 남겨두고, 파일 이름의 파일 업로드 부분에 대한 경로를 얻을 수 있습니다
파일명 = filename.substring
(filename.lastIndexOf ( "\\ ') + 1);
// 스트림에 입력 업로드 된 파일의 항목을 가져 오기
에서의 InputStream item.getInputStream = ();
파일 출력 스트림을 작성합니다 //
=을 FileOutputStream에
새로운 FileOutputStream에 (savePath + "\\"+ 파일 이름);
버퍼를 생성 //
바이트 버퍼 [] = 새로운 바이트 [1024];
// 데이터 입력 스트림 식별자로부터 판독되었는지의 여부를 판단
INT LEN = 0;
// 버퍼로 루프 입력 스트림 어떤
(렌 = in.read (완충액))> 0이되는 데이터가 존재한다는 것을 의미
반면 (LEN (= in.read (완충액))> 0) {
out.write (버퍼 0 렌);
}
입력 스트림을 닫고 //
넣다();
출력 스트림을 닫고 //
out.close ();
업로드 된 파일을 처리 할 때 // 임시 파일이 생성, 삭제
item.delete ();
메시지는 "파일 업로드!";
}
}
} 캐치 (예외 전자) {
메시지 = "파일 업로드 실패!";
e.printStackTrace ();
}
request.setAttribute ( "메시지", 메시지);
request.getRequestDispatcher ( "/ message.jsp") 전방 (요청, 응답).;
}
}
● web.xml 파일에 UploadServelt은 등록.
<? XML 버전 = "1.0"인코딩 = "UTF-8"?>
<웹 응용 프로그램의 xmlns : XSI = "http://www.w3.org/2001/XMLSchema-instance"
의 xmlns = "http://xmlns.jcp.org/xml/ns/javaee"
XSI :의 schemaLocation = "http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
버전 = "3.1">
<서블릿>
<서블릿 이름>에서 UploadServelt </ 서블릿 이름>
<서블릿 클래스> com.xdl.servlet.UploadServlet </ 서블릿 클래스>
</ 서블릿>
<서블릿 매핑>
<서블릿 이름>에서 UploadServelt </ 서블릿 이름>
<URL 패턴> / 업로드 </ URL 패턴>
</ 서블릿 매핑>
</ 웹 응용 프로그램>
Tomcat 서버 시작 동작 21, 22, 23 및도 24을 초래한다.
21 개 업로드 된 파일
22 개 성공적인 업로드 파일
23 콘솔 업로드 할 파일의 이름을 인쇄
(24) 서버는 클라이언트 파일 업로드를 수신
파일 업로드 정보
위의 코드가 성공적으로 위의 지정된 디렉토리 서버에 파일을 업로드 할 수 있지만, 많은 작은 세부 사항 파일 업로드 기능이 관심을 지불 할 필요가 있지만, A는 몇 가지 아래에 특별한주의가 필요합니다
● 서버 보안을 보장하기 위해, 업로드 파일은 WEB-INF 디렉토리에 넣어 같은 직접 외부 세계에 액세스 할 수있는 디렉토리에 배치해야합니다.
● 업로드 된 파일의 고유 한 파일 이름을 생성하는 현상을 포함하는 문서를 방지합니다.
●는 디렉토리 아래에 너무 많은 파일을 방지 저장소를 파괴하기 위해 해시 알고리즘을 사용합니다.
● 최대 업로드 파일을 제한합니다.
● 당신이받을 때 접미사의 적법성을 결정하기 위해, 파일 이름을 업로드, 업로드 파일 형식을 제한합니다.
● 针对上述提出的5点细节问题,我们来改进一下UploadServlet,改进后的代码如下:
package com.xdl.servlet;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
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.FileUploadBase;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,
// 不允许外界直接访问,保证上传文件的安全
String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
// 上传时生成的临时文件保存目录
String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp");
File tmpFile = new File(tempPath);
if (!tmpFile.exists()) {
// 创建临时目录
tmpFile.mkdir();
}
// 消息提示
String message = "";
try {
// 使用Apache文件上传组件处理文件上传步骤:
// 1、创建一个DiskFileItemFactory工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
// 设置工厂的缓冲区的大小,当上传的文件大小超过缓冲区的大小时,
//就会生成一个临时文件存放到指定的临时目录当中。
factory.setSizeThreshold(1024 * 100);
// 设置缓冲区的大小为100KB,如果不指定,那么缓冲区的大小默认是10KB
// 设置上传时生成的临时文件的保存目录
factory.setRepository(tmpFile);
// 2、创建一个文件上传解析器
ServletFileUpload upload = new ServletFileUpload(factory);
// 监听文件上传进度
upload.setProgressListener(new ProgressListener() {
public void update(long pBytesRead, long pContentLength,
int arg2) {
System.out.println("文件大小为:" + pContentLength
+ ",当前已处理:" + pBytesRead);
}
});
// 解决上传文件名的中文乱码
upload.setHeaderEncoding("UTF-8");
// 3、判断提交上来的数据是否是上传表单的数据
if (!ServletFileUpload.isMultipartContent(request)) {
// 按照传统方式获取数据
return;
}
// 设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB
upload.setFileSizeMax(1024 * 1024);
// 设置上传文件总量的最大值
upload.setSizeMax(1024 * 1024 * 10);
// 4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个
// List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
List<FileItem> list = upload.parseRequest(request);
for (FileItem item : list) {
// 如果fileitem中封装的是普通输入项的数据
if (item.isFormField()) {
String name = item.getFieldName();
// 解决普通输入项的数据的中文乱码问题
String value = item.getString("UTF-8");
System.out.println(name + "=" + value);
} else {// 如果fileitem中封装的是上传文件
// 得到上传的文件名称
String filename = item.getName();
System.out.println(filename);
if (filename == null || filename.trim().equals("")) {
continue;
}
// 处理获取到的上传文件的文件名的路径部分,只保留文件名部分
filename = filename.substring(
filename.lastIndexOf("\\") + 1);
// 得到上传文件的扩展名
String fileExtName =
filename.substring(filename.
lastIndexOf(".") + 1);
// 如果需要限制上传的文件类型,那么可以通过文件的扩展名来判断上
// 传的文件类型是否合法
System.out.println("上传的文件的扩展名是:" + fileExtName);
// 获取item中的上传文件的输入流
InputStream in = item.getInputStream();
// 得到文件保存的名称
String saveFilename = makeFileName(filename);
// 得到文件的保存目录
String realSavePath = makePath(saveFilename, savePath);
// 创建一个文件输出流
FileOutputStream out = new FileOutputStream
(realSavePath + "\\" + saveFilename);
// 创建一个缓冲区
byte buffer[] = new byte[1024];
// 判断输入流中的数据是否已经读完的标识
int len = 0;
// 循环将输入流读入到缓冲区当中
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
// 关闭输入流
in.close();
// 关闭输出流
out.close();
// 删除处理文件上传时生成的临时文件
// item.delete();
message = "文件上传成功!";
}
}
} catch (FileUploadBase.FileSizeLimitExceededException e) {
e.printStackTrace();
request.setAttribute("message", "单个文件超出最大值!!!");
request.getRequestDispatcher("/message.jsp").
forward(request, response);
return;
} catch (FileUploadBase.SizeLimitExceededException e) {
e.printStackTrace();
request.setAttribute("message",
"上传文件的总的大小超出限制的最大值!!!");
request.getRequestDispatcher("/message.jsp").
forward(request, response);
return;
} catch (Exception e) {
message = "文件上传失败!";
e.printStackTrace();
}
request.setAttribute("message", message);
request.getRequestDispatcher("/message.jsp").
forward(request, response);
}
private String makeFileName(String filename) {
// 为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名
return UUID.randomUUID().toString() + "_" + filename;
}
/**
* 为防止一个目录下面出现太多文件,要使用hash算法打散存储
*/
private String makePath(String filename, String savePath) {
// 得到文件名的hashCode的值,得到的就是filename这个字符串对象在内存中的地址
int hashcode = filename.hashCode();
int dir1 = hashcode & 0xf;
int dir2 = (hashcode & 0xf0) >> 4;
// 构造新的保存目录
String dir = savePath + "\\" + dir1 + "\\" + dir2;
// 파일이 두 파일은 또한 디렉토리를 표시 나타낼 수
파일 파일 = 새로운 파일 (디렉토리);
// 디렉토리가 존재하지 않는 경우
만약 (! file.exists ()) {
디렉토리를 생성 //
file.mkdirs ();
}
디렉토리를 반환;
}
}
5시 작은 세부 사항에 대한 개선은 위에 명시된 다음에는 더 완벽 할 경우에도, 우리는 업로드 기능을 파일.