关于上传文件,首先我的第一个案例是一个文本文件的上传,简单容易上手!
首先我们上传文件肯定就属于实体内容部分了;所以不能过GET方式请求了,要通过POST方式请求;
因为:
1.get方式是URL传值,URL长度是有限的,很短,并且实体内容只能通过POST传递;因为只有POST方式才有content-type属性。
2.因为是实体内容,所以不能通过getParameter这么草率没脑子的步骤去得到上传文件的内容了,要通过获得request的InputStream来得到实体内容:(插播一个,在序列化的时候之后,网络传输对象我之前没有思路,这里看来也应该通过流的方式)。
其次:
1.我们要注意的是上传也是一个input标签,表单上传,但是type就是填写file(当我们点击这个file类型的input的时候,就会自动弹出选择文件的窗口)。
2.我们还要注意,form中其实是可以设置加密的类型格式:entype;
默认是这么一个玩意儿:entype="application/x-www-form-urlencoded"
但是这样的话只会以键值对的方式传上文件的名字,在浏览器的开发者模式下就可以查看到,很尴尬!
所以我们要把entype修改为:multipart/form-data;
修改之后,就可以看到长度变长了:并且可用看到实际传入了值;
长度变长了:
content-type有了实际的值:
实际查看也可以看到POST请求带到服务器的内容:
首先贴jsp中的显示层的代码:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>文件上传</title>
</head>
<body>
<%--
在浏览器的开发模式下查看:
使用get方式的时候
实体部分没有内容
使用post方式的时候
实体部分有了内容
文件属于实体内容,
不能通过URL进行传递,只能通过POST
所以不能用GET方式请求
发现我点击上传之后,上传的不是内容
而是name和value的键值对:attachment=java8混合模式.txt 【诸如此类的】
原因就是form中的enctype影响的!
enctype="application/x-www-form-urlencoded"
要修改编码类型:
multipart/form-data
从键值对变成了:
multipart/form-data; boundary=----WebKitFormBoundary9qkZBbwklcwsP0yC
--%>
<%-- <form action="01.upload.jsp" method="POST" enctype="application/x-www-form-urlencoded"> --%>
<%-- <form method="POST" enctype="multipart/form-data"> --%>
<form action="${pageContext.servletContext.contextPath }/servlet/UpLoadDemo01" method="POST" enctype="multipart/form-data">
请选择要上传的文件:<input type="file" name="attachment" />
<input type="submit" value="上传文件"/>
</form>
</body>
</html>
servlet中处理的逻辑代码:
package upload;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 模拟服务器处理上传过来的文件(手动解析文件的内容)
* @author mzy
*
*/
public class UpLoadDemo01 extends HttpServlet {
private static final long serialVersionUID = -6589048171165363182L;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1) 获取实体 内容
InputStream in = request.getInputStream();
// 包装成BufferdReader来简化操作!
BufferedReader br = new BufferedReader(new InputStreamReader(in));
// 读取一行
/*
* 回忆:
* 在POST中的实体内容中查看;
* 我们发现,其中的实体内容中在文件内容的
* 开始和结束的时候,都有一段分割符
* 在火狐中开发模式下抓到的实体内容如下:
* -----------------------------41184676334
* Content-Disposition: form-data; name="attachment"; filename="mzy_test_attach.txt"
* Content-Type: text/plain
*
* aaa
* bbb
* ccc
*
* hello world!!!
* -----------------------------41184676334--
*/
// 读第一行:文件开始的分隔符:将开始分隔符保存起来
// 为什么呢?
// 因为我们可以从上面的实体内容中看到:
// 结束符号就比开始符号最后多两根横杠(我们就可以定位到结束位置)
String fileTag = br.readLine();
// 读第二行:第二行就是文件的名称了
String str = br.readLine();
// 获取文件的名称:
// 在下觉得这个获取文件名称很精彩!
// System.out.println(str);
String fileName = str.substring(str.indexOf("filename="")+10, str.length()-1);
/*
* 但是上面的fileName:
* 最终截取出来的名字要注意;
* 在火狐或者chrome内核中,只有文件名!
* 但是在IE中包含着文件在客户端上的物理路径信息;
* 所以如果是IE的话还要再次截取!
*/
if(fileName.contains("\")) {
// System.out.println(fileName);
fileName = fileName.substring(fileName.lastIndexOf("\")+1, fileName.length());
}
// 之后需要跳过两行无用行:
// 1.第一行是读取的格式的声明Content-Type;
// 2.第二行是正文开始之前的空行(默认会加一个空行)
br.readLine();
br.readLine();
// 正式开始读取文件的正文内容
String content = null;
// new 一个writer将用户上传的文件写入到我的服务器的盘符上
BufferedWriter bw = new BufferedWriter(new FileWriter("e:/"+fileName));
while((content=br.readLine()) != null) {
// 写出到服务器上:遇到结束符号结束
if(content.equals(fileTag+"--")) {
break;
// continue; 都可以
}
bw.write(content);
bw.newLine(); // 换行
bw.flush();
}
bw.close();
br.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
/*
* 我今天傻逼了在doPost中调用doPost,恩?恩?恩?是个傻子。
* doPost(request, response);
*/
doGet(request, response);
}
}