
2008年10月20日
作者:羅代均 ldj_work#126.com,轉(zhuǎn)載請保持完整性
環(huán)境說明
Apache :apache_2.0.55 1 個
Tomcat: apache-tomcat-5.5.17 (zip版) 2個
mod_jk:: mod_jk-apache-2.0.55.so 1個
第一部分:負(fù)載均衡
負(fù)載均衡,就是apache將客戶請求均衡的分給tomcat1,tomcat2....去處理
1.安裝apche,tomcat
http://httpd.apache.org/ 下載Apache 2.0.55
http://tomcat.apache.org/download-55.cgi 下載tomcat5.5 zip版本(解壓即可,綠色版)
http://apache.justdn.org/tomcat/tomcat-connectors/jk/binaries/win32/jk-1.2.15/ 下載mod_jk,注意和 apache版本匹配
按照jdk,我的路徑為:E:\ide\apache\Apache2
解壓兩份Tomcat, 路徑分別為 E:\ide\tomcat1,E:\ide\tomcat2
下載mod_jk
2.修改Apache配置文件http.conf
在apache安裝目錄下conf目錄中找到http.conf
在文件最后加上下面一句話就可以了
include "E:\ide\apache\Apache2\conf\mod_jk.conf"
2. http.conf 同目錄下新建mod_jk.conf文件,內(nèi)容如下
#加載mod_jk Module
LoadModule jk_module modules/mod_jk-apache-2.0.55.so
#指定 workers.properties文件路徑
JkWorkersFile conf/workers.properties
#指定那些請求交給tomcat處理,"controller"為在workers.propertise里指定的負(fù)載分配控制器
JkMount /*.jsp controller
3.在http.conf同目錄下新建 workers.properties文件,內(nèi)容如下
worker.list = controller,tomcat1,tomcat2 #server 列表
#========tomcat1========
worker.tomcat1.port=8009 #ajp13 端口號,在tomcat下server.xml配置,默認(rèn)8009
worker.tomcat1.host=localhost #tomcat的主機(jī)地址,如不為本機(jī),請?zhí)顚慽p地址
worker.tomcat1.type=ajp13
worker.tomcat1.lbfactor = 1 #server的加權(quán)比重,值越高,分得的請求越多
#========tomcat2========
worker.tomcat2.port=9009 #ajp13 端口號,在tomcat下server.xml配置,默認(rèn)8009
worker.tomcat2.host=localhost #tomcat的主機(jī)地址,如不為本機(jī),請?zhí)顚慽p地址
worker.tomcat2.type=ajp13
worker.tomcat2.lbfactor = 1 #server的加權(quán)比重,值越高,分得的請求越多
#========controller,負(fù)載均衡控制器========
worker.controller.type=lb
worker.controller.balanced_workers=tomcat1,tomcat2 #指定分擔(dān)請求的tomcat
worker.controller.sticky_session=1
4.修改tomcat配置文件server.xml
如果你在不同電腦上安裝tomcat,tomcat的安裝數(shù)量為一個,可以不必修改tomcat配置文件
我這里是在同一臺電腦上安裝兩個tomcat,所以需要更改其中一個的設(shè)置
打開tomcat2/conf/server.xml文件

5.編寫一個測試jsp
建立一個目錄test.里面新建一個test.jsp,內(nèi)容為
<%
System.out.println("===========================");
%>
把test放到tomcat1,tomcat2的webapps下
6.啟動apache,tomcat1,tomcat2,進(jìn)行測試
再刷新一次,tomcat2也打印了一條,再刷新,可以看到請求會被tomcat1,tomcat2輪流處理,實(shí)現(xiàn)了負(fù)載均衡
第二部分,配置集群
只配置負(fù)載均衡還不行,還要session復(fù)制,也就是說其中任何一個tomcat的添加的session,是要同步復(fù)制到其它tomcat, 集群內(nèi)的tomcat都有相同的session
1. 修改tomcat1, tomcat2的server.xml,將集群部分配置的在注釋符刪掉,并將tomcat2的4001端口改為4002,以避免與tomcat沖突,當(dāng)然,如果是兩臺電腦,是不用改端口的,去掉注釋符即可

2,修改測試項目test
修改test.jsp,內(nèi)容如下
<%@ page contentType="text/html; charset=GBK" %>
<%@ page import="java.util.*" %>
<html><head><title>Cluster App Test</title></head>
<body>
Server Info:
<%
out.println(request.getLocalAddr() + " : " + request.getLocalPort()+"<br>");%>
<%
out.println("<br> ID " + session.getId()+"<br>");
// 如果有新的 Session 屬性設(shè)置
String dataName = request.getParameter("dataName");
if (dataName != null && dataName.length() > 0) {
String dataValue = request.getParameter("dataValue");
session.setAttribute(dataName, dataValue);
}
out.print("<b>Session 列表</b>");
Enumeration e = session.getAttributeNames();
while (e.hasMoreElements()) {
String name = (String)e.nextElement();
String value = session.getAttribute(name).toString();
out.println( name + " = " + value+"<br>");
System.out.println( name + " = " + value);
}
%>
<form action="index.jsp" method="POST">
名稱:<input type=text size=20 name="dataName">
<br>
值:<input type=text size=20 name="dataValue">
<br>
<input type=submit>
</form>
</body>
</html>
然后在test 新建WEB-INF目錄,WEB-INF下新建web.xml,內(nèi)容如下
注意:在你的應(yīng)用的web.xml加入 <distributable/> 即可
ok,講test復(fù)制到tomcat1,tomcat2的webapps下,重啟apache,tomcat1,tomcat2,
新建一個 名稱為 xiaoluo ,值為 cdut 的session,提交查詢,新開一個ie窗口,再提交查詢,如圖,可以看到,兩個tomcat 是負(fù)載均衡,并且session同步的
posted @
2008-10-20 08:49 Loy Fu 閱讀(527) |
評論 (0) |
編輯 收藏

2008年10月4日
前臺:
Store:
var resource = new Ext.data.Store({
fields: ['imgpath','typeImage','title', 'type'],
url: 'teaching/resource/resourceAction.evi?method=getResourceList',
reader: new Ext.data.XmlReader(
{
record: "Item",
totalRecords: "TotalCount"
},
[{name:'title',mapping: 'title'}, {name:'type',mapping: 'type'},{name:'imgpath',mapping: 'imgpath'},{name:'typeImage',mapping: 'typeImage'} ]
)
});
resource.addListener('load', function(st, rds, opts) {
// st 是當(dāng)前的store, rds是讀到的Record[], opts是store的配置
for( var c=0; c<rds.length; c++ ) {
rds[c].set('typeImage', "<img src='./images/33.gif' width='12' height='12' />");
//待定類別,先定死類別圖片
}
});
resource.load({params:{start:0,limit:10}});
var resourceType = new Ext.data.Store({
,
reader: new Ext.data.XmlReader({
record: "Item"
}, [
{name: 'resourceTypeId', mapping: 'resourceTypeId'},
{name: 'resourceType', mapping: 'resourceType'}
])
});
resourceType.load();
var languageType = new Ext.data.Store({
,
reader: new Ext.data.XmlReader({
record: "Item"
}, [
{name: 'languageTypeId', mapping: 'languageTypeId'},
{name: 'languageType', mapping: 'languageType'}
])
});
languageType.load();
列表:
resourcePanel = new Ext.grid.GridPanel({
id: 'resources',
frame: true,
header: false,
width: 288,
autoWidth: true,
autoHeight: true,
loadMask:{msg:'正在加載數(shù)據(jù),請稍侯……'},
iconCls:'icon-grid',
viewConfig: { forceFit: true },
columns:[
{header: " ",dataIndex: 'typeImage' , width:20},
{header: "資源標(biāo)題", width: 190, sortable: true, dataIndex: 'title'},
{header: "類別", width: 80, sortable: true, dataIndex: 'type'}
],
store: resource,
selModel: new Ext.grid.RowSelectionModel({singleSelect:false}),
bbar: new Ext.PagingToolbar({
pageSize: 10,
store: resource,
displayInfo: false,
//displayMsg: '顯示第 {0} 條到 {1} 條記錄,一共 {2} 條',
emptyMsg: "沒有記錄"
}),
listeners: {
rowclick:function(e) {
try {
window.parent.parent.Ext.ux.MyTips.msg("提示", "雙擊該行可預(yù)覽該資源");
} catch(e) {}
},
rowdblclick:function(g, rIdx, e) {
var rd = g.getStore().getAt(rIdx);
var html = "<img src='./images/" + rd.get('imgpath') + "' />";
window.parent.showWin({
layout: 'fit',
maximizable: true,
title: rd.get('title'),
width: 400,
height: 400,
//modal: true,
//closeAction: 'hide',
plain: true,
items: [ {html: html} ]
});
}
}
});
FormPanel:
var rform = new Ext.form.FormPanel({
id:'rform',
header: false,
frame: true,
hideBorders: false,
items: [
new Ext.form.TextField({
fieldLabel: '關(guān)鍵字',
name:'keyword'
}),
new Ext.form.ComboBox({
fieldLabel: '資源類別',
mode: 'local',
triggerAction: 'all',
store: resourceType,
typeAhead: true,
hiddenName:'resourceTypeId',
displayField: 'resourceType',
valueField: 'resourceTypeId',
readOnly: true,
selectOnFocus: true
}),
new Ext.form.ComboBox({
fieldLabel: '語言',
mode: 'local',
triggerAction: 'all',
typeAhead: true,
hiddenName:'languageTypeId',
displayField:'languageType',
valueField:'languageTypeId',
readOnly: true,
selectOnFocus: true,
store:languageType
}),
new Ext.Panel({
layout: 'table',
buttonAlign: 'center',
layoutConfig: { colspan: 3 },
buttons:[{text: '搜 尋',
handler: function() {
var keyword = Ext.get('keyword').dom.value;
var resourceTypeId = Ext.get('resourceTypeId').dom.value;
var languageTypeId = Ext.get('languageTypeId').dom.value;
resource.reload({params:{start:0,limit:3,keyword:keyword,resourceTypeId:resourceTypeId,languageTypeId:languageTypeId}});
//這里不用再寫ajax,Ext已經(jīng)封裝了ajax,只要把參數(shù)傳進(jìn)去就行了
}},
{
text: '重 置',
handler: function() {
Ext.getCmp('rform').form.reset();
}
}
]
})
]
})
后臺:
public ActionForward getResourceList(ActionMapping mapping,
ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws IOException {
Document document = DocumentHelper.createDocument();
String start = request.getParameter("start");
String limit = request.getParameter("limit");
String keyword = request.getParameter("keyword");
String resourceTypeId = request.getParameter("resourceTypeId");
String languageTypeId = request.getParameter("languageTypeId");
List<HqlCondition> hqlFilter = new LinkedList<HqlCondition>();
if(keyword != null && keyword.length()>0){
hqlFilter.add( new HqlCondition("and", "rs.title", "like", "%" + keyword + "%", HqlCondition.String) );
hqlFilter.add( new HqlCondition("or", "rs.remarks", "like", "%" + keyword + "%", HqlCondition.String) );
}
if(resourceTypeId != null && resourceTypeId.length()>0){
hqlFilter.add( new HqlCondition("and", "rs.resourceType.resourceTypeId", "=", new Long(resourceTypeId), HqlCondition.Long) );
}
if(languageTypeId != null && languageTypeId.length()>0){
hqlFilter.add( new HqlCondition("and", "rs.languageType.languageTypeId", "=", new Integer(languageTypeId), HqlCondition.Integer) );
}
int pageno =1;
int pagesize = 10;
if(limit != null && limit.length()>0){
pagesize = Integer.parseInt(limit);
}
if(!start.equalsIgnoreCase("0") && start != null && start.length()>0){
int bpos = Integer.parseInt(start);
pageno = (bpos + pagesize)/pagesize;
}
int total = this.rse.getResourceTotalCount(hqlFilter);
Collection<BaseVO> coll = this.rse.getResourceList(hqlFilter,pageno,pagesize);
Iterator<BaseVO> it = coll.iterator();
while(it != null && it.hasNext()){
BaseVO bv = it.next();
ResourceType rt = this.rts.getResourceType(((ResourceType)bv.get("resourceType")).getResourceTypeId());
bv.set("type", rt.getResourceType());
}
document.addElement("type");
new OutputVOXml().writeXML(total,new LinkedList<BaseVO>(coll), response);
return null;
}
posted @
2008-10-04 22:43 Loy Fu 閱讀(1376) |
評論 (0) |
編輯 收藏
Apache
提供的一個插件包,可以把Action
中的數(shù)據(jù)以JSON
做個封裝然后返回。
它會將整個action中的變量轉(zhuǎn)化為JSON數(shù)據(jù)(根對象在JSON中數(shù)據(jù)添加一個”root”標(biāo)識)。如果要使用它,Action必須遵循以下幾點(diǎn):
1. 返回的頁面類型中”content-type”必須是”application/json”.(這個已經(jīng)Internet Community采用).
2. JSON內(nèi)容必須是符合格式要求的.
3. Action中field必須有public的set方法.(是不是沒有set方法就不會將field添加到JSON數(shù)據(jù)中,有待驗(yàn)證).
4. 它支持的類型有: 基本類型(int,long...String), Date, List, Map, Primitive Arrays, 其它class, 對象數(shù)組.
5. 在JSON中任何的Object會被封裝在list或map中,數(shù)據(jù)會被封裝程Long,如果是含有的數(shù)據(jù)則會被封裝程Double,數(shù)組會被封裝程List.
下面給出JSON的數(shù)據(jù)格式:
{
"doubleValue": 10.10,
"nestedBean": {
"name": "Mr Bean"
},
"list": ["A", 10, 20.20, {
"firstName": "El Zorro"
}],
"array": [10, 20]
}
說明:
a. 這個插件支持以下幾個注釋:
注釋名
|
簡介
|
默認(rèn)值
|
序列化
|
反序列化
|
name
|
配置JSON中name
|
empty
|
yes
|
no
|
serialize
|
在serialization中
|
true
|
yes
|
no
|
deserialize
|
在deserialization中
|
true
|
no
|
yes
|
format
|
格式化Date字段
|
"yyyy-MM-dd'T'HH:mm:ss"
|
yes
|
yes
|
可以通過配置來顯示指出要放在JSON中field,其中有個自己的驗(yàn)證規(guī)則需要研究.
<!-- Result fragment -->
<result type="json">
<param name="excludeProperties">
login.password,
studentList.*".sin
</param>
</result>
<!-- Interceptor fragment -->
<interceptor-ref name="json">
<param name="enableSMD">true</param>
<param name="excludeProperties">
login.password,
studentList.*".sin
</param>
</interceptor-ref>
b. 根對象
<result type="json">
<param name="root">
person.job
</param>
</result>
也可以使用攔截器配置操作父對象
<interceptor-ref name="json">
<param name="root">bean1.bean2</param>
</interceptor-ref>
c. 將JSON數(shù)據(jù)用注釋封裝
如果wrapWithComments設(shè)置為true(默認(rèn)值為false),則生成的JSON數(shù)據(jù)會變成這樣:
/* {
"doubleVal": 10.10,
"nestedBean": {
"name": "Mr Bean"
},
"list": ["A", 10, 20.20, {
"firstName": "El Zorro"
}],
"array": [10, 20]
} */
這樣做可以避免js中一些潛在的風(fēng)險,使用時需要:
Var responseObject = eval("("+data.substring(data.indexOf(""/"*")+2, data.lastIndexOf(""*"/"))+")");
d. 父類
“root”對象中父類的field不會默認(rèn)存放到JSON數(shù)據(jù)中,如果不想這樣做,需要在配置時指定ignoreHierarchy為false:
<result type="json">
<param name="ignoreHierarchy">false</param>
</result>
e. 枚舉類型
默認(rèn)處理枚舉類型時,會被處理成JSON數(shù)據(jù)中name等于枚舉中value而value等于枚舉中name.
public enum AnEnum {
ValueA,
ValueB
}
JSON: "myEnum":"ValueA"
如果在處理枚舉類型時,在xml中配置了enumAsBean,則會被當(dāng)作一個Bean處理,在JSON數(shù)據(jù)中會有一個特別的屬性”_name”值為name().這個枚舉中的所有屬性都會被處理.
public enum AnEnum {
ValueA("A"),
ValueB("B");
private String val;
public AnEnum(val) {
this.val = val;
}
public getVal() {
return val;
}
}
JSON: myEnum: { "_name": "ValueA", "val": "A" }
Xml中配置:
<result type="json">
<param name="enumAsBean">true</param>
</result>
f. 例子
a) Action
import java.util.HashMap;
import java.util.Map;
import com.opensymphony.xwork2.Action;
public class JSONExample {
private String field1 = "str";
private int[] ints = {10, 20};
private Map map = new HashMap();
private String customName = "custom";
//'transient' fields are not serialized
private transient String field2;
//fields without getter method are not serialized
private String field3;
public String execute() {
map.put("John", "Galt");
return Action.SUCCESS;
}
public String getField1() {
return field1;
}
public void setField1(String field1) {
this.field1 = field1;
}
public int[] getInts() {
return ints;
}
public void setInts(int[] ints) {
this.ints = ints;
}
public Map getMap() {
return map;
}
public void setMap(Map map) {
this.map = map;
}
@JSON(name="newName")
public String getCustomName() {
return this.customName;
}
}
b) Xml配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="example" extends="json-default">
<action name="JSONExample" class="example.JSONExample">
<result type="json"/>
</action>
</package>
</struts>
這里有兩個地方需要注意:
1) 需要繼承json-default包
2) <result>簽的定義
c) JSON數(shù)據(jù)
{
"field1" : "str",
"ints": [10, 20],
"map": {
"John":"Galt"
},
"newName": "custom"
}
d) JSON RPC
JSON插件可以在js中調(diào)用action方法,返回執(zhí)行結(jié)果。這個已經(jīng)在dojo中有了實(shí)現(xiàn),可以用Simple Method Definition調(diào)用遠(yuǎn)程服務(wù)。來一起看看下面的例子:
首先寫一個Action:
package smd;
import com.googlecode.jsonplugin.annotations.SMDMethod;
import com.opensymphony.xwork2.Action;
public class SMDAction {
public String smd() {
return Action.SUCCESS;
}
@SMDMethod
public Bean doSomething(Bean bean, int quantity) {
bean.setPrice(quantity * 10);
return bean;
}
}
e) 方法必須用SMDMethod加上注解,這樣才能被遠(yuǎn)程調(diào)用,為了安全因素。這個方法會產(chǎn)生一個bean對象,實(shí)現(xiàn)修改價格的功能。Action被添加上SMD注解會生成一個SMD,同時參數(shù)也會被加上SMDMethodParameter注解。像你所看到的,Action中定義了一個空方法:smd。這個方法是作為Simple Method Definition (定義class中提供的服務(wù)),在struts.xml配置<result>時使用type屬性值為”json”。
下面是bean的定義:
package smd;
public class Bean {
private String type;
private int price;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
Xml文件:
<package name="RPC" namespace="/nodecorate" extends="json-default">
<action name="SMDAction" class="smd.SMDAction" method="smd">
<interceptor-ref name="json">
<param name="enableSMD">true</param>
</interceptor-ref>
<result type="json">
<param name="enableSMD">true</param>
</result>
</action>
</package>
這里需要注意一點(diǎn):” enableSMD”這個必須在interceptor和result都要配置.
Js代碼:
<s:url id="smdUrl" namespace="/nodecorate" action="SMDAction" />
<script type="text/javascript">
//load dojo RPC
dojo.require("dojo.rpc.*");
//create service object(proxy) using SMD (generated by the json result)
var service = new dojo.rpc.JsonService("${smdUrl}");
//function called when remote method returns
var callback = function(bean) {
alert("Price for " + bean.name + " is " + bean.price);
};
//parameter
var bean = {name: "Mocca"};
//execute remote method
var defered = service.doSomething(bean, 5);
//attach callback to defered object
defered.addCallback(callback);
</script>
JsonService會發(fā)出一個請求到action加載SMD,同時遠(yuǎn)程方法會返回一個JSON對象,這個過程是Dojo給action中的方法創(chuàng)建了一個Proxy。因?yàn)檫@是異步調(diào)用過程,當(dāng)遠(yuǎn)程方法執(zhí)行的時候,它會返回一個對象到callback方法中。
f) 代理的對象
當(dāng)使用的注解不是繼承自Java,可能你使用代理會出現(xiàn)一些問題。比如:當(dāng)你使用aop攔截你的action的時候。在這種情況下,這個插件不會自動發(fā)現(xiàn)注解的方法。為了避免這種情況發(fā)生,你需要在xml中配置ignoreInterfaces為false,這樣插件會自己查找注解的所有接口和父類。
注意:這個參數(shù)只有在Action執(zhí)行的過程是通過注解來運(yùn)行的時候才應(yīng)該設(shè)為false。
<action name="contact" class="package.ContactAction" method="smd">
<interceptor-ref name="json">
<param name="enableSMD">true</param>
<param name="ignoreInterfaces">false</param>
</interceptor-ref>
<result type="json">
<param name="enableSMD">true</param>
<param name="ignoreInterfaces">false</param>
</result>
<interceptor-ref name="default"/>
</action>
posted @
2008-10-04 14:45 Loy Fu 閱讀(7743) |
評論 (2) |
編輯 收藏
struts2的
json plugin的位置在:http://code.google.com/p/
jsonplugin/
下載
json plugin的jar包,放到/WEB-INF/lib/目錄下就可以了
Spring + Struts + JPA的項目結(jié)構(gòu)如其他例子中的一致
首先是web.xml
xml 代碼
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app id="WebApp_ID" version="2.4"
- xmlns="http://java.sun.com/xml/ns/j2ee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
- <display-name>quickstart</display-name>
- <filter>
- <filter-name>struts2</filter-name>
- <filter-class>
- org.apache.struts2.dispatcher.FilterDispatcher
- </filter-class>
- </filter>
- <filter>
- <filter-name>jpaFilter</filter-name>
- <filter-class>
- org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
- </filter-class>
- <init-param>
- <param-name>entityManagerFactory</param-name>
- <param-value>entityManagerFactory</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>jpaFilter</filter-name>
- <url-pattern>*.action</url-pattern>
- </filter-mapping>
- <filter-mapping>
- <filter-name>struts2</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <welcome-file-list>
- <welcome-file>index.jsp</welcome-file>
- </welcome-file-list>
- <listener>
- <listener-class>
- org.springframework.web.context.ContextLoaderListener
- </listener-class>
- </listener>
- </web-app>
加入
jpaFilter,是為了不讓hibernate的session過早關(guān)閉,因?yàn)橛械腶ction會通過ajax動態(tài)調(diào)用。
下面是struts.xml,注意struts.xml需要放在源代碼目錄下面:
xml 代碼
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE struts PUBLIC
- "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
- "http://struts.apache.org/dtds/struts-2.0.dtd">
- <struts>
- <constant name="struts.objectFactory" value="spring" />
- <constant name="struts.devMode" value="true" />
- <constant name="struts.i18n.encoding" value="UTF-8"/>
- <package name="person" extends="json-default">
- <action name="list" method="execute" class="personaction">
- <result type="json"/>
- </action>
- </package>
- </struts>
這里注意,struts.objectFactory告訴struts所有的action都到spring的上下文里面去找,另外還需要注意,我們自己的包要繼承自json-default,這樣才可以在result的type屬性中使用json。
下面是spring的配置文件applicationContext.xml:
xml 代碼
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
- <bean
- class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
- <bean id="entityManagerFactory"
- class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
- <property name="dataSource" ref="dataSource" />
- <property name="jpaVendorAdapter">
- <bean
- class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
- <property name="database" value="MYSQL" />
- <property name="showSql" value="true" />
- </bean>
- </property>
- </bean>
- <bean id="dataSource"
- class="org.springframework.jdbc.datasource.DriverManagerDataSource">
- <property name="driverClassName" value="com.mysql.jdbc.Driver" />
- <property name="url" value="jdbc:mysql://localhost/extjs" />
- <property name="username" value="root" />
- <property name="password" value="" />
- </bean>
-
-
- <bean id="transactionManager"
- class="org.springframework.orm.jpa.JpaTransactionManager">
- <property name="entityManagerFactory"
- ref="entityManagerFactory" />
- </bean>
- <tx:annotation-driven transaction-manager="transactionManager" />
-
- <bean id="personService" class="com.myext.service.impl.PersonServiceJpaImpl"/>
- <bean id="personaction" class="com.myext.action.PersonPageAction">
- <property name="person" ref="personService"/>
- </bean>
- </beans>
這里的bean personaction和strutx.xml中的action class一致就可以了,下面是代碼:
action:
java 代碼
- package com.myext.action;
-
- import java.util.ArrayList;
- import java.util.List;
-
- import com.myext.service.PersonService;
-
- public class PersonPageAction {
- private int limit=10;
- private int start=0;
- private PersonService person;
- private int total=0;
- private List persons = new ArrayList();
- private boolean success=true;
- public boolean getSuccess(){
- return this.success;
- }
- public void setLimit(int limit) {
- this.limit = limit;
- }
-
- public void setStart(int start) {
- this.start = start;
- }
-
-
- public void setPerson(PersonService person) {
- this.person = person;
- }
-
- public int getTotal() {
- return total;
- }
-
- public void setTotal(int total) {
- this.total = total;
- }
-
- public List getPersons() {
- return persons;
- }
-
- public void setPersons(List persons) {
- this.persons = persons;
- }
-
- public String execute(){
- this.total = person.getTotal();
- this.persons = person.getPage(this.start, this.limit);
- return "success";
- }
- }
service:
java 代碼
- package com.myext.service.impl;
-
- import java.util.List;
-
- import javax.persistence.EntityManager;
- import javax.persistence.PersistenceContext;
- import javax.persistence.Query;
-
- import com.myext.model.Person;
- import com.myext.service.PersonService;
-
- public class PersonServiceJpaImpl implements PersonService {
- private EntityManager em;
- private static String poname = Person.class.getName();
- @PersistenceContext
- public void setEntityManager(EntityManager em){
- this.em = em;
- }
- @SuppressWarnings("unchecked")
- @Override
- public List getPage( int start, int limit) {
- Query q = this.em.createQuery("from " + poname );
- q.setFirstResult(start);
- q.setMaxResults(limit);
- return q.getResultList();
- }
- @Override
- public int getTotal() {
- return this.em.createQuery("from " + poname).getResultList().size();
- }
-
- }
頁面的代碼:
xml 代碼
- xml version="1.0" encoding="UTF-8" ?>
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- >
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <title>Grid3title>
- <link rel="stylesheet" type="text/css" href="extjs/resources/css/ext-all.css" />
-
- <script type="text/javascript" src="extjs/adapter/ext/ext-base.js">script>
-
- <script type="text/javascript" src="extjs/ext-all.js">script>
- <script type="text/javascript" src="extjs/ext-lang-zh_CN.js">script>
- head>
- <body>
- <script type="text/javascript" src="grid3.js">script>
- <div id="grid3" >
- div>
- body>
- html>
grid3.js代碼
js 代碼
-
-
-
- Ext.onReady(function(){
- Ext.BLANK_IMAGE_URL = 'extjs/resources/images/default/s.gif';
- Ext.QuickTips.init();
- var sm = new Ext.grid.CheckboxSelectionModel(); //CheckBox選擇列
- var cm = new Ext.grid.ColumnModel([
- new Ext.grid.RowNumberer(), //行號列
- sm,
- {header:'編號',dataIndex:'id'},
- {header:'性別',dataIndex:'sex',renderer:function(value){
- if(value=='male'){
- return "男";
- }else{
- return "女";
- }
- }},
- {header:'名稱',dataIndex:'name'},
- {header:'描述',dataIndex:'descn'}
- ]);
-
-
- var ds = new Ext.data.Store({
- proxy: new Ext.data.HttpProxy({url:'list.action'}),//調(diào)用的動作
- reader: new Ext.data.JsonReader({
- totalProperty: 'total',
- root: 'persons',
- successProperty :'success'
- }, [
- {name: 'id',mapping:'id',type:'int'},
- {name: 'sex',mapping:'sex',type:'string'},
- {name: 'name',mapping:'name',type:'string'},
- {name: 'descn',mapping:'descn',type:'string'} //列的映射
- ])
- });
-
-
- var grid = new Ext.grid.GridPanel({
- el: 'grid3',
- ds: ds,
- sm: sm,
- cm: cm,
- width:700,
- height:280,
- bbar: new Ext.PagingToolbar({
- pageSize: 10,
- store: ds,
- displayInfo: true,
- displayMsg: '顯示第 {0} 條到 {1} 條記錄,一共 {2} 條',
- emptyMsg: "沒有記錄"
- }) //頁腳顯示分頁
- });
-
- grid.render();
- ds.load({params:{start:0, limit:10}}); //加載數(shù)據(jù)
- });
注意,這里的gridpanel一定要設(shè)置高度,否則數(shù)據(jù)是顯示不出來的。
最后啟動tomcat,在瀏覽器里輸入http://localhost:8080/extjs/grid3.jsp,就可以看到效果
posted @
2008-10-04 14:35 Loy Fu 閱讀(4532) |
評論 (2) |
編輯 收藏
摘要: http://prototype.conio.net/dist/
下載(對Ajax支持的prototype--js函數(shù)庫):
prototype-1.4.0.js
或
prototype-1.4.0.tar.gz
http://code.google.com/p/jsonplugin/downloads/list
下載(Struts2...
閱讀全文
posted @
2008-10-04 14:19 Loy Fu 閱讀(2058) |
評論 (0) |
編輯 收藏
關(guān)鍵字: Struts2 COC
摘要:介紹Struts2中的零配置(Zero Configuration),以及如何用COC來更好地簡化Struts2的配置。在第一章,我使用Maven來創(chuàng)建一個起點(diǎn)項目;第二章,以該項目為例,講解如何使用Struts2的零配置;第三章,論述第二章中的實(shí)現(xiàn)方式的缺陷,然后講解如何使用COC來改進(jìn)這些缺陷,并進(jìn)一步簡化Struts2的配置。附件是這篇文章用到的示例代碼。
一、從零開始
這里,我將建立一個新的示例項目,作為講解的起點(diǎn)。我使用JDK 6、Maven 2、Eclipse 3.3來建立這個示例,如果讀者對Maven2不熟也沒關(guān)系,這只是個示例。
首先,運(yùn)行下邊的命令:
mvn archetype:create -DgroupId=demo.struts -DartifactId=demo-struts-coc -DarchetypeArtifactId=maven-archetype-webapp
這會建立如下的目錄結(jié)構(gòu):
|- POM.xml
|- src
|- main
|- resources
|- webapp
|- index.jsp
|- WEB-INF
|- web.xml
然后我們在src/main目錄下新建一個名為java的目錄,用來放置java代碼。在src下建立test目錄,并在test目錄下建立java目錄,用來放置測試代碼。另外,我這個示例不想使用JSP,所以我將src/main/webapp目錄下的index.jsp改為index.html。
現(xiàn)在,需要配置該項目要用到哪些lib。在POM.xml中加入struts2-core:
xml 代碼
- <dependency>
- <groupId>org.apache.struts</groupId>
- <artifactId>struts2-core</artifactId>
- <version>2.0.9</version>
- </dependency>
另外,我想在Eclipse里使用jetty來啟動項目并進(jìn)行測試,所以在POM.xml中再加入jetty、jetty-util、servlet-api等的依賴,詳情見附件。
我希望使用Eclipse來作為這個項目的IDE,所以,我在命令行狀態(tài)下,進(jìn)入這個項目所在的目錄,運(yùn)行:
mvn eclipse:eclipse
然后使用Eclipse導(dǎo)入這個項目。如果你是第一次用Eclipse導(dǎo)入用Maven生成的項目,那你需要在Eclipse里配置一個名叫M2_REPO的Variable,指向你的Maven 2的repository目錄。缺省情況下,它應(yīng)該位于${user.home}/.m2/repository。
OK!現(xiàn)在我們已經(jīng)可以在Eclipse中進(jìn)行工作了。
修改src/main/webapp/WEB-INF/web.xml,加入struts2的FilterDispatcher并設(shè)置filter-mapping。在這個示例中我將url-pattern設(shè)為"/app/*",也就是說,url的匹配是基于路徑來做的。這只是我的個人喜好而已,你也可以將它設(shè)成"*"。
既然是在講struts2的零配置,當(dāng)然是可以不要任何配置文件的。但是為了更好地進(jìn)行“配置”,我還是建立了struts.xml文件(在src/main/resources目錄下)。我不喜歡url最后都有個action后綴,現(xiàn)在,我在struts.xml中配置struts.action.extension,將這個后綴去掉:
xml 代碼
- <struts>
- <constant name="struts.action.extension" value="" />
- </struts>
然后我在src/test/java下建立demo/RunJetty.java文件,main方法如下:
java 代碼
- public static void main(String[] args) throws Exception {
- Server server = new Server(8080);
- File rootDir = new File(RunJetty.class.getResource("/").getPath()).getParentFile().getParentFile();
- String webAppPath = new File(rootDir, "src/main/webapp").getPath();
- new WebAppContext(server, webAppPath, "/");
- server.start();
- }
現(xiàn)在,在Eclipse里運(yùn)行或調(diào)試這個RunJetty.java,用瀏覽器打開http://localhost:8080/看看吧。如果不出問題,應(yīng)該可以訪問到webapp目錄下的index.html了。有了Jetty,你還在用MyEclipse或其它插件么?
二、零配置
首先要澄清一點(diǎn),這里說的零配置并不是一點(diǎn)配置都沒有,只是說配置很少而已。
Struts2(我只用過Struts 2.0.6和2.0.9,不清楚其它版本是否支持零配置)引入了零配置的新特性,元數(shù)據(jù)可以通過規(guī)則和注解來表達(dá):A "Zero Configuration" Struts application or plugin uses no additional XML or properties files. Metadata is expressed through convention and annotation.
目前,這個新特性還在測試階段,但經(jīng)過一段時間的使用,我覺得這個特性已經(jīng)可用。下面我講一下如何使用它。
1. Actions的定位
以前需要在xml配置文件中配置Action的name和class,如果使用零配置,所帶來的一個問題就是如何定位這些Action。我們需要在web.xml中找到struts2的filter的配置,增加一個名為actionPackages的init-param,它的值是一個以逗號分隔的Java包名列表,比如:demo.actions1,demo.actions2。struts2將會掃描這些包(包括這些包下邊的子包),在這些包下,所有實(shí)現(xiàn)了Action接口的或者是類名以“Action”結(jié)尾的類都會被檢查到,并被當(dāng)做Action。
以前,我們寫Action必須要實(shí)現(xiàn)Action接口或者繼承ActionSupport。但是,上面提到的類名以"Action"結(jié)尾的類并不需要這樣做,它可以是一個POJO,Struts2支持POJO Action!
下面是actionPackages的配置示例:
xml 代碼
- <filter>
- <filter-name>struts2</filter-name>
- <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
- <init-param>
- <param-name>actionPackages</param-name>
- <param-value>demo.actions1,demo.actions2</param-value>
- </init-param>
- </filter>
2. 示例
現(xiàn)在我們建立demo.actions1.app.person和demo.actions2.app.group兩個包,在demo.actions1.app.person包下建立ListPeopleAction.java,在demo.actions2.app.group下建立ListGroupAction.java。作為示例,這兩個類只是包含一個execute方法,返回"success"或"error",其它什么都不做:
java 代碼
- public String execute() {
- return "success";
- }
在Filter的配置中,我指定actionPackages為demo.actions1,demo.actions2,當(dāng)系統(tǒng)啟動時,Struts2就會在這兩個包下掃描到demo.actions1.app.person.ListPeopleAction和demo.actions2.app.group.ListGroupAction。
3. Action and Package name
Struts2掃描到Action后,從actionPackages指定的包開始,子包名會成為這個Action的namespace,而Action的name則由這個Action的類名決定。將類名首字母小寫,如果類名以Action結(jié)尾,則去掉"Action"后綴,形成的名字就是這個Action的名字。在如上所述的示例中,actionPackages指定為demo.actions1,demo.actions2,那么你可以這樣訪問demo.actions1.app.person.ListPeopleAction:
http://localhost:8080/app/person/listPeople
4. Results
Struts2是通過"Result"和"Results"兩個類級別的annotations來指定Results的。
作為示例,我們在webapp目錄下建兩個html文件:success.html和error.html,隨便寫點(diǎn)什么內(nèi)容都可以。現(xiàn)在假設(shè)我們訪問/app/person/listPeople時,或Action返回success就轉(zhuǎn)到success.html頁面,若是error就轉(zhuǎn)到error.html頁面,這只需要在ListPeopleAction類上加上一段注解就可以了:
java 代碼
- @Results({
- @Result(name="success", type=NullResult.class, value = "/success.html", params = {}),
- @Result(name="error", type=NullResult.class, value = "/error.html", params = {})
- })
- public class ListPeopleAction {
- public String execute() {
- return "success";
- }
- }
同上,我們給ListGroupAction也加上注解。
現(xiàn)在,我們已經(jīng)完成了一個零配置的示例。我們并沒有在xml文件里配置ListPeopleAction和ListGroupAction,但它們已經(jīng)可以工作了!
用Eclipse運(yùn)行RunJetty,然后用瀏覽器訪問http://localhost:8080/app/person/listPeople和http://localhost:8080/app/group/listGroup看看,是不是正是success.html(或error.html)的內(nèi)容?
5. Namespaces
如上所述,namespace由包名所形成,但我們可以使用"Namespace"注解來自己指定namespace。
6. Parent Package
這個配置用得較少。Struts2提供一個"ParentPackage"注解來標(biāo)識Action應(yīng)該是屬于哪個package。
三、使用COC
如上所述,Struts2用注解來實(shí)現(xiàn)零配置。然而,這不是我喜歡的方式。在我看來,這不過是將配置從XML格式換成了注解方式,并不是真的零配置。而且,這種方式也未必比XML形式的配置更好。另外,對元數(shù)據(jù)的修改必然會導(dǎo)致項目的重新編譯和部署。還有,現(xiàn)在的Struts2版本似乎對Result注解中的params的處理有些問題。
其實(shí),Struts2的actionPackages配置已經(jīng)使用了COC,那為什么不能為Results也實(shí)現(xiàn)COC,從而去除這些每個Action都要寫的注解?
在嚴(yán)謹(jǐn)?shù)捻椖恐校琾ackage、action的名稱和頁面的路徑、名稱一定存在著某種關(guān)系。比如,頁面的路徑可能和package是對應(yīng)的,頁面的名稱可能和action的名稱是對應(yīng)的,或是根據(jù)某種法則運(yùn)算得到。我們知道webwork2和struts2有個配置叫g(shù)lobal-results。我們?yōu)槭裁床荒芨鶕?jù)這些對應(yīng)規(guī)則寫個Result,將它配到global-results中,從而真正免去result的配置?
事實(shí)上,我推薦Struts2的使用者只用Struts2輸出XML或JSON,放棄UI,頁面這層還是使用標(biāo)準(zhǔn)的HTML、CSS和一些JS組件來展現(xiàn)。許多人反映Struts2慢,確實(shí),Struts2是慢,很慢!慢在哪兒?很大一部分因素是UI這層引起的,特別是使用了過多的Struts2的tag,并使用了ajax theme。但是,如果我們放棄了Struts2的笨拙的UI,Result只輸出XML或JSON,UI則使用標(biāo)準(zhǔn)的HTML+CSS,使用JS組件(DOJO、Adobe Spry Framework、YUI-Ext等)來操作Struts2的輸出數(shù)據(jù),情況將會如何?我們會得到一個高性能、高可配的、UI和應(yīng)用服務(wù)器的職責(zé)分割更為明確、合理的、更易于靜態(tài)化部署的開發(fā)組合。
這似乎是閹割了Struts2,但是這樣閹割過的Struts2擺脫了性能低下的包袱,更輕、更現(xiàn)代化。
有些扯遠(yuǎn)了,言歸正傳,不管是讓Struts2輸出XML或JSON,還是輸出頁面,我們都有辦法根據(jù)項目的規(guī)則寫一個Result,將它配到global-results中,從而大大減少Result的配置。
假設(shè)我們讓Struts2只輸出JSON,有個jsonplugin可以做這件事。使用JsonResult時,不再需要知道頁面的位置、名稱等信息,它僅僅是數(shù)據(jù)輸出,那么我們就可以將這個Result配成全局的,大部分Action將不再需要Result的配置。
作為示例,我假設(shè)我的例子中輸出的兩個html頁面(success.html和error.html)是JSON,我們看看怎么免去我例子中的兩個Action的Result注解。
首先,我們刪去ListPeopleAction和ListGroupAction兩個Action的注解,并修改struts.xml文件,加入:
xml 代碼
- <package name="demo-default" extends="struts-default">
- <global-results>
- <result name="success">/success.html</result>
- </global-results>
- </package>
請記住這只是一個示例,為了方便,我沒在項目中加入jsonplugin來作真實(shí)的演示,我只是假設(shè)這個success是json輸出,讀者可以自行使用jsonplugin來作實(shí)驗(yàn)。
現(xiàn)在,離成功不遠(yuǎn)了,但是項目仍然不能正常運(yùn)行。我們的Action返回success,但并不會匹配到global-results中配置。為什么呢?因?yàn)椋覀冞@里是把global-results配置到"demo-default"這個package下的,而Struts2根據(jù)actionPackages找到的Action不會匹配到這個package上。解決辦法也很簡單,還記得上面講到的Parent Package吧?給Action加個注解,指定ParentPackage為"demo-default"。但這樣可不是我喜歡的,其實(shí)有更好的辦法,我們在struts.xml中加個constant就好了:
xml 代碼
- <constant name="struts.configuration.classpath.defaultParentPackage" value="demo-default" />
現(xiàn)在,大功告成!運(yùn)行RunJetty來測試下吧!你可以訪問/app/person/listPeople,可以訪問/app/group/listGroup,而所有的配置僅僅是web.xml和struts.xml中的幾行,我們的Java代碼中也沒有加注解。如果再加上幾百個Action呢?配置仍然就這幾行。
可是,某些Action確實(shí)需要配置怎么辦?對這些Action,你可以加注解,也可以針對這些Action來寫些XML配置。一個項目中,大部分Action的配置是可以遵從一定規(guī)則的,可以使用規(guī)則來簡化配置,只有少部分需要配置,這就是COC。
posted @
2008-10-04 14:08 Loy Fu 閱讀(1036) |
評論 (0) |
編輯 收藏