com.logicbus.backend.message.MultiPartForm Maven / Gradle / Ivy
package com.logicbus.backend.message;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
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.io.FileCleaningTracker;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.anysoft.util.IOTools;
import com.anysoft.util.JsonTools;
import com.anysoft.util.Settings;
import com.jayway.jsonpath.spi.JsonProvider;
import com.jayway.jsonpath.spi.JsonProviderFactory;
import com.logicbus.backend.Context;
import com.logicbus.backend.ServantException;
import com.logicbus.backend.server.http.HttpContext;
/**
* MultiPartForm
*
* 处理multipart/form-data类型的输入数据,主要用于处理Http上传文件。
*
* @author duanyy
* @since 1.6.3.31
*
* @version 1.6.4.30 [20160126 duanyy]
* - 文件上传消息处理透传Context对象
*
* @version 1.6.5.6 [20160523 duanyy]
* - 淘汰MessageDoc,采用Context替代
* - 增加getContentType和getContentLength
*
* @version 1.6.7.9 [20170201 duanyy]
* - 采用SLF4j日志框架输出日志
*/
public class MultiPartForm implements Message {
/**
* a logger of log4j
*/
protected static final Logger logger = LoggerFactory.getLogger(MultiPartForm.class);
protected static JsonProvider provider = null;
static {
provider = JsonProviderFactory.createProvider();
}
protected static FileItemFactory factory = null;
protected static final String ID = "uploadItemFactory";
/**
* 文件列表
*/
protected List fileItems = null;
/**
* Json结构的根节点
*/
protected Map root = null;
private long contentLength = 0;
/**
* 获取FileItemFactory
* @return FileItemFactory
*/
public static FileItemFactory getFileItemFactory(){
if (factory == null){
synchronized (MultiPartForm.class){
if (factory == null){
Settings settings = Settings.get();
factory = (FileItemFactory)settings.get(ID);
if (factory == null){
factory = new DiskFileItemFactory();
}
}
}
}
return factory;
}
/**
* 获取JSON结构的根节点
*
* @return JSON结构的根节点
*/
public Map getRoot(){
return root;
}
/**
* 获取文件列表
* @return 文件列表
*/
public List getFileItems(){
return fileItems;
}
@Override
public String getContentType() {
return "application/json;charset=utf-8";
}
@Override
public long getContentLength() {
return contentLength;
}
@Override
public void init(Context ctx) {
if (!(ctx instanceof HttpContext)){
throw new ServantException("core.e1001",
"The context's class must be HttpContext when using UploadFiles");
}
HttpContext httpCtx = (HttpContext)ctx;
ServletFileUpload fileUpload = new ServletFileUpload(getFileItemFactory());
try {
fileItems = fileUpload.parseRequest(httpCtx.getRequest());
} catch (FileUploadException e) {
logger.error(ExceptionUtils.getStackTrace(e));
throw new ServantException("core.e1015",e.getMessage());
}
root = new HashMap(); // NOSONAR
}
@Override
public void finish(Context ctx, boolean closeStream) {
Map theRoot = getRoot();
JsonTools.setString(theRoot, "code", ctx.getReturnCode());
JsonTools.setString(theRoot, "reason", ctx.getReason());
JsonTools.setString(theRoot, "duration", String.valueOf(ctx.getDuration()));
JsonTools.setString(theRoot, "host", ctx.getHost());
JsonTools.setString(theRoot, "serial", ctx.getGlobalSerial());
OutputStream out = null;
try {
String data = provider.toJson(theRoot);
String jsonp = ctx.GetValue("jsonp", "");
if (jsonp != null && jsonp.length() > 0){
data = jsonp + "(" + data + ")";
}
out = ctx.getOutputStream();
ctx.setResponseContentType(getContentType());
byte[] bytes = data.getBytes();
contentLength += bytes.length;
Context.writeToOutpuStream(out, bytes);
out.flush();
}catch (Exception ex){
logger.error(ExceptionUtils.getStackTrace(ex));
}finally{
if (closeStream)
IOTools.close(out);
}
}
/**
* 处理已上传的文件
* @param ctx 上下文
* @param cookies 处理的cookies
* @param handler 处理器
*/
public void handle(Context ctx,Object cookies,FileItemHandler handler){
if (fileItems != null && !fileItems.isEmpty()){
Map result = new HashMap(); // NOSONAR
for (FileItem item:fileItems){
if (item != null && !item.isFormField()){
contentLength += item.getSize();
Map fileResult = new HashMap(); // NOSONAR
fileResult.put("field", item.getFieldName());
fileResult.put("name", item.getName());
fileResult.put("size",item.getSize());
handler.handle(ctx,cookies,item, fileResult);
result.put(item.getFieldName(), fileResult);
}
}
getRoot().put("files", result);
}
}
/**
* FileItem处理器
*
* @author duanyy
*
*/
public static interface FileItemHandler {
/**
* 处理文件
* @param ctx 上下文
* @param cookies 处理的cookies
* @param item FileItem
* @param result 用于输出文件的处理状态
*/
public void handle(Context ctx,Object cookies,FileItem item,Map result);
}
/**
* Upload临时文件自动删除
*
* @author duanyy
*
*/
public static class Cleaner implements ServletContextListener{
@Override
public void contextDestroyed(ServletContextEvent sce) {
Settings settings = Settings.get();
DiskFileItemFactory f = (DiskFileItemFactory)settings.get(ID);
FileCleaningTracker tracker = f.getFileCleaningTracker();
if (tracker != null){
logger.info("The uploaded temp files will be deleted.");
tracker.exitWhenFinished();
}
}
@Override
public void contextInitialized(ServletContextEvent sce) {
Settings settings = Settings.get();
logger.info("Files uploading will be supported.");
DiskFileItemFactory f = new DiskFileItemFactory();
f.setFileCleaningTracker(new FileCleaningTracker());
settings.registerObject(ID, f);
}
}
}