diff --git a/common/src/main/java/com/jeesite/common/ueditor/Encoder.java b/common/src/main/java/com/jeesite/common/ueditor/Encoder.java new file mode 100644 index 00000000..a444a48c --- /dev/null +++ b/common/src/main/java/com/jeesite/common/ueditor/Encoder.java @@ -0,0 +1,24 @@ +package com.jeesite.common.ueditor; + +public class Encoder { + + public static String toUnicode ( String input ) { + + StringBuilder builder = new StringBuilder(); + char[] chars = input.toCharArray(); + + for ( char ch : chars ) { + + if ( ch < 256 ) { + builder.append( ch ); + } else { + builder.append( "\\u" + Integer.toHexString( ch& 0xffff ) ); + } + + } + + return builder.toString(); + + } + +} \ No newline at end of file diff --git a/common/src/main/java/com/jeesite/common/ueditor/PathFormat.java b/common/src/main/java/com/jeesite/common/ueditor/PathFormat.java new file mode 100644 index 00000000..f13bb953 --- /dev/null +++ b/common/src/main/java/com/jeesite/common/ueditor/PathFormat.java @@ -0,0 +1,170 @@ +package com.jeesite.common.ueditor; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.StringUtils; + +import com.jeesite.common.web.http.ServletUtils; + +public class PathFormat { + + private static final String TIME = "time"; + private static final String FULL_YEAR = "yyyy"; + private static final String YEAR = "yy"; + private static final String MONTH = "mm"; + private static final String DAY = "dd"; + private static final String HOUR = "hh"; + private static final String MINUTE = "ii"; + private static final String SECOND = "ss"; + private static final String RAND = "rand"; + private static final String USERID = "userid"; // ThinkGem 添加自定义变量,获取当前用户ID + + private static Date currentDate = null; + + private static Pattern pattern = Pattern.compile( "\\{([^\\}]+)\\}", Pattern.CASE_INSENSITIVE ); + + public static String parse ( String input ) { + + Matcher matcher = pattern.matcher(input); + + PathFormat.currentDate = new Date(); + + StringBuffer sb = new StringBuffer(); + + while ( matcher.find() ) { + + matcher.appendReplacement(sb, PathFormat.getString( matcher.group( 1 ) ) ); + + } + + matcher.appendTail(sb); + + return sb.toString(); + } + + /** + * 格式化路径, 把windows路径替换成标准路径 + * @param input 待格式化的路径 + * @return 格式化后的路径 + */ + public static String format ( String input ) { + + return input.replace( "\\", "/" ); + + } + + public static String parse ( String input, String filename ) { + + Matcher matcher = pattern.matcher(input); + String matchStr = null; + + PathFormat.currentDate = new Date(); + + StringBuffer sb = new StringBuffer(); + + while ( matcher.find() ) { + + matchStr = matcher.group( 1 ); + if ( matchStr.indexOf( "filename" ) != -1 ) { + filename = filename.replace( "$", "\\$" ).replaceAll( "[\\/:*?\"<>|]", "" ); + matcher.appendReplacement(sb, filename ); + } else { + matcher.appendReplacement(sb, PathFormat.getString( matchStr ) ); + } + + } + + matcher.appendTail(sb); + + return sb.toString(); + } + + private static String getString ( String pattern ) { + + pattern = pattern.toLowerCase(); + + // time 处理 + if ( pattern.indexOf( PathFormat.TIME ) != -1 ) { + return PathFormat.getTimestamp(); + } else if ( pattern.indexOf( PathFormat.FULL_YEAR ) != -1 ) { + return PathFormat.getFullYear(); + } else if ( pattern.indexOf( PathFormat.YEAR ) != -1 ) { + return PathFormat.getYear(); + } else if ( pattern.indexOf( PathFormat.MONTH ) != -1 ) { + return PathFormat.getMonth(); + } else if ( pattern.indexOf( PathFormat.DAY ) != -1 ) { + return PathFormat.getDay(); + } else if ( pattern.indexOf( PathFormat.HOUR ) != -1 ) { + return PathFormat.getHour(); + } else if ( pattern.indexOf( PathFormat.MINUTE ) != -1 ) { + return PathFormat.getMinute(); + } else if ( pattern.indexOf( PathFormat.SECOND ) != -1 ) { + return PathFormat.getSecond(); + } else if ( pattern.indexOf( PathFormat.RAND ) != -1 ) { + return PathFormat.getRandom( pattern ); + } else if ( pattern.indexOf( PathFormat.USERID ) != -1 ) { + return PathFormat.getUserid( pattern ); + } + + return pattern; + + } + + private static String getTimestamp () { + return System.currentTimeMillis() + ""; + } + + private static String getFullYear () { + return new SimpleDateFormat( "yyyy" ).format( PathFormat.currentDate ); + } + + private static String getYear () { + return new SimpleDateFormat( "yy" ).format( PathFormat.currentDate ); + } + + private static String getMonth () { + return new SimpleDateFormat( "MM" ).format( PathFormat.currentDate ); + } + + private static String getDay () { + return new SimpleDateFormat( "dd" ).format( PathFormat.currentDate ); + } + + private static String getHour () { + return new SimpleDateFormat( "HH" ).format( PathFormat.currentDate ); + } + + private static String getMinute () { + return new SimpleDateFormat( "mm" ).format( PathFormat.currentDate ); + } + + private static String getSecond () { + return new SimpleDateFormat( "ss" ).format( PathFormat.currentDate ); + } + + private static String getRandom ( String pattern ) { + + int length = 0; + pattern = pattern.split( ":" )[ 1 ].trim(); + + length = Integer.parseInt( pattern ); + + return ( Math.random() + "" ).replace( ".", "" ).substring( 0, length ); + + } + + private static String getUserid(String pattern) { + String userId = null; + HttpServletRequest request = ServletUtils.getRequest(); + if (request != null){ + userId = (String)request.getSession().getAttribute("userCode"); + } + return StringUtils.isNotBlank(userId) ? userId : "0"; + } + +} diff --git a/common/src/main/java/com/jeesite/common/ueditor/define/ActionMap.java b/common/src/main/java/com/jeesite/common/ueditor/define/ActionMap.java new file mode 100644 index 00000000..a4b18f03 --- /dev/null +++ b/common/src/main/java/com/jeesite/common/ueditor/define/ActionMap.java @@ -0,0 +1,42 @@ +package com.jeesite.common.ueditor.define; + +import java.util.Map; +import java.util.HashMap; + +/** + * 定义请求action类型 + * @author hancong03@baidu.com + */ +@SuppressWarnings("serial") +public final class ActionMap { + + // 获取配置请求 + public static final int CONFIG = 0; + public static final int UPLOAD_IMAGE = 1; + public static final int UPLOAD_SCRAWL = 2; + public static final int UPLOAD_VIDEO = 3; + public static final int UPLOAD_FILE = 4; + public static final int CATCH_IMAGE = 5; + public static final int LIST_FILE = 6; + public static final int LIST_IMAGE = 7; + + public static final Map mapping; + + static { + mapping = new HashMap(){{ + put( "config", ActionMap.CONFIG ); + put( "uploadimage", ActionMap.UPLOAD_IMAGE ); + put( "uploadscrawl", ActionMap.UPLOAD_SCRAWL ); + put( "uploadvideo", ActionMap.UPLOAD_VIDEO ); + put( "uploadfile", ActionMap.UPLOAD_FILE ); + put( "catchimage", ActionMap.CATCH_IMAGE ); + put( "listfile", ActionMap.LIST_FILE ); + put( "listimage", ActionMap.LIST_IMAGE ); + }}; + } + + public static int getType ( String key ) { + return ActionMap.mapping.get( key ); + } + +} diff --git a/common/src/main/java/com/jeesite/common/ueditor/define/ActionState.java b/common/src/main/java/com/jeesite/common/ueditor/define/ActionState.java new file mode 100644 index 00000000..99d65b2c --- /dev/null +++ b/common/src/main/java/com/jeesite/common/ueditor/define/ActionState.java @@ -0,0 +1,5 @@ +package com.jeesite.common.ueditor.define; + +public enum ActionState { + UNKNOW_ERROR +} diff --git a/common/src/main/java/com/jeesite/common/ueditor/define/AppInfo.java b/common/src/main/java/com/jeesite/common/ueditor/define/AppInfo.java new file mode 100644 index 00000000..dd05a362 --- /dev/null +++ b/common/src/main/java/com/jeesite/common/ueditor/define/AppInfo.java @@ -0,0 +1,78 @@ +package com.jeesite.common.ueditor.define; + +import java.util.HashMap; +import java.util.Map; + +public final class AppInfo { + + public static final int SUCCESS = 0; + public static final int MAX_SIZE = 1; + public static final int PERMISSION_DENIED = 2; + public static final int FAILED_CREATE_FILE = 3; + public static final int IO_ERROR = 4; + public static final int NOT_MULTIPART_CONTENT = 5; + public static final int PARSE_REQUEST_ERROR = 6; + public static final int NOTFOUND_UPLOAD_DATA = 7; + public static final int NOT_ALLOW_FILE_TYPE = 8; + + public static final int INVALID_ACTION = 101; + public static final int CONFIG_ERROR = 102; + + public static final int PREVENT_HOST = 201; + public static final int CONNECTION_ERROR = 202; + public static final int REMOTE_FAIL = 203; + + public static final int NOT_DIRECTORY = 301; + public static final int NOT_EXIST = 302; + + public static final int ILLEGAL = 401; + + @SuppressWarnings("serial") + public static Map info = new HashMap(){{ + + put( AppInfo.SUCCESS, "SUCCESS" ); + + // 无效的Action + put( AppInfo.INVALID_ACTION, "\u65E0\u6548\u7684Action" ); + // 配置文件初始化失败 + put( AppInfo.CONFIG_ERROR, "\u914D\u7F6E\u6587\u4EF6\u521D\u59CB\u5316\u5931\u8D25" ); + // 抓取远程图片失败 + put( AppInfo.REMOTE_FAIL, "\u6293\u53D6\u8FDC\u7A0B\u56FE\u7247\u5931\u8D25" ); + + // 被阻止的远程主机 + put( AppInfo.PREVENT_HOST, "\u88AB\u963B\u6B62\u7684\u8FDC\u7A0B\u4E3B\u673A" ); + // 远程连接出错 + put( AppInfo.CONNECTION_ERROR, "\u8FDC\u7A0B\u8FDE\u63A5\u51FA\u9519" ); + + // "文件大小超出限制" + put( AppInfo.MAX_SIZE, "\u6587\u4ef6\u5927\u5c0f\u8d85\u51fa\u9650\u5236" ); + // 权限不足, 多指写权限 + put( AppInfo.PERMISSION_DENIED, "\u6743\u9650\u4E0D\u8DB3" ); + // 创建文件失败 + put( AppInfo.FAILED_CREATE_FILE, "\u521B\u5EFA\u6587\u4EF6\u5931\u8D25" ); + // IO错误 + put( AppInfo.IO_ERROR, "IO\u9519\u8BEF" ); + // 上传表单不是multipart/form-data类型 + put( AppInfo.NOT_MULTIPART_CONTENT, "\u4E0A\u4F20\u8868\u5355\u4E0D\u662Fmultipart/form-data\u7C7B\u578B" ); + // 解析上传表单错误 + put( AppInfo.PARSE_REQUEST_ERROR, "\u89E3\u6790\u4E0A\u4F20\u8868\u5355\u9519\u8BEF" ); + // 未找到上传数据 + put( AppInfo.NOTFOUND_UPLOAD_DATA, "\u672A\u627E\u5230\u4E0A\u4F20\u6570\u636E" ); + // 不允许的文件类型 + put( AppInfo.NOT_ALLOW_FILE_TYPE, "\u4E0D\u5141\u8BB8\u7684\u6587\u4EF6\u7C7B\u578B" ); + + // 指定路径不是目录 + put( AppInfo.NOT_DIRECTORY, "\u6307\u5B9A\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55" ); + // 指定路径并不存在 + put( AppInfo.NOT_EXIST, "\u6307\u5B9A\u8DEF\u5F84\u5E76\u4E0D\u5B58\u5728" ); + + // callback参数名不合法 + put( AppInfo.ILLEGAL, "Callback\u53C2\u6570\u540D\u4E0D\u5408\u6CD5" ); + + }}; + + public static String getStateInfo ( int key ) { + return AppInfo.info.get( key ); + } + +} diff --git a/common/src/main/java/com/jeesite/common/ueditor/define/BaseState.java b/common/src/main/java/com/jeesite/common/ueditor/define/BaseState.java new file mode 100644 index 00000000..6a4c2207 --- /dev/null +++ b/common/src/main/java/com/jeesite/common/ueditor/define/BaseState.java @@ -0,0 +1,92 @@ +package com.jeesite.common.ueditor.define; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import com.jeesite.common.ueditor.Encoder; + +public class BaseState implements State { + + private boolean state = false; + private String info = null; + + private Map infoMap = new HashMap(); + + public BaseState () { + this.state = true; + } + + public BaseState ( boolean state ) { + this.setState( state ); + } + + public BaseState ( boolean state, String info ) { + this.setState( state ); + this.info = info; + } + + public BaseState ( boolean state, int infoCode ) { + this.setState( state ); + this.info = AppInfo.getStateInfo( infoCode ); + } + + @Override + public boolean isSuccess () { + return this.state; + } + + public void setState ( boolean state ) { + this.state = state; + } + + public void setInfo ( String info ) { + this.info = info; + } + + public void setInfo ( int infoCode ) { + this.info = AppInfo.getStateInfo( infoCode ); + } + + @Override + public String toJSONString() { + return this.toString(); + } + + @Override + public String toString () { + + String key = null; + String stateVal = this.isSuccess() ? AppInfo.getStateInfo( AppInfo.SUCCESS ) : this.info; + + StringBuilder builder = new StringBuilder(); + + builder.append( "{\"state\": \"" + stateVal + "\"" ); + + Iterator iterator = this.infoMap.keySet().iterator(); + + while ( iterator.hasNext() ) { + + key = iterator.next(); + + builder.append( ",\"" + key + "\": \"" + this.infoMap.get(key) + "\"" ); + + } + + builder.append( "}" ); + + return Encoder.toUnicode( builder.toString() ); + + } + + @Override + public void putInfo(String name, String val) { + this.infoMap.put(name, val); + } + + @Override + public void putInfo(String name, long val) { + this.putInfo(name, val+""); + } + +} diff --git a/common/src/main/java/com/jeesite/common/ueditor/define/FileType.java b/common/src/main/java/com/jeesite/common/ueditor/define/FileType.java new file mode 100644 index 00000000..0827d617 --- /dev/null +++ b/common/src/main/java/com/jeesite/common/ueditor/define/FileType.java @@ -0,0 +1,32 @@ +package com.jeesite.common.ueditor.define; + +import java.util.HashMap; +import java.util.Map; + +public class FileType { + + public static final String JPG = "JPG"; + + @SuppressWarnings("serial") + private static final Map types = new HashMap(){{ + + put( FileType.JPG, ".jpg" ); + + }}; + + public static String getSuffix ( String key ) { + return FileType.types.get( key ); + } + + /** + * 根据给定的文件名,获取其后缀信息 + * @param filename + * @return + */ + public static String getSuffixByFilename ( String filename ) { + + return filename.substring( filename.lastIndexOf( "." ) ).toLowerCase(); + + } + +} diff --git a/common/src/main/java/com/jeesite/common/ueditor/define/MIMEType.java b/common/src/main/java/com/jeesite/common/ueditor/define/MIMEType.java new file mode 100644 index 00000000..e4f94327 --- /dev/null +++ b/common/src/main/java/com/jeesite/common/ueditor/define/MIMEType.java @@ -0,0 +1,21 @@ +package com.jeesite.common.ueditor.define; + +import java.util.HashMap; +import java.util.Map; + +public class MIMEType { + + @SuppressWarnings("serial") + public static final Map types = new HashMap(){{ + put( "image/gif", ".gif" ); + put( "image/jpeg", ".jpg" ); + put( "image/jpg", ".jpg" ); + put( "image/png", ".png" ); + put( "image/bmp", ".bmp" ); + }}; + + public static String getSuffix ( String mime ) { + return MIMEType.types.get( mime ); + } + +} diff --git a/common/src/main/java/com/jeesite/common/ueditor/define/MultiState.java b/common/src/main/java/com/jeesite/common/ueditor/define/MultiState.java new file mode 100644 index 00000000..a73ff47a --- /dev/null +++ b/common/src/main/java/com/jeesite/common/ueditor/define/MultiState.java @@ -0,0 +1,111 @@ +package com.jeesite.common.ueditor.define; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import com.jeesite.common.ueditor.Encoder; + +/** + * 多状态集合状态 + * 其包含了多个状态的集合, 其本身自己也是一个状态 + * @author hancong03@baidu.com + */ +public class MultiState implements State { + + private boolean state = false; + private String info = null; + private Map intMap = new HashMap(); + private Map infoMap = new HashMap(); + private List stateList = new ArrayList(); + + public MultiState ( boolean state ) { + this.state = state; + } + + public MultiState ( boolean state, String info ) { + this.state = state; + this.info = info; + } + + public MultiState ( boolean state, int infoKey ) { + this.state = state; + this.info = AppInfo.getStateInfo( infoKey ); + } + + @Override + public boolean isSuccess() { + return this.state; + } + + public void addState ( State state ) { + stateList.add( state.toJSONString() ); + } + + /** + * 该方法调用无效果 + */ + @Override + public void putInfo(String name, String val) { + this.infoMap.put(name, val); + } + + @Override + public String toJSONString() { + + String stateVal = this.isSuccess() ? AppInfo.getStateInfo( AppInfo.SUCCESS ) : this.info; + + StringBuilder builder = new StringBuilder(); + + builder.append( "{\"state\": \"" + stateVal + "\"" ); + + // 数字转换 + Iterator iterator = this.intMap.keySet().iterator(); + + while ( iterator.hasNext() ) { + + stateVal = iterator.next(); + + builder.append( ",\""+ stateVal +"\": " + this.intMap.get( stateVal ) ); + + } + + iterator = this.infoMap.keySet().iterator(); + + while ( iterator.hasNext() ) { + + stateVal = iterator.next(); + + builder.append( ",\""+ stateVal +"\": \"" + this.infoMap.get( stateVal ) + "\"" ); + + } + + builder.append( ", list: [" ); + + + iterator = this.stateList.iterator(); + + while ( iterator.hasNext() ) { + + builder.append( iterator.next() + "," ); + + } + + if ( this.stateList.size() > 0 ) { + builder.deleteCharAt( builder.length() - 1 ); + } + + builder.append( " ]}" ); + + return Encoder.toUnicode( builder.toString() ); + + } + + @Override + public void putInfo(String name, long val) { + this.intMap.put( name, val ); + } + +} diff --git a/common/src/main/java/com/jeesite/common/ueditor/define/State.java b/common/src/main/java/com/jeesite/common/ueditor/define/State.java new file mode 100644 index 00000000..1c5260f2 --- /dev/null +++ b/common/src/main/java/com/jeesite/common/ueditor/define/State.java @@ -0,0 +1,17 @@ +package com.jeesite.common.ueditor.define; + +/** + * 处理状态接口 + * @author hancong03@baidu.com + */ +public interface State { + + public boolean isSuccess (); + + public void putInfo( String name, String val ); + + public void putInfo ( String name, long val ); + + public String toJSONString (); + +} diff --git a/common/src/main/java/com/jeesite/common/ueditor/hunter/FileManager.java b/common/src/main/java/com/jeesite/common/ueditor/hunter/FileManager.java new file mode 100644 index 00000000..d920729d --- /dev/null +++ b/common/src/main/java/com/jeesite/common/ueditor/hunter/FileManager.java @@ -0,0 +1,124 @@ +package com.jeesite.common.ueditor.hunter; + +import java.io.File; +import java.util.Arrays; +import java.util.Collection; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.io.FileUtils; + +import com.jeesite.common.ueditor.PathFormat; +import com.jeesite.common.ueditor.define.AppInfo; +import com.jeesite.common.ueditor.define.BaseState; +import com.jeesite.common.ueditor.define.MultiState; +import com.jeesite.common.ueditor.define.State; + +public class FileManager { + + public static final String USERFILES_BASE_URL = "/userfiles/"; + + private String dir = null; + private String rootPath = null; + private String[] allowFiles = null; + private int count = 0; + + public FileManager ( Map conf ) { + + this.rootPath = (String)conf.get( "rootPath" ); + this.dir = this.rootPath + (String)conf.get( "dir" ); + this.allowFiles = this.getAllowFiles( conf.get("allowFiles") ); + this.count = (Integer)conf.get( "count" ); + + } + + public State listFile (HttpServletRequest request, int index ) { + +// File dir = new File( this.dir ); + File dir = new File( PathFormat.parse(this.dir) ); // ThinkGem 路径中有变量时变量不转化问题 + State state = null; + + if ( !dir.exists() ) { + return new BaseState( false, AppInfo.NOT_EXIST ); + } + + if ( !dir.isDirectory() ) { + return new BaseState( false, AppInfo.NOT_DIRECTORY ); + } + + Collection list = FileUtils.listFiles( dir, this.allowFiles, true ); + + if ( index < 0 || index > list.size() ) { + state = new MultiState( true ); + } else { + Object[] fileList = Arrays.copyOfRange( list.toArray(), index, index + this.count ); + state = this.getState(request, fileList ); + } + + state.putInfo( "start", index ); + state.putInfo( "total", list.size() ); + + return state; + + } + + private State getState (HttpServletRequest request, Object[] files ) { + + MultiState state = new MultiState( true ); + BaseState fileState = null; + + File file = null; + + for ( Object obj : files ) { + if ( obj == null ) { + break; + } + file = (File)obj; + fileState = new BaseState( true ); + //fileState.putInfo( "url", PathFormat.format( this.getPath( file ) ) ); + // ThinkGem 将绝对路径转换为虚拟路径 + String url = PathFormat.format( this.getPath( file ) ); + int index = url.indexOf(USERFILES_BASE_URL); + if(index > 0) { + url = url.substring(index + USERFILES_BASE_URL.length()); + } + fileState.putInfo( "url", request.getContextPath() + USERFILES_BASE_URL + url ); + state.addState( fileState ); + } + + return state; + + } + + private String getPath ( File file ) { + + String path = file.getAbsolutePath(); + + return path.replace( this.rootPath, "/" ); + + } + + private String[] getAllowFiles ( Object fileExt ) { + + String[] exts = null; + String ext = null; + + if ( fileExt == null ) { + return new String[ 0 ]; + } + + exts = (String[])fileExt; + + for ( int i = 0, len = exts.length; i < len; i++ ) { + + ext = exts[ i ]; + exts[ i ] = ext.replace( ".", "" ); + + } + + return exts; + + } + +} diff --git a/common/src/main/java/com/jeesite/common/ueditor/hunter/ImageHunter.java b/common/src/main/java/com/jeesite/common/ueditor/hunter/ImageHunter.java new file mode 100644 index 00000000..82c20e72 --- /dev/null +++ b/common/src/main/java/com/jeesite/common/ueditor/hunter/ImageHunter.java @@ -0,0 +1,145 @@ +package com.jeesite.common.ueditor.hunter; + +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.URL; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import com.jeesite.common.ueditor.PathFormat; +import com.jeesite.common.ueditor.define.AppInfo; +import com.jeesite.common.ueditor.define.BaseState; +import com.jeesite.common.ueditor.define.MIMEType; +import com.jeesite.common.ueditor.define.MultiState; +import com.jeesite.common.ueditor.define.State; +import com.jeesite.common.ueditor.upload.StorageManager; + +/** + * 图片抓取器 + * @author hancong03@baidu.com + */ +public class ImageHunter { + + private HttpServletRequest request = null; + private String filename = null; + private String savePath = null; + private String rootPath = null; + private List allowTypes = null; + private long maxSize = -1; + + private List filters = null; + + public ImageHunter (HttpServletRequest request, Map conf ) { + + this.request = request; + this.filename = (String)conf.get( "filename" ); + this.savePath = (String)conf.get( "savePath" ); + this.rootPath = (String)conf.get( "rootPath" ); + this.maxSize = (Long)conf.get( "maxSize" ); + this.allowTypes = Arrays.asList( (String[])conf.get( "allowFiles" ) ); + this.filters = Arrays.asList( (String[])conf.get( "filter" ) ); + + } + + public State capture ( String[] list ) { + + MultiState state = new MultiState( true ); + + for ( String source : list ) { + state.addState( captureRemoteData( source ) ); + } + + return state; + + } + + public State captureRemoteData ( String urlStr ) { + + HttpURLConnection connection = null; + URL url = null; + String suffix = null; + + try { + url = new URL( urlStr ); + + if ( !validHost( url.getHost() ) ) { + return new BaseState( false, AppInfo.PREVENT_HOST ); + } + + connection = (HttpURLConnection) url.openConnection(); + + connection.setInstanceFollowRedirects( true ); + connection.setUseCaches( true ); + + if ( !validContentState( connection.getResponseCode() ) ) { + return new BaseState( false, AppInfo.CONNECTION_ERROR ); + } + + suffix = MIMEType.getSuffix( connection.getContentType() ); + + if ( !validFileType( suffix ) ) { + return new BaseState( false, AppInfo.NOT_ALLOW_FILE_TYPE ); + } + + if ( !validFileSize( connection.getContentLength() ) ) { + return new BaseState( false, AppInfo.MAX_SIZE ); + } + + String savePath = this.getPath( this.savePath, this.filename, suffix ); + String physicalPath = this.rootPath + savePath; + + State state = StorageManager.saveFileByInputStream( connection.getInputStream(), physicalPath ); + + if ( state.isSuccess() ) { + state.putInfo( "url", request.getContextPath() + PathFormat.format( savePath ) ); + state.putInfo( "source", urlStr ); + } + + return state; + + } catch ( Exception e ) { + return new BaseState( false, AppInfo.REMOTE_FAIL ); + } + + } + + private String getPath ( String savePath, String filename, String suffix ) { + + return PathFormat.parse( savePath + suffix, filename ); + + } + + private boolean validHost ( String hostname ) { + try { + InetAddress ip = InetAddress.getByName(hostname); + if (ip.isSiteLocalAddress()) { + return false; + } + } catch (UnknownHostException e) { + return false; + } + return !filters.contains( hostname ); + + } + + private boolean validContentState ( int code ) { + + return HttpURLConnection.HTTP_OK == code; + + } + + private boolean validFileType ( String type ) { + + return this.allowTypes.contains( type ); + + } + + private boolean validFileSize ( int size ) { + return size < this.maxSize; + } + +} diff --git a/common/src/main/java/com/jeesite/common/ueditor/upload/Base64Uploader.java b/common/src/main/java/com/jeesite/common/ueditor/upload/Base64Uploader.java new file mode 100644 index 00000000..bc7d4ffa --- /dev/null +++ b/common/src/main/java/com/jeesite/common/ueditor/upload/Base64Uploader.java @@ -0,0 +1,55 @@ +package com.jeesite.common.ueditor.upload; + +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.codec.binary.Base64; + +import com.jeesite.common.ueditor.PathFormat; +import com.jeesite.common.ueditor.define.AppInfo; +import com.jeesite.common.ueditor.define.BaseState; +import com.jeesite.common.ueditor.define.FileType; +import com.jeesite.common.ueditor.define.State; + +public final class Base64Uploader { + + public static State save(HttpServletRequest request, String content, Map conf) { + + byte[] data = decode(content); + + long maxSize = ((Long) conf.get("maxSize")).longValue(); + + if (!validSize(data, maxSize)) { + return new BaseState(false, AppInfo.MAX_SIZE); + } + + String suffix = FileType.getSuffix("JPG"); + + String savePath = PathFormat.parse((String) conf.get("savePath"), + (String) conf.get("filename")); + + savePath = savePath + suffix; + String physicalPath = (String) conf.get("rootPath") + savePath; + + State storageState = StorageManager.saveBinaryFile(data, physicalPath); + + if (storageState.isSuccess()) { + String ctx = request.getContextPath(); // ThinkGem 修正上传图片后返回无contextpath问题 + storageState.putInfo("url", ctx + PathFormat.format(savePath)); + storageState.putInfo("type", suffix); + storageState.putInfo("original", ""); + } + + return storageState; + } + + private static byte[] decode(String content) { + return Base64.decodeBase64(content); + } + + private static boolean validSize(byte[] data, long length) { + return data.length <= length; + } + +} \ No newline at end of file diff --git a/common/src/main/java/com/jeesite/common/ueditor/upload/BinaryUploader.java b/common/src/main/java/com/jeesite/common/ueditor/upload/BinaryUploader.java new file mode 100644 index 00000000..a76a4041 --- /dev/null +++ b/common/src/main/java/com/jeesite/common/ueditor/upload/BinaryUploader.java @@ -0,0 +1,178 @@ +package com.jeesite.common.ueditor.upload; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.imageio.ImageIO; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.fileupload.FileItemIterator; +import org.apache.commons.fileupload.FileItemStream; +import org.apache.commons.fileupload.FileUploadException; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; + +import com.jeesite.common.io.FileUtils; +import com.jeesite.common.lang.StringUtils; +import com.jeesite.common.media.VideoUtils; +import com.jeesite.common.ueditor.PathFormat; +import com.jeesite.common.ueditor.define.ActionMap; +import com.jeesite.common.ueditor.define.AppInfo; +import com.jeesite.common.ueditor.define.BaseState; +import com.jeesite.common.ueditor.define.FileType; +import com.jeesite.common.ueditor.define.State; + +import net.coobird.thumbnailator.Thumbnails; +import net.coobird.thumbnailator.Thumbnails.Builder; + +public class BinaryUploader { + + public static final State save(HttpServletRequest request, + Map conf) { + FileItemStream fileStream = null; // 原始上传 + MultipartFile fileStream2 = null; // Spring MVC 上传 + boolean isAjaxUpload = request.getHeader( "X_Requested_With" ) != null; + + if (!ServletFileUpload.isMultipartContent(request)) { + return new BaseState(false, AppInfo.NOT_MULTIPART_CONTENT); + } + + ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory()); + + if ( isAjaxUpload ) { + upload.setHeaderEncoding( "UTF-8" ); + } + + try { + FileItemIterator iterator = upload.getItemIterator(request); + + while (iterator.hasNext()) { + fileStream = iterator.next(); + + if (!fileStream.isFormField()) { + break; + } + fileStream = null; + } + + if (fileStream == null) { + // 原始上传无文件,则检查是否是Spring MVC上传 ThinkGem + MultipartFile file = null; + if (request instanceof MultipartHttpServletRequest){ + MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request; + Iterator it = multiRequest.getFileNames(); + while (it.hasNext()) { + file = multiRequest.getFile(it.next()); + break; + } + } + if (file != null && !file.isEmpty() && file.getOriginalFilename() != null) { + fileStream2 = file; + } + } + + if (fileStream == null && fileStream2 == null) { + return new BaseState(false, AppInfo.NOTFOUND_UPLOAD_DATA); + } + + String savePath = (String) conf.get("savePath"); + String originFileName = fileStream != null ? fileStream.getName() : fileStream2.getOriginalFilename(); + String suffix = FileType.getSuffixByFilename(originFileName); + + originFileName = originFileName.substring(0, + originFileName.length() - suffix.length()); + savePath = savePath + suffix; + + long maxSize = ((Long) conf.get("maxSize")).longValue(); + + if (!validType(suffix, (String[]) conf.get("allowFiles"))) { + return new BaseState(false, AppInfo.NOT_ALLOW_FILE_TYPE); + } + + savePath = PathFormat.parse(savePath, originFileName); + + String physicalPath = FileUtils.path((String) conf.get("rootPath") + savePath); + + InputStream is = fileStream != null ? fileStream.openStream() : fileStream2.getInputStream(); + State storageState = StorageManager.saveFileByInputStream(is, physicalPath, maxSize); + is.close(); + + if (storageState.isSuccess()) { + int actionCode = ((Integer) conf.get("actionCode")).intValue(); + String ctx = request.getContextPath(); // ThinkGem 修正上传图片后返回无contextpath问题 + + // 上传图片后,进行图片压缩 + if (actionCode == ActionMap.UPLOAD_IMAGE){ + + // 如果开启了压缩图片 + if ((Boolean)conf.get("imageCompressEnable")){ + Integer width = (Integer)conf.get("imageCompressBorder"); + // 过滤掉gif图片,因为gif图片转换后会出现黑色背景的情况(gif基本也没有比较大的图片)。 + if (StringUtils.inString(FileUtils.getFileExtension(physicalPath), + "png","jpg","jpeg","bmp","ico")){ + Builder file = Thumbnails.of(physicalPath); + BufferedImage bufferedImage = ImageIO.read(new File(physicalPath)); + if (bufferedImage != null){ + if (bufferedImage.getWidth() <= width){ + file.width(bufferedImage.getWidth()); + }else{ + file.width(width); + } + file.toFile(physicalPath); + } + } + } + + } + + // 上传成功后 转换格式 按照新的视频格式 返回前台 ThinkGem + else if(actionCode == ActionMap.UPLOAD_VIDEO){ + final VideoUtils v = new VideoUtils(physicalPath); + // 先截图 + if (v.cutPic()){ + // 开启进程,在转换视频文件 + new Thread(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(5000); + v.convert(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }).start(); + storageState.putInfo("url", ctx + PathFormat.format(savePath) + "." + v.getOutputFileExtension()); + storageState.putInfo("type", "." + v.getOutputFileExtension()); + storageState.putInfo("original", originFileName +"."+ v.getInputFileExtension()); + return storageState; + } + } + storageState.putInfo("url", ctx + PathFormat.format(savePath)); + storageState.putInfo("type", suffix); + storageState.putInfo("original", originFileName + suffix); + } + + return storageState; + } catch (FileUploadException e) { + return new BaseState(false, AppInfo.PARSE_REQUEST_ERROR); + } catch (IOException e) { + return new BaseState(false, AppInfo.IO_ERROR); + } + } + + private static boolean validType(String type, String[] allowTypes) { + List list = Arrays.asList(allowTypes); + + return list.contains(type); + } + +} diff --git a/common/src/main/java/com/jeesite/common/ueditor/upload/StorageManager.java b/common/src/main/java/com/jeesite/common/ueditor/upload/StorageManager.java new file mode 100644 index 00000000..db27055a --- /dev/null +++ b/common/src/main/java/com/jeesite/common/ueditor/upload/StorageManager.java @@ -0,0 +1,213 @@ +package com.jeesite.common.ueditor.upload; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import com.jeesite.common.idgen.IdGenerate; +import com.jeesite.common.io.FileUtils; +import com.jeesite.common.io.PropertiesUtils; +import com.jeesite.common.lang.StringUtils; +import com.jeesite.common.ueditor.define.AppInfo; +import com.jeesite.common.ueditor.define.BaseState; +import com.jeesite.common.ueditor.define.State; + +public class StorageManager { + + public static final int BUFFER_SIZE = 8192; + + public StorageManager() { + + } + + public static State saveBinaryFile(byte[] data, String path) { + File file = new File(path); + + State state = valid(file); + + if (!state.isSuccess()) { + return state; + } + + BufferedOutputStream bos = null; + try { + bos = new BufferedOutputStream(new FileOutputStream(file)); + bos.write(data); + } catch (IOException ioe) { + return new BaseState(false, AppInfo.IO_ERROR); + }finally { + if (bos != null){ + try { + bos.flush(); + bos.close(); + } catch (IOException e) { + ; + } + } + } + + // 验证允许的上传的文件类型(如果没有设置则不验证,默认不设置) + String allowContentTypes = PropertiesUtils.getInstance() + .getProperty("file.allowContentTypes"); + if(StringUtils.isNotBlank(allowContentTypes)){ + String rct = FileUtils.getRealContentType(file); + if (!StringUtils.inString(rct, allowContentTypes.split(","))){ + file.delete(); + return new BaseState(false, AppInfo.NOT_ALLOW_FILE_TYPE); + } + } + + state = new BaseState(true, file.getAbsolutePath()); + state.putInfo( "size", data.length ); + state.putInfo( "title", file.getName() ); + return state; + } + + public static State saveFileByInputStream(InputStream is, String path, long maxSize) { + State state = null; + + File tmpFile = getTmpFile(); + + byte[] dataBuf = new byte[ 2048 ]; + BufferedInputStream bis = new BufferedInputStream(is, StorageManager.BUFFER_SIZE); + + BufferedOutputStream bos = null; + try { + try{ + bos = new BufferedOutputStream( + new FileOutputStream(tmpFile), StorageManager.BUFFER_SIZE); + int count = 0; + while ((count = bis.read(dataBuf)) != -1) { + bos.write(dataBuf, 0, count); + } + }finally { + if (bos != null){ + bos.flush(); + bos.close(); + } + } + + if (tmpFile.length() > maxSize) { + tmpFile.delete(); + return new BaseState(false, AppInfo.MAX_SIZE); + } + + // 验证允许的上传的文件类型(如果没有设置则不验证,默认不设置) + String allowContentTypes = PropertiesUtils.getInstance() + .getProperty("file.allowContentTypes"); + if(StringUtils.isNotBlank(allowContentTypes)){ + String rct = FileUtils.getRealContentType(tmpFile); + if (!StringUtils.inString(rct, allowContentTypes.split(","))){ + tmpFile.delete(); + return new BaseState(false, AppInfo.NOT_ALLOW_FILE_TYPE); + } + } + + state = saveTmpFile(tmpFile, path); + + if (!state.isSuccess()) { + tmpFile.delete(); + } + + return state; + } catch (IOException e) { + ; + }finally { + if (bis != null){ + try { + bis.close(); + } catch (IOException e) { + ; + } + } + } + return new BaseState(false, AppInfo.IO_ERROR); + } + + public static State saveFileByInputStream(InputStream is, String path) { + State state = null; + + File tmpFile = getTmpFile(); + + byte[] dataBuf = new byte[ 2048 ]; + BufferedInputStream bis = new BufferedInputStream(is, StorageManager.BUFFER_SIZE); + + try { + BufferedOutputStream bos = null; + try{ + bos = new BufferedOutputStream(new FileOutputStream(tmpFile), + StorageManager.BUFFER_SIZE); + int count = 0; + while ((count = bis.read(dataBuf)) != -1) { + bos.write(dataBuf, 0, count); + } + }finally { + if (bos != null){ + bos.flush(); + bos.close(); + } + } + state = saveTmpFile(tmpFile, path); + if (!state.isSuccess()) { + tmpFile.delete(); + } + return state; + } catch (IOException e) { + ; + }finally { + if (bis != null){ + try { + bis.close(); + } catch (IOException e) { + ; + } + } + } + return new BaseState(false, AppInfo.IO_ERROR); + } + + private static File getTmpFile() { +// File tmpDir = FileUtils.getTempDirectory(); + File tmpDir = new File(System.getProperty("java.io.tmpdir")); +// String tmpFileName = (Math.random() * 10000 + "").replace(".", ""); +// return new File(tmpDir, tmpFileName); + return new File(tmpDir, IdGenerate.randomBase62(10)); + } + + private static State saveTmpFile(File tmpFile, String path) { + State state = null; + File targetFile = new File(path); + + if (targetFile.canWrite()) { + return new BaseState(false, AppInfo.PERMISSION_DENIED); + } + try { + FileUtils.moveFile(tmpFile, targetFile); + } catch (IOException e) { + return new BaseState(false, AppInfo.IO_ERROR); + } + + state = new BaseState(true); + state.putInfo( "size", targetFile.length() ); + state.putInfo( "title", targetFile.getName() ); + + return state; + } + + private static State valid(File file) { + File parentPath = file.getParentFile(); + + if ((!parentPath.exists()) && (!parentPath.mkdirs())) { + return new BaseState(false, AppInfo.FAILED_CREATE_FILE); + } + + if (!parentPath.canWrite()) { + return new BaseState(false, AppInfo.PERMISSION_DENIED); + } + + return new BaseState(true); + } +} diff --git a/common/src/main/java/com/jeesite/common/ueditor/upload/Uploader.java b/common/src/main/java/com/jeesite/common/ueditor/upload/Uploader.java new file mode 100644 index 00000000..1ff1550c --- /dev/null +++ b/common/src/main/java/com/jeesite/common/ueditor/upload/Uploader.java @@ -0,0 +1,32 @@ +package com.jeesite.common.ueditor.upload; + +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import com.jeesite.common.ueditor.define.State; + +public class Uploader { + + private HttpServletRequest request = null; + private Map conf = null; + + public Uploader(HttpServletRequest request, Map conf) { + this.request = request; + this.conf = conf; + } + + public final State doExec() { + String filedName = (String) this.conf.get("fieldName"); + State state = null; + + if ("true".equals(this.conf.get("isBase64"))) { + state = Base64Uploader.save(this.request, this.request.getParameter(filedName), + this.conf); + } else { + state = BinaryUploader.save(this.request, this.conf); + } + + return state; + } +}