文件上传与下载
1.上传文件
@WebServlet(name = "UploadingServlet", value = "/uploading")
@MultipartConfig()
public class UploadingServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
//获取绝对路径名
String realPath = request.getServletContext().getRealPath("/upload");
File dir = new File(realPath);
//创建upload文件夹
if (!dir.exists()) {
dir.mkdirs();
}
//获取数据
Collection<Part> parts = request.getParts();
//判断表单元素是普通字段,还是文件
for (Part part : parts) {
String submittedFileName = part.getSubmittedFileName();
if (submittedFileName == null) {
String name = part.getName();
String value = request.getParameter(name);
System.out.println(name+"--"+value);
}else {
System.out.println(submittedFileName);
part.write(realPath + File.separator + submittedFileName);
//删除part
part.delete();
out.write(submittedFileName+"上传成功...");
}
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
但是根据表单元素的名字来创建文件,不同的浏览器会有不同的表示。
IE浏览器:
所以
@WebServlet(name = "UploadingServlet", value = "/uploading")
@MultipartConfig()
public class UploadingServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
//获取绝对路径名
String realPath = request.getServletContext().getRealPath("/upload");
File dir = new File(realPath);
//创建upload文件夹
if (!dir.exists()) {
dir.mkdirs();
}
//获取数据
Collection<Part> parts = request.getParts();
//判断表单元素是普通字段,还是文件
for (Part part : parts) {
String submittedFileName = part.getSubmittedFileName();
if (submittedFileName == null) {
String name = part.getName();
String value = request.getParameter(name);
System.out.println(name+"--"+value);
}else {
//从请求头中获取文件
String header = part.getHeader("content-disposition");
//截取
String filename = header.substring(header.lastIndexOf("filename=") + 10, header.length() - 1);
filename = filename.substring(filename.lastIndexOf("\\")+1);
System.out.println(filename);
part.write(realPath + File.separator + filename);
//删除part
part.delete();
out.write(filename+"上传成功...");
}
}
}
如果是不同的用户上传了相同的文件会覆盖,所以应该创建不同名称的文件。定义一个工具类,来生成不同的文件名
//创建新的文件名
public static String makeNewFileName(String filename) {
//UUID 统一唯一标识码,认32位的16进制,比如:2d990e71-f5cf-476e-9e31-0dc7ad681638,把“-”去掉,就是一个32位的字符串
String uuid = UUID.randomUUID().toString().replace("-", "");
return uuid = uuid+"_"+filename;
}
@WebServlet(name = "UploadingServlet", value = "/uploading")
@MultipartConfig()
public class UploadingServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
//获取绝对路径名
String realPath = request.getServletContext().getRealPath("/upload");
File dir = new File(realPath);
//创建upload文件夹
if (!dir.exists()) {
dir.mkdirs();
}
//获取数据
Collection<Part> parts = request.getParts();
//判断表单元素是普通字段,还是文件
for (Part part : parts) {
String submittedFileName = part.getSubmittedFileName();
if (submittedFileName == null) {
String name = part.getName();
String value = request.getParameter(name);
System.out.println(name+"--"+value);
}else {
//从请求头中获取文件
String header = part.getHeader("content-disposition");
//截取
String filename = header.substring(header.lastIndexOf("filename=") + 10, header.length() - 1);
filename = filename.substring(filename.lastIndexOf("\\")+1);
//生成新的文件名
String newFileName = UploadUtils.makeNewFileName(filename);
System.out.println(newFileName);
part.write(realPath + File.separator + newFileName);
//删除part
part.delete();
out.write(filename+"上传成功...");
}
}
}
还有问题,如果都往upload一个文件夹里存放文件,读1M的文件,和读1000个1k的文件,肯定是读1M的文件快,所以我们要让他们存放在不同的文件夹中,可以根据上传时间来设置文件夹。我则采用了另一种方式,通过新的文件名创建新的文件夹。我创建了一个生成新的路径的方法。
//生成新的路径,path是upload的路径。filename是新的文件名。
public static String makeNewPath(String path, String filename) {
int num = filename.hashCode();
int path1 = num&0xf;
int path2 = (num>>4)&0xf;
String newPath = path + File.separator +path1 +File.separator +path2;
File dir = new File(newPath);
if(!dir.exists()) {
dir.mkdirs();
}
return newPath;
}
@WebServlet(name = "UploadingServlet", value = "/uploading")
@MultipartConfig()
public class UploadingServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
//获取绝对路径名
String realPath = request.getServletContext().getRealPath("/upload");
File dir = new File(realPath);
//创建upload文件夹
if (!dir.exists()) {
dir.mkdirs();
}
//获取数据
Collection<Part> parts = request.getParts();
//判断表单元素是普通字段,还是文件
for (Part part : parts) {
String submittedFileName = part.getSubmittedFileName();
if (submittedFileName == null) {
String name = part.getName();
String value = request.getParameter(name);
System.out.println(name+"--"+value);
}else {
//从请求头中获取文件
String header = part.getHeader("content-disposition");
//截取
String filename = header.substring(header.lastIndexOf("filename=") + 10, header.length() - 1);
filename = filename.substring(filename.lastIndexOf("\\")+1);
//生成新的文件名
String newFileName = UploadUtils.makeNewFileName(filename);
System.out.println(newFileName);
//生成新的文件路径
String newFilePath = UploadUtils.makeNewPath(realPath, newFileName);
part.write(newFilePath + File.separator + newFileName);
//删除part
part.delete();
out.write(filename+"上传成功...");
}
}
}
我们还没有判断如果上传的文件为空,应该跳过,我们还可以限制上传文件的格式。
@WebServlet(name = "UploadingServlet", value = "/uploading")
@MultipartConfig()
public class UploadingServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
//添加接受的文件的格式
List<String> allowExts = new ArrayList<>();
allowExts.add("png");
allowExts.add("jpg");
allowExts.add("jpeg");
//获取绝对路径名
String realPath = request.getServletContext().getRealPath("/upload");
File dir = new File(realPath);
//创建upload文件夹
if (!dir.exists()) {
dir.mkdirs();
}
//获取数据
Collection<Part> parts = request.getParts();
//判断表单元素是普通字段,还是文件
for (Part part : parts) {
String submittedFileName = part.getSubmittedFileName();
if (submittedFileName == null) {
String name = part.getName();
String value = request.getParameter(name);
System.out.println(name+"--"+value);
}else {
//文件是空的
if(submittedFileName.equals("")){
response.getWriter().write("文件不能为空...");
continue;
}
//从请求头中获取文件
String header = part.getHeader("content-disposition");
//截取
String filename = header.substring(header.lastIndexOf("filename=") + 10, header.length() - 1);
filename = filename.substring(filename.lastIndexOf("\\")+1);
//判断是否符合接受的文件格式
String ext = filename.substring(filename.lastIndexOf(".")+1);
if(!allowExts.contains(ext)){
response.getWriter().write("文件格式不符合要求...");
continue;
}
//生成新的文件名
String newFileName = UploadUtils.makeNewFileName(filename);
System.out.println(newFileName);
//生成新的文件路径
String newFilePath = UploadUtils.makeNewPath(realPath, newFileName);
part.write(newFilePath + File.separator + newFileName);
//删除part
part.delete();
out.write(filename+"上传成功...");
}
}
}
最后我们还要设置一下上传文件的大小。只需在注解中添加属性就可以
@MultipartConfig(maxFileSize = 1024*1024*5, maxRequestSize = 1024*1024*20)
单个文件不超过5M,全部上传文件不超过20M,如果超出了这个界限,会出现500错误页面。所以我们可以设计一个错误界面,去显示这个具体的错误。
还有个问题,我们存文件的地址是不安全的,可以通过路径能访问到,所以我们可以把文件放到WEB-INF文件夹中,这个是不能通过浏览器访问的,但可以通过Servlet来访问。所以说是安全的
最终版
@WebServlet(name = "UploadingServlet", value = "/uploading")
@MultipartConfig(maxFileSize = 1024*1024*5, maxRequestSize = 1024*1024*20)
public class UploadingServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
//添加接受的文件的格式
List<String> allowExts = new ArrayList<>();
allowExts.add("png");
allowExts.add("jpg");
allowExts.add("jpeg");
//获取绝对路径名
String realPath = request.getServletContext().getRealPath("/WEB-INF/upload");
File dir = new File(realPath);
//创建upload文件夹
if (!dir.exists()) {
dir.mkdirs();
}
//获取数据
Collection<Part> parts = request.getParts();
//判断表单元素是普通字段,还是文件
for (Part part : parts) {
String submittedFileName = part.getSubmittedFileName();
if (submittedFileName == null) {
String name = part.getName();
String value = request.getParameter(name);
System.out.println(name+"--"+value);
}else {
//文件是空的
if(submittedFileName.equals("")){
response.getWriter().write("文件不能为空...");
continue;
}
//从请求头中获取文件
String header = part.getHeader("content-disposition");
//截取
String filename = header.substring(header.lastIndexOf("filename=") + 10, header.length() - 1);
filename = filename.substring(filename.lastIndexOf("\\")+1);
//判断是否符合接受的文件格式
String ext = filename.substring(filename.lastIndexOf(".")+1);
if(!allowExts.contains(ext)){
response.getWriter().write("文件格式不符合要求...");
continue;
}
//生成新的文件名
String newFileName = UploadUtils.makeNewFileName(filename);
System.out.println(newFileName);
//生成新的文件路径
String newFilePath = UploadUtils.makeNewPath(realPath, newFileName);
part.write(newFilePath + File.separator + newFileName);
//删除part
part.delete();
out.write(filename+"上传成功...");
}
}
}