一个博客系统中,图片的上传时必不可少的。
<form action="<%=URL%>/PhotoAction.action?action=upload" method="post"
enctype="multipart/form-data">
这是一个文件上传的表单的form项,enctype属性规定在发送到服务器之前应该如何对表单数据进行编码,一般默认是在发送表单前编码所有字符,默认值是”application/x-www-form-urlencoded”,我们进行文件上传时,不用编码,所以我们的设置值为”multipart/form-data”,因为对于文件上传的过程中是将文件以流的形式提交到服务器端的。
<input type="file" name="upfile">
然后input的type是file,表示上传文件,name是”upfile”。
文件上传的表单时代码是这样:
<form action="<%=URL%>/PhotoAction.action?action=upload" method="post"
enctype="multipart/form-data">
<!-- <input type="hidden" name="action" value="upload"> -->
<div>
<table>
<tr>
<td>
<input type="file" name="upfile">
</td>
</tr>
<tr>
<td>
<label for="photoInfo">图片描述:</label>
<input type="text" id="photoInfo" name="photoInfo">
</td>
</tr>
<tr>
<td>
<input type="submit" value="上传">
</td>
</tr>
</table>
</div>
</form>
表单弄好了我们就可以上传了,一般地,我们用servlet来处理文件上传。一般我们如果是直接获取上传的输入流后,再解析里面的请求参数是很麻烦的,处理不好可能会使保存的文件出现错误。
就比如下面这个例子,我们把这个表单上传的内容全部输出看看是什么样的结构:
String getAction = request.getParameter("action");
if (getAction != null && (getAction.equals("upload"))) // 上传文件
{
// 定义上传的最大文件字节数1M
int MAX_SIZE = 1024000;
String rootPath;
//输入流
DataInputStream in = null;
//文件输出流
FileOutputStream fileOut = null;
String remoteAddr = request.getRemoteAddr();
String serverName = request.getServerName();
String realPath = request.getRealPath("/");
realPath = realPath.substring(0, realPath.lastIndexOf("\\"));
// 设置保存文件的目录
rootPath = realPath + "\\upload\\telRecord\\";
// 取得客户端上传的数据类型
String contentType = request.getContentType();
if (contentType.indexOf("multipart/form-data") >= 0) {
try {
//获取request的输入流,并创建DataInputStream流
in = new DataInputStream(request.getInputStream());
//获取内容大小
int formDataLength = request.getContentLength();
if (formDataLength > MAX_SIZE) {
//大于限制则禁止上传
String url = "error.jsp";
return url;
}
// 用dateBytes保存上传的文件数据
byte dateBytes[] = new byte[formDataLength];
int byteRead = 0;
int totalRead = 0;
//读取表单所有内容
while (totalRead < formDataLength) {
byteRead = in.read(dateBytes, totalRead, formDataLength);
//读取内容,并保存在dateBytes里面
totalRead += byteRead;
}
String data = new String(dateBytes, "UTF-8");
//把表单的内容转成utf-8
System.out.println(data);
//输出内容
//后面的是如何截取表单中的文件内容,并把内容存入文件
//的操作但是我们必须是对dateBytes截取,不能是data,
//因为必须是非编码内容,如果是转成了string的data,估计
//已经对其编码了,如果我们截取data,那可能会乱码的。
//后面的步骤就省略了
String url = this.adminSelectPhoto(request, response);
return url;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
String url = "error.jsp";
return url;
我们上传的表单是这样设置的:
我们点击上传后。
这是我们输出的表单内容的最前面的一部分:
这是我们输出表单内容的最后面的一部分:
我们会发现,我们上传的表单的内容是用
这个字符串来隔开的,它把上传文件和图片描述输入框这两部分内容分割开来,而且整个表单开始也是用这个字符串。
整个表单结束是
这个字符从结束的
首先第一个是文件
文件名是123.jpg.
?PNG及其后面这些乱码就是文件内容。
然后是我们的图片描述的输入,我们输入的是123,
可以看出,我们的输入框的名字:photoInfo,内容是123。
看到这里,我们已经明白了怎么把文件内容取出来了,这整个表单内容,我们只要截取文件内容那一段,然后把它保存到文件里面就ok了,但是我们一般不宜采取string的格式来寻找文件内容,应该是按照比较原始的byte的格式来截取,转成string后来弄的话,会造成我们保存的文件出现问题。截取表单中的文件内容,并把内容存入文件的操作,我们必须是对dateBytes截取,不能是data,因为必须是非编码内容,如果是转成了string的data,估计已经对其编码了,如果我们截取data,那可能会乱码的。
所以我们一般采用apache的开源工具common-fileupload这个文件上传组件,然后common-fileupload是依赖于common-io这个包的,所以还要下载这个包。
然后这两个包放在项目的WebContent/WEB-INF/lib文件夹里面:
然后我们处理上传的代码如下:
// 获得目前登录的博主的id
HttpSession session = request.getSession();
MasterBean master = (MasterBean) session.getAttribute("masterBean");
int masterID = master.getId();
File file;
// 上传文件的最大值
int maxFileSize = 5000 * 1024;
// 内存中存储文件的最大值
int maxMemSize = 5000 * 1024;
// 为了设置文件存储路径,我们先获取该类PhotoAction.Java在web项目下的路径
URL url_photoAction = this.getClass().getResource("PhotoAction.class");
System.out.println(url_photoAction);
// 将URL类型的路径转换成String类型,方便后面利用indexOf方法对路径进行截取
String str_url_photoAction = url_photoAction.toString();
System.out.println(str_url_photoAction);
// 由于url_photoAction的路径是D:\JavaWeb\tomcat\wtpwebapps\MyBlog\WEB-INF\classes\com\MyBlog\action_implements
// 自己希望存储的路径为D:\JavaWeb\tomcat\wtpwebapps\MyBlog\images\photo
// 因此需要进行路径截取,以及配置,找到所需路径的最后一个位置的坐标
int pos = str_url_photoAction.indexOf("WEB-INF");
// 通过pos值。截取,先获得web服务器所在的根路径
String rootPath = str_url_photoAction.substring(6, pos);
// 设置自己想要存储的相对路径
String relativePath = "images/photo";
// 最后,设置文件存储路径
String filePath = rootPath + relativePath;
System.out.println(filePath);
System.out.println("action=" + request.getParameter("action"));
// 验证上传内容了类型
String contentType = request.getContentType();
if ((contentType.indexOf("multipart/form-data") >= 0)) {
// 如果上传的是"multipart/form-data",即不编码的内容,那么久处理,
// 创建一个DiskFileItemFactory工厂,
// 这个类的作用就是把文件内容临时保存到内存中
DiskFileItemFactory factory = new DiskFileItemFactory();
// 设置内存中存储文件的最大值
factory.setSizeThreshold(maxMemSize);
// 当内存中存储的数据大于 maxMemSize,那么保存到磁盘中,
// 所以这里设置用于存放临时文件的存放路径
factory.setRepository(new File("c:\\temp"));
// 创建一个新的文件上传解析器
// 把刚刚创建的factory传进去,
// 因为这个ServletFileUpload依赖于
// DiskFileItemFactory工厂
ServletFileUpload upload = new ServletFileUpload(factory);
// 设置最大上传的文件大小
upload.setSizeMax(maxFileSize);
try {
// 解析获取的文件,解析结果返回的是一个List<FileItem>集合,
// 每一个FileItem都对应一个form表单的ipnutx项。
List fileItems = upload.parseRequest(request);
// 处理上传的文件。先获取fileItems迭代器
Iterator i = fileItems.iterator();
while (i.hasNext()) {// 遍历整个迭代器
FileItem fi = (FileItem) i.next();
// 获取fileItems中的一项的内容,并强制转换为FileItem
if (!fi.isFormField()) {
// 这里是判断这个input项是不是非普通输入,即是文件输入
// 获取上传的文件名字,因为上传过程中,可能会在原文件
// 上面添加一些附加的信息,所以截掉"\\"前面的所有字符以及"\\"
String fileName = fi.getName();
// 写入文件
if (fileName.lastIndexOf("\\") >= 0) {
file = new File(filePath, fileName.substring(fileName.lastIndexOf("\\")));
} else {
file = new File(filePath, fileName.substring(fileName.lastIndexOf("\\") + 1));
} // 对文件名字进行处理
System.out.println(">>>>>>>>>>" + file);
if (!file.exists())
file.createNewFile();// 如果文件不存在,先创建文件
fi.write(file);// 将内容写入文件
// out.println("Uploaded Filename: " + filePath +
// fileName + "<br>");
// 获取页面上面的关于图片的描述信息
String photo_info = request.getParameter("photoInfo");
System.out.println("photoInfo:" + photo_info);
PhotoBean photoBean = new PhotoBean();
photoBean.setPhotoAddr("/images/photo/" + fileName);
photoBean.setPhotoSdTime(Common.changeTime(new Date()));
if (photo_info == null || photo_info.equals("")) {
// 若页面没有添加图片描述信息,则默认为文件名作为描述信息
photoBean.setPhotoInfo(fileName);
} else {
photoBean.setPhotoInfo(photo_info);
}
photoBean.setMasterID(masterID);
PhotoDao photoDao = new PhotoDao();
boolean flag = photoDao.operationPhoto("upload", photoBean);
if (flag) {
String url = this.adminSelectPhoto(request, response);
return url;
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
String url = "error.jsp";
return url;
这里面涉及到一个迭代器的使用。
List的迭代器的用法如下:
Iterator it = list.iterator();
while (it.hasNext()) {
personnelID= (String) it.next();
//这里一般要强制转换会原来的数据类型,因为这里返回的是object类型。
}
1)使用iterator()方法可使list返回一个迭代器It
2)it第一次调用next方法会返回list的第一个元素。
3)hasnext是判断是否存在下一个元素。
4)next方法获取下一个元素,并把这个迭代器移到这个元素的位置上。
这样不断循环,直到下一个没有元素,退出循环,达到遍历list的目的。