2021SC@SDUSC
软件工程应用与实践——OpenMeetings项目分析(十一):
本周,继续进行common包下的代码的分析,从下列红色箭头所指的类开始进行分析:
PagingNavigatorPanel:
package org.apache.openmeetings.web.common;
import java.util.List;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.markup.repeater.data.DataView;
import org.apache.wicket.model.PropertyModel;
public abstract class PagingNavigatorPanel extends Panel {
private static final long serialVersionUID = 1L;
private int entitiesPerPage;
public PagingNavigatorPanel(String id, final DataView<?> dataView, List<Integer> numbers) {
this(id, dataView, numbers, 50);
}
public PagingNavigatorPanel(String id, final DataView<?> dataView, List<Integer> numbers, int _entitiesPerPage) {
super(id);
setOutputMarkupId(true);
this.entitiesPerPage = _entitiesPerPage;
dataView.setItemsPerPage(entitiesPerPage);
final Form<Void> f = new Form<>("pagingForm");
f.add(new OmPagingNavigator("navigator", dataView).setOutputMarkupId(true))
.add(new DropDownChoice<>("entitiesPerPage", new PropertyModel<Integer>(this, "entitiesPerPage"), numbers)
.add(new AjaxFormComponentUpdatingBehavior("change") {
private static final long serialVersionUID = 1L;
@Override
protected void onUpdate(AjaxRequestTarget target) {
long newPage = dataView.getCurrentPage() * dataView.getItemsPerPage() / entitiesPerPage;
dataView.setItemsPerPage(entitiesPerPage);
dataView.setCurrentPage(newPage);
target.add(f);
PagingNavigatorPanel.this.onEvent(target);
}
}));
add(f.setOutputMarkupId(true));
}
public int getEntitiesPerPage() {
return entitiesPerPage;
}
public void setEntitiesPerPage(int entitiesPerPage) {
this.entitiesPerPage = entitiesPerPage;
}
protected abstract void onEvent(AjaxRequestTarget target);
}
PagingNavigatorPanel类是一个抽象类继承自org.apache.wicket.markup.html.panel下的Panel类而不是AWT下的Panel类,定义了分页导航面板类;
首先是代码结构:
构造方法:形参为String id, final DataView<?> dataView, List numbers或者String id, final DataView<?> dataView, List numbers, int _entitiesPerPage,没有返回值,作用为实例化分页导航面板类的对象,第一个构造方法在第一行且只能在第一行用this关键字调用了另一个构造方法,另一个构造方法首先用super传入id调用父类构造函数,然后setOutputMarkupId设置为true,设置输出标记,点击去源码发现这个方法就是设置了一个flag的component对象,然后用形参给成员变量entitiesPerPage赋值,接着用setItemsPerPage方法为形参dataview设置每页项目数,然后创建新的form对象add分页导航面板所需要的小组件后,最后将新建的form数组对象设置输出id为真后添加到本类的实例变量里面;
getEntitiesPerPage方法:返回值为int类型,形参为空,直接返回成员变量entitiesPerPage;
setEntitiesPerPage方法:形参为int entitiesPerPage,返回值为空,作用为成员变量entitiesPerPage设置值;
onEvent方法:抽象方法,形参AjaxRequestTarget target,返回值为空,留给子类去实现,作用是规定了有关分页导航面板的特定事件发生时偶应该执行的代码;
GroupChoiceProvider:
package org.apache.openmeetings.web.common;
import static org.apache.openmeetings.web.app.Application.getBean;
import static org.apache.openmeetings.web.app.WebSession.getUserId;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import org.apache.openmeetings.db.dao.user.GroupDao;
import org.apache.openmeetings.db.dao.user.UserDao;
import org.apache.openmeetings.db.entity.user.Group;
import org.apache.openmeetings.db.entity.user.GroupUser;
import org.apache.openmeetings.db.entity.user.User;
import org.apache.openmeetings.web.app.WebSession;
import org.apache.wicket.util.string.Strings;
import org.wicketstuff.select2.ChoiceProvider;
import org.wicketstuff.select2.Response;
public class GroupChoiceProvider extends ChoiceProvider<Group> {
private static final long serialVersionUID = 1L;
@Override
public void query(String term, int page, Response<Group> response) {
if (WebSession.getRights().contains(User.Right.Admin)) {
List<Group> groups = getBean(GroupDao.class).get(0, Integer.MAX_VALUE);
for (Group g : groups) {
if (Strings.isEmpty(term) || g.getName().toLowerCase(Locale.ROOT).contains(term.toLowerCase(Locale.ROOT))) {
response.add(g);
}
}
} else {
User u = getBean(UserDao.class).get(getUserId());
for (GroupUser ou : u.getGroupUsers()) {
if (Strings.isEmpty(term) || ou.getGroup().getName().toLowerCase(Locale.ROOT).contains(term.toLowerCase(Locale.ROOT))) {
response.add(ou.getGroup());
}
}
}
}
@Override
public Collection<Group> toChoices(Collection<String> ids) {
Collection<Group> c = new ArrayList<>();
for (String id : ids) {
c.add(getBean(GroupDao.class).get(Long.valueOf(id)));
}
return c;
}
@Override
public String getDisplayValue(Group choice) {
return choice.getName();
}
@Override
public String getIdValue(Group choice) {
Long id = choice.getId();
return id == null ? null : "" + id;
}
}
此类继承自org.wicketstuff.select2包下的ChoiceProvider<Group>,结构比较简单,提供了一些选择加入组或团体的一些方法;
query方法:形参为:String term, int page, Response<Group> response,无返回值,作用是根据传入的查询条件以及当前的用户状态,查询组内成员或者用户拥有的不同的组,先取session并获得当前用户是否为admin,是的话,构造group的数组,查找所属的组的名字若查询条件term为空或者总的组列表包含要查的列表,则添加到数组并返回,如果不是则查找此用户所在的组的所有成员并添加到数组并返回;
toChoices方法:形参为Collection<String>ids,返回值为Collection<Group>,将指定id的组添加到ArrayList里并返回;
getDisplayValue方法:形参为Group choice,返回值为String,作用是获取组选择方案的名字;
getIdValue方法:形参为Group choice,返回值为String,获取指定组方案的id;
LanguageDropDown:
package org.apache.openmeetings.web.common;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.apache.openmeetings.db.dao.label.LabelDao;
import org.apache.wicket.markup.html.form.ChoiceRenderer;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.model.IModel;
public class LanguageDropDown extends DropDownChoice<Long> {
private static final long serialVersionUID = 1L;
private final List<Long> languages = new ArrayList<>();
public LanguageDropDown(String id, IModel<Long> model) {
super(id, model, new ArrayList<Long>());
internalInit();
}
public LanguageDropDown(String id) {
super(id);
internalInit();
}
private void internalInit() {
for (Map.Entry<Long, Locale> e : LabelDao.getLanguages()) {
languages.add(e.getKey());
}
setChoices(languages);
setChoiceRenderer(new ChoiceRenderer<Long>() {
private static final long serialVersionUID = 1L;
@Override
public Object getDisplayValue(Long object) {
return LabelDao.getLocale(object).getDisplayName();
}
@Override
public String getIdValue(Long object, int index) {
return "" + object;
}
});
}
}
此类继承自DropDownChoice<Long>,定义了语言下拉菜单的相关方法;
构造方法:无返回值,形参为String id, IModel model,代码里通过super调用父类的构造方法,随后调用第三个成员方法internalInit进行内部初始化语言下拉菜单;
internalInit方法:形参返回值都为空,正如上面所讲,此方法是用来进行语言下拉菜单的内部初始化,代码里,首先通过LabelDao.getLanguages()获取自定义的语言列表类Omlanguages,然后通过键值对映射集合进行遍历,并将key添加到成员变量语言列表中,然后调用org.apache.wicket.markup.html.form.AbstractChoice<T, E>下的setChoices设置可供选择的语言列表,然后设置选择渲染器,并通过新建一个org.apache.wicket.markup.html.form.IChoiceRenderer<? super E>对象作为参数传入,以设置详细的获取显示值和获取ID值的方法;
PagedEntityListPanel:
package org.apache.openmeetings.web.common;
import java.util.Arrays;
import java.util.List;
import org.apache.openmeetings.db.entity.IDataProviderEntity;
import org.apache.openmeetings.web.admin.SearchableDataView;
import org.apache.openmeetings.web.data.SearchableDataProvider;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.PropertyModel;
import com.googlecode.wicket.jquery.ui.form.button.AjaxButton;
public abstract class PagedEntityListPanel extends Panel {
private static final long serialVersionUID = 1L;
private List<Integer> numbers = Arrays.asList(10, 25, 50, 75, 100, 200);
public PagedEntityListPanel(String id, final SearchableDataView<? extends IDataProviderEntity> dataView) {
super(id);
final PagingNavigatorPanel navPanel = new PagingNavigatorPanel("pagedPanel", dataView, numbers) {
private static final long serialVersionUID = 1L;
@Override
protected void onEvent(AjaxRequestTarget target) {
PagedEntityListPanel.this.onEvent(target);
}
};
final SearchableDataProvider<? extends IDataProviderEntity> dp = dataView.getDataProvider();
Form<Void> searchForm = new Form<>("searchForm");
add(searchForm.setOutputMarkupId(true));
searchForm.add(new TextField<>("searchText", new PropertyModel<String>(dp, "search")).setOutputMarkupId(true));
AjaxButton b = new AjaxButton("search", searchForm) {
private static final long serialVersionUID = 1L;
@Override
protected void onSubmit(AjaxRequestTarget target) {
target.add(navPanel);
PagedEntityListPanel.this.onEvent(target);
}
};
searchForm.add(b);
searchForm.setDefaultButton(b);
add(navPanel);
}
protected abstract void onEvent(AjaxRequestTarget target);
}
此类同样是继承自org.apache.wicket.markup.html.panel的一个抽象类,定义了一个分页实体列表面板类,结构如下:
包含两个成员变量以及两个成员方法;
构造方法:形参为String id, final SearchableDataView<? extends IDataProviderEntity> dataView,返回值没有,作用为实例化PagedEntityListPanel对象,首先用super调用父类的构造方法,然后定义了一个PagingNavigatorPanel类型的常量,同时重写了其中的onEvent方法,随后new一个Form<Void>的变量searchForm,并添加了TextField,AjaxButton等组件,AjaxButton还重写了一个onSubmit方法,定义了在表单提交成功后执行的方法,最后省略this调用继承自父类的add的方法,将装配好的searchForm添加到此类实例化的对象里面;
OmPagingNavigator:
package org.apache.openmeetings.web.common;
import org.apache.wicket.ajax.markup.html.navigation.paging.AjaxPagingNavigator;
import org.apache.wicket.markup.html.navigation.paging.IPageable;
public class OmPagingNavigator extends AjaxPagingNavigator {
private static final long serialVersionUID = 1L;
public OmPagingNavigator(String id, IPageable pageable) {
super(id, pageable);
}
}
此类继承自AjaxPagingNavigator,定义了项目的分页导航器,结构比较简答,
构造方法:将参数用super调用父类的构造方法,实例化此分页导航器类的对象;
ComunityUserForm:
package org.apache.openmeetings.web.common;
import org.apache.openmeetings.db.entity.user.User;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.Radio;
import org.apache.wicket.markup.html.form.RadioGroup;
import org.apache.wicket.markup.html.form.TextArea;
import org.apache.wicket.markup.html.panel.IMarkupSourcingStrategy;
import org.apache.wicket.markup.html.panel.PanelMarkupSourcingStrategy;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
public class ComunityUserForm extends Form<User> {
private static final long serialVersionUID = 1L;
public ComunityUserForm(String id, IModel<User> model) {
super(id, model);
RadioGroup<Long> rg = new RadioGroup<>("community_settings", new IModel<Long>() {
private static final long serialVersionUID = 1L;
@Override
public Long getObject() {
User u = ComunityUserForm.this.getModelObject();
if (u.isShowContactData()) {
return 1L;
} else if (u.isShowContactDataToContacts()) {
return 2L;
}
return 3L;
}
@Override
public void setObject(Long choice) {
User u = ComunityUserForm.this.getModelObject();
if (choice.equals(1L)) {
u.setShowContactData(true);
u.setShowContactDataToContacts(false);
} else if (choice.equals(2L)) {
u.setShowContactData(false);
u.setShowContactDataToContacts(true);
} else {
u.setShowContactData(false);
u.setShowContactDataToContacts(false);
}
}
});
add(rg.add(new Radio<>("everybody", Model.of(1L)), new Radio<>("contact", Model.of(2L))
, new Radio<>("nobody", Model.of(3L))).setOutputMarkupId(true).setRenderBodyOnly(false)
);
add(new TextArea<String>("userOffers"));
add(new TextArea<String>("userSearchs"));
}
@Override
protected IMarkupSourcingStrategy newMarkupSourcingStrategy() {
return new PanelMarkupSourcingStrategy(false);
}
}
此类继承自Form<User>,定义了组织用户表格的相关操作;结构比较简单,包含一个构造方法以及一个成员方法;
构造方法:super调用父类构造方法,然后新建一个RadioGroup对象rg,且重写了两个方法getObject和setObject,getobject方法通过判断此类通过getModelObject方法得到的对象是否是已登录用户联系人数据还是显示给联系人的联系人数据,来返回不同的值,而set方法是根据get到的类型判断后,为ComunityUserForm.this.getModelObject得到的对象设置属性值;最后利用省略this的add方法将文本域组件以及上面构建好的rg组件添加到本类的实例对象里;
newMarkupSourcingStrategy方法:返回值为IMarkupSourcingStrategy,形参为空,作用是新建一个资源策略类型,直接返回了一个默认构造函数参数为false的PanelMarkupSourcingStrategy对象;
总结:本周分析了上图这些类,相比之前的抽象类需要定义其子类的模板,代码量较多,这几个类构成较为简单,代码量主要集中在构造函数;下周将剩下的common下的抽象类分析完成
2021/12/11