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

2021SC@SDUSC

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

上周分析了如下图红框内的具有继承关系的类,本周选择几个独立的类进行分析 ;

image-20211127205751254

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 客户端信息行为相关的方法的类;

首选是类的结构:

image-20211130203635912

没有定义无参构造方法,初始化此类对象的时候应该去调用父类的无参构造方法;

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类,同样也是一个抽象类,同时这个类里面还包含了一个内部类,以下是代码结构图;

image-20211130205552466

首先是五个构造方法,通过参数列表进行区分,没有返回值,作用都是初始化此类的对象,通过观察发现,前四个构造方法均是将未传入的参数补上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类,定义了有关表单操作面板的相关方法,同时,他也是一个抽象类;

image-20211130230942509

构造方法:形参为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,返回值为空,作用是保存错误处理程序,未做具体实现;

image-20211127205751254

总结:篇幅原因,本周分析了红框下面的三个类,两个是抽象类,是为继承他的子类规定模板的,下周继续进行common包下其他类的分析

2021/12/04

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

HiddenWorld

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

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

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

打赏作者

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

抵扣说明:

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

余额充值