?
結(jié)論:
當(dāng)在Liferay中用管理員登錄,導(dǎo)航到控制面板->Documents and Media ,在指定文件夾下添加BasicDocument時(shí),服務(wù)器做了如下的事情:
(1) 在DLFILEENTRY表中添加一條記錄代表被添加的文檔。
(2) 在DLFILEENTRYVERSION表中添加一條記錄,通過fileEntryId外鍵關(guān)聯(lián)到DLFILEENTRY表,用來記錄剛被添加文檔的版本信息。
(3)?在DLFOLDER表中更新最新post提交的時(shí)間戳。
(4) 根據(jù)服務(wù)器對于com.liferay.portlet.documentlibrary.store的具體實(shí)現(xiàn)的不同,先對文件進(jìn)行病毒掃描(在portal.properties 中有開關(guān)),然后把上傳的資源文件存入到Store的某個(gè)具體位置。
Store有5種實(shí)現(xiàn),我至少可以保證,如果用的是FileSystemStore,那么這個(gè)資源文件被放入$liferay_home/data/document_library目錄,并且最終文件名不再是上傳的文件名,而是<version_number>.如果使用的是DBStore,那么這個(gè)資源文件最終會(huì)被放在數(shù)據(jù)庫中DLCONTENT表中,并且資源文件(比如圖片)以BLOB的形式存儲(chǔ)。
(5)在ASSETENTRY表中添加一條記錄,它通過classpk外鍵關(guān)聯(lián)到DLFILEENTRY,因?yàn)镕ile也是一種資產(chǎn),所以必須在這張表中也留下記錄。
?
?
具體分析:
?Liferay控制面板中,當(dāng)創(chuàng)建了文件夾,然后要在其中添加某個(gè)Basic Document:
?
查看瀏覽器debug信息:
可以發(fā)現(xiàn),它調(diào)用的struts_action為/document_library/edit_file_entry
?
我們?nèi)?strong>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>? 可以發(fā)現(xiàn), 它會(huì)forward到portlet.document_library.edit_file_entry的路徑名下找頁面:
我們?nèi)?strong>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>? ?
所以,它最終會(huì)訪問/portlet/document_library/edit_file_entry.jsp頁面:
這個(gè)頁面會(huì)吧你剛才選擇的目錄列出來,比如我們剛才選擇了abcde目錄,那么在這里,它就會(huì)顯示出來:
對應(yīng)的顯示代碼是
<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>? 然后,它會(huì)有一個(gè)文件上傳框:
<aui:input?name="file"?type="file">?????????????<aui:validator?name="acceptFiles">?????????????????'<%=?StringUtil.merge(PrefsPropsUtil.getStringArray(PropsKeys.DL_FILE_EXTENSIONS,?StringPool.COMMA))?%>'?????????????</aui:validator>?????????</aui:input>? 它會(huì)通過aui框架的校驗(yàn)器來校驗(yàn)被上傳的文件擴(kuò)展名和大小。
輸入文件標(biāo)題和正文的部分我就略過了,不是重點(diǎn),我們現(xiàn)在想關(guān)注的是,到底當(dāng)點(diǎn)擊最下方的"Publish"按鈕時(shí)發(fā)生了什么。
?
深入分析點(diǎn)擊"Publish"按鈕后發(fā)生的事情
對應(yīng)的代碼是:
<aui:button?disabled="<%=?checkedOut?&&?!hasLock?||?(pending?&&?PropsValues.DL_FILE_ENTRY_DRAFTS_ENABLED)?%>"?name="publishButton"?type="submit"?value="<%=?publishButtonLabel?%>"?/>? 它會(huì)吧整個(gè)表單提交,對應(yīng)代碼是:
<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?%>"?/>?..? 而因?yàn)橛胮ost提交,所以這些信息都在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:
因?yàn)槲覀兊腸md是add,所以它會(huì)走以下流程:
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);?????????????}?????????????..? ?
它會(huì)去調(diào)用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中獲取一些參數(shù)信息,然后第29行對folderId進(jìn)行判斷,因?yàn)槲覀兊?strong>folderId為19604,它大于0,所以第30行用DLAppServiceUtil的方法獲取這個(gè)folder的實(shí)例,它最終會(huì)調(diào)用DLFolderLocalServiceImpl的getFolder(folderId)方法:
public?DLFolder?getFolder(long?folderId)?????????throws?PortalException,?SystemException?{??????????return?dlFolderPersistence.findByPrimaryKey(folderId);?????}? 這會(huì)發(fā)起一個(gè)數(shù)據(jù)庫的查詢,然后把查出來的結(jié)果封裝成DLFolder對象:
從這里看出來,這個(gè)folder就是我們昨天創(chuàng)建的名字叫"abcde"的folder.
?
然后從40行開始,正式對于這個(gè)文檔中的文件進(jìn)行操作。先從40-72行做一些信息提取工作,然后從74行開始正式上傳文件,因?yàn)槲覀兊腸md是“add",所以它會(huì)執(zhí)行86-95行,我們詳細(xì)分析:
?
添加FileEntry:
第88-90行最終會(huì)調(diào)用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行,它最終會(huì)調(diào)用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;?????}? 所以,總結(jié)來說就是(13-52行)在DLFILEENTRY表中添加一條記錄,代表了我們剛創(chuàng)建的文件:
然后(54-62行)在DLFILEVERSION表中添加一條記錄:
然后(64-69行)在DLFOLDER表中更新最新post提交的時(shí)間戳:
然后(73-82行)會(huì)添加這個(gè)我們被上傳的文件(比如 charles_wang.jpg), 如何添加呢?可以一直跟進(jìn)直到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);?????}? 它首先會(huì)判斷是否開啟了store的病毒掃描機(jī)制,這個(gè)變量定義在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? 然后調(diào)用store的addFile方法,它會(huì)具體根據(jù)我們Store的實(shí)現(xiàn)來決定如何添加這個(gè)資源文件。
?那么我們的服務(wù)器上用的是什么樣的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? ?
所以,我們會(huì)用FileSystemStore作為Store的實(shí)現(xiàn),這也是默認(rèn)的實(shí)現(xiàn)。
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);?????????}?????}? 從調(diào)試信息上來看,它會(huì)先去獲取companyId,repositoryId,fileName等信息,最終File對象是服務(wù)器節(jié)點(diǎn)上一個(gè)帶版本號的url:
而被上傳的文件也被蓋頭換面了,居然在$tomcat_home/temp目錄下,而且名字叫upload_000010.jpg,我們在這個(gè)目錄下找,是我們所要上傳的文件:
?
所以,最終這個(gè)文件被保存到了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>.并且后面不帶擴(kuò)展名了。我們比較這charles_wang.png和這個(gè)1.0文件的大小,發(fā)現(xiàn)他們是一致的(都是153kb),所以這說明文件已經(jīng)被復(fù)制到了Liferay節(jié)點(diǎn)上。
?
進(jìn)一步研究,如果不使用FileSystemStore會(huì)如何。我們在portal-ext.properties中把?dl.store.impl改為DBStore:
dl.store.impl=com.liferay.portlet.documentlibrary.store.DBStore? 它會(huì)去調(diào)用DBStore類的addFile代碼,最終會(huì)調(diào)用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());?????}? 它最終會(huì)調(diào)用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);?????????}?????}? 從這里我們可以很清楚的看到,它會(huì)吧這個(gè)文件的內(nèi)容以Blob的形式保存,然后連同companyId,repositoryId,version等信息一起寫在DLCONTENT數(shù)據(jù)庫表中:
我們復(fù)制上述動(dòng)作時(shí)候,不幸發(fā)生了如下的異常:
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就可以了。
為此,我們新建一個(gè)文件叫portal-hbm-new.xml,讓其復(fù)制portal-hbm.xml的所有內(nèi)容,除了dataBlob的type改為java.sql.Blob。
然后我們在portal-ext.properties中添加如下行,讓hibernate映射文件指向我們新建的這個(gè)文件:
#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? ?這樣,我們就上傳成功了:
我們檢查數(shù)據(jù)庫,在DLCONTENT表中果然找到了blob形式存在的圖片:
?
事情2:
第18行-19行,它最終會(huì)調(diào)用DLAppHelperLocalServiceImpl的addFileEntry方法,具體不展開了,結(jié)論就是,它會(huì)在AssetEntry數(shù)據(jù)庫表中添加一條記錄:
?
到此,我們?nèi)糠治鐾炅恕?/p>
?
轉(zhuǎn)載于:https://blog.51cto.com/supercharles888/921761
總結(jié)
以上是生活随笔為你收集整理的Liferay 控制面板在指定文件夹添加Basic Document流程分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。