java struts2 框架 入门简介

目录

一、Struts2框架执行流程

二、Struts2的快速入门

1.导入jar包

2.配置web.xml文件

3.配置struts.xml文件

4.创建Action来完成逻辑操作

三、Struts2配置详解

Struts2配置文件加载顺序

struts.xml文件配置介绍

package配置

action配置

result配置

扩展

常量配置

四、Struts2的Action详解

Action类创建方式(三种)

Action的访问方式

五、Struts2框架封装数据

属性驱动

模型驱动

小结

六、Struts2中获取Servlet API

ServletActionContext获取

采用注入方式

OGNL表达式

单独使用OGNL来完成示例

七、valueStack 值栈

valueStack介绍

valueStack内部结构

获取ValueStack

ActionContext是什么

valueStack操作---存储数据

手动向valueStack存储数据

Struts2框架自动向valueStack中存储数据

valueStack操作---获取数据

El表达式可以从valueStack中获取信息

Ognl表达式中特殊字符

八、Interceptor拦截器

Interceptor拦截器

Interceptor作用与自定义Interceptor

小结

九、Struts2文件上传

上传案例

注意事项

十、Struts2框架使用Ajax的方式

使用HttpServletResponse响应数据

使用strtus2框架的json插件来完成ajax操作

十一、Struts2注解开发

快速入门

其他注解


Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。

Struts2=struts1+webwork

一、Struts2框架执行流程

 

 

 

  1. 当通过浏览器发送一个请求
  2. 会被StrutsPrepareAndExecuteFilter拦截
  3. 会调用strtus2框架默认的拦截器(interceptor)完成部分功能
  4. 在执行Action中操作
  5. 根据Action中方法的执行结果来选择来跳转页面Resutl视图

Strtus2的默认拦截器(interceptor)它们是在struts-default.xml文件中配置 注意:这上xml文件是在strtus-core.jar包中,默认的拦截器是在defaultStack中定义的。

二、Struts2的快速入门

  1. 导入相关的jar文件
  2. 需要在web.xml文件中配置StrutsPrepareAndExecuteFilter
  3. 配置struts.xml文件
  4. 创建Action来完成逻辑操作

1.导入jar包

 

 

 

如果我们只是创建一个简单的项目的话,不需要将它的lib包下的所有的jar文件copy到项目中,而是使用其中的一部分。

2.配置web.xml文件

在web.xml文件中配置StrutsPrepareAndExecuteFilter。一般管StrutsPrepareAndExecuteFilter 叫做前端控制器(核心控制器),只有配置了这个filter我们的strtus2框架才能使用。

<filter>
  	<!-- filter-name	可以随便写 -->
  	<filter-name>struts2</filter-name>
  	<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>struts2</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>
复制代码

3.配置struts.xml文件

jsp页面的代码

<form action="${ pageContext.request.contextPath }/LoginAction" method="post">
	账号:<input type="text" name="username"><br/>
	密码:<input type="password" name="password"><br/>
	<input type="submit" value="LOGIN">
</form>
<s:debug/>
复制代码

struts.xml文件对应配置

<struts>

<constant name="struts.devMode" value="true"></constant>

<package name="default" namespace="/" extends="struts-default">
	<action name="LoginAction" class="com.lbb.strus2.action.LoginAction" method="login">
		<result name="success" type="redirect">/success.jsp</result>
		<result name="failer">/failter.jsp</result>
	</action>
</package>

</struts>
复制代码

4.创建Action来完成逻辑操作

public class LoginAction {
	private String username;
	private String password;
/*
	......
	提供属性对应的get/set方法
	......
*/
	public String login() {
		System.out.println(username+"   "+password);
		if("tom".equals(username)&&"123".equals(password)){
			return "success";
		}else{
			return "failer";
		}
	}
	
}
复制代码

三、Struts2配置详解

Struts2配置文件加载顺序

通过以下步骤可以找到加载配置文件源代码的位置

 

 

 

 

 

ps:我也不知道为什么只有123567,没有4

  1. 第一个加载的是default.properties文件 位置:strtus2-core.jar包 org.apache.struts2包下 作用:主要是声明了struts2框架的常量
  2. 第二个加载的是一批配置文件 Strtus-default.xml 位置:struts2-corl.jar 作用:声明了interceptor result bean Strtus-plugin.xml 位置:在strtus2的插件包中 作用:主要用于插件的配置声明 Strtus.xml 位置:在我们自己的工程中 作用:用于我们自己工程使用strtus2框架的配置
  3. 第三个加载的是自定义的strtus.properties 位置:都是在自己工程的src下 作用:定制常量
  4. 第四自定义配置提供 第五加载的是web.xml配置文件 主要是加载strtus2框架在web.xml文件中的相关配置. (项目最开始加载的就是web.xml,这里是指在前四个配置文件加载完成后,又返回来重新加载一次这个配置文件)
  5. 第六 bean相关配置

(这里的加载是指从硬盘加载到内存并进行部分的读取,而在一个请求中进行的加载是指在内存中读取配置文件)

struts.xml文件配置介绍

<package name="default" namespace="/" extends="struts-default">
    <action name="LoginAction" class="com.lbb.strus2.action.LoginAction" method="login">
        <result name="success" type="redirect">/success.jsp</result>
        <result name="failer">/failter.jsp</result>
    </action>
</package>
复制代码

package配置

  1. name属性 作用:定义一个包的名称,它必须唯一。
  2. namespace属性 作用:主要是与action标签的name属性联合使用来确定一个action 的访问路径
  3. extends属性 作用:指定继承自哪个包。一般值是strtus-default strtus-default包是在strtus-default.xml文件中声明的。
  4. abstruct属性 它代表当前包是一个抽象的,主要是用于被继承 <package name="struts-default" abstract="true">

action配置

  1. name属性 作用:主要是与package的namespace联合使用来确定一个action的访问路 径
  2. class属性 作用:用于指示当前的action类
  3. method属性 作用:用于指示当前的action类中的哪个方法执行

result配置

它主要是用于指示结果视图

  1. name属性 作用是与action类的method方法的返回值进行匹配,来确定跳转路径
  2. type属性 作用是用于指定跳转方式(默认是请求转发)

关于路径跳转问题,它的name属性是与action中的方法的返回值进行对比的。

它的type属性可以取哪些值?

 

 

 

默认值是dispatcher 它代表的是请求转发。针对于jsp页面 redirect 它代表的是重定向 针对于jsp页面 chain 它类似于请示转发,只不过它是针对于action跳转. redirectAction 它类似于重定向 针对于action 关于路径跳转的配置 可以直接在<package>下创建全局的result

 

 

 

扩展

关于action配置中的class与method的默认值以及result中的name与type 默认值问题.

<action name="LoginAction">
     <result>/success.jsp</result>
</action>
复制代码

原因:strtus-default.xml文件中配置 <default-class-ref class="com.opensymphony.xwork2.ActionSupport" /> 它的作用就是当一个请求来时,如果查找不到指定的class及对应的method就会执行ActionSupport类中的execute方法。在这个类的execute方法中默认返回的是”success”。也就是说,result的name属性默认值是success,默认的跳转方式是请求转发 dispatcher。

常量配置

在default.properties文件中定义了struts2框架常用常量。 那么,我们怎样可以设置常量。

  1. 可以在src下创建一个strtus.properties配置文件
  2. 可以在web.xml文件中配置
  3. 可以直接在strtus.xml文件中定义常量 (推荐)

注意:后加载的配置文件中的常量会将先加载的常量覆盖

<!-- 声明常量 -->
<constant name="struts.i18n.encoding" value="UTF-8"></constant>
<!-- 可以帮助我们解决post请求乱码问题 -->
<!-- <constant name="struts.action.extension" value="action"></constant> -->
<!-- 指定访问strtsu2框架路径的扩展名 -->
<constant name="struts.devMode" value="true"></constant>
<!-- 配置这项后,它会提供更加详细报错信息,以及在struts.xml文件修改后不在需要重启服务器 -->
<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
<!-- 开启动态方法调用 -->
复制代码

四、Struts2的Action详解

Struts2中的action,主要是完成业务逻辑操作。Action替代在servlet中完成的作用。

Action的学习主要有两点

  1. 如何创建一个struts2的action
  2. 如果访问一个struts2的action

Action类创建方式(三种)

  1. 创建一个pojo类 Pojo(plani Ordinary java object)简单的java对象 Pojo类就是没有实现任何接口没有继承任何类 优点:无耦合 缺点:所有的功能都要自己完成
  2. 创建一个类实现一个Action接口 com.opensymphony.xwork2.Action

 

 

 

在Action接口中定义了五个常量,一个execute方法。 五个常量:它们是默认的五个结果视图<result name="">: ERROR : 错误视图 INPUT: 它是struts2框架中interceptor中发现问题后会访问的一个视图 LOGIN:它是一个登录视图,可以在权限操作中使用 NONE:它代表的是null,什么都不做(也不会做跳转操作) SUCCESS:这是一个成功视图 优点:耦合度低 缺点:还是需要自己来完成功能 3. 创建一个类继承ActionSupport类 com.opensymphony.xwork2.ActionSupport ActionSupport类也实现了Action接口。 我们在开发中一般会使用这种方案: 优点:具有丰富的功能,例如 表单校验 错误信息设置 国际化 缺点:耦合度高

Action的访问方式

  1. 直接通过标签来配置,通过method来指定访问的方法,如果method没有,默认访问的是execute方法。
  2. 简化的action访问方式,可以使用*通配符来访问。
<action name="Book_*" class="com.lbb.strus2.action.BookAction" method="{1}"></action>
<action name="*_*" class="com.lbb.strus2.action.{1}Action" method="{2}"></action>
复制代码
public class BookAction extends ActionSupport{
	public void add() {
		System.out.println("bookadd");
	}
	public void del() {
		System.out.println("bookdel");
	}
	public void update() {
		System.out.println("bookupdate");
	}
	public void find() {
		System.out.println("bookfind");
	}
}
public class ProductAction extends ActionSupport{
	public void add() {
		System.out.println("productadd");
	}
	public void del() {
		System.out.println("productdel");
	}
	public void update() {
		System.out.println("productupdate");
	}
	public void find() {
		System.out.println("productfind");
	}
}
复制代码

这种方式的缺点:不建议使用过多的号,它带来程序阅读障碍,不便于理解 使用来简化操作方案,它对名称规范必须进行一个统一。

扩展--动态方法调用

<!-- localhost:8080/工程名/Book_add!add -->
<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
<!-- 开启动态方法调用 -->
复制代码

注意:对于strtus2的动态方法调用,要想使用我们必须配置一个常量来开启动态方法调用。 个人不建议使用动态方法调用(出现过漏洞!)

五、Struts2框架封装数据

在action中如果获取请求参数? 主要有两类三种方法

属性驱动

第一种,直接在action类中提供与请求参数匹配属性,提供get/set方法。

public class LoginAction {
	private String username;
	private String password;
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String login() {
		System.out.println(username+"   "+password);
		if("tom".equals(username)&&"123".equals(password)){
			return "success";
		}else{
			return "failer";
		}
	}
}
复制代码

第二种,在action类中创始一个javaBean,对其提供get/set ,在请求时页面上要进行修改, 例如 user.username user.password ,要使用ognl表达式

public class LoginAction2{
	private User user = new User();
	public User getUser() {
		return user;
	}
	public void setUser(User user) {
		this.user = user;
	}
	public String login() {
		System.out.println(user.getUsername()+"   "+user.getPassword());
		if("tom".equals(user.getUsername())&&"123".equals(user.getPassword())){
			return "success";
		}else{
			return "failer";
		}
	}
}
复制代码

以上两种方式的优缺点: 第一种:比较简单,在实际操作我们需要将action的属性在赋值给模型(javaBean) 去操作 第二种:不需要在直接将值给javaBean过程,因为直接将数据封装到了javaBean 中。它要求在页面上必须使用ognl表达式,就存在页面不通用问题。

模型驱动

步骤:

  1. 让Action类要实现一个指定接口ModelDriven
  2. 实例化模型对象(就是要new出来javaBean)
  3. 重写getModel方法将实例化的模型返回。 对于模型驱动它与属性驱动对比,在实际开发中使用比较多,模型驱动缺点,它只能对 一个模型数据进行封装。
public class LoginAction3 implements ModelDriven<User>{
	private User user = new User();
	public User getModel() {
		return user;
	}
	public String login() {
		System.out.println(user.getUsername()+"   "+user.getPassword());
		if("tom".equals(user.getUsername())&&"123".equals(user.getPassword())){
			return "success";
		}else{
			return "failer";
		}
	}
}
复制代码

小结

 

 

 

六、Struts2中获取Servlet API

在action类中获取request response session...对象,有两种方案。

ServletActionContext获取

 

 

 

采用注入方式

Struts2框架在运行时,请求会被StrutsPrepareAndExecuteFilter拦截,会根据请求,去 strtus.xml文件中查找到匹配的action,在action执行前,会走一些interceptor。

默认执行的拦截器是struts-default.xml文件中定义的,在默认执行的拦截器中有一个

<interceptor name="servletConfig" "lass="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
......
<interceptor-ref name="servletConfig"/>
复制代码

查看一下ServletConfigInterceptor源代码。以下是部分源代码

 

 

 

ServletRequestAware, 实现这个接口可以获取HttpServletRequest ServletResponseAware ,实现这个接口可以获取HttpServletResponse ServletContextAware 实现这个接口可以获取ServletContext

 

 

 

OGNL表达式

OGNL是Object-Graph Navigation Language(对象图导航语言)的缩写,它是一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。

Strtsu2框架内置了OGNL OGNL本身也是一个项目,它是可以单独使用。

OGNL作用 支持对象的操作,调用对象的方法 支持静态成员访问 支持赋值操作与表达串联 访问OGNL上下文,访问ActionContext 操作集合对象。

单独使用OGNL来完成示例

OGNL三要素: 1.表达式 2.OgnlContext 上下文 3. Root 根

支持对象操作

// 表达式 OgnlContext 上下文 Root 根
@Test
public void test1() throws OgnlException {
	// String s="hello";
	// int length = s.length();
	// 1.获取上下文对象OgnlContext
	OgnlContext context = new OgnlContext(); // 它就是一个java.util.Map
	// 2.操作
	Object root = context.getRoot();
	Object value = Ognl.getValue("'hello'.length()", context, root);
	System.out.println(value);
}
复制代码

支持静态成员访问

// 1.获取上下文对象OgnlContext
OgnlContext context = new OgnlContext(); // 它就是一个java.util.Map
// 2.操作
Object value = Ognl.getValue("@java.lang.Math@random()", context, context.getRoot());
Object value2 = Ognl.getValue("@java.lang.Math@PI", context, context.getRoot());
System.out.println(value);
System.out.println(value2);
复制代码

访问Ognl上下文

@Test
public void test3() throws Exception {
	// 1.获取上下文对象OgnlContext
	OgnlContext context = new OgnlContext(); // 它就是一个java.util.Map
	// 2.向上下文中存储数据
	context.put("username", "tom");
	// 3.操作
	Object value = Ognl.getValue("#username", context, context.getRoot());
	System.out.println(value);
}

@Test
public void test4() throws Exception {
	// 1.获取上下文对象OgnlContext
	OgnlContext context = new OgnlContext(); // 它就是一个java.util.Map
	// 2.存储数据
	Map<String, String> map = new HashMap<String, String>();
	map.put("username", "fox");
	context.put("username", "tom");
	// 将map存储到context的根中
	context.setRoot(map);
	// 3.操作
	Object value = Ognl.getValue("username", context, context.getRoot());
	System.out.println(value);
}
复制代码

如果从根中获取数据,不需要添加#号,如果不是从根中获取,需要#。

如果root中存了一个对象,可以直接访问这个对象的属性。如果是存在上下文context中的对象则需要通过”对象.属性”的形式访问

操作集合

// 操作集合
@Test
public void test5() throws OgnlException {
	// 1.获取上下文对象OgnlContext
	OgnlContext context = new OgnlContext(); // 它就是一个java.util.Map
	//2.操作
	Object value = Ognl.getValue("{'hello','good','well'}", context,context.getRoot()); //相录于创建了一个List集合
	context.setRoot(value);		
	System.out.println(Ognl.getValue("[0]",context, context.getRoot()));		
	//Object value2 = Ognl.getValue("#{'username':'tom','age':20}", context,context.getRoot()); //相当于创建了一个Map集合		
	//System.out.println(value2.getClass());
}
	
//支持表达式赋值及串联
@Test
public void test6() throws OgnlException {
	// 1.获取上下文对象OgnlContext
	OgnlContext context = new OgnlContext(); // 它就是一个java.util.Map		
	//2.操作		
	Object value = Ognl.getValue("#{'username':'tom','age':20}", context,context.getRoot()); //相当于创建了一个Map集合	
	context.setRoot(value);		
	Object value2 = Ognl.getValue("username='张三',age=45", context,context.getRoot());
	System.out.println(value2);				
}
复制代码

Strtus2框架中如何使用ognl表达式

在struts2框架中我们使用ognl表达式的作用是从valueStack中获取数据。我们在struts2框架中可以使用ognl+valueStack达到在页面(jsp)上来获取相关的数据。要想在jsp页面上使用ognl表达式,就需要结合struts2框架的标签 <%@taglib prefix="s" uri="/struts-tags"%> <s:property value="表达式"> 来使用.

七、valueStack 值栈

valueStack介绍

 

 

 

我们使用valueStack的主要目的是为我将我们action中产生的数据携带到页面上,也就是说valueStack它就是一个容器。

在Struts2框架中将valueStack设计成一个接口。 com.opensymphony.xwork2.util.ValueStack

我们主要使用的是它的实现类 com.opensymphony.xwork2.ognl.OgnlValueStack。

当客户端向我们发送一个请求,服务器就会创始一个Action来处理请求,struts2中的action是一个多例,每一次请求都会有一个新的action对应。所以它不存在线程安全问题。 一个valueStack对应一个action,valueStack贯穿整个action的生命周期。 rquest------Action------ValueStack

struts2框架将valueStack保存在request中。 在Dispatcher.class中有以下代码

 

 

 

valueStack内部结构

 

 

 

 

 

 

valueStack主要有两部分组成: CompoundRoot:它就是一个ArrayList 它主要存储的是action的相关数据 Map<String,Object> context:就是一个Map Context中主要存储了一些引用,这个引用主要是关于web开发中相关信息 pameters :请求参数 request:请求对象中所有属性 session:会话对象中所有属性 application:application对象中的所有发展 以上都是Map

在struts2框架中我们通过ognl表达式来获取valueStack中数据,没有使用#就会从CompoundRoot中获取数据,如果使用#来获取,这时就会从context中来获取。

获取ValueStack

一种方式:可以直接通过request对象来获取

ValueStack stack = (ValueStack) ServletActionContext.getRequest().getAttribute("ServletActionContext.STRUTS_VALUESTACK_KEY");
复制代码

二种方式:使用ActionContext来获取

ValueStack stack = ActionContext.getContext().getValueStack();
复制代码

ActionContext是什么

ActionContext它是action上下文,strtus2框架它使用actionContext来保存Action在执行过程中所需要的一些对象,例如 session, application…

ActionContext的获取 是通过它的静态方法getContext()得到。 Struts2会根据每一次的http请求来创建对应的ActionContext,它是与当前线程绑定的。

每一次请求,就是一个线程,对应着一个request,每一次请求,会创建一个Action,每一个action对应一个ActionContext.每一次请求也对应着一个valueStack. request---ActionContext----Action-----ValueStaci它们都对应着一次请求(一个线程). valueStack与ActionContext本质上是可以获取

 

 

 

 

 

 

ActionContext里存有一个valueStack的context,而valueStack的context里存有valueStack的一个Root

valueStack操作---存储数据

 

 

 

手动向valueStack存储数据

// 向valueStack存储数据
stack.set("name", "tom");
// 底层会创建一个HashMap,保存数据,在将hashMap存储到root中。
stack.push("hello word!");
// 向root中存储
复制代码

Struts2框架自动向valueStack中存储数据

每次请求,访问action,这个对象会存储到valueStack中。 在DefaultActionInvocation的init方法内

 

 

 

在ModelDrivernInterceptor中会将模型对象存储到valueStack中。

 

 

 

valueStack操作---获取数据

在jsp页面中如何从valueStack中获取数据的问题,让我们通过以下代码和运行结果来分析。

<body>
<s:property value="[0].top"/>
<br/>
<s:property value="username2"/>
<br/>
<s:property value="username"/>
<br/>
<s:property value="password"/>
<br/>
<s:property value="user.username"/>
<br/>
<s:property value="model.username"/>
<br/>
<s:property value="loginMsg"/>
<s:actionerror />
<form action="${ pageContext.request.contextPath }/LoginAction" method="post">
	账号:<input type="text" name="username"><br/>
	密码:<input type="password" name="password"><br/>
	<input type="submit" value="LOGIN">
</form>
<s:debug/>
</body>
复制代码

输入用户名和密码:tom:111

public class LoginAction extends ActionSupport implements ModelDriven<User>{
	private String username2 = "rose";
	public String getUsername2(){
		return "Rose";
	}
	private User user = new User();
	public User getModel() {
		return user;
	}
	public User getUser() {
		return user;
	}
	public String login(){	
		 if("tom".equals(user.getUsername())&&"123".equals(user.getPassword())){
			 System.out.println(user);
			 ServletActionContext.getRequest().getSession().setAttribute("user", user);
			 return "success";
		 }else{
			 ActionContext actionContext = ActionContext.getContext();
			 ValueStack valueStack = actionContext.getValueStack();
			 user = new User();
			 user.setUsername("fox");
			 user.setPassword("456");
			 valueStack.set("username","jack");
			 valueStack.set("loginMsg","用户名或密码错误!");
			 valueStack.push("hello word!");
			 return "failer";
		 }	 
	}	

public class User {
	private String username;
	private String password;
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	@Override
	public String toString() {
		return "User [username=" + username + ", password=" + password + "]";
	}
}
复制代码

结果图如下

 

 

 

 

 

 

分析结论:

  1. com.lbb.struts2.action.LoginAction代表Action本身
  2. com.lbb.struts2.domain.User代表的是最初始的接受的model实例对象,而LoginAction中的model和user代表的是LoginAction类中user属性这个引用。如果在类的方法中user属性没有被重新赋值,那么他们指向同一个实例对象,如果user属性被重新赋值,则com.lbb.struts2.domain.User仍指向最初的model对象,而LoginAction中的model和user则指向新的实例对象。从com.lbb.struts2.domain.User中取属性直接写属性名就行,参考第四行结果,如果要从com.lbb.struts2.action.LoginAction的对象中取属性,要写上对象名,参考第五行,第六行结果。 可以参考下图进行理解
  3. com.lbb.struts2.domain.User以上的数据就是我们手动向添加valueStack中添加的数据
  4. 从valueStack中取数据的顺序是从上向下取第一个找到的对应的元素。例如手动设置的和com.lbb.struts2.domain.User中都有的时候,取手动存的。没有手动存的时候取com.lbb.struts2.domain.User中的。参考第三行和第四行的数据。

El表达式可以从valueStack中获取信息

为什么el表达式可以从valueStack中获取数据? 在org.apache.struts2.dispatcher.StrutsRequestWrapper中

 

 

 

Struts2框架对request进行了增强,重写了getAttribute方法,如果在request域中查找不到数据,就会在valueStack中获取。

Ognl表达式中特殊字符

OGNL是通常要结合Struts 2的标志一起使用。主要是#、%和$这三个符号的使用

#号:它是从非root中获取数据 %用于强制是否要解析ognl表达式

<%
		request.setAttribute("username", "tom");
		session.setAttribute("password", "123");
	%>
	<h1>#号用法</h1>
	<s:property value="#request.username" />
	<br>
	<s:property value="#session.password" />
	<br>
	<!-- localhost:8080/struts2-day02/ognl3.jsp?username=tom -->
	<s:property value="#parameters.username"/>
	
	<h2>%号用法</h2>
	<s:property value="%{#request.itcast}"/><br> <!-- 会解析成ognl -->
	<s:property value="%{'#request.itcast'}"/><br> <!-- 不会解析ognl -->
	
	<s:debug />
复制代码

$它主要是在配置文件中来获取valueStack中数据

<action name="vs" class="com.lbb.action.ValueStackAction">	
	<result name="success" type="redirect">/ognl2.jsp?username=${model.username}</result>
</action>
复制代码

八、Interceptor拦截器

Interceptor拦截器

Struts2中的interceptor它是基于spring aop思想,而aop思想它本质上是通过动态代理来实现。我们strtus2的拦截器它主要是拦截Action的操作,在action的执行前或执行后进行一些其它的功能操作。

以下是struts2的执行流程图

 

 

 

执行的过程 当我们发送请求访问Action时,会被StrutsPrepareAndExecuteFilter拦截 在其doFilter方法内执行了 execute.executeAction(request, response, mapping)。

这个代码执行后,dispatcher.serviceAction(request, response, mapping), serviceAction方法执行。

在这个方法执行过程中会创建Action代理对象

ActionProxy proxy = getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, name, method, extraContext, true, false);
复制代码

通过proxy去执行了proxy.execute(),在execute方法内return invocation.invoke()。

invocation它是ActionInvocation一个对象。 在invoke方法内

 

会去加载我们的配置文件,将配置文件中所有的interceptor得到进行遍历。 在struts-default.xml文件中定义了默认加载的拦截器栈 defaultStack

 

在每一个拦截器的interceptor方法内,又调用了DefaultActionInvocation的invoke方法,其实就是递归调用。

 

Interceptor作用与自定义Interceptor

我们使用intercep[tor可以在action执行前后进行处理工作。例如,完成权限控制。

问题:如何定义Interceptor

所有的Interceptor都要实现一个接口 com.opensymphony.xwork2.interceptor.Interceptor

在配置文件中声明Interceptor

我们也可以将多个interceptor封装成一个stack

可以在Action的配置中引入自己的interceptor 在使用时name也可以引入一个interceptor stack.

注意:当我们显示的引入了一个自定义的Interceptor,那么默认的defaultStack就不会在导入,需要手动导入

<!-- 声明 -->
<interceptors>
	<interceptor name="myInterceptor" class="cn.lbb.utils.MyInterceptor">
	<param name="includeMethods">showProduct</param>
	<param name="excludeMethods">addProduct</param>
	</interceptor>
		<interceptor-stack name="myStack">
			<interceptor-ref name="myInterceptor"/>
			<interceptor-ref name="defaultStack"></interceptor-ref>	
		</interceptor-stack>
</interceptors>	

<action name="product_*" class="cn.lbb.action.ProductAction" method="{1}">
	<result name="success">/product.jsp</result>
	<result name="login">/login.jsp</result>
	<interceptor-ref name="myStack"/>			
</action>
复制代码

我们在struts.xml文件中配置action时,可以使用*通配置符,这时它可以处理多个方法,你指定的interceptor只想拦截某一个方法,可以使用Interceptor接口的一个实现类来完成操作MethodFilterInterceptor

小结

注意:在实际开发中,我们一般会让action去继承ActionSupport类,这样可以使用父类提供的对于错误操作的处理this.addActionError("错误信息!") 在struts2中处理简单的信息(字符串)

this.addActionError("错误信息!")
this.addFieldError(fieldName,errorMessage)
this.addActionMessage(amessage)
复制代码

第一个:一般用于逻辑业务操作 第二个:对接收的参数进行格式校验,是否满足格式 第三个:普通信息 获取

<s:actionerror/>
<s:fielderror/>
<s:actiommessage/>
复制代码

要想在页面上展示集合信息可以使用<s:iterator>标签来完成

<s:iterator value="ps">
	<tr>
		<td><s:property value="name" /></td>
		<td><s:property value="price" /></td>
		<td><s:property value="count" /></td>
	</tr>
</s:iterator>

<s:iterator value="ps" var="p">
	<tr>
		<td><s:property value="p.name" /></td>
		<td><s:property value="p.price" /></td>
		<td><s:property value="p.count" /></td>
	</tr>
</s:iterator>
复制代码

九、Struts2文件上传

浏览器端注意事项

表单提交方式method=post 表单中必须有一个组件 表单中必须设置enctype=”multipart/form-data”

服务器端

Commons-fileupoad.jar包完成。

Struts2框架使用一个fileupload的interceptor来完成文件上传

上传案例

<form action="${ pageContext.request.contextPath }/upMany" enctype="multipart/form-data" method="post">
<input type="file" name="upload">
<input type="file" name="upload">
<input type="submit" value="上传">
</form>
复制代码
public class UploadActionMany extends ActionSupport{
//	 extends ActionSupport 
	private File[] upload;
	private String[] uploadContentType;
	private String[] uploadFileName;
/*
	提供对应的set/get方法
*/
	public String upload(){
		System.out.println(3);
		String path = ServletActionContext.getServletContext().getRealPath("/upload");
		try {
			for (int i = 0; i < upload.length; i++) {
				File file = new File(path,uploadFileName[i]);
				FileUtils.copyFile(upload[i], file);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println(4);
		return null;
	}
}
复制代码

注意事项

<!-- 开发模式 -->
<constant name="struts.devMode" value="true"></constant>
<!-- 设置文件上传的大小限制 -->
<constant name="struts.multipart.maxSize" value="40971520"></constant>
<action name="upMany" class="com.lbb.struts2.action.UploadActionMany" method="upload">
	<!-- 文件上传出错后的视图 -->
	<result name="input">/error.jsp</result>
	<interceptor-ref name="fileUpload">
		<!-- <param name="maximumSize"></param> --><!-- 设置每一个文件的单独的上传大小 -->
		<!-- <param name="allowedTypes"></param> --><!-- 文件的mime类型 -->
		<param name="allowedExtensions">txt,jpg,bmp</param><!-- 设置允许的后缀名 -->
	</interceptor-ref>
	<interceptor-ref name="defaultStack"></interceptor-ref>
</action>
复制代码

input接受错误信息

<s:actionerror/>
<s:fielderror/>
复制代码

十、Struts2框架使用Ajax的方式

使用HttpServletResponse响应数据

在struts2框架中可以获取HttpServletResponse对象,就可以通过response来完成将数据(json)响应到浏览器过程。

使用strtus2框架的json插件来完成ajax操作

首先要导入插件包struts2-json-plugin-2.3.24.jar

我们怎样使用struts2提供的json插件

  1. 将我们自己配置文件中的<package extends=”json-default”>.
  2. Action的返回视图<result name=”” type=”json”>
  3. 因为我们配置了上面两步,那么struts2框架就会将valueStack中的栈顶元素转换成json响应到浏览器

案例

<script type="text/javascript">
$(function(){
	$("#productaa").toggle(function(){
		$.post("/day03_struts2/struts2_ajax/showProduct",{},function(data){
			$("#product").append("<tr><td>商品名</td><td>价格</td></tr>")
			$.each(data,function(i,n){
				$("#product").append("<tr><td>"+n.name+"</td><td>"+n.price+"</td></tr>")
			});
		},"json");
	},function(){
		$("#product").html("");
	});
});
</script>
<body>
<a href="javascript:void(0)" id="productaa">查看商品</a>
<div>
<table id="product" border="1"></table>
</div>
</body>
复制代码
<package name="default3" namespace="/struts2_ajax" extends="json-default">
		
		<action name="showProduct" class="com.lbb.struts2.action.ProductAction" method="show">
			<result name="success" type="json">
				<!-- 设置生成数据时的根 -->
				<!-- 
					没有设置root前返回的json结构   ps:[{},{}]
					设置root它的根为ps后的返回的json结构  [{},{}]
				 -->
				<param name="root">list</param>
				<!-- 生成json数据时包含或不包含属性 -->
				<param name="excludeProperties">\[\d+\]\.releaseDate</param>
				<!-- <param name="includeProperties">ps\[\d+\]\.id,ps\[\d+\]\.name</param> -->
			</result>
		</action>
		
	</package>
复制代码
public String show(){
		List<Product> list = new ArrayList<Product>();
		/*
		......
		*/
		list.add(product1);
		list.add(product2);
		list.add(product3);
		ActionContext.getContext().getValueStack().set("list",list);
		return "success";
	}
复制代码
public class Product {
	private int id;
	private String name;
	private double price;
	private Date releaseDate;
//	@JSON(serialize=false)	生成json数据时忽略属性
	public Date getReleaseDate() {
		return releaseDate;
	}
	/*
	对应的set/get方法
	*/	
}
复制代码

十一、Struts2注解开发

想使用struts2的注解,我们必须单独在导入一个jar包。它是在strtus2的2.1版本后引入。struts2-convention-plugin-2.3.24.jar

我们在action类中定义了注解,strtus2框架怎样识别它们 我们必须查看插件包中的配置,会发现 <constant name="struts.convention.package.locators" value="action,actions,struts,struts2"/> 是在action,actions,struts,struts2这样的包下扫描注解

快速入门

案例 登录页面

<body>
<s:actionerror/>
<form action="${ pageContext.request.contextPath }/user/login" method="post">
用户名<input type="text" name="username"><br/>
密码<input type="password" name="password"><br/>
<input type="submit" value="登录">
</form>
</body>
复制代码

登录Action

@Namespace("/user")
@ParentPackage("struts-default")
public class UserAction extends ActionSupport implements ModelDriven<User>{
	private User user = new User();
	@Override
	public User getModel() {
		return user;
	}
	@Action(value="login",results = { @Result(name="success",type="redirect",location="/product2.jsp"),
			@Result(name="error",location="/login.jsp") })
	public String login(){
		IUserService userService = new UserServiceImpl();
		try {
			user = userService.login(user);
			if(user!=null){
				ServletActionContext.getRequest().getSession().setAttribute("user",user);
				return SUCCESS;
			}else{
				addActionError("用户名或密码错误!");
				return ERROR;
			}
		} catch (SQLException e) {
			e.printStackTrace();
			throw new RuntimeException();
		}
	}
}
复制代码

商品展示页面

<script type="text/javascript" src="/day04_struts2_exam/js/jquery-1.8.3.js"></script>
<body>
<script type="text/javascript">
$(function(){
	$("#productaa").toggle(function(){
		$.post("${pageContext.request.contextPath}/product/productlist",{},function(data){
			if(data.type=="1"){
				$("#product").append("<tr><td>商品名</td><td>价格</td></tr>")
				$.each(data.list,function(i,n){
					$("#product").append("<tr><td>"+n.name+"</td><td>"+n.price+"</td></tr>")
				});
			}else{
				alert(data.message);
			}
		},"json");
	},function(){
		$("#product").html("");
	});
});
</script>
<a href="javascript:void(0)" id="productaa">查看商品</a>
<div>
<table id="product" border="1"></table>
</div>
</body>
复制代码

定义一个被商品Action继承的包,声明权限控制拦截器

<package name="base" namespace="/" extends="struts-default">
		<interceptors>
			<interceptor name="myInterceptor" class="com.lbb.struts2.interceptor.MyInterceptor">
			</interceptor>
			<interceptor-stack name="myStack">
				<interceptor-ref name="myInterceptor"></interceptor-ref>
				<interceptor-ref name="defaultStack"></interceptor-ref>
			</interceptor-stack>
		</interceptors>
	</package>
复制代码

商品展示Action

@Namespace("/product")
@ParentPackage("base")
public class ProductListAction {
     @Action(value="productlist",interceptorRefs={@InterceptorRef("myStack")})
	public void showProduct2(){
		ServletActionContext.getResponse().setContentType("text/html;charset=UTF-8");
		IProductService productService = new ProductServiceImpl();
		try {
			Result<Product> result = new Result<>();
			result.setType(1);
			List<Product> list = productService.findAll();
			result.setList(list);
			String resultString = JSONObject.toJSONString(result);
			System.out.println(resultString);
			ServletActionContext.getResponse().getWriter().println(resultString);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
复制代码

权限控制拦截器

public class MyInterceptor extends MethodFilterInterceptor{
	@Override
	protected String doIntercept(ActionInvocation arg0) throws Exception {
		ServletActionContext.getResponse().setContentType("text/html;charset=UTF-8");
		User user = (User) ServletActionContext.getRequest().getSession().getAttribute("user");
		if(user!=null){
			return arg0.invoke();
		}else{
			Result<Product> result = new Result<>();
			result.setMessage("权限不足!");
			String resultString = JSONObject.toJSONString(result);
			ServletActionContext.getResponse().getWriter().println(resultString);
			return null;
		}
	}
}
复制代码

其他注解

@Actions 用在方法上

@Actions({
    @Action(value = "testAction",results = {@Result(location="/success.jsp")}),
    @Action(value = "testAction2",results = {@Result(location="/success.jsp")})
})
public String demo1(){
	......
}
复制代码

@Results 用在类上,相当于全局结果视图

@Results( { @Result(name = "global", location = "/global.jsp") })  
public class demo1 extends ActionSupport {  
  
    @Action(value = "test1", results = { @Result(name = "success", location = "/success.jsp"),  
            @Result(name = "failure", location = "/fail.jsp") })  
    public String execute() {  
        if (...) {  
            return "failure";  
        } else if (...) {  
            return "success";  
        } else {  
            return "global";  
        }  
    }  
  
    @Action("test2")  
    public String demo2() {  
        return "global";  
    }  
}  
复制代码

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值