• 2-40 分页、上传和下载


    EmpProject整合修改页面为EL+JSTL模式

    1.将Standard.jar 和 jstl.jar包导入到工程中

    2.修改showAllEmp.jsp页面

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ page import="com.qf.emp.entity.Emp" %>
    <%@ page import="java.util.List" %>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    
        查询所有员页面
    
    
           
                        
    编号 姓名 工资 年龄 操作
    ${emp.id} ${emp.name} ${emp.salary} ${emp.age} 删除 修改
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    3.修改showUpdateEmpInfo.jsp页面

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ page import="com.qf.emp.entity.Emp" %>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    
        修改员工信息页面
    
    
    
             
    编号:
    姓名:
    工资:
    年龄:

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    分页

    概念

    分页是Web应用应用程序非常总要的一个技术,数据库中数据可能是成千上万条,不可能把这么多数据一次性显示在浏览器页面上,一般会根据行数据在页面上所占的空间设置每页显示的若干行,例如:jd商品展示页面中,一页就展示60行数据

    分页的实现思路

    在mysql中如果需要进行限制显示数据条数 limit ,在web中会使用数据库中 limit 关键字进行分页操作
    
    #抛开分页而言
    select * from tableName limit n;  限制显示n条数
    select * from tableName limit m,n ;m是显示行的起始位置  n 显示的个数
    例如:
    select * from tableName limit 0,20; 一次性显示1~20条的数据 即显示20条数据
    
    #web分页
    既然在mysql中提供了 limit 这个关键字,前端页面展示数据也是需要进行查询数据库完成,那么就可以使用 limit 关键字以达到显示前端页面展示数据条数
    #例如: 展示20条数据
    select * from tableName limit 20;
    假如:每一页都展示20条数据,那么上面这个写法就不是很合理了,所以我们就利用 limit m,n 这种形式完成分页查询显示数据的效果
    
    #问题:在于如何计算分页中展示数据的条数,并按照翻页来展示数据
    解决:
    select * from tableName limit 0,20  第一个参数代表第几条开始展示
    #问题:前端页面传递给我们的式页数不是条数,所以如果计算当前也从什么位置开始展示数据?
      ps: 所有网页中数据的展示都是从 第1页也开始,所以m这个值就需要计算了
         #公式: m = 第一个参数(页数)-1(固定值)* 页面展示总条数(n的值) 
         #推算:3页面 每页20条数据 select * from tableName limit m,n 语法
         第一页:先通过公式计算m值
         select * from tableName limit (1-1)*20,20 -->
         select * from tableName limit  0,20  ---> 第一页展示【1-20条数据】
         第二页:先通过公式计算m值
         select * from tableName limit (2-1)*20,20 -->
         select * from tableName limit  20,20  ---> 第二页展示【21-40条数据】
         第三页:先通过公式计算m值
         select * from tableName limit (3-1)*20,20 -->
         select * from tableName limit  40,20  ---> 第三页展示【41-60条数据】
        
        limit 关键字中 m的值 = (pageIndex-1)*pageSize 即 limit关键字做分页数据查询时需要写成(计算)
        select * from tableName limit (pageIndex-1)*pageSize,pageSize;    
         #ps:计算分页公式是固定的,要修改页面展示条数,修改pageSize即可
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    借助EmpProject工程完成分页操作

    1.在EmpProject工程中测试分页显示

    1.1先修改dao包下EmpDao添加分页查询方法

    public List<Emp> selectAll(int pageIndex,int pageSize);
    
    • 1

    1.2实现EmpDao中分页方法【EmpDaoImpl】

     @Override
        public List<Emp> selectAll(int pageIndex, int pageSize) {
            try {
                List<Emp> emps = queryRunner.query(DbUtils.getConnection(),
                        "select * from emp limit ?,?",
                        new BeanListHandler<Emp>(Emp.class),
                        pageIndex, pageSize);
                return emps;
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return  null;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    1.3测试了结果

    package com.qf.emp.dao.impl;
    
    import com.qf.emp.dao.EmpDao;
    import com.qf.emp.entity.Emp;
    
    import java.util.List;
    
    import static org.junit.Assert.*;
    
    public class EmpDaoImplTest {
        //测试分页实现
        @org.junit.Test
        public void selectAll() {
            EmpDao ed = new EmpDaoImpl();
            int pageIndex = 2;//页码
            int pageSize = 5;//页面显示条数
            List<Emp> emps = ed.selectAll((pageIndex - 1) * pageSize, pageSize);
            for(Emp emp : emps){
                System.out.println(emp);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    思考:pageIndex页面应该是前端页面传递给我们,而展示页面数据多少即pageSize应该是为我们设置好的

    ​ 如果超出查询范围,一页展示4数据数据共16条数据,已经到达第4也用户不小心点击下一页,如何处理?

    2.分页在代码中核心处理

    2.1对分页逻辑进行一个统一封装

    会为所有操作到分页数据提供实例类【包含 页码,页大小,总条数,总页数,起始行】

    提供一个分页的实体类Page,在entity包中

    package com.qf.emp.entity;
    
    /**
     * 分页实体类,即对分页中使用数据进行统一封装
     */
    public class Page {
         private Integer pageIndex;//页码
         private Integer pageSize;//页大小即显示多少行数据
         private Integer totalCounts;//数据的总行数
         private Integer totalPages;//总页数
         private Integer startRows;//起始行
    
        //提供一个公有方法,外界可以进行操作,对pageIndex进行赋值
          public Page(Integer pageIndex){
              this(pageIndex,5);
          }
        //提供一个私有化构造方法,这个方法进行计算使用【分页计算】
        private  Page(Integer pageIndex , Integer pageSize){
            this.pageIndex = pageIndex;
            this.pageSize = pageSize;
            //设置起始行
            this.startRows = (pageIndex-1)*pageSize;
        }
    
        //在实际开发中page类中该提供哪些get和set方法由开发者决定
        public Integer getPageIndex() {
            return pageIndex;
        }
    
        public void setPageIndex(Integer pageIndex) {
            this.pageIndex = pageIndex;
        }
    
        public Integer getPageSize() {
            return pageSize;
        }
    
        public void setPageSize(Integer pageSize) {
            this.pageSize = pageSize;
        }
    
        public Integer getTotalCounts() {
            return totalCounts;
        }
    
        public void setTotalCounts(Integer totalCounts) {
            this.totalCounts = totalCounts;
            //总页数计算
            this.setTotalPages(totalCounts%pageSize == 0
                    ?totalCounts/pageSize:totalCounts/pageSize+1);
    
        }
    
        public Integer getTotalPages() {
            return totalPages;
        }
    
        public void setTotalPages(Integer totalPages) {
            this.totalPages = totalPages;
        }
    
        public Integer getStartRows() {
            return startRows;
        }
    
        public void setStartRows(Integer startRows) {
            this.startRows = startRows;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    2.2修改dao包中EmpDao中的方法并添加新方法

     //修改分页方法
        public List<Emp> selectAll(Page page);
        //查询数据总行数
        public long selectCount();
    
    • 1
    • 2
    • 3
    • 4

    2.3实现EmpDao包中新添加的方法

    package com.qf.emp.dao.impl;
    
    import com.qf.emp.dao.EmpDao;
    import com.qf.emp.entity.Emp;
    
    import com.qf.emp.entity.Page;
    import com.qf.emp.utils.DbUtils;
    import org.apache.commons.dbutils.QueryRunner;
    import org.apache.commons.dbutils.handlers.BeanHandler;
    import org.apache.commons.dbutils.handlers.BeanListHandler;
    import org.apache.commons.dbutils.handlers.ScalarHandler;
    
    import java.sql.SQLException;
    import java.util.List;
    
    public class EmpDaoImpl implements EmpDao {
    
        private QueryRunner queryRunner = new QueryRunner();
        @Override
        public List<Emp> selectAll() {
            try {
                List<Emp> emps = queryRunner.query(DbUtils.getConnection(), "select * from emp", new BeanListHandler<Emp>(Emp.class));
                return  emps;
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        @Override
        public int delete(int id) {
            try {
                int update = queryRunner.update(DbUtils.getConnection(), "delete from emp where id = ?", id);
                return update;
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return 0;
        }
    
        @Override
        public int update(Emp emp) {
            try {
                int update = queryRunner.update(
                        DbUtils.getConnection()
                        , "update emp set name = ?,salary=?,age = ? where id = ?"
                        , emp.getName(), emp.getSalary(), emp.getAge(), emp.getId());
                return update;
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return 0;
        }
    
        @Override
        public Emp select(int id) {
            try {
                Emp emp = queryRunner.query(DbUtils.getConnection(),
                        "select * from emp where id = ?", new BeanHandler<Emp>(Emp.class), id);
                return  emp;
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return  null;
        }
    
        @Override
        public List<Emp> selectAll(Page page) {
            try {
                List<Emp> emps = queryRunner.query(DbUtils.getConnection(),
                        "select * from emp limit ?,?",
                        new BeanListHandler<Emp>(Emp.class),
                        page.getStartRows(),page.getPageSize());
                return emps;
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return  null;
        }
    
        @Override
        public long selectCount() {
            try {
                return queryRunner.query(DbUtils.getConnection(),"select count(*) from emp",new ScalarHandler<>());
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return 0;
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92

    2.4 添加业务实现对应Dao包中方法,在service包中对EmpService添加分页业务

    public List<Emp> showAllEmp(Page page);
    
    
    • 1
    • 2

    2.5 实现具体业务逻辑

     @Override
        public List<Emp> showAllEmp(Page page) {
            List<Emp> emps = null;
            try{
                DbUtils.begin();
                //获取总行数
                long count = empDao.selectCount();
                page.setTotalCounts((int)count);
                //根据传递的page查询对应数据
                emps = empDao.selectAll(page);
                DbUtils.commit();
            }catch(Exception e){
                DbUtils.rollback();
                e.printStackTrace();
            }
            return emps;
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2.6 修改controller包中showAllEmpController

    package com.qf.emp.controller;
    
    import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGMacAddrExpr;
    import com.qf.emp.entity.Emp;
    import com.qf.emp.entity.Page;
    import com.qf.emp.service.EmpService;
    import com.qf.emp.service.impl.EmpServiceImpl;
    
    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 java.io.IOException;
    import java.util.List;
    
    @WebServlet(name = "ShowAllEmpController",value="/manager/safe/showAllEmpController")
    public class ShowAllEmpController extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                doGet(request,response);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //1.需要获取URL中参数
            String pageIndex = request.getParameter("pageIndex");
            //2.如果是第一次访问
            if(pageIndex == null){
                pageIndex = "1";//必然展示第一页
            }
            //3.创建page对象进行分页查询
            Page page = new Page(Integer.valueOf(pageIndex));
            EmpService empService = new EmpServiceImpl();
            List<Emp> emps = empService.showAllEmp(page);
            
            //4.将查询结果和page对象设置到作用域中
            request.setAttribute("emps",emps);
            request.setAttribute("page",page);
            //通过请求转换,将数据转发另外一个Servlet进行处理[页面Servlet]
            request.getRequestDispatcher("/manager/safe/showAllEmp.jsp").forward(request,response);
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    2.7最后修改showAllEmp.jsp页面

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ page import="com.qf.emp.entity.Emp" %>
    <%@ page import="java.util.List" %>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    
        查询所有员页面
    
    
           
                        
    编号 姓名 工资 年龄 操作
    ${emp.id} ${emp.name} ${emp.salary} ${emp.age} 删除 修改
    首页 <%-- 什么情况之下才可以出现山上一页--%> 上一页 <%-- 什么情况下出现下一页--%> 下一页 尾页
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    上传文件和下载文件

    上传和下载的场景

    在项目中,文件上传和下载都是常见功能,很多程序或者软件都会经常使用文件上传和下载

    场景:

    1.QQ或微信的头像【上传】

    2.邮箱中有附件上传和下载

    文件上传

    逻辑:当用户在前端页面文件上传之后,用户上传的文件数据会提交给服务器,实现保存

    文件上传实现步骤
    1.提交方式

    如果是文件上传必须使用form标签,而却method必须是post,因为post请求无数据限制

    <form method="post">form>
    
    
    • 1
    • 2
    2.提交数据格式

    表单中有一个属性 enctype 设置表单提交数据类型

    如果是上传文件,这个属性必须是设置为【multipart/form-data】

    它的含义是“以多段的形式进行拼接提交,以二进制流的方式处理表单种数据,会把指定内容封装进请求参数中”

    <form enctype="multipart/form-data" method="post">form>
    
    
    • 1
    • 2
    3.提供组件

    在input中可以使用file属性进行用户上文件组件提供

    <form enctype="multipart/form-data" method="post">
    	上传用户:<input type="text" name="username"><br/>
        上传文件:<input type="file" name="file"><br/>
        <input type = "submit" value = "提交">
    form>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    具体实现文件上传操作

    1.创建jsp页面,实现文件上传操作

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    
        文件上传页面
    
    
      
    上传用户:
    上传文件:
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2.实现文件接收Servlet

    package com.qfed.UploadAndDownload.Upload;
    
    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 java.io.IOException;
    
    @WebServlet(name = "UploadServlet",value = "/upload")
    public class UploadServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("文件上传过来了!!!");
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                doPost(request,response);
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在页面提交请求之后在请求头中多了一条数据

    请添加图片描述

    content-Type:表示提交的数据类型, multipart/form-data【表示提交的数据是以分段的形式进行拼接,并且以(二进制流)的形式发送给服务器】

    boundary :表示每段数据都是以 分隔符进行分隔 ,这个分隔的产生是【虚线+字母和数字随机】

    请添加图片描述

    3.填充具体实现内容到uploadServlet中

    在Servlet3.0及其以上版本的容器中进行服务器端文件上传的编程,是围绕着注解了类型MultipartConfig和javax.servlet.http.Part接口进行的,处理已上传文件的Servlet必须以@MultipartConfig注解进行

    package com.qfed.UploadAndDownload.Upload;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.MultipartConfig;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.Part;
    import java.io.File;
    import java.io.IOException;
    
    @WebServlet(name = "UploadServlet",value = "/upload")
    //maxFileSize 单个文件最大值【单个文件大小】
    //maxRequestSize 一次请求多个文件 一共的大小是多少
    @MultipartConfig(maxFileSize = 1024*1024*100,maxRequestSize = 1024*1024*200 )
    public class UploadServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
           // 设置防止乱码
             request.setCharacterEncoding("UTF-8");
             response.setContentType("text/html;charset=utf-8");
             //获取文件--->需要用过getPart方法
            Part file = request.getPart("file");//file就是上传文件对象
            //决定文件保存位置
            /*
            1.开发中我们会将上传的文件保存在服务器目录中即WEB-INF
            2.还可以保存在实体盘符目录中【绝对路径】
             */
            //getRealPath 文件上传保存的真是路径,会最终出现在out目录下的artifacts目录下的WEB-INF目录中
            String uploadPath = request.getServletContext().getRealPath("/WEB-INF/upload");
            //创建文件夹
            File f = new File(uploadPath);
            if(!f.exists()){//判断文件夹是否存在
                f.mkdirs(); //不存在直接创建
            }
            //上传文件不是空的,进行保存
            if(file != null){
                //getSubmittedFileName获取文件名
                file.write(uploadPath+File.separator+file.getSubmittedFileName());
            }
            response.getWriter().println("上传成功!"+file.getSubmittedFileName());
    
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                doPost(request,response);
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    文件上传注意的小细节

    上述代码虽然可以成功上传文件到服务器指定目录中,但是文件上传功能有许多需要注意的小细节问题

    1.安全问题

    为了保证服务器安全,上传文件应该放在外界无法访问到目录下,习惯性将上传文件放置到WEB-INF目录下

    request.getServletContext().getRealPath("/WEB-INF/upload");
    
    
    • 1
    • 2

    2.文件覆盖

    当上传重名文件的时候,为了防止文件覆盖的现象发生,要为上传文件生产一个唯一的文件名

    ps:这个功能需要根据实际开发中决定。

    package com.qfed.UploadAndDownload.Utils;
    
    import java.util.UUID;
    
    public class UploadUtils {
        private  UploadUtils(){}
        //这个名字的拼接方式是你决定的,将来下载的时候如何还原为原有名字那么就需要通过拼接决定
        //使用Java中提供唯一标识符,唯一标识符的生成需要一个类【UUID】
        public static String NewFileName(String fileName){
            return  UUID.randomUUID().toString().replace("-","")+"_"+fileName;
        }
        
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    修改uploadServlet中的代码

    //上传文件不是空的,进行保存
            if(file != null){
                //保证不覆盖原有文件
                String oldName = file.getSubmittedFileName();
                String newName = UploadUtils.NewFileName(oldName);
                //getSubmittedFileName获取文件名
                file.write(uploadPath+File.separator+newName);
            }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.散列存储

    为了防止一个目录下出现太多文件,要使用hash算法生成二级、三级目录,散列存储山回传文件

     /**
         * 散列计算二、三级目录
         * @param basePath 原始真是路径【即一级目录的路径】
         * @param filename  文件的名字
         * @return 文件存储在服务器中目录的路径
         */
        public static String NewFilePath(String  basePath,String filename){
              //1.先文件名字的hashcode值
            int  hashCode = filename.hashCode();
            //2.使用hashcode值进行进行二级目录计算
            int path1 = hashCode & 15;
            //3.产生三级目录
            int path2 =  (hashCode >> 4) & 15;
            // 与一级目录进行片接形成新的二、三级目录
            String  dir = basePath+ File.separator+path1+File.separator+path2;
            File file = new File(dir);
            if(!file.exists()){
                file.mkdirs();
            }
            return  dir;
    
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    请添加图片描述

    修改uploadServlet类

     //上传文件不是空的,进行保存
            if(file != null){
                //保证不覆盖原有文件,getSubmittedFileName获取文件名
                String oldName = file.getSubmittedFileName();
                String newName = UploadUtils.NewFileName(oldName);
                //通过散列生成 二、三级目录
                String newPath = UploadUtils.NewFilePath(uploadPath, oldName);
                file.write(newPath+File.separator+newName);
            }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4.文件类型限制

    要限制上传文件类型,在在收到文件名字的时候,判断后缀是否合法

    修改uploadServlet类

    //上传文件不是空的,进行保存
            if(file != null){
                //保证不覆盖原有文件,getSubmittedFileName获取文件名
                String oldName = file.getSubmittedFileName();
                //创建一个集合,集合中存储和着文件类型(后缀名字)
                List<String> fileNameList = new ArrayList<>();
                Collections.addAll(fileNameList,".jpg",".bmp",".png");
                String  subFileName = oldName.substring(oldName.lastIndexOf("."));
                if(!fileNameList.contains(subFileName)){
                    response.getWriter().println(oldName+"不符合文件上传规则,上传失败!!");
                    return;
                }
                String newName = UploadUtils.NewFileName(oldName);
                //通过散列生成 二、三级目录
                String newPath = UploadUtils.NewFilePath(uploadPath, oldName);
                file.write(newPath+File.separator+newName);
            }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    多文件上传

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    
        多文件上传页面
    
    
      
    上传用户:
    上传文件1:
    上传文件2:
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    package com.qfed.UploadAndDownload.Upload;
    
    import com.qfed.UploadAndDownload.Utils.UploadUtils;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.MultipartConfig;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.Part;
    import java.io.File;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Collections;
    import java.util.List;
    
    @WebServlet(name = "UploadServlet",value = "/upload2")
    //maxFileSize 单个文件最大值【单个文件大小】
    //maxRequestSize 一次请求多个文件 一共的大小是多少
    @MultipartConfig(maxFileSize = 1024*1024*100,maxRequestSize = 1024*1024*200 )
    public class MoreUploadServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
           // 设置防止乱码
             request.setCharacterEncoding("UTF-8");
             response.setContentType("text/html;charset=utf-8");
            //getRealPath 文件上传保存的真是路径,会最终出现在out目录下的artifacts目录下的WEB-INF目录中
            String basePath = request.getServletContext().getRealPath("/WEB-INF/upload");
            File dir= new File(basePath);
            if(!dir.exists()){
                dir.mkdirs();
            }
            //获取多段数据的集合【获取表单中所有数据】
            Collection<Part> parts = request.getParts();
            if(parts != null){
                for(Part part : parts){
                    //获取文件提交名字
                    String fileName = part.getSubmittedFileName();
                    if(fileName != null){ //文件
                        //为了防止某个上传文件操作没有提供数据
                        if(fileName.trim().equals("")){
                            continue;
                        }
                        //获取包含UUID的文件名字
                        String newFileName = UploadUtils.NewFileName(fileName);
                        //散列文件路径
                        String newFilePath = UploadUtils.NewFilePath(basePath, fileName);
                        //存储
                        part.write(newFilePath+File.separator+newFileName);
                        response.getWriter().println(fileName+"上传成功");
    
                    }else{ //不是文件【普通表单项】
                        //获取input标签中的name名字
                        String name = part.getName();
                        String value = request.getParameter(name);
                        System.out.println(name+"------"+value);
    
                    }
                }
            }
    
    
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletExceptwe
            ion, IOException {
                doPost(request,response);
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    文件下载

    概念

    我们将Web应用系统中的文件资源提供给用户进行下载,首先我们需要先提供一个页面列出上传文件目录下的所有文件,当用户点击文件下下载链接的时候进行下载

    FileListController类显示所有文件列表

    package com.qfed.UploadAndDownload.Download;
    
    import com.qfed.UploadAndDownload.Utils.UploadUtils;
    
    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 java.io.File;
    import java.io.IOException;
    import java.util.HashMap;
    
    @WebServlet(name = "FileListController",value="/fileListController" )
    public class FileListController extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                doGet(request,response);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                //1.乱码
            request.setCharacterEncoding("UTF-8");
            response.setContentType("text/html;charset=utf-8");
            //2.获取文件列表【key是uuid,value是原有文件的名字】
            HashMap<String,String> filemap = new HashMap<>();
            String savePath = request.getServletContext().getRealPath("WEB-INF/upload");
            //遍历【防止文件夹中还有文件夹】
            UploadUtils.getFileList(new File(savePath),filemap);
            //转发:
            request.setAttribute("map",filemap);
            request.getRequestDispatcher("/list.jsp").forward(request,response);
    
    
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    在uploadUtils类中创建了一个方法遍历文件夹下的文件

     /**
         * 遍历文件及存文件值
         * @param file  存文件的路径
         * @param filemap 存储文件的集合
         */
        public static void getFileList(File file, HashMap<String, String> filemap) {
              //获取当前文件对象下所有内容【文件、文件夹】
            File[] files = file.listFiles();
            //如果数据不为空,证明有文件和文件夹
             if(files != null){
                 //每次拿到的文件对象进行判断是【文件还是文件夹】
                 for(File file1 :files){
                     if(file1.isDirectory()){
                         getFileList(file1,filemap);
                     }else{
                         //获取文件的名字
                         String filename = file1.getName();
                         //获取第一个_的下标位
                         int i = filename.indexOf("_");
                         //获取uuid和原来文件名字
                         String realName = filename.substring(i + 1);
                         filemap.put(filename,realName);
                     }
                 }
             }
    
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    提供下载页面list.jsp页面

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%--
      Created by IntelliJ IDEA.
      User: jkmaster
      Date: 2020/10/19
      Time: 15:04
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    
        下载页面
    
    
       

    下载文件列表

    文件名 操作
    ${entry.value} 下载
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    DownServlet下载操作

    ps:千万不要忘了流!!!!!!!

    package com.qfed.UploadAndDownload.Download;
    
    import com.qfed.UploadAndDownload.Utils.UploadUtils;
    
    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 java.io.FileInputStream;
    import java.io.IOException;
    import java.net.URLEncoder;
    
    @WebServlet(name = "DownServlet",value="/down")
    public class DownServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doGet(request,response);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //1.乱码
            request.setCharacterEncoding("UTF-8");
            response.setContentType("text/html;charset=utf-8");
            String savepath = request.getServletContext().getRealPath("WEB-INF/upload");
            System.out.println(savepath);
            //1.获取文件的名称
            String uuidFileName = request.getParameter("filename");
            //如果没有做分目录,下面这两个操作可以不用,做了就必须要用
            //1.才分UUID和原有文件的名字
            String fileName = uuidFileName.split("_")[1];
            //2.通过源文件的名字得到分散路径
            String downPath = UploadUtils.NewFilePath(savepath, fileName);
            System.out.println(downPath);
    
            //3.在回之前,通过响应头告客户端返回数据类型是什么【选做】
            response.setContentType(getServletContext().getMimeType(savepath+"/"+uuidFileName));
            //4.设置响应有,告诉浏览器如何处理流,(附件在下载)【核心】
            /*
             这个设置可以防止浏览器直接打开文件,而是使用附件下载的方式下载
             content-disposition 响应头,表示收到数据后如何处理
             attachment 表示附件,表示附件下载使用
             filename  表示文件的名字
             URLEncoder.encode  指定编码集防止中文乱码
             */
            response.setHeader("content-disposition",
                    "attachment;filename="+ URLEncoder.encode(uuidFileName,"utf-8"));
            //使用流读取下载
            FileInputStream fis = new FileInputStream(downPath+"/"+uuidFileName);
            ServletOutputStream outputStream = response.getOutputStream();
            //下载流
            byte[] buf = new byte[1024*1024*100];
            int len = 0;
            while(((len = fis.read(buf))!=-1)){
                outputStream.write(buf,0,len);
            }
            outputStream.close();
            fis.close();
    
    
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
  • 相关阅读:
    Smart-tools 产品介绍
    信息论与编码——信道编码
    Spring Retry方法重试
    Kotlin语言集合学习:List,Set,去重转换
    觉非科技数据闭环系列 | BEV感知研发实践
    Metabase的基本使用:10分钟快速入门
    Rust之构建命令行程序(六):信息写入
    day05_编译原理学习
    tableau 处理MySql 的bug:时间列被自动加上一个月
    [iOS]-NSOperation、NSOperationQueue
  • 原文地址:https://blog.csdn.net/WilsonDone/article/details/127559692