Eclipse中的TreeViewer类和ListViewer类
TreeViewer和TableViewer在使用上还是有很多相似之处.TreeViewer中冶有TableViewer中的过滤器和排序器.具体使用看TableViewer中的使用.
和Table有JFace的扩展TableViewer一样,Tree也有一个JFace中的扩展,那就是TreeViewer.因为TreeViewer和TableViewer继承自同一个父类StructuredViewer所以两者有很多方法的使用是一样的.例如:都使用setInput方法输入数据,都有内容器,标签器,以及排序器,过滤器等.
建立一个树节点的接口类:
树节点由两个基本特征,名称和子节点.这里把这两个特征抽象出来写成一个接口,然后将要做树节点的实体类实现此接口.
主义这个接口不是必须的.仅仅是为了今后操作方便,以及规范化涉及才建立的.
但是每个实体对应的都是树上的一个节点.这里定义一个树中节点的通用接口.
然后每个实体类都实现这个接口.
接着建立几个实体类:
ITreeEntry.java
/**
* 树上的每个一个节点都对应的是一个实体,这个实体是树上的一个节点.
* 首先在定义实体类(People City Country)之前要先定义这个接口ITreeEntry
* 树的节点接口
* @author kongxiaohan
*/
public interface ITreeEntry {
/*
* 设置dedao 树节点的名称
* 只声明抽象方法,不声明字段名
*/
public String getName();
public void setName(String name); /*
* 设置与得到子节点集合.
*/
public void setChildren(List<ITreeEntry> children);
public List<ITreeEntry> getChildren();
}
City.java
/**
* City城市实体类
* @author kongxiaohan
*
*/
public class City implements ITreeEntry{
private Long id; // 唯一识别码,在数据库里常为自动递增的ID列
private String name;// 城市名 private List<ITreeEntry> peoples;//City实体的子节点 城市中的人,装在一个List集合中 public City(String name) {
super();
this.name = name;
} public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
} //这个地方是设置子节点....当前是City实体,其子节点是People实体
@Override
public void setChildren(List<ITreeEntry> children) {
//这个地方我犯了一错误,以前写习惯了,this.name = name
//所以一开始这个地方我写的是this.peoples = peoples
//在Country实体类中也是这个错误,所以运行出来的程序只有一列国家名,国家下面的城市都没有了....
this.peoples = children;
} @Override
public List<ITreeEntry> getChildren() {
return peoples;
}
}
Country.java
/**
* Country国家实体类
* @author kongxiaohan
*/
public class Country implements ITreeEntry {
private Long id; // 唯一识别码,在数据库里常为自动递增的ID列
private String name; // 国家名 private List<ITreeEntry> cities; //Country实体的子节点是城市 City 此国家所包含的的城市的集合,集合元素为City对象 public Country() {
} public Country(String name) {
super();
this.name = name;
} public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
} @Override
public void setChildren(List<ITreeEntry> children) {
this.cities = children;
} @Override
public List<ITreeEntry> getChildren() {
return cities;
}
}
People.java
public class People implements ITreeEntry {
private Long id; // 唯一识别码,在数据库里常为自动递增的ID列
private String name; // 姓名
private boolean sex; // 性别 true男,flase女
private int age; // 年龄
private Date createDate; // 记录的建立日期,是java.util.Date,而不是java.sql.Date public People(String name) {
super();
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
} //因为人是这个树的最小子节点,所以这个地方空实现接口中的这两个方法就可以了
@Override
public void setChildren(List<ITreeEntry> children) {
}
@Override
public List<ITreeEntry> getChildren() {
return null;
}
}
制造各个实体类的工具类
DataFactory.java
/**
* 此类负责生成TreeViewer的方法setInput所需要的参数.
* @author kongxiaohan
*
* 这个地方我没有用书中用的局部代码块,在组织代码的时候确实犯了一些小错误,
* 确实体会到了局部代码块的意义,代码读起来容易,而且节省了内存.
*/
public class DataFactory {
/**
* 在这个方法中定义生成的数据
* 要有人People的数据对象
* 要有国家Country的数据对象
* 要有城市City的数据对象
* @return
*/
public static Object createTreeData(){
//生成人People的数据对象
People people1 = new People("张A");
People people2 = new People("张B");
People people3 = new People("张C");
People people4 = new People("张D");
People people5 = new People("张E");
People people6 = new People("张F");
People people7 = new People("张G");
People people8 = new People("张H");
People people9 = new People("张I"); //生成城市City的数据对象
City city1 = new City("北京");
City city2 = new City("广州");
City city3 = new City("东京");
City city4 = new City("芝加哥");
City city5 = new City("洛杉矶"); //生成国家Country的的数据对象
Country country1 = new Country("中国");
Country country2 = new Country("日本");
Country country3 = new Country("美国"); /**
* 将这些封装的对象建立关系.
*/
//1.人和城市的关系
//张A 张B 张C 在帝都
ArrayList<ITreeEntry> list1 = new ArrayList<ITreeEntry>();
list1.add(people1);
list1.add(people2);
list1.add(people3);
city1.setChildren(list1); //张D 张E 张F在广州
ArrayList<ITreeEntry> list2 = new ArrayList<ITreeEntry>();
list2.add(people4);
list2.add(people5);
list2.add(people6);
city2.setChildren(list2); //张G 在东京
ArrayList<ITreeEntry> list3 = new ArrayList<ITreeEntry>();
list3.add(people7);
city3.setChildren(list3); //张I 在芝加哥
ArrayList<ITreeEntry> list4 = new ArrayList<ITreeEntry>();
list4.add(people8);
city4.setChildren(list4); //张H 在洛杉矶
ArrayList<ITreeEntry> list5 = new ArrayList<ITreeEntry>();
list5.add(people9);
city5.setChildren(list5); //2.城市和国家的关系
//北京 上海 广州是中国的
ArrayList<ITreeEntry> list6 = new ArrayList<ITreeEntry>();
list6.add(city1);
list6.add(city2);
country1.setChildren(list6); //东京是日本的
ArrayList<ITreeEntry> list7 = new ArrayList<ITreeEntry>();
list7.add(city3);
country2.setChildren(list7); //芝加哥和洛杉矶是美国的
ArrayList<ITreeEntry> list8 = new ArrayList<ITreeEntry>();
list8.add(city4);
list8.add(city5);
country3.setChildren(list8); //3.将国家置于一个对象之下,这个对象可以是一个List也可以是个数组
//国家是这个树上的最上层的节点.国家和国家之间是并列的关系,把这几个国家放到一个List集合对象中.
ArrayList<ITreeEntry> list9 = new ArrayList<ITreeEntry>();
list9.add(country1);
list9.add(country2);
list9.add(country3);
return list9;
}
}
内容器:TreeViewerContentProvider.java
标签器还比较简单,在TreeViewer中最主要和最复杂的是内容器,熟悉内容器是掌握TreeViewer的要点.
/**
* "内容器" 由它决定哪些对象记录应该输出在TreeViewer里显示.
* @author kongxiaohan
*
*/
public class TreeViewerContentProvider implements ITreeContentProvider{ /**
* 这个方法决定树的一级目录显示哪些对象
* @param inputElement 是用tv.setInput()方法输入的那个对象
* @return Object[]一个数组,数组中一个元素就是一个结点
*/
@Override
public Object[] getElements(Object inputElement) {
if (inputElement instanceof List) {
List list = (List) inputElement;
return list.toArray();
} else {
return new Object[0]; // 生成一个空数组
}
} /**
* 判断某结点是否有子结点。如果有子结点,这时结点前都有一个“+”号图标
*
* @param element 需要判断是否有子的结点
* @return true有子结点,false无子结点
*/
@Override
public boolean hasChildren(Object element) {
ITreeEntry entry = (ITreeEntry) element;
List<ITreeEntry> list = entry.getChildren();
if (list == null || list.isEmpty()) {
return false;
} else {
return true;
}
} /**
* 由这个方法决定父结点应该显示那些子结点。
*
* @param parentElement 当前被点击的结点对象
* @return 由子结点做为元素的数组
*/
@Override
public Object[] getChildren(Object parentElement) {
ITreeEntry entry = (ITreeEntry) parentElement;
List<ITreeEntry> list = entry.getChildren();
if (list == null || list.isEmpty()) {
return new Object[0];
} else {
return list.toArray();
}
} //>>>>>>>>>>>>>>>>>>>>>>>>>书上说以下三个方法是没有用的,空实现就哦了>>>>>>>>>>>>>>>>>>>>>>
@Override
public Object getParent(Object element) {
return null;
} @Override
public void dispose() {
} @Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
}
程序说明:在内容器中最关键的是getElements,hasChildren,getChildren这三个方法.
1.getElements自在显示"第一级"结点的时候才会被执行.
2.hasChildren主要用于判断当前说系那是的节点是否有子节点,如果有子节点则前面显示一个"+"号图标,而有"+"号的结点则可以单击展开其下一级的子节点.
3.当单击右"子"的结点的时候,才会执行getChildren方法.展开其子节点后,又会对子节点执行一遍hasChildren方法,以决定其各子结点前是否显示"+"图标.
下面是"内容器"在启动,单击,关闭窗口时执行的过程.
下面以本例来解释这个图:
1.树界面启动的时候 ,先执行inputChanged()方法,接着执行getElements方法,其inputElement参数就是由setInput传入的对象:包含所有实体对象的List,此List在getElements中被转化成一个数组,数组包含第一级结点的两个元素,中国,美国,日本,他们将首先显示在页面上.接下来执行三次hasChildren方法,判断中国,日本和美国是否有子节点.他们都有子节点.,所以方法返回True,两结点前都显示"+"图标.
2.单击右子节点的中国:先执行一次getChildren方法,方法的parentElement参数就是中国结点对象.方法中把中国的子节点取出转换陈给一个数组返回,此数组包含3个元素"北京,上海,济南".接下来连续执行3次hasChildren方法来判断"北京,上海,济南"是否有子节点,如果有在结点的前面显示一个"+"图标.
3.单击没有子节点的结点:不会有执行内容器中的任何方法.
4.关闭窗口:会先后执行inputChanged和dispose方法.
标签器TreeViewerLableProvider.java
将标签器写成单独的外部类,以便于后面的实例共用,其代码如下,在getText方法中element的类型可以是国家,城市,人,由于他们都是属于一个接口,所以getText的代码简洁不少.getImage()的实现参考TableViewer的标签器.
/**
* "标签器" 控制记录在树中显示的文字和图像等.
* @author kongxiaohan
*/
public class TreeViewerLableProvider implements ILabelProvider { /**
* 记录显示的文字。不能返回NULL值
*/
@Override
public String getText(Object element) {
//得到这个节点对应的名字,首先对element进行强制类型转换
ITreeEntry entry = (ITreeEntry) element;
return entry.getName();
} /**
* 记录显示的图像,可以返回NULL值
*/
@Override
public Image getImage(Object element) {
return null;
} //>>>>>>>>>>>>>>>>>>>>>>书上说一下几个方法没有用,空实现就可以了.>>>>>>>>>>>>>>>>>>>>>>>>>
@Override
public void addListener(ILabelProviderListener listener) {
// TODO Auto-generated method stub } @Override
public void removeListener(ILabelProviderListener listener) {
// TODO Auto-generated method stub }
@Override
public void dispose() {
// TODO Auto-generated method stub }
@Override
public boolean isLabelProperty(Object element, String property) {
// TODO Auto-generated method stub
return false;
}
}
给TreeViewer加上右键菜单的方法和TableViewer相似,也要用到Action,ActionGroup,MenuManager类.当然程序要根据树的特点稍作改动.
MyActionGroup内含有各Action类,在实现Action时,对传入的结点对象要记得进行空值判断.因为TreeViewer的大部分方法都不支持空值参数.会导致异常并中断程序.
MyActionGroup.java
public class MyActionGroup extends ActionGroup {
//ActionGroup这是个抽象类,但是其中并没有抽象方法.
private TreeViewer treeViewer; //构造方法
public MyActionGroup(TreeViewer treeViewer) {
this.treeViewer = treeViewer;
} /**
* 生成菜单Menu,并将两个Action传入
*/
public void fillContextMenu(IMenuManager mgr) {
/*
* 加入两个Action对象到菜单管理器
*/
MenuManager menuManager = (MenuManager) mgr; // 把接口类转换成其实现类.
//用MenuManager管理Action
menuManager.add(new OpenAction());
menuManager.add(new RefreshAction());
menuManager.add(new ExpandAction());
menuManager.add(new CollapseAction());
menuManager.add(new AddEntryAction());
menuManager.add(new RemoveEntryAction());
menuManager.add(new ModifyEntryAction());
/*
* 把这些功能加入到右键的Menu菜单中.
*/
Tree tree = treeViewer.getTree();
Menu menu = menuManager.createContextMenu(tree);
tree.setMenu(menu);
} /**
* 打开"菜单"对应的Action类
*/
private class OpenAction extends Action {
public OpenAction() {
setText("打开");
}
/**
* 继承自Action的方法,动作代码写此方法中
*/
//覆盖Action中的run()方法.
public void run() {
ITreeEntry obj = getSelTreeEntry();//getgetSelTreeEntry()得到当前节点
if (obj != null) {
//弹出一个这个节点名字的对话框.
MessageDialog.openInformation(null, null, obj.getName());
}
}
} /**
* 刷新对应的Action类.
*/
private class RefreshAction extends Action {
public RefreshAction() {
setText("刷新");
} //覆盖Action类中的run()方法,里面是调用的refresh()方法.
public void run() {
treeViewer.refresh();// 调用TreeViewer的刷新方法
}
} /**
* 展开当前结点的Action类
*/
private class ExpandAction extends Action {
public ExpandAction() {
setText("展开");
}
//重写run()方法
public void run() {
ITreeEntry obj = getSelTreeEntry();
if (obj != null) {
treeViewer.expandToLevel(obj, 1);
// 这个方法后面的数字是展开的层级数.这个地方设置成仅仅展开1个层级.
}
}
} /**
* 收缩当前结点的Action类
*/
private class CollapseAction extends Action {
public CollapseAction() {
setText("收缩");
}
//重写run()方法
public void run() {
ITreeEntry obj = getSelTreeEntry();
if (obj != null) {
treeViewer.collapseToLevel(obj, -1); // -1为将当前结点的所有子结点收缩
}
}
} /**
* 给当前结点增加一个子结点的Action类
*/
private class AddEntryAction extends Action {
public AddEntryAction() {
setText("增加");
}
@Override
public void run() {
ITreeEntry obj = getSelTreeEntry();
if (obj == null || obj instanceof People) {
return;
}
InputDialog dialog = new InputDialog(null, "给当前结点增加一个子结点", "输入名称", "请输入你要增加的节点的名字", null);
if (dialog.open() == InputDialog.OK) {// 如果单击OK按钮
String entryName = dialog.getValue(); // 得到Dialog输入值
/* 根据单击结点的不同类型生成相应的子结点 */
ITreeEntry newEntry = null;
if (obj instanceof Country) {
newEntry = new City(entryName);
} else if (obj instanceof City) {
newEntry = new People(entryName);
}
/* 在增加子结点之前将父结点展开 */
if (!treeViewer.getExpandedState(obj)) {
treeViewer.expandToLevel(obj, 1);
}
treeViewer.add(obj, newEntry);// 增加结点
}
}
} /**
* 删除结点的Action类
*/
private class RemoveEntryAction extends Action {
public RemoveEntryAction() {
setText("删除");
}
@Override
public void run() {
ITreeEntry obj = getSelTreeEntry();
if (obj == null) {
return;
}
treeViewer.remove(obj);
}
} /**
* 修改结点名称的Action类
*/
private class ModifyEntryAction extends Action {
public ModifyEntryAction() {
setText("修改");
}
@Override
public void run() {
ITreeEntry obj = getSelTreeEntry();
if (obj == null) {
return;
}
InputDialog dialog = new InputDialog(null, "修改结点", "输入新名称", obj.getName(), null);
if (dialog.open() == InputDialog.OK) {
String entryName = dialog.getValue();//得到对话框中的值.
obj.setName(entryName);//给这个节点设置成得到的对话框中的名字.
treeViewer.refresh(obj); // 刷新结点
}
}
}
/**
* 这个方法是自定义的方法,这个方法的作用就是得到当前选择的节点.
*/
private ITreeEntry getSelTreeEntry() {
IStructuredSelection selection = (IStructuredSelection) treeViewer.getSelection();
ITreeEntry treeEntry = (ITreeEntry) (selection.getFirstElement());
return treeEntry;
}
}
TreeViewer.java的实例
public class TreeViewer1 {
public static void main(String[] args) {
TreeViewer1 window = new TreeViewer1();
window.open();
} //定义这个open()方法.就是创建一个典型的SWT程序的步骤
public void open(){
//1.Display负责管理一实现循环和控制UI线程和其他线程之间的通信
final Display display = new Display();
//2.创建一个或者多个Shell(shell是程序的主窗口)
final Shell shell = new Shell();
//3.设置shell的布局.
shell.setSize(200, 300);
//设置shell的布局为FillLayout
shell.setLayout(new FillLayout());
shell.setText("TreeViewer的第一个例子"); Composite c = new Composite(shell, SWT.NONE);
c.setLayout(new FillLayout());
TreeViewer treeViewer = new TreeViewer(c, SWT.BORDER);
treeViewer.setContentProvider(new TreeViewerContentProvider());
treeViewer.setLabelProvider(new TreeViewerLableProvider());
// 和TableViewer一样,数据的入口也是setInput方法
Object inputObj = DataFactory.createTreeData();
treeViewer.setInput(inputObj); /*
//调用自定义的方法创建表格
createTableViewer(shell);
//4.设定内容器
tableviewer.setContentProvider(new TableViewerContentProvider());
//5.设定标签器
tableviewer.setLabelProvider(new TableViewerLabelProvider());
//6.用setInput输入数据(把PeopleFactory产生的List集合传进来)
tableviewer.setInput(PeopleFactory.getPeoples());
*/ //7.创建Shell中的组件(这个例子中没有加入组件,只有一个空窗口)
shell.open();
//8.写一个时间转发循环
while(!shell.isDisposed()){//如果主窗口没有关闭,则一直循环
//dispose 是"处理,处置,毁掉"的意思
if(!display.readAndDispatch()){//// 如果display不忙
display.sleep();// display休眠
}
}
}
}
TreeViewer1.java的运行结果图
TreeViewer2.java
public class TreeViewer2 { public static void main(String[] args) {
TreeViewer2 window = new TreeViewer2();
window.open();
} public void open() {
final Display display = new Display();
final Shell shell = new Shell();
shell.setSize(200, 300); shell.setLayout(new FillLayout());
Composite c = new Composite(shell, SWT.NONE);
c.setLayout(new FillLayout());
TreeViewer treeViewer = new TreeViewer(c, SWT.BORDER);
treeViewer.setContentProvider(new TreeViewerContentProvider());
treeViewer.setLabelProvider(new TreeViewerLableProvider());
Object inputObj = DataFactory.createTreeData();
//>>>>>>>>>>>>>相比于TreeViewer1.java增加的>>>>>>>>>>>>>>>>>>>>>>>>>
//生成一个ActionGroup对象
MyActionGroup actionGroup = new MyActionGroup(treeViewer);
// 调用fillContextMenu方法将按钮注入到菜单对象中
actionGroup.fillContextMenu(new MenuManager());
// --------------加入代码:END--------------------
treeViewer.setInput(inputObj);
// -----------------------------
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
}
TreeViewer2.java的运行结果图:
上面的这个是<<Eclispe从入门到精通>>中第一版的代码,在第二版中对一些功能进行了一些改进.
该进在于"不同的结点显示不同的菜单".
树的"人"结点是没有子节点的.因此对于"人"这个节点来说,右键菜单中的"展开,收缩,增加"菜单项都没有任何意义,应该隐藏起来,再根据当前节点的类型决定要将哪些Action加入菜单中.按着这个思路将MyActionGroup类的fillContextMenu方法修改如下:
Eclipse中的TreeViewer类和ListViewer类的更多相关文章
- eclipse中运行出错:无法初始化主类的解决办法
问题描述:eclipse中运行程序时,出现如下错误 解决办法: 出现此类:无法初始化主类有可能是因为eclipse中Java的版本与JDK的版本不匹配,我开始用的时候eclipse中用的是Java s ...
- 在Eclipse中生成接口的JUnit测试类
在Spring相关应用中,我们经常使用“接口” + “实现类” 的形式,为了方便,使用Eclipse自动生成Junit测试类. 1. 类名-new-Other-java-Junit-Junit Tes ...
- eclipse中从数据库生成hibernate实体类
为什么写这篇BLOG,是因为经常有同事或网友问起我hiberante实体类的生成问题.所以下次再有人问我可以省一堆的话了,其实这个真的是很简单. 现在hibernate在项目中的应用是越 ...
- eclipse中根据方法找到其实现类
面向接口编程中,程序全是面向接口变成调用,在维护别人写的系统的时候怎么样快速定位当前根据接口调用的方法是哪个实体类实现的: Ctrl + T/f4(光标放在需要查看的方法上,然后按Ctrl+T或者F4 ...
- Eclipse中按CTRL键点击类不能进入
是因为Eclipse或项目没有关联jdk,首先看window->preferences->java->Installed JREs,看是不是关联的你所安装的jdk,有的是关联的JRE ...
- Eclipse中Copy Qualified Name复制类全名解决办法
Eclipse中用Copy Qualified Name复制类全名时总是这样的/struts1/src/me/edu/HelloAction.java很不方便可以这样解决下载下边插件解压到Eclips ...
- 如何在Eclipse中查看Android源码或者第三方组件包源码
文章出处:http://blog.csdn.net/cjjky/article/details/6535426 在学习过程中如果经常阅读源码,理解程度会比较深,学习效率也会比较高,那么如何方便快捷的阅 ...
- Eclipse 中构建 Maven 项目的完整过程 - SpringBoot 项目
进行以下步骤的前提是你已经安装好本地maven库和eclipse中的maven插件了(有的eclipse中已经集成了maven插件) 一.Maven项目的新建 1.鼠标右键---->New--- ...
- eclipse中使用lombok不生效
eclipse中使用lombok,在实体类中添加@Data后,还是不能调用get.set方法.需要修改eclipse配置 1.将 lombok.jar 复制到eclipse.ini同级目录.下载的lo ...
随机推荐
- 笔记:1.css样式,最前边加 @charset "utf-8";是为什么2.js判断各种浏览器的方法
表明CSS文件的页面编码为UTF-8..如果这个CSS的文件编码也是UTF-8的话..那么在浏览器中看到的CSS文件的页面中中文的注释或者中文字体就可以正确显示为中文,如果CSS的文件编码和页面不一致 ...
- MATLAB和c#混合编程实现心电图显示软件
[在此处输入文章标题] 由于MATLAB自带的GUI平台设计的界面不是很美观而且设计过程并不是很方便,我们选择了用c#来做软件界面的实现.我们用MATLAB做信号处理封装成函数,把函数编译成dll格式 ...
- HW6.5
import java.util.Scanner; public class Solution { public static void main(String[] args) { Scanner i ...
- A Tour of Go Buffered Channels
Channels can be buffered. Provide the buffer length as the second argument to make to initialize a b ...
- mssql游标demo
declare @billIds varchar(400) declare @billId varchar(40) DECLARE c1 CURSOR FOR select top 5 SaleNo ...
- [转]windows下srand48()和drand48()的问题
转自:windows下srand48()和drand48()的问题 #ifndef DRAND48_H #define DRAND48_H #include <stdlib.h> #def ...
- Java中的二维数组
Java 中的二维数组 所谓二维数组,可以简单的理解为是一种"特殊"的一维数组,它的每个数组空间中保存的是一个一维数组. 那么如何使用二维数组呢,步骤如下: 1. 声明数组并分配空 ...
- 【C++深入浅出】设计模式学习之观察者模式
前言 前两天学习了weak_ptr以后还是不甚明了,一则需要实际应用去锤炼,二来就是不懂观察者模式. 正文 观察者模式又叫发布-订阅模式,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一主题对 ...
- Oracle中的AS和IS
Oracle中的AS和IS是ORACLE为了方便而设置的同义词基本上没有不同 . 使用规则: 1.在创建存储过程(PROCEDURE)/函数(FUNCTION),以及自定义类型(TPYE)和包(PAC ...
- mybatis的辅助类
package org.ssi.util; import java.io.InputStream; import org.apache.ibatis.session.SqlSession; impor ...