如果你的代码使用的是标准MVC开发的,那么强烈建议使用SmartUpload完成,但是如果你的项目代码使用的是框架开发,例如:Struts 1.x、Struts 2.x、Spring MVC,那么就只能够使用FileUpload,因为这些框架针对于FileUpload的处理是比较方便的。
1 基础上传
如果现在使用的是Struts 1.x,那么要接收上传文件的时候使用的是一个FormFile类,但是这个类虽然包装了许多的内容,不过从实际来讲,有些多余,所以在Struts 2.x中的上传接收直接利用java.io.File类完成,这样的操作会比较直观一些。
范例:定义上传表单
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<html>
<head>
<base href="<%=basePath%>">
<title>Upload</title>
</head>
<body>
<form action="UploadAction!insert.action" method="post" enctype="multipart/form-data">
Name: <input type="text" name="name"><br>
Photo: <input type="file" name="photo"><br>
<input type="submit" value="submit">
</form>
</body>
</html>
随后定义UploadAction,但是为了可以接收上传文件,使用File定义一个photo属性。
范例:定义UploadAction
package org.lks.action;
import java.io.File;
import com.opensymphony.xwork2.ActionSupport;
@SuppressWarnings("serial")
public class UploadAction extends ActionSupport {
private String name;
private File photo;
public void setName(String name) {
this.name = name;
}
public void setPhoto(File photo) {
this.photo = photo;
}
public void insert(){
System.out.println("Name:" + this.name + ", Photo:" + this.photo + ", Photo Size:" + this.photo.length());
}
}
范例:在struts.xml配置Action
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<package name="UploadAction" namespace="/" extends="struts-default">
<action name="UploadAction" class="org.lks.action.UploadAction">
</action>
</package>
</struts>
随后运行项目代码。
六月 27, 2020 5:32:35 下午 com.opensymphony.xwork2.util.logging.commons.CommonsLogger info
信息: Unable to find 'struts.multipart.saveDir' property setting. Defaulting to javax.servlet.context.tempdir
Name:lks,
Photo:D:\Program Files\Tomcat\apache-tomcat-9.0.13\work\Catalina\localhost\StrutsUpload\upload__5785603a_172f51f1af4__8000_00000001.tmp,
Photo Size:13301
六月 27, 2020 5:32:36 下午 com.opensymphony.xwork2.util.logging.commons.CommonsLogger info
信息: Removing file photo D:\Program Files\Tomcat\apache-tomcat-9.0.13\work\Catalina\localhost\StrutsUpload\upload__5785603a_172f51f1af4__8000_00000001.tmp
此时发现可以成功上传了,但是里面却出现有警告信息。因为在Struts 2.x中实现的信息上传流程如下:首先会将上传的文件保存在一个临时文件夹中,而后在Action里面所读取的文件内容实际上就是这个临时文件夹中的信息内容,但是严格来讲你应该自己定义一个这样的临时文件夹信息。
范例:在struts.properties文件中定义临时保存目录
struts.multipart.saveDir=tempdir
此时文件已经可以正常的上传了。
2 上传的进一步操作
虽然此时可以由Action接收上传文件,那么并且也可以取得文件内容了,但是依然无法进行保存,因为不知道上传的文件是什么东西,在使用Struts 2.x上传的时候是将上传的内容先临时保存到了一个存储目录中,这个目录中所保存的文件是一个随意自动生成的名称。
Name:lks,
Photo:D:\Program Files\Tomcat\apache-tomcat-9.0.13\work\Catalina\localhost\StrutsUpload\upload__5785603a_172f51f1af4__8000_00000001.tmp,
Photo Size:13301
六月 27, 2020 5:32:36 下午 com.opensymphony.xwork2.util.logging.commons.CommonsLogger info
信息: Removing file photo D:\Program Files\Tomcat\apache-tomcat-9.0.13\work\Catalina\localhost\StrutsUpload\upload__5785603a_172f51f1af4__8000_00000001.tmp
这个时候你无法知道你上传的文件类型以及文件的原始名称。
如果要想得到文件的原始名称以及文件类型,必须定义两个属性,如果说现在接收上传文件的属性名称为photot,则需要定义两个属性才可以接收:
(1)文件名称:photoFileName;
(2)文件类型:photoContentType。
范例:接收文件名称以及文件类型。
package org.lks.action;
import java.io.File;
import com.opensymphony.xwork2.ActionSupport;
@SuppressWarnings("serial")
public class UploadAction extends ActionSupport {
private String name;
private File photo;
private String photoFileName;
private String photoContentType;
public void setPhotoFileName(String photoFileName) {
this.photoFileName = photoFileName;
}
public void setPhotoContentType(String photoContentType) {
this.photoContentType = photoContentType;
}
public void setName(String name) {
this.name = name;
}
public void setPhoto(File photo) {
this.photo = photo;
}
public void insert(){
System.out.println("Name:" + this.name + ", Photo:" + this.photo + ", Photo Size:" + this.photo.length());
System.out.println("Photo Name: " + this.photoFileName);
System.out.println("File type: " + this.photoContentType);
}
}
既然文件的原始信息已经可以找到,那么对用户而言就可以进行文件的存储操作了,但是如果要进行文件的保存,一定需要设置一个保存的目录,同时也需要进行文件的名称生成,考虑到所有的问题,下面可以单独定义一个类,这个类专门负责文件的保存。
范例:实现文件保存的工具类
package org.lks.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
public class UploadFileUtil{
private File uploadFile; //保存上传文件的内容
private String contentType; //保存上传文件的类型
private String fileName; //生成文件名称
/**
* 构造进行操作的文件内容以及文件类型
* @param uploadFile 包含了上传文件的信息
* @param contentType 上传文件的类型
*/
public UploadFileUtil(File uploadFile, String contentType) {
this.uploadFile = uploadFile;
this.contentType = contentType;
}
/**
* 取得文件名称,根据uuid生成
* @return 返回一个不会重复的文件名称
*/
public String getFileName(){ //取得文件的名称
if(this.fileName ==null || "".equals(this.fileName)){
String fileExt = null; //保存文件的扩展类型
if("image/bmp".equalsIgnoreCase(this.contentType)){
fileExt = "bmp";
}else if("image/gif".equalsIgnoreCase(this.contentType)){
fileExt = "gif";
}else if("image/jpeg".equalsIgnoreCase(this.contentType)){
fileExt = "jpg";
}else if("image/png".equalsIgnoreCase(this.contentType)){
fileExt = "png";
}
this.fileName = UUID.randomUUID() + "." + fileExt;
}
return this.fileName;
}
public boolean saveFile(String outFilePath) throws IOException{ //文件的保存操作
File file = new File(outFilePath);
OutputStream output = null;
InputStream input = null;
try{
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
output = new FileOutputStream(file);
input = new FileInputStream(this.uploadFile);
byte data[] = new byte[2048];
int len = 0;
while((len = input.read(data, 0, len)) != -1){
output.write(data,0, len);
}
return true;
}catch(Exception e){
throw e;
}finally{
if(output != null){
output.close();
}
if(input != null){
input.close();
}
}
}
public boolean deleteFile(String filePath){
return new File(filePath).delete();
}
}
随后在Action里面调用此类的方法进行文件保存。
范例:在Action中保存信息
public void insert(){
UploadFileUtil ufu = new UploadFileUtil(this.photo, this.photoContentType);
String fileName = ufu.getFileName();
System.out.println(fileName);
String outFilePath = ServletActionContext.getServletContext().getRealPath("/upload/") + fileName;
try {
System.out.println(ufu.saveFile(outFilePath));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
对于任何的开发代码,如果发现重复编写了,必须要进行很好的类功能设计。
3 上传限制
现在虽然可以进行文件的上传了,但是上传是有一些限制的,也就是说它本身是有一些文件大小的限制。
1、改变上传文件的大小限制——修改struts.properties文件
(1)以下为默认的上传文件的最大额限制
struts.multipart.maxSize=2097152
但是一般图片别弄得太大,除非你是那种专业的图片网站。但是如果文件一大,那么肯定要进行错误的显示,那么也就是说应该继续配置一个input的路径,修改struts.xml文件。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<package name="UploadAction" namespace="/" extends="struts-default">
<action name="UploadAction" class="org.lks.action.UploadAction">
<result name="input">upload.jsp</result>
</action>
</package>
</struts>
2、这个时候如果文件太大,那么struts 2.x就默认出现了错误操作,但是虽然大的方向上不能够进行错误处理,但是可以在每一个Action中进行错误的配置;
范例:修改struts.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<package name="UploadAction" namespace="/" extends="struts-default">
<action name="UploadAction" class="org.lks.action.UploadAction">
<interceptor-ref name="fileUpload">
<param name="maximumSize">10000</param>
<param name="allowedTypes">
image/gif,image/jpg,image/jpeg,image/png,image/bmp
</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
<result name="input">upload.jsp</result>
</action>
</package>
</struts>
所有的错误依然保存在了fieldErrors集合里面。
<h1>${fieldErros['photo'][0] }</h1>
但是此时输出的错误的默认信息是英文,不是中文。可以在全局资源文件中定义显示的文字。
范例:在Messages.properties里面定义文字信息
Struts 2.x的文件上传的确考虑了不少的情况。