Struts2框架---21

Struts2框架---21

工作原理图


最近的过滤器,StrutsPrepareAndExecuteFilter

一 工作原理

在Struts2框架中的处理大概分为以下几个步骤 1 客户端初始化一个指向Servlet容器(例如Tomcat)的请求 2 这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助,例如:SiteMesh Plugin) 3 接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper来决定这个请是否需要调用某个Action 4 如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy 5 ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类 6 ActionProxy创建一个ActionInvocation的实例。 7 ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。 8 一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可 能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。在表示的过程中可以使用Struts2 框架中继承的标签。在这个过程中需要涉及到ActionMapper

二 工作流程

1、客户端浏览器发出HTTP请求. 2、根据web.xml配置,该请求被FilterDispatcher接收 3、根据struts.xml配置,找到需要调用的Action类和方法, 并通过IoC方式,将值注入给Action 4、Action调用业务逻辑组件处理业务逻辑,这一步包含表单验证。 5、Action执行完毕,根据struts.xml中的配置找到对应的返回结果result,并跳转到相应页面 6、返回HTTP响应到客户端浏览器
 

Struts2核心文件

web.xml

任何MVC框架都需要与Web应用整合,这就不得不借用于web.xml文件,只有配置web.xml文件中Servlet才会被应用加载
Model2:JSP+JavaBean+Servlet
通常,所有MVC框架都需要Web应用加载一个核心控制器,对于Struts2框架而言,需要加载StrutsPerpareAndExecuteFilter,只负责Web应用加载StrutsPerpareAndExecuteFilter,StrutsPerpareAndExecuteFilter将会加载Struts2框架遇到.acton文件就会拦截并进行处理

struts.xml

struts2的核心配置文件,在开发过程中利用率最高。 该文件主要负责管理Action的映射,以及该Action包含的Result定义等。
struts.xml中包含的内容:
1、全局属性
2、用户请求和相应Action之间的对应关系3、Action可能会用到的参数和返回结果4、各种拦截器的配置

struts.properties

struts2框架的全局属性文件,自动加载和strusts.xml在一个路径该文件包含很多key-value键值对。这个文件可以不要,可以在structs.xml中进行配置,使用constant元素可以替换
struts.xml文件模板
struts.xml模版:
<?xml version="1.0" encoding="UTF-8" ?>
//.dtd就是约束struts.xml中可以有哪些标签不能有哪些标签
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
//可以通过 <include file=“”>包含其他文件
//可以把每个功能模块独立到一个xml配置文件中,然后用Include节点引用
	<include file=""></include>
//<package>
//package提供了将多个Action组织成为一个模块的方式
//package的名字必须是唯一的,可以在这个包上加一些拓展的包
//<package name="包名" extends="继承的父类的名称" 
//abstract设置package的属性为抽象,抽象的package不能定义action的值,ture或false
//namespace 包的命名空间>
	<package name="" extends="" namespace="" abstract="" externalReferenceResolver="">		
			   <interceptors>//为拦截器,可以为拦截器定义name(名称)和class(类路径)			<interceptor name="" class=""></interceptor>
			<interceptor-stack name="">//拦截器栈
				<interceptor-ref name=""></interceptor-ref>
			</interceptor-stack>
		</interceptors>
		
		<default-interceptor-ref name=""></default-interceptor-ref>//定义默认的拦截器,每个Action都会自动引用如果
		<!-- 全局results配置,在包里的都可以引用-->
		<global-results>
			<result name="input">/xxx.jsp</result>
			<result name="error">/xxx.jsp</result>
			</global-results>
		<!-- 可以定义多个Action
		name:action名称Http://localhost:8080/projectName/test/hello.action
			class:对应的类的路径
			method:调用Action中的方法名
		-->
		 <action name="hello" class="" method="" converter="">
		 	<interceptor-ref name=""></interceptor-ref>
		 	
		 	<result name="" type="">/xxx.jsp</result>
		 	
		 	<param name="">值</param>
		 </action>
	</package>
	//常量的定义:等同于在struts2配置:struts.i18n.reload=ture
	<constant name="struts.i18n.reload" value="ture"></constant>
</struts>
=================================================================

Action搜索顺序:

http://localhost:8080/product_one/hellowworld.jsp可以进入result.jsp页面
http://localhost:8080/product_one/aaa/ddd/ccc/hellowworld.jsp也可以进入result.jsp页面
Action搜索顺序:
http://localhost:8080/struts2/path1/path2/path3/student.action
第一步:判断package是否存在,如:path1/path2/path3/

如果package存在
第二步:则判断该package中action是否存在,如果不存在则去默认namespace的package里面寻找action
第三步:如果没有,则报错

如果package不存在:
第二步:检查上一级路径的package是否存在(直到默认namespace),重复第一步
第三步:如果没有则报错

 如果请求为/login.action,系统会根据根命名空间("/")中查找名为login的Action,如果在根命名空间中找到了名为login的Action,则该Action处理用户的请求;否则系统将转为在默认命名空间中寻找名为login的Action,如果默认的命名空间中有名为login的Action,则由该Action处理用户的请求。如果两个命名空间中都找不到名为login的Action,那么系统将出现错误。

      注意:命名空间只有一个级别。如果请求的URL是/bookservice/search/get.action系统将先在/bookservice/search的命名空间下查找名为get的Action,如果在该系统命名空间内找到名为get的Action,则由该Action处理该用户的请求;如果在该命名空间中没有找到名为get的Action,系统将直接进入默认的命名空间中查找名为get的Action,而不会在bookservice的命名空间下查找名为get的Action。
可以多个包使用同一个命名空间,但是相同的命名空间相当于同一个模块,也就是同一个包。
一个包中可以有name值相同的action,但是后面的action会把前面同名的action覆盖掉
=========================================================================

Action动态方法调用的三个方式:

(动态方法调用就是为了解决一个Action对应对个请求的处理,以免Action太多)

1)指定method属性;

有一个jsp就要增加有个action,比较麻烦;
<action name="add" method="add" class="com.imooc.action.HelloWorldAction"> <result>/add.jsp</result> </action>

2)感叹号方式(不推荐);

先在package外面添加:<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant> <action name="helloworld" class="com.imooc.action.HelloWorldAction"> <result>/reuslt.jsp</result> <result name="add">/add.jsp</result> </action> 访问add方法则地址最后目标改为:helloworld!add.action

3)通配符方式。(推荐方式)

第一个*代替{1},第二个*代替{2},result里的name是Action的返回值,action的里method是Action里的方法名,调用某个方法时最后目标就输入 {1}_{2}.action;这样可以访问多个Action里的方法 <action name="*_*" method="{2}" class="com.imooc.action.{1}Action"> <result>/result.jsp</result> <result name="add">/{2}.jsp</result> <result name="update">/{2}.jsp</result> </action> 浏览器地址: http://localhost:8080/HelloWorld/HelloWorld_add.action,则请求的是add.jsp 此方式可以灵活运用,可以用于class的包名、类名、以及Action的name属性中占位
=============================================================================

指定多个配置文件:

1、如果有很多个Action的配置文件,则需要在struts.xml中使用
<include file="XXXX.xml"/>来包含其他的配置文件
2、struts文件中添加<constant name="struts.i18n.encoding" value="UTF-8">
</constant>以防乱码问题的出现

配置文件和struts.xml的格式如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
 "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
<package name="default" namespace="/">
<action name="*_*" method="{2}" class="com.imooc.action.{1}Action">
<result>/result.jsp</result>
<result name="add">/{2}.jsp</result>
<result name="update">/{2}.jsp</result>
</action>
</package>
</struts>
==========================================================================

默认action:

//声明默认action <default-action-ref name="actionName"></default-action-ref> //定义默认action <action name="actionName" method="..." class="..."> <result>objective.jsp</result> </action>
============================================================================

struts2后缀:

三种方式: 1.struts.properties中:struts.action.extension=action,do,struts2 2.xml中增加常量constant: <constant name="struts.action.extension" value="action,do,struts2"></constant> 3.在过滤器中配置init-param参数: <init-param> <param-name>struts.action.extension</param-name> <param-value>do,action,strtus2</param-value> </init-param>
================================================================================

action接收JSP页面传输的参数:

【1、使用action类的属性接收参数:

a.在action类中定义成员变量,并添加get、set方法; b.在JSP页面中Form表单的Action属性指向对应的action,input控件的name属性和Action类中定义的成员变量一致。

【2、使用DomainModel接收参数:

a.创建一个实体javaBean类,定义成员变量,并添加get、set方法; b.在action类中以之前创建的实体类(如user)作为成员变量,并添加get、set方法,此实体类不需要实例化对象; c.在JSP页面中Form表单的Action属性指向对应的action,input控件的name属性需要指定到实体类的属性(如name=user.username);

<!-- 使用DomainModel接收参数 -->
@login.jsp
<form action="LoginAction.action" method="post">
    	用户名:<input name="user1.user" type="text" />
    	密码:<input name="user1.pwd" type="password" />
    	<input value="提交" type="submit" />
</form>

@LoginAction.java
public class LoginAction extends ActionSupport {
	private User user1;
	
	public User getUser1() {
		return user1;
	}

	public void setUser1(User user1) {
		this.user1 = user1;
	}

	public String login(){
		System.out.println(user1.getUser());
		System.out.println(user1.getPwd());
		return SUCCESS;
	}
}

@struts.xml
<action name="LoginAction" class="com.imooc.action.LoginAction" method="login">
<result>/success.jsp</result>
</action>

@User.java
public class User {
	private String user;
	private String pwd;
	public String getUser() {
		return user;
	}
	public void setUser(String user) {
		this.user = user;
	}
	public String getPwd() {
		return pwd;
	}
	public void setPwd(String pwd) {
		this.pwd = pwd;
	}
}

【3、使用ModeDriven接收参数(推荐):

1使用ModelDriven<T>接口,这个action必须实现这个接口的public T getModel()方法。
2此时声明的属性必须实例化,eg: private User user = new User(); 同时不需要getter和setter。
3前端的name也只需要写username和password就可以,不需要再加域了。这种方法时最推荐的方法,因为可以减少前后端的耦合
<!-- 使用ModelDriven接收参数(推荐) -->
@login.jsp
<form action="LoginAction.action" method="post">
用户名:<input name="user" type="text" />
密码:<input name="pwd" type="password" />
书籍1:<input name="bookList[0].user" type="text" />
书籍2:<input name="bookList[1].user" type="text" />
<input value="提交" type="submit" />
</form>

@LoginAction.java
public class LoginAction extends ActionSupport implements ModelDriven<User>{
private User user1 =new User();	
public String login(){
System.out.println(user1.getUser());
System.out.println(user1.getPwd());
System.out.println(user1.getBookList().get(0).getUser());
System.out.println(user1.getBookList().get(1).getUser());
return SUCCESS;
}
public User getModel() {
return user1;
}
}

@struts.xml
<action name="LoginAction" class="com.imooc.action.LoginAction" method="login">
<result>/success.jsp</result>
</action>

@User.java
public class User {
	private String user;
	private String pwd;
private List<User> bookList;
	//setter/getter...
}

注意:request方式接收参数也行。
======================================================================

Action中5种内置属性

(1) SUCCESS :Action正确的执行完成,返回相应的视图,success是name属性的默认值。 (2) NONE :表示Action正确的执行完成,但并不返回任何事视图。 (3) ERROR : 表示Action执行失效,返回错误处理视图。 (4) LOGIN : Action因为用户没有登录的原因没有正确执行,将返回该登录视图,要求用户进行登录验证 (5) INPUT : Action的执行,需要从前端界面获取参数,INPUT就是代表这个参数输入界面,一般在应用中,会对这些 参数进行验证,如果验证没有通过,将自动返回该视图。


结果类型input的效果

* 1.当参数类型转换错误时,如age输入框中的类型是字母等情况,方法自动返回input * 2.当action中存在addFiledError时: * 1)addFileError放在一般执行方法,addFieldError("", "");语句后面有返回input的语句 * 2)addFileError放在validate()中 *3.FileError的表现形式: * 在jsp页面中使用<s:fielderror/>标签,该标签name属性为addFieldError方法中的参数fieldName,在jsp页面中使用struts标签, * 需要导入标签库 语句:<%@ taglib prefix="s" uri="/struts-tags" %>
相关代码——(上):
@LoginAction.java
public class LoginAction extends ActionSupport implements ModelDriven<User>{
	private User user1 =new User();
	
	public String login(){
		
		/*if(user1.getUser()==null||"".equals(user1.getUser())){方法一
			this.addFieldError("error_user", "用户名不能为空!");
			return INPUT;
		}*/
		
		System.out.println(user1.getUser());
		System.out.println(user1.getPwd());
		System.out.println(user1.getBookList().get(0).getUser());
		System.out.println(user1.getBookList().get(1).getUser());
		System.out.println(user1.getAge());
		return SUCCESS;
	}

	public User getModel() {
		return user1;
	}
	
	@Override
	public void validate() {//方法二:推荐
		if(user1.getUser()==null||"".equals(user1.getUser())){
			this.addFieldError("error_user", "用户名不能为空!");
}
}
}
相关代码——(下):
@User.java
public class User {
private String user;
private String pwd;
private int age;
private List<User> bookList;
//setter/getter...
}

@login.jsp
<%@ taglib prefix="s" uri="/struts-tags" %>
<form action="LoginAction.action" method="post">
    	用户名:<input name="user" type="text" /><s:fielderror name="error_user"></s:fielderror>
    	密码:<input name="pwd" type="password" />
    	书籍1:<input name="bookList[0].user" type="text" />
    	书籍2:<input name="bookList[1].user" type="text" />
    	年龄:<input name="age" type="text" />
    	<input value="提交" type="submit" />
</form>
==============================================================================

8.处理结果类型-

result标签下还有param标签:

1)location:该属性定义了该视图对应的实际视图资源 2)parse:该参数指定是否可以再实际视图名字中使用OGNL表达式,默认值为TRUE,支持OGNL(Object-Graph Navigation Language)表达式 ognl表达式可以在jsp页面去写,也可以在struts2页面中去写,在实际开发中是不常用的,默认情况下ognl是允许的,是打开状态 <param name="parse">true</param> <param name="location">...地址</param>

result标签根据位置不同,分为两种:

全局结果:需要在一个包下面,如: <package name=""> <global-result> <result name=""></result> </global-result> </package>
==================================================================================

自定义拦截器:

1.方法一:实现Interceptor接口

-void init():初始化拦截器所需资源 -void destroy() :释放在init()中分配的资源 -String intercept(ActionInvocation ai)throws Exception 实现拦截器功能,利用ActionInvocation参数获取Action状态,返回result字符串作为逻辑视图。

2.方式二:继承AbstractInterceptor类

-提供了init()和destroy() 方法的空实现 -只需要实现intercept方法即可 实际开发当中一般会去继承AbstractInterceptor这个父类

新建拦截器的步骤:

1. 建立一个拦截器类继承自AbstractInterceptor类,并实现intercept方法 invocation.invoke()方法调用下一个拦截器,如果已经是最后一个拦截器,则执行目标action 2. 在strut的配置文件的package中注册拦截器,注册拦截器在action调用之前,在响应的action配置中,通过interceptor-ref标签来引用拦截器

Struts2内置常用的拦截器:

1.params拦截器:

-负责将请求参数设置为Action属性

2.staticParams拦截器:

-将配置文件中action元素的子元素param参数设置为Action属性

3.servletConfig拦截器:

-将源于Servlet API的各种对象注入到Action,必须实现对应接口

4.fileUpload拦截器:

-对文件上传提供支持,将文件和元素设置到对应的Action属性,实际上内部依然使用了Commons-FileUpload组件。

5.exception拦截器:

-捕获异常,并且将异常映射到用户自定义的错误页面

6.validation拦截器:

-调用验证框架进行数据验证 更多的拦截器可在struts核心包的struts-default.xml中查看

默认拦截器栈:

<!-- 为Action显示引用拦截器后,默认的拦截器defaultStack不再生效,需要手工引用。而且从顺序角度去讲,最好把默认的拦截器写在自定义拦截器上面 --> <interceptor-ref name="defaultStack"></interceptor-ref>
=============================================================================

下面是4个开发模式常用配置的简介---

<!-- 开启使用开发模式,详细错误提示 --> <!-- <constant name="struts.devMode" value="true"/>--> <!-- 指定每次请求到达,重新加载资源文件 --> <!-- <constant name="struts.i18n.reload" value="true"/>--> <!-- 指定每次配置文件更改后,自动重新加载 --> <!-- <constant name="struts.configuration.xml.reload" value="true"/>--> <!-- 指定XSLT Result使用样式表缓存 --> <!-- <constant name="struts.xslt.nocache" value="true"/>-->
===============================================================================
4.定义拦截器,判断用户是否已经登录.此拦截器在跳转的action中引用.
在拦截器的intercept(ActionInvocation arg0)方法中通过获取session对象(三种方式其中一种),判断session里面是否存在登录成功的那个属性,即loginsuccess,来判断用户是否登录成功.
如果loginsuccess属性不为空,则直接调用arg0的invoke()方法,此方法返回字符串与在执行action方法中返回的字符串一致.(引用了该拦截器的action),直接返回这个字符串即可.
如果判断用户未登录,则直接返回"login",表示用户需要登录.那么在此action中也要配置一个<result name="login">login.jsp</result>,当直接访问未登录时,便会跳转到登录页面.
拦截器与Action方法里的返回值,即return,都会与struts.xml中的result结果集进行匹配.拦截器可以在访问Action之前,进行一些操作.
整个项目结果:通过login.jsp登录,当登录成功便自动跳转到管理页面,否则跳转到登录页面.
当直接访问跳转到后台的action时,如果用户登录了,便会跳转到后台管理页面,未登录的话则跳转到登录页面.

相关代码——(上):
@LoginAction.java
public class LoginAction extends ActionSupport implements SessionAware{
	private String user;
	private String pwd;
	private Map<String,Object> session;
	public void setSession(Map<String, Object> session) {
this.session=session;
}
	//setter/getter...
	public String login(){
		if("admin".equals(user)&&".".equals(pwd)){
			session.put("session_user", user);
return SUCCESS;
}else{
session.put("session_error", "用户名或密码不正确!");
return ERROR;
}
}
}

@AuthInterceptor.java
public class AuthInterceptor extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation invocation) throws Exception {
ActionContext context=ActionContext.getContext();
Map<String , Object> session=context.getSession();
if(session.get("session_user")!=null){
String result=invocation.invoke();
return result;
}else{
return "login";
}
}
}
相关代码——(中):
@struts.xml
<struts>
<package name="default" extends="struts-default" namespace="/">
<!-- 注册拦截器 -->
<!-- Ps:拦截器栈内的拦截器(除了默认拦截器)的name要与拦截器栈外的拦截器要一致,因为引用拦截器栈的时候,里面的拦截器是从外面的拦截器中的class引用的 -->
<interceptors>
<interceptor name="AuthI" class="com.imooc.interceptor.AuthInterceptor"></interceptor>
<!-- 自定义拦截器mystack:组合了defaultStack和AuthI -->
	<interceptor-stack name="mystack"> 
		<interceptor-ref name="defaultStack"></interceptor-ref>
		<interceptor-ref name="AuthI"></interceptor-ref>
	</interceptor-stack>
</interceptors>
		
<!-- 通过此Action访问后台管理页面,需要判断用户是否已登录,如果未登录则跳转到登录页面 -->
		<action name="Auth">
			<result>/WEB-INF/page/manager.jsp</result>
			<result name="login">/login.jsp</result>
			<!-- 引用自定义的拦截器 -->
			<interceptor-ref name="mystack"></interceptor-ref>
		</action>
		
		<action name="Login" class="com.imooc.action.LoginAction" method="login">
			<result>/WEB-INF/page/manager.jsp</result>
			<result name="error">/login.jsp</result>
		</action>
	</package>
</struts>
相关代码——(下):
@login.jsp
信息:${session_error}
<form action="Login" method="post"><!-- 默认情况下:Login.action或Login都行。 -->
用户名:<input name="user" type="text" />
密码:<input name="pwd" type="password" />
<input value="Login" type="submit" />
</form>

@manager.jsp
后台管理页面。只有已登录的用户才能访问!










 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值