后臺(tái)采用Struts2+Spring2.5+Hibernate3的經(jīng)典模式。簡(jiǎn)約主義,體現(xiàn)在分層簡(jiǎn)約(三層:Action、service、dao)、結(jié)構(gòu)節(jié)約(類的解耦:Action一個(gè)類,通過DI調(diào)用Service。Service通過配置注入泛型基類dao的實(shí)例,無(wú)需手工書寫dao。添加一個(gè)Model,后臺(tái)就OK了)、配置節(jié)約,默認(rèn)的Struts無(wú)需進(jìn)行任何配置,因?yàn)槲覀円呀?jīng)采用了通配符的方式:
Struts.xml
1 <package name="page" extends="json-default" namespace="/page">
2 <action name="*/*" class="{1}Action" method="{2}">
4 <result name="success">/WEB-INF/pages/{1}/list.jsp</result>
5 <!-- 引入JSON,前臺(tái)用YUI展示 -->
6 <result name="json" type="json"/>
7 </action>
8 </package>
Spring需要配置如:
1 <!-- Service Begin -->
2 <bean id="userManager" class="com.aostar.service.UserManager">
3 <property name="sessionFactory" ref="sessionFactory" />
4 </bean>
5 <!-- Service End -->
6 <!-- Action Begin -->
7 <bean id="userAction" class="com.aostar.webapp.action.UserAction" scope="prototype">
8 <property name="userManager" ref="userManager" />
9 </bean>
10 <!-- Action End -->
Hibernate需要加一行:
1 <property name="annotatedClasses">
2 <list>
3 <value>com.aostar.model.User</value>
4 </list>
5 </property>
因?yàn)槲覀儾捎昧薐PA,避免手工書寫xml。
至于前臺(tái),與后臺(tái)的聯(lián)系是單純的數(shù)據(jù)交換,JSON格式的數(shù)據(jù)很適合在有限的帶寬里無(wú)限奔跑?;诖?,數(shù)據(jù)交換格式采用JSON,而前臺(tái)UI使用YUI制作。話說YUI還是不錯(cuò)的,文檔一應(yīng)俱全(雖然是英文),效果也很可贊。
前臺(tái),一個(gè)頁(yè)面搞定CURD:
1 <script type="text/javascript">
2 YAHOO.namespace("aostar.container");
3
4 var myDataTable,myDataSource;
5 //啟動(dòng)時(shí)載入,獲取JSON數(shù)據(jù),初始化列表
6 YAHOO.util.Event.addListener(window, "load", function() {
7 YAHOO.aostar.USERJSON = new function() {
8 var myColumnDefs = [
9 {key:"id", sortable:true, resizeable:true},
10 {key:"name",sortable:true, resizeable:true},
11 {key:"module",sortable:true, resizeable:true},
12 {key:"note"},
13 {key:"active"}
14 ];
15
16 myDataSource = new YAHOO.util.DataSource("jsonList.action");
17 myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
18 myDataSource.connXhrMode = "queueRequests";
19 myDataSource.responseSchema = {
20 resultsList: "page.list",
21 fields: ["id","name","module","note","active"]
22 };
25
26 myDataTable = new YAHOO.widget.DataTable("json", myColumnDefs,
27 myDataSource, {initialRequest:""});
28
29 myDataTable.subscribe("checkboxClickEvent", function(oArgs){
30 var elCheckbox = oArgs.target;
31 var oRecord = this.getRecord(elCheckbox);
32 oRecord.setData("check",elCheckbox.checked);
33 });
34
35 //監(jiān)聽row的相關(guān)行為
36 myDataTable.subscribe("rowMouseoverEvent", myDataTable.onEventHighlightRow);
37 myDataTable.subscribe("rowMouseoutEvent", myDataTable.onEventUnhighlightRow);
38 myDataTable.subscribe("rowClickEvent", myDataTable.onEventSelectRow);
39 };
40 });
41 //處理Dialog的各種動(dòng)作
42 function init() {
43 // 處理Dialog層的各種觸發(fā)動(dòng)作
44 var handleSubmit = function() {
45 this.submit();
46 };
47 var handleCancel = function() {
48 YAHOO.aostar.container.dlg.form.reset();
49 this.cancel();
50 };
51 var handleSuccess = function(o) {
52 var m,response;
53 try {
54 m = YAHOO.lang.JSON.parse(o.responseText);
55 }
56 catch (x) {
57 alert("解析JSON失敗!");
58 return;
59 }
60 YAHOO.aostar.container.dlg.form.reset();
61 if(m.message=="create"){
62 response = "新增表成功,點(diǎn)擊“確定”刷新頁(yè)面"
63 }else if(m.message=="update"){
64 response = "更新表成功,點(diǎn)擊“確定”刷新頁(yè)面"
65 }
66 if (confirm(response)) {
67 window.location.reload();
68 }
69 };
70 var handleFailure = function(o) {
71 alert("提交失敗: " + o.status);
72 };
73
74 var batchDeleteMethod = {
75 success : function (o) {
76 var m,response;
77 try {
78 m = YAHOO.lang.JSON.parse(o.responseText);
79 }
80 catch (x) {
81 alert("解析JSON失敗!");
82 return;
83 }
84 if(m.message=="delete"){
85 response = "刪除表成功,點(diǎn)擊“確定”刷新頁(yè)面"
86 }
87 if (confirm(response)) {
88 window.location.reload();
89 }
90 },
91 failure : function (o) {
92 if (!YAHOO.util.Connect.isCallInProgress(o)) {
93 alert("服務(wù)調(diào)用失敗!");
94 }
95 },
96 timeout : 3000
97 };
98
99 //編輯方法
100 var editRowData = function(e){
101 //var oRecord = myDataTable.getRecord(myDataTable.getFirstTrEl());
102 var oRecord;
103 var selectRows = myDataTable.getSelectedRows();
104 if(selectRows.length!=null && selectRows.length==1){
105 oRecord = myDataTable.getRecordSet().getRecord(selectRows[0]);
106 var formData = YAHOO.aostar.container.dlg.form;
107 formData.reset();
108 formData.id.value = YAHOO.lang.dump(oRecord.getData("id"));
109 formData.name.value = YAHOO.lang.dump(oRecord.getData("name"));
110 formData.module.value = YAHOO.lang.dump(oRecord.getData("module"));
111 formData.active.value = YAHOO.lang.dump(oRecord.getData("active"));
112 formData.note.value = YAHOO.lang.dump(oRecord.getData("note"));
113 YAHOO.aostar.container.dlg.show();
114 }else{
115 alert("請(qǐng)選中一行進(jìn)行編輯");
116 }
117 }
118 //刪除方法
119 var deleteRowData = function(e){
120 //var oRecord = myDataTable.getRecord(myDataTable.getFirstTrEl());
121 var oRecord;
122 var selectRows = myDataTable.getSelectedRows();
123 if(selectRows.length>0){
124 var sId="{id:[";
125 for(var i=0;i<selectRows.length;i++){
126 oRecord = myDataTable.getRecordSet().getRecord(selectRows[i]);
127 if(i>0){
128 sId += ",";
129 }
130 sId += YAHOO.lang.dump(oRecord.getData("id"));
131 }
132 sId += "]}";
133 }else{
134 alert("請(qǐng)選中行進(jìn)行刪除");
135 }
136 YAHOO.util.Connect.asyncRequest('GET',"batchDelete.action?batchId="+sId, batchDeleteMethod);
137 }
138 //定義Dialog的一些屬性
139 YAHOO.aostar.container.dlg = new YAHOO.widget.Dialog("dlg",
140 { width : "30em",
141 fixedcenter : true,
142 visible : false,
143 constraintoviewport : true,
144 modal: true,//hideMask
145 buttons : [ { text:"提交", handler:handleSubmit, isDefault:true },
146 { text:"取消", handler:handleCancel } ]
147 });
148
149 // 進(jìn)行數(shù)據(jù)驗(yàn)證的方法
150 YAHOO.aostar.container.dlg.validate = function() {
151 var data = this.getData();
152 if (data.name == "" || data.module == "") {
153 alert("請(qǐng)輸入名字和所屬模塊");
154 return false;
155 } else {
156 return true;
157 }
158 };
159
160 // Wire up the success and failure handlers
161 YAHOO.aostar.container.dlg.callback = { success: handleSuccess,
162 failure: handleFailure };
163
164 //裝配Dialog層
165 YAHOO.aostar.container.dlg.render();
166
167 YAHOO.util.Event.addListener("addtable", "click", YAHOO.aostar.container.dlg.show, YAHOO.aostar.container.dlg, true);
168 YAHOO.util.Event.addListener("edittable", "click", editRowData);
169 YAHOO.util.Event.addListener("deletetable", "click", deleteRowData);
170 }
171 YAHOO.util.Event.onDOMReady(init);
172 </script>
看到這里,似乎這個(gè)架構(gòu)不過平平,類似的東東網(wǎng)上一抓一把。OK,接下來說到重點(diǎn)。
我們知道,在傳統(tǒng)的架構(gòu)里,前臺(tái)只是管理業(yè)務(wù)數(shù)據(jù)的地方。而程序數(shù)據(jù)和程序結(jié)構(gòu)則在如迷宮一般的后臺(tái)里,或者需要到浩如煙海的文檔中搜尋。一批接一批的開發(fā)人員前仆后繼,軟件越來越迷宮,文檔越來越蕪雜,維護(hù)也越發(fā)困難。
既然hibernate已經(jīng)把數(shù)據(jù)表作為對(duì)象在后臺(tái)進(jìn)行管理了,為何我們不能開發(fā)出一個(gè)前臺(tái)管理版的hibernate?在前臺(tái)可以看到每個(gè)表的名字、所屬模塊、作用。點(diǎn)開以后可以看到每個(gè)字段的說明及索引等,何等直觀。而且做好這一切后,將數(shù)據(jù)表直接轉(zhuǎn)化為Web頁(yè)面的工作也會(huì)迅速很多,可以通過程序和模板直接進(jìn)行轉(zhuǎn)換。這樣,我們把后臺(tái)數(shù)據(jù)表和前臺(tái)頁(yè)面有機(jī)的聯(lián)合起來,而且都作為對(duì)象進(jìn)行管理了。對(duì)于后來的維護(hù)者也大大的便利了。這個(gè)想法,我們可以稱之為“數(shù)據(jù)注冊(cè)機(jī)制”。
軟件,是對(duì)資源的管理。不管是業(yè)務(wù)資源還是程序本身的資源,一個(gè)架構(gòu)良好的軟件可以對(duì)他們進(jìn)行清晰和方便的管理。既然我們有了“數(shù)據(jù)注冊(cè)機(jī)制”,那么下一步,我們還可以有“類注冊(cè)機(jī)制”、“包注冊(cè)機(jī)制”……如果能把軟件本身相應(yīng)的資源管理起來。那么所謂DDD、安全、SOA等模式,都可以有一個(gè)良好的開始和基礎(chǔ)。
附上YUI+JSON版的前臺(tái)架構(gòu)樣式:
http://www.tkk7.com/Files/shenlei/ssh+yui.rar