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" %>
<html>
<head>
<title>查询所有员页面</title>
</head>
<body>
<table border='1'>
<tr>
<td>编号</td>
<td>姓名</td>
<td>工资</td>
<td>年龄</td>
<td colspan='2'>操作</td>
</tr>
<c:forEach var="emp" items="${emps}">
<tr>
<td>${emp.id}</td>
<td>${emp.name}</td>
<td>${emp.salary}</td>
<td>${emp.age}</td>
<td><a href="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/removeEmpController?id=${emp.id}'></c:url>">删除</a></td>
<td><a href="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/showEmpController?id=${emp.id}'></c:url>">修改</a></td>
</tr>
</c:forEach>
</table>
</body>
</html>
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" %>
<html>
<head>
<title>修改员工信息页面</title>
</head>
<body>
<form action="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/updateEmpController'></c:url>" method='post'>
编号:<input type='text' name='id' value="${emp.id}" readonly/><br/>
姓名:<input type='text' name='name' value="${emp.name}" /><br/>
工资:<input type='text' name='salary' value="${emp.salary}" /><br/>
年龄:<input type='text' name='age' value="${emp.age}" /><br/>
<input type='submit' value='修改'/><br/>
</form>
</body>
</html>
分页
概念
分页是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即可
借助EmpProject工程完成分页操作
1.在EmpProject工程中测试分页显示
1.1先修改dao包下EmpDao添加分页查询方法
public List<Emp> selectAll(int pageIndex,int pageSize);
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.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);
}
}
}
思考: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;
}
}
2.2修改dao包中EmpDao中的方法并添加新方法
//修改分页方法
public List<Emp> selectAll(Page page);
//查询数据总行数
public long selectCount();
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;
}
}
2.4 添加业务实现对应Dao包中方法,在service包中对EmpService添加分页业务
public List<Emp> showAllEmp(Page page);
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;
}
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);
}
}
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" %>
<html>
<head>
<title>查询所有员页面</title>
</head>
<body>
<table border='1'>
<tr>
<td>编号</td>
<td>姓名</td>
<td>工资</td>
<td>年龄</td>
<td colspan='2'>操作</td>
</tr>
<c:forEach var="emp" items="${emps}">
<tr>
<td>${emp.id}</td>
<td>${emp.name}</td>
<td>${emp.salary}</td>
<td>${emp.age}</td>
<td><a href="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/removeEmpController?id=${emp.id}'></c:url>">删除</a></td>
<td><a href="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/showEmpController?id=${emp.id}'></c:url>">修改</a></td>
</tr>
</c:forEach>
<tr>
<td colspan="6">
<a href="<c:url context='${pageContext.request.contextPath}'
value='/manager/safe/showAllEmpController?pageIndex=1'></c:url>">首页</a>
<%-- 什么情况之下才可以出现山上一页--%>
<c:if test="${page.pageIndex > 1}">
<a href="<c:url context='${pageContext.request.contextPath}'
value='/manager/safe/showAllEmpController?pageIndex=${page.pageIndex-1}'></c:url>">上一页</a>
</c:if>
<%-- 什么情况下出现下一页--%>
<c:if test="${page.pageIndex < page.totalPages}">
<a href="<c:url context='${pageContext.request.contextPath}'
value='/manager/safe/showAllEmpController?pageIndex=${page.pageIndex+1}'></c:url>">下一页</a>
</c:if>
<a href="<c:url context='${pageContext.request.contextPath}'
value='/manager/safe/showAllEmpController?pageIndex=${page.totalPages}'></c:url>">尾页</a>
</td>
</tr>
</table>
</body>
</html>
上传文件和下载文件
上传和下载的场景
在项目中,文件上传和下载都是常见功能,很多程序或者软件都会经常使用文件上传和下载
场景:
1.QQ或微信的头像【上传】
2.邮箱中有附件上传和下载
文件上传
逻辑:当用户在前端页面文件上传之后,用户上传的文件数据会提交给服务器,实现保存
文件上传实现步骤
1.提交方式
如果是文件上传必须使用form标签,而却method必须是post,因为post请求无数据限制
<form method="post"></form>
2.提交数据格式
表单中有一个属性 enctype 设置表单提交数据类型
如果是上传文件,这个属性必须是设置为【multipart/form-data】
它的含义是“以多段的形式进行拼接提交,以二进制流的方式处理表单种数据,会把指定内容封装进请求参数中”
<form enctype="multipart/form-data" method="post"></form>
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.创建jsp页面,实现文件上传操作
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>文件上传页面</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/upload" enctype="multipart/form-data" method="post">
上传用户:<input type="text" name="username"><br/>
上传文件:<input type="file" name="file"><br/>
<input type = "submit" value = "提交">
</form>
</body>
</html>
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);
}
}
在页面提交请求之后在请求头中多了一条数据
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.安全问题
为了保证服务器安全,上传文件应该放在外界无法访问到目录下,习惯性将上传文件放置到WEB-INF目录下
request.getServletContext().getRealPath("/WEB-INF/upload");
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;
}
}
修改uploadServlet中的代码
//上传文件不是空的,进行保存
if(file != null){
//保证不覆盖原有文件
String oldName = file.getSubmittedFileName();
String newName = UploadUtils.NewFileName(oldName);
//getSubmittedFileName获取文件名
file.write(uploadPath+File.separator+newName);
}
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;
}
修改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);
}
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);
}
多文件上传
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>多文件上传页面</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/upload2" enctype="multipart/form-data" method="post">
上传用户:<input type="text" name="username"><br/>
上传文件1:<input type="file" name="file1"><br/>
上传文件2:<input type="file" name="file2"><br/>
<input type = "submit" value = "提交">
</form>
</body>
</html>
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);
}
}
文件下载
概念
我们将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);
}
}
在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);
}
}
}
}
提供下载页面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" %>
<html>
<head>
<title>下载页面</title>
</head>
<body>
<h2>下载文件列表</h2>
<table>
<tr>
<th>文件名</th>
<th>操作</th>
</tr>
<c:forEach items="${map}" var = "entry">
<tr>
<td>
${entry.value}
</td>
<td>
<a href="${pageContext.request.contextPath}/down?filename=${entry.key}">下载</a>
</td>
</tr>
</c:forEach>
</table>
</body>
</html>
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();
}
}