如何把文件上传到服务器?
实现web开发中的文件上传功能,需完成如下两步操作:
- 在web页面中添加上传输入项。(将数据放到请求报文的请求体中)
- 在servlet中读取上传文件的数据,并保存到服务器硬盘中。(解析请求报文,取出请求体,会用到IO流)
如何在web页面中添加上传输入项?
标签用于在web页面中添加文件上传输入项,设置文件上传输入项时须注意:
1、必须要设置input输入项的name属性,否则浏览器将不会发送上传文件的数据
2、必须把form的enctype属值设为multipart/form-data.设置该值后,浏览器在上传文件时,将把文件数据附带在http请求消息体中,并使用MIME协议对上传的文件进行描述,以方便接收方对上传数据进行解析和处理。
3、表单的提交方式要是post
upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/app/upload" method="post">
<input type="text" name="username"><br>
<input type="file" name="image"><br>
<input type="submit">
</form>
</body>
</html>
uploadServlet.java
package upload;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
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.FileOutputStream;
import java.io.IOException;
@WebServlet("/upload")
public class UploadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletInputStream inputStream = req.getInputStream();
String realPath = getServletContext().getRealPath("upload/1.jpg");
File file = new File(realPath);
if (!file.getParentFile().exists()){
//如果file的上层目录不存在,则创建对应的目录
file.getParentFile().mkdirs();
}
FileOutputStream outputStream = new FileOutputStream(file);
int length = 0;
byte[] bytes = new byte[1024];
while ((length = inputStream.read(bytes)) != -1){
outputStream.write(bytes, 0 , length);
}
outputStream.flush();
outputStream.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
1.1 问题一:仅会上传文件名,不会上传文件的二进制数据
解决方案
form表单添加enctype = “multipart/form-data”
处理完毕之后,发现文件已经损坏,图片无法打开。
1.2 问题二:上传图片,处理完毕图片损坏,无法打开
为什么呢?不用图片,用txt文件尝试一下
在报文中多出了一些分隔符,如果这些分隔符在二进制文件中,会导致文件损坏。
1.3 问题三:如果此时普通form表单数据和文件上传同时提交,获取参数
获取username参数,得到的却是null。
原来可以请求到的参数的API不能够再使用了。
添加enctype = “multipart/form-data”之后,获取请求参数的方法不能够再使用了
enctype = “multipart/form-data”没加之前:
这个时候API可以使用,能够获取参数。
enctype = “multipart/form-data”添加之后:
根本原因在于:数据结构发生变化。之前是key1=value1&key2=value2
数据结构发生了变化,导致了getParameter这个API不能再使用。
1.4 处理这个问题:
第三方工具供我们使用。不要重复造轮子。需要我们利用工具来解决你的实际问题即可。
工具类:Commons-fileupload
官方文档网址:http://commons.apache.org/proper/commons-fileupload/
使用步骤:
- 导包
- 根据文档的方法写代码
有没有中文乱码问题?
setCharacter方法已经不再使用了。
普通form表单数据中文乱码问题解决方案
上传的文件名乱码问题解决
upload.setHeaderEncodeing()
可以设置上传文件的大小,单位是字节
用户注册:普通form表单数据、上传头像。
头像以什么形式在数据库里面?地址。
实现文件上传的代码:
FileUploadUtils.java
package com.cskaoyan.fileupload.utils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.*;
public class FileUploadUtils {
public static Map<String, Object> parseRequest(HttpServletRequest request) {
// Create a factory for disk-based file items
DiskFileItemFactory factory = new DiskFileItemFactory();
// Configure a repository (to ensure a secure temp location is used)
ServletContext servletContext = request.getServletContext();
File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
//设置一个缓存仓库,如果文件很大,那么就边缓存边上传
factory.setRepository(repository);
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);
//设置上传的文件名中文乱码问题
upload.setHeaderEncoding("utf-8");
// bytes
//upload.setFileSizeMax(1024);
// Parse the request
Map<String, Object> params = new HashMap<>();
try {
List<FileItem> items = upload.parseRequest(request);
Iterator<FileItem> iterator = items.iterator();
while (iterator.hasNext()){
FileItem fileItem = iterator.next();
if(fileItem.isFormField()){
//是一个常规的form表单数据
processFormField(fileItem, params);
}else {
//上传的文件
processUploadedFile(fileItem, params, request);
}
}
//map里面有哪些数据?
System.out.println(params);
// BeanUtils.populate(product, params)
} catch (FileUploadException e) {
e.printStackTrace();
}
return params;
}
private static void processUploadedFile(FileItem fileItem, Map<String, Object> params, HttpServletRequest request) {
String fieldName = fileItem.getFieldName();
String fileName = fileItem.getName();
String s = UUID.randomUUID().toString();
fileName = s + "-" + fileName;
System.out.println("file:" + fieldName);
System.out.println("file:" + fileName);
//取hashcode
int hashCode = fileName.hashCode();
String hexString = Integer.toHexString(hashCode);
char[] chars = hexString.toCharArray();
String uploadPath = "upload";
for (char aChar : chars) {
uploadPath = uploadPath + "/" + aChar;
}
String relativePath = uploadPath + "/" + fileName;
String realPath = request.getServletContext().getRealPath(relativePath);
// http://localhost/app/upload/1.jpg
File file = new File(realPath);
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
try {
fileItem.write(file);
params.put(fieldName, relativePath);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 普通的form表单数据,name属性以及对应的值
* @param fileItem
* @param params
*/
private static void processFormField(FileItem fileItem, Map<String, Object> params) {
String fieldName = fileItem.getFieldName();
String value = null;
//反射吗?
try {
value = fileItem.getString("utf-8");
params.put(fieldName, value);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
System.out.println(fieldName + ":" + value);
}
}
UploadServlet1.java
package com.cskaoyan.fileupload;
import com.cskaoyan.fileupload.bean.User;
import com.cskaoyan.fileupload.utils.FileUploadUtils;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.ServletContext;
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.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@WebServlet("/upload1")
public class UploadServlet1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
//判断当前请求内是否有multipart/form-data数据
//request.setCharacterEncoding("utf-8"); 不再适用
Map<String, Object> params = FileUploadUtils.parseRequest(request);
//BeanUtils
System.out.println(params);
User user = new User();
try {
BeanUtils.populate(user, params);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
System.out.println(user);
//JDBC
//定时跳转 context---session
getServletContext().setAttribute("user", user);
response.getWriter().println("注册成功,回显信息");
response.setHeader("refresh","2;url=" + request.getContextPath() + "/view");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
ViewServlet.java
package com.cskaoyan.fileupload;
import com.cskaoyan.fileupload.bean.User;
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("/view")
public class ViewServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
User user = (User) getServletContext().getAttribute("user");
response.getWriter().println("<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>Title</title>\n" +
"</head>\n" +
"<body>");
response.getWriter().println("<div>" + user.getUsername() + "</div>");
response.getWriter().println("<img src='" +request.getContextPath() + "/" + user.getImage() + "'>");
response.getWriter().println("</body>\n" +
"</html>");
}
}
upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/upload/upload1" enctype="multipart/form-data" method="post">
<input type="text" name="username"><br>
<input type="file" name="image"><br>
<input type="submit">
</form>
</body>
</html>
1.5文件上传重名问题
解决方案很多,只提供一种参考。
比如说可以加随机字符、可以加时间戳、可以加年月日时间段
1.6.同一目录下文件数过多的问题
比如电脑性能不是很好,然后硬盘某个目录下有非常多文件,打开的时候会卡,会转圈。
100万张图片,加载某一个图片。
分散文件夹。比如根据年月日-----不均匀。
去年国庆加国旗。自己更换头像成功以后,自己看到了变化,但是别人没看到。几个小时以后才同步更新过去。原因是什么呢?
头像尽可能均匀分散。散列Hashcode。
根据文件名–进行散列 散列
Sakjdlasdjkasd.jpg----->hashcode----->0x 1 2 3 7 a b c d 文件放进去
1.7案例
用户注册,然后将信息进行回显在浏览器窗口,图片需要显示出来。
Upload.html--------->servlet(fileupload form表单数据和上传的文件路径,封装到bean中)-------->JDBC保存到数据库(保存到某个域中),跳转到某个页面显示出刚刚的信息。