[jsp]代码库
import com.bruce.util.BeanHelper;
import com.bruce.util.Logger;
import com.bruce.util.http.FileUploader;
import com.bruce.util.http.FileUploader.FileInfo;
import static com.bruce.util.http.FileUploader.*;
@SuppressWarnings ("unused")
public class CheckUpload extends ActionSupport
{
// 上传路径
private static final String UPLOAD_PATH = "upload";
// 可接受的文件类型
private static final String[] ACCEPT_TYPES = {"txt", "pdf", "doc", ".Jpg", "*.zip", "*.RAR"};
// 总上传文件大小限制
private static final long MAX_SIZE = 1024 * 1024 * 100;
// 单个传文件大小限制
private static final long MAX_FILE_SIZE = 1024 * 1024 * 10;
@Override
public String execute()
{
// 创建 FileUploader 对象
FileUploader fu = new FileUploader (UPLOAD_PATH, ACCEPT_TYPES, MAX_SIZE, MAX_FILE_SIZE);
// 根据实际情况设置对象属性(可选)
/*
fu.setFileNameGenerator(new FileNameGenerator()
{
@Override
public String generate(FileItem item, String suffix)
{
return String.format("%d_%d", item.hashCode(), item.get().hashCode());
}
});
fu.setServletProgressListener(new ProgressListener()
{
@Override
public void update(long pBytesRead, long pContentLength, int pItems)
{
System.out.printf("%d: length -> %d, read -> %d.\n", pItems, pContentLength, pBytesRead);
}
});
*/
// 执行上传并获取操作结果
Result result = fu.upload (getRequest(), getResponse() );
// 检查操作结果
if (result != FileUploader.Result.SUCCESS)
{
// 设置 request attribute
setRequestAttribute ("error", fu.getCause() );
// 记录日志
Logger.exception (fu.getCause(), "upload file fail", Level.ERROR, false);
return ERROR;
}
// 通过非文件表单域创建 Form Bean
Persion persion = BeanHelper.createBean (Persion.class, fu.getParamFields() );
// 图片保存路径的列表
List<String> photos = new ArrayList<String>();
/* 轮询文件表单域,填充 photos */
Set<String> keys = fu.getFileFields().keySet();
for (String key : keys)
{
FileInfo[] ffs = fu.getFileFields().get (key);
for (FileInfo ff : ffs)
{
photos.add (String.format ("(%s) %s%s%s", key, fu.getSavePath(), File.separator, ff.getSaveFile().getName() ) );
}
}
// 设置 Form Bean 的 photos 属性
persion.setPhotos (photos);
// 设置 request attribute
setRequestAttribute ("persion", persion);
return SUCCESS;
}
}
class Persion
{
private String firstName;
private String lastName;
private Date birthday;
private boolean gender;
private int workingAge;
private int[] interest;
private List<String> photos;
}
static class FileInfo
{
private String uploadFileName;
private File saveFile;
}
/** 文件上传器 */
class FileUploader
{
/** 不限制文件上传总大小的 Size Max 常量 */
public static final long NO_LIMIT_SIZE_MAX = -1;
/** 不限制文件上传单个文件大小的 File Size Max 常量 */
public static final long NO_LIMIT_FILE_SIZE_MAX = -1;
/** 默认的写文件阀值 */
public static final int DEFAULT_SIZE_THRESHOLD = DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD;
/** 默认的文件名生成器 */
public static final FileNameGenerator DEFAULT_FILE_NAME_GENERATOR = new CommonFileNameGenerator();
/** 设置上传文件的保存路径(不包含文件名)
*
* 文件路径,可能是绝对路径或相对路径<br>
* 1) 绝对路径:以根目录符开始(如:'/'、'D:\'),是服务器文件系统的路径<br>
* 2) 相对路径:不以根目录符开始,是相对于 WEB 应用程序 Context 的路径,(如:mydir 是指
* '${WEB-APP-DIR}/mydir')<br>
* 3) 规则:上传文件前会检查该路径是否存在,如果不存在则会尝试生成该路径,如果生成失败则
* 上传失败并返回 {@link Result#INVALID_SAVE_PATH}
*
*/
private String savePath;
/** 文件上传的总文件大小限制 */
private long sizeMax = NO_LIMIT_SIZE_MAX;
/** 文件上传的单个文件大小限制 */
private long fileSizeMax = NO_LIMIT_FILE_SIZE_MAX;
/** 可接受的上传文件类型集合,默认:不限制 */
private Set<String> acceptTypes = new LStrSet();
/** 非文件表单域的映射 */
private Map<String, String[]> paramFields = new HashMap<String, String[]>();
/** 文件表单域的映射 */
private Map<String, FileInfo[]> fileFields = new HashMap<String, FileInfo[]>();
/** 文件名生成器 */
private FileNameGenerator fileNameGenerator = DEFAULT_FILE_NAME_GENERATOR;
// commons file upload 相关属性
private int factorySizeThreshold = DEFAULT_SIZE_THRESHOLD;
private String factoryRepository;
private FileCleaningTracker factoryCleaningTracker;
private String servletHeaderencoding;
private ProgressListener servletProgressListener;
/** 文件上传失败的原因(文件上传失败时使用) */
private Throwable cause;
/** 执行上传
*
* @param request : {@link HttpServletRequest} 对象
* @param response : {@link HttpServletResponse} 对象
*
* @return : 成功:返回 {@link Result#SUCCESS} ,失败:返回其他结果,
* 失败原因通过 {@link FileUploader#getCause()} 获取
*
*/
@SuppressWarnings ("unchecked")
public Result upload (HttpServletRequest request, HttpServletResponse response)
{
reset();
// 获取上传目录绝对路径
String absolutePath = getAbsoluteSavePath (request);
if (absolutePath == null)
{
cause = new FileNotFoundException (String.format ("path '%s' not found or is not directory", savePath) );
return Result.INVALID_SAVE_PATH;
}
ServletFileUpload sfu = getFileUploadComponent();
List<FileItemInfo> fiis = new ArrayList<FileItemInfo>();
List<FileItem> items = null;
Result result = Result.SUCCESS;
// 获取文件名生成器
String encoding = servletHeaderencoding != null ? servletHeaderencoding : request.getCharacterEncoding();
FileNameGenerator fnGenerator = fileNameGenerator != null ? fileNameGenerator : DEFAULT_FILE_NAME_GENERATOR;
try
{
// 执行上传操作
items = (List<FileItem>) sfu.parseRequest (request);
}
catch (FileUploadException e)
{
cause = e;
if (e instanceof FileSizeLimitExceededException)
{
result = Result.FILE_SIZE_EXCEEDED;
}
else if (e instanceof SizeLimitExceededException)
{
result = Result.SIZE_EXCEEDED;
}
else if (e instanceof InvalidContentTypeException)
{
result = Result.INVALID_CONTENT_TYPE;
}
else if (e instanceof IOFileUploadException)
{
result = Result.FILE_UPLOAD_IO_EXCEPTION;
}
else
{
result = Result.OTHER_PARSE_REQUEST_EXCEPTION;
}
}
if (result == Result.SUCCESS)
{
// 解析所有表单域
result = parseFileItems (items, fnGenerator, absolutePath, encoding, fiis);
if (result == Result.SUCCESS)
// 保存文件
{
result = writeFiles (fiis);
}
}
return result;
}
// 解析所有表单域
private Result parseFileItems (List<FileItem> items, FileNameGenerator fnGenerator, String absolutePath, String encoding, List<FileItemInfo> fiis)
{
for (FileItem item : items)
{
if (item.isFormField() )
// 解析非文件表单域
{
parseFormField (item, encoding);
}
else
{
if (item.getSize() == 0)
{
continue;
}
// 解析文件表单域
Result result = parseFileField (item, absolutePath, fnGenerator, fiis);
if (result != Result.SUCCESS)
{
reset();
cause = new InvalidParameterException (String.format ("file '%s' not accepted", item.getName() ) );
return result;
}
}
}
return Result.SUCCESS;
}
// 解析文件表单域
private Result parseFileField (FileItem item, String absolutePath, FileNameGenerator fnGenerator, List<FileItemInfo> fiis)
{
String suffix = null;
String uploadFileName = item.getName();
boolean isAcceptType = acceptTypes.isEmpty();
if (!isAcceptType)
{
suffix = null;
int stuffPos = uploadFileName.lastIndexOf (".");
if (stuffPos != -1)
{
suffix = uploadFileName.substring (stuffPos, uploadFileName.length() ).toLowerCase();
isAcceptType = acceptTypes.contains (suffix);
}
}
if (!isAcceptType)
{
return Result.INVALID_FILE_TYPE;
}
// 通过文件名生成器获取文件名
String saveFileName = fnGenerator.generate (item, suffix);
if (!saveFileName.endsWith (suffix) )
{
saveFileName += suffix;
}
String fullFileName = absolutePath + File.separator + saveFileName;
File saveFile = new File (fullFileName);
FileInfo info = new FileInfo (uploadFileName, saveFile);
// 添加表单域文件信息
fiis.add (new FileItemInfo (item, saveFile) );
addFileField (item.getFieldName(), info);
return Result.SUCCESS;
}
private void parseFormField (FileItem item, String encoding)
{
String name = item.getFieldName();
String value = item.getString();
// 字符串编码转换
if (!GeneralHelper.isStrEmpty (value) && encoding != null)
{
try
{
value = new String (value.getBytes ("ISO-8859-1"), encoding);
}
catch (UnsupportedEncodingException e)
{
}
}
// 添加表单域名/值映射
addParamField (name, value);
}
/** 文件名生成器接口
*
* 每次保存一个上传文件前都需要调用该接口的 {@link FileNameGenerator#generate} 方法生成要保存的文件名
*
*/
public static interface FileNameGenerator
{
/** 文件名生成方法
*
* @param item : 上传文件对应的 {@link FileItem} 对象
* @param suffix : 上传文件的后缀名
*
*/
String generate (FileItem item, String suffix);
}
/** 默认通用文件名生成器
*
* 实现 {@link FileNameGenerator} 接口,根据序列值和时间生成唯一文件名
*
*/
public static class CommonFileNameGenerator implements FileNameGenerator
{
private static final int MAX_SERIAL = 999999;
private static final AtomicInteger atomic = new AtomicInteger();
private static int getNextInteger()
{
int value = atomic.incrementAndGet();
if (value >= MAX_SERIAL)
{
atomic.set (0);
}
return value;
}
/** 根据序列值和时间生成 'XXXXXX_YYYYYYYYYYYYY' 格式的唯一文件名 */
@Override
public String generate (FileItem item, String suffix)
{
int serial = getNextInteger();
long millsec = System.currentTimeMillis();
return String.format ("%06d_%013d", serial, millsec);
}
}
/** 上传文件信息结构体 */
public static class FileInfo
{
private String uploadFileName;
private File saveFile;
// getters and setters ...
}
private class FileItemInfo
{
FileItem item;
File file;
// getters and setters ...
}
/** 文件上传结果枚举值 */
public static enum Result
{
/** 成功 */
SUCCESS,
/** 失败:文件总大小超过限制 */
SIZE_EXCEEDED,
/** 失败:单个文件大小超过限制 */
FILE_SIZE_EXCEEDED,
/** 失败:请求表单类型不正确 */
INVALID_CONTENT_TYPE,
/** 失败:文件上传 IO 错误 */
FILE_UPLOAD_IO_EXCEPTION,
/** 失败:解析上传请求其他异常 */
OTHER_PARSE_REQUEST_EXCEPTION,
/** 失败:文件类型不正确 */
INVALID_FILE_TYPE,
/** 失败:文件写入失败 */
WRITE_FILE_FAIL,
/** 失败:文件的保存路径不正确 */
INVALID_SAVE_PATH;
}
}