不知不觉,感觉我已经开始走向全栈的道路了,这两天学到了在后端接收前端传递过来的文件数据,由于水平太菜,我准备先使用servlet接收数据。
这篇博客由浅入深记录了我如何实现获取上传的文件、在html协议内容来看如何获取文件、我读Apache Commons FileUpload源码的一点理解。
<form action="../form_ajax" method="post" enctype="multipart/form-data">
用户名:<input type="text" name="username"/><br/>
选择要上传的文件<br/>
请选择文件:<input type="file" name="myfile"/><br/>
<input type="submit" value="submit"/><br/>
form>
@MultipartConfig
public class FileUpload1Servlet extends HttpServlet {
private static Logger LOGGER = Logger.getLogger(FileUpload1Servlet.class);
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//文件上传
//首先要在Servlet上用 @MultipartConfig 标识支持文件上传
//获取part对象 参数为name属性的值
Part part = req.getPart("myfile");
//Servlet3没有提供直接获取文件名的方法,需要从请求头中解析出来
//获取文件名
String fileName = part.getSubmittedFileName();
//获取数据的流
InputStream inputStream = part.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
StringBuffer sb = new StringBuffer();
String line = br.readLine();
while(line != null){
sb.append("\n").append(line);
line = br.readLine();
}
LOGGER.info("content:"+sb.toString());
PrintWriter printWriter = resp.getWriter();
printWriter.print("皮皮虾,我们走。");
printWriter.flush();
printWriter.close();
}
}
含有 enctype=”multipart/form-data” 属性的表单提交上来的数据,用ServletRequest.getParameter 方法是获取不到参数的。要按照下面的步骤获取参数:
缺点:
首先添加Apache Commons FileUpload依赖。
public class FileUpload2Servlet extends HttpServlet {
private static Logger LOGGER = Logger.getLogger(FileUpload2Servlet.class);
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// Configure a repository (to ensure a secure temp location is used)
ServletContext servletContext = this.getServletConfig().getServletContext();
File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
factory.setRepository(repository);
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);
try {
// Parse the request
List items = upload.parseRequest(req);
// Process the uploaded items
Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = iter.next();
if (item.isFormField()) {
processFormField(item);
} else {
processUploadedFile(item);
}
}
} catch (Exception e) {
e.printStackTrace();
}
PrintWriter printWriter = resp.getWriter();
printWriter.print("皮皮虾,我们走。");
printWriter.flush();
printWriter.close();
}
private void processFormField(FileItem item) {
}
private void processUploadedFile(FileItem item) {
}
}
如上面代码,获取到的FileItem就是对应的表单里的input,通过FileItem可以获取流或者值等,比原生的servlet api要方便。
FileItem.getString是获取表单传递过来的属性值的方法,该方法默认是用 ISO-8859-1 解码的。该方法有一个重载的方法 String getString(String encoding) throws UnsupportedEncodingException; 来指定解码字符集。
如果form表单里没有添加enctype=”multipart/form-data”(或者multipart/mixed等相似的)属性,我们就使用 ServletRequest.getParameter 来获取参数,不能使用上面的介绍的两种方式处理,否则会报错。
如果form表单里添加了enctype=”multipart/form-data”(或者multipart/mixed等相似的)属性,就需要使用上述两种方法或类似的方法处理请求参数,因为 ServletRequest.getParameter 方法无法获取到值。
因此,对于form表单里是否添加了enctype=”multipart/form-data”(或者multipart/mixed等相似的)属性,会有不同的处理。当然,这本来就是已知的,因为那form表单都是我们自己写的。我们也可以从传递过来的http请求头里判断出来,下面的博客中就会提现出来再http请求发送的数据里到底是如何不同的。Apache Commons FileUpload库给我们提供了简单的方法判断,如:
boolean isMultipart = ServletFileUpload.isMultipartContent(req);
socket实现简单web服务器,可查看http请求信息 这是我以前写的一篇博客,通过它可以直观的观察到http请求发送的内容。
enctype=”multipart/form-data”:这个属性影响的是当post数据的时候,是以一种什么样的形式来编码数据。该属性默认值是application/x-www-form-urlencoded。我们只讨论post,enctype为这两个值是的情况。
POST / HTTP/1.1
Host: 127.0.0.1:8000
Connection: keep-alive
Content-Length: 44
Cache-Control: max-age=0
Origin: http://localhost:8080
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Referer: http://localhost:8080/jquery/jquery_easy_ui_demo/index2.html?
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6
Cookie: _ga=GA1.1.2113425928.1460981708
username=%E5%BC%A0%E4%B8%89&myfile=test1.sql
POST / HTTP/1.1
Host: 127.0.0.1:8000
Connection: keep-alive
Content-Length: 1043
Cache-Control: max-age=0
Origin: http://localhost:8080
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary2vmXA3pgPdCoiZjv
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Referer: http://localhost:8080/jquery/jquery_easy_ui_demo/index2.html?
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6
Cookie: _ga=GA1.1.2113425928.1460981708
------WebKitFormBoundary2vmXA3pgPdCoiZjv
Content-Disposition: form-data; name="username"
张三
------WebKitFormBoundary2vmXA3pgPdCoiZjv
Content-Disposition: form-data; name="myfile"; filename="test1.sql"
Content-Type: application/octet-stream
/*
Navicat MySQL Data Transfer
Source Server : localhost
Source Server Version : 50716
Source Host : localhost
Source Database : test1
Target Server Version : 50716
File Encoding : utf-8
Date: 11/18/2016 00:54:30 AM
*/
SET NAMES utf8;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for `obj1`
-- ----------------------------
DROP TABLE IF EXISTS `obj1`;
CREATE TABLE `obj1` (
`name` varchar(20) NOT NULL,
`id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of `obj1`
-- ----------------------------
BEGIN;
INSERT INTO `obj1` VALUES ('张三', '1');
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
------WebKitFormBoundary2vmXA3pgPdCoiZjv--
在这里我们只需要注意两个地方:请求头里的Content-Type属性和请求体。
当get请求或post且enctype=”application/x-www-form-urlencoded”时,直接使用ServletRequest.getParameter方法就能得到参数,这里就不讨论了。
当post且enctype=”multipart/form-data”时,数据就在请求体里,我们也知道请求体的格式了,就是按照这个格式把需要的数据解析出来。首先得到请求体力的内容,我们知道ServletRequest.getInputStream方法,该方法返回的输入流包含整个请求体力的内容。
对于真正解析上述的post请求体数据,还是比较复杂的一件事情,本着负责任(懒)的态度,我就没有自己动手写,下面内容是我阅读Apache Commons FileUpload源码的一点理解。
代码有点多,就不贴了,写点我的理解。
➜ jquery pwd
/Users/mabinbin/Library/Caches/IntelliJIdea2016.1/tomcat/Unnamed_blog_backend/work/Catalina/localhost/jquery
➜ jquery ls -lh
total 249792
-rw-r--r-- 1 mabinbin staff 122M 4 26 14:18 upload_08e39bf7_614a_4684_aee1_6d44138ff8f4_00000001.tmp
HTML