BCSP-玄子Java开发之Java Web编程CH07_使用JSP/Servlet开发复杂业务
实现数据分页查
大量数据的展示
- 页面冗长、数据定位不方便,需要拖动页面才能浏览更多的数据
- 一次性查询大量数据,数据库查询压力大,浪费系统资源
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d5AyOCQK-1687706642193)(./assets/image-20230625120023570.png)]
分页展示大量数据
常见的数据分页展示案例
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B3JeGASW-1687706642194)(./assets/image-20230625120049398.png)]
分页功能要点
- 每页显示数据量
- 数据总量
- 当前页码
实现分页的关键步骤
- 确定每页需要展示的数据数量
- 计算数据可以展示的总页数
- 实现获取指定页码的数据记录
确定每页需要展示的数据数量
- 根据需求,设定每页展示数据量或通过请求动态传递每页展示的数据量
- 创建分页类( Page.java),封装分页相关信息
public class Page {
private int totalPageCount = 0; //总页数
private int pageSize = 10; //每页展示记录数
private int totalCount; //记录总数
private int currPageNo = 1; //当前页码
private List<Blog> blogsList; //每页微博集合
// 省略其他代码…
}
计算数据可以展示的总页数
- 查询数据总量
select count(1) from 表名
- 计算总页数
//每页微博集合
public void setTotalCount(int totalCount) {
if (totalCount > 0){
this.totalCount = totalCount;
totalPageCount = this.totalCount % pageSize == 0 ?
(this.totalCount / pageSize) :
(this.totalCount / pageSize + 1);
}
}
使用limit关键字分页查询数据
select … from blog LIMIT 5, 10
-- 从第6条数据开始 查询10条数据
- 实现获取指定页码的数据记录
起始行偏移量 = (当前页页码 - 1) * 每页展示的记录数
不同数据库实现分页的SQL语句之间存在差异,因此在实际应用中根据数据库的不同,需要修改相应的SQL语句
页面边界控制
- 当前页码:页面初次打开时,页码默认是第1页
String pageIndex = request.getParameter(“pageIndex”);//获得当前页码
if (pageIndex == null || (pageIndex = pageIndex.trim()).length() == 0) {
pageIndex = "1";
}
- 首页:当页面处于首页时,不可执行上一页操作
if (currPageNo < 1) { currPageNo = 1; }
- 末页:当页面处于末页时,不可执行下一页操作
// 如果页码大于总页数,设置页面值为最大页数
if (pageObj.getCurrPageNo() > pageObj.getTotalPageCount()){
pageObj.setCurrPageNo(pageObj.getTotalPageCount());
}
前端实现分页功能
- 当页面处于首页时,不显示“首页”、“上一页”
- 当页面处于末页时,不显示“末页”、“下一页”
当前页数:[<%=pageObj.getCurrPageNo()%>/<%=pageObj.getTotalPageCount()%>]
<% if (pageObj.getCurrPageNo() > 1) {%>
<a href="../control/blog?opr=allBlogList&keyword=<%=keyword%>&pageIndex=1">首页</a>
<a href="../control/blog?opr=allBlogList&keyword=<%=keyword%>
&pageIndex=<%=pageObj.getCurrPageNo()-1%>">上一页</a>
<%} if (pageObj.getCurrPageNo() < pageObj.getTotalPageCount()) {%>
<a href="../control/blog?opr=allBlogList&keyword=<%=keyword%>
&pageIndex=<%=pageObj.getCurrPageNo()+1%>">下一页</a>
<a href="../control/blog?opr=allBlogList&keyword=<%=keyword%>
&pageIndex=<%=pageObj.getTotalPageCount()%>">末页</a>
<%}%>
实现文件上传
常见的文件上传功能
- 发表朋友圈、微博
- 发布抖音、快手视频
- 上传证件照片
- …
Servlet 3.0 文件上传API
Part接口代表上传的文件或表单数据,Part接口的常用方法
方法 | 说明 |
---|---|
String getName() | 获取控件的name属性 |
long getSize() | 获取上传文件大小,单位是字节 |
InputStream getInputStream() | 获取输入流,用于检索文件的内容 |
void write(String fileName) | 将上传的文件写入磁盘 |
String getHeader(String name) | 获取指定part请求头信息 |
Collection<String> getHeaders(String name) | 获取指定名称的所有请求头信息 |
Collection<String> getHeaderNames() | 获取所有请求头的名称 |
String getContentType() | 获取文件MIME类型 |
MIME
Multipurpose Internet Mail Extensions
- 描述消息类型的因特网标准
- 包含文本、图像、音频、视频以及其他应用程序专用的数据
类型/子类型 | 扩展名 |
---|---|
application/pdf | |
application/x-javascript | js |
image/gif | gif |
image/jpeg | jpeg |
image/jpeg | jpg |
@MultipartConfig注解
标注在 Servlet 上
- 表示Servlet希望处理请求的MIME类型是 multipart/form-data
- 标注@MultipartConfig注解后,可通过HttpServletRequest.getPart()方法或HttpServletRequest.getParts()方法获取Part对象
属性名称 | 说明 |
---|---|
fileSizeThreshold | 是否将文件缓存到磁盘的大小阈值。当文件小于该值时,文件存储在内存中;否则缓存到磁盘中。默认为0,即文件被直接缓存到磁盘 |
location | 指定缓存上传文件的临时目录,默认为"" |
maxFileSize | 每个上传文件的最大体量,以字节为单位。默认值为-1L,表示不限制大小 |
maxRequestSize | 整个multipart/form-data请求所允许的最大体量,默认值为-1L,表示不限制大小 |
通过Servlet API实现单文件上传
- 编写文件上传表单
<form action="UploadServlet" enctype="multipart/form-data" method="post">
用户名:<input type="text" name="user"><br>
上传文件:<input type="file" name="ufile"><br>
<input type="submit" value="上传">
</form>
enctype属性常用取值
- application/x-www-form-urlencode(默认值)
- multipart/form-data
- text/plain
- 创建文件上传的Servlet并添加@MultipartConfig注解
@WebServlet(name="UploadServlet", urlPatterns = "/UploadServlet")
@MultipartConfig
public class UploadServlet extends HttpServlet {…}
- 通过Part对象获取上传文件信息
Part part = request.getPart("ufile"); //获取Part对象
// 对应表单中name 属性为“ufile”的 input标签
String fileName = extractFileName(part); //提取文件名
- 从请求头中提取文件名
private String extractFileName(Part part) {
String contentDisp = part.getHeader("content-disposition");
String[] items = contentDisp.split(";");
for (String s : items) {
if (s.trim().startsWith("filename")) {
return s.substring(s.indexOf("=") + 2, s.length()-1);
}
}
return "";
}
- 将文件写入指定目录
String uploadFilePath = request.getSession()
.getServletContext().getRealPath("upload/");
// 服务器文件目录 绝对路径
part.write(uploadFilePath + File.separator + fileName);
如果写入文件的目录不存在,则需要先创建该目录
通过Servlet API实现多文件上传
- 编写文件上传表单
<form action="UploadServlet" enctype="multipart/form-data" method="post">
用户名:<input type="text" name="user"><br>
上传文件1:<input type="file" name="ufile1"><br>
上传文件2:<input type="file" name="ufile2"><br>
<input type="submit" value="上传">
</form>
- 获取上传文件的Part对象集合,循环处理上传文件
- 通过Part对象获取上传文件信息
Collection<Part> parts = request.getParts();
for (Part part : request.getParts()) {
if(part.getName().startsWith("ufile")){ //判断是否是上传文件
String fileName = extractFileName(part);
part.write(uploadFilePath + File.separator + fileName);
}
}
控制上传文件类型
- 定义允许上传的图片类型
private String ALLOW_IMG_TYPE = "image/gif;image/png;image/jpeg";
- 获取上传文件的类型
String contentType = part.getContentType(); // 获取上传文件类型
- 判断上传文件类型是否符合规定
List<String> allowTypes = Arrays.asList(ALLOW_IMG_TYPE.split(";"));
if(!(contentType==null || "".equals(contentType.trim()))
&& allowTypes.contains(contentType)){
String fileName = extractFileName(part); //提取文件名
part.write(uploadFilePath + File.separator + fileName); //写入文件
message = "上传成功!";
}else{message = "上传失败,文件类型只能是gif格式、jpg格式和png格式!"; }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DoFI9m6p-1687706642195)(./assets/image-20230625121708298.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ms8mH4Gy-1687706642195)(./assets/image-20230625121710629.png)]
控制上传文件大小
通过@MultipartConfig注解设置上传文件大小
@WebServlet(name="UploadServlet", urlPatterns = "/UploadServlet")
@MultipartConfig(maxFileSize=1024*1024*2) //设置文件最大为2MB
public class UploadServlet extends HttpServlet {…}
获取注解中设置的值
private static MultipartConfig config
= UploadServlet.class.getAnnotation(MultipartConfig.class);
根据文件上传结果,封装提示信息
try { // 省略其他代码
part.write(uploadFilePath + File.separator + fileName); //将文件写入指定目录
message = "上传成功后的文件名是:"+fileName+",文件大小是:"+
part.getSize()+"bytes!";
}catch(IllegalStateException e){
message = "上传失败,文件太大,文件的最大限制是:"+
config.maxFileSize() +"bytes!";
}
- 上传文件大小超限,运行效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qBkOtkFW-1687706642196)(./assets/image-20230625121949360.png)]