Struts技术介绍
一. 基本概念
1. 框架(Framework):可重用的,半完成的应用程序,可以用来产生专门的定制程序。
2. 模型(Model):就是封装数据和所有基于对这些数据的操作,也就是事务逻辑。
3. 视图(View):就是封装的是对数据显示,即用户界面。
4. 控制器(Control):就是封装外界作用于模型的操作和对数据流向的控制等。
5. MVC模式:模型+视图+控制器的模式。
6. Servlet:是用Java编写的Server端程序。
7. Struts:作为一个开放原代码的应用框架,在JSP Web应用开发中应用得非常广泛。Struts 实际就是基于J2EE 的 web 形式 MVC 模式实现。它主要由两大部分组成,其一是上面所说的改善web 系统结构的 MVC 框架部分。 另一部分是 Struts 的标签库。
二. Struts 的优点
所谓Struts的优点就是我们为什么要用Struts框架来作实现web 系统。
它是建立在MVC这种公认的比较好的模式上的,Struts在M、V和C上都有涉及。另外它提供一个好的控制器, 丰富的 TagLib,熟练用之,将节省大量的开发时间。
三. Struts 的基本结构
要理解struts的基本结构就先要了解JSP WEB应用的两种基本结构模式,Model 1和Model 2。
Model 1
Model 1是一个以JSP为中心的模式,这种Model中的JSP页面不仅负责表现逻辑,而且控制逻辑,这种模式对于小的,简单的项目来说比较适合,因为开发者可以在一个页面上把握全局。但对于大型系统来说,修改一个页面时会影响其他很多页面,牵一发而动全身,是维护和修改变得异常困难。例外程序逻辑和页面设计放在一起也不利于分工合作。
Model 2
Model 2引入了一个控制器的概念,控制器一般有Servlet担当。客户端的请求不再直接送给一个处理业务逻辑的JSP页面,而是送给这个控制器,再由控制器根据具体的请求调用不同的事务逻辑,并将处理结果返回到合适的页面。这样完全将业务逻辑从jsp页面中剥离出来。独立出来的业务逻辑,jsp页面和控制器就构成的MVC模式,为开发大型系统提供了巨大的便利。
struts的结构如下:
见图
下面我们看一个简单的例子:
客户提交(login.jsp)
<html:form action="/loginInitAction" focus="username">
…
<html:submit>submit</html:submit>
…
</html>
客户输入数据通过ActionForm类转到LoginActionForm.java中
struct到struts-config.xml文件中寻找配置好的ActionMapping
<action-mappings>
<action path="/loginInitAction"
type="view.login.LoginInitAction"
name="loginForm"
scope="session"
input="login.jsp"
validate="false">
<forward name="success" path="/web/login/main.jsp"/>
</action>
</action-mappings>
1.ActionServlet 类:
描述:ActionServlet 是该 MVC中控制层的 Command 部分,它是这一框架的核心。
作用:ActionServlet为从客户端来的请求url映射到相应的actionmapping,创建或找到其实例;Actionservlet调用在actionmapping中声明的action类,创建并生成相应的actionform bean实例。然后把actionform bean传到action类;actionservlet给action类传递actionform bean,actionmapping,request和response对象;
action产生处理好的业务逻辑的结果;
actionservlet接受从action返回的actionforward,转发response到由actionforward指定的源(可以是一个jsp或另一个action或另一个servlet)
例如:
(1)客户端发送请求login.jsp
<html:form action="/loginInitAction" focus="username">
…
<TD>
<html:submit>submit</html:submit>
</TD>
…
</html:form>
public ActionForward doAction(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
hrows IOException,ServletException {
…
逻辑处理
…
//JSPへ遷移
return (mapping.findForward("success"));
}
2.ActionForm 类
描述:ActionForm 是一个抽象类。
作用:ActionForm通常和Web页面的Form元素绑定,用于数据的收集和校验。
3. Action 类
描述:Action 类用来处理业务逻辑的一个类。
4.ActionMapping 类
描述:输入事件通常是在 HTTP 请求表单中发生的,控制器将 HTTP 请求转换为 HttpServletRequest。控制器查看输入事件并将请求分派给某个 Action 类。struts-config.xml 确定调用哪个 Action 类。struts-config.xml 配置信息被转换为一组 ActionMapping,而后者又被放入 ActionMappings 容器中。
作用:将struts-config文件中的配置信息封装。
五. 输入数据的验证机制
在web开发过程中输入数据的验证都通过vbscript和javascript来验证,目前大多使用javascript来验证如:
<SCRIPT SRC="../../js/jsfset.js"></SCRIPT>
<SCRIPT LANGUAGE="JavaScript">
function OnSearch(){
chk_flg = 0;
//仕損発行期間
//英数字チェック
if (chk_flg == 0){chk_flg = fnumchk(txt_xxx, '<%=komoku[6][1]%>');}
if(chk_flg == 0){
document.kensaku.actionFlag.value = "this";
document.kensaku.submit();
}
}
</SCRIPT>
<html:form name="kensaku" type="xxxKensakuForm" action="/xxxItiran.do" >
…
<html:button property="cmbKensaku" value=" 検索 " οnclick="OnSearch()"/>
如果使用javascript()来对页面入力数据实施验证的话,所有的验证码必须自己构造,在Struts 1.1的版本中,提供了表单输入自动验证的功能,在包org.apache.struts.validator中提供了许多有用的类,例如ValidatorForm类。
它能够提供动态ActionForm和自动表单输入验证的功能。由于Validator自带了15个基本验证器,可以满足大部分需要,因此十分方便。
使用validate作表单输入验证的方式一般有三种:
1.客户端验证
在JSP中写入
<html:form action="/XXX" οnsubmit="return validateXXXX(this);">
这里的XXX 是与要进行验证的 forward name
validateXXXX (this);里面的XXXX是需要进行验证的ActionForm名
<html:javascript formName="mytestForm"/>
在validation.xml文件中写入验证代码就可以进行基本的验证了
这种方式安全性不高。
2.服务端动态验证DynaValidatorForm的使用:
不需要再写对应的ActionForm,只需在struts-config.xml里把自己的ActionForm进行配置
<form-bean name="testForm"
type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="mytext" type="java.lang.String"/>
<form-property name="mytextarea" type="java.lang.String"/>
<form-property name="mydatetext" type="java.lang.String"/>
</form-bean>
在form-property里设置相应的项目,比如说needtest什么的,执行的时候会动态生成ActionForm, 再在validation.xml里写入所希望的验证代码,就可以了
JSP文件里不需要写入任何东西,验证也是在服务器端进行,验证部分代码在JSP
中不可见。
3.服务端验证:
使自己的ActionForm继承ValidatorForm类,在里面编写自己的方法:
JSP页面的formName和struts-config.xml中的formName一致。
在validation.xml文件中写入验证代码就可以进行基本的验证了。
此类方法是在服务器端进行验证,验证部分代码客户端不可见。
第三种是比较普遍使用的方法
现在以第三种为例:
你必须首先在配置文件(struts-config.xml)中进行配置。
<form-beans>
<!--- ============xxxActionForm============= -->
<form-bean name="xxxActionForm" type=" XXXActionForm"/>
</form-beans>
同时要定义的插件:
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property value="/WEB-INF/conf/fl/validator-rules.xml,/WEB-INF/conf/fl/validation.xml" property="pathnames" />
<set-property property="definitions-debug" value="2" />
<set-property property="definitions-parser-details" value="2" />
<set-property property="definitions-parser-validate" value="true" />
</plug-in>
定义消息的资源文件位置:
例:
<message-resources parameter="shopch.sc.P_SMESSG"/>
其中的validator.xml和validator-rules.xml分别表示验证定义和验证规则的内容(可以合并在一起),validator-rules.xml里面自带15种验证器。比如针对上例中的XXXActionForm,我们有如下验证规则文件(validator-rules.xml):
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE form-validation PUBLIC
"-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.0//EN"
"http://jakarta.apache.org/commons/dtds/validator_1_0.dtd">
<form-validation>
<global>
<validator name="minlength"
classname="org.apache.struts.validator.FieldChecks"
method="validateMinLength"
methodParams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionErrors,
javax.servlet.http.HttpServletRequest"
depends=""
msg="ECMO0032">
<javascript><![CDATA[
function validateMinLength(form) {
var isValid = true;
var focusField = null;
var i = 0;
var fields = new Array();
oMinLength = new minlength();
for (x in oMinLength) {
var field = form[oMinLength[x][0]];
if (field.type == 'text' ||
field.type == 'textarea') {
var iMin = parseInt(oMinLength[x][2]("minlength"));
if ((trim(field.value).length > 0) && (field.value.length < iMin)) {
if (i == 0) {
focusField = field;
}
fields[i++] = oMinLength[x][1];
isValid = false;
}
}
}
if (fields.length > 0) {
focusField.focus();
alert(fields.join('/n'));
}
return isValid;
}]]>
</javascript>
</validator>
</global>
</form-validation>
以上是一个验证最小长度的规则。我们有如下验证规则的文件(validation.xml):
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE form-validation PUBLIC
"-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.0//EN"
"http://jakarta.apache.org/commons/dtds/validator_1_0.dtd">
<form-validation>
<formset>
<!-- ==========XXXActionForm 在庫移動状況一覧 Start========= -->
<form name="xxxActionForm">
<!-- 移動指示番号 -->
<field property="logicBean.searchDataBean.stk_form_no" depends="FLmask,minlength">
<msg name="minlength" key="IFFO0070"/>
<msg name="FLmask" key="IFFO0072"/>
<arg0 key="XXXActionForm.logicBean.searchDataBean.stk_form_no"/>
<arg1 key="${var:minlength}" resource="false"/>
<var>
<var-name>minlength</var-name>
<var-value>10</var-value>
</var>
<var>
<var-name>FLmask</var-name>
<var-value>^[0-9]*$</var-value>
</var>
</field>
</form>
</formset>
</form-validation>
从上述定义中,我们可以看到对于属性logicBean.searchDataBean.stk_form_no有两项验证:minlength, Flmask(解说省略)。minlength意思是该字段的最小长度是10。然后通过在配置文件中配置的资源文件message-resources在相应的文件中根据key找到对应的消息。注意在<form-bean>中定义的form是如何与validation.xml中的form关联起来的。最后,要启动自动验证功能,还需要将Action配置的validate属性设置为true。
<!-- ==========XXXSearchAction================ -->
<action path="/xxxSearchAction"
type="shopch.sc.view.iv.inventory.stockmovereferencejpt.xxx.XXXSearchAction"
name="xxxActionForm"
scope="session"
input="XXX"
validate="true">
<forward name="success" path="XXX"/>
</action>
以上就是通过validation.xml和validator-rules.xml文件的组合达到控制验证的方法。
六. 错误处理机制
1. 构造错误异常,这里就利用了错误模式去发现错误并纠正它。
例如:InvalidNameException.java
class InvalidNameException extends Exception{
public InvalidNameException(){
}
}
程序中:
public User validate(String userName,String password) throws InvalidNameException{
if(userName.equals("java")){
}else{
throw new InvalidNameException();
}
//return null;
}
InvalidNameException继承Exception类
以上这段代码,意思就是,如果用户名不为java的话,那么就抛出InvalidNameException()这个异常,于是我们就可以成功的捕捉这个异常,并发出提示或警告。这样构造一个强大的错误处理集合就可以对程序内部或外部进行错误处理。
2. key/values方式.
根据配置文件查找相应的错误信息,并显示给用户。
例如:ErrorMessage error=new ErrorMessage();
if(!username.equals(“java”)){
error.add(“ERROR.LOGIN.USERNAME.FAILED”);
}
创建一个ErrorMessage对错误进行处理,如果返回空的error对像的话,说明没有错误,如果返回一个非空的error对像,那么就跳转到error.jsp页面,并捕捉这个错误。将ERROR.LOGIN.USERNAME.FAILED作為key 到错误信息配置文件取出错误信息。
错误信息配置文件:
LOGIN = 用户登陆
ERROR.LOGIN.EMPTY_INPUT = 登陆失败:无效输入!
ERROR.LOGIN.EMPTY_INPUT.DESC = 可能输入了空值或其他非法字符。
ERROR.LOGIN.USERNAME.FAILED = 用户名错误
ERROR.LOGIN.USERNAME.DESC = 请后退重试,检查您的用户名是否输入正确!
以上两种方式结合于log4j一起使用,可以达到对错误处理的要求。
七. Struts的Tag库
Taglib是Struts的一大优势,Struts提供丰富的JSP 标记库: Html,Bean,Logic,Nested等,这有利于分开表现逻辑和程序逻辑。熟悉taglib可以大大减少开发中的工作量。
Struts提供了六种自定义Tag库:
1. Bean标记库(struts-bean.tld库):
包含访问bean和bean属性时所使用的tag,同时也包含一些消息显示时所使用的tag。
主要包括:cookie、 define、 header、 include、 message、 page、 parameter、 resource、 size、 struts、 Write标记。
使用该标记前首先要在jsp的页面导入相应的标记定义,例如<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>。
使用的方法如<bean:*** id=""/>
例如:
<bean:define id="ACTIONFORM" name="XXXActionForm"/>。
包含创建基于HTML用户界面的tag。
主要包括:base、 button、 cancel、 checkbox、 errors、 file、 form、 frame、 hidden、 html、 image、 img、 javascript、 link、 message、 multibox、 option、 options、 optionCollection、 password、 radio、 reset、 rewrite、 select、 submit、 text、 textarea、 xhtml等。
使用该标记库首先要在相应的页面中引入标记库定义文件,
<%@ taglib uri="/WEB-INF/ struts-html.tld" prefix="html" %>
例:
select:
<html:select name="ACTIONFORM" property="xxxSelect ">
<html:optionsCollection name="ACTIONFORM" property="list"/>
</html:select>
text:
<html:text name="ACTIONFORM" property="xxxText " size="14" maxlength="11"/>
<html:radio name="ACTIONFORM" property="xxxRadio" value="1" disabled="true"/>
3. Logic标记库(struts-logic.tld):
包含控制流程的tag。
主要包括: empty、 equal、 forward、 greaterEqual、 greatThan、 iterate、 lessEqual、 lessThan、 match、 messagePresent、 messageNoPresent、 notEmpty、 notEqual、 notMatch、 notPresent、 present、 redirect等。
使用该标记库首先要在相应的页面中引入标记库定义文件,如:<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
例:
<logic:empty name="ACTIONFORM" property="logicBean.details">
…
</logic:empty >
<logic:notEmpty name="ACTIONFORM" property="logicBean.details">
…
</logic:notEmpty >
通过判定bean中的一个list(details)为不为空来进行下一步操作。
<logic:equal name="ACTIONFORM" property="logicBean.firstDisabledValue"
value="disabled">
…
</logic:equal>
<logic:notEqual name="ACTIONFORM" property="logicBean.firstDisabledValue"
value="disabled">
…
</logic:notEqual>
用“disabled”和bean中的firstDisabledValue的值进行比较,通过判定相等不相等来进行不同的操作。
4. template标记库(struts-template.tld):
包含用来定义模板机制的tag。
使用该标记库首先要在相应的页面中引入标记库定义文件,如:<%@ taglib uri="/WEB-INF/struts-template.tld" prefix="template" %>
5. nested标记库(struts-nested.tld):
让前面4种基本标记库可以嵌套使用。
使用该标记库首先要在相应的页面中引入标记库定义文件,如:<%@ taglib uri="/WEB-INF/struts-nested.tld" prefix="nested" %>例:
iterate:用来做循环的。
<nested:iterate property="logicBean.details" >
<nested:write property="po_no"/>
</nested:iterate >
6. tiles标记库(struts-tiles.tld)
用来简化JSP开发的一个插件。除了替代Template的基本功能外,还增加了布局定义,虚拟页面定义和动态页面生成等功能。
使用该标记库首先要在相应的页面中引入标记库定义文件,如:<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>