通過(guò)繼承ActionSupport類(lèi)來(lái)完成Action開(kāi)發(fā),ActionSupport類(lèi)不僅對(duì)Action接口進(jìn)行簡(jiǎn)單實(shí)現(xiàn), 同時(shí)增加了驗(yàn)證、本地化等支持 。真實(shí)開(kāi)發(fā)中自定義Action都需要繼承該類(lèi)。對(duì)用戶(hù)登錄添加表單驗(yàn)證功能
ActionSupport類(lèi)的作用:
struts2不要求我們自己設(shè)計(jì)的action類(lèi)繼承任何的struts基類(lèi)或struts接口,但是我們?yōu)榱朔奖銓?shí)現(xiàn)我們自己的action,大多數(shù)情況下都會(huì)繼承com.opensymphony.xwork2.ActionSupport類(lèi),并重寫(xiě)此類(lèi)里的public String execute() throws Exception方法。因?yàn)榇祟?lèi)中實(shí)現(xiàn)了很多的實(shí)用借口,提供了很多默認(rèn)方法,這些默認(rèn)方法包括國(guó)際化信息的方法、默認(rèn)的處理用戶(hù)請(qǐng)求的方法等,這樣可以大大的簡(jiǎn)化Acion的開(kāi)發(fā)。 Struts2中通常直接使用Action來(lái)封裝HTTP請(qǐng)求參數(shù),因此,Action類(lèi)里還應(yīng)該包含與請(qǐng)求參數(shù)對(duì)應(yīng)的屬性,并且為屬性提供對(duì)應(yīng)的getter和setter方法。
那么Action 接口和 ActionSupport類(lèi)的區(qū)別是什么呢?
Action接口有:
1
2
3
4
5
|
public static final String SUCCESS = "success" ; public static final String NONE = "none" ; public static final String ERROR = "error" ; public static final String LOGIN = "login" ; public String execute() throws Exception; |
可以看到有五個(gè)靜態(tài)常量和返回類(lèi)型為String 的execute()
而Actionsupport這個(gè)工具類(lèi)在實(shí)現(xiàn)了Action接口的基礎(chǔ)上還定義了一個(gè)validate()方法,重寫(xiě)該方法,它會(huì)在execute()方法之前執(zhí)行,如校驗(yàn)失敗,會(huì)轉(zhuǎn)入input處,必須在配置該Action時(shí)配置input屬性。
另外,Actionsupport還提供了一個(gè)getText(String key)方法還實(shí)現(xiàn)國(guó)際化,該方法從資源文件上獲取國(guó)際化信息.
這樣在自定義標(biāo)簽時(shí)可以定義一個(gè)變量為new actionsupport對(duì)象實(shí)現(xiàn)國(guó)際化。
Actionsupport類(lèi)有(源碼):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable { protected static Logger LOG = LoggerFactory.getLogger(ActionSupport. class ); private final ValidationAwareSupport validationAware = new ValidationAwareSupport(); private transient TextProvider textProvider; private Container container; public void setActionErrors(Collection<String> errorMessages) { validationAware.setActionErrors(errorMessages); } public Collection<String> getActionErrors() { return validationAware.getActionErrors(); } public void setActionMessages(Collection<String> messages) { validationAware.setActionMessages(messages); } public Collection<String> getActionMessages() { return validationAware.getActionMessages(); } @Deprecated public Collection<String> getErrorMessages() { return getActionErrors(); } @Deprecated public Map<String, List<String>> getErrors() { return getFieldErrors(); } public void setFieldErrors(Map<String, List<String>> errorMap) { validationAware.setFieldErrors(errorMap); } public Map<String, List<String>> getFieldErrors() { return validationAware.getFieldErrors(); } public Locale getLocale() { ActionContext ctx = ActionContext.getContext(); if (ctx != null ) { return ctx.getLocale(); } else { if (LOG.isDebugEnabled()) { LOG.debug( "Action context not initialized" ); } return null ; } } public boolean hasKey(String key) { return getTextProvider().hasKey(key); } public String getText(String aTextName) { return getTextProvider().getText(aTextName); } public String getText(String aTextName, String defaultValue) { return getTextProvider().getText(aTextName, defaultValue); } public String getText(String aTextName, String defaultValue, String obj) { return getTextProvider().getText(aTextName, defaultValue, obj); } public String getText(String aTextName, List<?> args) { return getTextProvider().getText(aTextName, args); } public String getText(String key, String[] args) { return getTextProvider().getText(key, args); } public String getText(String aTextName, String defaultValue, List<?> args) { return getTextProvider().getText(aTextName, defaultValue, args); } public String getText(String key, String defaultValue, String[] args) { return getTextProvider().getText(key, defaultValue, args); } public String getText(String key, String defaultValue, List<?> args, ValueStack stack) { return getTextProvider().getText(key, defaultValue, args, stack); } public String getText(String key, String defaultValue, String[] args, ValueStack stack) { return getTextProvider().getText(key, defaultValue, args, stack); } public String getFormatted(String key, String expr) { Map<String, Object> conversionErrors = ActionContext.getContext().getConversionErrors(); if (conversionErrors.containsKey(expr)) { String[] vals = (String[]) conversionErrors.get(expr); return vals[ 0 ]; } else { final ValueStack valueStack = ActionContext.getContext().getValueStack(); final Object val = valueStack.findValue(expr); return getText(key, Arrays.asList(val)); } } public ResourceBundle getTexts() { return getTextProvider().getTexts(); } public ResourceBundle getTexts(String aBundleName) { return getTextProvider().getTexts(aBundleName); } public void addActionError(String anErrorMessage) { validationAware.addActionError(anErrorMessage); } public void addActionMessage(String aMessage) { validationAware.addActionMessage(aMessage); } public void addFieldError(String fieldName, String errorMessage) { validationAware.addFieldError(fieldName, errorMessage); } public String input() throws Exception { return INPUT; } public String doDefault() throws Exception { return SUCCESS; } public String execute() throws Exception { return SUCCESS; } public boolean hasActionErrors() { return validationAware.hasActionErrors(); } public boolean hasActionMessages() { return validationAware.hasActionMessages(); } public boolean hasErrors() { return validationAware.hasErrors(); } public boolean hasFieldErrors() { return validationAware.hasFieldErrors(); } public void clearFieldErrors() { validationAware.clearFieldErrors(); } public void clearActionErrors() { validationAware.clearActionErrors(); } public void clearMessages() { validationAware.clearMessages(); } public void clearErrors() { validationAware.clearErrors(); } public void clearErrorsAndMessages() { validationAware.clearErrorsAndMessages(); } public void validate() { } @Override public Object clone() throws CloneNotSupportedException { return super .clone(); } public void pause(String result) { } private TextProvider getTextProvider() { if (textProvider == null ) { TextProviderFactory tpf = new TextProviderFactory(); if (container != null ) { container.inject(tpf); } textProvider = tpf.createInstance(getClass(), this ); } return textProvider; } @Inject public void setContainer(Container container) { this .container = container; } |
可以看到里面有很多的方法,但我們很明顯看到有一個(gè)我們很了解的,validate(),數(shù)據(jù)校驗(yàn)的方法。通過(guò)這個(gè)方法,我們可以登錄時(shí),用戶(hù)名和密碼為空的提示,或其他··
現(xiàn)在舉一個(gè)簡(jiǎn)單的例子:當(dāng)用戶(hù)名和密碼為空,給客戶(hù)一個(gè)友好提示。
下面通過(guò)兩種方式來(lái)闡述Struts 2的數(shù)據(jù)校驗(yàn)功能。
1. 編碼方式校驗(yàn)
1) Action一定要繼承自ActionSupport
2) 針對(duì)某個(gè)要進(jìn)行校驗(yàn)的請(qǐng)求處理方法編寫(xiě)一個(gè) public void validateXxx()方法,在方法內(nèi)部進(jìn)行表單數(shù)據(jù)校驗(yàn).
3) 也可針對(duì)所有的請(qǐng)求處理方法編寫(xiě)public void validate()方法。
4) 在校驗(yàn)方法中,可以通過(guò)addFieldError()方法來(lái)添加字段校驗(yàn)錯(cuò)誤消息。
5) 當(dāng)校驗(yàn)失敗時(shí),Struts框架會(huì)自動(dòng)跳轉(zhuǎn)到name為input的Result頁(yè)面。在校驗(yàn)失敗頁(yè)面中,可以使用<s:fielderror/>來(lái)顯示錯(cuò)誤消息
6) 簡(jiǎn)單,靈活。但重用性不高
重寫(xiě)validate方法
1.我們編寫(xiě)的Action一般繼承與ActionSupport,而ActionSupport不僅實(shí)現(xiàn)了Action接口,還實(shí)現(xiàn)了Validatable接口,提供了數(shù)據(jù)校驗(yàn)功能。在Validatable接口中定義一個(gè)validate方法,重寫(xiě)該方法,如果校驗(yàn)表單輸入域出現(xiàn)錯(cuò)誤,則將錯(cuò)誤添加到ActionSupport類(lèi)的fieldError域中,然后通過(guò)OGNL表達(dá)式輸出。
下面是用戶(hù)登錄校驗(yàn)界面:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<body> <%--輸出校驗(yàn)信息--%> <%--想要單個(gè)提示 <s:fielderror fieldName= "uname" />--%> <%--<s:property value= "" /> --%><div style= "color:red" ><s:fielderror/></div> <s:form name= "form1" namespace= "/" method= "post" action= "LoginValidateAction" > <s:div>請(qǐng)輸入用戶(hù)名:<s:textfield name= "user.uname" ></s:textfield></s:div> <s:div>請(qǐng)輸入密碼:<s:password name= "user.upwd" ></s:password></s:div> <s:submit value= "登錄" ></s:submit> </s:form> <%--debug --%> <s:debug></s:debug> </body> |
用戶(hù)輸入數(shù)據(jù)后,提交到LoginValidateAction 中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
public class LoginValidateAction extends ActionSupport implements Action { public User user; public Map<String, Object> map; //驗(yàn)證的方法,會(huì)對(duì)所有的Action起作用 @Override public void validate() { if (user.getUname().length()== 0 ){ addFieldError( "uname" , "用戶(hù)名不能為空!" ); } if (user.getUpwd().length()== 0 ){ addFieldError( "upwd" , "密碼不能為空!" ); } } //處理業(yè)務(wù)的方法 public String execute() throws Exception { System.out.println(user.getUname()); if (user.getUname().equals( "admin" )&&user.getUpwd().equals( "admin" )){ //讓Struts2注入 map集合 map.put( "uname" , user.getUname()); //如果登錄成功,返回“ success” return SUCCESS; } else { //登錄失敗,返回 error return INPUT; //此處一定是 input } } /** * @return the user */ public User getUser() { return user; } /** * @param user the user to set */ public void setUser(User user) { this .user = user; } |
上面的LoginValidateAction類(lèi)重寫(xiě)了validate方法,該方法會(huì)在執(zhí)行excute方法之前執(zhí)行,如果執(zhí)行該方法之后,Action類(lèi)的filedError中包含了數(shù)據(jù)校驗(yàn)錯(cuò)誤,請(qǐng)求將被轉(zhuǎn)發(fā)到input邏輯視圖。
struts.xml配置如下:
1
2
3
4
5
6
7
8
9
|
<!-- 數(shù)據(jù)校驗(yàn) --> <action name= "LoginValidateAction" class = "cn.struts2.action.LoginValidateAction" > <!-- 結(jié)果為“success”時(shí),跳轉(zhuǎn)至success.jsp頁(yè)面 --> <result name= "success" >success.jsp</result> <!-- 結(jié)果為 "error" 時(shí),跳轉(zhuǎn)至fail.jsp頁(yè)面 或 還在登錄界面 login.jsp--> <result name= "input" >LoginValidateAction.jsp</result> <result name= "login" >fail.jsp</result> <result name= "error" >fail.jsp</result> </action> |
在客戶(hù)端的效果:
但是大家注意沒(méi)有呢,當(dāng)提示錯(cuò)誤的時(shí)候不太是我們想要的的效果顯示。
這個(gè)不是我們所想要的,那么我們?cè)趺锤哪??其?shí)這主要顯示的struts2主題樣式導(dǎo)致的,
再來(lái)看看:
它自動(dòng)給我們添加了樣式。struts2提供了三種主題,ajax, simple, xhtml,它默認(rèn)的是xhtml主題,當(dāng)然你可以寫(xiě)任意個(gè)你自己的主題,我們稱(chēng)之為自定義主題??梢酝ㄟ^(guò)設(shè)置解決以上問(wèn)題
有兩種方法可以解決:
1.簡(jiǎn)單的方法(也很實(shí)用,針對(duì)所有struts2標(biāo)簽),在Struts.xml中,加上下一行代碼就可以了。
1
|
<constant name= "struts.ui.theme" value= "simple" /> |
代表所有的頁(yè)面采用的都是 simple主題了,這時(shí)它輸出的頁(yè)面,不回添加任何多余的代碼,比如 table tr td 等,我們就可以像其他編輯頁(yè)面的方式編輯頁(yè)面的風(fēng)格。
現(xiàn)在再來(lái)看看,錯(cuò)誤的提示格式
我們可以通過(guò)設(shè)置這樣一個(gè)標(biāo)簽:
1
|
<s:property value= "errors.uname[0]" /> |
把這個(gè)標(biāo)簽注釋掉:
1
|
<div style= "color:red" ><s:fielderror/></div> |
但我們?cè)O(shè)置成 這樣時(shí),會(huì)出現(xiàn)這樣的效果。
這種效果就有點(diǎn)想我們平常輸入錯(cuò)誤時(shí)的那個(gè)提示了,還有其他屬性值,這里就不用一一列舉了。
使用Struts2的校驗(yàn)框架
XML配置方式校驗(yàn)。
在編碼方式之前被執(zhí)行。
1) 針對(duì)要校驗(yàn)的Action類(lèi),在同包下編寫(xiě)一個(gè)名為:Action類(lèi)名-validation.xml校驗(yàn)規(guī)則文件。
2) 在校驗(yàn)規(guī)則文件中添加校驗(yàn)規(guī)則:具體的校驗(yàn)器名,參數(shù)可參看Struts2的reference或Struts2的API。
a) Field校驗(yàn):針對(duì)Action類(lèi)中每個(gè)非自定義類(lèi)型的Field進(jìn)行校驗(yàn)的規(guī)則。
1
2
3
4
5
6
7
|
<field name= "要校驗(yàn)的Field名" > <field-validator type= "校驗(yàn)規(guī)則器名" short -circuit= "是否要短路徑校驗(yàn)(默認(rèn)是false)" > <param name= "校驗(yàn)器要使用的參數(shù)名" >值</param> <message>校驗(yàn)失敗時(shí)的提示消息</message> </field-validator> <!-- 還可添加其它的校驗(yàn)規(guī)則 --> </field> |
b) 非Field校驗(yàn):針對(duì)Action類(lèi)的某些Field使用OGNL表達(dá)進(jìn)行組合校驗(yàn)。
1
2
3
4
5
6
|
<validator type= "fieldexpression" > <param name= "fieldName" >pwd</param> <param name= "fieldName" >pwd2</param> <param name= "expression" ><![CDATA[pwd==pwd2]]></param><!-- OGNL表達(dá)式 --> <message>確認(rèn)密碼和密碼輸入不一致</message> </validator> |
c) visitor校驗(yàn):主要是用來(lái)校驗(yàn)Action類(lèi)中的自定義類(lèi)型Field。(針對(duì)使用模型驅(qū)動(dòng)方式時(shí))
i) 在Action類(lèi)的的校驗(yàn)規(guī)則文件中針對(duì)自定義類(lèi)型Field使用visitor校驗(yàn)規(guī)則。
1
2
3
4
5
6
7
8
9
10
11
|
<!-- 針對(duì)自定義Field使用visitor校驗(yàn) --> <field name= "user" > <field-validator type= "required" short -circuit= "true" > <message>用戶(hù)的信息必填</message><!-- 消息前綴 --> </field-validator> <field-validator type= "visitor" ><!-- 指定為visitor校驗(yàn)規(guī)則 --> <param name= "context" >userContext</param><!-- 指定本visitor校驗(yàn)的上下文名 --> <param name= "appendPrefix" > true </param><!-- 是否要添加校驗(yàn)失敗消息的前綴 --> <message>用戶(hù)的</message><!-- 消息前綴 --> </field-validator> </field> |
ii) 針對(duì)visitor的Field編寫(xiě)一個(gè)校驗(yàn)規(guī)則文件.文件名為: visitor字段類(lèi)型名[-visitor校驗(yàn)的上下文名]-validation.xml. 例如: 本例中的文件名為User-userContext-validation.xml
注意: 此文件要存放到visitor字段類(lèi)型所在的包下.
iii) 在visitor的Field校驗(yàn)規(guī)則文件中針對(duì)要校驗(yàn)的Field添加校驗(yàn)規(guī)則.
我們還可以不重寫(xiě)validate方法,而通過(guò)增加校驗(yàn)配置文件來(lái)進(jìn)行數(shù)據(jù)校驗(yàn)。這個(gè)校驗(yàn)配置文件通過(guò)使用Struts2已有的校驗(yàn)器來(lái)完成對(duì)表單域的校驗(yàn),下面以requiredstring校驗(yàn)器為例,這個(gè)校驗(yàn)器是一個(gè)必填校驗(yàn)器,指定某個(gè)表單域必須輸入。
下面是這個(gè)校驗(yàn)配置文件LoginValidateAction-validation.xml的寫(xiě)法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<?xml version= "1.0" encoding= "UTF-8" ?> <!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.2//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd" > <validators> <field name= "uname" > <field-validator type= "requiredstring" > <message>用戶(hù)名不能為空</message> </field-validator> </field> <field name= "upwd" > <field-validator type= "requiredstring" > <message>密碼不能為空</message> </field-validator> <field-validator type= "stringlength" > <param name= "maxLength" > 18 </param> <param name= "minLength" > 6 </param> <message>密碼長(zhǎng)度應(yīng)該在${minLength}--${maxLength}位之間</message> </field-validator> </field> </validators> |
注意:這個(gè)校驗(yàn)配置文件必須遵守下面兩個(gè)規(guī)則:
1、該文件命運(yùn)格式必須是Action類(lèi)名-validation.xml,例如本例中該文件名為:LoginValidateAction-validation.xml
2、該文件必須與Action類(lèi)的class文件位于同一路徑下,本例中文件位于
LoginValidateAction類(lèi)的代碼還是一樣:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
public class LoginValidateAction extends ActionSupport implements Action { public User user; public Map<String, Object> map; //驗(yàn)證的方法,會(huì)對(duì)所有的Action起作用 @Override public void validate() { if (user.getUname().length()== 0 ){ addFieldError( "uname" , "用戶(hù)名不能為空!" ); } if (user.getUpwd().length()== 0 ){ addFieldError( "upwd" , "密碼不能為空!" ); } } //處理業(yè)務(wù)的方法 public String execute() throws Exception { System.out.println(user.getUname()); if (user.getUname().equals( "admin" )&&user.getUpwd().equals( "admin" )){ //讓Struts2注入 map集合 map.put( "uname" , user.getUname()); //如果登錄成功,返回“ success” return SUCCESS; } else { //登錄失敗,返回 error return INPUT; //此處一定是 input } } /** * @return the user */ public User getUser() { return user; } /** * @param user the user to set */ public void setUser(User user) { this .user = user; } |
以上所述是小編給大家介紹的Struts 2 數(shù)據(jù)校驗(yàn)功能及校驗(yàn)問(wèn)題的解決方案,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)服務(wù)器之家網(wǎng)站的支持!
原文鏈接:http://www.cnblogs.com/whyhappy/p/5831937.html