開心一笑
剛來北京,租了一個小房,一樓,上淘寶買衣服,選了付錢了聯系賣家:“我已付款,請發貨。
”誰知那貨直接說:“我看到你地址了,自己上樓來拿吧!我就在你樓上。”
拿你妹,老子付了郵費的。。。送下來。
提出問題
Ueditor前后端源碼的學習和簡單的研究???
解決問題
前提:
- 假如你已經看了我的前一篇文章,這一點很重要的啊,當然不看也可以,因為你已經是一個高手,就像我一樣,哈哈;
- 假如你已經安裝tomcat服務器;
- 假如你已經把項目運行到Eclipse上;
- 假如你已經有java基礎;
- 假如你對js有一定基礎;
- 假如你已經下載ueditor1_4_3_3-src源碼,記得是開發的哦;
那么開始吧!
這是我的項目目錄
1.從訪問路徑http://localhost:8081/Test/_examples/simpleDemo.html,
我們主要是要看看,富文本框被加載出來之前,會調用哪些代碼,
不賣關子,很明顯,會調用后端的controller.jsp代碼,因為我們已經在ueditor.config配置了:
// 服務器統一請求接口路徑
, serverUrl: URL + "jsp/controller.js
看看controller.jsp代碼,上一篇文章我們已經講了,要把這些代碼看作是后端代碼,很重要很重要的:
<%@ page language="java" contentType="text/html; charset=UTF-8"
import="com.baidu.ueditor.ActionEnter"
pageEncoding="UTF-8"%>
<%@ page trimDirectiveWhitespaces="true" %>
<%
request.setCharacterEncoding( "utf-8" );
response.setHeader("Content-Type" , "text/html");
/** 項目根路徑 **/
String rootPath = application.getRealPath( "/" );
/** 調用后端的ActionEnter類,并執行exec方法 **/
out.write( new ActionEnter( request, rootPath ).exec() );
%>
我們就到ActionEnter.java看看吧,這個類就是前端調用后端的唯一入口,也只有這個入口了,
記住第一章有講了,要把源碼復制到src下,進行調試哦!不知道先看第一章吧!!!!!
package com.baidu.ueditor;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.baidu.ueditor.define.ActionMap;
import com.baidu.ueditor.define.AppInfo;
import com.baidu.ueditor.define.BaseState;
import com.baidu.ueditor.define.State;
import com.baidu.ueditor.hunter.FileManager;
import com.baidu.ueditor.hunter.ImageHunter;
import com.baidu.ueditor.upload.Uploader;
public class ActionEnter {
private HttpServletRequest request = null;
private String rootPath = null;
private String contextPath = null;
private String actionType = null;
private ConfigManager configManager = null;
/** action統一入口 **/
public ActionEnter ( HttpServletRequest request, String rootPath ) {
this.request = request;
/** rootPath = /Test/ **/
this.rootPath = rootPath;
/** actionType = config **/
this.actionType = request.getParameter( "action" );
/** contextPath = /Test **/
this.contextPath = request.getContextPath();
/** 調用ConfigManager **/
this.configManager = ConfigManager.getInstance( this.rootPath, this.contextPath, request.getRequestURI() );
}
2.ConfigManager類主要用來讀取后端的配置文件,就是config.json這個文件,事實上這個文件應該放在后端的。
/**
* 配置管理器
* @author hancong03@baidu.com
*
*/
public final class ConfigManager {
private final String rootPath;
private final String originalPath;
private final String contextPath;
/** 存放備注文件 **/
private static final String configFileName = "config.json";
private String parentPath = null;
private JSONObject jsonConfig = null;
// 涂鴉上傳filename定義
private final static String SCRAWL_FILE_NAME = "scrawl";
// 遠程圖片抓取filename定義
private final static String REMOTE_FILE_NAME = "remote";
/*
* 通過一個給定的路徑構建一個配置管理器, 該管理器要求地址路徑所在目錄下必須存在config.properties文件
*/
private ConfigManager ( String rootPath, String contextPath, String uri ) throws FileNotFoundException, IOException {
rootPath = rootPath.replace( "\\", "/" );
//下面的rootPath就是我的根路徑
// rootPath=D:/workspace_de_client/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/Test/
this.rootPath = rootPath;
this.contextPath = contextPath;
//請求路徑 url = /Test/jsp/controller.jsp
if ( contextPath.length() > 0 ) {
// D:/workspace_de_client/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/Test//jsp/controller.jsp
this.originalPath = this.rootPath + uri.substring( contextPath.length() );
} else {
this.originalPath = this.rootPath + uri;
}
/** 調用當前類的初始化環境方法 initEnv **/
this.initEnv();
}
//上面的方法無非就是獲得controller.jsp這個類所在的真實目錄而已
//下面看看initEnv()這個方法
private void initEnv () throws FileNotFoundException, IOException {
/** **/
File file = new File( this.originalPath );
if ( !file.isAbsolute() ) {
file = new File( file.getAbsolutePath() );
}
/** 獲得文件的父路徑,也就是 ..../jsp **/
this.parentPath = file.getParent();
/** 讀取配置文件,這個方法比較重要,往下看 **/
String configContent = this.readFile( this.getConfigPath() );
try{
/** 把返回的的json字符串扔進JsonObject對象中 **/
JSONObject jsonConfig = new JSONObject( configContent );
this.jsonConfig = jsonConfig;
} catch ( Exception e ) {
this.jsonConfig = null;
}
}
/** 獲得配置路徑,記住config.json是和controller.jsp放在同一個目錄下的,很坑有木有 **/
private String getConfigPath () {
/** 拼湊config.json的真實路徑 **/
return this.parentPath + File.separator + ConfigManager.configFileName;
}
private String[] getArray ( String key ) {
JSONArray jsonArray = this.jsonConfig.getJSONArray( key );
String[] result = new String[ jsonArray.length() ];
for ( int i = 0, len = jsonArray.length(); i < len; i++ ) {
result[i] = jsonArray.getString( i );
}
return result;
}
/** 獲得配置文件的內容,變成字符串返回 **/
private String readFile ( String path ) throws IOException {
StringBuilder builder = new StringBuilder();
try {
InputStreamReader reader = new InputStreamReader( new FileInputStream( path ), "UTF-8" );
BufferedReader bfReader = new BufferedReader( reader );
String tmpContent = null;
while ( ( tmpContent = bfReader.readLine() ) != null ) {
builder.append( tmpContent );
}
bfReader.close();
} catch ( UnsupportedEncodingException e ) {
// 忽略
}
//過濾輸入字符串, 剔除多行注釋以及替換掉反斜杠
return this.filter( builder.toString() );
}
// 過濾輸入字符串, 剔除多行注釋以及替換掉反斜杠
private String filter ( String input ) {
return input.replaceAll( "/\\*[\\s\\S]*?\\*/", "" );
}
從上面的方法中,讀取配置文件的所有后端代碼就都執行完了吧!!!!很簡單吧!!!!
3.后端代碼執行完之后,富文本框就初始化出來了,很有成就感吧!!
如圖:
我們點擊上傳圖片的按鈕,選擇一張圖片上傳,好,接下來就看看前端是如何調用,以及后端是如何保存文件的吧!!
我們看simpleupload.js這個文件,它是實現單文本上傳的主要前段代碼,很重要的
我們從53行開始看也就是:domUtils.on(input, 'change', function()
找不到可以Ctrl +F,相信這點技能還是有的吧,否則就不適合這個行業了 !!!!
這里我要說明下,ueditor讀取配置文件的順序,是:
后端返回json配置文件 -->
用戶自定義的配置文件 -->
ueditor.config(我不知道有沒有記錯,在家里寫,沒網啊!!!一切都是憑記憶啊)
/**
* @description
* 簡單上傳:點擊按鈕,直接選擇文件上傳
* @author Jinqn
* @date 2014-03-31
*/
UE.plugin.register('simpleupload', function (){
var me = this,
isLoaded = false,
containerBtn;
/** 初始化上傳的圖片按鈕,人家名字取得好啊!! **/
function initUploadBtn(){
var w = containerBtn.offsetWidth || 20,
h = containerBtn.offsetHeight || 20,
btnIframe = document.createElement('iframe'),
btnStyle = 'display:block;width:' + w + 'px;height:' +
h + 'px;overflow:hidden;border:0;margin:0;padding:0;position:absolute;top:0;left:0;filter:alpha(opacity=0);
-moz-opacity:0;-khtml-opacity: 0;
opacity: 0;cursor:pointer;';
domUtils.on(btnIframe, 'load', function(){
var timestrap = (+new Date()).toString(36),
wrapper,
btnIframeDoc,
btnIframeBody;
btnIframeDoc = (btnIframe.contentDocument || btnIframe.contentWindow.document);
btnIframeBody = btnIframeDoc.body;
wrapper = btnIframeDoc.createElement('div');
wrapper.innerHTML = '<form id="edui_form_' + timestrap + '" target="edui_iframe_'
+ timestrap + '" method="POST" enctype="multipart/form-data" action="' + me.getOpt('serverUrl') + '" ' +
'style="' + btnStyle + '">' +
'<input id="edui_input_' + timestrap + '" type="file" accept="image/*" name="'
+ me.options.imageFieldName + '" ' +
'style="' + btnStyle + '">' +
'</form>' +
'<iframe id="edui_iframe_' + timestrap + '" name="edui_iframe_' + timestrap
+ '" style="display:none;width:0;height:0;border:0;margin:0;padding:0;position:absolute;"></iframe>';
wrapper.className = 'edui-' + me.options.theme;
wrapper.id = me.ui.id + '_iframeupload';
btnIframeBody.style.cssText = btnStyle;
btnIframeBody.style.width = w + 'px';
btnIframeBody.style.height = h + 'px';
btnIframeBody.appendChild(wrapper);
if (btnIframeBody.parentNode) {
btnIframeBody.parentNode.style.width = w + 'px';
btnIframeBody.parentNode.style.height = w + 'px';
}
var form = btnIframeDoc.getElementById('edui_form_' + timestrap);
var input = btnIframeDoc.getElementById('edui_input_' + timestrap);
var iframe = btnIframeDoc.getElementById('edui_iframe_' + timestrap);
/** 點擊上傳圖片按鈕時,調用的代碼 **/
domUtils.on(input, 'change', function(){
if(!input.value) return;
var loadingId = 'loading_' + (+new Date()).toString(36);
var params = utils.serializeParam(me.queryCommandValue('serverparam')) || '';
/** 獲得配置文件中的imageActionName值 **/
var imageActionUrl = me.getActionUrl(me.getOpt('imageActionName'));
//獲取允許的文件格式
var allowFiles = me.getOpt('imageAllowFiles');
me.focus();
me.execCommand('inserthtml', '<img class="loadingclass" id="'
+ loadingId + '" src="' + me.options.themePath + me.options.theme
+'/images/spacer.gif" title="' + (me.getLang('simpleupload.loading') || '') + '" >');
//這個方法先不看,它是后端執行完圖片上傳后回調函數
function callback(){
try{
var link, json, loader,
body = (iframe.contentDocument || iframe.contentWindow.document).body,
result = body.innerText || body.textContent || '';
json = (new Function("return " + result))();
link = me.options.imageUrlPrefix + json.url;
if(json.state == 'SUCCESS' && json.url) {
loader = me.document.getElementById(loadingId);
loader.setAttribute('src', link);
loader.setAttribute('_src', link);
loader.setAttribute('title', json.title || '');
loader.setAttribute('alt', json.original || '');
loader.removeAttribute('id');
domUtils.removeClasses(loader, 'loadingclass');
} else {
showErrorLoader && showErrorLoader(json.state);
}
}catch(er){
showErrorLoader && showErrorLoader(me.getLang('simpleupload.loadError'));
}
form.reset();
domUtils.un(iframe, 'load', callback);
}
function showErrorLoader(title){
if(loadingId) {
var loader = me.document.getElementById(loadingId);
loader && domUtils.remove(loader);
me.fireEvent('showmessage', {
'id': loadingId,
'content': title,
'type': 'error',
'timeout': 4000
});
}
}
/* 判斷后端配置是否沒有加載成功 */
if (!me.getOpt('imageActionName')) {
errorHandler(me.getLang('autoupload.errorLoadConfig'));
return;
}
// 判斷文件格式是否錯誤
var filename = input.value,
fileext = filename ? filename.substr(filename.lastIndexOf('.')):'';
if (!fileext || (allowFiles && (allowFiles.join('') + '.').indexOf(fileext.toLowerCase() + '.') == -1)) {
showErrorLoader(me.getLang('simpleupload.exceedTypeError'));
return;
}
// -----這里要注意了,這就是調用后端接口的重要代碼 start ----
domUtils.on(iframe, 'load', callback);
//給form標簽的action設置請求路徑,不要問我form標簽在哪里,在上面的初始化按鈕就有了
form.action = utils.formatUrl(imageActionUrl + (imageActionUrl.indexOf('?') == -1 ? '?':'&') + params);
//很簡單,把form代碼提交了
form.submit();
// -------end ----------------------------------------
});
var stateTimer;
me.addListener('selectionchange', function () {
clearTimeout(stateTimer);
stateTimer = setTimeout(function() {
var state = me.queryCommandState('simpleupload');
if (state == -1) {
input.disabled = 'disabled';
} else {
input.disabled = false;
}
}, 400);
});
isLoaded = true;
});
btnIframe.style.cssText = btnStyle;
containerBtn.appendChild(btnIframe);
}
return {
bindEvents:{
'ready': function() {
//設置loading的樣式
utils.cssRule('loading',
'.loadingclass{display:inline-block;cursor:default;background: url(\''
+ this.options.themePath
+ this.options.theme +'/images/loading.gif\') no-repeat center center transparent;
border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;}\n' +
'.loaderrorclass{display:inline-block;cursor:default;background: url(\''
+ this.options.themePath
+ this.options.theme +'/images/loaderror.png\') no-repeat center center transparent;
border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;' +
'}',
this.document);
},
/* 初始化簡單上傳按鈕 */
'simpleuploadbtnready': function(type, container) {
containerBtn = container;
me.afterConfigReady(initUploadBtn);
}
},
outputRule: function(root){
utils.each(root.getNodesByTagName('img'),function(n){
if (/\b(loaderrorclass)|(bloaderrorclass)\b/.test(n.getAttr('class'))) {
n.parentNode.removeChild(n);
}
});
},
commands: {
'simpleupload': {
queryCommandState: function () {
return isLoaded ? 0:-1;
}
}
}
}
});
好了,開始來調用后端的代碼了,一樣是調用ActionEnter.java這個類
前端的請求路徑是
"http://localhost:8081/Test/jsp/controller.jsp?action=uploadimage"
/**
* 處理不同類型的回調函數
* @return
*/
public String invoke() {
//自己添加上去的
Map<String, Integer> mapping = ActionMap.mapping;
if ( actionType == null || !ActionMap.mapping.containsKey( actionType ) ) {
return new BaseState( false, AppInfo.INVALID_ACTION ).toJSONString();
}
if ( this.configManager == null || !this.configManager.valid() ) {
return new BaseState( false, AppInfo.CONFIG_ERROR ).toJSONString();
}
State state = null;
// 獲得actionType類型碼 ActionMap這個類我就不介紹了,自己可以看看,主要是封裝的一些常量
int actionCode = ActionMap.getType( this.actionType );
Map<String, Object> conf = null;
switch ( actionCode ) {
//如果配置文件,執行下面的方法,這個就是我們開始講的后端讀取的配置文件執行的邏輯
case ActionMap.CONFIG:
return this.configManager.getAllConfig().toString();
//這里是我們這次重點講解的路徑,圖片上傳,視頻上傳都執行這個路基
case ActionMap.UPLOAD_IMAGE:
case ActionMap.UPLOAD_SCRAWL:
case ActionMap.UPLOAD_VIDEO:
case ActionMap.UPLOAD_FILE:
//發現沒有,這里獲得配置文件,看到這里,你應該先看getConfig這個方法,跟著思路走,不是是跟著調試代碼走
conf = this.configManager.getConfig( actionCode );
//這里就是執行文件上傳的方法了,看完上面代碼才可以看這里呀,不要急
state = new Uploader( request, conf ).doExec();
break;
case ActionMap.CATCH_IMAGE:
conf = configManager.getConfig( actionCode );
String[] list = this.request.getParameterValues( (String)conf.get( "fieldName" ) );
state = new ImageHunter( conf ).capture( list );
break;
case ActionMap.LIST_IMAGE:
case ActionMap.LIST_FILE:
conf = configManager.getConfig( actionCode );
int start = this.getStartIndex();
state = new FileManager( conf ).listFile( start );
break;
}
return state.toJSONString();
}
看看configManager.getConfig這個類
//如何是獲得后端的所有配置,調用這個方法
public JSONObject getAllConfig () {
return this.jsonConfig;
}
//獲得部分的配置
public Map<String, Object> getConfig ( int type ) {
Map<String, Object> conf = new HashMap<String, Object>();
String savePath = null;
switch ( type ) {
case ActionMap.UPLOAD_FILE:
conf.put( "isBase64", "false" );
conf.put( "maxSize", this.jsonConfig.getLong( "fileMaxSize" ) );
conf.put( "allowFiles", this.getArray( "fileAllowFiles" ) );
conf.put( "fieldName", this.jsonConfig.getString( "fileFieldName" ) );
savePath = this.jsonConfig.getString( "filePathFormat" );
break;
//上傳圖片邏輯
case ActionMap.UPLOAD_IMAGE:
conf.put( "isBase64", "false" );
conf.put( "maxSize", this.jsonConfig.getLong( "imageMaxSize" ) );
conf.put( "allowFiles", this.getArray( "imageAllowFiles" ) );
//看看看,走在路上別瞎看,看這里很重要的
//imageFieldName 圖片名稱
conf.put( "fieldName", this.jsonConfig.getString( "imageFieldName" ) );
//圖片保存路徑,有沒有發現在config.json配置的imagePathFormat返回前端變成savePath
savePath = this.jsonConfig.getString( "imagePathFormat" );
break;
case ActionMap.UPLOAD_VIDEO:
conf.put( "maxSize", this.jsonConfig.getLong( "videoMaxSize" ) );
conf.put( "allowFiles", this.getArray( "videoAllowFiles" ) );
conf.put( "fieldName", this.jsonConfig.getString( "videoFieldName" ) );
savePath = this.jsonConfig.getString( "videoPathFormat" );
break;
case ActionMap.UPLOAD_SCRAWL:
conf.put( "filename", ConfigManager.SCRAWL_FILE_NAME );
conf.put( "maxSize", this.jsonConfig.getLong( "scrawlMaxSize" ) );
conf.put( "fieldName", this.jsonConfig.getString( "scrawlFieldName" ) );
conf.put( "isBase64", "true" );
savePath = this.jsonConfig.getString( "scrawlPathFormat" );
break;
case ActionMap.CATCH_IMAGE:
conf.put( "filename", ConfigManager.REMOTE_FILE_NAME );
conf.put( "filter", this.getArray( "catcherLocalDomain" ) );
conf.put( "maxSize", this.jsonConfig.getLong( "catcherMaxSize" ) );
conf.put( "allowFiles", this.getArray( "catcherAllowFiles" ) );
conf.put( "fieldName", this.jsonConfig.getString( "catcherFieldName" ) + "[]" );
savePath = this.jsonConfig.getString( "catcherPathFormat" );
break;
case ActionMap.LIST_IMAGE:
conf.put( "allowFiles", this.getArray( "imageManagerAllowFiles" ) );
conf.put( "dir", this.jsonConfig.getString( "imageManagerListPath" ) );
conf.put( "count", this.jsonConfig.getInt( "imageManagerListSize" ) );
break;
case ActionMap.LIST_FILE:
conf.put( "allowFiles", this.getArray( "fileManagerAllowFiles" ) );
conf.put( "dir", this.jsonConfig.getString( "fileManagerListPath" ) );
conf.put( "count", this.jsonConfig.getInt( "fileManagerListSize" ) );
break;
}
conf.put( "savePath", savePath );
conf.put( "rootPath", this.rootPath );
return conf;
}
接下了這個類Uploader.java
package com.baidu.ueditor.upload;
import com.baidu.ueditor.define.State;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
public class Uploader {
private HttpServletRequest request = null;
private Map<String, Object> conf = null;
public Uploader(HttpServletRequest request, Map<String, Object> 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"))) {
//重點看這里,好了,知道我們要干嘛了吧!!!看Base64Uploader類的代碼
state = Base64Uploader.save(this.request.getParameter(filedName),
this.conf);
} else {
state = BinaryUploader.save(this.request, this.conf);
}
return state;
}
}
接下來看這個類的方法:BaseUploader.java,這里的save方法就是把文件保存到硬盤上
package com.baidu.ueditor.upload;
import com.baidu.ueditor.PathFormat;
import com.baidu.ueditor.define.AppInfo;
import com.baidu.ueditor.define.BaseState;
import com.baidu.ueditor.define.FileType;
import com.baidu.ueditor.define.State;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
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;
public class BinaryUploader {
public static final State save(HttpServletRequest request,
Map<String, Object> conf) {
FileItemStream fileStream = null;
boolean isAjaxUpload = request.getHeader( "X_Requested_With" ) != null;
if (!ServletFileUpload.isMultipartContent(request)) {
return new BaseState(false, AppInfo.NOT_MULTIPART_CONTENT);
}
//common-io包中類,用于文件上傳
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) {
return new BaseState(false, AppInfo.NOTFOUND_UPLOAD_DATA);
}
//獲得保存路徑
String savePath = (String) conf.get("savePath");
//文件原始名稱
String originFileName = fileStream.getName();
//文件后綴
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 = (String) conf.get("rootPath") + savePath;
InputStream is = fileStream.openStream();
//這里就是把文件保存到硬盤上,具體怎么保存的可以自己跟過去看看
//State這個類很重要,是一個接口,它是返回到前端的數據
State storageState = StorageManager.saveFileByInputStream(is,
physicalPath, maxSize);
is.close();
if (storageState.isSuccess()) {
storageState.putInfo("url", 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<String> list = Arrays.asList(allowTypes);
return list.contains(type);
}
}
最后,我們再看一個類就是State這個類,它是一個接口,我們主要是看它的實現類BaseState
這個類很重要,很重要,很重要,重要事情說3遍:::
介紹下吧:
這個類主要是返回前端的數據,格式就是下面這個樣子,格式一定要對,否則前端會出現問題
package com.baidu.ueditor.define;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import com.baidu.ueditor.Encoder;
public class BaseState implements State {
//狀態碼
private boolean state = false;
private String info = null;
//里面存保存好的文件路徑和
private Map<String, String> infoMap = new HashMap<String, String>();
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 );
}
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();
}
/** 這里很重要的,也很簡單,它把infoMap手工拼湊成json字符串返回回去 **/
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<String> 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+"");
}
}
4.上面后端的代碼已經調完了,接下來就是后端數據返回到前端
之前講過,看前端的simpleupload.js
后端返回數據后會調用回調函數的callback()方法
function callback(){
try{
var link, json, loader,
body = (iframe.contentDocument || iframe.contentWindow.document).body,
result = body.innerText || body.textContent || '';
//這里result就是后端返回的數據
json = (new Function("return " + result))();
//imageUrlPrefix這個很重要很重要很重要,如果沒配置的話,圖片可能顯示不出來
//link就是圖片的路徑
link = me.options.imageUrlPrefix + json.url;
if(json.state == 'SUCCESS' && json.url) {
loader = me.document.getElementById(loadingId);
loader.setAttribute('src', link);
loader.setAttribute('_src', link);
loader.setAttribute('title', json.title || '');
loader.setAttribute('alt', json.original || '');
loader.removeAttribute('id');
domUtils.removeClasses(loader, 'loadingclass');
} else {
showErrorLoader && showErrorLoader(json.state);
}
}catch(er){
showErrorLoader && showErrorLoader(me.getLang('simpleupload.loadError'));
}
form.reset();
domUtils.un(iframe, 'load', callback);
}
function showErrorLoader(title){
if(loadingId) {
var loader = me.document.getElementById(loadingId);
loader && domUtils.remove(loader);
me.fireEvent('showmessage', {
'id': loadingId,
'content': title,
'type': 'error',
'timeout': 4000
});
}
}
5.結束了,好累啊,可是朋友們,這樣就滿足了嗎?NO NO NO,這里只是講源碼實現,至于如何和真實項目結合才是重點啊!!!
篇幅太長了,請看下一章吧!!!!
讀書感悟
來自《貓的報恩》
- 我始終相信,在這個世界上,一定有另一個自己,在做著我不敢做的事,在過著我想過的生活。
- 生命可以隨心所欲,但不能隨波逐流。
- 當人類用感情和希望去創造一樣東西,那一樣東西就會被賦予靈魂。