您的位置:首页 > 编程语言 > Java开发

【JavaWeb-15】Struts2环境配置、入门案例、执行流程、package、action、result详解

2016-09-29 16:31 881 查看
1、Struts2的历史在此不多说,它是Apache和别人共同开发的,下载的话,可以去Apache的官网。它是用来管理MVC的,也就是项目的表现层。它怎么来管理呢,核心控制器是一个过滤器,所以我们需要在web.xml中配置这个过滤器。

2、配置环境。

——我们先拷贝jar。我们打开Struts2文件夹,里面的lib包含了很多jar包,但是我们并不需要所有的jar包。所以我们就找到它里面有一个struts-blank的war项目模板,解压缩后找到里面的lib里的jar包,这是最核心的必需的jar包。拷贝到我们的项目lib目录里面。



——写配置文件。在src目录下创建特定名称的xml文件(是不是和配置C3P0xml文件时类似?),叫struts.xml。在里面写什么呢?找一个模板先把约束照抄下来,然后写个最大层级。我们一写那个struts标签之后发现这个xml文件前面变成了一个设置的蓝色icon。



——去哪里找struts.xml的模板?还是去struts2的blank模板里面找,按照我们创建这个xml的习惯,别人肯定也是放在src里面的。



——第三步就是配置这个核心控制器,也就是一个过滤器。在web.xml中配置。不会配置,照抄。增加如下代码:

<filter>
<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>


——配合,启动,没有报错,说明配置环境就搭建好了。接下来就是在struts.xml里面写具体的代码了。

3、第一个案例。



——我们在
struts.xml
中写了上面的代码。这段代码的意思是:我们的struts核心控制器(也就是我们在web.xml中配置的那个过滤器)默认是拦截所有请求的(是
/*
)。拦截的请求是默认带后缀action的,比如这里的hello.action,拦截之后它只拿到后缀前面的名字(hello),然后到这个
struts.xml
文件中找对应的action,找到后就去后面的class找对应的method去执行。可以看到这个方法的执行结果是返回一个
success
字符串。然后再回到
struts.xml
里这个action里,找对应的result,找到一个name是success的result,然后执行result里面的跳转等操作。

package com.hello.web.action;

public class HelloWorld {
public String hello(){
System.out.println("我是hello方法,我被执行了。");
return "success";
}
}


——这里需要注意的是,我们的请求可以不添加action后缀,直接写hello。

<a href="${pageContext.request.contextPath }/hello.action">有action的hello</a>
<br>
<a href="${pageContext.request.contextPath }/hello">没有action的hello</a>


——这里模仿的就是我们之前经常写的判断和跳转。比如我们针对用户模块,有增删改查用户,那我们可以把连接变成:

localhost:8080/Day01_Hello/user?op=add
localhost:8080/Day01_Hello/user?op=del
localhost:8080/Day01_Hello/user?op=update
localhost:8080/Day01_Hello/user?op=select


然后,我们增加servlet里面拦截所有的/user,拦截下来获取参数,再判断是哪个参数,跑去执行对应的方法。

param=request.getParameter("op");
if("add".equal(op)){
}else if("del".equal(op)){
}
……


——我们这里的请求URL后面的hello就相当于之前写的op=xxx的这个xxx参数,然后我们在struts.xml里面直接配置以下就让它去执行什么类什么方法执行完去哪里,就不需要我们在servlet里面拦截获取参数判断执行等操作了。

——服务器启动的时候,先加载web.xml配置文件,然后加载struts.xml配置文件了。所以我们发出请求的时候,因为web.xml里面有过滤器并且已经加载了,所以就交由过滤器处理(就是我们struts的核心控制器),然后它根据name去找struts.xml,找到对应的action,找到之后将这个action实例化,调用对应的类里面的方法,得到返回值,再判断返回值与result的name比较,做最后的跳转等操作。



4、配置文件的加载顺序。

——最开始是default.properties文件,里面有一些是否开启开发模式,如果开启的话,修改配置文件后不需要重启。还有比如后缀.action也是在这里面定义的。

——然后加载的是struts-default.xml文件。

——然后是struts-plugin.xml文件。

——然后是struts.xml,这就是我们创建的文件。我们一般修改配置信息就在这里修改。

——然后是struts.properties。其实和struts.xml一样,但是我们一般不用这个,而是用上面的struts.xml。

——最后是加载web.xml,在这里我们也可以修改配置文件。

——后面的加载文件里面的配置如果重复的话会覆盖之前文件里面的配置。所以我们一般就是在struts.xml里面修改配置。比如我们在struts.xml里面修改成了开发者模式、把后缀从action改成do了:

<struts>
<constant name="struts.devMode" value="true"></constant>
<constant name="struts.action.extension" value="do"></constant>
……
</struts>


——如果我们要测试的话,可以在
struts.properties
web.xml
里面再修改后缀名称,然后测试,点击这样的请求看看是不是可以进入到过滤器里面。在properties文件里面是这样的:

struts.action.extension=abc


或者在web.xml里面是这样的:

<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
<init-param>
<param-name>struts.action.extension</param-name>
<param-value>do</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>


5、package讲解。

——name是唯一的,不能重名。

——我们可以看到package是按照面向对象的思想来管理的。因为它还有继承extends。

——package可以被定义为抽象包,也就是增加一个属性abstract=”true”,抽象包里面是不能定义action的,只能被用来继承,这也是面向对象的思想。

——namespace,命名空间。如果设置了命令空间,那么访问路径就变成了
命名空间+动作名称
。我们之前的案例里面是没有写的,所以它的默认值是空字符串
""
,而不是
"/"
,需要注意。

——命令空间的搜索原理。比如我们增加了一个命名空间
namespace="/user"
,那么我们访问URL就应该变成
localhost:8080/user/hello.action
,它的搜索原理是这样的:拿到这个url之后,把应用名后面的路径分成两部分,动作名称
hello.action
和命名空间
/user
,然后去找是否有
/user
命名空间,如果有的话,那么就进入到对应的package,然后查找对应的action等等。

——这里面有一个问题就是,如果我们把上面的url写成
localhost:8080/user/new/hello.action
的话,是否有效?结论是依然有用,因为这时候命名空间是
/user/new
,如果找不到的话,就网上追溯,也就是查找
/user
,找到后和上面步骤类似,如果还是找不到,继续向上就是根目录
/
了,如果还找不到,那么就返回错误。

——所以我们可以看看
localhost:8080/new/user/hello.action
是错误的,因为先查找
/new/user
,找不到就找
/new
,找不到就找
/
,最终肯定是找不到我们的hello的,所以会出错。

——那如果我们找到了对应的命名空间,但是这个空间里面没有对应的action,怎么办?答案是没有对应的action就去默认的命名空间里面去找,注意默认的命名空间就是
namespace=""
或者就是我们没有写
namespace
的那个package(再次强调,默认的和根目录”/”不要搞混)。

6、action的讲解。

——action对应着的就是一个处理类和里面的方法。我们之前自己写了一个类,然后在里面写了个方法。其实,还有另外两种创建动作类的方法。

——让我们的类实现Action方法,当然需要实现里面的execute方法,这就是我们的默认执行方法,这个方法可以返回SUCCESS、ERROR、INPUT、LOGIN、NONE等参数(被定义为常量了,可以直接使用)。

package com.hello.web.action;

import com.opensymphony.xwork2.Action;

public class Action1 implements Action {

public String execute() throws Exception {
return SUCCESS;
}

}


——还有一个方法是我们继承一个已经实现Action接口的类,叫ActionSupport。在这个类里面它实现了Action接口的execute方法,所以我们继承这个方法的时候可以不写这个方法(直接用继承过来的)。如下:

package com.hello.web.action;

import com.opensymphony.xwork2.ActionSupport;

public class Action2 extends ActionSupport {

}


所以我们在struts.xml中就可以省略method方法了:

<action name="hello" class="com.hello.web.action.Action2">
<result name="success">/success.jsp</result>
</action>


——上面这种方式是我们常用的创建动作类的方法,就是继承ActionSupport。还有一个极品的就是我们其实在action中不仅可以省略method还可以省略class,只保留一个name就行,那么它会去执行默认的类,这个类是在struts-default.xml中配置的。当然,我们原则上是可以在struts.xml中修改这个默认类,但是我们一般不需要这么做。

7、动态方法调用不太安全,所以默认是关闭的。

——我们一般的操作就是创建一些action。

<action name="addUser" class="com.hello.web.action.UserAction" method="addUser">
<result name="success">/addUsersuccess.jsp</result>
</action>
<action name="delUser" class="com.hello.web.action.UserAction" method="delUser">
<result name="success">/delUsersuccess.jsp</result>
</action>


——创建一个继承自ActionSupport的UserAction类。在里面写对应上面的几个方法。

public class UserAction extends ActionSupport {
public String addUser(){
return SUCCESS;
}
public String delUser(){
return SUCCESS;
}
}


——然后,用户访问
localhost:8080/Day01/addUser.action
,通过action找到对应的类和对用的方法进行执行。

——我们可以利用通配符
*
来简化多个action的写法。比如我们只写了1个action。

<action name="*" class="com.hello.web.action.UserAction" method="{1}">
<result name="success">/{1}success.jsp</result>
</action>


——这里的通配符代替了我们的name,也就是代替了我们在url里面写的action名称,比如我们访问的是
localhost:8080/Day01/addUser.action
,那么这个通配符
*
就表示addUser,后面我们用{1}来表示第一个通配符也就是addUser,然后在对应的地方都可以替换掉。同样的如果访问的是
localhost:8080/Day01/delUser.action
,那么
*
就表示delUser,{1}表示第一个
*
,也就是是delUser。那么既然有{1},那就有{2}{3}等等,比如我们的action名字和方法名字不一致的时候可以用多个来拼接。

——比如我们访问的是
localhost:8080/Day01/add_User.action
,那么上述的通配符就不灵了,但我们可以修改成如下:

<action name="*_*" class="com.hello.web.action.UserAction" method="{1}{2}">
<result name="success">/{1}{2}success.jsp</result>
</action>


——就是说那
*_*
来代替
add_User
,那么第一个
*
表示add,第二个
*
表示User,那么我们的方法名字是addUser,那么就用
{1}{2}
来拼接成一个addUser即可。

——但是,如你所见,如果我们的url中的动作名称和方法不一致的时候,还是有些麻烦。所以更进一步,我们可以用动态方法调用来说实现。既然是动态方法调用,也就是我们其实没有把方法写死,而是根据url来调用,所以我们在action里面没有配置method:

<action name="user" class="com.hello.web.action.UserAction">
<result name="success">/success.jsp</result>
</action>


——上面的name是user,也就是说我们的访问url应该是user.action才有用,但是我们在user.action上增加些小动作,这个小动作就是我们动态的方法名字,规则是这样写的
user!addUser.action
。完整路径比如说
localhost:8080/Day01/user!addUser.action
,这个时候它就自动找到name叫做user的action,然后一看这个action没有指定的方法而url里面
!
后面有一个指定的方法,然后就去action对应的类里面去找这个方法了。这就是动态方法调用的流程和原理。

——但是动态方法调用的URL实在太难看,而且不安全,所以struts2是默认关闭的,我们如果要使用上面这种动态方法调用的方式,还需要开启,如果不开启的话,上面那种方法是没有用的,开启就是在struts.xml里面配置。

<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>


8、下面我们说说result。默认的result跳转是转发。也就是说我们看到虽然浏览器跳转到了success.jsp,但是是利用dispatcher方式,我们看那个URL就发现了URL没有改变。



——当然,我们可以修改它的类型type。如:

<result name="success" type="redirect">/success.jsp</result>


然后我们输入
http://localhost:8080/Day01_StrutsTemplate/action1.action
后,发现URL地址变成了
http://localhost:8080/Day01_StrutsTemplate/success.jsp


——除了这两种方式之外,还有2种重要的跳转。当然这个跳转不是跳转到某个jsp了,而是在action之间跳转。

——比如在同一个包(命名空间)里面的action互相跳转。一个是chain(转发跳转action),一个是redirectAction(重定向跳转action)。我们写了如下代码,是转发跳转到另一个action2的。输入
http://localhost:8080/Day01_StrutsTemplate/action1.action
,最终页面成功,URL还是这个没变。

<action name="action1" class="com.hello.web.action.Action2">
<result name="success" type="chain">action2</result>
</action>
<action name="action2">
<result name="success">/success.jsp</result>
</action>


——同一个包下面利用重定向在不同action之间跳转试试。输入的URL变成了
http://localhost:8080/Day01_StrutsTemplate/action2.action


<action name="action1" class="com.hello.web.action.Action2">
<result name="success" type="redirectAction">action2</result>
</action>
<action name="action2">
<result name="success">/success.jsp</result>
</action>


——我们结合result里面的重定向到jsp试试,变成下面的代码了,结果网址变成了
http://localhost:8080/Day01_StrutsTemplate/success.jsp


<action name="action1" class="com.hello.web.action.Action2">
<result name="success" type="redirectAction">action2</result>
</action>
<action name="action2">
<result name="success" type="redirect">/success.jsp</result>
</action>


——下面就是在不同包之间进行action的跳转。在result里面不是直接写一个action的名字了,而是添加了param标签,在里面定义了一个namespace和这个namespace里面的action名字。当然,这个也是可以自由变换action跳转的方式和result跳转的方式。

<package name="p_name_1" extends="struts-default">
<action name="action1" class="com.hello.web.action.Action2">
<result name="success" type="redirectAction">
<param name="namespace">/n2</param>
<param name="actionName">action3</param>
</result>
</action>
</package>
<package name="p_name_2" extends="struts-default" namespace="/n2">
<action name="action3">
<result name="success">/success.jsp</result>
</action>
</package>


9、我们也可以自己自定义一个result的type类型,结果类型。

——我们先创建一个继承自StrutsResultSupport的类叫做CAPTCHAResult。然后重写里面的doExecute方法,比如利用ValidateCode的jar包生成一个验证码图片。

——然后,我们在struts.xml里面配置我们自定义的结果类型。看到下图里面我们给我们的结果类型起名name叫做captcha,然后这个action是到CaptchaAction(新建的一个继承ActionSupport的类)里面执行默认的execute方法,但是系统并不知道这个captcha结果类型,所以我们需要在上面增加一个声明结果类型的代码result-types标签,这里面声明的是什么类型以及对应的类。



——执行顺序就是,我们在jsp页面写
"${pageContext.request.contextpath}/captchaAction.action"
之后,会触发我们的这个action,去CaptchaAction类里面去执行默认方法,返回success后,进入对应的result,发现是找到captcha类型,那么就去它的CAPTCHAResult类里面去执行doExecute方法,也就是向页面输出了一个验证码图片。

——接下来就是模拟配置参数的问题。我们在CAPTCHAResult类里面定义宽高两个变量,这样就不需要把图片尺寸固定。然后在struts.xml里面配置:



——上面配置的自定义结果类型和视图的问题在于,它只能在定义它的package内部供action们使用,其他package包的action用的时候就不能了。所以我们需要把这个包单独写出来叫myDefault,然后谁用就继承它,而不是继承struts-default。继承后,里面可以不写结果视图result,它如果没找到的话,会向全局的结果视图里面找去。



10、获取ServletAPI。

——推荐。第一种方式用
ServletActionContext
,其中request是struts返回的包装过的request,而其他几个都是tomcat容器catalina提供的。

HttpServletRequest request=ServletActionContext.getRequest();
HttpServletResponse response=ServletActionContext.getResponse();
ServletContext application=ServletActionContext.getServletContext();
HttpSession session=request.getSession();


——第二种方式是利用注入的思想。我们在这个类里面定义这几个变量,然后让类实现ServletRequestWare、ServletResponseWare、ServletContextWare接口,然后在实现的setServletRequest、setServletResponse、setServletContext里面用this.request=request给我们的变量赋值。这样我们就拿到了。但是这里面是怎么赋值给我们的变量的呢?是利用拦截器interceptor,有一个叫servletConfig的拦截器,这个拦截器是在执行action的方法之前执行的,所以它就在这个过程中判断你是否实现了某个接口,实现的话就拿到request等,然后在set方法中赋值了。

11、分文件写struts.xml的配置信息。

——多人各自写了自己的模块和配置信息,比如
struts_user.xml
struts_role.xml
等,然后我只需在
struts.xml
中包含这几个文件即可。

<struts>
<include file="struts_user.xml"></include>
<include file="struts_role.xml"></include>
……
</struts>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  struts struts2.0
相关文章推荐