使用FileUpload工具实现文件上传与使用ThreadLocal容器传递数据实现分页查询下载

    FileUpload是apache commons中的一个组件,FileUpload依赖apache io包,最新的最新的FileUpload可以很好的解析以MIME协议(form表单设置为enctype="multipart/form-data")上传的文件,并对文件进行读写操作,而不用关心如缓存等问题。

    以下是文件上传的web层代码:

package com.hao.web.controller;

import com.hao.domain.Upfile;
import com.hao.factory.Factory;
import com.hao.service.BusinessService;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
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;
import org.apache.commons.fileupload.util.Streams;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.UUID;

public class UploadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.getRequestDispatcher(request.getContextPath() + "/WEB-INF/jsp/upload.jsp").forward(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        DiskFileItemFactory itemFactory = new DiskFileItemFactory();
        //设置内存缓冲区的大小,默认值为10K。当上传文件大于缓冲区大小时, fileupload组件将使用临时文件缓存上传文件
        itemFactory.setSizeThreshold(1024*1024);
        //设置缓存位置,默认值为System.getProperty("java.io.tmpdir"):这里设为应用目录下的/temp目录
        File repository = new File(request.getServletContext().getRealPath("/temp"));
        itemFactory.setRepository(repository);
        //如果CleaningTracker不为空,临时文件会自动删除
        //itemFactory.setFileCleaningTracker(null);
        //CleaningTracker应该在不使用时应该被清除,只要在web.xml中配置
        // <listener>
        //        <listener-class>
        //            org.apache.commons.fileupload.servlet.FileCleanerCleanup
        //        </listener-class>
        // </listener>

        ServletFileUpload fileUpload = new ServletFileUpload(itemFactory);
        //设置上传的文件名编码(注意,普通字段编码要单独设置)
        fileUpload.setHeaderEncoding("UTF-8");
        //设置单个文件最大字节数,单个文件大于这个值解析时抛出FileUploadBase.FileSizeLimitExceededException
        fileUpload.setFileSizeMax(524288000);
        //设置一个完整的请求的最大允许大小,请求大于这个值解析时抛出FileUploadBase.SizeLimitExceededException
        fileUpload.setSizeMax(534288000);
        //注册监听器:可以用于做进度条,这里使每上传1M打印一次进度
        fileUpload.setProgressListener(new ProgressListener() {
            private long init = -1;

            @Override
            public void update(long pBytesRead, long pContentLength, int pItems) {
                long ar = pBytesRead / 1048576;
                if (ar == init) {
                    return;
                }
                init = ar;
                //注意,表单元素也会使pItems自增
                System.out.print("正在上传" + pItems);
                if (pContentLength == -1) {
                    System.out.println("已经上传了" + ar + "Mb");
                } else {
                    System.out.println("已经上传了" + ar + "Mb/" + pContentLength / 1048576f + "Mb");
                }
            }
        });
        //判断封装在request中的上传表单是否为multipart/form-data类型
        t:if (fileUpload.isMultipartContent(request)) {
            Upfile upfile = new Upfile();
            upfile.setUptime(new Date());
            try {
                FileItemIterator itemIterator = fileUpload.getItemIterator(request);
                while (itemIterator.hasNext()) {
                    FileItemStream item = itemIterator.next();
                    //得到字段名
                    String name = item.getFieldName();
                    //得到字段对应的流
                    InputStream stream = item.openStream();
                    //如果是普通字段输入项:将输入项的值保存
                    if (item.isFormField()) {
                        //记得设置编码,防止乱码
                        String value = Streams.asString(stream,"UTF-8");
                        BeanUtils.setProperty(upfile, name, value);
                    } else {
                        String filename = item.getName();
                        filename = filename.substring(filename.lastIndexOf("\\") + 1);
                        if (filename.trim().equals("")){
                            request.setAttribute("message","上次文件不能为空");
                            break t;
                        }
                        BeanUtils.setProperty(upfile, "filename", filename);
                        saveFile(stream, upfile, request.getServletContext().getRealPath("/WEB-INF/upload"));
                    }
                }
                BusinessService bs = Factory.getInstance().create(BusinessService.class);
                bs.addFile(upfile);
                request.setAttribute("message", "上传成功");
            } catch (FileUploadBase.SizeLimitExceededException | FileUploadBase.FileSizeLimitExceededException e) {
                request.setAttribute("message", "上传文件不能超过5Mb");
            } catch (Exception e) {
                e.printStackTrace();
                request.setAttribute("message", "未知错误");
            }
        } else {
            request.setAttribute("message", "上传文件失败");
        }
        request.getRequestDispatcher("/WEB-INF/jsp/message.jsp").forward(request, response);
    }

    private void saveFile(InputStream in, Upfile upfile, String rootPath) throws IOException {
        FileOutputStream out = null;
        try {
            String filename = upfile.getFilename();
            //由文件名的文件路径,以分包储存,提高文件目录性能
            String id = UUID.randomUUID().toString();
            int i = id.hashCode();
            int dir1 = i & 15;
            int dir2 = i >>> 4 & 15;
            upfile.setId(id);
            File savedir = new File(rootPath + File.separator + dir1 + File.separator + dir2 );
            savedir.mkdirs();
            File savepath = new File(rootPath + File.separator + dir1 + File.separator + dir2 + File.separator + id + "_" + filename);
            upfile.setSavepath(savepath.getAbsolutePath());
            byte[] buff = new byte[1024];
            int len;
            out = new FileOutputStream(savepath);
            while ((len = in.read(buff)) > 0) {
                out.write(buff, 0, len);
            }
        } finally {
            in.close();
            if (out != null) {
                out.close();
            }
        }
    }
}

        ThreadLocal可以将保存在其中的数据与线程号绑定,实现同一线程的数据方便访问。使用ThreadLocal将查询信息从web层存储,在dao层就可以取出进行查询,相比于使用参数传递来传递查询信息,该方法可以方便实现跨层传输信息,使用起来非常清爽,代码也简单明了。实现如下:

        用于封装查询信息的FileQueryInfo类:

package com.hao.domain;

//由web层创建封装用户查询信息,给dao层使用,要跨层传递数据,可以用ThreadLocal容器
public class FileQueryInfo {
    private int currentpage = 1;
    private int pagesize = 5;
    private int currentrecord;
    private static ThreadLocal<FileQueryInfo> tl = new ThreadLocal();

    public FileQueryInfo() {
        tl.set(this);
    }

    public static FileQueryInfo getInfo() {
        return tl.get();
    }

    public static void removeInfo() {
        tl.remove();
    }

    public int getCurrentpage() {
        return currentpage;
    }

    public void setCurrentpage(int currentpage) {
        if (currentpage < 1) {
            this.currentpage = 1;
        } else {
            this.currentpage = currentpage;
        }
    }

    public int getPagesize() {
        return pagesize;
    }

    public void setPagesize(int pagesize) {
        if (pagesize < 1) {
            this.pagesize = 5;
        } else {
            this.pagesize = pagesize;
        }
    }

    public int getCurrentrecord() {
        currentrecord = (currentpage - 1) * pagesize;
        return currentrecord;
    }
}

        用于返回查询信息,并在jsp被调用输出的FileQueryBean类:

package com.hao.domain;

import java.util.List;

//由service层创建,封装web层要用的数据
public class FileQueryBean {
    //数据库传的数据 : get set 不用多管
    private int totalrecord;
    private List<Upfile> records;
    //用户传的数据
    private int currentpage;
    private int pagesize;
    //自动生成的数据 : 无set只能get,也可以不设计为字段
    private int nextpage;
    private int previouspage;
    private int totalpage;
    private String[] pagebar;


    public int getNextpage() {
        nextpage = currentpage + 1;
        if (nextpage > getTotalpage()) {
            nextpage = getTotalpage();
        }
        return nextpage;
    }

    public int getPreviouspage() {
        if (currentpage <= 1) {
            previouspage = 1;
        } else {
            previouspage = currentpage - 1;
        }
        return previouspage;
    }

    public int getTotalpage() {
        totalpage = (totalrecord - 1) / pagesize + 1;
        return totalpage;
    }

    public String[] getPagebar() {
        int start;
        int end;
        //这个bar长为10
        if (getTotalpage() < 10) {
            start = 1;
            end = getTotalpage();
        } else {
            if (currentpage > getTotalpage() - 5) {
                end = getTotalpage();
                start = getTotalpage() - 9;
            } else {
                start = currentpage - 4;
                end = currentpage + 5;
            }
        }
        pagebar = new String[end - start + 1];
        for (int i = 0; i < pagebar.length; i++) {
            pagebar[i] = start + i + "";
        }
        return pagebar;
    }

    public int getCurrentpage() {
        return currentpage;
    }

    public void setCurrentpage(int currentpage) {
        this.currentpage = currentpage;
    }

    public int getTotalrecord() {
        return totalrecord;
    }

    public void setTotalrecord(int totalrecord) {
        this.totalrecord = totalrecord;
    }

    public int getPagesize() {
        return pagesize;
    }

    public void setPagesize(int pagesize) {
        this.pagesize = pagesize;
    }

    public List<Upfile> getRecords() {
        return records;
    }

    public void setRecords(List<Upfile> records) {
        this.records = records;
    }
}

        控制最后数据输出的Servlet与JSP:

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            BusinessService bs = Factory.getInstance().create(BusinessService.class);
            FileQueryInfo queryInfo = new FileQueryInfo();
            BeanUtils.populate(queryInfo, request.getParameterMap());
            FileQueryBean filePage = bs.getFilePage();
            request.setAttribute("result", filePage);
            request.getRequestDispatcher("/WEB-INF/jsp/download.jsp").forward(request, response);
        } catch (Exception e) {
            request.setAttribute("message", "未知错误");
            request.getRequestDispatcher("/WEB-INF/jsp/message.jsp").forward(request, response);
        }
    }
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>下载视图</title>
</head>
<body>
<div align="center">
    <table border="1" width="80%">
        <tr>
            <td>
                文件名
            </td>
            <td>
                上传用户
            </td>
            <td>
                上传时间
            </td>
            <td>
                文件描述
            </td>
            <td>
                操作
            </td>
        </tr>
        <c:forEach var="record" items="${result.records }">
            <tr>
                <td>
                        ${record.filename }
                </td>
                <td>
                        ${record.username }
                </td>
                <td>
                        ${record.uptime }
                </td>
                <td>
                        ${record.description }
                </td>
                <td>
                    <a href="DownloadServlet?id=${record.id }" methods="post">下载</a> 
                    <a href="ModifyServlet?id=${record.id }">修改</a> 
                    <a href="DeleteServlet?id=${record.id }">删除</a>
                </td>
            </tr>
        </c:forEach>
    </table>
</div>
<div align="center">
    共${result.totalrecord }条记录,每页${result.pagesize }条记录,共${result.totalpage }页,当前第${result.currentpage }页
    <a href="?currentpage=${result.previouspage }">上一页</a>  

    <c:forEach var="bar" items="${result.pagebar }">
        <c:choose>
            <c:when test="${bar==result.currentpage }">
                ${bar }
            </c:when>
            <c:otherwise>
                <a href="?currentpage=${bar }">${bar }</a>
            </c:otherwise>
        </c:choose>
    </c:forEach>

      <a href="?currentpage=${result.nextpage }">下一页</a>
</div>
</body>
</html>
        最会基本效果是:


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值