Day1:
overview:
1.MVC概述
2.Struts框架 (技术概览)
3.Struts开发步骤
4.Struts新手上路
5.Struts详解
6.使用工具构建struts应用
**************************************************************
一 MVC概述 (教材Page 219)
1 起源
2 设计理念
图(Page 219)
Controller:
Model:
View:
3.分层设计对Model的影响
4.Web MVC的发展(Page 221 ~ 227)
Model1 ---> Model2 ---> Framework
1)Model1的特点(Page 222)
2)Model2的特点(Page 224)
3)Framework的引入(Page 226)
引入框架的作用
A. 使得功能组件松散耦合,甚至可配置
B. 提供公用的服务:
例如:i18n,安全,表单的重复提交,文件上传……
C. 简化开发模型——使得开发人员的精力集中在业务逻辑之上
框架的分类
A.设计的思路
白盒框架:使用时,需要了解其内部结构(extends);入侵性框架
黑盒框架:不需了解其代码细节,最多实现其接口;非入侵性框架
B.功能、作用
Web:Strusts1.x, WebWork, Strusts2.x(发展1.x和webwork), JSF(抗衡.net), Tapestry,
Shale, ZK, Echo, (根本全是Servlet规范) ……
Business:Spring, Seam
Persistence(持久层):Hibernate, Toplink, OpenOJB, ……
评价框架的优劣?
A.设计理念 先进?
B.编程模型 简单?
C.是否拥抱规范、标准?
D.社区是否庞大?第三方的支持程度?
程序设计思路
可维护性:预见需求(预见多年后的事)
可重用:
代码可重用(最低级别):粒度:方法(常用代码块),类,包,组件(类库)
设计的可重用:框架(半成品,如Hibernate);产品(开发软件);算法、设计模式
分析的可重用(最高级别,见不到代码):文档、规范、标准(ISO:CMM,CMMI)
可扩展性:
*****************************************************
二、Struts框架 (技术概览)
1.Struts简介
Apache
OpenSource
官方网站:http://jakarta.apache.org
MVC
Servlet, JSP, 资源文件, 定制标签库
Struts框架的位置
2.Struts快速上手
需求描述:
系统的登录
开发步骤
1) 创建项目、搭建环境
下载Struts开发包
把%STRUTS_HOME%/lib/*.jar拷贝到WEB-INF/lib
把%STRUTS_HOME%/contrib/struts-el/lib/*.jar拷贝到WEB-INF/lib
把%STRUTS_HOME%/lib/*.tld拷贝到WEB-INF(新版本无需这么做)
将%STRUTS_HOME%/contrib/struts-el/lib/*.tld 拷贝到WEB-INF(新版本无需这么做)
2) 配置WEB-INF/web.xml文件
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<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>3</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>3</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
3) 在WEB-INF创建struts-config.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
"http://struts.apache.org/dtds/struts-config_1_3.dtd">
<struts-config>
<form-beans />
<global-exceptions />
<global-forwards />
<action-mappings />
<message-resources parameter="com.yourcompany.struts.ApplicationResources" />
</struts-config>
4) 提供login.jsp
引入struts标签库
<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean"%>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
<html:form action="/login">
<table>
<tr>
<td>用户名:</td>
<td><html:text property="username"></html:text></td>
</tr>
<tr>
<td>密 码:</td>
<td><html:password property="password"></html:password></td>
</tr>
<tr>
<td colspan=2 align=center>
<html:submit value="登录"></html:submit>
</td>
</tr>
</table>
</html:form>
5) 提供Form Bean
com.form.LoginForm
public class LoginForm extends ActionForm {
private String username;
private String password;
//getter, setter
}
配置文件更新:
<form-beans>
<form-bean name="loginForm" type="com.form.LoginForm"></form-bean>
</form-beans>
6) 提供action:LoginAction extends Action
public class LoginAction extends Action {
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
LoginForm loginForm = (LoginForm)form;
String username = loginForm.getUsername();
String password = loginForm.getPassword();
boolean isLogin = false;
if("maxwell".equals(username) && "123".equals(password)) {
isLogin = true;
}
if(isLogin) {
return mapping.findForward("success");
} else {
return mapping.findForward("error");
}
}
}
配置文件更新:
<action-mappings>
<action path="/login" type="com.action.LoginAction" name="loginForm">
<forward name="success" path="/success.jsp"></forward>
<forward name="error" path="/error.jsp"></forward>
</action>
</action-mappings>
3.Struts技术详解
1) struts的MVC模型 (Page229)
2) 主要组件详解
1)ActionServlet
继承HttpServlet类,需要在web.xml中配置
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
2)Action
开发人员必须继承这个Action类,供ActionServlet所驱动。
职责:调用业务逻辑方法
将控制权返回给ActionServlet并且提供相关的路由信息
public class LoginAction extends Action {
......
}
步骤:
(1) 继承Action类。
(2) 覆盖 execute(...)方法。
(3) 返回ActionForward对象 (提供决策信息给ActionServlet选择适当的视图响应用户) 。
(4) 在struts-config.xml中配置
<action-mappings>
<action input="/index.jsp" :ActionForm验证失败的跳转页面
name="aForm" :与Action对应的FormBean对象
path="/myAction" :请求URI(/myAction.do)
scope="session" :FormBean作用域范围
type="action.LoginAction" :自定义的Action类
validate="true" :FormBean是否调用validate(...)方法
>
<forward name="success" path="/success.jsp" /> :成功跳转的页面
</action>
......
</action-mappings>
注:scope的值可以是request和session,默认是session
3)ActionForm:封装HTTP请求中的数据
将用户提交的数据自动填充(在相应的action的execute方法被调用之前)到form的属性中
无需手工调用request.getParameter(…)
开发人员必须继承这个ActionForm类
public class LoginForm extends ActionForm {
......
}
3) 处理流程(程序中的关系)
****************************************************************************
三、使用IDE工具生成struts项目
Day2:
1 视图选择
2 国际化
3 Struts中的异常处理
4 动态表单
5.标签库
*************************************************************************
1 视图选择
局部转发与全局转发(优先级:局部转发的优先级比全局转发的优先级高)
1) 局部转发:只对某个Action可见
<action ...>
<forward name="success" path="/success.jsp" />
</action>
2) 全局转发:对所有的Action可见(共享)
<global-forwards>
<forward name="success" path="/globalsuccessful.jsp"></forward>
</global-forwards>
例子:
把登录例子中的成功跳转设置为全局转发。
2 I18N
I18N解决办法
创建多个资源文件,根据用户设置选择不同资源文件
ApplicationResources.properties
ApplicationResources_en.properties
ApplicationResources_zh.properties
资源文件:
用于映射页面中的静态信息、按钮标签、错误信息等,
通过一个属性文件(.properties) 把所有页面的静态信息集中在一起,便于修改。
例子:
编写资源文件的步骤:
1) 编辑资源文件
login_en.properties
login.title=Login Page
login.success=Congratuation! You successfully login our System!
login.username=User Name
login.password=Password
添加对中文的支持txt:
login.title=登录页面
login.success=恭喜你!你已经成功登录我们的系统了!
login.username=用户名
login.password=密码
login.submit=登录
转换本地编码为Unicode:
native2ascii login.txt login_zh.properties ----->生成login_zh.properties文件
login.title=/u767b/u5f55/u9875/u9762
login.success=/u606d/u559c/u4f60/uff01/u4f60/u5df2/u7ecf/u6210/u529f/u767b/u5f55/u6211/u4eec/u7684/u7cfb/u7edf/u4e86/uff01
login.username=/u7528/u6237/u540d
login.password=/u5bc6/u7801
login.submit=/u767b/u5f55
2)在struts-config.xml文件中配置资源文件<message-resources parameter="login" />
3)在JSP文件中使用<bean:message key="login.title"/>标签输出资源文件中的值
4)演示效果:
修改浏览器的设置
英文界面少写了"login.submit";则是找出中文的
3 Struts中的异常处理
java class: try/catch/finally/throws/throw/custom Exception class
jsp: page指令 + web.xml配置<error-page>
struts: try/catch/finally/throws/throw/custom Exception class
声明方式(*)------->struts-config.xml
定制异常处理器(*)
ActionErrors(或ActionMessages):异常的集合类
ActionMessage:具体异常类
关系图
方法一:
在actionform的validate方法中处理(很少使用,一般用验证框架实现用户输入合法性验证)
(1)重写action form的validate方法
@Override
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
ActionErrors errors = new ActionErrors();
if(username == null || username.equals("") || username.length() > 50) {
ActionMessage msg = new ActionMessage("error.username");
errors.add("errorusername", msg);
}
return errors;
}
login_en.properties的内容
error.username=Please input the correct user name!
login_zh
error.username=请输入正确的用户名信息!
error.username=/u8bf7/u8f93/u5165/u6b63/u786e/u7684/u7528/u6237/u540d/u53ca/u5bc6/u7801/uff01
(2)配置struts-config.xml文件
在action标记内添加一个input属性和validate属性
其中,
input属性的值-----表示发生错误后跳转到的页面
validate属性的值-----表示ActionServlet是否去执行ActionForm的validate(...)方法,并且这个属性默认值是true
<action-mappings>
<action name="loginForm"
path="/login"
type="com.action.LoginAction"
input="/login.jsp"
validate="true">
<forward name="fail" path="/fail.jsp"></forward>
</action>
</action-mappings>
(3)在login.jsp页面中加入<html:errors/>输出错误。
方法二:
在action的execute方法中处理(极少使用,知道这种方法就可以了)
(1)在action的execute方法中写错误处理的代码(和action form里valdiate方法的代码基本一致)
例如:
对于登录用户例子----把narci的都列为黑名单。
Action:
ActionMessages errors = new ActionMessages();
if("narci".equals(loginform.getUsername())) {
System.out.println("narci");
ActionMessage msg = new ActionMessage("error.user.blacklist");
errors.add("blacklist", msg);
this.saveErrors(request, errors);
return mapping.findForward("current");
}
(2)
//比在form的validate方法多出的一步
saveErrors(request, errors);
return mapping.findForward("current");
并且在struts-config.xml中配置
<forward name="current" path="/login.jsp"></forward>
login_en.properties加入内容
error.user.blacklist=this user in blacklist!
login_zh
error.user.blacklist=该用户已被列入黑名单!
正式的: error.user.blacklist=/u8be5/u7528/u6237/u5df2/u88ab/u5217/u5165/u9ed1/u540d/u5355/uff01
(3)
<html:errors/>---->用于页面中显示异常信息(通过资源文件映射)
方法三:
通过抛出异常处理错误(推荐使用:处理业务逻辑方面出现的错误)
(1)在action的方法中抛出异常
(2)在struts-config.xml声明该异常的处理方法(通过exception标记) 局部异常
<action-mappings>
<action name="loginForm"
path="/login"
type="com.action.LoginAction"
input="/login.jsp"
validate="true">
<exception key="errors.noauthorization"
type="com.exception.NoAuthorizationException"
path="/noauthorization.jsp">
</exception>
<forward name="fail" path="/fail.jsp"></forward>
<forward name="current" path="/login.jsp"></forward>
</action>
</action-mappings>
key="errors.noauthorization" 异常提示信息仍然通过资源文件作映射
path="/noauthorization.jsp" 出现异常时的处理页面
type="exception.NoAuthorizationException" Action处理业务过程中有可能出现的异常类型
资源文件加入:
errors.noauthorization=no authorization
errors.noauthorization=当前用户没有授权!
全局异常(对所有的action共享的,所以优先级应该比较低)
<global-exceptions>
<exception key="errors.global" type="java.lang.Exception" path="/error.jsp"></exception>
</global-exceptions>
资源文件加入:
errors.global=System Error! Please contact our administrators!
errors.global=系统错误!请联系管理员!
在LoginAction中加入
if("admin".equals(loginform.getUsername())
&& "".equals(loginform.getPassword())) {
throw new Exception();
}
4 动态表单
可以减少ActionForm的数量,完成对html form属性的动态映射,更便于应用维护。
实现动态表单功能:通过struts-config.xml配置
<form-beans >
<form-bean name="dynForm" type="org.apache.struts.action.DynaActionForm">
<form-property name="name" type="java.lang.String"></form-property>
<form-property name="age" type="java.lang.String"></form-property>
<form-property name="city" type="java.lang.String"></form-property>
<form-property name="gender" type="java.lang.String"></form-property>
</form-bean>
</form-beans>
<action-mappings >
<action name="dynForm"
path="/enroll"
scope="request"
type="com.tarena.struts.action.EnrollAction" >
<forward name="success" path="/success.jsp" />
<forward name="fail" path="/fail.jsp" />
</action>
</action-mappings>
<message-resources parameter="com.tarena.struts.ApplicationResources" />
Struts中表单使用技巧:
1)同类型或结构相近的html form通过一个ActionForm类型映射
2)在都能满足需要的前提下,尽量使用动态表单
3)ActionForm的作用域范围应尽量小,对于存放在session中的ActionForm,当不再使用时应销毁
4)ActionForm主要用于控制器与视图之间传数据,不应包含任何业务逻辑
Struts 标签
************************************************************************************************
一、Struts标签库概述
1.回顾已经学了JSTL标签库
标签库的作用:
1.使得(jsp)页面开发人员不再依赖Java(EL表达式的作用也是如此)
2.功能封装:可重用
2.Struts的五类标签库
Bean Tags :用来创建bean、访问bean
HTML Tags :用来创建 html 页面的动态元素,对html进行了封装;
Logic Tags:逻辑判断、集合迭代和流程控制。
Nested Tags:该标签库建立在前三个标签库的基础上,具有前三个标签库的所有功能,只是允许标签间的嵌套。
Tiles Tags :该标签库包含的标签可以用来创建tiles样式的页面;布局专用。
3.重点学习前3类标签库
二、Bean标签
可以看成 <jsp:useBean> 的增强版,
它可以定义bean :获取某些数据(cookie,请求参数,请求头),将之定义成一个脚本变量,并同时置于某个作用域(缺省pagaContext) 中;
bean标签的公共属性:
id - 定义一个变量
name - 引用一个存在的bean或对象的名字
property - 被引用的bean的属性
scope - 放置或搜索bean的范围,若没有制定,则依次 page--request---session--application
1.<bean:define/>
作用: 把一个bean 或其属性, 定义成一个变量
* 通过<bean:define/>定义的变量可以通过JSP脚本、EL以及Struts本身的<bean:write/>标记访问。
Example1:
1) 定义一个Java bean:student,并且对其属性进行赋值
2) 通过<bean:define/>定义stuName、stuAge、stuGender三个变量,将student这个对象的属性值赋值给这些变量
<bean:define id="stuName" name="student" property="name"></bean:define>
<bean:define id="stuAge" name="student" property="age"></bean:define>
<bean:define id="stuGender" name="student" property="gender"></bean:define>
3) 输出
<%=stuName%> //jsp形式
${stuAge } //EL表达式
<bean:write name="stuGender"/> //Struts方式
* 如果JavaBean的属性是List等类型,可以指定type属性
Example2:
1)在Java Bean中添加List属性,并提供get/set方法。
private List songs;
public List getSongs() {
List list = new ArrayList();
list.add("我爱北京天安门");
list.add("我和你");
list.add("我不做大哥好多年");
return list;
}
2)<bean:define id="songs" name="student" property="songs"></bean:define>
3)输出
${mySongs[0] }
* 定义新变量,例如:
<bean:define id="bookName" value="Effective Java"></bean:define>
2.<bean:write/>
作用: 输出 bean 或bean属性;
等价于:
${} 或者 <%= %>
3.<bean:message/>
作用:读取属性静态文本内容,支持国际化(i18n)
Example:
1)确认在类路径上含有
com/ApplicationResources.properties
配置路径: <message-resources parameter="com.ApplicationResources" />
2)在文件中加入key,value对
page.title=/u9875/u9762/u6807/u9898
3)提供message.jsp
使用<bean:message key="page.title"/>
4.<bean:size/>
作用:获得一个集合或者数组的大小
Example:
1)定义Java Bean : student
2)读取student这个java bean的songs的size
<jsp:useBean id="student" class="com.bean.Student"></jsp:useBean>
<bean:size id="songsize" name="student" property="songs"/>
3)输出songsize值
Exapmple:定义一个列表,输出其size,要求使用<bean:size/>获取该值
1)<%定义一个List,并初始化%>
2)使用 <bean:size id="listsize1" collection="<%=list %>"/> 获取值
注意:如果使用${},必须要把list放置到范围对象中
3)输出
5.<bean:cookie/>
作用:读取请求头中cookie的信息
* <bean:cookie id="cid" name="customid">
获得指定的名为 "customid" 的coockie,并将其赋值给脚本变量 cid
* 若找不到id为costCookie这个cookie,所以系统创建一个cookie,并将它的值设置为"uu11"
<bean:cookie id="cost" name="costCookie" value="uu11"/>
输出: <bean:write name="cost" property="value"/>
6.<bean:header/>
作用:获取请求头的属性信息
<bean:header id="userAgent" name="User-Agent"/>
//打印出:Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.8.0.7) Gecko/20061011....未完
<bean:header id="host" name="host"/>
//打印出:127.0.0.1:8080
<bean:header id="dummy" name="UNKNOWN-HEAD" value="no defined Header"/>
// no defined Header
7.<bean:include/>
作用:对指定url(由forward、href或page确定)处的资源做一个请求,
将响应数据作为一个String类型的bean绑定到page作用域,
同时创建一个scripting变量。我们可以通过id值访问它们。
Example:
1)在根目录下定义一个文件:include.txt
2)获取文件的内容数据,并赋于words
<bean:include id="words" page="/include.txt"/>
3)输出内容
8.<bean:resource/>
作用:获取指定的资源,以String或者InputStream的方式来读取,其中input属性是决定了对应的方式。
默认(false)是以字符串的方式来读取。
例如:
<bean:resource id="r1" name="/include.txt" /> //打印文件原内容: Hello World!
<bean:resource id="r2" name="/include.txt" input="true" />
//打印出:java.io.ByteArrayInputStream@735f45 input="false"时同样这打印
9.<bean:parameter/>
作用:取出url中queryString中指定参数名称的值
例子:
<bean:parameter id="target" name="action" />
只会读取第一个名字为"action"的参数
<bean:parameter id="ps" name="hobby" multiple="true" />
把url中queryString中名字叫hobby的所有值赋值给变量ps,所以ps应该是一个数组
10.<bean:page/>
作用:把pageContext中的特定的隐含对象(application, request, response, config, session) 取出来,
绑定到某个id中,本页的其他地方就可以使用id来操纵这些隐含对象了。
Example:
<bean:page id="res" property="response" />
<bean:page id="sess" property="session" />
<bean:write name="res" property="contentType"/>
<bean:write name="res" property="characterEncoding"/>
<bean:write name="sess" property="id"/>
<bean:write name="sess" property="maxInactiveInterval"/>
三、HTML标签库
使用taglib指令引入标签库
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
通常是配合bean标签一起使用,是struts中最常用的标签之一。
1.<html:form/>
作用:对html的form表单进行简单的封装,满足struts中表单请求的处理
<html:form action="/login">
</html:form>
如果你有上述一个标签,那么你的Struts配置文件的元素中必须有一个如下内容:
<action-mappings>
<action input="/login.jsp" name="loginForm" path="/login"
type="action.LoginAction" validate="true">
<forward name="success" path="/success.jsp" />
<forward name="error" path="/error.jsp" />
</action>
</action-mappings>
这就是说一个form标签是和form bean相关联的。
任何包含在<form>中用来接收用户输入的标签
(<text>、<password>、<hidden>、<textarea>、<radio>、<checkbox>、<select>)
必须在相关的form bean中有一个指定的属性值。<form>标签中method属性的缺省值是POST
2.<html:link>
作用:超文本连接
属性:page,指定一个页面的路径,必须以/开始。
Example:
当前页面跳转到/bean/parameter.jsp
需要提供参数:
<bean:define id="beanName" value="beanValue"></bean:define>
<html:link page="/bean/parameter.jsp"
paramId="action" paramName="beanName">
<html:param name="hobby" value="sports"></html:param>
跳转到bean:parameter.jsp
</html:link>
这等价于:
http://localhost:8080/工程名/bean/parameter.jsp?hobby=sports&action=beanValue
<a href="/工程名/bean/parameter.jsp?hobby=sports&action=beanValue">跳转到parameter.jsp</a>
3.<html:errors/>
作用:输出错误信息
异常处理会介绍
Example:
1)在资源文件中定义
property1.error1=Property1 Error1
property2.error1=Property2 Error1
property2.error2=Property2 Error2
property2.error3=Property2 Error3
property3.error1=Property3 Error1
property3.error2=Property3 Error2
globalError=Global Error
property1.message1=Property1 Message1
property2.message1=Property2 Message1
property2.message2=Property2 Message2
property2.message3=Property2 Message3
property3.message1=Property3 Message1
property3.message2=Property3 Message2
globalMessage=Global Message
messages.header=<table border=1><tr><td>错误变量</td><td>错误信息</td></tr>
messages.footer=</table>
2)添加jsp文件并编辑
<%@ page import="org.apache.struts.action.*"%>
<%@page import="org.apache.struts.Globals"%>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean"%>
<%
ActionMessages errors = new ActionMessages();
errors.add("property1", new ActionMessage("property1.error1"));
errors.add("property2", new ActionMessage("property2.error1"));
errors.add("property2", new ActionMessage("property2.error2"));
errors.add("property2", new ActionMessage("property2.error3"));
errors.add("property3", new ActionMessage("property3.error1"));
errors.add("property3", new ActionMessage("property3.error2"));
errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("globalError"));
request.setAttribute(Globals.ERROR_KEY, errors);
ActionMessages messages = new ActionMessages();
messages.add("property1", new ActionMessage("property1.message1"));
messages.add("property2", new ActionMessage("property2.message1"));
messages.add("property2", new ActionMessage("property2.message2"));
messages.add("property2", new ActionMessage("property2.message3"));
messages.add("property3", new ActionMessage("property3.message1"));
messages.add("property3", new ActionMessage("property3.message2"));
messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("globalMessage"));
request.setAttribute(Globals.MESSAGE_KEY, messages);
%>
3)输出相应的(出错) 信息:
<table border=1>
<tr>
<td>错误变量</td>
<td>错误信息</td>
</tr>
<tr>
<td>property1</td>
<td><html:errors property="property1" /></td>
</tr>
<tr>
<td>property2</td>
<td><html:errors property="property2" /></td>
</tr>
<tr>
<td>property3</td>
<td><html:errors property="property3" /></td>
</tr>
<tr>
<td>org.apache.struts.action.GLOBAL_MESSAGE</td>
<td><html:errors
property="org.apache.struts.action.GLOBAL_MESSAGE" /></td>
</tr>
<tr>
<td>All</td>
<td><html:errors /></td>
</tr>
</table>
<html:messages message="true" id="msg"
header="messages.header" footer="messages.footer">
<tr>
<td></td>
<td><bean:write name="msg" /></td>
</tr>
</html:messages>
4.<html:image>与<html:img>
作用:在页面中产生图像的输出
最重要的属性page:图象文件的路径,前面必须带有一个斜线。
其它属性:height、width(只有 img 可以设置长和宽)、alt(不知何用)。
Example:
<html:image page="/f4icmu.jpg" alt="软件工程之通俗版"></html:image>
<html:img page="/f4icmu.jpg"/>
等价于:
<input type="image" name="" src="/工程名/f4icmu.jpg" alt="软件工程详解">
<img src="/工程名/f4icmu.jpg">
5.<html:checkbox/>
生成一个checkbox。这里的value值可以是true,yes或on。
checkboxForm的属性:
private boolean one = false;
private boolean two = false;
private boolean three = false;
<html:checkbox name="checkboxForm" property="one">One</html:checkbox>
<html:checkbox name="checkboxForm" property="two">Two</html:checkbox>
<html:checkbox name="checkboxForm" property="three">Three</html:checkbox>
如果选中后被提交则相应的属性的值为true。
6.<html:radio/>
生成一个radio。主要的用法有两种。
下面的代码示例了html:radio标签的一般用法,
如果被提交则选中的radio的value值将被提交到radioForm中的id中。
<html:radio name="radioForm" property="id" value="00001"> One </html:radio>
<html:radio name="radioForm" property="id" value="00002"> Two </html:radio>
7.<html:select>标签和<html:option>标签
作用:对html中的下拉选择标签与选项标签做了封装
单选下拉
Example1:
<html:select property="singleSelect" size="3">
<html:option value="Single 0">Single 0</html:option>
<html:option value="Single 1">Single 1</html:option>
<html:option value="Single 2">Single 2</html:option>
</html:select>
Example2:性别
1)提供label和value的数组
<% String[] label = { "男", "女", "未知" };
String[] value = { "male", "female", "unknown" };
pageContext.setAttribute("label", label);
pageContext.setAttribute("value", value);
%>
2)标签使用:
<html:select property="sex" size="1">
<html:options labelName="label" name="value" />
</html:select>
Example3:兴趣爱好多选
1)提供列表
<% List options = new ArrayList();
options.add(new LabelValueBean("电脑游戏", "PCGame"));
options.add(new LabelValueBean("看电视", "TV"));
options.add(new LabelValueBean("阅读", "Reading"));
options.add(new LabelValueBean("唱歌", "Singing"));
pageContext.setAttribute("opt", options);
%>
其中,
public class LabelValueBean {
private String label;
private String value;
public LabelValueBean(String label, String value){}
}
2)提供多选标签
<html:select property="favors" multiple="true">
<html:options collection="opt" property="value"
labelProperty="label" />
</html:select>
Example4:联系方式多选
1)提供多选列表
<% List myPhones=new ArrayList();
myPhones.add(new LabelValueBean("小灵通","33213322"));
myPhones.add(new LabelValueBean("固话","80512010"));
myPhones.add(new LabelValueBean("手机","13711221113"));
pageContext.setAttribute("myPhones",myPhones);
%>
2)标签的使用
<html:select property="phones" multiple="true">
<html:optionsCollection name="myPhones"/>
</html:select>
8.<html:submit>标签
<html:submit value="Submit" />
9.<hmtl:text>标签
文本输入框
<html:text property="username" />
10.<html:password>标签
<html:password property="password"/>
11.<html:cancel/>取消标签
四、Logic标记 :
该标签库包含的标签可以用来进行逻辑判断、集合迭代和流程控制。
1.<logic:iterate/>
作用:<logic:iterate/>标签用来迭代集合
Example:
<%
List stuList=new ArrayList();
Student stu=new Student();
stu.setName("Alice");
...
stuList.add(stu);
request.setAttribute("stuList",stuList);
%>
<logic:iterate id="stu" name="stuList">
<tr>
<td>${stu.id }</td>
<td>${stu.name }</td>
<td>${stu.sex }</td>
<td>${stu.age }</td>
<td>${stu.desc }</td>
</tr>
</logic:iterate>
(2) logic:empty
用来判断是否为空的。如果为空,该标签体中嵌入的内容就会被处理。该标签用于以下情况:
当Java对象为null时
当String对象为""时
当java.util.Collection对象中的isEmpty()返回true时
当java.util.Map对象中的isEmpty()返回true时
下面的代码示例了logic:empty标签判断集合persons是否为空:
<logic:empty name="stu" property = "books">
<div>集合books为空!</div> </logic:empty>
logic:notEmpty标签的应用正好和logic:empty标签相反。
(3) logic:equal
这里要介绍的不只是logic:equal(=)标签,而是要介绍一类标签,这类标签完成比较运算,
包括:
logic:equal(=)
logic:notEqual(!=)
logic:greaterEqual(>=)
logic:lessEqual(<=)
logic:graterThan(>)
logic:lessThan(<)
Example:
<logic:equal name="stu" property="name" value="Alice">
I am Alice.
</logic:equal>
<bean:define id="count" value="168"/>
<logic:equal name="count" value="168">
Good lucky number.
</logic:equal>
Day3:
1 定制Action
2 禁止表单重复提交
3 定制Controller
4 验证框架
************************************************************************
1 定制Action
1) DispatchAction:可以将相关的一组操作放在一个Action类中(同一模块功能)
特点(优点) :
1)一个 Action可以对应多个业务方法(CRUD),而无需通过增加隐藏域的方式来处理。
2)避免Action类数量随业务复杂度而膨胀,可以共享公共的业务逻辑代码。
3)无需重写execute方法
4)DispatchAction类本身已经重写了Action类的execute方法。
实现DispatchAction的步骤:
1) 继承DispatchAction
SuperGileAction extends DispatchAction
2) 定义自己的处理方法,不要覆盖execute()方法
3) struts-config.xml中action元素增加parameter属性
<action path="/super" name="superForm" parameter="method"
type="com.tarena.action.SuperGileAction">
<forward name="success" path="/success.jsp"></forward>
</action>
用户请求URL应有如下格式:
a)Get方法
http://localhost:8080/super/SuperGileAction.do?method=<method_name>
b) Post方法
在表单中添加参数来完成
2) LookupDispatchAction:
特点:它是DispatchAction的子类,所以具备DispatchAction的所有特性,
支持一个表单对应多个业务方法。
实现LookupDispatchAction的步骤:
1) 继承LookupDispatchAction
2) 定义自己的处理方法,覆盖getKeyMethodMap()方法,不要覆盖execute()方法
getKeyMethodMap()完成资源文件中Key与Action中方法映射
@Override
protected Map getKeyMethodMap() {
Map map = new HashMap();
map.put("submit.modify", "modify");
map.put("submit.add", "register");
return map;
}
public ActionForward modify(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response){
...
}
public ActionForward register(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response){
...
}
3)struts-config.xml中为Action增加parameter属性
<action path="/lookupAction"
name="superForm"
type="com.tarena.action.SuperGirlLookupAction"
parameter="method">
<forward name="success" path="/success.jsp"></forward>
</action>
4) 提交页面按钮有如下格式
html:submit的property属性值与Action中的parameter属性值映射
<html:submit property="method">
<bean:message key="submit.add"/>
</html:submit>
<html:submit property="method">
<bean:message key="submit.modify"/>
</html:submit>
3) Action编程技巧(建议) :
1)尽量避免使用实例变量或静态变量
(servlet是单实例多线程,所以要自己维护成员变量的同步问题)
2)使用自己的BaseAction完成Action的公共操作,其余Action可从BaseAction派生
3)Action不要代替Model工作
在设计多层架构时,使用Business Delegate可降低层与层之间的耦合度
2 禁止表单重复提交
1)客户端实现(JavaScript)
2)JSP实现(脚本)
图解
实现代码
3)Struts实现
(1)Struts内置实现,无需额外配置
(2)需要在前一个action的方法中调用saveToken()方法
saveToken(request);
(3)在后一个执行业务逻辑的方法中使用isTokenValid(request)判断表单是否被重复提交
if (isTokenValid(request)) {
// invoke business method
//......
// reset transaction token after transaction success!
this.resetToken(request);
return mapping.findForward("success");
} else {
System.out.println("duplicate token");
return mapping.findForward("error");
}
3 定制Controller(可选)
扩展控制器功能
ActionServlet与RequestProcessor的作用
1)继承RequestProcessor
2)通过processPreprocess()增加定制功能
//自定义控制器需要派生自RequestProcessor
package com.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.RequestProcessor;
public class SecurityRequestProcessor extends RequestProcessor {
@Override
protected boolean processPreprocess(HttpServletRequest request,
HttpServletResponse response) {
System.out.println("start controller ...");
request.getSession().getServletContext().log("URL="+request.getRequestURL());//写日志
String ip = request.getRemoteAddr();
if (ip.equals("127.0.0.1")) {
System.out.println("valid client: 127.0.0.1");
return true; //只允许此IP登录
}
int lastPoint = ip.lastIndexOf(".");
String fourth = ip.substring(lastPoint + 1);
int fourthInt = Integer.parseInt(fourth);
if (ip.startsWith("192.168.1.") && fourthInt > 50 && fourthInt < 60) {
System.out.println("invalid client: 192.168.1.[50~60]");
return false; //限制黑名单IP的登录
}
return false;
}}
3)struts-config.xml中配置 <controller .../> (一般只有一个controller)
写在<action-mappings /> 之后;<message-resources .../> 之前
<controller processorClass="com.controller.SecurityRequestProcessor"/>
补充说明:
通常的一个struts-config.xml只能配置一个controller
一般地,在开发时通过定制controller来增强系统功能,例如:日志、安全限制等。
但在实际的应用中比较少使用。
举例:
public class SecurityRequestProcessor extends RequestProcessor {
public boolean processPreprocess(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response){
String ip=request.getRemoteAddr();
if(ip.equals("127.0.0.1"))
return true;
int lastPoint = ip.lastIndexOf(".");
String fourth=ip.substring(lastPoint+1);
int fourthInt=Integer.parseInt(fourth);
if(ip.startsWith("192.168.1.")&&fourthInt>50&&fourthInt<60){
return true;
}
return false;
}
}
4 验证(校验) 框架
(1)有三种数据验证方式:
a.在ActionForm.validate() 当中进行
b.在Action.execute()方法中进行(这两种参看day2的异常处理,前两种)
c.引入validator框架(apache.jakata)
(2)声明式的数据验证(为什么能使用声明式?)--配置
原因:对于数据的验证有模式
(3)validator框架已经定义了一部分通用的验证规则和逻辑
开发者只需对特定数据指定具体的验证规则(业务)--使用
包含在validation.xml
使用验证框架的步骤:
1)在struts-config.xml配置校验插件(validate plugin)
放在<message-resources ../> 之后
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>
注释:
1.验证插件:
1) validator-rules.xml :定义验证规则
规则名(如:required, maxlength.....)
验证方法
验证失败时出错提示(放到上下文中)
2)validation.xml
使用规则:对指定的表单属性进行校验
2.基本的结构:
1)验证逻辑:
validateXxx()方法
2)在validator-rule.xml中定义的都是校验规则
3)在validation.xml中(声明式验证)
a.引入了struts-config.xml的表单名字(form-bean的名字)
b.声明域的验证依赖规则
depends = "required,Integer"
2)add validator-rule.xml and validation.xml to /WEB-INF/
copy validator-rule.xml from struts framework
edit validation.xml
注意版本的一致
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE form-validation PUBLIC
"-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN"
"http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd">
<form-validation>
<formset>
<form name="enrollForm">
<field property="name" depends="required">
<arg key="register.name"/>
</field>
<field property="age" depends="required, integer">
<arg key="register.age"/>
</field>
<field property="city" depends="required">
<arg key="register.city"/>
</field>
<field property="gender" depends="required">
<arg key="register.gender"/>
</field>
<field property="email" depends="required,email">
<arg key="register.email"/>
</field>
<field property="birthday" depends="required, date">
<arg key="register.birthday"/>
<var>
<var-name>datePattern</var-name>
<var-value>yyyy-MM-dd</var-value>
</var>
</field>
</form>
</formset>
</form-validation>
注意:如果是使用1.3.x以上的版本,只需要引入:
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames"
value="/org/apache/struts/validator/validator-rules.xml, /WEB-INF/validation.xml"/>
</plug-in>
validation.xml为:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE form-validation PUBLIC
"-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.3.0//EN"
"http://jakarta.apache.org/commons/dtds/validator_1_3_0.dtd">
<form-validation>
<formset>
<form name="enrollForm">
<field property="name" depends="required">
<arg key="register.name"/>
</field>
<field property="age" depends="required, integer">
<arg key="register.age"/>
</field>
<field property="city" depends="required">
<arg key="register.city"/>
</field>
<field property="gender" depends="required">
<arg key="register.gender"/>
</field>
<field property="email" depends="required,email">
<arg key="register.email"/>
</field>
<field property="birthday" depends="required, date">
<arg key="register.birthday"/>
<var>
<var-name>datePattern</var-name>
<var-value>yyyy-MM-dd</var-value>
</var>
</field>
</form>
</formset>
</form-validation>
3)develop ur ActionForm (服务器端验证需要遵循的规范)
(1) 自定义ActionForm 要继承 ValidatorForm
最好不要重写validate方法!如果重写validate方法,则必须显式调用 return super.validate(...)方法
(2) 动态form要使用org.apache.struts.validator.DynaValidatorForm
4)(服务器端验证需要遵循的规范)
<action ..... validate="true" input="假如出错的页面" >
5)copy validation rules to ApplicationResources.properties
register.title=Super Boy Register Form
register.name=Name:
register.gender=Gender:
register.age=Age:
register.city=City:
register.email=Email:
register.birthday=Birthday:
errors.required={0} is required.
errors.integer={0} must be an integer.
errors.date={0} is not a date.
errors.email={0} is an invalid e-mail address.
6)active javaScript in Jsp page.(采用客户端验证才需要这一步)
<html:javascript formName="enrollForm"/>
<html:form action="/enroll" onsubmit="return validateEnrollForm(this)" method="post">
建议:(1) 客户端能做的验证,一般不要在服务器端验证。
一般输入格式等方面的验证
(2) 客户端实在没有能力进行验证的情况,发到服务器端做验证。
禁止表单重复提交:
1.客户端方案(Java Script)
使用js来实现禁止表单重复提交的方法很多,大体有如下几种:
1)提交时,使提交按钮不可用(disable),或者隐藏按钮,使用进度条
参考实现:
/*
函数名称:disableButtons
函数功能:提交前,将所有表单中的button,reset,submit禁用disabled;
如果是submit按钮,则添加与之相同隐藏文本框hidden对象,让提交的信息无一漏网
*/
function disableBtns()
{
for(k=0;k<document.all.length;k++ )
{
//当前节点对象
var obj = document.all(k)
if( obj.type=='button' || obj.type=='submit' || obj.type=='reset')
{
obj.disabled = true
if (obj.type=='submit')
{
//添加隐藏节点
var oNewNode = document.createElement("input");
oNewNode.type = "hidden"
oNewNode.name = obj.name
oNewNode.value = obj.value
obj.insertAdjacentElement("afterEnd",oNewNode);
}
}
}
}
/*
函数名称:disButtons2
函数功能:提交前,将所有表单中的button,reset,submit禁用disabled;
如果是submit按钮,则添加与之相同隐藏文本框hidden对象,让提交的信息无一漏网
函数说明:与上面的函数功能一样,但适用浏览器范围更广,推荐使用此函数。
*/
function disableBtns()
{
for(k=0;k<document.forms.length;k++ )
{
//获取当前表单
var frm = document.forms[k]
for(i=0;i<frm.length;i++)
{
var obj = frm.elements[i]
if ( obj.type=='button' || obj.type=='submit' || obj.type=='reset' )
{
obj.disabled = true
if (obj.type=='submit')
{
var oNewNode = document.createElement("input");
oNewNode.type = "hidden"
oNewNode.name = obj.name
oNewNode.value = obj.value
//frm.insertAdjacentElement("beforeEnd",oNewNode);
obj.insertAdjacentElement("afterEnd",oNewNode);
}
}
}
}
}
/*
函数名称:hiddenForm
函数功能:提交时让表单自动隐藏,而不影响数据的提交
*/
function hideForm(form)
{
//waitStr 提交过程中出现的提示,可以自行设置
var waiting = "<center><img src='progress.jpg'>数据正在提交中,请等候</center>";
form.innerHTML = "<div style='display:none;'>"+form.innerHTML+"</div>"+waiting;
}
2)使用标识来实现控制客户端多次点击
<script type="text/javascript">
//控制标志
var submitted = false;
function checkSubmit() {
if(submitted == true) {
alert("submitted == true");
return false;
}
submitted = true;
return true;
}
//控制页面双击行为
document.ondblclick = function docOnDblClick() {
window.event.returnValue = false;
}
//控制页面单击行为
document.onclick = function docOnClick() {
if(submitted) {
window.event.returnValue = false;
}
}
</script>
<html:form action="/logon" method="post" onsubmit="return checkSubmit();">
<html:text property="name"></html:text>
<html:submit value="login">
</html:submit>
</html:form>
2.服务器端方案
原理:使用transaction token
1)jsp版
Day4:
一、 文件上传
步骤:
1)定义表单
<html:form action="/fileupload" enctype="multipart/form-data">
<table>
<tr>
<td><b>请选择上传的文件:</b></td>
<td><html:file property="file"></html:file></td>
</tr>
<tr></tr>
<tr>
<td colspan=2 align=center>
<html:submit>上传</html:submit>
</td>
</tr>
</table>
</html:form>
2)配置stuts-config.xml
*定义Form
*定制Action
a)form
public class FileUploadForm extends ActionForm {
private FormFile file;
public FormFile getFile() { return file; }
public void setFile(FormFile file) { this.file = file; }
}
b)action
//处理文件
FormFile file = fileUploadForm.getFile();
InputStream is = file.getInputStream();
OutputStream os = new FileOutputStream(path + filename);
输出文件
二、Struts Tiles----强大的页面模板与页面布局技术
1.作用:Tiles框架提供模板机制,完成页面布局和内容展示逻辑的解耦
-------分离变与不变的元素:布局是不变的,而内容是变化的
2.如何使用tiles框架
步骤:
1) 在struts-config.xml配置tiles插件
<plug-in className="org.apache.struts.tiles.TilesPlugin">
<set-property property="definitions-config"
value="/WEB-INF/tiles-define.xml"/>
</plug-in>
2) 定义tiles:tiles-define.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 1.3//EN"
"http://struts.apache.org/dtds/tiles-config_1_3.dtd">
<tiles-definitions>
<definition name="definition1" page="/layout/baselayout.jsp">
<put name="title" value="mainspace"></put>
<put name="header" value="/layout/header.jsp"></put>
<put name="footer" value="/layout/footer.jsp"></put>
<put name="body" value="/layout/body.jsp"></put>
<put name="navigator" value="/layout/navigator.jsp"></put>
</definition>
<definition name="user" extends="definition1">
<put name="title" value="another mainspace"></put>
<put name="body" value="/usermanager/user.jsp"></put>
</definition>
</tiles-definitions>
3) 定义布局以及所有的组成部分
baselayout.jsp
header.jsp
footer.sjp
body.jsp
navigator.jsp
变化的内容定义为:
<tiles:getAsString name="title"/>
<tiles:insert attribute="header">
baselayout.jsp参考代码:
-------------------------------------------------------------------------------------------------------
<%@ taglib uri="http://struts.apache.org/tags-tiles" prefix="tiles"%>
<html>
<head>
<title><tiles:getAsString name="title"/></title>
</head>
<body>
<table border="0" width="100%" cellspacing="5">
<tr><td colspan=2 align=center>
<tiles:insert attribute="header"></tiles:insert></td></tr>
<tr><td width="15%" valign="top">
<tiles:insert attribute='navigator'></tiles:insert></td>
<td align="left">
<tiles:insert attribute='body'></tiles:insert></td></tr>
<tr><td colspan="2"><hr></td></tr>
<tr><td colspan=2 align=center>
<tiles:insert attribute="footer"></tiles:insert></td></tr>
</table>
</body>
</html>
-------------------------------------------------------------------------------------------------------
4) 在页面中引用 tiles:
<tiles:insert definition="defall"/>
也可以覆盖定义的属性值
<tiles:insert definition="defall">
<tiles:put name="title" value="my page"/>
</tiles:insert>
3.使用tiles-define.xml定义tiles的好处:
1) tiles可重用(被多个页面)
2) tiles的定义可以被"继承"和"覆盖"
3) 使用已定义的definition