?
結論:
當在Liferay中用管理員登錄,導航到控制面板->Documents and Media ,在指定文件夾下添加BasicDocument時,服務器做了如下的事情:
(1) 在DLFILEENTRY表中添加一條記錄代表被添加的文檔。
(2) 在DLFILEENTRYVERSION表中添加一條記錄,通過fileEntryId外鍵關聯到DLFILEENTRY表,用來記錄剛被添加文檔的版本信息。
(3)?在DLFOLDER表中更新最新post提交的時間戳。
(4) 根據服務器對于com.liferay.portlet.documentlibrary.store的具體實現的不同,先對文件進行病毒掃描(在portal.properties 中有開關),然后把上傳的資源文件存入到Store的某個具體位置。
Store有5種實現,我至少可以保證,如果用的是FileSystemStore,那么這個資源文件被放入$liferay_home/data/document_library目錄,并且最終文件名不再是上傳的文件名,而是<version_number>.如果使用的是DBStore,那么這個資源文件最終會被放在數據庫中DLCONTENT表中,并且資源文件(比如圖片)以BLOB的形式存儲。
(5)在ASSETENTRY表中添加一條記錄,它通過classpk外鍵關聯到DLFILEENTRY,因為File也是一種資產,所以必須在這張表中也留下記錄。
?
?
具體分析:
?Liferay控制面板中,當創建了文件夾,然后要在其中添加某個Basic Document:
?
查看瀏覽器debug信息:
可以發現,它調用的struts_action為/document_library/edit_file_entry
?
我們去struts-config.xml中去找:
<action?path="/document_library/edit_file_entry"?type="com.liferay.portlet.documentlibrary.action.EditFileEntryAction">?????????????<forward?name="portlet.document_library.edit_file_entry"?path="portlet.document_library.edit_file_entry"?/>?????????????<forward?name="portlet.document_library.error"?path="portlet.document_library.error"?/>?????????</action>? 可以發現, 它會forward到portlet.document_library.edit_file_entry的路徑名下找頁面:
我們去tiles-def.xml中找匹配:
<definition?name="portlet.document_library.edit_file_entry"?extends="portlet.document_library">?????????<put?name="portlet_content"?value="/portlet/document_library/edit_file_entry.jsp"?/>?????</definition>? ?
所以,它最終會訪問/portlet/document_library/edit_file_entry.jsp頁面:
這個頁面會吧你剛才選擇的目錄列出來,比如我們剛才選擇了abcde目錄,那么在這里,它就會顯示出來:
對應的顯示代碼是
<aui:field-wrapper?label="folder">?????????????<aui:a?href="<%=?viewFolderURL?%>"?id="folderName"><%=?folderName?%></aui:a>??????????????<c:if?test="<%=?referringPortletResourceRootPortletId.equals(PortletKeys.ASSET_PUBLISHER)?%>">?????????????????<aui:button?name="openFolderSelectorButton"?onClick='<%=?renderResponse.getNamespace()?+?"openFolderSelector();"?%>'?value="select"?/>??????????????????<%?????????????????String?taglibRemoveFolder?=?"Liferay.Util.removeFolderSelection('folderId',?'folderName',?'"?+?renderResponse.getNamespace()?+?"');";?????????????????%>??????????????????<aui:button?disabled="<%=?folderId?<=?0?%>"?name="removeFolderButton"?onClick="<%=?taglibRemoveFolder?%>"?value="remove"?/>?????????????</c:if>?????????</aui:field-wrapper>? 然后,它會有一個文件上傳框:
<aui:input?name="file"?type="file">?????????????<aui:validator?name="acceptFiles">?????????????????'<%=?StringUtil.merge(PrefsPropsUtil.getStringArray(PropsKeys.DL_FILE_EXTENSIONS,?StringPool.COMMA))?%>'?????????????</aui:validator>?????????</aui:input>? 它會通過aui框架的校驗器來校驗被上傳的文件擴展名和大小。
輸入文件標題和正文的部分我就略過了,不是重點,我們現在想關注的是,到底當點擊最下方的"Publish"按鈕時發生了什么。
?
深入分析點擊"Publish"按鈕后發生的事情
對應的代碼是:
<aui:button?disabled="<%=?checkedOut?&&?!hasLock?||?(pending?&&?PropsValues.DL_FILE_ENTRY_DRAFTS_ENABLED)?%>"?name="publishButton"?type="submit"?value="<%=?publishButtonLabel?%>"?/>? 它會吧整個表單提交,對應代碼是:
<aui:form?action="<%=?editFileEntryURL?%>"?cssClass="lfr-dynamic-form"?enctype="multipart/form-data"?method="post"?name="fm"?onSubmit='<%=?"event.preventDefault();?"?+?renderResponse.getNamespace()?+?"saveFileEntry(false);"?%>'>?????<aui:input?name="<%=?Constants.CMD?%>"?type="hidden"?/>?????<aui:input?name="redirect"?type="hidden"?value="<%=?redirect?%>"?/>?????<aui:input?name="backURL"?type="hidden"?value="<%=?backURL?%>"?/>?????<aui:input?name="referringPortletResource"?type="hidden"?value="<%=?referringPortletResource?%>"?/>?????<aui:input?name="uploadProgressId"?type="hidden"?value="<%=?uploadProgressId?%>"?/>?????<aui:input?name="repositoryId"?type="hidden"?value="<%=?repositoryId?%>"?/>?????<aui:input?name="folderId"?type="hidden"?value="<%=?folderId?%>"?/>?????<aui:input?name="fileEntryId"?type="hidden"?value="<%=?fileEntryId?%>"?/>?????<aui:input?name="workflowAction"?type="hidden"?value="<%=?WorkflowConstants.ACTION_PUBLISH?%>"?/>?..? 而因為用post提交,所以這些信息都在payload中:
?Content-Disposition:?form-data;?name="_20_formDate"??1341536588996??Content-Disposition:?form-data;?name="_20_cmd"??add??Content-Disposition:?form-data;?name="_20_redirect"??http://localhost:8080/group/control_panel/manage?p_p_id=20&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view&doAsGroupId=19&refererPlid=12655&_20_refererPlid=12655&_20_doAsGroupId=19&_20_struts_action=%2Fdocument_library%2Fview&_20_folderId=16904??Content-Disposition:?form-data;?name="_20_backURL"????Content-Disposition:?form-data;?name="_20_referringPortletResource"????Content-Disposition:?form-data;?name="_20_uploadProgressId"??dlFileEntryUploadProgress??Content-Disposition:?form-data;?name="_20_repositoryId"??19??Content-Disposition:?form-data;?name="_20_folderId"??16904??Content-Disposition:?form-data;?name="_20_fileEntryId"??0??Content-Disposition:?form-data;?name="_20_workflowAction"??1??Content-Disposition:?form-data;?name="_20_file";?filename="charles_wang.jpg"?Content-Type:?p_w_picpath/jpeg????Content-Disposition:?form-data;?name="_20_title"??title?of?new?document??Content-Disposition:?form-data;?name="_20_description"??a?new?document?which?contains?a?p_w_picpath?and?resides?in?abcde?folder??Content-Disposition:?form-data;?name="_20_fileEntryTypeId"??0??Content-Disposition:?form-data;?name="_20_assetTagNames"????Content-Disposition:?form-data;?name="_20_assetLinkSearchContainerPrimaryKeys"????Content-Disposition:?form-data;?name="_20_assetLinkEntryIds"????Content-Disposition:?form-data;?name="_20_inputPermissionsShowOptions"??false??Content-Disposition:?form-data;?name="_20_inputPermissionsViewRole"??Guest??Content-Disposition:?form-data;?name="_20_guestPermissions"??ADD_DISCUSSION??Content-Disposition:?form-data;?name="_20_guestPermissions"??VIEW??Content-Disposition:?form-data;?name="_20_groupPermissions"??ADD_DISCUSSION??Content-Disposition:?form-data;?name="_20_groupPermissions"??VIEW?? 所以,action還是自身頁面,不難在struts-config.xml中找到Action類名為EditFileEntryAction:
因為我們的cmd是add,所以它會走以下流程:
public?void?processAction(?????????????ActionMapping?mapping,?ActionForm?form,?PortletConfig?portletConfig,?????????????ActionRequest?actionRequest,?ActionResponse?actionResponse)?????????throws?Exception?{??????????String?cmd?=?ParamUtil.getString(actionRequest,?Constants.CMD);??????????..?????????????else?if?(cmd.equals(Constants.ADD)?||?cmd.equals(Constants.UPDATE)?????????????????||?cmd.equals(Constants.UPDATE_AND_CHECKIN))?{??????????????????updateFileEntry(portletConfig,?actionRequest,?actionResponse);?????????????}?????????????..? ?
它會去調用updateFileEntry方法,這就是我們研究的重心:
protected?void?updateFileEntry(?????????????PortletConfig?portletConfig,?ActionRequest?actionRequest,?????????????ActionResponse?actionResponse)?????????throws?Exception?{??????????UploadPortletRequest?uploadPortletRequest?=?????????????PortalUtil.getUploadPortletRequest(actionRequest);??????????ThemeDisplay?themeDisplay?=?(ThemeDisplay)actionRequest.getAttribute(?????????????WebKeys.THEME_DISPLAY);??????????String?cmd?=?ParamUtil.getString(uploadPortletRequest,?Constants.CMD);??????????long?fileEntryId?=?ParamUtil.getLong(?????????????uploadPortletRequest,?"fileEntryId");??????????long?repositoryId?=?ParamUtil.getLong(?????????????uploadPortletRequest,?"repositoryId");?????????long?folderId?=?ParamUtil.getLong(uploadPortletRequest,?"folderId");?????????String?sourceFileName?=?uploadPortletRequest.getFileName("file");?????????String?title?=?ParamUtil.getString(uploadPortletRequest,?"title");?????????String?description?=?ParamUtil.getString(?????????????uploadPortletRequest,?"description");?????????String?changeLog?=?ParamUtil.getString(?????????????uploadPortletRequest,?"changeLog");?????????boolean?majorVersion?=?ParamUtil.getBoolean(?????????????uploadPortletRequest,?"majorVersion");??????????if?(folderId?>?0)?{?????????????Folder?folder?=?DLAppServiceUtil.getFolder(folderId);??????????????if?(folder.getGroupId()?!=?themeDisplay.getScopeGroupId())?{?????????????????throw?new?NoSuchFolderException();?????????????}?????????}??????????InputStream?inputStream?=?null;??????????try?{?????????????String?contentType?=?uploadPortletRequest.getContentType("file");??????????????long?size?=?uploadPortletRequest.getSize("file");??????????????if?(cmd.equals(Constants.ADD)?&&?(size?==?0))?{?????????????????contentType?=?MimeTypesUtil.getContentType(title);?????????????}??????????????if?(cmd.equals(Constants.ADD)?||?(size?>?0))?{?????????????????String?portletName?=?portletConfig.getPortletName();??????????????????if?(portletName.equals(PortletKeys.MEDIA_GALLERY_DISPLAY))?{?????????????????????String?portletResource?=?ParamUtil.getString(?????????????????????????actionRequest,?"portletResource");??????????????????????PortletPreferences?portletPreferences?=?null;??????????????????????if?(Validator.isNotNull(portletResource))?{?????????????????????????PortletPreferencesFactoryUtil.getPortletSetup(?????????????????????????????actionRequest,?portletResource);?????????????????????}?????????????????????else?{?????????????????????????portletPreferences?=?actionRequest.getPreferences();?????????????????????}??????????????????????String[]?mimeTypes?=?DLUtil.getMediaGalleryMimeTypes(?????????????????????????portletPreferences,?actionRequest);??????????????????????if?(Arrays.binarySearch(mimeTypes,?contentType)?<?0)?{?????????????????????????throw?new?FileMimeTypeException(contentType);?????????????????????}?????????????????}?????????????}??????????????inputStream?=?uploadPortletRequest.getFileAsStream("file");??????????????ServiceContext?serviceContext?=?ServiceContextFactory.getInstance(?????????????????DLFileEntry.class.getName(),?actionRequest);??????????????FileEntry?fileEntry?=?null;??????????????if?(cmd.equals(Constants.ADD))?{?????????????????if?(Validator.isNull(title))?{?????????????????????title?=?sourceFileName;?????????????????}????????????????????????????????????fileEntry?=?DLAppServiceUtil.addFileEntry(?????????????????????repositoryId,?folderId,?sourceFileName,?contentType,?title,?????????????????????description,?changeLog,?inputStream,?size,?serviceContext);??????????????????AssetPublisherUtil.addAndStoreSelection(?????????????????????actionRequest,?DLFileEntry.class.getName(),?????????????????????fileEntry.getFileEntryId(),?-1);?????????????}?????????????else?if?(cmd.equals(Constants.UPDATE_AND_CHECKIN))?{????????????????????????????????????fileEntry?=?DLAppServiceUtil.updateFileEntryAndCheckIn(?????????????????????fileEntryId,?sourceFileName,?contentType,?title,?????????????????????description,?changeLog,?majorVersion,?inputStream,?????????????????????size,?serviceContext);?????????????}?????????????else?{????????????????????????????????????fileEntry?=?DLAppServiceUtil.updateFileEntry(?????????????????????fileEntryId,?sourceFileName,?contentType,?title,?????????????????????description,?changeLog,?majorVersion,?inputStream,?????????????????????size,?serviceContext);?????????????}??????????????AssetPublisherUtil.addRecentFolderId(?????????????????actionRequest,?DLFileEntry.class.getName(),?folderId);?????????}?????????finally?{?????????????StreamUtil.cleanUp(inputStream);?????????}?????}? ?
從第06-27行就是從post的請求的payload中獲取一些參數信息,然后第29行對folderId進行判斷,因為我們的folderId為19604,它大于0,所以第30行用DLAppServiceUtil的方法獲取這個folder的實例,它最終會調用DLFolderLocalServiceImpl的getFolder(folderId)方法:
public?DLFolder?getFolder(long?folderId)?????????throws?PortalException,?SystemException?{??????????return?dlFolderPersistence.findByPrimaryKey(folderId);?????}? 這會發起一個數據庫的查詢,然后把查出來的結果封裝成DLFolder對象:
從這里看出來,這個folder就是我們昨天創建的名字叫"abcde"的folder.
?
然后從40行開始,正式對于這個文檔中的文件進行操作。先從40-72行做一些信息提取工作,然后從74行開始正式上傳文件,因為我們的cmd是“add",所以它會執行86-95行,我們詳細分析:
?
添加FileEntry:
第88-90行最終會調用DLAppServiceImpl類的addFileEntry方法:
public?FileEntry?addFileEntry(?????????????long?repositoryId,?long?folderId,?String?sourceFileName,?????????????String?mimeType,?String?title,?String?description,?String?changeLog,?????????????InputStream?is,?long?size,?ServiceContext?serviceContext)?????????throws?PortalException,?SystemException?{??????????if?(is?==?null)?{?????????????is?=?new?UnsyncByteArrayInputStream(new?byte[0]);?????????????size?=?0;?????????}??????????Repository?repository?=?getRepository(repositoryId);??????????FileEntry?fileEntry?=?repository.addFileEntry(?????????????folderId,?sourceFileName,?mimeType,?title,?description,?changeLog,?????????????is,?size,?serviceContext);??????????dlAppHelperLocalService.addFileEntry(?????????????getUserId(),?fileEntry,?fileEntry.getFileVersion(),?serviceContext);??????????return?fileEntry;?????}? 它一共做了2件事情:
?
事情1:
第14行-15行,它最終會調用DLFileEntryLocalServiceImpl類的addFileEntry方法:
public?DLFileEntry?addFileEntry(?????????????long?userId,?long?groupId,?long?repositoryId,?long?folderId,?????????????String?sourceFileName,?String?mimeType,?String?title,?????????????String?description,?String?changeLog,?long?fileEntryTypeId,?????????????Map<String,?Fields>?fieldsMap,?File?file,?InputStream?is,?long?size,?????????????ServiceContext?serviceContext)?????????throws?PortalException,?SystemException?{??????????if?((size?==?0)?&&?Validator.isNull(title))?{?????????????throw?new?FileNameException();?????????}????????????????????User?user?=?userPersistence.findByPrimaryKey(userId);?????????folderId?=?dlFolderLocalService.getFolderId(?????????????user.getCompanyId(),?folderId);?????????String?name?=?String.valueOf(?????????????counterLocalService.increment(DLFileEntry.class.getName()));?????????String?extension?=?getExtension(title,?sourceFileName);?????????fileEntryTypeId?=?getFileEntryTypeId(?????????????DLUtil.getGroupIds(groupId),?folderId,?fileEntryTypeId);?????????Date?now?=?new?Date();??????????validateFile(groupId,?folderId,?title,?extension,?file,?is);??????????long?fileEntryId?=?counterLocalService.increment();??????????DLFileEntry?dlFileEntry?=?dlFileEntryPersistence.create(fileEntryId);??????????dlFileEntry.setUuid(serviceContext.getUuid());?????????dlFileEntry.setGroupId(groupId);?????????dlFileEntry.setCompanyId(user.getCompanyId());?????????dlFileEntry.setUserId(user.getUserId());?????????dlFileEntry.setUserName(user.getFullName());?????????dlFileEntry.setVersionUserId(user.getUserId());?????????dlFileEntry.setVersionUserName(user.getFullName());?????????dlFileEntry.setCreateDate(serviceContext.getCreateDate(now));?????????dlFileEntry.setModifiedDate(serviceContext.getModifiedDate(now));?????????dlFileEntry.setRepositoryId(repositoryId);?????????dlFileEntry.setFolderId(folderId);?????????dlFileEntry.setName(name);?????????dlFileEntry.setExtension(extension);?????????dlFileEntry.setMimeType(mimeType);?????????dlFileEntry.setTitle(title);?????????dlFileEntry.setDescription(description);?????????dlFileEntry.setFileEntryTypeId(fileEntryTypeId);?????????dlFileEntry.setVersion(DLFileEntryConstants.VERSION_DEFAULT);?????????dlFileEntry.setSize(size);?????????dlFileEntry.setReadCount(DLFileEntryConstants.DEFAULT_READ_COUNT);??????????dlFileEntryPersistence.update(dlFileEntry,?false);????????????????????DLFileVersion?dlFileVersion?=?addFileVersion(?????????????user,?dlFileEntry,?serviceContext.getModifiedDate(now),?extension,?????????????mimeType,?title,?description,?null,?StringPool.BLANK,?????????????fileEntryTypeId,?fieldsMap,?DLFileEntryConstants.VERSION_DEFAULT,?????????????size,?WorkflowConstants.STATUS_DRAFT,?serviceContext);??????????dlFileEntry.setFileVersion(dlFileVersion);????????????????????if?(folderId?!=?DLFolderConstants.DEFAULT_PARENT_FOLDER_ID)?{?????????????dlFolderLocalService.updateLastPostDate(?????????????????dlFileEntry.getFolderId(),?dlFileEntry.getModifiedDate());?????????}????????????????????if?(file?!=?null)?{?????????????DLStoreUtil.addFile(?????????????????user.getCompanyId(),?dlFileEntry.getDataRepositoryId(),?name,?????????????????false,?file);?????????}?????????else?{?????????????DLStoreUtil.addFile(?????????????????user.getCompanyId(),?dlFileEntry.getDataRepositoryId(),?name,?????????????????false,?is);?????????}??????????return?dlFileEntry;?????}? 所以,總結來說就是(13-52行)在DLFILEENTRY表中添加一條記錄,代表了我們剛創建的文件:
然后(54-62行)在DLFILEVERSION表中添加一條記錄:
然后(64-69行)在DLFOLDER表中更新最新post提交的時間戳:
然后(73-82行)會添加這個我們被上傳的文件(比如 charles_wang.jpg), 如何添加呢?可以一直跟進直到DLStoreImpl類的addFile方法:
public?void?addFile(?????????????long?companyId,?long?repositoryId,?String?fileName,?????????????boolean?validateFileExtension,?File?file)?????????throws?PortalException,?SystemException?{??????????validate(fileName,?validateFileExtension,?file);??????????if?(PropsValues.DL_STORE_ANTIVIRUS_ENABLED)?{?????????????AntivirusScannerUtil.scan(file);?????????}??????????store.addFile(companyId,?repositoryId,?fileName,?file);?????}? 它首先會判斷是否開啟了store的病毒掃描機制,這個變量定義在portal.properties文件中:
???#?Set?this?property?to?true?to?enable?execution?of?antivirus?check?when????#?files?are?submitted?into?a?store.?Setting?this?value?to?true?will?prevent????#?any?potential?virus?files?from?entering?the?store?but?will?not?allow?for????#?file?quarantines.????#????dl.store.antivirus.enabled=false? 然后調用store的addFile方法,它會具體根據我們Store的實現來決定如何添加這個資源文件。
?那么我們的服務器上用的是什么樣的store呢?可以參見portal.properties中的定義:
#????#?Set?the?name?of?a?class?that?implements????#?com.liferay.portlet.documentlibrary.store.Store.?The????#?document?library?server?will?use?this?to?persist?documents.????#????#dl.store.impl=com.liferay.portlet.documentlibrary.store.AdvancedFileSystemStore????#dl.store.impl=com.liferay.portlet.documentlibrary.store.CMISStore????#dl.store.impl=com.liferay.portlet.documentlibrary.store.DBStore????dl.store.impl=com.liferay.portlet.documentlibrary.store.FileSystemStore????#dl.store.impl=com.liferay.portlet.documentlibrary.store.JCRStore????#dl.store.impl=com.liferay.portlet.documentlibrary.store.S3Store? ?
所以,我們會用FileSystemStore作為Store的實現,這也是默認的實現。
public?void?addFile(?????????????long?companyId,?long?repositoryId,?String?fileName,?InputStream?is)?????????throws?PortalException,?SystemException?{??????????try?{?????????????File?fileNameVersionFile?=?getFileNameVersionFile(?????????????????companyId,?repositoryId,?fileName,?VERSION_DEFAULT);??????????????if?(fileNameVersionFile.exists())?{?????????????????throw?new?DuplicateFileException(fileNameVersionFile.getPath());?????????????}??????????????FileUtil.write(fileNameVersionFile,?is);?????????}?????????catch?(IOException?ioe)?{?????????????throw?new?SystemException(ioe);?????????}?????}? 從調試信息上來看,它會先去獲取companyId,repositoryId,fileName等信息,最終File對象是服務器節點上一個帶版本號的url:
而被上傳的文件也被蓋頭換面了,居然在$tomcat_home/temp目錄下,而且名字叫upload_000010.jpg,我們在這個目錄下找,是我們所要上傳的文件:
?
所以,最終這個文件被保存到了D:\Liferay_Cluster_Enterprise\Node1\liferay-portal-tomcat-6.1.10-ee-ga1\liferay-portal-6.1.10-ee-ga1\data\document_library\1\16904\501 目錄下,并且文件名不再是charles_wang.png,而是就叫<version_number>.并且后面不帶擴展名了。我們比較這charles_wang.png和這個1.0文件的大小,發現他們是一致的(都是153kb),所以這說明文件已經被復制到了Liferay節點上。
?
進一步研究,如果不使用FileSystemStore會如何。我們在portal-ext.properties中把?dl.store.impl改為DBStore:
dl.store.impl=com.liferay.portlet.documentlibrary.store.DBStore? 它會去調用DBStore類的addFile代碼,最終會調用DBStore類的updateFile代碼:
public?void?updateFile(?????????????long?companyId,?long?repositoryId,?String?fileName,?????????????String?versionLabel,?File?file)?????????throws?PortalException,?SystemException?{??????????if?(DLContentLocalServiceUtil.hasContent(?????????????????companyId,?repositoryId,?fileName,?versionLabel))?{??????????????throw?new?DuplicateFileException(fileName);?????????}??????????InputStream?inputStream?=?null;??????????try?{??????????????inputStream?=?new?FileInputStream(file);?????????}?????????catch?(FileNotFoundException?fnfe)?{?????????????throw?new?SystemException(fnfe);?????????}??????????DLContentLocalServiceUtil.addContent(?????????????companyId,?repositoryId,?fileName,?versionLabel,?inputStream,?????????????file.length());?????}? 它最終會調用DLContentLocalServiceImpl的addContent方法:
public?DLContent?addContent(?????????????long?companyId,?long?repositoryId,?String?path,?String?version,?????????????InputStream?inputStream,?long?size)?????????throws?SystemException?{??????????try?{?????????????long?contentId?=?counterLocalService.increment();??????????????DLContent?dlContent?=?dlContentPersistence.create(contentId);??????????????dlContent.setCompanyId(companyId);?????????????dlContent.setRepositoryId(repositoryId);?????????????dlContent.setPath(path);?????????????dlContent.setVersion(version);??????????????OutputBlob?dataOutputBlob?=?new?OutputBlob(inputStream,?size);??????????????dlContent.setData(dataOutputBlob);??????????????dlContent.setSize(size);??????????????dlContentPersistence.update(dlContent,?false);??????????????return?dlContent;?????????}?????????finally?{?????????????StreamUtil.cleanUp(inputStream);?????????}?????}? 從這里我們可以很清楚的看到,它會吧這個文件的內容以Blob的形式保存,然后連同companyId,repositoryId,version等信息一起寫在DLCONTENT數據庫表中:
我們復制上述動作時候,不幸發生了如下的異常:
Caused?by:?java.lang.ClassCastException:?com.liferay.portal.kernel.dao.jdbc.OutputBlob?cannot?be?cast?to?oracle.sql.BLOB?????at?oracle.jdbc.driver.OraclePreparedStatement.setBlob(OraclePreparedStatement.java:6663)?????at?oracle.jdbc.driver.OraclePreparedStatementWrapper.setBlob(OraclePreparedStatementWrapper.java:128)? 從http://issues.liferay.com/browse/LPS-26375上我找到了解決方法,就是修改portal-hbm.xml文件,然后把類型配置正確就可以了:
<class?name="com.liferay.portlet.documentlibrary.model.DLContentDataBlobModel"?table="DLContent"?lazy="true">?????????<id?name="contentId"?column="contentId">?????????????<generator?class="foreign">?????????????????<param?name="property">com.liferay.portlet.documentlibrary.model.impl.DLContentImpl</param>?????????????</generator>?????????</id>?????????<property?column="data_"?name="dataBlob"?type="org.hibernate.type.BlobType"?/>?????</class>? ?把這里的dataBlob的type改為java.sql.Blob就可以了。
為此,我們新建一個文件叫portal-hbm-new.xml,讓其復制portal-hbm.xml的所有內容,除了dataBlob的type改為java.sql.Blob。
然后我們在portal-ext.properties中添加如下行,讓hibernate映射文件指向我們新建的這個文件:
#added?by?charles?to?fix?the?dbStore?problem?,use?the?new?portal?hibernate?mapping?file???hibernate.configs=\?????????META-INF/mail-hbm.xml,\?????????META-INF/portal-hbm-new.xml,\?????????META-INF/ext-hbm.xml? ?這樣,我們就上傳成功了:
我們檢查數據庫,在DLCONTENT表中果然找到了blob形式存在的圖片:
?
事情2:
第18行-19行,它最終會調用DLAppHelperLocalServiceImpl的addFileEntry方法,具體不展開了,結論就是,它會在AssetEntry數據庫表中添加一條記錄:
?
到此,我們全部分析完了。
?
轉載于:https://blog.51cto.com/supercharles888/921761
總結
以上是生活随笔為你收集整理的Liferay 控制面板在指定文件夹添加Basic Document流程分析的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。