[java]代码库
package com.normandy.position.web;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* 上传图片
* <p>
* 为CKEDITOR定制的图片上传功能,后续可以扩展上传其他格式的文件
* 上传的文件的基础路径为: ${apache.home}/${project.name}/${project.name}/freemarker/upload/img/${'yyyyMMdd'}/
* 每个文件夹下最多500个文件
* </p>
* @author mikko
*
*/
@Controller
@RequestMapping ("/upload.do")
public class FileUploadController {
protected final Logger logger = Logger
.getLogger (FileUploadController.class);
/** ~~~ 上传文件的保存路径 */
private static final String FILE_UPLOAD_DIR = "/upload";
/** ~~~ 上传文件的保存的下一级路径,标示存储类型 */
private static final String FILE_UPLOAD_SUB_IMG_DIR = "/img";
/** ~~~ 为了能让CKEDITOR加载到上传的图片,此处将位置限制在了freemarker下*/
private static final String FOR_FREEMARKER_LOAD_DIR = "/freemarker";
/** ~~~ 每个上传子目录保存的文件的最大数目 */
private static final int MAX_NUM_PER_UPLOAD_SUB_DIR = 500;
/** ~~~ 上传文件的最大文件大小 */
private static final long MAX_FILE_SIZE = 1024 * 1024 * 2;
/** ~~~ 系统默认建立和使用的以时间字符串作为文件名称的时间格式*/
private static final String DEFAULT_SUB_FOLDER_FORMAT_AUTO = "yyyyMMdd";
/** ~~~ 这里扩充一下格式,防止手动建立的不统一*/
private static final String DEFAULT_SUB_FOLDER_FORMAT_NO_AUTO = "yyyy-MM-dd";
@RequestMapping (method = RequestMethod.GET)
public void processUpload (ModelMap modelMap, HttpServletRequest request,
HttpServletResponse response) {
processUploadPost (modelMap, request, response);
return;
}
@RequestMapping (method = RequestMethod.POST)
public void processUploadPost (ModelMap modelMap,
HttpServletRequest request, HttpServletResponse response) {
// 判断提交的请求是否包含文件
boolean isMultipart = ServletFileUpload.isMultipartContent (request);
if (!isMultipart) {
return;
}
// 获取目录
File floder = buildFolder (request);
if (null == floder) {
return;
}
try {
response.setContentType ("text/html; charset=UTF-8");
response.setHeader ("Cache-Control", "no-cache");
PrintWriter out = response.getWriter();
// 上传文件的返回地址
String fileUrl = "";
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload servletFileUpload = new ServletFileUpload (factory);
servletFileUpload.setFileSizeMax (MAX_FILE_SIZE);
@SuppressWarnings ("unchecked")
List<FileItem> fileitem = servletFileUpload.parseRequest (request);
if (null == fileitem || 0 == fileitem.size() ) {
return;
}
Iterator<FileItem> fileitemIndex = fileitem.iterator();
if (fileitemIndex.hasNext() ) {
FileItem file = fileitemIndex.next();
if (file.isFormField() ) {
logger.error ("上传文件非法!isFormField=true");
}
String fileClientName = getFileName (file.getName() );
String fileFix = StringUtils.substring (fileClientName,
fileClientName.lastIndexOf (".") + 1);
if (!StringUtils.equalsIgnoreCase (fileFix, "jpg")
&& !StringUtils.equalsIgnoreCase (fileFix, "jpeg")
&& !StringUtils.equalsIgnoreCase (fileFix, "bmp")
&& !StringUtils.equalsIgnoreCase (fileFix, "gif")
&& !StringUtils.equalsIgnoreCase (fileFix, "png") ) {
logger.error ("上传文件的格式错误=" + fileFix);
return;
}
if (logger.isInfoEnabled() ) {
logger.info ("开始上传文件:" + file.getName() );
}
// 为了客户端已经设置好了图片名称在服务器继续能够明确识别,这里不改名称
File newfile = new File (floder, fileClientName);
file.write (newfile);
if (logger.isInfoEnabled() ) {
logger.info ("上传文件结束,新名称:" + fileClientName + ".floder:"
+ newfile.getPath() );
}
// 组装返回url,以便于ckeditor定位图片
fileUrl = FOR_FREEMARKER_LOAD_DIR + FILE_UPLOAD_DIR + FILE_UPLOAD_SUB_IMG_DIR + File.separator + floder.getName() + File.separator + newfile.getName();
fileUrl = fileUrl.substring (1); // 去掉/freemarker的第一个/,否则ckeditor不识别
fileUrl = StringUtils.replace (fileUrl, "//", "/");
// 将上传的图片的url返回给ckeditor
String callback = request.getParameter ("CKEditorFuncNum");
out.println ("<mce:script type=/"text / javascript / "><!--
");
out.println ("window.parent.CKEDITOR.tools.callFunction("
+ callback + ",'" + fileUrl + "',''" + ")");
out.println ("
// --></mce:script>");
}
out.flush();
out.close();
} catch (IOException e) {
logger.error ("上传文件发生异常!", e);
} catch (FileUploadException e) {
logger.error ("上传文件发生异常!", e);
} catch (Exception e) {
logger.error ("上传文件发生异常!", e);
}
return;
}
/**
* 获取文件名称
* @param str
* @return
*/
private String getFileName (String str) {
int index = str.lastIndexOf ("//");
if (-1 != index) {
return str.substring (index);
} else {
return str;
}
}
/**
* 创建目录
*
* @return
*/
private File buildFolder (HttpServletRequest request) {
// 这里照顾一下CKEDITOR,由于ftl放置位置的原因,这里必须要在freemarker目录下才能被加载到图片,否则虽然可以正常上传和使用,但是
// 在控件中无法正常操作
String realPath = request.getSession().getServletContext()
.getRealPath (FOR_FREEMARKER_LOAD_DIR);
logger.error (realPath);
// 一级目录,如果不存在,创建
File firstFolder = new File (realPath + FILE_UPLOAD_DIR);
if (!firstFolder.exists() ) {
if (!firstFolder.mkdir() ) {
return null;
}
}
// 二级目录,如果不存在,创建
String folderdir = realPath + FILE_UPLOAD_DIR + FILE_UPLOAD_SUB_IMG_DIR;
if (logger.isDebugEnabled() ) {
logger.debug ("folderdir" + folderdir);
}
if (StringUtils.isBlank (folderdir) ) {
logger.error ("路径错误:" + folderdir);
return null;
}
File floder = new File (folderdir);
if (!floder.exists() ) {
if (!floder.mkdir() ) {
logger.error ("创建文件夹出错!path=" + folderdir);
return null;
}
}
// 再往下的文件夹都是以时间字符串来命名的,所以获取最新时间的文件夹即可
String[] files = floder.list();
if (null != files && 0 < files.length) {
// 含有子文件夹,则获取最新的一个
Date oldDate = null;
int index = -1;
for (int i = 0; i < files.length; i++) {
String fileName = files[i];
try {
Date thisDate = DateUtils.parseDate (fileName, new String[] {
DEFAULT_SUB_FOLDER_FORMAT_AUTO, DEFAULT_SUB_FOLDER_FORMAT_NO_AUTO
});
if (oldDate == null) {
oldDate = thisDate;
index = i;
} else {
if (thisDate.after (oldDate) ) {
// 保存最新的时间和数组中的下标
oldDate = thisDate;
index = i;
}
}
} catch (ParseException e) {
// 这里异常吃掉,不用做什么,如果解析失败,会建立新的文件夹,防止人为的建立文件夹导致的异常。
}
}// for
// 判断当前最新的文件夹下是否已经存在了最大数目的图片
if (null != oldDate && -1 != index) {
File pointfloder = new File (folderdir + File.separator
+ files[index]);
if (!pointfloder.exists() ) {
if (!pointfloder.mkdir() ) {
logger.error ("创建文件夹出错!path=" + folderdir);
return null;
}
}
// 如果文件夹下的文件超过了最大值,那么也需要新建一个文件夹
String[] pointfloderFiles = pointfloder.list();
if (null != pointfloderFiles
&& MAX_NUM_PER_UPLOAD_SUB_DIR < pointfloderFiles.length) {
return buildNewFile (folderdir);
}
return pointfloder;
}
// 查找当前子文件夹失败,新建一个
return buildNewFile (folderdir);
} else {
// 不含有子文件夹,新建一个,通常系统首次上传会有这个情况
return buildNewFile (folderdir);
}
}
/**
* 创建一个新文件
* @param path
* @return
*/
private File buildNewFile (String path) {
// 不含有子文件夹,新建一个,通常系统首次上传会有这个情况
File newFile = buildFileBySysTime (path);
if (null == newFile) {
logger.error ("创建文件夹失败!newFile=" + newFile);
}
return newFile;
}
/**
* 根据当前的时间建立文件夹,时间格式yyyyMMdd
*
* @param path
* @return
*/
private File buildFileBySysTime (String path) {
DateFormat df = new SimpleDateFormat (DEFAULT_SUB_FOLDER_FORMAT_AUTO);
String fileName = df.format (new Date() );
File file = new File (path + File.separator + fileName);
if (!file.mkdir() ) {
return null;
}
return file;
}
}