Struts 2下的helloword

更新时间:2024-06-11 12:50:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

本章要点

— Struts 2的下载和安装 — 纯手工创建一个Web应用 — 纯手工创建一个Struts 2应用 — 实现Struts 2的Action — 配置Struts 2的Action — 在Action中访问HttpSession — 在JSP中输出Action的返回值 — 使用Struts 2的表单标签 — 程序国际化初步 — 数据校验初步

前面已经简要介绍了Struts 2的起源,以及Struts 2的两个前身:Struts 1和WebWork,并详细对比了Struts 2和Struts 1的差异,对比了Struts 2和WebWork的差异,而且指出:Struts 2是WebWork的升级,而不是Struts 1的升级。

虽然Struts 2提供了与Struts 1的兼容,但已经不是Struts 1的升级。对于已有Struts 1开发经验的开发者而言,Struts 1的开发经验对于Struts 2并没有太大的帮助;相反,对于已经有WebWork开发经验的开发者而言,WebWork的开发经验对Struts 2的开发将有很好的借鉴意义。

下面将以一个Struts 2的HelloWorld应用为例,介绍Strust 2 MVC框架如何拦截用户请求,如何调用业务控制器处理用户请求,并介绍Action处理结果和资源之间的映射关系。

本HelloWorld应用是一个简单的应用:用户进入一个登录页面,允许用户输入用户名、密码,如果用户输入的用户名和密码符合要求,则进入一个欢迎页面;如果用户输入错误,则进入一个提示页面。当用户提交表单时,本应用会有基本的数据校验。

2.1 下载和安装Struts 2框架

下面我们从下载、安装Struts 2开始,慢慢开始体验Struts 2 MVC框架的魅力。 笔者写本书的时候,Struts 2已经发布了其产品化GA(General Availability)版,其实最新的产品化GA版是Struts 2.06,故本书的所有应用都是基于该版本的Struts 2。建议读者下载Struts 2.06版,而不是下载最新的Beta版,如果Struts 2有最新的GA版,读者也可以下载更新的GA版,相信不会有太大差异。 下载和安装DWR请按如下步骤进行。 登录http://struts.apache.org/download.cgi#Struts206站点,下载Struts 2的最新GA版。在Struts 2.06下有如下几个选项: — Full Distribution:下载Struts 2的完整版。通常建议下载该选项。 — Example Applications:下载Struts 2的示例应用,这些示例应用对于学习Struts 2有很大的帮助,下载Struts 2的完整版时已经包含了该选项下全部应用。 — Blank Application only:仅下载Struts 2的空示例应用,这个空应用已经包含在Example Applications选项下。 — Essential Dependencies:仅仅下载Struts 2的核心库,下载Struts 2的完整版时将包括该选项下的全部内容。 — Documentation:仅仅下载Struts 2的相关文档,包含Struts 2的使用文档、参考手册和API文档等。下载Struts 2的完整版时将包括该选项下的全部内容。 — Source:下载Struts 2的全部源代码,下载Struts 2的完整版时将包括该选项下的全部内容。 — Alternative Java 4 JARs:下载可选的JDK 1.4的支持JAR。下载Struts 2的完整版时将包括该选项下的全部内容。 通常建议读者下载第一个选项:下载Struts 2的完整版,将下载到的Zip文件解压缩,该文件就是一个典型的Web结构,该文件夹包含如下文件结构: — apps:该文件夹下包含了基于Struts 2的示例应用,这些示例应用对于学习者是非常有用的资料。 — docs:该文件夹下包含了Struts 2的相关文档,包括Struts 2的快速入门、Struts 2的文档,以及API文档等内容。 — j4:该文件夹下包含了让Struts 2支持JDK 1.4的JAR文件。 — lib:该文件夹下包含了Struts 2框架的核心类库,以及Struts 2的第三方插件类库。 — src:该文件夹下包含了Struts 2框架的全部源代码。 将lib文件夹下的Struts2-core-2.0.6.jar、xwork-2.0.1.jar和ognl-2.6.11.jar等必需类库复制到Web应用的WEB-INF/lib路径下。当然,如果你的Web应用需要使用Struts 2的更多特性,则需要将更多的JAR文件复制到Web应用的WEB-INF/lib路径下。如果需要在DOS或者Shell窗口下手动编译Struts 2相关的程序,则还应该将Struts2-core-2.0.6.jar和xwork-2.0.1.jar添加到系统的CLASSPATH环境变量里。

提示 大部分时候,使用Struts 2的Web应用并不需要利用到Struts 2的全部特性,因此没有必要一次将该lib路径下JAR文件全部复制到Web应用的WEB-INF/lib路径下。 编辑Web应用的web.xml配置文件,配置Struts 2的核心Filter。下面是增加了Struts 2的核心Filter配置的web.xml配置文件的代码:

xsi:schemaLocation=\

com/xml/ns/j2ee/web-app_2_4.xsd\>

struts2

org.apache.Struts2.dispatcher.FilterDispatcher

Struts2 /*

经过上面3个步骤,我们已经可以在一个Web应用中使用Struts 2的基本功能了,下面将带领读者进入Struts 2 MVC框架的世界。

2.2 从用户请求开始

Struts 2支持大部分视图技术,当然也支持最传统的JSP视图技术,本应用将使用最基本的视图技术:JSP技术。当用户需要登录本系统时,用户需要一个简单的表单提交页面,这个表单提交页面包含了两个表单域:用户名和密码。

下面是一个最简单的表单提交页面,该页面的表单内仅包含两个表单域,甚至没有任何动态内容,实际上,整个页面完全可以是一个静态HTML页面。但考虑到需要在该页面后面增加动态内容,因此依然将该页面以jsp为后缀保存。下面是用户请求登录的JSP页面代码:

<%@ page language=\contentType=\charset=GBK\

登录页面

正如前面介绍的,该页面没有包含任何的动态内容,完全是一个静态的HTML页面。但我们注意到该表单的action属性:login.action,这个action属性比较特殊,它不是一个普通的Servlet,也不是一个动态JSP页面。可能读者已经猜到了,当表单提交给login.action时,Struts 2的FilterDispatcher将自动起作用,将用户请求转发到对应的Struts 2 Action。 注意 Struts 2 Action默认拦截所有后缀为.action的请求。因此,如果我们需要将某个表单提交给Struts 2 Action处理,则应该将该表单的action属性设置为*.action的格式。 该页面就是一个基本的HTML页面,在浏览器中浏览该页面,看到如图2.1所示的界面。

整个页面就是一个标准的HTML页面,整个单独的页面还没有任何与用户交互的能力。下面我们开始动手创建一个Struts 2的Web应用。

2.3 创建Struts 2的Web应用

Struts 2的Web应用就是一个普通的Web应用,然后增加Struts 2功能,该应用就可以充分利用Struts 2的MVC框架了。

2.3.1 创建Web应用

笔者一直相信:要想成为一个优秀的程序员,应该从基本功练起,所有的代码都应该用简单的文本编辑器(包括EditPlus、UtraEdit等工具)完成。笔者

经常见到一些有两三年开发经验的程序员,一旦离开了熟悉的IDE(集成开发环境,如Eclipse、JBuilder等),完全不能动手写任何代码。而他们往往还振振有词:谁会不用任何工具来开发?

实际上,真正优秀的程序员当然可以使用IDE工具,但即使使用VI(UNIX下无格式编辑器)、记事本也一样可以完成非常优秀的项目。笔者对于IDE工具的态度是:可以使用IDE工具,但绝不可依赖于IDE工具。学习阶段,千万不要使用IDE工具;开发阶段,才去使用IDE工具。

提醒 对于IDE工具,业内有一个说法:IDE工具会加快高手的开发效率,但会使初学者更白痴。 为了让读者更加清楚Struts 2应用的核心,笔者下面将“徒手”建立一个Struts 2应用。 建立一个Web应用请按如下步骤进行。 在任意目录新建一个文件夹,笔者将以该文件夹建立一个Web应用。 在第1步所建的文件夹内建一个WEB-INF文件夹。 进入Tomcat,或任何Web容器内,找到任何一个Web应用,将Web应用的WEB-INF下的web.xml文件复制到第2步所建的WEB-INF文件夹下。 修改复制的web.xml文件,将该文件修改成只有一个根元素的XML文件,修改后的web.xml文件代码如下: 在第2步所建的WEB-INF路径下,新建两个文件夹:classes和lib,它们分别用于保存单个*.class文件和JAR文件。 经过上面步骤,已经建立了一个空Web应用。将该Web应用复制到Tomcat的webapps路径下,该Web应用将可以自动部署在Tomcat中。 将2.2节所定义的JSP页面文件复制到第1步所建的文件夹下,该JSP页面将成为该Web应用的一个页面。该Web将有如下文件结构: Struts2qs |-WEB-INF | |-classes | |-lib | |-web.xml |-login.jsp 上面的Struts2qs是Web应用所对应文件夹的名字,可以更改;login.jsp是该Web应用下JSP页面的名字,也可以修改。其他文件夹、配置文件都不可以修改。 启动Tomcat,在浏览器中浏览2.2节定义的JSP页面,将看到如图2.1所示的页面。 2.3.2 增加Struts 2功能 为了给Web应用增加Struts 2功能,只需要将Struts 2安装到Web应用中即可。在Web应用中安装Struts 2框架核心只需要经过如下三个步骤。 修改web.xml文件,在web.xml文件中配置Struts 2的核心Filter。 将Struts 2框架的类库复制到Web应用的WEB-INF/lib路径下。 在WEB-INF/classes下增加struts.xml配置文件。 下面是增加了Struts 2功能后Web应用的文件结构: Struts2qs |-WEB-INF | |-classes(struts.xml) | |-lib(commons-logging.jar,freemarker.jar,ognl.jar,struts2-core.jar,xwork.jar) | |-web.xml |-login.jsp 在上面的文件结构中,lib下Struts 2框架的类库可能有版本后缀。例如commons-logging.jar,可能是commons-logging-1.1.jar;struts2-core.jar可能是struts2-core-2.0.6.jar。

修改后的web.xml文件在2.1节已经给出了,故此处不再赘述。

此处需要给读者指出的是,Struts 2的Web应用默认需要Java 5运行环境,需要Web容器支持Servlet API 2.4和JSP API 2.0。如果读者需要使用更低版本的Java运行时环境,则需要使用Struts 2框架的JDK 1.4支持。为了简单起见,笔者建议读者使用Java 5运行时环境,使用Tomcat 5.5或者更高版本。

注意 Struts 2应用默认需要Java 5运行时环境,需要支持Servlet API 2.4和JSP API 2.0的Web容器。 2.4 实现控制器 前面介绍MVC框架时,已经指出:MVC框架的核心就是控制器。当用户通过2.2节的页面提交用户请求时,该请求需要提交给Struts 2的控制器处理。Struts 2的控制器根据处理结果,决定将哪个页面呈现给客户端。 2.4.1 实现控制器类 Struts 2下的控制器不再像Struts 1下的控制器,需要继承一个Action父类,甚至可以无需实现任何接口,Struts 2的控制器就是一个普通的POJO。 实际上,Struts 2的Action就是一个包含execute方法的普通Java类,该类里包含的多个属性用于封装用户的请求参数。下面是处理用户请求的Action类的代码: //Struts 2的Action类就是一个普通的Java类 public class LoginAction { //下面是Action内用于封装用户请求参数的两个属性 private String username; private String password; //username属性对应的getter方法 public String getUsername() { return username; }

//username属性对应的setter方法 public void setUsername(String username) {

this.username = username; }

//password属性对应的getter方法 public String getPassword() {

return password; }

//password属性对应的setter方法 public void setPassword(String password) {

this.password = password; }

//处理用户请求的execute方法

public String execute() throws Exception {

//当用户请求参数的username等于scott,密码请求参数为tiger时,返回success 字符串

//否则返回error字符串

if (getUsername().equals(\&& getPassword().equals(\) {

return \} else {

return \} } }

上面的Action类是一个再普通不过的Java类,该类里定义了两个属性:username和password,并为这两个属性提供了对应的setter和getter方法。除

此之外,该Action类里还包含了一个无参数的execute方法——这大概也是Action类与POJO唯一的差别。实际上,这个execute方法依然是一个很普通的方法,既没有与Servlet API耦合,也没有与Struts 2 API耦合。

提示 表面上看起来,该Action的两个属性只提供了对应的setter和getter方法,很难理解请求参数在什么时候赋值给该Action的属性,事实上,因为Struts 2的拦截器机制,它们负责解析用户的请求参数,并将请求参数赋值给Action对应的属性。 2.4.2 配置Action

上面定义了Struts 2的Action,但该Action还未配置在Web应用中,还不能处理用户请求。为了让该Action能处理用户请求,还需要将该Action配置在struts.xml文件中。

前面已经介绍过了,struts.xml文件应该放在classes路径下,该文件主要放置Struts 2的Action定义。定义Struts 2 Action时,除了需要指定该Action的实现类外,还需要定义Action处理结果和资源之间的映射关系。下面是该应用的struts.xml文件的代码:

\Software Foundation//DTD Struts Configuration 2.0//EN\\

上面映射文件定义了name为login的Action,即:该Action将负责处理向login.action URL请求的客户端请求。该Action将调用自身的execute方法处理用户请求,如果execute方法返回success字符串,请求将被转发到/welcom

e.jsp页面;如果execute方法返回error字符串,则请求被转发到/error.jsp页面。 2.4.3 增加视图资源完成应用 经过上面步骤,这个最简单的Struts 2应用几乎可以运行了,但还需要为该Web应用增加两个JSP文件,两个JSP文件分别是error.jsp页面和welcome.jsp页面,将这两个JSP页面文件放在Web应用的根路径下(与WEB-INF在同一个文件夹下)。 这两个JSP页面文件是更简单的页面,它们只是包含了简单的提示信息。其中welcome.jsp页面的代码如下: <%@ page language=\contentType=\charset=GBK\ 成功页面 您已经登录! 上面的页面就是一个普通的HTML页面,登录失败后进入的error.jsp页面也与此完全类似。 在如图2.1所示页面的“用户名”输入框中输入scott,在“密码”输入框中输入tiger,页面将进入welcome.jsp页面,将看到如图2.2所示的页面。 对于上面的处理流程,可以简化为如下的流程:用户输入两个参数,即username和password,然后向login.action发送请求,该请求被FilterDispatcher转发给LoginAction处理,如果LoginAction处理用户请求返回success字符串,则返回给用户welcome.jsp页面;如果返回error字符串,则返回给用户error.jsp页面。 图2.3显示了上面应用的处理流程。 图2.3 HelloWorld应用的处理流程 2.5 改进控制器 通过前面介绍,读者已经可以完成简单的Struts 2的基本应用了,但还可以进一步改进应用的Action类,例如该Action类可以通过实现Action接口,利用该接口的优势。前面应用的Action类没有与JavaBean交互,没有将业务逻辑操作的结果显示给客户端。 2.5.1 实现Action接口 表面上看起来,实现Struts 2的Action接口没有太大的好处,仅会污染该Action的实现类。事实上,实现Action接口可以帮助开发者更好地实现Action类。下面首先看Action接口的定义: public interface Action { //下面定义了5个字符串常量 public static final String SUCCESS = \public static final String NONE = \public static final String ERROR = \public static final String INPUT = \public static final String LOGIN = \//定义处理用户请求的execute抽象方法 public String execute() throws Exception; } 在上面的Action代码中,我们发现该Action接口里已经定义了5个标准字符串常量:SUCCESS、NONE、ERROR、INPUT和LOGIN,它们可以简化execute方法的返回值,并可以使用execute方法的返回值标准化。例如对于处理成功,则返回SUCCESS常量,避免直接返回一个success字符串(程序中应该尽量避免直接返回数字常量、字符串常量等)。

因此,借助于上面的Action接口,我们可以将原来的Action类代码修改为如下:

//实现Action接口来实现Struts 2的Action类 public class LoginAction implements Action {

//下面是Action内用于封装用户请求参数的两个属性 private String username; private String password;

//username属性对应的getter方法 public String getUsername() {

return username; }

//username属性对应的setter方法 public void setUsername(String username) {

this.username = username; }

//password属性对应的getter方法 public String getPassword() {

return password; }

//password属性对应的setter方法 public void setPassword(String password) {

this.password = password; }

//处理用户请求的execute方法

public String execute() throws Exception

{

//当用户请求参数的username等于scott,密码请求参数为tiger时,返回success 字符串

//否则返回error的字符串 if (getUsername().equals(\&& getPassword().equals(\) {

return SUCCESS; } else {

return ERROR; } } }

对比前面Action和此处的Action实现类,我们发现两个Action类的代码基本相似,除了后面的Action类实现了Action接口。因为实现了Action接口,故Action类的execute方法可以返回Action接口里的字符串常量。

2.5.2 跟踪用户状态

前面的Action处理完用户登录后,仅仅执行了简单的页面转发,并未跟踪用户状态信息——通常,当一个用户登录成功后,需要将用户的用户名添加为Session状态信息。

为了访问HttpSession实例,Struts 2提供了一个ActionContext类,该类提供了一个getSession的方法,但该方法的返回值类型并不是HttpSession,而是Map。这又是怎么回事呢?实际上,这与Struts 2的设计哲学有关,Struts 2为了简化Action类的测试,将Action类与Servlet API完全分离,因此getSession方法的返回值类型是Map,而不是HttpSession。

虽然ActionContext的getSession返回的不是HttpSession对象,但Struts 2的系列拦截器会负责该Session和HttpSession之间的转换。

为了可以跟踪用户信息,我们修改Action类的execute方法,在execute方法中通过ActionContext访问Web应用的Session。修改后的execute方法代码如下:

//处理用户请求的execute方法

public String execute() throws Exception {

//当用户请求参数的username等于scott,密码请求参数为tiger时,返回success字符串 //否则返回error的字符串 if (getUsername().equals(\&& getPassword().equals(\) {

//通过ActionContext对象访问Web应用的Session

ActionContext.getContext().getSession().put(\, getUsername()); return SUCCESS; } else {

return ERROR; } }

上面的代码仅提供了Action类的execute方法,该Action类的其他部分与前面的Action类代码完全一样。在上面的Action类通过ActionContext设置了一个Session属性:user。为了检验我们设置的Session属性是否成功,我们修改welcome.jsp页面,在welcome.jsp页面中使用JSP 2.0表达式语法输出Session中的user属性。下面是修改后的welcome.jsp页面代码:

<%@ page language=\contentType=\charset=GBK\

成功页面

欢迎,${sessionScope.user},您已经登录!

上面的JSP页面与前面的JSP页面没有太大改变,除了使用了JSP 2.0语法来输出Session中的user属性。关于JSP 2.0表达式的知识,请参看笔者所著的《轻量级J2EE企业应用实战》一书的第2章。 在如图2.1所示页面的“用户名”输入框中输入scott,在“密码”输入框中输入tiger,然后单击“登录”按钮,将看到如图2.4所示的页面。 在上面登录成功的页面中,已经输出登录所用的用户名:scott,可见在Action通过ActionContext设置Session是成功的。 2.5.3 添加处理信息 到目前为止,Action仅仅控制转发用户请求,JSP页面并未获得Action的处理结果。对于大部分Web应用而言,用户需要获得请求Action的处理结果,例如,在线购物系统需要查询某个种类下的商品,则Action调用业务逻辑组件的业务逻辑方法得到该种类下的全部商品,而JSP页面则获取该Action的处理结果,并将全部结果迭代输出。 下面将为应用增加一个Action,该Action负责获取某个系列的全部书籍。为了让该Action可以获取这系列的书籍,我们增加一个业务逻辑组件,它包含一个业务逻辑方法,该方法可以获取某个系列的全部书籍。 下面是系统所用的业务逻辑组件的代码: public class BookService { //以一个常量数组模拟了从持久存储设备(数据库)中取出的数据 private String[] books = new String[]{ \宝典\, \轻量级J2EE企业应用实战\\基于J2EE的Ajax宝典\\整合开发\}; //业务逻辑方法,该方法返回全部图书 public String[] getLeeBooks() { return books; } }

上面的业务逻辑组件实际上就是MVC模式中的Model,它负责实现系统业务逻辑方法。理论上,业务逻辑组件实现业务逻辑方法时,必须依赖于底层的持久层组件,但此处的业务逻辑组件则只是返回一个静态的字符串数组——因为这只是一种模拟。

注意 此处的业务逻辑组件只是模拟实现业务逻辑方法,并未真正调用持久层组件来获取数据库信息。 在系统中增加如下Action类,该Action类先判断Session中user属性是否存在,并且等于scott字符串——这要求查看图书之前,用户必须已经登录本系统。如果用户已经登录本系统,则获取系统中全部书籍,否则返回登录页面。

新增的Action类的代码如下:

public class GetBooksAction implements Action {

//该属性并不用于封装用户请求参数,而用于封装Action需要输出到JSP页面信息 private String[] books; //books属性的setter方法

public void setBooks(String[] books) {

this.books = books; }

//books属性的getter方法 public String[] getBooks() {

return books; }

//处理用户请求的execute方法

public String execute() throws Exception {

//获取Session中的user属性

String user = (String)ActionContext.getContext().getSession(). get(\

//如果user属性不为空,且该属性值为scott if (user != null && user.equals(\{

//创建BookService实例

BookService bs = new BookService();

//将业务逻辑组件的返回值设置成该Action的属性 setBooks(bs.getLeeBooks()); return SUCCESS; } else {

return LOGIN; }

} }

通过上面的Action类,我们发现Action类中的成员属性,并不一定用于封装用户的请求参数,也可能是封装了Action需要传入下一个JSP页面中显示的属性。

提示 Action中的成员属性,并一定用于封装用户的请求参数,也可能是封装了Action需要传入下一个页面显示的值。实际上,这些值将被封装在ValueStack对象中。 当我们的控制器需要调用业务逻辑方法时,我们直接创建了一个业务逻辑组件的实例,这并不是一种好的做法,因为控制器不应该关心业务逻辑组件的实例化过程。比较成熟的做法可以利用工厂模式来管理业务逻辑组件;当然,目前最流行的方式是利用依赖注入——这将在后面章节里介绍。

注意 实际项目中不会在控制器中直接创建业务逻辑组件的实例,而是通过工厂模式管理业务逻辑组件实例,或者通过依赖注入将业务逻辑组件实例注入控制器组件。 该Action处理用户请求时,无需获得用户的任何请求参数。将该Action配置在struts.xml文件中,配置该Action的配置片段如下:

当用户向getBooks.action发送请求时,该请求将被转发给lee.GetBooksAction处理。

2.5.4 输出处理信息

如果用户没有登录,直接向getBooks.action发送请求,该请求将被转发到login.jsp页面。如果用户已经登录,getBooks.action将从系统中加载到系统中的所有图书,并将请求转发给showBook.jsp页面,因此showBook.jsp页面必须负责输出全部图书。

下面笔者将以最原始的方式:JSP脚本来输出全部图书。

注意 在实际应用中,几乎绝对不会使用笔者这种方式来输出Action转发给JSP输出的信息,但笔者为了让读者更清楚Struts 2标签库在底层所完成的动作,故此处使用JSP脚本来输出全部图书信息。 当Action设置了某个属性值后,Struts 2将这些属性值全部封装在一个叫做struts.valueStack的请求属性里。

提示 读者可能感到奇怪:笔者是如何知道Struts 2将这些属性值封装在struts.valueStack请求属性里的?这一方面与编程经验有关,另一方面可以通过查看Struts 2的各种文档,最重要的一点是可以在showBook.jsp页面中通过getAttributeNames方法分析请求中的全部属性。 为了在JSP页面中输出需要输出的图书信息,我们可以通过如下代码来获取包含全部输出信息的ValueStack对象。

//获取封装输出信息的ValueStack对象 request.getAttribute(\

上面代码返回一个ValueStack对象,该对象封装了全部的输出信息。该对象是 Struts 2使用的一个ValueStack对象,可以通过OGNL表达式非常方便地访问该对象封装的信息。

从数据结构上来看,ValueStack有点类似于Map结构,但它比Map结构更加强大(因为它可以根据表达式来查询值)。Action所有的属性都被封装到了ValueStack对象中,Action中的属性名可以理解为ValueStack中value的名字。

大致理解了ValueStack对象的结构后,我们可以通过如下代码来获取Action中设置的全部图书信息。

//调用ValueStack的fineValue方法查看某个表达式的值 vs.findValue(\

理解了上面关键的两步,整个JSP页面的代码就比较容易了解了。下面是showBook.jsp页面的代码:

<%@ page language=\contentType=\charset=GBK\<% @page import=\

作者李刚的图书

作者李刚的图书 <%

//获取封装输出信息的ValueStack对象

ValueStack vs = (ValueStack)request.getAttribute(\//调用ValueStack的fineValue方法获取Action中的books属性值 String[] books = (String[])vs.findValue(\//迭代输出全部图书信息 for (String book : books) { %>

书名: <%=book%> <%}%>

不可否认,上面JSP页面的代码是丑陋的,而且难以维护,因为里面镶嵌了大量的Java脚本。但它对于读者理解Struts 2如何处理封装在Action的ValueStack却很有帮助。

在浏览器中向getBooks.action发送请求,将看到如图2.5所示的页面。 通过上面页面,我们看到JSP页面已经输出了Struts 2控制器的返回信息。上面整个过程,已经完全包括了Struts 2框架的3个部分:视图、控制器和模型。

图2.5 在JSP页面中输出Action的返回信息 2.6 改进视图组件 通过前面的几节的介绍,我们已经明白了Struts 2 MVC框架的基本数据流,已经完成了Struts 2应用中模型、控制器、视图3个组件的开发。但应用中的视图组件:JSP页面非常丑陋,特别是输出Action返回信息的JSP页面,使用了大量的Java脚本来控制输出,下面将会使用Struts 2的标签来改善整个应用视图组件。 2.6.1 改善输出页面 为了控制输出Struts 2的ValueStack中封装的值,Struts 2提供了大量的标签。其中比较常用的标签有: — if:该标签支持标签体,如果if标签里判断的表达式返回真,则输出标签体内容。 — else:该标签不能独立使用,它需要与if标签结合使用,如果if标签内判断的表达式返回假,则输出该标签里的标签体。 — iterator:主要用于迭代输出某个集合属性的各个集合元素。 — property:该标签用于输出指定属性值。 关于Struts 2标签库更深入的使用,第10章还会深入介绍,故此处不再详细讲解。通过使用上面的几个标签,替换showBook.jsp页面中的Java脚本,修改后的showBook.jsp页面代码如下: <%@ page language=\contentType=\charset=GBK\%> <%@taglib prefix=%uri=\ 作者李刚的图书

作者李刚的图书

书名:

上面的JSP页面使用了Struts 2的标签库,因此必须在JSP页面的首部添加taglib指令,该taglib指令用于导入标签库。

提示 如果需要使用某个标签库中的标签,则必须在页面的开始导入该标签库。 页面中使用Struts 2的iterator标签迭代输出ValueStack中的books数组,并为每个数组元素定义了一个序号:index。通过判断序号是否为奇数,如果行序号为奇数,则输出一个有背景色的表格行;否则输出一个无背景色的表格行。

在浏览器中再次向getBooks.action发送请求(发送请求之前,必须先登录本系统),将看到如图2.6所示的界面。

图2.6 使用Struts 2标签改善后的输出界面 上面页面的输出效果与图2.5并没有太大的不同,只是使用不同颜色来分隔了记录行。这也得益于Struts 2标签库的简洁。 关键在于2.5.4节中的JSP页面代码与本节页面代码的差异:前面JSP页面使用了大量的Java脚本,让整个页面的代码看起来非常凌乱,降低了可阅读性、可维护性。但本页面中仅使用Struts 2脚本控制输出,完全消除了页面中的Java脚本,降低了该页面的后期维护成本。 2.6.2 使用UI标签简化表单页面 前面已经提到过,Struts 2的一个重要组件就是标签库。Struts 2标签库中不仅提供了前面所示的基本控制、数据输出等功能,还提供了非常丰富的UI组件,除了提供系列的主题相关标签外,还提供了一系列的表单相关的标签。 Struts 2为常用表单域都提供了对应的标签,下面是常用的表单域标签。 — form:对应一个表单元素。 — checkbox:对应一个复选框元素。 — password:对应一个密码输入框。 — radio:对应一个单选框元素。 — reset:对应一个重设按钮。 — select:对应一个下拉列表框。 — submit:对应一个提交按钮。 — textarea:对应一个多行文本域。 — textfield:对应一个单行文本框。 关于这些界面相关的标签,同样将在第10章详细介绍。下面将使用Struts 2的表单相关标签简化用户登录的login.jsp页面,修改的login.jsp页面的代码如下: <%@ page language=\contentType=\charset=GBK\<%@taglib prefix=%uri=\ 登录页面 将该页面与前面的表单页面进行对比,我们发现该页面的代码简洁多了。因为使用了Struts 2的表单标签,定义表单页面也更加迅速。在浏览器中浏览该页面,看到如图2.7所示的界面。 图2.7 使用Struts 2表单标签后的表单页 当然,Struts 2的标签还有许多功能,此处先不详述,本书的第10章将会详细介绍Struts 2标签的用法。 2.7 完成程序国际化 因为一个企业应用经常需要面对多区域的用户,因此,程序国际化是一个企业应用必须实现的功能。Struts 2提供了很好的程序国际化支持。 2.7.1 定义国际化资源文件 Struts 2的程序国际化支持建立在Java程序国际化的基础之上,关于Java程序的国际化笔者将在第9章简要介绍。此处不会详细介绍,但我们要明白一个概念:程序国际化的设计思想是非常简单的,其主要思想是:程序界面中需要输出国际化信息的地方,我们不要在页面中直接输出信息,而是输出一个key值,该key值在不同语言环境下对应不同的字符串。当程序需要显示时,程序将根据不同的语言环境,加载该key对应该语言环境下的字符串——这样就可以完成程序的国际化。 图2.8显示了程序国际化的示意图。 图2.8 程序国际化示意图 从图2.8可以看出,如果需要程序支持更多的语言环境,只需要增加更多语言资源文件即可。 为了给本应用增加程序国际化支持(支持英文和中文),则应该提供两份语言资源文件。下面是本应用所使用的中文语言环境下资源文件的代码。 loginPage=登录页面 errorPage=错误页面 succPage=成功页面

failTip=对不起,您不能登录! succTip=欢迎,${0},您已经登录! viewLink=查看作者李刚已出版的图书 bookPageTitle=作者李刚已出版的图书 bookName=书名: user=用户名 pass=密 码 login=登录

因为该资源文件中包含了非西欧字符,因此必须使用native2ascii命令来处理该文件。将上面文件保存在WEB-INF/classes路径下,文件名为“messageResouce.properties”。保存该文件后,必须使用native2ascii命令来处理该文件,处理该文件的命令格式为:

native2ascii messageResouce.properties messageResouce_zh_CN.properties

上面命令将包含非西欧字符的资源文件处理成标准的ASCII格式,处理完成后生成了一份新文件:messageResouce _zh_CN.properties文件。这个文件的文件名符合资源文件的命名格式,资源文件的文件名命名格式为:

basename_语言代码_国家代码.properties

当请求来自简体中文的语言环境时,系统将自动使用这种资源文件中的内容输出。

注意 对于包含非西欧字符的资源文件,一定要使用native2assii命令来处理该文件,否则将看到一堆乱码。 除此之外,还应该提供如下英文语言环境的资源文件。 loginPage=Login Page errorPage=Error Page succPage=Welcome Page failTip=Sorry,You can't log in!

succTip=welcome,{0},you has logged in! viewLink=View LiGang\\'s Books bookPageTitle=LiGang\\'s Books bookName=BookName: user=User Name pass=User Pass login=Login

将上面资源文件保存在WEB-INF/classes路径下,文件名为“messageResouce_en_ US.properties”。当请求来自美国时,系统自动使用这份资源文件的内容输出。

2.7.2 加载资源文件

Struts 2支持在JSP页面中临时加载资源文件,也支持通过全局属性来加载资源文件。通过全局属性加载资源文件更简单,本应用使用全局属性加载Struts 2国际化资源文件。

加载资源文件可以通过struts.properties文件来定义,本应用的struts.properties文件仅有如下一行代码:

//定义Struts 2的资源文件的baseName是messageResource struts.custom.i18n.resources=messageResource

在struts.properties文件中增加上面的代码定义后,表明该应用使用的资源文件的baseName为“messageResouce”——这与我们前面保存资源文件的baseName是一致的。

Struts 2默认加载WEB-INF/classes下的资源文件,在上一节中,我们就是将资源文件保存在该路径下的。如果将该资源文件保存在WEB-INF/classes的子目录下,例如保存在WEB-INF/classes/lee路径下,则需要修改struts.properties中的定义如下:

//定义Struts 2的资源文件的baseName是messageResource,且文件放在WEB-INF/

classes/lee路径下

struts.custom.i18n.resources=lee.messageResource

2.7.3 输出国际化信息

为了让程序可以显示国际化信息,则需要在JSP页面中输出key,而不是直接输出字符串常量。

Struts 2提供了如下两种方式来输出国际化信息:

因此,我们再次修改表现层的JSP页面,使用国际化标签输出国际化信息。修改后的showBook.jsp页面代码如下:

<%@ page language=\contentType=\charset=GBK\<%@taglib prefix=%uri=\

<s:text name=\</head> <body> </p><p> </p><p><caption><s:text name=\<s:iterator value=\status=\<s:if test=\== true\ <s:else> </p><p></s:else> </p><p><s:text name=\<s:property/> </p><p></s:iterator> </body> </html> </p><p>我们发现,上面的JSP页面不再包含任何直接字符串,而是全部通过<s:text name=\来输出国际化提示。 </p><p>再次在浏览器浏览该页面,将看到与图2.7相同的界面。 </p><p>重新设置浏览者所在的语言/区域选项,设置语言/区域选项请先进入“控制面板”,在控制面板中单击“区域和语言选项”,进入如图2.9所示的对话框。 </p><p>如果我们选择“英语(美国)”选项,然后单击“确定”按钮,将设置本地的语言环境为美国英语。 </p><p>再次向服务器请求login.jsp页面,将看到如图2.10所示的页面。 </p><p> 图2.9 设置语言/区域选项 图2.10 程序国际化的效果 如果我们使用FireFox浏览器来浏览该页面时,发现依然显示中文界面——这是因为FireFox的语言环境并不受Windows系统的控制。为了让FireFox也使用美国英语环境,单击FireFox浏览器菜单栏中的“工具”菜单,选择“选项”菜单项,将出现“选项”对话框,单击“高级”按钮,将看到如图2.11所示的界面。 在如图2.11所示的对话框中单击“选择”按钮,将出现“语言和字符编码”对话框,在该对话框下面的下拉列表框中选择“英语/美国 [en-us]”选项,如图2.12所示,然后单击下拉框右边的“添加”按钮,将添加了“英语/美国”的语言环境。并在该对话框上面的列表框中选择“英语/美国 [en-us]”,然后单击“上移”按钮,将该选项移至最上面,让整个页面优先使用英语/美国的环境。 图2.11 设置FireFox的语言环境 图2.12 设置FireFox的语言环境为英语/美国 再次使用FireFox浏览器浏览login.jsp页面,将看到该页面变成了英文界面。 2.8 增加数据校验 </p><p>在上面应用中,即使浏览者输入任何用户名、密码,系统也会处理用户请求。在我们整个HelloWorld应用中,这种空用户名、空密码的情况不会引起太大的问题。但如果数据需要保存到数据库,或者需要根据用户输入的用户名、密码查询数据,这些空输入可能引起异常。 </p><p>为了避免用户的输入引起底层异常,通常我们会在进行业务逻辑操作之前,先执行基本的数据校验。 </p><p>2.8.1 继承ActionSupport </p><p>ActionSupport类是一个工具类,它已经实现了Action接口。除此之外,它还实现了Validateable接口,提供了数据校验功能。通过继承该ActionSupport类,可以简化Struts 2的Action开发。 </p><p>在Validatable接口中定义了一个validate()方法,重写该方法,如果校验表单输入域出现错误,则将错误添加到ActionSupport类的fieldErrors域中,然后通过OGNL表达式负责输出。 </p><p>为了让Struts 2增加输入数据校验的功能,改写程序中的LoginAction,增加重写validate方法。修改后的LoginAction类代码如下: </p><p>//Struts 2的Action类就是一个普通的Java类 public class LoginAction { </p><p>//下面是Action内用于封装用户请求参数的两个属性 private String username; private String password; </p><p>//username属性对应的getter方法 public String getUsername() { </p><p>return username; } </p><p>//username属性对应的setter方法 public void setUsername(String username) { </p><p></p><p>this.username = username; } </p><p>//password属性对应的getter方法 public String getPassword() { </p><p>return password; } </p><p>//password属性对应的setter方法 public void setPassword(String password) { </p><p>this.password = password; } </p><p>//处理用户请求的execute方法 </p><p>public String execute() throws Exception { </p><p>//当用户请求参数的username等于scott,密码请求参数为tiger时,返回success 字符串 </p><p>//否则返回error的字符串 if (getUsername().equals(\&& getPassword().equals(\) { </p><p>return \} else { </p><p>return \} } </p><p>//完成输入校验需要重写的validate方法 public void validate() { </p><p>//如果用户名为空,或者用户名为空字符串 </p><p>if (getUsername() == null || getUsername().trim().equals(\{ </p><p>//添加表单校验错误 </p><p>addFieldError(\\} </p><p>//当密码为空,或者密码为空字符串时,添加表单校验错误 if (getPassword() == null || getPassword().trim().equals(\{ addFieldError(\\} } } 上面的Action类重写了validate方法,该方法会在执行系统的execute方法之前执行,如果执行该方法之后,Action类的fieldErrors中已经包含了数据校验错误,请求将被转发到input逻辑视图处。 为了在校验失败后,系统能将视图转入input处,必须在配置该Action时配置input属性。下面是修改后login Action的配置片段: <result name=\ <result name=\success \ <result name=\ </action> 对比上面的Action配置与前面的Action配置,我们发现该Action配置片段中增加了input逻辑视图的配置,该逻辑视图映射到login.jsp页面。 前面已经提到:当用户提交请求时,请求得到execute方法处理之前,先会被validate方法处理,如果该方法处理结束后,Action的fieldErrors里的校验错误不为空,请求将被转发给input逻辑视图。如果我们不输入用户名、密码而直接提交表单,将看到如图2.13所示的界面。 图2.13 输入校验的界面 看到这里也许读者觉得非常神奇:我们仅仅在Action添加了数据校验错误,并未在输入页面输出这些校验错误信息,但图2.13所示的页面,却可以看到页面已经输出了这些校验信息——这是因为Struts 2的标签,上面的JSP页面中表单使用的并不是HTML表单,而是用了<s:form .../>标签,Struts 2的<s:form ... />标签已经具备了输出校验错误的能力。 </p><p>提示 Struts 2的<s:form .../>默认已经提供了输出校验错误的能力。 但上面的程序还存在一个问题:校验信息的国际化。查看上面的Action类代码发现:重写validate方法时,如果发生校验失败的问题,校验错误的提示信息是以硬编码方式写死了——这就失去了国际化的能力。 </p><p>实际上,ActionSupport类已经提供了国际化信息的能力,它提供了一个getText(String key)方法,该方法用于从资源文件中获取国际化信息。为了让校验信息支持国际化,再次改写Action里的validate方法,改写后的validate方法代码如下: </p><p>//执行数据校验的validate方法 public void validate() { </p><p>//如果用户名为空,或者为空字符串 </p><p>if (getUsername() == null || getUsername().trim().equals(\{ </p><p>//添加校验错误提示,使用getText方法来使提示信息国际化 addFieldError(\getText(\} </p><p>if (getPassword() == null || getPassword().trim().equals(\{ </p><p>addFieldError(\getText(\} } </p><p>在上面的validate方法中,添加校验错误提示时,并不是直接给出了错误提示的字符串,而是调用了getText方法来获取错误提示。因为在Action中,</p><p>使用getText方法来获取了两个国际化提示:user.required和pass.required,因此应该在国际化资源文件中添加这两条提示信息。 </p><p>提示 ActionSupport增加了让提示信息国际化的能力,ActionSupport提供的getText方法可以根据资源文件加载获得国际化提示信息。 此时,如果没有任何输出,直接提交登录表单,将看到如图2.14所示的界面。 图2.14 国际化数据校验的错误提示 2.8.2 使用Struts 2的校验框架 上面的输入校验是通过重写ActionSupport类的validate方法实现的,这种方法虽然不错,但需要大量重写的validate方法——毕竟,重复书写相同的代码不是一件吸引人的事情。 类似于Struts 1,Struts 2也允许通过定义配置文件来完成数据校验。Struts 2的校验框架实际上是基于XWork的validator框架。 下面还是使用原来的Action类(即不重写validate方法),却增加一个校验配置文件,校验配置文件通过使用Struts 2已有的校验器,完成对表单域的校验。Struts 2提供了大量的数据校验器,包括表单域校验器和非表单域校验器两种。 本应用主要使用了requiredstring校验器,该校验器是一个必填校验器——指定某个表单域必须输入。 下面是校验规则的定义文件: <?xml version=\encoding=\ </p><p><!DOCTYPE validators PUBLIC \Group//XWork Validator 1.0.2//EN\ </p><p>\ <validators> </p><p> <field name=\ </p><p><field-validator type=\</p><p> <message key=\</field-validator> </field> </p><p> <field name=\</p><p><field-validator type=\</p><p> <message key=\</field-validator> </field> </validators> </p><p>定义完该校验规则文件后,该文件的命名应该遵守如下规则: </p><p>ActionName-validation.xml:其中ActionName就是需要校验的Action的类名。 </p><p>因此上面的校验规则文件应该命名为“LoginAction-validation.xml”,且该文件应该与Action类的class文件位于同一个路径下。因此,将上面的校验规则文件放在WEB-INF/classes/lee路径下即可。 </p><p>当然,在struts.xml文件的Action定义中,一样需要定义input的逻辑视图名,将input逻辑视图映射到login.jsp页面。 </p><p>如果不输入用户名、密码而提交表单,将再次看到如图2.14所示的界面。在这种校验方式下,无需书写校验代码,只需要通过配置文件指定校验规则即可,因此提供了更好的可维护性。 </p><p>2.9 本章小结 </p><p>本章以一个HelloWorld应用为例,简要介绍了Struts 2 MVC框架的基本流程,从Action类基本流程控制讲起,详细介绍了如何开发一个Struts 2应用。本章的后面部分在基本Struts 2应用基础上,介绍了一些Struts 2的深入应用,包括在Action中访问HttpSession状态,将Action处理结果传回JSP页面显示,本应用也综合应用了Struts 2的标签库、数据校验、程序国际化等常用功能。通过阅读本章的内容,读者应该对Struts 2框架有一个大致的掌握。 </p><p> </p><p></p><p>2.9 本章小结 </p><p>本章以一个HelloWorld应用为例,简要介绍了Struts 2 MVC框架的基本流程,从Action类基本流程控制讲起,详细介绍了如何开发一个Struts 2应用。本章的后面部分在基本Struts 2应用基础上,介绍了一些Struts 2的深入应用,包括在Action中访问HttpSession状态,将Action处理结果传回JSP页面显示,本应用也综合应用了Struts 2的标签库、数据校验、程序国际化等常用功能。通过阅读本章的内容,读者应该对Struts 2框架有一个大致的掌握。 </p><p> </p><p></p> <p>本文来源:<a href="https://www.bwwdw.com/article/pzr6.html">https://www.bwwdw.com/article/pzr6.html</a></p><span class="doc-download-e"></span> </div> <script type="text/javascript">s("download_bottom");</script> <div class="related_article"> <div class="related_top"><code>相关文章:</code></div> <ul><li><a href="https://www.bwwdw.com/article/pzr6.html" target="_blank" title="Struts 2下的helloword">Struts 2下的helloword</a></li><li><a href="https://www.bwwdw.com/article/tdd6.html" target="_blank" title="struts2">struts2</a></li><li><a href="https://www.bwwdw.com/article/9q16.html" target="_blank" title="struts2">struts2</a></li><li><a href="https://www.bwwdw.com/article/41ht.html" target="_blank" title="Struts2试题">Struts2试题</a></li><li><a href="https://www.bwwdw.com/article/uihj.html" target="_blank" title="Struts 2讲义 (5)">Struts 2讲义 (5)</a></li><li><a href="https://www.bwwdw.com/article/fesm.html" target="_blank" title="struts2的常用注解功能">struts2的常用注解功能</a></li><li><a href="https://www.bwwdw.com/article/wh1r.html" target="_blank" title="Struts2 标签介绍">Struts2 标签介绍</a></li><li><a href="https://www.bwwdw.com/article/uldx.html" target="_blank" title="struts2Ajax标签">struts2Ajax标签</a></li><li><a href="https://www.bwwdw.com/article/d5m3.html" target="_blank" title="struts2学习笔记">struts2学习笔记</a></li><li><a href="https://www.bwwdw.com/article/3wvf.html" target="_blank" title="SCME - STRUTS2试卷">SCME - STRUTS2试卷</a></li></ul> </div> <div class="in_reading"><p class="rel_art_line">正在阅读:</p><p><a target="_blank" href="https://www.bwwdw.com/article/pzr6.html" title="Struts 2下的helloword">Struts 2下的helloword</a><span>06-11</span></p><p><a target="_blank" href="https://www.bwwdw.com/article/dtcv.html" title="冀教版五年级上册英语全册教案">冀教版五年级上册英语全册教案</a><span>11-09</span></p><p><a target="_blank" href="https://www.bwwdw.com/article/t0a.html" title="项目劳务用工分包合同">项目劳务用工分包合同</a><span>03-08</span></p><p><a target="_blank" href="https://www.bwwdw.com/article/9sfm.html" title="大学生党课心得体会学习体会">大学生党课心得体会学习体会</a><span>07-29</span></p><p><a target="_blank" href="https://www.bwwdw.com/article/la05.html" title="投影仪连接笔记无法显示怎么办">投影仪连接笔记无法显示怎么办</a><span>12-11</span></p><p><a target="_blank" href="https://www.bwwdw.com/article/4p7q.html" title="数电课后答案解析康华光第五版(完整)">数电课后答案解析康华光第五版(完整)</a><span>04-28</span></p><p><a target="_blank" href="https://www.bwwdw.com/article/o5wn.html" title="物流公司客服2022年度个人工作总结范文">物流公司客服2022年度个人工作总结范文</a><span>03-24</span></p><p><a target="_blank" href="https://www.bwwdw.com/article/vf44.html" title="波峰焊温度曲线测量方法及参数控制标准">波峰焊温度曲线测量方法及参数控制标准</a><span>05-20</span></p><p><a target="_blank" href="https://www.bwwdw.com/article/vzp2.html" title="福建省晋江市2017年初中学业质量检查地理试题">福建省晋江市2017年初中学业质量检查地理试题</a><span>11-06</span></p><p><a target="_blank" href="https://www.bwwdw.com/article/goz.html" title="2012年优秀个人简历模板集合(经典)">2012年优秀个人简历模板集合(经典)</a><span>07-02</span></p></div> <div class="previous"> <span class="pre">上一篇:<a title="班级操行量化评分细则1" href="https://www.bwwdw.com/article/gzr6.html">班级操行量化评分细则1</a></span> <span class="next">下一篇:<a title="好后勤管理工作的几点思考" href="https://www.bwwdw.com/article/rzr6.html">好后勤管理工作的几点思考</a></span> </div> </div> </div> <div class="right-side"> <div class="right_fix"> <script type="text/javascript">s("right_top");</script> <div class="hotSearch"><div class="hotSearch_tl"><span></span>相关文章</div><ul><li><span>1</span><a href="https://www.bwwdw.com/article/6eew.html" title="Struts2文档" target="_blank">Struts2文档</a></li><li><span>2</span><a href="https://www.bwwdw.com/article/ilzp.html" title="Struts2文档" target="_blank">Struts2文档</a></li><li><span>3</span><a href="https://www.bwwdw.com/article/gwo1.html" title="Struts2官方帮助整理" target="_blank">Struts2官方帮助整理</a></li><li><span>4</span><a href="https://www.bwwdw.com/article/jh2w.html" title="Struts2 Validate验证详解" target="_blank">Struts2 Validate验证详解</a></li><li><span>5</span><a href="https://www.bwwdw.com/article/ukxo.html" title="struts2笔记(入门)" target="_blank">struts2笔记(入门)</a></li><li><span>6</span><a href="https://www.bwwdw.com/article/56l2.html" title="实验项目-struts2入门范例" target="_blank">实验项目-struts2入门范例</a></li><li><span>7</span><a href="https://www.bwwdw.com/article/ywg4.html" title="Tutorial_Create Struts 2 Application in Eclipse" target="_blank">Tutorial_Create Struts 2 Application in Eclipse</a></li><li><span>8</span><a href="https://www.bwwdw.com/article/drr7.html" title="Struts2考试题分析" target="_blank">Struts2考试题分析</a></li><li><span>9</span><a href="https://www.bwwdw.com/article/cefg.html" title="Struts2考试题分析" target="_blank">Struts2考试题分析</a></li><li><span>10</span><a href="https://www.bwwdw.com/article/1pl7.html" title="Struts新手详解 - Struts实现流程" target="_blank">Struts新手详解 - Struts实现流程</a></li></ul></div> <script type="text/javascript">s("right_mid");</script> <div class="right_list"><div class="right_list_t"><i></i><span>最新文章</span></div><ul><li><a href="https://www.bwwdw.com/article/inb.html" target="_blank" title="多层物业服务方案">多层物业服务方案</a></li><li><a href="https://www.bwwdw.com/article/hnb.html" target="_blank" title="(审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)">(审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)</a></li><li><a href="https://www.bwwdw.com/article/mnb.html" target="_blank" title="人教版新课标六年级下册语文全册教案">人教版新课标六年级下册语文全册教案</a></li><li><a href="https://www.bwwdw.com/article/jnb.html" target="_blank" title="词语打卡">词语打卡</a></li><li><a href="https://www.bwwdw.com/article/4nb.html" target="_blank" title="photoshop实习报告">photoshop实习报告</a></li><li><a href="https://www.bwwdw.com/article/1nb.html" target="_blank" title="钢结构设计原理综合测试2">钢结构设计原理综合测试2</a></li><li><a href="https://www.bwwdw.com/article/qnb.html" target="_blank" title="2014年期末练习题">2014年期末练习题</a></li><li><a href="https://www.bwwdw.com/article/enb.html" target="_blank" title="高中数学中的逆向思维解题方法探讨">高中数学中的逆向思维解题方法探讨</a></li><li><a href="https://www.bwwdw.com/article/nnb.html" target="_blank" title="名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版">名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版</a></li><li><a href="https://www.bwwdw.com/article/lnb.html" target="_blank" title="北航《建筑结构检测鉴定与加固》在线作业三">北航《建筑结构检测鉴定与加固》在线作业三</a></li><li><a href="https://www.bwwdw.com/article/snb.html" target="_blank" title="XX县卫生监督所工程建设项目可行性研究报告">XX县卫生监督所工程建设项目可行性研究报告</a></li><li><a href="https://www.bwwdw.com/article/knb.html" target="_blank" title="小学四年级观察作文经典评语">小学四年级观察作文经典评语</a></li><li><a href="https://www.bwwdw.com/article/znb.html" target="_blank" title="浅谈110KV变电站电气一次设计-程泉焱(1)">浅谈110KV变电站电气一次设计-程泉焱(1)</a></li><li><a href="https://www.bwwdw.com/article/0nb.html" target="_blank" title="安全员考试题库">安全员考试题库</a></li><li><a href="https://www.bwwdw.com/article/cnb.html" target="_blank" title="国家电网公司变电运维管理规定(试行)">国家电网公司变电运维管理规定(试行)</a></li><li><a href="https://www.bwwdw.com/article/9nb.html" target="_blank" title="义务教育课程标准稿征求意见提纲">义务教育课程标准稿征求意见提纲</a></li><li><a href="https://www.bwwdw.com/article/ukb.html" target="_blank" title="教学秘书面试技巧">教学秘书面试技巧</a></li><li><a href="https://www.bwwdw.com/article/ynb.html" target="_blank" title="钢结构工程施工组织设计">钢结构工程施工组织设计</a></li><li><a href="https://www.bwwdw.com/article/6kb.html" target="_blank" title="水利工程概论论文">水利工程概论论文</a></li><li><a href="https://www.bwwdw.com/article/3kb.html" target="_blank" title="09届九年级数学第四次模拟试卷">09届九年级数学第四次模拟试卷</a></li><li><a href="https://www.bwwdw.com/helloword/" target="_blank" title="helloword">helloword</a></li><li><a href="https://www.bwwdw.com/Struts/" target="_blank" title="Struts">Struts</a></li></ul></div> <script type="text/javascript">s("right_bottom");</script> <div class="right_list"><div class="right_list_t"><i></i><span>推荐文章</span></div><ul><li><a href="https://www.bwwdw.com/article/8zr6.html" target="_blank" title="应用光学复习资料">应用光学复习资料</a></li><li><a href="https://www.bwwdw.com/article/azr6.html" target="_blank" title="山东大学工程化学习题解答">山东大学工程化学习题解答</a></li><li><a href="https://www.bwwdw.com/article/bzr6.html" target="_blank" title="单片机原理及应用答案(张毅刚)">单片机原理及应用答案(张毅刚)</a></li><li><a href="https://www.bwwdw.com/article/wzr6.html" target="_blank" title="2013年部分二本录取院校第一志愿投档线">2013年部分二本录取院校第一志愿投档线</a></li><li><a href="https://www.bwwdw.com/article/ozr6.html" target="_blank" title="第八章 发电机氢水油系统">第八章 发电机氢水油系统</a></li><li><a href="https://www.bwwdw.com/article/xzr6.html" target="_blank" title="关于增强法律专科学生学习实效性的研究.doc">关于增强法律专科学生学习实效性的研究.doc</a></li><li><a href="https://www.bwwdw.com/article/5zr6.html" target="_blank" title="2016-2022年中国电池行业市场分析及发展战略研究报告 - 图文">2016-2022年中国电池行业市场分析及发展战略研究报告 - 图文</a></li><li><a href="https://www.bwwdw.com/article/tzr6.html" target="_blank" title="振动测试平台">振动测试平台</a></li><li><a href="https://www.bwwdw.com/article/vzr6.html" target="_blank" title="第2章 动力学基本定律">第2章 动力学基本定律</a></li><li><a href="https://www.bwwdw.com/article/2zr6.html" target="_blank" title="沪科版2018中考物理模拟试题一">沪科版2018中考物理模拟试题一</a></li><li><a href="https://www.bwwdw.com/article/7zr6.html" target="_blank" title="中考语文课外文言文阅读专项练习试题">中考语文课外文言文阅读专项练习试题</a></li><li><a href="https://www.bwwdw.com/article/6zr6.html" target="_blank" title="会计实习报告">会计实习报告</a></li><li><a href="https://www.bwwdw.com/article/3zr6.html" target="_blank" title="中原经济区“十八谈”(可直接打印、免费下载)">中原经济区“十八谈”(可直接打印、免费下载)</a></li><li><a href="https://www.bwwdw.com/article/uzr6.html" target="_blank" title="博罗县推进三旧改造工作实施方案的通知">博罗县推进三旧改造工作实施方案的通知</a></li><li><a href="https://www.bwwdw.com/article/y0r6.html" target="_blank" title="2016.1 海淀期末高三生物试题及答案">2016.1 海淀期末高三生物试题及答案</a></li><li><a href="https://www.bwwdw.com/article/c0r6.html" target="_blank" title="煤矿通风工作总结范文">煤矿通风工作总结范文</a></li><li><a href="https://www.bwwdw.com/article/90r6.html" target="_blank" title="物理中考总复习1">物理中考总复习1</a></li><li><a href="https://www.bwwdw.com/article/z0r6.html" target="_blank" title="2010年全国计算机等级考试二级3">2010年全国计算机等级考试二级3</a></li><li><a href="https://www.bwwdw.com/article/00r6.html" target="_blank" title="(已改)因式分解难题经典题">(已改)因式分解难题经典题</a></li><li><a href="https://www.bwwdw.com/article/s0r6.html" target="_blank" title="广东省深圳高级中学2011届高三上学期期中考试(语文)word版">广东省深圳高级中学2011届高三上学期期中考试(语文)word版</a></li></ul></div> </div> </div> </div> <div class="footer"> <p>Copyright©<script>timestamp2date(1);</script><a href="https://www.bwwdw.com/" target="_blank" title="博文网">博文网</a>bwwdw.com 版权所有</p> <p class="gray"><a href="https://www.bwwdw.com/article/" target="_blank">最新更新</a> | <a href="https://www.bwwdw.com/hot/" target="_blank">热点专题</a> | <a href="https://www.bwwdw.com/sitemap.html" target="_blank">网站地图</a> | <a href="https://www.bwwdw.com/tag/" target="_blank">TAG专题</a> | <a href="https://www.bwwdw.com/sitemap.xml" target="_blank">XML地图</a> | <a href="https://so.bwwdw.com" target="_blank">范文搜索</a><script type="text/javascript">tj();</script></p> </div> <a href="#0" class="cd-top">Top</a> <script src="/static/fanwen/js/jquery-1.9.1.min.js"></script> <script type="text/javascript"> document.write('<script type="text/javascript" src="/static/fanwen/js/pubuliu.js?'+RAND_STR+'"><\/script>'); document.write('<script type="text/javascript" src="/static/fanwen/js/lazyimg.js?'+RAND_STR+'"><\/script>'); document.write('<script type="text/javascript" src="/static/fanwen/js/gotop.js?'+RAND_STR+'"><\/script>'); </script> <script type="text/javascript"> $.ajax({ "url":"https://www.bwwdw.com/open/doc/readViews.json?id=pzr6", "type":"get", "data":"", "dataType":"json", "success":function(res){ $("#read_views").html(res.data); } }); </script> <script type="text/javascript">bottomAction();</script> </body> </html>