Struts 1.2
第一天:
MVC : M : 业务逻辑,业务数据 ( 可以重复利用 ) java Bean ( VO BO) EJB 其实struts1没有实现业务层,也无法实现
V : 显示逻辑 ,同一份数据 ,对应多种显示方法. JSP代码实现。
C:流程控制器 , Servlet代码实现。javabean Servlet javabean 其实他有两个部分组成:
1,系统核心控制器 由Struts 1 框架提供,就是 ActionServlet
2,业务逻辑控制器 由Struts 1框架提供就是用户自己写的Action 实例
在struts-config.xml配置文件中的一些属性: >
Struts : 基于mvc的软件框架 . Struts :
1使用struts需要完成的准备工作 :
1) 前置控制器 (ActionServlet) .
2) 定义了配置文件的格式 . /WEB-INF/struts-config.xml
3) 提供了一个父类, Action , 要求所有的javabean 都来继承这个父类 , 覆盖其中的方法 . 使用struts1需要完成的准备工作 : version 2.0 version 1.2.x 下面是1.2的版本
1) 获取struts的jar包 --> 拷贝到WEB-INF/lib
2) 对struts提供的前端控制器( ActionServlet ) 在 自己的web.xml中 进行配置
3) 确保struts用到的配置文件被放置到指定的位置 . struts1.2.7/webapps/struts-blank.war 解
压之后,从中拷贝struts-config.xml到我们 自己的应用里 .
4) 将struts提供的jar包配置到classpath中. struts.jar : 编译时依赖
2常用的业务流程
0) 写jsp , 这个jSP中有用户需要的连接或表单,
1) javabean , 通过它里面的方法,完成业务逻辑 .
2) 写Action , 调用javabean ,并根据javabean的结果,返回不同的页面 .
3) 在配置文件中对Action进行配置 .
4) 写jsp login.do http://localhost:8989/strutsapp/ok.jsp Resource file
1) 编写资源文件. a, properties
2) 在struts-config.xml中对资源文件进行配置 . 通知struts, 要使用的资源文件的名称 .
3) 在jsp中使用资源文件的内容 . 编程时使用key 显示时看到的是value
errors.header //errors会在所有错误的开头自动加上该key所代表的值(value), errors.footer //errors会在所有错误的结尾自动加上该key所代表的值(value), ActionForm : 用来保存客户端提交的数据 .
name password ----> Object |->name |->password
1) 写一个类( ActionForm ) , 用于保存客户端提交的参数.
2) 编辑配置文件, 告知struts,什么样的请求 使用哪个ActionForm 对象 .
3) 在Action的execute方法中, 从ActionForm对象中获取数据 .通过ActionForm做验证 .
1) 在配置文件中说明,哪些请求是需要做验证的 .
2) 在ActionForm里编写验证代码 . @Override validate() ActionMessage ---> Resource
3) 在错误页面上显示错误信息 .
0) 编写biz对象的方法,用于处理用户请求 . |-> 测试功能
1) 编写用户发送请、求的页面
2) 根据表单的参数 编写 ActionForm
3) 编写Action对象.execute方法 |-> 调用biz对象的方法. |->
根据biz方法的返回结果,返回不同的ActionForward
4) 对ActionForm , Action 进行配置 .
5) 编写与 ActionForward 对应的jsp页面 .
第二天:具体实现
<form-beans>
<form-bean name="" type=""/>
</form-beans>
<action-mappings>
<action path="" type="" name="" validate="true" input="">
<forward name="" path="" redirect="true"/>
</action>
</action-mappings>
<html:errors />
3,常用配置文件 最原始的Action接口,验证登陆的实例
(1) web.xml文件 :
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<!—在web.Xml配置前端控制器 -->
<servlet>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>2</param-value>
</init-param>
<servlet-name>actionServlet</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>
<!-- 对任意请求,都采用Struts提供的那个ActionServlet进行转发 -->
<servlet-mapping>
<servlet-name>actionServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
(2) struts-config.xml文件 :
ActionServlet<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">
<struts-config>
<form-beans>
<!-- 将表单提交的数据封装为一个对象 name属性对应Action中的name 自己手动写的actionform-->
<form-bean name="loginForm" type="com.kettas.struts.LoginForm"/>
<!—动态actionForm
<form-bean name="regForm" type="org.apache.struts.action.DynaActionForm">
<form-property name="userName" type="String"/>
<form-property name="age" type="java.lang.Integer"/>
</form-bean>
</form-beans>
<!-- 指定映射 指定请求路径对应指定Action
name属性指定与此Action对应的表单对象
validate指定是否采用表单验证 input指定若是表单验证出错 要去的页面 -->
<action-mappings>
<action path="/login" type="com.kettas.struts.LoginAction" name="loginForm"
validate="true" input="/login.jsp">
<forward name="ok" path="/ok.jsp" redirect="true"/>
<forward name="error" path="/error.jsp"/>
</action>
</action-mappings>
<!-- 指定资源文件 注意 : 以WEB-INF/classes为根目录 -->
<message-resources parameter="res.AppResources"/>
</struts-config>
(3) 表单对象 自己手动写actionForm
package com.kettas.struts ;
import org.apache.struts.action.* ;
import javax.servlet.http.* ;
// 要继承ActionForm类
public class LoginForm extends ActionForm{
// 成员变量的名字要和客户端参数一一对应.
private String userName ;
private String password ;
// 添加get、set方法
。。。。。。。。
/***********************************************
* 用于对表单的数据进行验证, 该方法在调用execute之前
* 被前端控制器调用,根据他的返回结果,来判断验证是否
* 成功
************************************************/
@Override
public ActionErrors validate( ActionMapping mapping ,
HttpServletRequest request )
{// errors用于存放错误的集合
ActionErrors errors = new ActionErrors();
if( userName == null || userName.trim().length() == 0 ){
// ActionMessage对象用来装载错误信息 初始化参数为资源文件中的键
ActionMessage m = new ActionMessage( "errors.username.required" );
errors.add( "error" , m );
}
if( password == null || password.trim().length()<3 ){
ActionMessage m = new ActionMessage( "errors.password.required" ) ;
errors.add( "error" , m ) ;
}
// 若返回的对象size为0 则说明验证通过 否则进入Action中input属性指定的页面中
return errors ;
}
}
// 在input指定的页面中要显示ActionErrors中的错误信息 则要用到标签 : <html:errors/>
errors.header : 错误信息的头
errors.footer : 错误信息的主体
引入标签库 : <%@taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
// <bean:message key="login.password"/> : 用于显示资源文件中指定键值对应的内容
由于规范的jsp页面中除了标签是不能含有静态文本内容的,故这个标签会被大量使用
引入标签库 : <%@taglib uri="http://struts.apache.org/tags-bean" prefix="bean"%>
(4) Action : 的实现
package com.kettas.struts ;
import org.apache.struts.action.* ;
import javax.servlet.http.* ;
import com.kettas.biz.*;
public class LoginAction extends Action{
@Override
public ActionForward execute( ActionMapping mapping , ActionForm form ,
HttpServletRequest request , HttpServletResponse response )
{ // 传统的获取表单数据方式
// String name = request.getParameter("userName" ) ;
// String pwd = request.getParameter("password" ) ;
// 得到表单对象 从中获取表单数据
LoginForm lf = (LoginForm)form ;
// 调用biz对象,返回下一个页面 .
try{
UserService biz = new UserService();
biz.login( lf.getUserName() , lf.getPassword() ) ;
ActionForward af = mapping.findForward("ok");
return af ;
}catch( Exception e ){
request.setAttribute( "errorMessage" , e.getMessage() ) ;
return mapping.findForward( "error" );
}
}
}
(5) Biz的实现 :
package com.kettas.biz ;
public class UserService{
public void login( String name , String pwd ){
if( ! name.equals( "liucy" ) ){
throw new RuntimeException( "user " + name + " not found" ) ;
}
if( ! pwd.equals( "12345" ) ){
throw new RuntimeException( "Invalid password" ) ;
}
}
}
4,资源文件 .国际化
1, 默认资源文件 : 当没有专门为每个用户准备资源文件
时 ,使用默认资源文件 .
<message-resources parameter="res.AppResources"/>
2,其他资源文件在命名上有一个规定 .
默认资源文件名_国家缩写 .
AppResources_zh
AppResources_ja
内容上是键值对 login.username=USER NAME: 前面是名称后面是显示的值
在jsp上的使用:<bean:define id="add"> <bean:message key=" login.username "/></bean:define>
3, 所有的资源文件要以utf-8的编码来编写 .如果不是的话要进去以下转换。
a,用中文编写一个临时的资源文件a.properties ( 中国字 GBK )
临时文件中的编码 临时文件的名字 新文件的文件名
b, native2ascii -encoding GBK a.properties AppResources_zh.properties
.
5,struts 中的异常处理 :==================
---> Action ---> Biz ---> Dao
Action中对异常进行捕获 .
try{
biz.fn();
return mapping.findforward( "ok" ) ;
}catch( Exception e){
return mapping.findforward( "error" );
}
系统级异常:
* 由于没个具体的技术操作导致的异常 ,
* 系统级异常通常是定义好的类型( SQLException , IOException )
* 一般发生在DAO层 .
* 在处里上要粒度粗一些 RuntimeException
应用级异常
* 由于用户违反了特定的业务逻辑导致的异常
* 应用级一般是用户自定义的异常 .
* 一般发生在 biz 层 .
* 粒度细一些 .
最好做一个异常的体系结构
实例 :
(1) struts-config.xml文件 :
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">
<struts-config>
<form-beans>
<form-bean name="loginForm" type="com.kettas.struts.LoginForm"/>
动态actionForm
<form-bean name="regForm" type="org.apache.struts.action.DynaActionForm">
<form-property name="userName" type="String"/>
<form-property name="age" type="java.lang.Integer"/>
</form-bean>
</form-beans>
<!-- 全局变量 可用在一些struts标签中 如<html:link /> -->
<global-forwards>
<forward name="login" path="/login.jsp"/>
</global-forwards>
<action-mappings>
<action path="/login" type="com.kettas.struts.LoginAction" name="loginForm"
validate="true" input="/login.jsp">
<!-- 将Action中抛出的异常捕获 并跳转到对应的错误页面
在错误页面中 还是用标签<html:errors />来显示错误
可见 这里key标签中指定的资源文件内容已经被封装到
ActionErrors对象中去了 -->
<exception type="com.kettas.struts.expt.SystemException"
path="/error.jsp" key="errors.system"/>
<exception type="com.kettas.struts.expt.UserNotFoundException"
path="/error.jsp" key="errors.user"/>
<exception type="com.kettas.struts.expt.PasswordException"
path="/error.jsp" key="errors.pwd"/>
<!-- redirect="true"表示在一个新的连接中打开指定页面
默认在同一个连接中打开指定页面 -->
<forward name="ok" path="/ok.jsp" redirect="true"/>
<forward name="error" path="/error.jsp"/>
</action>
</action-mappings>
//引入资源文件
<message-resources parameter="res.AppResources"/>
</struts-config>
(2) 定义根系统异常 作为其他一切系统异常的父类 这一步是有意义的
package com.kettas.struts.expt ;
// 继承至RuntimeException类而不是Exception 如此 无需try、catch捕获 可自动抛出异常
public class SystemException extends RuntimeException{
// 注意写这三个构造函数 后面都这么写
public SystemException( ){
super();
}
public SystemException( String msg ){
super( msg ) ;
}
public SystemException( Throwable t ){
super( t );
}}
// 定义根业务异常 作为其他一切业务异常的父类
package com.kettas.struts.expt ;
public class BizException extends RuntimeException{
..
}
// 密码错误异常 继承至根业务异常
package com.kettas.struts.expt ;
public class PasswordException extends BizException{
...
}
// 用户未发现异常 继承至根业务异常
package com.kettas.struts.expt ;
public class UserNotFoundException extends BizException{
...
}
(3) dao的实现 :
import ...
// 由于是采用tomcat的连接池获取连接 故这里引入这两个名字空间
import javax.sql.* ;
import javax.naming.* ;
public class UserDao{
public User queryByLoginName( String loginName ){
Connection conn = null ;
PreparedStatement pstm = null ;
ResultSet rs = null ;
String sql = "select id , loginname , password from liucy_users where loginname=?" ;
User u = null ;
try{
// 从连接池中获取连接的三个步骤
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup( "java:comp/env/oracle/ds" ) ;
conn = ds.getConnection();
pstm = conn.prepareStatement( sql ) ;
pstm.setString( 1 , loginName ) ;
rs = pstm.executeQuery();
if( rs.next() ){
u = new User();
u.setId( rs.getInt( 1 ) ) ;
u.setLoginName( rs.getString(2 ) ) ;
u.setPassword( rs.getString( 3 ) ) ;
}
return u ;
}catch( Exception e){
e.printStackTrace();
// 抛出前面定义的系统异常 抛给biz 再从biz抛出 抛给Action 然后被系统捕获
throw new SystemException( e );
}finally{
if( rs != null ) try{ rs.close(); }catch( Exception e){}
if( pstm != null ) try{ pstm.close();}catch( Exception e ){}
// 由于是连接池中的连接 故不会真的关闭 只是被连接池回收
if( conn != null ) try{ conn.close();}catch( Exception e ){}
}}}
(4) biz的实现 :
public class UserService{
public void login( String name , String pwd ){
UserDao dao = new UserDao();
User u = dao.queryByLoginName(name);
if( u == null ){
// 抛出用户不存在业务异常
throw new UserNotFoundException( "user " + name + " not found" ) ;
}
if( ! u.getPassword().equals( pwd ) ){
// 抛出密码错误业务异常
throw new PasswordException( "Invalid password" );
}}}
(5) Action的实现 :
public class LoginAction extends Action{
@Override
public ActionForward execute( ActionMapping mapping , ActionForm form ,
HttpServletRequest request , HttpServletResponse response ) { LoginForm lf = (LoginForm)form ;
/*
try{
*/
// 这里会自动抛出biz和dao中的异常 抛给struts处理
UserService biz = new UserService();
biz.login( lf.getUserName() , lf.getPassword() ) ;
ActionForward af = mapping.findForward("ok");
return af ;
/*
// 若自己处理异常 则比较麻烦,可以在struts配置文件配置
}catch( SystemException e ){
request.setAttribute( "errorMessage" , "System is busy" ) ;
return mapping.findForward( "error" );
}catch( UserNotFoundException e){
request.setAttribute( "errorMessage" , e.getMessage() ) ;
return mapping.findForward( "error" ) ;
}catch( PasswordException e ){
request.setAttribute( "errorMessage" , e.getMessage() ) ;
return mapping.findForward( "error" ) ;
}catch( Exception e ){
request.setAttribute( "errorMessage" , "you catch an error" );
return mapping.findForward( "error" ) ;
}
*/
}}
4 ActionMessages对象 :
public class MessageAction extends Action{
@Override
public ActionForward execute( ActionMapping mapping , ActionForm form ,
HttpServletRequest request , HttpServletResponse response )
{ActionMessages messages = new ActionMessages();
// 用资源文件内容初始化
ActionMessage m1 = new ActionMessage( "msg1" );
ActionMessage m2 = new ActionMessage( "msg2" ) ;
messages.add( "message" , m1 ) ;
messages.add( "message" , m2 ) ;
request.setAttribute( "msgs" , messages );
return mapping.findForward( "ok" );
}
}
// 在jsp中显示ActionMessages内容
<html>
<body>
This message jsp
<!-- name指定命名属性 -->
<html:messages id="m" name="msgs">
<h1>${m}</h1>
</html:messages>
</body>
</html>
<bean:message />
<html:errors />
html: 处理页面的显示问题
bean: 定义变量和javabean <c:set />
logic: <c:if > <c:forEach>
<forward name="ok" path="/path.jsp"/>
html:
<html:link /> <===> <a href="">
<html:link forward="xxxx" page="xxx">Test</html:link>
page : 指向一个明确的连接地址 .
forward : 全局的forward 的 逻辑名字 .
* 可以自动加应用名称
* 可以使用逻辑名字 .
* 在不支持cookie的情况下, 自动增加jsessionid
<html:link forward="ok"></html:link>
<html:form action="/login.do" method="">
<input type="text" name="age"/>
<html:text property="age"/>
<input type="password" name=""/>
<html:password />
<select name="">
<option>aaa</option>
</slelect>
<html:select>
<html:option></html:option>
</html:select>
<input type="hidden" name="" value=""/>
<html:hidden />
</html:form>
<html:messages id="" name="">
</html:messages>
name : 被迭代的消息结合在作用域中的名字 .
id : 当前整备迭代的消息对象 .
* 被该标签迭代的集合类型是 ActionMessages类型 .
集合中的每个元素都是 一个 ActionMessage , 他
能够封装资源文件中的数据 .
<html:errors />
定义一个变量:id表示变量名,value:表示变量值
<bean:define id="a" value="1234"/>
<bean:define id="">
XXXXXXXX
</bean:define>
定义命名属性:
<bean:define id="a" name="data"/>
Action ---> a.jsp
request.setAttribute( "a" , "hello")
${ a }
第三天:标签的使用======================================================================================
5 struts标签 :
<html:link forward="login"page="/webdir/login.jsp">
Test</html:link>
page : 指向一个明确的连接地址 .
forward : 全局的forward的逻辑名字, 在配置文件中指定的 :
<global-forwards>
<forward name="login" path="/login.jsp"/>
</global-forwards>
* 可以自动加应用名称
* 可以使用逻辑名字, 在配置文件中说明实际路径
* 在不支持cookie的情况下, 自动增加jsessionid
在html中表单标签用struts标签代替 :
<!-- action中无需写应用名 会自动添加上 -->
<html:form action="/login.do" method="">
<-- <input type="text" name="age"/> -->
<html:text property="age" value=""/>
<!-- <input type="password" name="pwd"/> -->
<html:password property="pwd"/>
<!--<select name="">
<option>aaa</option>
</slelect> -->
<html:select>
<html:option></html:option>
</html:select>
<!-- <input type="hidden" name="" value=""/> -->
<html:hidden />
</html:form>
html :
<html:link forward|page="/" >
<html:form action="" method="">
<html:text property="" value=""/>
<html:password property=""/>
<html:select property=""/>
<html:option/>
<html:radio property="" />
<html:checkbo property=""/>
</html:form>
<html:errors/>
<html:messages id="m" name="">
${m}
</html:messages>
bean :
<!-- 在当前页面范围内 定义一个变量 -->
<bean:define id="" value=""/>
<bean:define id="">
...
</bean:define>
<!-- 将某一个命名属性对应的值赋予变量 -->
<bean:define id="a" name="student"/>
<bean:define id="a" name="student" property="name"/>
相当于 : String a = student.getName();
<!-- 将客户端提交的指定表单数据赋予变量 -->
<bean:parameter id="a" name="age"/>
<!-- 将客户端提交的指定cookie的值赋予变量 -->
<bean:cookie id="c" name="JSESSIONID"/>
<!-- 显示资源文件内容 -->
<bean:message key=""/>
logic :
<logic:present parameter|cookie|name="age">
xxxxxxx ;
xxxxxxx ;
xxxxxxx ;
</logic:present>
<logic:notPresent >
Xxxxx
</logic:notPresent>
<logic:greaterThan parameter="age" value="23">
</logic:greaterThan>
<logic:greateThan cookie="age" value="23">
cxddddd
</logic:greateThan >
<logic:greateThan name="student"property="age"value="23">
</logic:greateThan>
<logic:equal>
<logic:notEqual>
<logic:greaterThan>
<logic:lessThan>
<logic:greaterEqual>
<logic:lessEqual>
<!-- 循环标签 -->
<logic:iterate id="" collection="">
</logic:iterate>
=================================================
request ----> ActionForm ---> Action
简化对ActionForm 的开发 .直接在配置文件配置,不用写单独的类
DynaActionForm ( 动态 ActionForm )
1) 在配置文件中配 .
<form-beans>
<form-bean name="" type=""/>
<form-bean name="regForm" type="org.apache.struts.action.DynaActionForm">
<form-property name="userName" type="String"/>
<form-property name="age" type="java.lang.Integer"/>
</form-bean>
</form-beans>
2) Action中使用.
execute( ActionForm form ){
DynaActionForm af = ( DynaActionForm )form ;
af.get( "age" ) ;
af.get( "userName" ) ;
}
================================================
login , register , query
7 关于MappingDispatchAction, DispatchAction, LookupDispatchAction
(1) MappingDispatchAction : 容许一个action中包含多个方法,分别处理与之对应的请求
实例 :
配置文件 :
<form-bean name="dynaLoginForm" type="org.apache.struts.action.DynaActionForm">
<form-property name="userName" type="java.lang.String"/>
<form-property name="password" type="java.lang.String"/>
</form-bean>
<form-bean name="dynaRegForm" type="org.apache.struts.action.DynaActionForm">
<form-property name="userName" type="java.lang.String"/>
<form-property name="password" type="java.lang.String"/>
<form-property name="email" type="java.lang.String" />
</form-bean>
...
...
<action parameter="login" path="/login" type="com.kettas.struts.
UserSelfServiceAction" name="dynaLoginForm">
<exception type="com.kettas.struts.expt.SystemException" path="/error.jsp"
key="errors.system"/>
<exception type="com.kettas.struts.expt.UserNotFoundException"
path="/error.jsp" key="errors.user"/>
<exception type="com.kettas.struts.expt.PasswordException" path="/error.jsp"
key="errors.pwd"/>
<forward name="ok" path="/ok.jsp" redirect="true"/>
</action>
<action parameter="register" path="/reg" type="com.kettas.struts.
UserSelfServiceAction" name="dynaRegForm">
<forward name="ok" path="/regok.jsp"/>
</action>
...
Action :
public class UserSelfServiceAction extends MappingDispatchAction{
// 用于处理用户登陆请求 .
public ActionForward login( ActionMapping mapping , ActionForm form ,
HttpServletRequest request , HttpServletResponse response )
{
DynaActionForm daf = (DynaActionForm)form ;
String userName = (String)daf.get( "userName" );
String password = (String)daf.get( "password" ) ;
UserService biz = new UserService();
biz.login( userName , password );
return mapping.findForward( "ok" ) ;
}
// 负责处理用户的注册请求
public ActionForward register( ActionMapping mapping , ActionForm form ,
HttpServletRequest request , HttpServletResponse response )
{
DynaActionForm daf = ( DynaActionForm ) form ;
System.out.println( daf.get( "userName" ) ) ;
System.out.println( daf.get( "password" ) ) ;
System.out.println( daf.get( "email" ) ) ;
return mapping.findForward( "ok" ) ;
} }
(2) DispatchAction :
1 将相关的操作合并在同一个Action中处理,这些相关的操作,必须使用同一个ActionForm
2 客户端提交的参数值决定使用Action中的哪个方法
3 不能覆盖execute方法,为每一个请求单独写一个方法
4 采用DispatchAction的方式简化了配置文件
实例 :
配置文件 :
<!-- parameter指定客户端请求中决定action方法的那个参数 -->
<action parameter="method" path="/all" type="com.kettas.struts.
DispatchActionSample" name="allForm">
<exception type="com.kettas.struts.expt.SystemException" path="/error.jsp"
key="errors.system"/>
<forward name="ok" path="/ok.jsp" redirect="true"/>
<forward name="regOk" path="/regok.jsp"/>
</action>
Action :
public class DispatchActionSample extends DispatchAction{
public ActionForward login( ActionMapping mapping , ActionForm form ,
HttpServletRequest request , HttpServletResponse response )
{
DynaActionForm daf = (DynaActionForm)form ;
String userName = (String)daf.get( "userName" ) ;
String password = (String)daf.get( "password" ) ;
UserService service = new UserService();
service.login( userName , password ) ;
return mapping.findForward( "ok" ) ;
}
public ActionForward register( ActionMapping mapping , ActionForm form ,
HttpServletRequest request , HttpServletResponse response )
{
DynaActionForm daf = (DynaActionForm)form ;
System.out.println( daf.get( "userName" ) );
System.out.println( daf.get( "password" ) ) ;
System.out.println( daf.get( "email" ) ) ;
return mapping.findForward( "regOk" ) ;
}}
客户端 :
<a href="/webdir/all.do?method=login">登录</a>
<a href="/webdir/all.do?method=register">注册</a>
Method有不同的参数,对应处理的action方法
(3) LookupDispatchAction :
(1) 不能覆盖父类的execute方法,为每一个按钮单独写一个方法
(2) 覆盖父类getKeyMethodMap方法,在这个方法中指明按钮的值与方法名称的对应关系
(3) 按钮的值,不能直接写死在程序中,要来自于资源文件
(4) 在配置文件中对Action进行配置
<action parameter="指明按钮的名称" path="" type="" name="" ></action>
(5) 适合一个表单多种请求方式的时候
实例 :
配置文件 :
<action parameter="btn" path="/math" type="com.kettas.struts.MathAction"
name="allForm">
<forward name="ok" path="/submit.jsp"/>
</action>
Action :
public class MathAction extends LookupDispatchAction{
// 覆盖父类getKeyMethodMap方法,在这个方法中指明按钮的值与方法名称的对应关系
@Override
public Map getKeyMethodMap(){
// 按钮的值应来自于资源文件 在map中保存是资源文件中的key,values是对应的方法
Map m = new HashMap();
m.put( "btn.add" , "addOperate" );
m.put( "btn.subtract" , "subOperate" );
return m ;
}
// 加法运算
public ActionForward addOperate( ActionMapping mapping, ActionForm form ,
HttpServletRequest request , HttpServletResponse response )
{
DynaActionForm daf = (DynaActionForm)form ;
Integer a = (Integer)daf.get( "a" ) ;
Integer b = (Integer)daf.get( "b" ) ;
int ret = a.intValue() + b.intValue();
request.setAttribute( "ret" , ret ) ;
return mapping.findForward( "ok" ) ;
}
// 减法运算
public ActionForward subOperate( ActionMapping mapping, ActionForm form ,
HttpServletRequest request , HttpServletResponse response )
{
DynaActionForm daf = (DynaActionForm)form ;
Integer a = (Integer)daf.get( "a" ) ;
Integer b = (Integer)daf.get( "b" ) ;
int ret = a.intValue() - b.intValue();
request.setAttribute( "ret" , ret ) ;
return mapping.findForward( "ok" ) ;
}
}
客户端 :
<%@page contentType="text/html"%>
<%@page isELIgnored="false"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@taglib uri="http://struts.apache.org/tags-bean" prefix="bean"%>
<html>
<body>
<!-- 为变量赋值 获得资源文件的值 -->
<bean:define id="add">
<bean:message key="btn.add"/>
</bean:define>
<bean:define id="sub">
<bean:message key="btn.subtract"/>
</bean:define>
<form action="/strutsapp/math.do" method="GET">
Number A :<input type="text" name="a"/><br/>
Number B :<input type="text" name="b"/><br/>
<!-- 按钮的name属性与action配置中的parameter属性是对应的 -->
<input type="submit" name="btn" value="${add}"/>
<input type="submit" name="btn" value="${sub}"/>
</form>
<!-- 显示计算结果 -->
<c:if test="${!empty ret}">
<h2>ret = ${ret}</h2>
</c:if>
</body>
</html>
================================== ====================================================
n m ( m-1 ) * n ---> Begin
(m-1)*n + n ---> end
select id
from
( select id , rownum rn from product )
rn> ? and rn < ?
======================================================
ResultSet
1) 改bug.
2) 增加上一页 , 下一页 功能 .
3) 总页数 通过 ServletContextListener
保存到ServletContext对象中 .
第五天:
Validation --> 表便验证 .
Overide
validate()
1) dynaActionForm
2)
3)
validation :
1,varliator.jar | jakarta-ora.jar .
|-> 在这些类中实现了通用的验证方法.
2, validator-rules.xml .
|-> 相当于类的使用说明. 写给struts看的.
not null --->class ---> function
3, validation.xml :
|-> 相当于程序员编写的需求说明书 .
loginForm
|--> userName
|--> not null .
Validation框架的使用方式 :
1) 程序员负责编写需求说明书 . 说明
哪些表单 , 哪些数据,需要做什么验证 .
2) struts 通过阅读validator-rules.xml,
调用相应方法,实现验证逻辑 .
===============================================
使用validation框架的准备工作 :
1) 保证validation.jar , jakarta-ora.jar
保存在应用的/WEB-INF/lib
2) 保证两个配置文件 validator-rules.xml
validation.xml 要保存到/WEB-INF 中 .
3) 将validation以插件的方式嵌入到struts中.
修改 struts-config.xml ,插件的配置标签
可以从validator-rules.xml的注释中拷贝.
4) 确保需要验证的请求 validate="true"
<action path="login" type="xxxAction"
name="xxxForm" validate="true"
input="xxx.jsp"/>
5) 如果要通过Validation作验证的话 .
ActionForm
- DynaValidatorActionForm 在validation.xml配置文件中的form标签中的属性为path
- DynaValidatorForm 在validation.xml配置文件中的form标签中的属性为name
DynaActionForm
- org.apache.struts.validator.DynaValidatorForm
- DynaValidatorActionForm
6) 将错误提示信息从validator-rules.xml中拷贝到自己的资源文件中 .
编辑需求说明书( validation.xml ) 提出自己的验证需求
formset
|-> form
|-> field
|-> form
tiles .
<script>
function fn(){
xxxxxxxxx ;
xxxxxxxxxx;
return false ;
}
</script>
<form action="" method="" οnsubmit="return xxxx();">
</form>
1) 将validation写的javascript代码嵌入到自己的网页中.
<html:javascript formName=""/>
2) 获取javascript验证函数的名字 .
allForm ---> valdiateAllForm
abc -------> validateAbc
login.do
regster.do
AllForm
MappingDisaptcherAction
<action path="/login" type="" name="all" validate="true" >
<action path="/reg" type="" name="all" validate="true">
9 struts中的模板
(1) 在struts-config.xml文件中指定使用模板 : 通过插件件的方式
<action-mappings> ... </action-mappings>
<plug-in className="org.apache.struts.tiles.TilesPlugin" >
<!-- 指定模板配置文件的路径 -->
<set-property property="definitions-config" value="/WEB-INF/tiles-defs.xml" />
<!-- 使模板识别生效 -->
<set-property property="moduleAware" value="true" />
</plug-in>
(2) tiles-defs.xml文件 :
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/tiles-config_1_1.dtd">
<tiles-definitions>
<!-- template.jsp是个模板页面 里面只有一个页面布局 -->
<definition name="base" path="/tiles/template.jsp">
<!-- 向模板页面的指定位置插入其他页面 -->
<put name="header" value="/tiles/header.jsp"/>
<put name="menu" value="/tiles/menu.jsp"/>
</definition>
<!-- 继承至上面的添加了部分内容的模板 再添加新的内容 -->
<definition name="register" extends="base">
<put name="body" value="/tiles/regBody.jsp"/>
</definition>
<!-- 继承至上面的添加了部分内容的模板 再添加新的内容 -->
<definition name="login" extends="base">
<put name="body" value="/tiles/loginBody.jsp"/>
</definition>
</tiles-definitions>
(3) template.jsp页面 :
<%@page contentType="text/html;charset=utf-8"%>
<%@taglib uri="http://struts.apache.org/tags-tiles" prefix="tiles"%>
<html>
<body>
<table width="100%" height="100%">
<tr height="10%" bgcolor="gray">
<td colspan="2" align="center">
<!-- 指定此地可以插入新的页面 -->
<tiles:insert attribute="header"/>
</td>
</tr>
<tr height="90%">
<td width="15%" bgcolor="blue">
<!-- 指定此地可以插入新的页面 -->
<tiles:insert attribute="menu"/>
</td>
<td width="85%" align="center">
<!-- 指定此地可以插入新的页面 -->
<tiles:insert attribute="body"/>
</td>
</tr>
</table>
</body>
</html>
(4) 使用的时候 页面格式如下 register.jsp :
<%@taglib uri="http://struts.apache.org/tags-tiles" prefix="tiles"%>
<!-- definition属性指定tiles-defs.xml文件中装配完成的页面名称 -->
<tiles:insert definition="register"/>
<!-- 若在tiles-defs.xml文件中没有声明 则要这么写 :
<tiles:insert page="/tiles/template.jsp">
<tiles:put name="header" value="/tiles/header.jsp"/>
<tiles:put name="menu" value="/tiles/menu.jsp"/>
<tiles:put name="body" value="/tiles/regBody.jsp"/>
</tiles:insert>
-->
一个客户在浏览器的地址栏输入了如下:
URL: http://www.tarena.com/webdev/account/deposit?accno=1212&amt=1000
调用 EG 的方法 F 可以获得初始参数interestRate的值。
在accountServlet中调用HttpServletRequest的getRequestURI返回H ,
调用getQueryString返回B ,调用getContextPath返回 A ,
调用getServletPath返回 C ,调用getPathInfo返回 D 。
A. /webdev
B. accno=1212&amt=1000
C. /account
D. /deposit
E. Servletconfig
F. getInitParameter
G. HttpServlet
H. /webdev/account/deposit
Struts 2
- Struts2的体系和struts1的体系差别很大,因为struts2使用WebWork的设计核心,而不是原来struts1的设计核心。Struts2大量使用拦截器来处理用户请求,从而允许用户的业务逻辑控制器与Servlet API分离。
- struts2框架的大致处理流程如下:
①浏览器发送请求,例如请求 /mypage.action[U1] /report/myreport.pdf等
②核心控制器FilterDispatcher根据请求决定调用合适的Action
③WebWork的拦截器链自动对请求应用通用功能,例如 workflow,validation或文件下载和上传
④回调Action的execute方法(其实可以是任意方法),该方法execute方法先获得用户的请求参数,然后执行某种数据操作,调用业务逻辑组组件来处理用户请求。
⑤Action的execute方法处理结果信息将被输出发哦浏览器中,可以是html页面,pdf还有jsp,Velocity,FreeMarker等技术模板。
3,在struts2 中的web.xml配置 加拦截器(拦截器是整个struts的核心技术)
<?xml version="1.0" encoding="GBK"?>
<web-app 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">
<!-- 定义Struts2的FilterDispathcer的Filter -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<!-- FilterDispatcher用来初始化struts2并且处理所有的WEB请求。 -->
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
- struts.xml的配置
<struts>
<!-- include节点是struts2中组件化的方式 可以将每个功能模块独立到一个xml配置文件中 然后用include节点引用 -->
<include file="struts-default.xml"></include>
<!-- package提供了将多个Action组织为一个模块的方式
package的名字必须是唯一的 package可以扩展 当一个package扩展自
另一个package时该package会在本身配置的基础上加入扩展的package
的配置 父package必须在子package前配置
name:package名称 extends:继承的父package名称
abstract:设置package的属性为抽象的 抽象的package不能定义action 值true:false
namespace:定义package命名空间 该命名空间影响到url的地址,例如此命名空间为/test那么访问是的地址为
http://localhost:8080/struts2/test/XX.action -->
<package name="com.kay.struts2" extends="struts-default" namespace="/test">
<interceptors>
<!-- 定义拦截器 name:拦截器名称 class:拦截器类路径 -->
<interceptor name="timer" class="com.kay.timer"></interceptor>
<interceptor name="logger" class="com.kay.logger"></interceptor>
<!-- 定义拦截器栈 -->
<interceptor-stack name="mystack[U2] ">
<interceptor-ref name="timer"></interceptor-ref>
<interceptor-ref name="logger"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 定义默认的拦截器 每个Action都会自动引用 如果Action中引用了其它的拦截器 默认的拦截器将无效 -->
<default-interceptor-ref name="mystack"></default-interceptor-ref>
<!-- 全局results配置 -->
<global-results><result name="input">/error.jsp</result> </global-results>
<!-- Action配置 一个Action可以被多次映射(只要action配置中的name不同)
name:action名称 class: 对应的类的路径 method: 调用Action中的方法名 -->
<action name="hello[U3] " class="com.kay.struts2.Action.LoginAction">
<!-- 引用拦截器 name:拦截器名称或拦截器栈名称 -->
<interceptor-ref name="timer"></interceptor-ref>
<!-- 节点配置 name : result名称 和Action中返回的值相同
type : result类型 不写则选用superpackage的type struts-default.xml中的默认为dispatcher
-->
<result name="success" type="dispatcher">/talk.jsp</result>
<result name="error" type="dispatcher">/error.jsp</result>
<result name="input" type="dispatcher">/login.jsp</result>
<!-- 配置Action返回cancel时重定向到Welcome的Action-->
<result name="cancel" type="redirect-action">Welcome</result>
<!—异常处理 result表示出现异常时返回的name为success的结果处理—》
<exception-mapping exception=”java.lang.Exception” result=”success”/>
<!-- 参数设置 name:对应Action中的get/set方法 -->
<param name="url">http://www.sina.com</param>
</action>
</package>
<!—引用国际化文件的base名-->
<constant name=”struts2.custom.i18n.resources”value=”messageResource”
</struts>
4,struts2的action编写
例1 HelloWorld.jsp
<% @ page contentType = " text/html; charset=UTF-8 " %>
<% @ taglib prefix = " s " uri = " /struts-tags " %>
[U4] < html >
< head >
< title > Hello World! </ title >
</ head >
< body >
< h2 >< s:property value ="message[U5] " /></ h2 >
</ body >
</ html >
例1 classes/tutorial/HelloWorld.java
import com.opensymphony.xwork2.ActionSupport;
public class HelloWorld extends ActionSupport {
private String message[U6] ;
public String getMessage() {
return message;
}
public void tring setMessage(String message) {
this.message=message;
}
@Override
public String execute[U7] () {
message = " Hello World, Now is " + DateFormat.getInstance().format( new Date());
return success;
}
}
例1 classes/struts.xml中HelloWorld Action的配置
< package name ="ActionDemo" extends ="struts-default" >
< action name ="HelloWorld" class ="tutorial.HelloWorld" >
< result > /HelloWorld.jsp </ result >
</ action >
</ package >
- 拦截器的编写
编写权限控制器
public class AuthorityInterceptor extends AbstractIntercepto[U8] r {
private static final long serialVersionUID = 1358600090729208361L;
//拦截Action处理的拦截方法
public String intercept(ActionInvocation invocation) throws Exception {
ActionContext ctx=invocation.getInvocationContext(); // 取得请求相关的ActionContext实例
Map session=ctx.getSession();
String user=(String)session.get("user"); //取出名为user的session属性
//如果没有登陆,或者登陆所有的用户名不是aumy,都返回重新登陆
if(user!=null && user.equals("aumy")){
return invocation.invoke();[U9]
}
//没有登陆,将服务器提示设置成一个HttpServletRequest属性
ctx.put("tip","您还没有登录,请登陆系统");
return Action.LOGIN;
}
}
Struts2.xml的配置文件
<struts>
<include file="struts-default.xml"/>
<!--受权限控制的Action请求配置-->
<package name="authority" extends="struts-default">
<interceptors>
<!--定义一个名为authority的拦截器-->
<interceptor class="com.aumy.struts.example.intercepter.AuthorityInterceptor" name="authority"/>
<!--定义一个包含权限检查的拦截器栈-->
<interceptor-stack name="mydefault">
<interceptor-ref name="defaultStack"/> <!--配置内建默认拦截器-->
<interceptor-ref name="authority"/> <!--配置自定义的拦截器-->
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="mydefault" />[U10]
<!--定义全局Result-->
<global-results>
<result name="login">/login.jsp</result>
</global-results>
<action name="show" class="com.aumy.struts.example.LoginAction"
method="show">
<result name="success">/show.jsp</result>
</action>
<action name="add" class="com.aumy.struts.example.LoginAction" method="add">
<result name="success">/add.jsp</result>
</action>
</package>
</struts>
还要一种方法拦截器,可以对某个action的方法进行拦截 编码类似action拦截器
public class MyInterceptor3 extends MethodFilterInterceptor {
@Override
protected String doIntercept(ActionInvocation invocation) throws Exception {
System.out.println("use MethodFilterInterceptor");
String result = invocation.invoke();
return result;
}
}
只是在配置的时候和其他interceptor有些区别:
<interceptor name="myInterceptor3" class="com.langhua.interceptor.MyInterceptor3">
<param name="excludeMethods">execute,login</param> <!-- execute,login两个方法不需要拦截
<!—addmessage 方法需要拦截 可以指名多个方法,只需要用逗号隔开
<param name="includeMethods">addmessage</param>
</interceptor>
6,拦截结果的监听器,用来精确定义在execute方法执行之后,在处理物力资源转向之前的动作,这个监听器是通过手动注册到拦截器内部的
public class MyListener implements PreResultListener[U11] {
public void beforeResult(ActionInvocation invocation, String resultCode[U12] ) {
System.out.println(“放回的逻辑视图是:”+resultCode);
}
}
然后再在拦截器里面调用 invocation.addPreResultListener(new MyListener());
监听器是在这个拦截器完成别的拦截器之后调用的
5,struts2的标签库 相比struts1,struts2提供了大量的标签,且更加强大 ,且主要有,1 UI 用户界面标签(html页面显示) 2 非UI 主要是数据访问,逻辑控制的标签 3 Ajax支持的标签
6,Struts2 的(客户端和服务端)校验更为方便更容易国际化处理
7,国际化处理:
8,支持文件的上传和下载
Struts1和Struts2的区别和对比:
Action 类:
• Struts1要求Action类继承一个抽象基类。Struts1的一个普遍问题是使用抽象类编程而不是接口。
• Struts 2 Action类可以实现一个Action接口,也可实现其他接口,使可选和定制的服务成为可能。Struts2提供一个ActionSupport基类去实现常用的接口。Action接口不是必须的,任何有execute标识的POJO对象都可以用作Struts2的Action对象。
线程模式:
• Struts1 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1 Action能作的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步的。
• Struts2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。(实际上,servlet容器给每个请求产生许多可丢弃的对象,并且不会导致性能和垃圾回收问题)
Servlet 依赖:
• Struts1 Action 依赖于Servlet API ,因为当一个Action被调用时HttpServletRequest 和 HttpServletResponse 被传递给execute方法。
• Struts 2 Action不依赖于容器,允许Action脱离容器单独被测试。如果需要,Struts2 Action仍然可以访问初始的request和response。但是,其他的元素减少或者消除了直接访问HttpServetRequest 和 HttpServletResponse的必要性。
可测性:
• 测试Struts1 Action的一个主要问题是execute方法暴露了servlet API(这使得测试要依赖于容器)。一个第三方扩展--Struts TestCase--提供了一套Struts1的模拟对象(来进行测试)。
• Struts 2 Action可以通过初始化、设置属性、调用方法来测试,“依赖注入”支持也使测试更容易。
捕获输入:
• Struts1 使用ActionForm对象捕获输入。所有的ActionForm必须继承一个基类。因为其他JavaBean不能用作ActionForm,开发者经 常创建多余的类捕获输入。动态Bean(DynaBeans)可以作为创建传统ActionForm的选择,但是,开发者可能是在重新描述(创建)已经存 在的JavaBean(仍然会导致有冗余的javabean)。
• Struts 2直接使用Action属性作为输入属性,消除了对第二个输入对象的需求。输入属性可能是有自己(子)属性的rich对象类型。Action属性能够通过 web页面上的taglibs访问。Struts2也支持ActionForm模式。rich对象类型,包括业务对象,能够用作输入/输出对象。这种 ModelDriven 特性简化了taglib对POJO输入对象的引用。
表达式语言:
• Struts1 整合了JSTL,因此使用JSTL EL。这种EL有基本对象图遍历,但是对集合和索引属性的支持很弱。
• Struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言--"Object Graph Notation Language" (OGNL).
绑定值到页面(view):
• Struts 1使用标准JSP机制把对象绑定到页面中来访问。
• Struts 2 使用 "ValueStack"技术,使taglib能够访问值而不需要把你的页面(view)和对象绑定起来。ValueStack策略允许通过一系列名称相同但类型不同的属性重用页面(view)。
类型转换:
• Struts 1 ActionForm 属性通常都是String类型。Struts1使用Commons-Beanutils进行类型转换。每个类一个转换器,对每一个实例来说是不可配置的。
• Struts2 使用OGNL进行类型转换。提供基本和常用对象的转换器。
校验:
• Struts 1支持在ActionForm的validate方法中手动校验,或者通过Commons Validator的扩展来校验。同一个类可以有不同的校验内容,但不能校验子对象。
• Struts2支持通过validate方法和XWork校验框架来进行校验。XWork校验框架使用为属性类类型定义的校验和内容校验,来支持chain校验子属性
Action执行的控制:
• Struts1支持每一个模块有单独的Request Processors(生命周期),但是模块中的所有Action必须共享相同的生命周期。
• Struts2支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不同的生命周期。堆栈能够根据需要和不同的Action一起使用
Struts1是*.do来处理
多个拦截器组合成一个拦截器栈,同时拥有几个拦截器的功能
Struts2的name就是处理url的前半部分,/hello.action,而struts1的name是该action关联ActionForm,path才是处理的url
Struts2只用引入一个标签就可以
在struts2中通过标签直接访问访问action中的属性值。当要访问集合,数组等时就要用表达式语言来访问这些对象,OGNL是一种数据访问语言
没有struts1中的actionForm,struts2只用设置属性的get和set方法就可以得到值
方法名可以任意,只是execute是默认的
可以继承Intercept接口还要实现 init()和destroy()方法,但是最好使用抽象方法AbstractInterceptor
该方法就像action的execute()方法一样,放回一个逻辑视图的字符串。
定义之后整个包都会有权限过滤
必须实现PreResultListener接口
就是execute的返回值