结论:
theme上传logo会做以下事情:
(1)用UploadPortletRequest对象来处理页面的<input type=file>
(2)对于上传的logo图片为空,则抛出异常。
(3)对于上传的logo图片不为空,则先从数据库中找到当前layout,为logo定义logoId,并吧logoId添加到当前layout并存回数据库,然后根据布尔变量设定,来决定是否吧这个logo关联到hook,以及这个这个logo图片是否要持久化。
过程展示:
当在Liferay中的某个theme选择上传logo,并点击"save"按钮:
如下所示
具体分析:
它会去触发struts动作/group_pages/edit_layout_set,我们在struts-config.xml中找到匹配选项:
- <action path="/group_pages/edit_layout_set" type="com.liferay.portlet.layoutsadmin.action.EditLayoutSetAction">
- <forward name="portlet.layouts_admin.edit_layouts" path="portlet.layouts_admin.edit_layouts" />
- <forward name="portlet.layouts_admin.error" path="portlet.layouts_admin.error" />
- </action>
可以发现,它对应的动作类是EditLayoutSetAction类的updateLogo方法:
- protected void updateLogo(
- ActionRequest actionRequest, long liveGroupId,
- long stagingGroupId, boolean privateLayout, boolean hasLogo)
- throws Exception {
- UploadPortletRequest uploadPortletRequest =
- PortalUtil.getUploadPortletRequest(actionRequest);
- boolean useLogo = ParamUtil.getBoolean(actionRequest, "useLogo");
- InputStream inputStream = null;
- try {
- File file = uploadPortletRequest.getFile("logoFileName");
- if (useLogo && !file.exists()) {
- if (hasLogo) {
- return;
- }
- throw new UploadException("No logo uploaded for use");
- }
- if (file.exists()) {
- inputStream = new ByteArrayFileInputStream(file, 1024);
- }
- if (inputStream != null) {
- inputStream.mark(0);
- }
- LayoutSetServiceUtil.updateLogo(
- liveGroupId, privateLayout, useLogo, inputStream, false);
- if (inputStream != null) {
- inputStream.reset();
- }
- if (stagingGroupId > 0) {
- LayoutSetServiceUtil.updateLogo(
- stagingGroupId, privateLayout, useLogo, inputStream, false);
- }
- }
- finally {
- StreamUtil.cleanUp(inputStream);
- }
- }
这个方法我们仔细分析:
首先,在06行和14行定义了一个UploadPortletRequest对象,这个对象可以用来处理文件上传的操作,也就是从图示的文件上传控件中上传文件,因为上传文件的<input type="file",name="logoFileName",所以我们在14行uploadPortletRequest.getFile(fileName)就可以取得我们所上传的文件,也就是我们上传的图标。
然后第16-22行对于File对象为空进行了处理,这种情况下也就是没有上传任何文件就点了“save”,所以就会抛出没有logo的异常。
第24行,对于这个图标,我们打开一个字节文件输入流指向这个图标文件,然后调用32行的LayoutSetServiceUtil的updateLogo方法来更新图标,我们继续跟进:
可以发现它最终调用的是LayoutSetServiceImpl的updateLogo方法:
- public void updateLogo(
- long groupId, boolean privateLayout, boolean logo,
- InputStream inputStream, boolean cleanUpStream)
- throws PortalException, SystemException {
- GroupPermissionUtil.check(
- getPermissionChecker(), groupId, ActionKeys.UPDATE);
- layoutSetLocalService.updateLogo(
- groupId, privateLayout, logo, inputStream, cleanUpStream);
- }
它先去检查这个update动作的permission,然后在去调用LayoutSetLocalService的updateLogo方法,其最终是调用LayoutSetLocalServiceImpl的updateLogo方法:
- public void updateLogo(
- long groupId, boolean privateLayout, boolean logo, InputStream is,
- boolean cleanUpStream)
- throws PortalException, SystemException {
- LayoutSet layoutSet = layoutSetPersistence.findByG_P(
- groupId, privateLayout);
- layoutSet.setModifiedDate(new Date());
- layoutSet.setLogo(logo);
- if (logo) {
- long logoId = layoutSet.getLogoId();
- if (logoId <= 0) {
- logoId = counterLocalService.increment();
- layoutSet.setLogoId(logoId);
- }
- }
- layoutSetPersistence.update(layoutSet, false);
- if (logo) {
- imageLocalService.updateImage(
- layoutSet.getLogoId(), is, cleanUpStream);
- }
- else {
- imageLocalService.deleteImage(layoutSet.getLogoId());
- }
- }
从这里可以看出,它会先从数据库中读取当前LayoutSet,然后把logo的对应logoId添加到layoutSet中,然后把这个layoutSet写回数据库中。最后它根据bool变量logo ,来决定是否吧这个logo对应的Image写入数据库和绑定hook.