java web fileupload_javaweb 文件上传(fileupload) 下载

1 文件上传

html中通过可以向服务器上传文件。不过后台需要手动解析请求,比较复杂,所以可以使用smartupload或apache的fileupload组件进行文件的上传。smartupload据网友测试,在上传大文件时不稳定,所以还是使用fileupload的吧,毕竟apache出品。

本例子中使用的jar包:

commons-fileupload-1.3.2.jar

commons-io-2.5.jar(fileupload依赖)

前端jsp页面:

上传文件:

上传

重置

其中有几个需要注意的点:

form表单的enctype必须为"multipart/form-data"。

中必须有name属性,因为在fileupload中会根据fieldName解析上传的文件。

method必须为POST方法。

如果多文件上传的话,file类型的name必须为不同的名称。

服务端需要建立一个UploadFileServlet来处理请求。

关键的doPost方法:

protected void doPost(HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException {

// TODO Auto-generated method stub

// 首先检测是否是文件上传,主要依据enctype的值来判定

if (!ServletFileUpload.isMultipartContent(request)) {

PrintWriter writer = response.getWriter();

writer.write("Error 不是文件上传,表单必须包含 enctype='multipart/form-data'");

writer.flush();

writer.close();

return;

}

DiskFileItemFactory factory = new DiskFileItemFactory();

// 设置在内存中的缓存大小,如果超过了则保存到临时文件。

factory.setSizeThreshold(MEMORY_THRESHOLD);

System.err.println(System.getProperty("java.io.tmpdir"));

// 设置临时文件夹的目录

factory.setRepository(new File(System.getProperty("java.io.tmpdir")));

ServletFileUpload upload = new ServletFileUpload(factory);

// 设置单个文件大小的最大值

upload.setFileSizeMax(MAX_FILE_SIZE);

// 设置上传文件总量的最大值,包括所有文件和表单的总和

upload.setSizeMax(MAX_REQUEST_SIZE);

File uploadDir = new File(UPLOAD_PATH);

if (!uploadDir.exists()) {

uploadDir.mkdir();

}

try {

// 解析request

List formItems = upload.parseRequest(request);

if (formItems != null && formItems.size() > 0) {

for (FileItem item : formItems) {

// 如果不是普通的formField则就是上传的文件

if (!item.isFormField()) {

String fileName = item.getName();

File storeFile = new File(UPLOAD_PATH + File.separator

+ fileName);

System.err.println(storeFile.getAbsolutePath());

item.write(storeFile);

item.delete();

} else {

System.err.println(item.getString());

}

}

}

request.setAttribute("message", "成功");

request.getRequestDispatcher("result.jsp").forward(request,

response);

} catch (Exception e) {

// TODO: handle exception

request.setAttribute("message", e.getMessage());

request.getRequestDispatcher("result.jsp").forward(request,

response);

e.printStackTrace();

return;

}

}

这样即可实现文件的上传。

需要改进的地方

没有上传进度

限制文件大小

限制文件类型

对于第2点,可以利用fileupload的抛出异常解决。

catch(FileUploadBase.FileSizeLimitExceededException e){

request.setAttribute("message", "单个文件大小超过限制");

request.getRequestDispatcher("result.jsp").forward(request,

response);

e.printStackTrace();

return;

} catch(FileUploadBase.SizeLimitExceededException e){

request.setAttribute("message", "上传文件总大小超过限制");

request.getRequestDispatcher("result.jsp").forward(request,

response);

e.printStackTrace();

return;

}

对于第3点,可以在页面用js进行校验。

enctype="multipart/form-data" οnsubmit="return check_file()">

上传文件:

type="submit" value="upload">上传

value="reset">重置

function check_file() {

var fileName = document.getElementById("uploadFile").value;

var suffix = fileName.substr(fileName.lastIndexOf(".") + 1);

if (suffix !== "exe") {

alert("只能上传exe文件");

return false;

}

}

对于第1点,fileupload可以添加监听器,监听上传进度。

//设置上传进度的监听器

ProgressListener progressListener = new ProgressListener() {

public void update(long pBytesRead, long pContentLength, int pItems) {

System.out.println("We are currently reading item " + pItems);

if (pContentLength == -1) {

System.out.println("So far, " + pBytesRead

+ " bytes have been read.");

} else {

System.out.println("So far, " + pBytesRead + " of "

+ pContentLength + " bytes have been read.");

uploadPercent = (double) pBytesRead / pContentLength;

System.err.println(uploadPercent);

}

}

};

upload.setProgressListener(progressListener);

虽然服务端添加了监听器,可以在console或者Log里打印上传进度,但我们想要的是让用户看到上传进度。所以需要把进度返回给用户。

要解决的问题主要有两个:

进度信息如何保存

前台如何获取

其中的一种方案是利用session。我们将上传进度保存在session里,前台通过ajax方法定时获取上传的进度,因为每个用户是一个session,不同的用户session不同。这样当不同的用户同时上传文件时,依然可以正确的获得上传进

度,不会获取到其他用户上传文件的进度。

具体首先有一个简单的保存上传进度的实体类:

public class UploadStatus {

private double percent;

public double getPercent() {

return percent;

}

public void setPercent(double percent) {

this.percent = percent;

}

}

然后有一个监听的类,实现了ProgressListener接口

public class UploadListener implements ProgressListener{

private UploadStatus status;

public UploadListener(UploadStatus status) {

// TODO Auto-generated constructor stub

this.status = status;

}

@Override

public void update(long pBytesRead, long pContentLength, int pItems) {

// TODO Auto-generated method stub

double uploadPercent = (double) pBytesRead / pContentLength;

status.setPercent(uploadPercent);

}

}

在doPost方法中:

//设置上传进度的监听器

UploadStatus status = new UploadStatus();

UploadListener listener = new UploadListener(status);

upload.setProgressListener(listener);

request.getSession(true).setAttribute("uploadStatus", status);

最后在doGet方法中,返回上传进度。

protected void doGet(HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException {

// TODO Auto-generated method stub

response.setContentType("text/html");

response.setCharacterEncoding("UTF-8");

response.setHeader("Cache-Control", "no-store");

response.setDateHeader("Expires", 0);

response.setHeader("Pragrma", "no-cache");

PrintWriter writer = response.getWriter();

UploadStatus status = (UploadStatus)(request.getSession().getAttribute("uploadStatus"));

if(status != null){

writer.write("上传进度:" + status.getPercent());

}else{

writer.write("没有上传信息");

}

writer.flush();

writer.close();

}

当用户上传时可以访问doGet方法即可获取进度。

前台页面可以这样写:

其中form的target属性可以防止页面跳转。

enctype="multipart/form-data" target="uploadFrame" οnsubmit="getStatus()">

上传文件:

type="submit" value="upload">上传

value="reset">重置

上传进度:

var finished ;

function check_file() {

var fileName = document.getElementById("uploadFile").value;

var suffix = fileName.substr(fileName.lastIndexOf(".") + 1);

if (suffix !== "exe") {

//alert("只能上传exe文件");

//return false;

}

finished = false;

return true;

}

function getStatus(){

finished = false;

console.log("finished = " + finished)

showStatus();

}

function showStatus(){

console.log("showstatus finished = " + finished)

if(finished === true) return;

$.ajax({

url:'UploadFileServlet',

type:'GET',

success:function(data){

$('#progress').text(data);

if(data == '1.0'){

finished = true;

}

},

error:function(data){

alert(data);

}

});

setTimeout(showStatus,1000);

}

最后 完整的程序UploadFile.zip

除了使用form表单上传文件这种方式,也可以利用html5的特性使用ajax上传文件。

下面是主要代码。

var formData = new FormData();

formData.append('file', $('#input')[0].files[0]);

$.ajax({

url: contextPath + '/file/upload?savedName=' + savedName,

type: 'POST',

data: formData,

cache: false,

contentType: false,

processData: false,

xhr: function () {

var xhr = $.ajaxSettings.xhr();

if (xhr.upload) {

xhr.upload.addEventListener("progress", function (evt) {

var percent = parseInt((evt.loaded / evt.total) * 100) + '%';

console.log(percent);

}, false);

return xhr;

}

}

}).done(function(e){})

首先初始化formData对象,然后将真正的file添加到formData里,然后创建一个ajax请求,type是POST,

data: formData,

cache: false,

contentType: false,

processData: false,

这几个属性很重要,具体解释请百度之。

上传进度则使用如下的方式获得:

xhr: function () {

var xhr = $.ajaxSettings.xhr();

if (xhr.upload) {

xhr.upload.addEventListener("progress", function (evt) {

var percent = parseInt((evt.loaded / evt.total) * 100) + '%';

console.log(percent);

}, false);

return xhr;

}

}

这里注意这个是浏览器上传的进度,在服务端还有写入磁盘的时间,所以即便达到100%了服务端可能也并没有完全完成保存操作,不过这个时间差可以忽略。

注意如果出于页面美化的目的,需要隐藏input框,那么一般会使用display:none这个css属性,但由于浏览器安全性的限制,这种方式无法奏效,这里提供一个tricky的方法,给input框设置一个position:absolute;top:-9999px;,这样既可以隐藏input,又可以触发选择文件的操作。

2 文件下载

文件下载相对比较简单

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

// TODO Auto-generated method stub

String id = request.getParameter("id");

//app.properties 路径

DFileItem dao = new DFileItem();

String basePath = request.getSession().getServletContext().getRealPath("");

String configPath = basePath+Constants.CONFIG_PATH;

String uploadPath = Configuration.getInstance(configPath).getProperty(Constants.FILE_STORAGE_PATH);

FileItem item = dao.queryFileItem(id);

if(item == null){

PrintWriter writer = response.getWriter();

writer.write("文件已经被删除");

writer.close();

return;

}

String name = item.getFileName();

response.setContentType("application/octet-stream");

String downloadName = URLEncoder.encode(name,"UTF-8").replaceAll("\\+", "%20");

response.setHeader("Content-Disposition", "attachment;filename*=utf-8'zh_cn'"+downloadName);

File file = new File(uploadPath+item.getUploadTime());

response.setContentLength((int)file.length());

FileInputStream in = new FileInputStream(file);

OutputStream out = response.getOutputStream();

byte[] buffer = new byte[8192];

int len = 0;

while((len = in.read(buffer)) != -1){

out.write(buffer, 0, len);

}

out.flush();

out.close();

in.close();

}

注意response 的contentType和header的设置即可。

最终一个完整的文件上传下载的例子FileServer

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值