一、修改模板文件
1、将模板文件IndexTemplate.xhtml中的<p:menuitem value="行政区划" url="#" />修改为:<p:menuitem value="中国行政区划" outcome="cn_address" />,outcome指向本系统内的一个JSF页面文件,不需要文件的后缀名。
2、增加一个导航到首页的菜单项<p:menuitem value="返回首页" outcome="index" icon="ui-icon-home"/>,icon用来在菜单项前增加一个图标。
3、在底部布局中,增加一个消息提示组件<p:growl/>,需要在<h:form/>中添加。代码如下:
<p:layoutUnit position="south" size="40" closable="true" collapsible="true"> <h:form id="bottomForm" style="padding: 4px;text-align:center;"> ... <p:growl id="bottomGrowl" showDetail="true" /> </h:form> </p:layoutUnit>修改后的模板文件见附件1。
二、创建AddressBean受管Bean
AddressBean受管Bean源代码见附件2。
AddressBean用来提供行政区划的数据,实现应用程序逻辑和业务逻辑。除了set、get方法外,其它的属性、方法均作了详细的注释。由于使用JadePool作为持久化工具,实现数据更新、查询的操作都非常方便。
三、创建中国行政区划管理页面
创建模板客户端网页文件cn_address.xhtml,源代码见附件3。
创建后,将文件的字符集编码修改GBK。
在cn_address.xhtml页面中实现了以下操作:
1、导入中国行政区划记录,并将记录保存到数据库中;
2、实现多功能的分页查询;
3、在DataTable行中修改行政区划记录。
需要指出的是ListMapDataModel dimingModel数据模型是直接将JadePool查询结果转换而来的,而且可以直接在JSF的UI组件中调用,如:<p:inputText value="#{m.longitude}" />。将其修改后又能直接保存到数据库中,因此,极大地方便了JadePool用户。代码如:onEdit方法中保存修改的代码
Record r = new Record(); Map dm = r.one(this.dimingList, "addresscode", m.get("addresscode")); Jade j = new Jade(); j.save("cn_address", dm); //......
修改记录时的页面效果见图
附件1:IndexTemplate.xhtml
<?xml version='1.0' encoding='GBK' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui" xmlns:ui="http://java.sun.com/jsf/facelets"> <h:head> <meta http-equiv="Content-Type" content="text/html; charset=GBK" /> <title>China软件项目</title> <h:outputStylesheet library="css" name="primefaces.css"/> <style type="text/css"> .ui-selectoneradio td{border: 0px;padding: 4px;background-color: transparent;}/*去掉p:selectOneRadio中表格宽度*/ .my-north,.my-north div{margin: 0px;padding: 0px;border: 0px;color:white;background:url(/blog_article/none/index.html) transparent;background-color: #004360;}/*修改头部布局的样式*/ .my-menu{width:160px;} .my-grid tbody td{border: 0px;}/*去掉td宽度*/ </style> </h:head> <h:body> <p:layout fullPage="true"> <p:layoutUnit position="north" size="70" styleClass="my-north"> <h:panelGrid columns="2" style="height: 30px;"> <h:column> <h1 style="padding: 8px;">China软件项目管理</h1> </h:column> <h:column> <div style="padding: 4px;"> JSF2.0卓越的JavaWEB框架 </div> </h:column> </h:panelGrid> </p:layoutUnit> <p:layoutUnit position="south" size="40" closable="true" collapsible="true"> <h:form id="bottomForm" style="padding: 4px;text-align:center;"> <p:spacer width="10"/> <h:outputText value="开发设计:胡开明"/> <p:spacer width="10"/> <h:outputText value="日期:2013年3月28日"/> <p:spacer width="10"/> <p:growl id="bottomGrowl" showDetail="true" /> </h:form> </p:layoutUnit> <p:layoutUnit position="west" size="180" header="China软件项目主菜单" collapsible="true"> <p:menu styleClass="my-menu"> <p:submenu label="基本数据管理"> <p:menuitem value="中国行政区划" outcome="cn_address" /> <p:menuitem value="民族" url="#" /> <p:menuitem value="产品分类" url="#" /> <p:menuitem value="国民经济行业分类" url="#" /> </p:submenu> <p:submenu label="通讯录管理"> <p:menuitem value="商务通讯录" url="#" /> </p:submenu> <p:submenu label="资讯管理"> <p:menuitem value="RSS订阅" url="#" /> <p:menuitem value="返回首页" outcome="index" icon="ui-icon-home"/> </p:submenu> </p:menu> </p:layoutUnit> <p:layoutUnit position="center"> <ui:insert name="content">各项业务实现部分</ui:insert> </p:layoutUnit> </p:layout> </h:body> </html>
附件2:AddressBean.java
/* * AddressBean.java * 胡开明 * 2013-01-25 * */ package china; import cn.jadepool.sql.Jade; import cn.jadepool.sql.Record; import cn.jadepool.util.China; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.faces.application.FacesMessage; import javax.faces.bean.ManagedBean; import javax.faces.bean.SessionScoped; import javax.faces.context.FacesContext; import org.primefaces.event.RowEditEvent; /** * 通用的地名管理 * * @author hkm */ @ManagedBean @SessionScoped public class AddressBean implements java.io.Serializable { private Map dimingMap = new LinkedHashMap();//地名记录 private Map dimingSelected = new LinkedHashMap();//被选择的地名记录 private List<Map> dimingList = new ArrayList();//地名列表 private ListMapDataModel dimingModel = null;//地名数据模型 private List<Map> dimingShengList = new ArrayList();//省地名列表 private List<Map> dimingShiList = new ArrayList();//市地名列表 private List<Map> dimingXianList = new ArrayList();//县地名列表 private China cn = new China(); private String codeSheng = ""; private String codeShi = ""; private String codeXian = ""; /** * Creates a new instance of Add
观察者模式是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。
2.观察者模式的实现虽然在Java中提供了现成的Observer和Observable实现,但由于Observable已经被实现成class,所以当需要将自己的某个业务类实现成可被观察的特性时,往往还是得自己来实现,因此下文不再使用Java中的Observable和Observer类,而是自行实现。
通常的实现方式是注册-通知-取消注册。代码如下:
public interface Listener { void onNotify(); } public class Subject { private List<Listener> listeners; private Object value; public Subject(){ listeners=new ArrayList<Listener>(); value=new Object(); } public void registe(Listener listener){ listeners.add(listener); } public void unRegiste(Listener listener){ listeners.remove(listener); } private void sendNotify(){ for(Listener listener:listeners){ listener.onNotify(); } } public Object getValue(){ return value; } public void setValue(Object value){ if (!this.value.equals(value)){ this.value=value; sendNotify(); } } }
被观察者需要一个容器来保留注册进来的观察者引用,上文的代码中使用了List作为容器,这个容器的选择会影响到整体的实现方案。
通常选择用一个Array或List容器来存储,这样一方面可以做到有序,另一方面在通知时方便遍历。
如果不想有重复的观察者引用,则要么在注册时检查是否已经存在于容器中,比如在上文registe()方法中加入contains()的判断,要么就选择不可重复的容器如Set,Map等。这样的容器本身已经包含了对重复的处理,但也意味着在发送通知时的顺序不是注册时的先后顺序。
2.2.通知后的数据获取方式也就是常说的‘推’或‘拉’。推方式是说变化的数据随着对观察者的接口调用以参数的方式传递给观察者。拉方式是说对观察者的接口调用只用于通知数据发生了变化这件事情,由观察者自行调用被观察者的getXXX()方法取得感兴趣的数据。前者不管三七二十一把变化就推给观察者了,不管你有用没用;后者只是尽到通知的义务,你对什么数据感兴趣就自己来拿。这个要根据实际的设计情况进行决策。
上文的代码中使用了拉的方式,当value发生变化时,会通过sendNotify()方法发送通知给Listener,但通知中未携带value的值,而是由Listener一方根据情况调用getValue()方法来拉取变化后的新的value值。
2.3.通知后的取消注册通知后的取消在实际应用中也没有上述示例代码这样简单。一个典型的需求就是某个Listener要在onNotify()方法执行的过程中调用unRegiste(this)。对这一需求的满足可以小心的处理sendNotify()方法,也可以通过标识位进行标识,还可以在sendNotify()中不使用原始的容器而是遍历一个副本,无论怎样,这个需求很容易发生,在实现观察者模式时要进行处理。
2.4.其他问题如果Subject是时间相关的业务,就要对每一个listener的运行时间加以约束,要能对每一个onNotify的调用时间进行监控并处理,以保持对每一个Listener的时间分配在一个合理的范围内。或者使用异步、多线程方式调起onNotify()。
如果Subject需要实现按优先级进行通知,那就要在优先级队列管理及通知调度上下功夫了。
3.总结观察者模式说得多,用得多,但在实际工作当中,要深入思考而不是完全照搬示例代码,这也是设计模式给我们的,要学会把它变成自己的经验。
——欢迎转载,请注明出处 http://blog.csdn.net/caowenbin ——
/* 寻找都有哪些子串 不能保证是字母或数字,所以子节点有差不多130个 */ #include <iostream> #include<string.h> #include<stdlib.h> using namespace std; int biaoshi[510]; const int kind = 130; int dulist[10]; struct node{ node *fail; //失败指针 node *next[kind]; int count; //是否为该单词的最后一个节点 node(){ //构造函数初始化 fail=NULL; count=0; memset(next,NULL,sizeof(next)); } }*q[5000000]; //队列,方便用于bfs构造失败指针 char keyword[510]; //输入的单词 char str[1000010]; //模式串 int head,tail; //队列的头尾指针 void insert(char *str,node *root,int no){ node *p=root; int i=0,index; while(str[i]){ index=str[i]-31; if(p->next[index]==NULL) p->next[index]=new node(); p=p->next[index]; i++; } p->count=no;//初始化为0,++后为1,表示是一个单词的结尾 } void build_ac_automation(node *root) { int i; root->fail=NULL; q[head++]=root; while(head!=tail) { node *temp=q[tail++];//拿到一个节点 node *p=NULL; for(i=0;i<130;i++) { if(temp->next[i]!=NULL)//若其i孩子非空 { if(temp==root) //他自己是头,其孩子的失败指针指向头 temp->next[i]->fail=root; else{ //普通节点 p=temp->fail; //指向自己的失败指针 while(p!=NULL) { if(p->next[i]!=NULL)//失败指针有i孩子 { temp->next[i]->fail=p->next[i]; //当前节点的i孩子的失败指针指向失败指针的i孩子,然后跳出 break; } p=p->fail; //继续找失败指针 } if(p==NULL) //若失败指针为空 temp->next[i]->fail=root; //当前节点的i孩子的失败指针指向头 } q[head++]=temp->next[i]; //进去的都是定义过失败指针的,故此过程是给其孩子定义失败指针 } } } } int query(node *root) { int i=0,cnt=0,index,len=strlen(str); node *p=root; while(str[i]) { index=str[i]-31; //计算孩子的位置 while(p->next[index]==NULL && p!=root) p=p->fail; //若没有i孩子节点,通过失败指针找与这之前相同的有i孩子的节点 p=p->next[index]; //指向其i孩子 p=(p==NULL)?root:p; node *temp=p; while(temp!=root && temp->count) { if(temp->count&&!biaoshi[temp->count])//主要是改这里 { cnt++; biaoshi[temp->count]=1; } temp=temp->fail; } i++; } return cnt; } int cmp(const void *a,const void *b) { int *c=(int*)a,*d=(int*)b; return *c-*d; } void print(int ji,int na,int n) { printf("web %d:",na); for(int i=1;i<=n;++i) { if(biaoshi[i]) { printf(" %d",i); } } printf("\n"); } int main(){ int n,t,i,j=0; while(scanf("%d",&n)!=EOF) { head=tail=0; node *root=new node(); getchar(); for(i=1;i<=n;i++) { gets(keyword); insert(keyword,root,i); } build_ac_automation(root); scanf("%d",&t); for(i=1;i<=t;++i) { memset(biaoshi,0,sizeof(biaoshi)); scanf("%s",str); int ge=query(root); if(ge) { print(ge,i,n); j++; } } printf("total: %d\n",j); } return 0; }