2021SC@SDUSC
软件工程应用与实践——OpenMeetings项目分析(十):
上周分析了如下图红框内的具有继承关系的类,本周选择几个独立的类进行分析 ;
OmAjaxClientInfoBehavior
package org.apache.openmeetings.web.common;
import java.util.List;
import org.apache.openmeetings.web.app.WebSession;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxClientInfoBehavior;
import org.apache.wicket.markup.head.HeaderItem;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
import org.apache.wicket.markup.head.PriorityHeaderItem;
import org.apache.wicket.markup.html.pages.BrowserInfoForm;
import org.apache.wicket.protocol.http.request.WebClientInfo;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.resource.JavaScriptResourceReference;
public class OmAjaxClientInfoBehavior extends AjaxClientInfoBehavior {
private static final long serialVersionUID = 1L;
private static final JavaScriptResourceReference MAIN_JS = new JavaScriptResourceReference(MainPanel.class, "main.js") {
private static final long serialVersionUID = 1L;
@Override
public List<HeaderItem> getDependencies() {
List<HeaderItem> list = super.getDependencies();
list.add(JavaScriptHeaderItem.forReference(BrowserInfoForm.JS));
return list;
}
};
@Override
public void renderHead(Component component, IHeaderResponse response) {
super.renderHead(component, response);
response.render(new PriorityHeaderItem(JavaScriptHeaderItem.forReference(MAIN_JS)));
}
@Override
protected WebClientInfo newWebClientInfo(RequestCycle requestCycle) {
return new WebClientInfo(requestCycle, WebSession.get().getExtendedProperties());
}
}
此类继承自AjaxClientInfoBehavior类,定义了一些Ajax 客户端信息行为相关的方法的类;
首选是类的结构:
没有定义无参构造方法,初始化此类对象的时候应该去调用父类的无参构造方法;
new成员变量MAIN_JS的时候,还重写了一个成员方法,getDependencies,通过调用父类的getDependencies方法,并在list后面添加浏览器的headeriteam的相关信息,然后作为结果返回;
renderHead方法:形参Component component, IHeaderResponse response,返回值为空,作用是头部渲染,首先调用父类的同名方法,然后调用response的render方法,并传入一个代理项目类PriorityHeaderItem的对象进行渲染;
newWebClientInfo方法:返回值为WebClientInfo类型,形参为RequestCycle requestCycle,作用为返回一个新建的web客户端信息,代码中直接返回了一个利用传入参数以及WebSession取到的某些属性构造的一个新的WebClientInfo对象;
ConfirmableAjaxBorder
package org.apache.openmeetings.web.common;
import static org.apache.openmeetings.web.common.BasePanel.EVT_CLICK;
import org.apache.wicket.ajax.AjaxEventBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
import org.apache.wicket.ajax.form.AjaxFormSubmitBehavior;
import org.apache.wicket.markup.html.border.Border;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.panel.EmptyPanel;
import org.apache.wicket.model.Model;
import org.danekja.java.util.function.serializable.SerializableConsumer;
import com.googlecode.wicket.jquery.ui.widget.dialog.AbstractFormDialog;
import com.googlecode.wicket.jquery.ui.widget.dialog.DialogButton;
import com.googlecode.wicket.jquery.ui.widget.dialog.DialogButtons;
import com.googlecode.wicket.jquery.ui.widget.dialog.DialogIcon;
import com.googlecode.wicket.jquery.ui.widget.dialog.MessageFormDialog;
public abstract class ConfirmableAjaxBorder extends Border {
private static final long serialVersionUID = 1L;
private static final String DIALOG_ID = "dialog";
protected final Form<?> form = new Form<>("form");
protected final Form<?> userForm;
private final ConfirmableBorderDialog dialog;
private boolean validate = false;
public ConfirmableAjaxBorder(String id, String title, String message) {
this(id, title, message, null, null);
}
public ConfirmableAjaxBorder(String id, String title, String message, Form<?> form) {
this(id, title, message, form, null);
}
public ConfirmableAjaxBorder(String id, String title, String message, ConfirmableBorderDialog dialog) {
this(id, title, message, null, dialog);
}
public ConfirmableAjaxBorder(String id, String title, String message, Form<?> userForm, ConfirmableBorderDialog dialog) {
this(id, title, message, userForm, dialog, false);
}
public ConfirmableAjaxBorder(String id, String title, String message, Form<?> userForm, ConfirmableBorderDialog dialog, boolean validate) {
super(id, Model.of(message));
if (dialog == null) {
this.dialog = new ConfirmableBorderDialog(DIALOG_ID, title, message, userForm == null ? form : userForm);
form.add(this.dialog);
} else {
this.dialog = dialog;
form.add(new EmptyPanel(DIALOG_ID));
}
this.userForm = userForm;
this.validate = validate;
this.dialog.setSubmitHandler((SerializableConsumer<AjaxRequestTarget>)t->onSubmit(t));
this.dialog.setErrorHandler((SerializableConsumer<AjaxRequestTarget>)t->onError(t));
setOutputMarkupId(true);
}
public AbstractFormDialog<?> getDialog() {
return dialog;
}
@Override
protected void onInitialize() {
super.onInitialize();
if (validate) {
add(new AjaxFormSubmitBehavior(EVT_CLICK) {
private static final long serialVersionUID = 1L;
@Override
protected void onSubmit(AjaxRequestTarget target) {
dialog.open(target);
}
@Override
protected void onError(AjaxRequestTarget target) {
ConfirmableAjaxBorder.this.onError(target);
}
});
} else {
add(new AjaxEventBehavior(EVT_CLICK) {
private static final long serialVersionUID = 1L;
@Override
protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
super.updateAjaxAttributes(attributes);
ConfirmableAjaxBorder.this.updateAjaxAttributes(attributes);
}
@Override
protected void onEvent(AjaxRequestTarget target) {
if (isClickable()) {
dialog.open(target);
}
}
});
}
addToBorder(form);
}
protected boolean isClickable() {
return true;
}
protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
}
protected void onEvent(AjaxRequestTarget target) {
dialog.open(target);
}
protected void onError(AjaxRequestTarget target) {
}
protected abstract void onSubmit(AjaxRequestTarget target);
public static class ConfirmableBorderDialog extends MessageFormDialog {
private static final long serialVersionUID = 1L;
private Form<?> form;
private SerializableConsumer<AjaxRequestTarget> submitHandler = null;
private SerializableConsumer<AjaxRequestTarget> errorHandler = null;
public ConfirmableBorderDialog(String id, String title, String message) {
this(id, title, message, null);
}
public ConfirmableBorderDialog(String id, String title, String message, Form<?> form) {
super(id, title, message, DialogButtons.OK_CANCEL, DialogIcon.WARN);
this.form = form;
}
public void setSubmitHandler(SerializableConsumer<AjaxRequestTarget> submitHandler) {
this.submitHandler = submitHandler;
}
public void setErrorHandler(SerializableConsumer<AjaxRequestTarget> errorHandler) {
this.errorHandler = errorHandler;
}
@Override
public DialogButton getSubmitButton() {
return this.findButton(OK);
}
@Override
public Form<?> getForm() {
return this.form;
}
@Override
protected void onError(AjaxRequestTarget target, DialogButton btn) {
super.close(target, null); // closes the dialog on error.
if (errorHandler != null) {
errorHandler.accept(target);
}
}
@Override
protected void onSubmit(AjaxRequestTarget target, DialogButton btn) {
if (submitHandler != null) {
submitHandler.accept(target);
}
}
}
}
此类定义了一些明确的Ajax通信的边界相关的方法,首先这个类继承自org.apache.wicket.markup.html.border包下的boder类,同样也是一个抽象类,同时这个类里面还包含了一个内部类,以下是代码结构图;
首先是五个构造方法,通过参数列表进行区分,没有返回值,作用都是初始化此类的对象,通过观察发现,前四个构造方法均是将未传入的参数补上null之后通过this进行最后一个方法的调用,第五个构造方法首先用super(传参id和message)调用父类的构造方法,然后判断dialog参数是否为空,为空的话就要新建一个ConfirmableBorderDialog对象,并add到成员变量form里,然后用参数进行成员变量的赋值操作;
getDialog方法:返回成员变量dialog;
onInitialize方法:定义了初始化此类对象时还需要执行的一系列方法,再调用了父类的同名方法后,判断成员变量validate的值,为真就add一个AjaxFormSubmitBehavior对象,为假add一个AjaxEventBehavior对象,最后调用org.apache.wicket.markup.html.border.Border里的addtoborder方法将form的数组值加入到边框中;
updateAjaxAttributes方法:形参为AjaxRequestAttributes attributes,返回值为空,作用是可以在属性的细节上进行修改,方法体为空,应该是要留给子类进行重写的方法;
onEvent方法:形参为AjaxRequestTarget target,返回值为空,定义了在表单填写的时候应该执行的动作,调用了成员变量dialog的open方法去激活那个target;
onError方法:形参为AjaxRequestTarget target,返回值为空,定义了表单提交但验证失败时触发要执行的动作,方法体为空;
onSubmit方法:形参为AjaxRequestTarget target,返回值为空,定义了表单提交且验证成功时触发要执行的动作,抽象方法;
然后是一个静态的内部类ConfirmableBorderDialog,他继承自MessageFormDialog,定义了一些可确认边框对话框里的相关方法;
首先是两个构造方法,用参数列表加以区分,其中一个将未传入的参数设置为null之后,调用另一个构造方法;主要的构造方法首先用super调用了父类的构造方法,然后对form成员变量做了赋值;
setSubmitHandler方法:形参为SerializableConsumer<AjaxRequestTarget&> submitHandler,返回值为空,用于设置提交处理程序的相关操作;
setErrorHandler方法:形参为SerializableConsumer<AjaxRequestTarget&> errorHandler,返回值为空,用于设置错误处理程序的相关操作;
getSubmitButton方法:形参为空,返回值为DialogButton的对象,返回提交按钮,通过findbutton方法寻找id为“ok”的按钮,为所求,然后返回;
onError方法:形参为AjaxRequestTarget target, DialogButton btn,返回值为空,定义了提交表单验证失败后应该执行的具体方法,先关闭错误提示框,然后错误处理程序不为空的话,就调用其accept方法去处理target;
onSubmit方法:形参为AjaxRequestTarget target, DialogButton btn,返回值为空,定义了提交表单验证成功通过后执行的方法,提交处理程序不为空的话,调用其accept方法去处理target;
FormActionsPanel
package org.apache.openmeetings.web.common;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.panel.Panel;
import com.googlecode.wicket.jquery.core.Options;
import com.googlecode.wicket.kendo.ui.panel.KendoFeedbackPanel;
public abstract class FormActionsPanel<T> extends Panel {
private static final long serialVersionUID = 1L;
private final Form<T> form;
protected final KendoFeedbackPanel feedback = new KendoFeedbackPanel("feedback", new Options("button", true));
private AjaxButton saveBtn;
private ConfirmableAjaxBorder purgeBtn;
public FormActionsPanel(String id, Form<T> form) {
super(id);
this.form = form;
setOutputMarkupId(true);
}
@Override
protected void onInitialize() {
add(feedback.setOutputMarkupId(true));
// add a save button that can be used to submit the form via ajax
add(saveBtn = new AjaxButton("btn-save", form) {
private static final long serialVersionUID = 1L;
@Override
protected void onSubmit(AjaxRequestTarget target) {
// repaint the feedback panel so that it is hidden
target.add(feedback);
onSaveSubmit(target, form);
}
@Override
protected void onError(AjaxRequestTarget target) {
// repaint the feedback panel so errors are shown
target.add(feedback);
FormActionsPanel.this.onError(target, form);
}
});
// add a refresh button that can be used to submit the form via ajax
add(new AjaxButton("btn-refresh", form) {
private static final long serialVersionUID = 1L;
@Override
protected void onSubmit(AjaxRequestTarget target) {
// repaint the feedback panel so that it is hidden
target.add(feedback);
setNewVisible(false);
onRefreshSubmit(target, form);
}
@Override
protected void onError(AjaxRequestTarget target) {
// repaint the feedback panel so errors are shown
target.add(feedback);
setNewVisible(false);
FormActionsPanel.this.onError(target, form);
}
});
purgeBtn = new ConfirmableAjaxBorder("btn-purge", getString("admin.purge"), getString("admin.purge.desc"), form, null, false) {
private static final long serialVersionUID = 1L;
@Override
protected void onSubmit(AjaxRequestTarget target) {
// repaint the feedback panel so that it is hidden
target.add(feedback);
setNewVisible(false);
onPurgeSubmit(target, form);
}
@Override
protected void onError(AjaxRequestTarget target) {
// repaint the feedback panel so errors are shown
target.add(feedback);
FormActionsPanel.this.onError(target, form);
}
};
add(purgeBtn.setOutputMarkupPlaceholderTag(true).setVisible(false));
super.onInitialize();
}
public void setSaveVisible(boolean visible) {
saveBtn.setVisible(visible);
}
/**
* Change visibility the new record text
*
* @param visible - new visibility
*/
public void setNewVisible(boolean visible) {
// for admin only, will be implemented in admin
}
public void setPurgeVisible(boolean visible) {
purgeBtn.setVisible(visible);
}
protected abstract void onSaveSubmit(AjaxRequestTarget target, Form<?> form);
protected abstract void onRefreshSubmit(AjaxRequestTarget target, Form<?> form);
protected abstract void onPurgeSubmit(AjaxRequestTarget target, Form<?> form);
/**
* Save error handler
*
* @param target Ajax target
* @param form form object
*/
protected void onError(AjaxRequestTarget target, Form<?> form) {
//no-op
}
}
此类继承自Panel类,定义了有关表单操作面板的相关方法,同时,他也是一个抽象类;
构造方法:形参为String id, Form form,没有返回值,用来实例化表单操作面板类的对象,首先利用super调用父类的构造方法 ,然后根据形参给成员变量赋值,实例化此类对象;
onInitialize函数:定义了表单操作面板在初始化时所要执行的一系列方法,形参和返回值都为空,是重写的org.apache.wicket.MarkupContainer的方法,开始还存在疑问,没有继承这个类,怎么会重写这个类的方法,看了他的父类后才发现继承的Panel并不是AWT包下的Panel,而是org.apache.wicket.markup.html.panel这样之前所有没在AWT_Panel下见过的被重写的类就都可以解释的通了;首先调用org.apache.wicket.MarkupContainer下的add方法,并传入feedback通过setOutputMarkupId获取到的component对象,为本类面板添加一个组件,然后同样调用add方法添加可用于通过ajax提交表单的保存按钮,并定义了提交验证失败和提交验证成功后的执行方法,成功后重新绘制反馈面板以使其隐藏,失败后重新绘制反馈面板,以便显示错误,然后同样还是调用add方法添加刷新按钮,可用于通过ajax提交表单,同样地定义了成功后重新绘制反馈面板以使其隐藏,失败后重新绘制反馈面板的方法;最后为prugebtn清除按钮成员变量进行赋值,定义了提交验证失败和提交验证成功后的执行方法,成功后重新绘制反馈面板以使其隐藏,失败后重新绘制反馈面板;
setSaveVisible方法:形参为boolean visible,返回值为空,设置保存按钮可见性;
setNewVisible方法:形参为boolean visible返回值为空,更改新记录文本的可见性,仅用于 admin,将在 admin 中实现;
setPurgeVisible方法:形参为boolean visible,返回值为空,设置清除按钮可见性;
onSaveSubmit,onRefreshSubmit,onPurgeSubmit:三个抽象方法,供子类实现;
onError方法:形参为AjaxRequestTarget target, Form<?> form,返回值为空,作用是保存错误处理程序,未做具体实现;
总结:篇幅原因,本周分析了红框下面的三个类,两个是抽象类,是为继承他的子类规定模板的,下周继续进行common包下其他类的分析
2021/12/04