2021SC@SDUSC # 软件工程应用与实践——OpenMeetings项目分析(九):

2021SC@SDUSC

软件工程应用与实践——OpenMeetings项目分析(九):

本周进行web包目录下的common包下剩余类的分析;

image-20211126210503780

之前的博客已经分析完了tree包以及menu包下的代码,因此上图中单独的java类都是结下来要分析的内容,由于类较多,同时web包下还有许多其他子包需要分析,因此仅对上图中有代表性的几个类进行分析;

本周从上面的具有继承关系的一系列类进行分析;

BasePanel.java

package org.apache.openmeetings.web.common;

import org.apache.openmeetings.db.util.FormatHelper;
import org.apache.openmeetings.web.app.WebSession;
import org.apache.openmeetings.web.common.menu.MenuPanel;
import org.apache.openmeetings.web.pages.BasePage;
import org.apache.openmeetings.web.pages.MainPage;
import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;

import com.github.openjson.JSONObject;

public abstract class BasePanel extends Panel {
	private static final long serialVersionUID = 1L;
	public static final String EVT_CLICK = "click";
	protected static final String BASE_ROW_CLASS = "ui-widget-content";
	protected static final String ROW_CLASS = BASE_ROW_CLASS + " clickable";

	public BasePanel(String id) {
		super(id);
		setOutputMarkupId(true);
	}

	public BasePanel(String id, IModel<?> model) {
		super(id, model);
		setOutputMarkupId(true);
	}

	public BasePage getBasePage() {
		return (BasePage)getPage();
	}

	public MainPanel getMainPanel() {
		return findParent(MainPanel.class);
	}

	protected boolean isRtl() {
		return FormatHelper.isRtlLanguage(WebSession.get().getLocale().toLanguageTag());
	}

	/**
	 * Overwrite this method to execute Java code after Panel is loaded by the
	 * {@link MenuPanel}
	 *
	 * @param handler - request handler to update menu
	 * @return - this for chaining
	 */
	public BasePanel onMenuPanelLoad(IPartialPageRequestHandler handler) {
		handler.add(getBasePage().getHeader().setVisible(true), getMainPanel().getMenu().setVisible(true)
				, getMainPanel().getTopLinks().setVisible(true)
				, ((MainPage)getPage()).getLoader().setVisible(false));
		return this;
	}

	/**
	 * This method should be overridden to perform necessary cleanup: remove timers etc.
	 *
	 * @param handler - request handler to perform cleanup
	 */
	public void cleanup(IPartialPageRequestHandler handler) {
	}

	/**
	 * This method should be overridden to perform after "new message" dialog was closed.
	 *
	 * @param handler - request handler to perform action after "new message" dialog was closed.
	 */
	public void onNewMessageClose(IPartialPageRequestHandler handler) {
	}

	/**
	 * Handler for WebSocket messages
	 *
	 * @param handler - handler to perform update
	 * @param o - message to process
	 */
	protected void process(IPartialPageRequestHandler handler, JSONObject o) {
	}
}

BasePanel是一个继承自Panel类的抽象类,结构如下:

image-20211126212744097

BasePanel构造方法:包括两个构造方法无返回值,通过参数列表进行区分;形参为:用来初始化类的实例,但是由于是抽象类不能实例化,因此这个构造方法大概率是被其子类利用super进行调用,达到了一次编写,多次复用的目的;

getBasePage方法:利用org.apache.wicket.Component 的getPage()方法经强转为BasePanel后直接返回;

getMainPanel方法:利用org.apache.wicket.Component 的findParent()方法传入参数为mainpanel.class后直接返回;

isRtl方法:调用org.apache.openmeetings.db.util包下的FormatHelper里的isRtlLanguage方法判断是否是RTL语言,返回值为bollean对象;

​ 代码文档:

​ 检查 BCP 47 / III 语言代码是否表示 RTL 语言,即: - 明确指定从右到左脚本之一的语言代码,例如“az-Arab”,或一种语言代码,指定通常以从右 到左的脚本编写的语言之一,例如“fa”(波斯语),但明确指定拉丁文或西里尔文脚本(这是通常的 LTR 替代方案)的语言代码除外。从右到左的脚 本列表出现在 http://www.unicode.org/iso15924/iso15924-num.html 中的 100-199 范围内,其中阿拉伯语和希伯来语是迄今为止使用最广泛的。 我们还认识 Thaana、N’Ko 和 Tifinagh,它们也具有重要的现代用法。 其余的(叙利亚语、撒玛利亚语、曼达语等)似乎极其有限或没有现代用法 并且不被认可。 通常以从右到左脚本编写的语言被视为带有抑制脚本的语言:http://www.iana.org/assignments/language-subtag-registry 中的 Hebr|Arab|Thaa|Nkoo|Tfng,如以及信德语(sd)和维吾尔语(ug)。 语言代码的其他子标签的存在,例如像 EG(埃及)这样的地区,将被忽 略

onMenuPanelLoad方法:在MenuPanel加载Panel后覆盖此方法执行Java代码,形参:handler - - 请求处理程序更新菜单,返回值:BasePanel这用于链接;

cleanup方法:应该重写此方法以执行必要的清理:删除计时器等。形参:handler – 请求处理程序执行清理;

onNewMessageClose方法:在“新消息”对话框关闭后,应重写此方法以执行。形参:处理程序——请求处理程序在“新消息”对话框关闭后执行操作。

process方法:针对 WebSocket 消息的行为,参数:handler - - 执行更新的处理程序,o - - 要处理的消息;

UserBasePanel.java

package org.apache.openmeetings.web.common;

import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation;
import org.apache.wicket.model.IModel;

@AuthorizeInstantiation("Dashboard")
public abstract class UserBasePanel extends BasePanel {
	private static final long serialVersionUID = 1L;

	public UserBasePanel(String id) {
		super(id);
	}

	public UserBasePanel(String id, IModel<?> model) {
		super(id, model);
	}
}

此类继承自BasePanel类,利用super调用父类构造方法用来实例化对象,但是同样是抽象类,因此也是供其子类进行super的调用;

ImagePanel.java

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License") +  you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.openmeetings.web.common;

import static org.apache.openmeetings.util.OpenmeetingsVariables.ATTR_TITLE;
import static org.apache.openmeetings.util.OpenmeetingsVariables.PARAM_SRC;

import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.markup.html.TransparentWebMarkupContainer;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.panel.Panel;

public abstract class ImagePanel extends Panel {
	private static final long serialVersionUID = 1L;
	protected final WebMarkupContainer profile = new TransparentWebMarkupContainer("profile");

	public ImagePanel(String id) {
		super(id);
		add(profile.setOutputMarkupId(true));
	}

	@Override
	protected void onInitialize() {
		super.onInitialize();
		update();
	}

	protected abstract String getImageUrl();

	protected String getTitle() {
		return getString("5");
	}

	protected Component getImage() {
		return new WebMarkupContainer("img").add(
				AttributeModifier.append("alt", getTitle())
				, AttributeModifier.append(ATTR_TITLE, getTitle())
				, AttributeModifier.append(PARAM_SRC, getImageUrl()));
	}

	public void update() {
		profile.addOrReplace(getImage());
	}
}

image-20211126223909711

ImagePanel继承自Panel类,结构如上;

构造方法:调用父类构造方法,用来实例化对象;

onInitialize方法:定义了一些初始化imagePanel对象是所要执行的一系列操作,利用super调用父类的同名方法,然后执行成员方法update更新面板状态;

getImageUrl方法:抽象方法,用以给子类去实现

getTitle方法:返回org.apache.wicket.Component类的getString的String类型的结果;

getImage方法:返回一个WebMarkupContainer类型的对象,并调用此对象的add方法,传入三个AttributeModifier类型的参数,对这三个参数对象调用append方法,添加关于getTitle方法以及getImageUrl方法的属性名等详细信息;

update方法:形参为空,返回值为空,用以更新本类实例化的对象的状态,调用成员变量profile的addOrReplace方法,根据getImage方法得到的Component数组每个元素的id是否为空,决定去替换还是增加一个子项目;

UploadableImagePanel.java

package org.apache.openmeetings.web.common;

import static org.apache.openmeetings.util.OpenmeetingsVariables.getMaxUploadSize;
import static org.apache.openmeetings.util.OpenmeetingsVariables.getWebAppRootKey;

import java.io.File;
import java.util.Optional;

import org.apache.openmeetings.util.StoredFile;
import org.apache.openmeetings.web.util.upload.BootstrapFileUploadBehavior;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormSubmitBehavior;
import org.apache.wicket.extensions.ajax.markup.html.form.upload.UploadProgressBar;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.upload.FileUpload;
import org.apache.wicket.markup.html.form.upload.FileUploadField;
import org.apache.wicket.model.util.ListModel;
import org.apache.wicket.util.lang.Bytes;
import org.red5.logging.Red5LoggerFactory;
import org.slf4j.Logger;

public abstract class UploadableImagePanel extends ImagePanel {
	private static final long serialVersionUID = 1L;
	private static final Logger log = Red5LoggerFactory.getLogger(UploadableImagePanel.class, getWebAppRootKey());
	private static final String HOVER = "$('.profile .ui-button-icon.ui-icon.ui-icon-closethick.remove').hover(function (e) {$(this).toggleClass('ui-widget-content', e.type === 'mouseenter');});";
	private final FileUploadField fileUploadField = new FileUploadField("image", new ListModel<FileUpload>());
	private final Form<Void> form = new Form<>("form");
	private final boolean delayed;

	public UploadableImagePanel(String id, boolean delayed) {
		super(id);
		this.delayed = delayed;
	}

	protected abstract void processImage(StoredFile sf, File f) throws Exception;

	protected abstract void deleteImage() throws Exception;

	@Override
	protected void onInitialize() {
		super.onInitialize();
		form.setMultiPart(true);
		form.setMaxSize(Bytes.bytes(getMaxUploadSize()));
		// Model is necessary here to avoid writing image to the User object
		form.add(fileUploadField);
		form.add(new UploadProgressBar("progress", form, fileUploadField));
		form.addOrReplace(getImage());
		if (delayed) {
			add(new WebMarkupContainer("remove").add(AttributeModifier.append("onclick"
					, String.format("$(this).parent().find('.fileinput').fileinput('clear');", form.getMarkupId()))));
		} else {
			add(new ConfirmableAjaxBorder("remove", getString("80"), getString("833")) {
				private static final long serialVersionUID = 1L;

				@Override
				protected void onSubmit(AjaxRequestTarget target) {
					try {
						deleteImage();
					} catch (Exception e) {
						log.error("Error", e);
					}
					update(Optional.of(target));
				}
			});
			fileUploadField.add(new AjaxFormSubmitBehavior(form, "change") {
				private static final long serialVersionUID = 1L;

				@Override
				protected void onSubmit(AjaxRequestTarget target) {
					process(Optional.of(target));
				}
			});
		}
		add(form.setOutputMarkupId(true));
		add(BootstrapFileUploadBehavior.INSTANCE);
	}

	@Override
	public void renderHead(IHeaderResponse response) {
		super.renderHead(response);
		response.render(OnDomReadyHeaderItem.forScript(HOVER));
	}

	@Override
	public void update() {
		profile.addOrReplace(new WebMarkupContainer("img").setVisible(false));
		form.addOrReplace(getImage());
	}

	private void update(Optional<AjaxRequestTarget> target) {
		update();
		target.ifPresent(t -> {
			t.add(profile, form);
			t.appendJavaScript(HOVER);
		});
	}

	public void process(Optional<AjaxRequestTarget> target) {
		FileUpload fu = fileUploadField.getFileUpload();
		if (fu != null) {
			File temp = null;
			try {
				temp = fu.writeToTempFile();
				StoredFile sf = new StoredFile(fu.getClientFileName(), temp);
				if (sf.isImage()) {
					processImage(sf, temp);
				}
			} catch (Exception e) {
				log.error("Error", e);
			} finally {
				if (temp != null && temp.exists()) {
					log.debug("Temp file was deleted ? {}", temp.delete());
				}
				fu.closeStreams();
				fu.delete();
			}
		}
		update(target);
	}
}

结构如图所示:

image-20211127194121844

此类继承自ImagePanel类,同样是抽象类,主要用于定义可上传图像的面板的相关操作的方法;

构造方法 :形参为String id, boolean delayed,作用为实例化对象,代码先用super调用了弗雷德构造方法然后给成员变量赋值;

processImage方法,deleteImage方法:抽象方法,定义一个模板留给子类去实现;

onInitiallze方法:形参返回值都为空,定义了一些初始化对象时要执行的操作,先是用super调用父类的同名方法,然后给成员变量form用一些set以及add方法添加属性;然后根据delayed成员变量的值,为真的话,调用org.apache.wicket.MarkupContainer的add方法,传入参数为WebMarkupContainer类型的对象,如果为假,则参数为ConfirmableAjaxBorder类型的对象,最后用add方法添加form变量以及BootstrapFileUploadBehavior的一个常量;

renderHead方法:形参为IHeaderResponse response,返回值为空,作用为渲染组件的头部,先调用父类的同名方法,然后传参OnDomReadyHeaderItem.forScript(HOVER)通过response对象的方法进行渲染;

update方法:形参返回值都为空,作用为更新面板状态,调用成员函数profile以及form的AddOrReplace方法,并传入WebMarkupContainer对象,以及getImage方法得到的Component对象,通过条件判断是用替换还是增加进行更新面板状态;此函数有一个通过参数列表构成的重载,利用了java8的lamda表达式,其中使用了ifpresent方法,作用为如果存在值(target不为空),则使用该值调用指定的使用者,否则不执行任何操作。

process方法:定义了用于处理上传图像的过程时后端需要执行的操作,通过fileUploadField成员变量的getFileUpload方法得到FileUpload对象,进一步取得客户端的文件类型判断是否为图像,是的话执行上传过程,同时catch定义了捕获到exception时需要执行的操作,最后进行面板的更新操作以刷新;

UploadableProfileImagePanel.java

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License") +  you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.openmeetings.web.common;

import static org.apache.openmeetings.util.OmFileHelper.EXTENSION_PNG;
import static org.apache.openmeetings.util.OmFileHelper.PROFILE_FILE_NAME;
import static org.apache.openmeetings.util.OmFileHelper.getUploadProfilesUserDir;
import static org.apache.openmeetings.web.app.Application.getBean;
import static org.apache.openmeetings.web.util.ProfileImageResourceReference.getUrl;

import java.io.File;

import org.apache.openmeetings.core.converter.ImageConverter;
import org.apache.openmeetings.util.OmFileHelper;
import org.apache.openmeetings.util.StoredFile;

public class UploadableProfileImagePanel extends UploadableImagePanel {
	private static final long serialVersionUID = 1L;
	private final long userId;

	public UploadableProfileImagePanel(String id, final long userId) {
		super(id, false);
		this.userId = userId;
	}

	@Override
	protected void processImage(StoredFile sf, File f) throws Exception {
		getBean(ImageConverter.class).convertImageUserProfile(f, userId, sf.isAsIs());
	}

	@Override
	protected void deleteImage() throws Exception {
		File f = new File(getUploadProfilesUserDir(userId), OmFileHelper.getName(PROFILE_FILE_NAME, EXTENSION_PNG));
		if (f.exists()) {
			f.delete();
		}
	}

	@Override
	protected String getImageUrl() {
		return getUrl(getRequestCycle(), userId);
	}
}

image-20211127204849459

此类继承自上一个类,不再是抽象类,重写了父类的几个方法,是可上传的个人资料图片面板 的类;

构造方法:利用super调用父类构造方法,同时给成员变量userid赋值;

processImage方法:形参为StoredFile sf, File f,返回值为空,作用诶处理要上传的图像,利用getBean方法取得ImageConverter的实例后进行convertImageUserProfile的调用用于转换图像用户配置文件;

deleteImage方法:用于删除已经上传的图片文件,首先获取上传配置文件用户目录,并根据取得的name创建一个file实例,然后判断不为空的话执行删除操作;

getImageUrl方法:返回值为字符串类型,直接根据请求中要获取图片的名字返回其url;

image-20211127205751254

总结:本周分析完了具有继承关系的这几个类,即图片中的红方框内,由于profileimagepanle就是一个简单的面板类,方法仅有一个,代码量较少,就没再分析,下周开始,对单个类逐一进行分析;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HiddenWorld

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值