Struts2 入门

1、原理

可参考:http://blog.csdn.net/laner0515/article/details/27692673/ 、 http://blog.csdn.net/wuwenxiang91322/article/details/11070513

2、第一个项目——HelloWorld

(1)步骤:

①建立web项目,拷贝struts-2.5.10.1-min-lib/lib中的jar包。还需添加一个log4j-core


②在web.xml中配置Struts2的前端控制器-StrutsPrepareAndExecuteFilter

③定义一个POJO类:HelloAction

public class HelloAction {

	public String sayHello(){
		System.out.println("Hello World!");
		//返回逻辑视图
		return "success";
	}
}
④拷贝struts.xml文件到项目的类路径或资源文件中,文件名不能修改


但可以针对每个action类设定一个struts的xml配置文件,该文件可改名字


但是在struts.xml配置文件中需要引入该配置文件

	<include file="\action\helloworld\struts-hello.xml"></include>

⑤在struts.xml文件中,配置HelloAction.(把HelloAction交给Struts框架管理)


⑥访问Action

协议+主机地址+端口号+上下文路径+命名空间(namespace)+资源名称(action name)

3、Struts2中的6大配置文件

(1)Struts2框架按照如下顺序加载struts2配置:
①default.properties 该文件保存在 struts2-core-2.5.10.1.jar 中 org.apache.struts2包里面:包含了Struts2的默认常量配置
②struts-default.xml 该文件保存在 struts2-core-2.5.10.1.jar:包含了框架依赖的对象配置和结果类型,拦截器等配置.
③struts-plugin.xml 该文件保存在Struts2框架的插件中:struts-Xxx-2.5.10.1.jar.由插件提供

上述三个文件时框架自带的,不能修改,只能使用。
---------------------------------------------------------
④struts.xml 该文件是web应用默认的struts配置文件.重点.配置自定义的Action和其他信息.
⑤struts.properties 该文件是Struts的默认配置文件-->可以修改default.properties 的常量配置.
⑥web.xml 该文件是Web应用的配置文件

上述三个文件是可以修改操作的。
---------------------------------------------------------
如果多个文件配置了同一个struts2 常量,则后一个文件中配置的常量值会覆盖前面文件配置的常量值.
注意:一般在struts.xml中做常量配置.

4、常见常量配置

(1)指定默认编码集,作用于HttpServletRequest的setCharacterEncoding方法和freemarker 、velocity的输出
<constantname="struts.i18n.encoding" value="UTF-8"/>

(2)指定需要Struts2处理的请求后缀,该属性的默认值是action,即所有匹配*.action的请求都由Struts2处理。如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开

<constant name="struts.action.extension" value="action,,"/>

(3)开发模式下使用,这样可以打印出更详细的错误信息
<constant name="struts.devMode" value="true" />:修改struts.xml之后,不需要重启Tomcat.

5、struts.xml配置文件元素详解

(1)package元素—— <struts>根元素的子元素

用来对多个<action>元素分类管理,和Java中的package没有关系.

①常见的属性:
name: <package>的名字
extends: 表示当前<package>继承哪一个<package>,一般都是:struts-default。而struts-default其实就是struts-default.xml中<package>元素的名字,继承struts-default之后,就拥有了该<package>定义的所有资源.(结果返回类型,拦截器..)
namespace: 表示命名空间,一般的以"/"打头.,命名一般以模块名.如: /crm, /oa. 和<action>的name决定了一个Action类的访问路径.
abstract: 抽象的,缺省值是false. 若一个<package>的abstract="true",那么该<package>中就不能再定义<action>元素,只能用来继承.

(2)action元素——<package>元素的子元素

专门用来配置Action类的,理论上一个Action类匹配一个<action>元素.
<action name="" class="" method=""/>

①常见的属性:
name: action的名称,在同一个<package>中,action的名字必须唯一. 和<package>的namespace共同决定了一个Action类的访问路径.
注意:action的name值不能以"/"打头.
class:一个Action类的全限定名. 缺省值:com.opensymphony.xwork2.ActionSupport类.


method:当前Action动作访问的方法, 缺省值:execute.
如果不填class和method,默认会找com.opensymphony.xwork2.ActionSupport类的execute方法

(3)result元素——配置结果视图

①局部结果视图:<result>定义在<action>中。优先级较高

②全局结果视图:<result>定义在<global-results>中,而<global-results>在<package>中


③常见的属性:
name:Action方法返回的逻辑视图名称. 缺省值:success
type:结果的跳转类型.该类型的值在struts-default.xml中已经预定义好了. 缺省值:dispatcher

常见的type值(结果类型):
dispatcher: 表示从Action请求转发到页面(JSP).
redirect: 表示从Action重定向到页面(JSP).
chain: 表示从Action请求转发到另一个Action.
redirectAction: 表示从Action重定向到另一个Action.


stream: 表示返回流. 文件下载时使用.

6、创建Action类的三种方式

(1)使用公共的POJO类作为Action. 提供公共的无参数的Action方法.(不推荐).

①缺点:
没有一种方式约束Action方法必须是公共的无参数的.
Action方法的返回逻辑视图名可以自定指定. 有时起名不规范. 比如:"ooxx".


(2)定义一个类,实现于com.opensymphony.xwork2.Action接口.并覆写execute方法即可.(不推荐)

①缺点: 不支持国际化,数据校验,消息机制


(3)定义一个Action类,继承于com.opensymphony.xwork2.ActionSupport类.(推荐)


7、Action多方法调用

(1)原始方式

StudentAction.java

public class StudentAction extends ActionSupport{

	private static final long serialVersionUID = 1L;
	public String list(){
		System.out.println("学生列表");
		return NONE;
	}
	public String save(){
		System.out.println("添加学生");
		return NONE;
	}
	public String delete(){
		System.out.println("删除学生");
		return NONE;
	}
	public String update(){
		System.out.println("更新学生");
		return NONE;
	}
}

Action中多个Action方法会造成<action>配置的臃肿。


(2)解决方案:
方案1: DMI:动态方法调用 :官方不推荐

格式:  action名!方法名

缺点:不安全,调用需要使用方法名。

在Struts2新的版本中,默认的关闭了DMI.若我们需要使用DMI,就需要struts.xml配置常量,启用动态方法调用.


此时:<action/>元素不需要指定method属性值.

测试:


方案2: 使用通配符的方式类配置: 通配符:*
①使用单个通配符


测试:



②使用多个通配符


测试:


8、访问ServletApi

有三种方式

(1)通过让Action类去实现感知接口(ServletRequestAware、ServletResponseAware、ServletSessionAware)

缺点:和ServletAPI藕合严重

eg:

getServletApi1Action.java

public class getServletApi1Action extends ActionSupport implements ServletRequestAware,ServletResponseAware{

	private static final long serialVersionUID = 1L;
	private HttpServletResponse resp;
	private HttpServletRequest req;
	public String execute(){
		System.out.println(req.getParameter("username"));
		return NONE;
	}
	@Override
	public void setServletResponse(HttpServletResponse resp) {
		this.resp = resp;
	}
	@Override
	public void setServletRequest(HttpServletRequest req) {
		this.req = req;
		
	}
}
②struts.xml

<struts>
	<package name="getServletPkg" extends="struts-default"
		namespace="/getServlet">
		<action name="api1" class="action.getServletApi.getServletApi1Action">
		</action>
	</package>
</struts>
③测试:



实现原理:

通过拦截器实现



(2)使用ServletActionContext类,该类提供很多静态方法可以返回Servelet API对象

eg:

①getServletApi2Action.java

public class getServletApi2Action extends ActionSupport {

	private static final long serialVersionUID = 1L;
	public String execute() {
		HttpServletRequest req = ServletActionContext.getRequest();
		req.setAttribute("requestName","requestVal");
		HttpSession session = ServletActionContext.getRequest().getSession();
		session.setAttribute("sessionName", "sessionVal");
		ServletContext context = ServletActionContext.getServletContext();
		context.setAttribute("contextName","contextVal");
		return SUCCESS;
	}
}

②struts.xml

<struts>
	<package name="getServletPkg" extends="struts-default"
		namespace="/getServlet">
		<action name="api2" class="action.getServletApi.getServletApi2Action">
		<result>/views/getServletApi/getServlet.jsp</result>
		</action>
	</package>
</struts>

③getServlet.jsp

<h3>使用ServletActionContext</h3>
<hr>
request:${requestName}
<br>
session:${sessionName}
<br>
servletContext:${contextName}
<br>
④测试:


(3)使用ActionContext类,本身是Struts2对Servlet API的封装.(推荐使用)

ActionContext:——Action的环境对象,每一次请求都是一个新的Action对象,一个ActionContext对象封装了这一次请求的相关数据.
ActionContext使用了ThreadLocal模式,所以说是线程安全的.

eg:

①getServletApi3Action.java

public class getServletApi3Action extends ActionSupport{

	private static final long serialVersionUID = 1L;
	public String execute(){
		ActionContext context = ActionContext.getContext();
		context.put("requestKey","requestValue");
		context.getApplication().put("appKey","applicationVal");
		context.getSession().put("sessionKey","sessionValue");
		return SUCCESS;
	}
}

②struts.xml

<struts>
	<package name="getServletPkg" extends="struts-default"
		namespace="/getServlet">
		<action name="api3" class="action.getServletApi.getServletApi3Action">
		<result>
			/views/getServletApi/getServlet.jsp
		</result>
		</action>
	</package>
</struts>

getServlet.jsp

<h3>使用ActionContext</h3>
<hr>
request:${requestKey}
<br>
session:${sessionKey}
<br>
servletContext:${appKey}
<br> <hr>
④测试:


9、Action获取请求参数

两种方式:

(1)Action本身作为Model对象,通过setter方法封装(属性注入)

①把Action本身作为一个领域模型;
②要求页面提交的参数名称和Action中对应属性名称相同(只需要有属性的setter方法即可),但是如果把Action本身当成模型,则也需要提供相应的getter方法;
③该功能是由拦截器完成的;并且自带类型转换;
④在Servlet中,因为线程安全的问题,不能在Servlet中定义成员变量;但是在Struts2中,Action是每次请求都重新创建,所以肯定在Action中定义模型属性;
优点:简单;缺点:如果模型参数过多,Action中的属性会非常多,就会把模型和业务混淆在一起;
eg:

①GetParameterAction.java

public class GetParameterAction extends ActionSupport {
	private static final long serialVersionUID = 1L;
	
	private String username;
	private String password;
	@Override
	public String execute() throws Exception {
		System.out.println("username:"+username);
		System.out.println("password:"+password);
		
		return NONE;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getUsername() {
		return username;
	}
	public String getPassword() {
		return password;
	}
}
②struts.xml

<struts>
	<package name="getparamPkg" extends="struts-default" namespace="/">
		<action name="login1" class="action.getParam.GetParameterAction"/>
	</package>
</struts>
③getParam.jsp

<fieldset>
	<legend>Action本身作为Model对象,通过setter方法封装</legend>
	<form action="${pageContext.request.contextPath}/login1" method="post">
		账户:<input type="text" name="username"><br> 密码:<input
			type="text" name="password"><br> <input type="submit"
			value="登陆">
	</form>
</fieldset>
④测试:


(2)创建独立Model对象,页面通过ognl表达式封装(属性注入)

两种写法:
i.一个字段,并提供对应的getter和setter
ii.一个字段,action自己new出来,并提供getter方法
优点:action和model责任分离;缺点:页面必须按照和domain一致的规则来写;
①User.java

public class User {
	private String age;
	private String username;
	private String password;
	
	public String getAge() {
		return age;
	}
	public void setAge(String age) {
		this.age = age;
	}
	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 + "]";
	}
}
②GetParameterAction2.java

public class GetParameterAction2 extends ActionSupport {
	private static final long serialVersionUID = 1L;
 
	private User user;
       //自己new出来,并提供getter方法
       //private User user = new User();
       @Override
	public String execute() throws Exception {
		System.out.println("username:  "+user.getUsername());
		System.out.println("password: "+user.getPassword());
		System.out.println("age: "+user.getAge());
		return NONE;
	}
	public void setUser(User user) {
		this.user = user;
	}
	public User getUser() {
		return user;
	}
}
③struts.xml

	<package name="getparamPkg" extends="struts-default" namespace="/">
		<action name="login2" class="action.getParam.GetParameterAction2"/>
	</package>
④getParam.jsp

 <fieldset>
	<legend>创建独立model对象,页面通过ognl表达式封装</legend>
	<form action="${pageContext.request.contextPath}/login2" method="post">
		账户:<input type="text" name="user.username"><br> 密码:<input
			type="text" name="user.password"><br> <input type="submit"
			value="登陆">
	</form>
</fieldset>
⑤测试



注意


如果Action中没有user的getter方法会出现什么情况?

针对两种写法:
i.一个字段,并提供对应的getter和setter

以该例子注入username为例,找到user.username,在Action类中寻找user属性,判断user是否为空,若为空则创建一个,调用setUser方法,然后调用user.setUserName方法注入数据到user模型。然后继续处理user.password,判断user是否为空,若为空则创建一个,此时如果没有提供getter方法,则无法取得user对象,继续创建,那么前面注入的数据将会丢失。

ii.一个字段,action自己new出来,并提供getter方法

此时无需setUser方法,因为已经自行创建(user不为空)但仍然需要提供getter方法,否则无法取出user对象,设置值或取出值无法进行。


猜你喜欢

转载自blog.csdn.net/ack_finding/article/details/78882370
今日推荐