struts总结

struts总结

 

1.为什么学习Struts框架

a.Struts框架好处

struts2是主流的开发技术,大多数公司在使用,struts把相关的servlet组件的各种操作都进行了相应的封装,这样就可以轻松地完成复杂的操作。Struts2是基于MVC模式开发的,MVC结构是一个优秀的设计思想,可以提高程序结构的灵活性,便于日后的维护和扩展。

–简化开发工作量,提高开发效率

–采用了优秀的设计思想(MVC)

b.Struts框架作用

struts充当控制器,接收请求,分发处理,

c.如何学习Struts框架

先重点掌握框架使用,原理性有余力可以多了解些。

 

注:我们目前使用的Struts版本为struts2 2.1.8。(2.1.6版本bug较多)

d.学校struts要掌握的重点:

valuestack

action

result

拦截器

标记库

2.MVC模式在JavaWeb中的应用

*a.什么是MVC

是一种软件架构的思想,将一个软件的组成部分划分成三种不同类型的 模块,分别是:

模型(用于封装业务逻辑,包括业务数据和业务处理逻辑,由JavaBean组件   (比如实体类,DAO,Service)实现),

视图(负责显示界面与用户交互,处理表示逻辑,一种是展示数据,另一种      是接受数据,由jsp组件实现),

控制器(用于控制流程,协调模型与视图,由Servlet、Filter组件(比如之 前的ActionServlet)实现)。

使用mvc的最主要的原因是为了实现模型的复用:即模型只需要开发 一次, 模型不关心处理的结果如何展现,模型将结果交给不同的视 图,由视图来展 现这些数据;另外,可以利用不同的视图来访问 同一个模型。

 

MVC:基于面向对象的一种常见的体系架构

Model:

封装数据以及对数据操作的方法(相当于饭店中做菜的材料(数据)和做菜的厨师(方法)

一个流程用一个方法

View:

封装的是用户界面,接收用户请求,负责输入和输出(和用户打交道)(相当于服务员)

Controller:

封装的是业务流程,控制业务流程(相当于饭店中的管理者)(如果程序比较简单,可以把Controller写在Model里面)

 

b.为什么使用MVC

企业程序更强调结构灵活,易于扩展和升级。所以广泛选用MVC模式开发。

*c.JavaWeb中如何实现MVC结构

JavaWeb技术主要有:Servlet,JSP,JavaBean,Filter,Listener等

V部分:JSP组件 (cart.jsp)

M部分:JavaBean组件(entity,dao)

C部分:Servlet,Filter组件 (ShoppingCartServlet)

*d.MVC处理流程

–首先浏览器发出请求

–请求进入C控制器

–C控制器调用M模型组件处理

–M模型组件处理后返回处理结果

— C控制器调用V视图组件生成响应信息

 

*e.Struts框架的MVC实现

原有ShoppingCart程序,虽然符合MVC结构,但不适合大型项目开发,因为请求一多,ShoppingCartServlet会出现大量的if..else… ,可以进行以下方式的改造:

为ShoppingCartServlet配置一个XML文件,该文件定义不同请求和不同Action组件的对应关系,将原有if..else..分支处理用Action组件封装。

**f.Struts框架的处理流程

–浏览器发出struts请求

–请求进入struts控制器

–struts控制器解析xml配置文件(xml定义了请求和Action对应关系)

–控制器根据不同请求,调用不同的Action

–Action调用DAO处理请求,之后返回结果

–控制器根据结果调用视图组件为用户响应

struts总结

 

3.了解Struts历史

Struts框架分成Struts1和Struts2.Struts2和Struts1没有必然联系。Struts2是以WebWork框架核心(xwork)为基础构建起来

最早出现的Struts1是一个非常著名的框架,它实现了MVC模式。Struts1简单小巧,其中最成熟的版本是Struts1.2。之后出现了WebWork框架,其实现技术比Struts1先进,但影响力不如Struts1。在框架技术不断发展过程中,有人在WebWork核心XWork的基础上包装了Struts1(算是两种框架的整合),由此,结合了Struts1的影响力和WebWork的先进技术,Struts 2诞生了。所以说,Struts2不是Struts1的升级,它更像是WebWork的升级版本。

*4.Struts基本使用

a.引入struts2核心开发包(5个)

(1).struts2-core-2.1.8.1.jar

Struts2核心包,是Struts框架的“外衣。

(2).xwork-core-2.1.6.jar

Struts2核心包,是WebWork内核。

(3).ognl-2.7.3.jar

用来支持ognl表达式的,类似于EL表达式,功能比EL表达式强大的

多。

(4).freemarker-2.3.15.jar

freemarker是比jsp更简单好用,功能更加强大的表现层技术,用来 替代jsp的。在Struts2中提倡使用freemarker模板,但实际项目中使 用jsp也很多。

(5).commons-fileupload-1.2.1.jar

用于实现文件上传功能的jar包。

b.在web.xml中配置下struts控制器

c.根据请求编写Action,JSP

d.在struts.xml定义Action和请求对应关系

5.HelloWord入门实例

welcome.action–>Struts控制器–>struts.xml–>WelcomeAction

–>welcome.jsp

(Action请求可以是/welcome.action或者/welcome两种写法)

7、struts.xml基本配置

struts.xml放在src根目录下。

a) <struts>

根元素,可以包含多个<package>元素

b)<package>

<package name=”***” namespace=”/默认” extends=”struts-default”>

元素主要用于将Action分组定义。name属性用于指定包名;extends一般指 定为struts-default。struts-default这个包在struts-default.xml中定义,其中 包含了struts2运行所需的必要组件。

添加namespace属性的主要作用是避免在大项目中出现的命名冲突问题。

注意:

http://localhost:8080/struts01/netctoss/welcome

<package name=”demo1″ namespace=”/netctosss”

extends=”struts-default”>

<action name=”welcome” class=”action.WelcomeAction”>

<result name=”success”>/WEB-INF/jsp/Welcome.jsp</result>

</action>

namespace属性默认为“/”(即从应用名后的第一个”/”开始到最后一个“/”结束)。

eg:对于http://localhost:8080/struts01/netctoss/cost/showList.action

其中的namespace属性值应为”/netctoss/cost”。

eg:

如果不加namespace=”/netctoss”那么

http://localhost:8080/struts01/netctoss/list.action便不会得到正确的匹配

一个<package>元素可以包含多个<action>..</action>主要用于定义请求

和Action组件的对应关系。name属性指定请求名;class属性指定Action的包

名.类名

c)<action>

<action name=”***” method=”execute默认” class=”***”>

一个<action>元素可以包含多个<result>…<result>主要用于定义视图响 应。name属性与Action.execute()返回值一致。

其中

(1).method属性可以省略,如果省略则默认调用Action中的execute()方法

(2.)如果不指定class属性,Struts会默认调用框架底层的ActionSupport

类处理(见下面:)。框架会默认为该<action>添加一个class,作用是

转发到对应

的<result  name=”success”>中指定的页面。当有nameform请求发

来时,struts不会调 用action(找不到)而是直接调用result中name属

性为success对应的页面。

注:name=”success”可以省略

<action name=”nameform”>

<!–<result name=”success”>/WEB-INF/jsp/Welcome.jsp</result>–>

<result>/WEB-INF/jsp/Welcome.jsp</result>

</action>

struts总结

——–ActionSupport类:———

public String execute(){

return “success”;

}

d)<result>

<result name=”success默认” type=”dispatcher默认”>

e:注意:

1.对于package、action、result,如果使用默认属性值,则可以省略属性名。

eg:<result name=”sucess” type=”dispatcher”>****</sesult>

如果使用默认属性值:则可以写成:

<result >****</sesult>

 

对于重复使用的result可以写成全局的result

<!– 定义全局result –>

<global-results>

<!– 错误处理 –>

<result name=”error”>/WEB-INF/jsp/error.html</result>

<!– 拦截器登录处理 –>

<result name=”login” type=”redirectAction”>showLogin</result>

</global-results>

 

2.page包中的各组件的放置顺序:

具体见struts-2.1.7dtd

package (result-types——> interceptors——>default-interceptor-ref——>

default-action-ref——> default-class-ref——> global-results——>

global-exception-mappings——> action*)>

拦截器配置放在global-results之前

 

3.当项目业务处理较多时如果将所有的配置都写在struts.xml一个文件中将很不方便,所以可以将不同的处理模块分别写在不同的xml文件中,最后在struts.xml中加载和模块配置文件,过程如下:

struts.xml:

<struts>

<!– 加载各模块配置文件 –>

<include file=”struts-cost.xml”/>

<include file=”struts-account.xml”/>

………..

<package name=”netctoss-default” extends=”json-default”>

<!– 追加共通的Action,Interceptor组件 –>

拦截器、全局results….

</package>

</struts>

struts-cost.xml:

<!– 资费模块配置文件 –>

<struts>

<package name=”cost” extends=”netctoss-default”>

……..

</package>

</struts>

struts-account.xml:

<!– 资费模块配置文件 –>

<struts>

<package name=”account” extends=”netctoss-default”>

……..

</package>

</struts>

………………………..

浏览器访问地址:

http://localhost:8080/应用名/namespace/action

http://localhost:8080/struts03_2/list/costList.action?page=4

以上的namespace默认为’’/’,本例为list

8、如何解决用户绕过ActionServlet,直接访问jsp文件的问题。

将所有jsp文件拷贝到WEB-INF目录下。因为WEB-INF目录中的内容不能直接访问,但能转发过来。

当然也可以用之前的session技术(太麻烦)。

对于struts中WebRoot文件夹下的.jsp页面仍可以直接输入地址访问。

9、Struts2提供的方便之处:

a.数据的自动的封装

根据页面组件的name属性,自动封装到Action中对应的name属性中。

在Jsp页面<input name=”name” type=”text”/>

在action中会自动给属性private String name 赋值。但是注意要有name对应的getter和setter方法。

b.数据的自动的传递

Action中的属性在jsp页面可以直接用EL表达式拿到

eg:

Action中属性private String name;

在jsp页面上可以直接${name}的到对应的值

按理说,EL表达式取数据的对象只有pageContext,request,session,application四类,不应该从Action对象中取name属性值,但struts框架重新包装了request,getAttribute()方法被改写(request的其他方法没被改写),如果从request对象中调用getAttribute()方法没获取到值(null),那么会自动从action中取,这样,struts中EL表达式就可以直接获取到Action属性中的值了。

上面介绍的采用了包装模式:(相当于手机加壳案例和线程池案例(其中的close方法特殊)。参考如下:

public class StrutsRequestWrapper extends HttpServletRequestWrapper{

//重写

public Object getAttribute(String key){

//寻找原request信息

Object obj = super.getAttribute(key);

if(obj == null){

//寻找valuestack信息

obj = valuestack.findValue(key);

//Ognl.getValue(key,context,root);

} struts总结

return obj;

}

}

${name} –>request.getAttribute(“name”)

–>Ognl.getValue(“name”,context,root)

 

10.项目示例(资费列表显示)

a.显示默认主页面

index.action–>struts控制器–>index.html

b.资费列表显示

feeList.action–>struts控制器

–>FeeListAction–>FeeDAO–>COST

–>fee_list.jsp

1)编写COST对应的Entity实体类

2)编写DAO,DBUtil

–引入oracle驱动包

3)编写Action

4)配置Action

5)编写JSP

–引入jstl.jar,standard.jar

11.OGNL技术的使用

1)什么是OGNL

OGNL是Object-Graphic Navigation Language(对象图导航语言)的缩写,

是一种功能强大的表达式语言(与EL表达式类似)。OGNL可以让我们用非常

简单的表达式访问对象层(访问对象的数据和方法),它用一个独立的lib形

式出现(封装于ognl.jar工具包中),方便我们使用或者构建自己的框架。

 

OGNL区别于EL表达式,OGNL可以在.java文件中通过getValue()方法访问对

象,而EL表达式不可以在.java文件中使用;EL表达式在.jsp文件中可以直接

输出数据,而OGNL不可以,OGNL在.jsp文件中只能当做struts标签中的属性

值,通过struts标签访问数据。

2)OGNL基本原理

OGNL工具主要由3部分构成,具体如下

a.OGNL引擎

负责解析ONGL表达式,定位数据

b.Root根存储区(Object类型)

负责存储要访问的目标对象(一个)。

c.Context变量存储区(Map类型)

负责存放多个要访问的目标对象。

 

*3)OGNL基本语法

a.访问Root区域对象基本语法

Ognl.getValue(“OGNL表达式”, “Map存储器内容”,”根存储器内容”);

Ognl.getValue(“OGNL表达式”, “根存储器内容”);

–访问简单数据:”属性” 例如”name”

int id = (Integer)Ognl.getValue(“id”, foo);

String name = (String)Ognl.getValue(“name”, foo);

–访问数组或List集合:”属性[0]”

例如”arr[1]”

String arrVal = (String)Ognl.getValue(“arr[1]”, foo);

String  listVal = (String)Ognl.getValue(“list[2]”, foo);

–访问map集合元素:”属性[‘key’]”或”属性.key”

例如”map.c”或”map[‘two’]”

注:”map[‘a’]”不可用(‘a’结果为整数)

String mapVal = (String)Ognl.getValue(“map.b”, foo);

String mapval2 = (String)Ognl.getValue(“map[‘user.name’]”,foo);

–访问方法:”属性值.方法()”,

例如”list.size()”

System.out.println(Ognl.getValue(“map[‘two’].toUpperCase()”, foo));

System.out.println(Ognl.getValue(“list.size()”, foo));

–访问构造方法:”new 包名.构造方法”

例如”new java.util.Date()”

Object obj =

Ognl.getValue(“new org.tarena.entity.Foo(‘TOM’)”, foo);

–访问静态成员:”@包名.类名@成员”

例如”@java.lang.Math@PI”

Ognl.getValue(“@java.lang.Math@abs(-1)”, foo);

Ognl.getValue(“@java.lang.Math@PI”, foo);

–创建List对象:”{元素1,元素2}”

Object obj1 = Ognl.getValue(“{‘struts’,’hibernate’,’spring’}”,foo);

–创建Map对象:

“#{key1:value1,key2:value2}”

Object obj2 = Ognl.getValue(“#{1:’tom’,2:’jack’,3:’rose’}”, foo);

 

public static void main(String[] args) throws Exception {

Foo foo = new Foo();

foo.setId(100);

foo.setName(“张三”);

foo.setArr(new String[] { “A”, “B”, “C” });

foo.setList(Arrays.asList(“芙蓉”, “凤姐”, “春哥”));

Map<String, String> map = new HashMap<String, String>();

map.put(“one”, “Java”);

map.put(“two”, “JavaWeb”);

map.put(“three”, “Struts2”);

map.put(“user.name”, “Scott”);

foo.setMap(map);

//测试OGNL访问foo目标对象

//Ognl.getValue(“OGNL表达式”, “Map存储器内容”,”根存储器内容”);

//Ognl.getValue(expression, root);

Map context = new HashMap();

//访问root基本的属性值

int id = (Integer)Ognl.getValue(“id”, foo);

System.out.println(id);

String name = (String)Ognl.getValue(“name”, foo);

System.out.println(name);

System.out.println(Ognl.getValue(“user.name”, foo));

//访问root数组和集合元素

String arrVal = (String)Ognl.getValue(“arr[1]”, foo);

System.out.println(arrVal);

String  listVal = (String)Ognl.getValue(“list[2]”, foo);

System.out.println(listVal);

//访问root对象的map集合元素

String mapVal = (String)Ognl.getValue(“map.b”, foo);

System.out.println(mapVal);

String mapval2 = (String)Ognl.getValue(“map[‘user.name’]”,foo);

System.out.println(mapval2);

//支持运算符

System.out.println(Ognl.getValue(“id+1”,foo));

//System.out.println((Integer)Ognl.getValue(“id”,foo)+1);

System.out.println(Ognl.getValue(“\”姓名:\”+name”, foo));

System.out.println(Ognl.getValue(“id > 200”,foo));

//方法调用

System.out.println(Ognl.getValue(“map[‘two’].toUpperCase()”, foo));

System.out.println(Ognl.getValue(“list.size()”, foo));

//构造方法的调用

Object obj = Ognl.getValue(“new org.tarena.entity.Foo(‘TOM’)”, foo);

System.out.println(obj);

System.out.println(Ognl.getValue(“name”, obj));

//静态方法和常量的调用

System.out.println(Ognl.getValue(“@java.lang.Math@abs(-1)”, foo));

System.out.println(Ognl.getValue(“@java.lang.Math@PI”, foo));

//创建一个list集合

Object obj1 = Ognl.getValue(“{‘struts’,’hibernate’,’spring’}”,foo);

System.out.println(obj1.getClass().getName());

//创建一个map集合

Object obj2 = Ognl.getValue(“#{1:’tom’,2:’jack’,3:’rose’}”, foo);

System.out.println(obj2.getClass().getName());

}

12、OGNL技术在Struts的使用

在Struts2中有一个ValueStack(本质就是存放数据的集合)数据对象,该对象存储了请求相关的所有数据信息。例如request,session,application,action等.

Struts2采用OGNL工具对ValueStack进行操作。

1)xwork对OGNL进行了部分改造

在xwork中将原来OGNL标准结构中的Root存储区改造成了一个栈结构

(CompoundRoot)以前只能存放一个对象,现在进行了扩容,可以存放

多个对象

当利用”属性”表达式访问时,优先去栈顶对象寻找,没有再去次栈顶寻找。

2)ValueStack结构(OgnlValueStack)

ValueStack就是一个容器(Map集合)(存放东西的不是Tomcat容器)

(参考valuestack.jpg)

3)Struts2标签的使用

在JSP中,利用Struts2标签显示数据,需要为标签指定OGNL表达式,标签利用表达式定位ValueStack中的数据,进行相应操作。

a) debug标签:显示valuestack状态

<s:debug></s:debug>

b) iterator标签:循环集合元素

value属性:指定ognl

var属性:指定循环变量,会被存放到ValueStack的context区域。

status属性:指定循环状态变量,会被存放到ValueStack的context区域.该

变量有count属性表示一共循环了多少个元素。

index属性表示当前循环元素的索引。

<s:iterator value=”new int[totalPages]” status=”i”>

<s:if test=”#i.count==page”>

<a class=”current_page”href=”costList.action?page=${i.count }”>

<s:property value=”#i.count”/>

</a>

</s:if>

<s:else>

<a href=”costList.action?page=${i.count }”>

<s:property value=”#i.count”/>

</a>

</s:else>

</s:iterator>

c) if…else…标签:判断分支

test属性:指定ognl判断表达式

<s:if test=”page < totalPages” >

<a href=”costList?page=${page+1 }”>下一页</a>

</s:if>

<s:else>

下一页

</s:else>

d) property标签:显示数据

value属性:指定ognl表达式

<s:iterator value=”costList” var=”cost”>

<tr><td><s:property value=”#cost.id”/></td></tr>

</s:iterator>

e) date标签:将date数据格式化输出

name属性:指定ognl表达式

format属性:指定日期模板

<td>

<s:date name=”#cost.createTime” format=”yyyy-MM-dd HH:mm:ss”/>

</td>

13、Action组件的相关使用

1)Action组件的原理

–客户发出action请求给struts控制器

–前端控制器截获请求并根据配置信息调用对应的action

–struts控制器会创建valuestack对象

–struts控制器根据请求创建Action对象并将Action压入valuestack的root

栈顶(Action线性安全,不用考虑并发问题,struts会为每一个请求 创

建一个Action对象,区别于Servlet)

–struts控制器调用一系列拦截器做一些辅助性的工作(一般都是

valuestack的操作),如通过parmaeterInterceptor将表单中的数据赋值

给action中的对象;还有将请求相关request,session对象放入到

valuestack的context区域,同时将ValueStack对象存入到request中。

存储的key为”struts.valueStack”。(这样,当一次请求结束后,容器

会销毁request,request销毁了,其中的valuestack对象也就销毁了)

–控制器调用Action,执行业务方法处理(根据输入算输出并返回结果)

–控制器根据Action返回值调用result视图组件处理。

–请求处理完毕,销毁valuestack和Action对象。

一次请求,一个valuestack和action对象

2)Struts中写Action过程:

定输入、定输出、根据输入算输出、返回结果

*3)Action中如何使用session,request

(1).利用ActionContext和ServletActionContext工具类(不推荐)

a.ActionContext返回是Struts框架封装成Map之后的

request,session,application.

eg:

//将用户信息写入Session

ActionContext ac = ActionContext.getContext();

Map<String,Object> session = ac.getSession();

session.put(“user”, adminCode);

Map<String,Object> application = ac.getApplication();

Map<String,Object> request = (Map)ac.get(“request”);

b.ServletActionContext返回的是Servlet中使用的request, session,

application原有类型。

(使用建议:存值取值建议用Map结构API,如果有特殊需求再采用

Servlet原有类型(如获取客户端IP))

eg:

HttpServletRequest request = ServletActionContext.getRequest();

HttpSession session = httpRequest.getSession();

HttpServletResponse response = ServletActionContext.getResponse();

ServletContext application = ServletActionContext.getServletContext()

 

ActionContext工具类中的方法getSession()如何将HttpSession对

象封装成Map对象的说明:

Map—-impements—>AbstructMap—extends–>SessionMap(重

写了Map中的put和get方法)

—-如何将原有HttpSession封装成Map——

public class SessionMap extends AbstractMap{

private HttpSession session;

public SessionMap(HttpSession session){

this.session = session;

}

public void put(Object key,Object val){

session.setAttribute(key,val);

}

public Object get(Object key){

session.getAttribute(key);

}

}

不推荐使用ActionContext访问Session的方式,因为这种方式的“侵入性”较强。ActionContext是Struts2的API, 如果使用其他框架代替目前的Struts2框架,而我们实际项目中的Action的数量非常庞大,每个类都修改的话,会非常麻烦。

(2).利用Aware接口方式注入(推荐)

将Action实现Aware接口,由框架底层将对象注入给Action中相应的变量

当action实例化时候,struts框架就会自动将session对象(在valuestack中)赋值给实现了SessionAware接口的类中的变量(就是注入)。

(即session,ruquest,response,application)

RequestAware 对应的是Map结构的Request

SessionAware 对应的是Map结构的Session

ApplicationAware 对应的是Map结构的Application

ServletRequestAware对应的HttpServletRequest

ServletResponseAware对应的HttpServeltResponse

ServletContextAware对应的ServletContext

eg:

public class LoginAction implements SessionAware{

protected Map<String,Object> session;

……………

public void setSession(Map<String, Object> session) {

this.session = session;

}

public String execute(){

if((“admin”.equals(adminCode)) && (“1234”.equals(passWord))){

session.put(“user”, adminCode);

return “success”;

}else{

return “error”;

}

}

}

(3)、使用工具类(ActionContext、ServletActionContext)还是

Aware接口?

Action组件内部用Aware接口、Action组件之外(比如后面的拦截器)用ActionContext、ServletActionContext

4)Action属性注入

作用:在创建Action对象时指定属性值

在<action>配置中为Action组件的属性指定一个初始值,该值在创建

Action对象时注入。可以将一些变化的参数值,利用该方法指定。例如

pageSize,管理员用户名,dir存储路径等。

在<action>配置中,为Action对象的属性指定初始值。使用格式如下:

<action name=”feeList” class=”org.action.FeeListAction”>

<!–创建Action对象时给属性指定一个值–>

<param name=”属性名”>属性值</param>

<result></result>

</action>

eg:

public class ListAction{

private Stirng param1;

private String param2;

…..

public String getParam1(){

return param1;

}

….. struts总结

public setParam1(Stirng param1){

this.param1 = param1;

}

…….

}

struts.xml:

<action name=”feeList” class=”org.action.FeeListAction”>

<param name=”param1″>admin</param>

<param name=”param2″>1234</param>

<result>……..</result>

</action>

5)Action通配符配置

Action通配符可以将多个具有相同属性的Action整合为一个Action。

在<action>配置时,name请求名可以使用若干个*符号。然后再其他属

性中通过使用{1},{2}引用第一个*号,第二个*号所代表的字符串。

<!– 通配符配置 –>

<action name=”*_*” method=”{2}”class=”com.tarena.action.{1}”>

<result name=”success”>/index.jsp</result>

</action>

 

eg:

CostAction.java:

public class CostAction {

//属性定义–省略

public String add(){

System.out.println(“资费添加操作”);

return “success”;

}

public String update(){

System.out.println(“资费更新操作”);

return “success”;

}

}

struts.xml:

<action name=”cost_*” method=”{1}”

class=”com.tarena.action.CostAction”>

<result name=”success”>/index.jsp</result>

</action>

 

14、Result组件的相关使用

1)Result组件原理

a.Result组件的作用

Result组件负责生成响应视图内容。将ValueStack中的数据做不同形式

的输出。

Struts2框架提供了多种不同的Result组件类型,用于做不同形式响应。

例如json数据响应,流数据响应,jsp响应等。

b.Result组件相关配置

–Result声明定义

<package>

<result-types>

<result-type name=”result类型” class=”Result组件实现类”/>

</result-types>

</package>

–Result使用定义

<action>

<result name=”标示符” type=”result类型”></result>

</action>

c.编写一个转发功能的Result组件

定义的类类必须实现Result接口(Result组件),并且将约定的execute方法实现在该方法中编写了生成响应输出的逻辑代码。

public class MyDispatcherResult implements Result{

private String location;

//setter和getter方法

…………….

//约定方法

public void execute(){

HttpServletRequest request = ServletActionContext.getRequest();

HttpServletResponse response =ServletActionContext.getResponse();

RequestDispatcher rd = request.getRequestDispatcher(location);

rd.forward(request,response);

}

}

*2)掌握经常使用的Result组件

a. JSP视图

–dispatcher(默认):以转发方式调用JSP

–redirect:以重定向方式调用JSP

<result name=”” type=”dispatcher(默认)/redirect”>

jsp页面

</result>

b.Action视图

–chain:以转发方式调用下一个Action

–redirectAction:以重定向方式调用下一个Action

c:

stream:以字节流方式响应,Action中的InputStream类型的属性以

字节流方式输出。

eg:由服务器端生成验证码图片并以流的方式发送给浏览器。

 

在struts.xml端的配置如下:

<!–验证码处理 –>

<action name=”image” class=”org.tarena.netctoss.action.ImageAction”>

<result type=”stream”  name=”success”>

<param name=”inputName”>imageStream</param>

</result>

<result name=”fail”>/WEB-INF/jsp/login.jsp</result>

</action>

注:其中的<param name=”inputName”>imageStream</param>区别于Action

属性注入,其作用为:给result对象指定参数值

d:

json:以json字符串响应,将Action中指定的属性拼成一个json字符串输

出。

注:

其中,a、b、c中的result组件在’struts-defaulg”包下,d中的result组件

在”json-default”,struts-core.jar中的默认包

<package name=”struts-default” abstract=”true”>如下:

 

<package name=”struts-default” abstract=”true”>

<result-types>

<result-type name=”chain” class=”*****”/>

<result-type name=”dispatcher” class=”*****”/>

<result-type name=”freemarker” class=”*****”/>

<result-type name=”httpheader” class=”*****”/>

<result-type name=”redirect” class=”*****”/>

<result-type name=”redirectAction” class=”*****”/>

<result-type name=”stream” class=”class=”*****”/>

<result-type name=”velocity” class=”class=”*****”/>

<result-type name=”xslt” class=”*****”/>

<result-type name=”plainText” class=”*****”/>

</result-types>

</package>

相同命名空间调用:

<result type=”redirectAction”>

请求名

</result>

跨命名空间调用

<result type=”redirectAction”>

<param name=”actionName”>请求名</param>

<param name=”namespace”>/</param>

</result>

======资费删除流程=====

fee_delete.action–>FeeDeleteAction–>FeeDAO

–>FeeListAction–>fee_list.jsp

============练习=============

完成课上项目任务。

扩展任务:完成资费的添加,更新处理,查看,启用等。

 

16、json Result组件

主要负责将Action的属性以json字符串格式输出。

json Result的使用步骤:

a.引入struts2-json-plugin.jar

b.将<package>元素的extends属性改为继承”json-default”(json-default包

的范围比原struts-default包大,所以更改后仍可以使用以前包中的组件)

c.<result>使用配置

//只返回Action中一个属性值

<result type=”json”>

<param name=”root”>属性名</param>

</result>

//返回Action中多个属性值

<result type=”json”>

<param name=”includeProperties”>

属性名1,属性名2,属性名3

</param>

</result>

//返回Action中所有属性值

<result type=”json”>

</result>

 

因为使用name属性默认值,所以name=”success”可以省略。

 

17、Struts2表单标签

1.什么是标签

struts标签封装了界面显示逻辑,用于简化JSP。

jstl标签用来代替jsp页面中的java代码,struts标签不但可以代替jsp页面中的

java代码,还可以代替jsp页面中html标记

2.struts常用标签:

textfield,password,hidden,textarea

radio,checkboxlist,select

checkbox,form

a) textfield

以输入框方式显示属性值.

name属性指定ognl表达式,表示输入框中的值

<input type=”text” class=”readonly” name=”cost.id” value=${cost.id}

readonly />

相当于:

<s:textfield name=”cost.id” cssClass=”readonly” readonly=”true”>

</s:textfield>

注:规定输入字段为只读(内容不可被更改)。在html中input标签readonly属性

直接写,在struts标签中要写成:readonly=”true”。类似的的还有disabled要写成

disabled=”true”

b) textarea

以文本域方式显示属性值.

name属性指定ognl表达式,表示文本域中的值

<textarea class=”width300 height70″>${cost.descr}</textarea>

<s:textarea name=”cost.descr” cssClass=”width300 height70″></s:textarea>

c)password:

以文本框方式显示密码

name属性指定ognl表达式,,表示输入框中的值

注:默认情况下,文本框内不会显示密码,如果要显示密码则需要设置showPassword属性。

密码:<s:password name=”password” showPassword=”true”></s:password>

d) radio:

以一组单选框方式显示,并可以根据属性值决定哪个选项选中。

list属性指定集合ognl,用于生成若干radio选项。

name属性指定ognl,用于决定哪个raido选中。

<s:radio name=”cost.costType” list=”#{‘1′:’包月’,’2′:’套餐’,’3′:’计时’}”>

</s:radio>

e)checkbox:

以单选框方式显示选中状态

name属性指定ognl表达式,name属性值为true时,单选框默认会被选中

eg:

婚姻状况:<s:checkbox name=”marry””></s:checkbox>已婚

f)checkboxlist:

以复选框方式显示选中状态

name属性指定ognl表达式,用来决定哪些复选框默认被选中。

list属性为map<key,value>集合

listKey属性为map集合中的key

listValue属性为map集合中的value,为在界面显示的内容

参考struts05_1中的form.jsp

eg1:

爱好:<s:checkboxlist name=”chk” list=”#session.favors” listKey=”id”

listValue=”name”></s:checkboxlist>

eg2:

<s:checkboxlist name=”” list=”costList’” listKey=”id”

listValue=”name”></s:checkboxlist>

 

g)select:

以下拉列表的方式显示数据:

name属性指定ognl表达式,用来决定哪个option默认被选中。

eg1:

<s:select name=”status” cssClass=”select_search”

list=”#{‘0’:’暂停’,’1′:’开通’,’2′:’暂停’,’3′:’删除’}”>

</s:select>

相当于

<select class=”select_search” >

<option value=”2″>全部</option>

<option value=”1″>开通</option>

<option value=”0″>暂停</option>

<option value=”-1″>删除</option>

</select>

eg2:

<s:select list=”costList” name=”” listKey=”id” listValue=”name”></s:select>

注:对于上面的struts标签中的name属性,不但可以指定ognl表达式获取相关的数据,还可以将action中的属性名设置为name的属性值,这样就可以实现表单数据的自动提交。

h)form:

theme属性:表示主题,可选项有xhtml和simple;如果不写,默认为xhtml 。

theme属性如果为默认值(xhtml),那么在使用struts表单标

签时候会自动添加样式(自动添加tr、tr,让显示更美观),

这样就会破坏当前页面的布局和样式。

如果在用struts表单标签时,没有用struts中的form标签而是

使用html中的form标签,那么在使用struts表单标签时候也

会自动添加样式

<s:form action=”update” namespace=”/” theme=”simple”>

………….

</s:form>

通用属性(所有标记都具备的属性):

label

labelpostion

required

tooltip

tooltipIconPath

cssClass(html中的class)

cssStyle(html中的style)

name

value

 

18、拦截器组件

2)什么是拦截器:

一般利用拦截器封装一些通用性处理功能,便于重复利用。例如请求参

数给action属性赋值、日志记录、权限检查、文件上传、事务处理等。拦截

器通过配置方式调用,因此使用方法比较灵活,便于维护或扩展。

Struts2框架提供了大量的拦截器组件,如果不能满足开发者需要,可以

进行自定义。

eg:

<interceptor name=”params”

class=”com.opensymphony.xwork2.interceptor.ParametersInterceptor”/>

其中ParametersInterceptor类用于在创建Action对象时将表单中的参数

赋值给Action中的相关属性。

具体见:

ReferencedLibraries/struts2-core-2.1.8.jar/struts-default.xml

/<interceptors>标记

 

2)拦截器完整工作流程:

上图中的FilterDispatcher为前端控制器

a.客户发送一个Action请求,请求交给控制器

b.控制器创建一个ValueStack、Action对象,并将Action压入ValueStack栈顶

c.控制器调用ActionInvocation组件执行请求处理

d.ActionInvocation组件调用请求相关的拦截器组件–前部分处理.

e.然后再调用Action组件业务方法

f.然后再调用Result组件处理方法

g.最后执行拦截器组件–后部分处理.

h.将响应信息输出,为客户端响应

3)拦截器作用

拦截器可以在Action和Result组件调用之前执行,也可以在Action和Result

组件之后执行。

4)自定义拦截器

a.编写拦截器组件实现类(两种方法):

1.编写拦截器组件实现类实现Interceptor接口的interceptor方法。

public class MyInterceptor implements Interceptor{

public String intercept (ActionInvocation in){

//拦截器的前期处理逻辑

in.invoke();//执行Action和Result

//in.invokeActionOnly();//仅执行Action

//拦截器的后期处理逻辑

}

}

eg:

public class CheckLoginInterceptor implements Interceptor{

public void destroy() {

// TODO Auto-generated method stub

}

public void init() {

// TODO Auto-generated method stub

}

public String intercept(ActionInvocation in) throws Exception {

System.out.println(“(前期处理)自定义拦截器被调用。。。”);

ActionContext ac = ActionContext.getContext();

//ActionContext ac = in.getInvocationContext();

Map<String,Object> session = ac.getSession();

//登录检查

if(session.get(“user”) == null){

//为登录

return “login”;//进入登录页面

}

in.invoke();//执行Action、DAO和Result—>jsp

System.out.println(“(后期处理)自定义拦截器被调用。。。”);

return null;//invoke()方法执行之后,后面的返回值都无效(即不会返回),因为执行in.invoke(),也即执行Action和Result调用Jsp后,返回的值没有任何意义。

}

}

2.所有拦截器组件实现类也可以通过继承AbstractInterceptor类并实现

inteceptor方法。

eg:

public class Interceptor2 extends AbstractInterceptor {

public String intercept(ActionInvocation in) throws Exception {

System.out.println(“(前期处理)自定义拦截器被调用。。。”);

// ActionContext ac = ActionContext.getContext();

ActionContext ac = in.getInvocationContext();

Map<String, Object> session = ac.getSession();

// 登录检查

if (session.get(“user”) == null) {

// 未登录

return “login”;// 进入登录页面

}

in.invoke();// 执行Action和Result

System.out.println(“(后期处理)自定义拦截器被调用。。。”);

return null;//invoke()方法执行之后,后面的返回值都无效(即不会返回),写着只是好看一点

}

}

注意:当执行了invoke()方法后,invoke()方法后面的返回值无效(即不会返回),写着只是好看一点。如果没有执行invoke(),返回值有效。控制器会根据该返回值调用一个Result生成响应信息

b.注册拦截器(将拦截器注册给struts2框架)

(1).方法一:

<package>

<interceptors>

<interceptor name=”拦截器名”class=”拦截器实现类”/>

<interceptor name=”” class=””/>

</interceptors>

</package>

eg:

<!– 定义拦截器 –>

<interceptors>

<interceptor name=”checklogin”

class=”org.tarena.netctoss.interceptor.CheckLoginInterceptor2″/>

</interceptors>

<!– 使用拦截器 –>

<action name=”costDelete” class=”org.tarena.netctos.CostDeleteAction”>

<interceptor-ref name=”checklogin”/>

<interceptor-ref name=”defaultStack”/>//调用默认拦截器栈中的拦截器

<result name=”cuccess”>/WEB-INF/jsp/cost/cost_delete.jsp</result>

</action>

struts总结

(1).方法二

创建拦截器栈(<interceptor-stack name=”loginStack”>),将多个拦截器放在拦截器栈中,这样就可以在需要的地方直接引入拦截器栈就行了(<interceptor-ref name=”loginStack”/>)

eg:

<!– 定义拦截器 –>

<interceptors>

<interceptor name=”checklogin”

class=”org.tarena.netctoss.interceptor.CheckLoginInterceptor2″/>

<interceptor-stack name=”loginStack”>

<interceptor-ref name=”checklogin”/>

<interceptor-ref name=”defaultStack”/>

</interceptor-stack>

</interceptors>

<!– 使用拦截器 –>

<action name=”costDelete” class=”org.tarena.netctos.CostDeleteAction”>

<interceptor-ref name=”loginStack”/>

<result name=”cuccess”>/WEB-INF/jsp/cost/cost_delete.jsp</result>

</action>

方法二中的定义拦截器的方法实际上是先定义一个checklogin拦截器,然后定义一个拦截器栈(用于存放多个拦截器),把定义的checklogin拦截器和struts默认的拦截器放在拦截器栈里面。在使用拦截器时候,直接引入拦截器栈就可以了(相当于引入了checklogin拦截器和struts默认拦截器)。

 

c.使用拦截器组件

(1).为所有Action指定默认使用配置,这样,拦截器便对该包中的所有Action

起拦截作用

<package ******>

<default-interceptor-ref  name=”拦截器名”/>

</package>

–(2).为某一个Action指定使用配置

<action>

<interceptor-ref name=”拦截器名”/>

</action>

eg:

<action name=”showAddCost”>

<interceptor-ref name=”loginStack”/>

<interceptor-ref name=”defaultStack”/>

<result>/WEB-INF/jsp/cost/cost_add.jsp</result>

</action>

注意:如果为某个Action指定了拦截器配置,不会再调用指定的默认拦截器.所以一般会加上<interceptor-ref name=”defaultStack”/>。

 

5)fileUpload内置拦截器的使用

a)fileUpload拦截器功能

用于实现文件上传功能。

fileUpload拦截器处理流程:

客户端发送上传文件请求

首先,struts控制器收到请求后调用fileUpload拦截器,fileUpload拦截器调用commons-file-upload.jar上传组件对请求提交

的表单信息进行解析。

然后将解析后的文件保存到服务器临时目录下,并将临时目录下的文件

对象赋值给Action的File属性。

执行Action,在Actin业务中,需要做文件复制,将临时文件转移到目标

目录中。

当Action和Result调用完毕后,清除临时目录下的文件,因此在Actin业务中,需要做文件复制,将临时文件转移到目标目录中。

b)上传示例

注意事项:

–需要引入commons-io.jar)

–form表单method必须为post;enctype必须为multipart/form-data

–Action组件按下面规则接收表单信息

<input type=”file” name=”xxx”>

Action属性如下:

private File xxx;// 临时目录下的文件

private String xxxFileName;// 源文件名

private String xxxContentType;// 源文件类型

—struts默认允许上传的文件所占最大内存为2097152字节(不同计算机可

能略有不同)。如果要更改默认设置,可以参考如下“更改struts中的默

认设置”

更改struts中的默认设置(即修改如下配置文件):

ReferencedLibraries/struts2-core-2.1.8.jar/org-apache.struts2/default.properties

 

18、更改strts中的默认配置:

1.更改对客服端发送过来的参数进行解码的方式:

<constant name=”struts.i18n.encoding” value=”gbk”/>(默认为utf-8)

2.更该允许客户端上传的最大文件大小值:

<constant name=”struts.multipart.maxSize” value=”100000000”/>

(默认大小为:2097152字节,约2M)

 

19、全局异常处理:

<!–全局的异常处理,当异常从Action中抛出时,会自动进入全局异常处理模块–>

<global-results>

<!– 错误处理 –>

<result name=”error”>/WEB-INF/jsp/error.html</result>

</global-results>

 

<global-exception-mappings>

<exception-mapping exception=”java.lang.Exception” result=”error”>

</exception-mapping>

</global-exception-mappings>

 

20、用户输入不存在请求资源路径(及action不存在)处理:

<!– 指定一个默认响应的Action,当遇到例外的action请求,该项配置启作用 –>

<default-action-ref name=”defaultAction”/>

<!– 采用重定向方式调用toLogin –>

<action name=”defaultAction”>

<result type=”redirectAction”>

<param name=”namespace”>/</param>

<param name=”actionName”>toLogin</param>

</result>

</action>

<!– 显示登录页面 –>

<action name=”toLogin”>

<result>/WEB-INF/jsp/login.jsp</result>

</action>

通过此配置后,用户输入非法请求资源路径时便不会出现“404”错误提示了,而是友好地跳转到登录页面。

======NETCTOSS项目========

1)项目描述(一期工程)

实现电信计费系统的账号管理,业务管理,资费管理,管理员和角色管理的功能。

2)项目技术架构

主要采用Struts2,JDBC,Ajax,jQuery技术。

采用MVC结构分层思想开发。

表现层(V):JSP,Ajax,jQuery

控制层(C):Struts2控制器Filter+Action

业务层(M):JavaBean,Bean组件

数据访问层(M):DAO+JDBC

3)项目工程结构

a.开发包引入

–Struts2开发包(5个核心+1个json响应包)

–Oracle驱动包

b.src源码

org.tarena.netctoss.action

org.tarena.netctoss.action.fee

org.tarena.netctoss.action.account

org.tarena.netctoss.service

org.tarena.netctoss.dao

org.tarena.netctoss.pojo

org.tarena.netctoss.util

org.tarena.netctoss.test

c.配置文件

web.xml : 配置struts2控制器

struts.xml:struts2框架主配置

–struts-fee.xml : 资费模块配置

–struts-account.xml:账号模块配置

d.WebRoot

WebRoot/WEB-INFO/jsp/fee/资费页面

WebRoot/styles/样式文件

WebRoot/js/脚本文件

WebRoot/images/页面图片

=========记录检索=========

search.action–>SearchAction–>DAO

 

 

 

1.项目评审

1)自我简介,项目需求描述,功能演示

2)典型功能实现讲解

2.共通问题处理

1)表单校验处理(参考“jQuery表单校验插件”目录的资料)

可以利用jQuery编写校验函数,

也可以基于现有的jQuery扩展插件来实现

例如validate和formvalidate等插件都可以

2)Struts2全局异常处理

当异常抛出Action的业务方法时,可以利用全局异常处理方式解决(在struts.xml追加配置)。

3)将页眉导航部分提取成一个head.jsp,

通过include方式引入各个页面。

4)设置一个默认响应Action。

遇到不能识别的Action请求,或找不到请求对应的Action时,调用该默认Action做响应

以上的“struts总结“是本人在学习期间自己总结出来的,今天,把她晒出来,希望能够和大家分享下!

标签