五、JSP 分页查询及文件上传
5.1 使用分页显示数据
通过网络搜索数据时最常用的操作,但当数据量很大时,页面就会变得冗长,用户必须拖动才能浏览更多的数据
分页是把数据库中需要展示的数据逐页分步展示给用户
以分页的形式显示数据,使数据更加清晰直观
页面不在冗长,也不受数据量的限制
5.1.1 如何实现分页
- 首先,要实现数据分页,可以参考以下几个关键步骤 
  - 确定数据的总量
- 确定每页需要显示的数据数量
- 计算数据可以显示的总页数
- 确定 当前显示的为第几页
 
1、确定数据的总量
- 确定你要查询的数据的总行
- 之后可以根据数据总量以及每页显示的数据数量求出显示的总页数
- 在数据库中可以使用聚合函数 count() 来查询数据总量
2、确定每页需要显示的数据数量
- 每页需要显示的数据数量,即每次需要从数据库中查询出多少条记录用于页面显示
- 这个数量是用户自己定义好的
3、计算数据可以显示的总页数
- 分页功能经常会提示用户按照每页显示的记录数总共会产生多少页数据
- 每次页面中显示的记录数是已知的
- 可以使用数据的总量除以每页显示的数据数量,来得到可以显示的总页数
- 要注意,如果数据的总量除以每页显示的数据数量,如果纯在余数,需要显示的总页数加一
4、实现获取指定页码的数据记录
-  使用 SQL 语句查询是实现数据分页的关键 
-  使用 SQL 语句中的 LIMIT 子句实现分页需求,来查询每页的数据 
-  使用 LIMIT 查询每页的数据具体语法如下 
-  //LIMIT 参数如下 LIMIT (当前页数-1)*每页显示的数据数量,每页显示的数据数量
5.1.2 实现分页的具体步骤
-  创建一个实体类,将有关分页的数据封装到一个类中 
-  代码示例 
 import java.util.List;
public class Page {
    //总数量
    private int totalCount;
    //总页数
    private int totalPageCount;
    //每页显示的数量,这里设置每页显示10个
    private int pageSize=10;
    //当前页数
    private int currPageNo;
    //存储数据的集合
    private List list;
    public int getTotalCount() {
        return totalCount;
    }
    public void setTotalCount(int totalCount) {
       
        this.totalCount = totalCount;
    }
    public int getTotalPageCount() {
        return totalPageCount;
    }
    public void setTotalPageCount(int totalPageCount) {
        //计算总页数
        this.totalPageCount =this.totalCount%pageSize==0?(this.totalCount/pageSize):(this.totalCount/pageSize+1);
    }
    public int getPageSize() {
        return pageSize;
    }
    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }
    public int getCurrPageNo() {
        return currPageNo;
    }
    public void setCurrPageNo(int currPageNo) {
        this.currPageNo = currPageNo;
    }
    public List getList() {
        return list;
    }
    public void setList(List list) {
    }
}
- 当在一个 JavaBean 接口的实现类中可将 Page 实体类当做参数
- 通过 Page 实体类中的各种参数,来编写 SQL 语句以此进行分页查询
5.2 实现文件上传
使用文件上传,需要借助一些使用的第三方文件上传工具
我这里使用的是 commons-fileupload 和 commons-io 依赖
提供了对文件上传的支持,内置的一些方法方便我们更好的上传文件
上传文件的 Maven 依赖
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.9.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.2</version>
</dependency>
5.2.1 页面中的表单元素
1、表单的属性设置
- HTTP 实现上传文件时需要用到表单元素
- 需要设置表单的 enctype 属性,该属性用于设置表达提交数据的编码方式
- 其使用的 multipart/form-data 的编码方式
<form action enctype="mutilpart/form-data" method="psot">
2、使用 File 组件选择文件
- 通过设置 input 标签的 type 属性可以在页面中添加不同类型的控件
- 如要实现文件上传,则需要使用 File 控件
<input type="file" name="ufile">
5.2.2 ServletFileUpload API详解
-  ServletFileUpload 类是 Apache 组件处理文件上传的核心高级类 
-  内置的一些方法可以方便地进行文件上传 
-  ServletFileUpload 常用方法 
| 方法 | 描述 | 
|---|---|
| List <FileItem>parseRequest(Request request) | 解析 Request对象,得到所有上传的数据 然后返回一个 FileItem 类型的 集合 | 
| boolean isMultipartContent(Request request) | 用于判断是否是上传,可以简单理解,就是判断 是否有 encType="multipart/form-data"如果存在才会执行文件上传 | 
| void setFileSizeMax(long fileSizeMax) | 设置单个文件上传大小 | 
| void setSizeMax(long sizeMax) | 设置总文件上传大小 | 
5.2.3 FileItem 类 详解
- ServletFileUpload 对象将 Request 中的每个数据都单独转成 FileItem 类型的数据
- 可以使用 FileItem 中的一些方法来对这些数据进行操作
- FileItem 常用方法
| 方法 | |
|---|---|
| boolean isFormField() | 判断数据是文件类型表单还是普通类型表单 | 
| String getFieldName() | 获取普通类型表单的 name 值 | 
| String getName() | 获取文件类型表单的 name 值 | 
| String getString() | 获取表单当中的值 | 
| InputStream getInputStream() | 获取输入流 | 
| void write(File file) | 写入文件 | 
5.2.4 通过 ServletFileUpload 实现文件上传 详解
- 上传文件之前,需要先确认上传的路径
- 上传路径应当为 Tomcat 服务器中的文件路径,而不是本地路径
- 因为项目在运行时,会部署在 Tomcat 服务器当中,如果你直接上传到了本地,第一次不会显示,需要重启项目才会显示
- 因此需要获取到 Tomcat 服务器当中的地址
- 项目中的 target 文件夹下的东西就是部署在 Tomcat 中的资源
 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q9XlVmH9-1685591009448)(C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20230601112942898.png)]
- 因此可以使用 Request 中的方法来获取到 target 的具体路径
- 获取 target 路径语法如下
String imgPath=req.getSession().getServletContext().getRealPath("imges/");
- 其中 req.getSession().getServletContext()表示获取 target 路径
- **getRealPath("imges/")表示在 target 路径下面查找 imges 文件夹 **
- 也可以在 项目结构当中设置 req.getSession().getServletContext()获取的路径


- 输出目录则是 req.getSession().getServletContext()获取的路径
- 文件上传需要使用 ServletFileUpload 类,但是创建 ServletFileUpload 类 需要使用到 FileItemFactory 工厂类
- 因此创建 ServletFileUpload 对象之前,需要先创建 FileIteamFactory 类工厂,当做参数传给 ServletFileUpload 对象
- 创建 ServletFileUpload 示例
FileItemFactory factory=new DiskFileItemFactory();
ServletFileUpload upload=new ServletFileUpload(factory);
5.2.5 ServletUpload 上传文件示例
- 在代码中实现文件上传功能的具体案例
package com.example.demo01.servlet;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
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.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
@WebServlet("/ser01")
public class Servlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html; charset=UTF-8");
        //创建 ServletFileUpload 对象
        FileItemFactory factory=new DiskFileItemFactory();
        ServletFileUpload upload=new ServletFileUpload(factory);
        //上传文件的路径
        String imgPath=req.getSession().getServletContext().getRealPath("imges/");
        System.out.println("tomcat"+imgPath);
        //判断表单是否时多类型表单
        Boolean isMultipart=ServletFileUpload.isMultipartContent(req);
        if(isMultipart){
            try {
                List<FileItem> fileItems=upload.parseRequest(req);
                Iterator<FileItem> iterator=fileItems.iterator();
                while (iterator.hasNext()) {
                    FileItem item=iterator.next();
                    if(item.isFormField()){
                        //输出 普通类型表单的 name
                        System.out.println(item.getFieldName());
                        //输出 普通类型表单的 value 值
                        System.out.println(item.getString());
                    }else {
                        String fileName=item.getName();
                        //判断文件是否上传,文件名是否为空
                        if(fileName!=null&&!"".equals(fileName)){
                            //修改文件的名字,获取系统毫秒值,防止文件名重复导致错误
                            String newsFileName=System.currentTimeMillis()+item.getName();
                            //创建 File 类型对象,将 上传路径以及文件名当作参数传入
                            File file=new File(imgPath,newsFileName);
                            //上传文件到指定的路径
                            item.write(file);
                            System.out.println(newsFileName);
                        }
                    }
                }
            } catch (FileUploadException e) {
                throw new RuntimeException(e);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
            //响应
        resp.sendRedirect("index.jsp");
    }
}
                }
            }
        } catch (FileUploadException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
        //响应
    resp.sendRedirect("index.jsp");
}
}



















