Struts2框架进阶(一)

Struts2框架入门之后,我们就要踏上Struts2框架漫漫的进阶之路了。我们以Struts2框架入门中的案例开始吧!

Struts2框架中Action名称的搜索顺序

假设某用户的请求路径的URL是http://localhost:8080/Struts2/path1/path2/path3/test.action,那么Struts2框架是怎么搜索到相应的Action来处理用户的请求呢?答案为:

  1. 首先寻找namespace为/path1/path2/path3的package,不存在这个package则转步骤2,如果存在这个package,则在这个package中寻找名字为test的action,当在该package下找不到action时就会直接跑到默认namespace里面寻找,找不到该action,页面提示找不到action;
  2. 寻找namespace为/path1/path2的package,如果不存在这个package,则转步骤3,如果存在这个package,则在这个package中寻找名字为test的action,当在该package下找不到action时就会直接跑到默认namespace里面寻找,找不到该action,页面提示找不到action;
  3. 寻找namespace为/path1的package,如果不存在这个package,转到步骤4,如果存在这个package,则在这个package中寻找名字为test的action,如果仍然不存在这个package,就去默认的namaspace的package下面去找名字为test的action(默认的命名空间为空字符串”” ),如果还是找不到,页面提示找不到action。
  4. 寻找namespace为/的package,如果存在这个package,则在这个package中寻找名字为test的action,如果仍然不存在这个package或者在package中找不到action,就去默认的namaspace的package下面去找,如果还是找不到,页面提示找不到action。

我们将Struts2框架入门案例中的struts.xml配置文件修改成这样:


<struts><package name="itcast" namespace="/test" extends="struts-default">package> <package name="it" extends="struts-default"><action name="helloworld" class="cn.itcast.action.HelloWorldAction" method="execute"><result name="success">/WEB-INF/page/hello.jspresult>action>package>
struts>

这样,当我们在浏览器中输入URL地址,如http://localhost:8080/Struts2/test/sadsa/dsadfs/233432/helloworld.action时,依然会看到这样的结果:
这里写图片描述

在struts.xml中配置Action

对于Struts2框架入门案例中的struts.xml配置文件中的这段代码:

<package name="itcast" namespace="/test" extends="struts-default"><action name="helloworld" class="cn.itcast.action.HelloWorldAction" method="execute"><result name="success">/WEB-INF/page/hello.jspresult>action>
package>

在Struts1中,通过path属性指定访问该action的URL路径。但在Struts2中,情况就不是这样的了,访问Struts2中的action的URL路径由两部份组成:包的命名空间+action的名称,例如访问上面例子中名为helloworld的Action的URL路径为:/test/helloworld (注意:完整路径为:http://localhost:端口/内容路径/test/helloworld.action)。
Action配置中的各项默认值:

  1. 如果没有为action指定class,默认是ActionSupport
  2. 如果没有为action指定method,默认执行action中的execute()方法
  3. 如果没有为action指定name属性,默认值是success

例如我们在Struts2框架入门案例中的struts.xml配置文件中配置如下Action:

<action name="addUI"> <result>/WEB-INF/page/employeeAdd.jspresult> 
action>

接着在WEB-INF/page/目录下创建employeeAdd.jsp页面,该页面的内容可以写为:

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title heretitle>
head>
<body><form action="/xxx">姓名:<input type="text" name="xxx">form>
body>
html>

这样,当我们通过浏览器访问http://localhost:8080/Struts2/test/addUI.action该地址时,会跳转到employeeAdd.jsp页面。

在struts.xml中配置Action的result

试看下面的这样一段代码:

name="helloworld" class="cn.itcast.action.HelloWorldAction" method="execute"><result name="success">/WEB-INF/page/hello.jspresult>

result配置类似于Struts1中的forward,但Struts2中提供了多种结果类型,如:dispatcher(默认值)(对应Struts1中的内部请求转发)、redirect、redirectAction、plainText。
下面我们就要来详讲Struts2中提供的多种结果类型。

dispatcher

dispatcher这种结果类型就是Struts2中默认的结果类型,对应Struts1中的内部请求转发,如:

<action path="/control/employee/addUI"  ... ><forward name="add">/index.jspforward>     
action>

没什么好讲的。

redirect

浏览器重定向就是使用redirect这种结果类型。在Struts1中的浏览器重定向是这样写的:

<action path="/control/employee/addUI"  ... ><forward name="add" redirect="true">/index.jspforward>   
action>

在Struts2中若要实现浏览器重定向,则必定要使用redirect这种结果类型。我们在Struts2框架入门案例中的struts.xml配置文件中配置如下Action:

<action name="redirect"><result type="redirect">/employeeAdd.jspresult>
action>

此时struts.xml配置文件的内容就为:


<struts><package name="itcast" namespace="/control/employee" extends="struts-default"><action name="helloworld" class="cn.itcast.action.HelloWorldAction" method="execute"><result name="success">/WEB-INF/page/hello.jspresult>action><action name="addUI"> <result>/WEB-INF/page/employeeAdd.jspresult> action><action name="redirect"><result type="redirect">/employeeAdd.jspresult>action>package>
struts>

由于用户是无法访问到WEB-INF中的文件的,所以重定向的时候不能重定向到WEB-INF中的jsp中,所以我们要把employeeAdd.jsp这个页面移到WebRoot根目录下。
这样,当我们通过浏览器访问http://localhost:8080/Struts2/control/employee/redirect.action该地址时,浏览器会重定向到employeeAdd.jsp页面。
有时我们希望浏览器重定向到某个页面(如employeeAdd.jsp页面)时,传递一个参数(如用户名)进去。那我们应该怎么办呢?
我们先将HelloWorldAction类的代码修改为:

public class HelloWorldAction {private String msg;private String username;public String getMessage() {return msg;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String execute() {this.username = "李阿昀";this.msg = "我的第一个struts2应用";return "success";}}

由于在result中可以使用${属性名}表达式访问action中的属性,表达式里的属性名对应action中的属性,所以我们可以这样编写代码:

<result type="redirect">/view.jsp?id=${id }result>

那么,此时struts.xml配置文件的内容就应改为:


<struts><package name="itcast" namespace="/control/employee" extends="struts-default"><action name="list" class="cn.itcast.action.HelloWorldAction" method="execute"><result name="success" type="redirect">/employeeAdd.jsp?username=${username }result>action><action name="addUI"> <result>/WEB-INF/page/employeeAdd.jspresult> action><action name="redirect"><result type="redirect">/employeeAdd.jspresult>action>package>
struts>

接下来,我们就要在employeeAdd.jsp中使用从URL中传过来的参数username${param.username }

<%@page import="java.net.URLDecoder"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title heretitle>
head>
<body>${param.username }<form action="/xxx">姓名:<input type="text" name="xxx">form>
body>
html>

这时,当我们通过浏览器访问http://localhost:8080/Struts2/control/employee/list.action该地址,发现浏览器中URL以及jsp页面出现乱码。原因:tomcat接收到来自URL的用UTF-8编码后的字符串,会使用ISO8859-1进行编码(注意tomcat8内部使用的是UTF-8进行编码的,所以无须多此一举),所以出现乱码。解决方法:以get方式提交过来的中文参数,先得到ISO8859-1的二进制数组,再转成字符串。这样在employeeAdd.jsp页面中,要显示用户名,就要换成这句代码:

<%= URLDecoder.decode(new String(request.getParameter("username").getBytes("ISO-8859-1"), "UTF-8"), "UTF-8") %>

除此之外,HelloWorldAction类的代码还应修改为:

public class HelloWorldAction {private String msg;private String username;public String getMessage() {return msg;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String execute() throws Exception { // execute()的返回值必须是String类型this.username = URLEncoder.encode("李阿昀", "UTF-8"); // 不能再URL中直接传字符串,所以应该编码this.msg = "我的第一个struts2应用";return "success";}}

至此,浏览器中URL以及jsp页面出现的中文乱码问题就得以解决了。

redirectAction

重定向到某个Action就要使用redirectAction这种结果类型。
如果重定向的action在同一个包下:
例如,Struts2框架入门案例中的struts.xml配置文件若为:


<struts><package name="itcast" namespace="/control/employee" extends="struts-default"><action name="list" class="cn.itcast.action.HelloWorldAction" method="execute"><result name="success" type="redirect">/employeeAdd.jsp?username=${username }result>action><action name="addUI"> <result>/WEB-INF/page/employeeAdd.jspresult> action><action name="redirect"><result type="redirect">/employeeAdd.jspresult>action><action name="redirectAction"><result type="redirectAction">/listresult>action>package>
struts>

这样,当我们通过浏览器访问http://localhost:8080/Struts2/control/employee/redirectAction.action该地址时,经过两次重定向之后就到了employeeAdd.jsp页面中。
如果重定向的action在别的命名空间下:
例如,Struts2框架入门案例中的struts.xml配置文件若为:


<struts><package name="itcast" namespace="/control/employee" extends="struts-default"><action name="list" class="cn.itcast.action.HelloWorldAction" method="execute"><result name="success" type="redirect">/employeeAdd.jsp?username=${username }result>action><action name="addUI"> <result>/WEB-INF/page/employeeAdd.jspresult> action><action name="redirect"><result type="redirect">/employeeAdd.jspresult>action><action name="redirectAction"><result type="redirectAction"><param name="actionName">xxxparam>    <param name="namespace">/control/departmentparam>result>action>package><package name="other" namespace="/control/department" extends="struts-default"><action name="xxx"><result>/WEB-INF/page/hello.jspresult>action>package>
struts>

这样,当我们通过浏览器访问http://localhost:8080/Struts2/control/employee/redirectAction.action该地址时,经过一次重定向和一次内部请求转发之后就能看到employeeAdd.jsp页面中的内容了。

plainText

plainText显示原始文件内容,例如:当我们需要原样显示jsp文件源码的时候,可以使用该类型。
我们可以在Struts2框架入门案例中的struts.xml配置文件配置这样一个Action:

<action name="plainText"><result type="plainText"><param name="location">/index.jspparam> <param name="charSet">UTF-8param> result>
action>

接下来,我们就要在WebRoot根目录下创建index.jsp页面了。

<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title heretitle>
head>
<body><%= new Date() %>   中国
body>
html>

这样,当我们通过浏览器访问http://localhost:8080/Struts2/control/employee/plainText.action该地址时,就能看到index.jsp文件的源码了。

全局结果

当多个action中都使用到了相同result,这时我们应该把result定义为全局结果。Struts1中提供了全局forward,Struts2中也提供了相似功能:

<package ....><global-results><result name="message">/message.jspresult>global-results>
package>

我们先将Struts2的配置文件——struts.xml修改为:


<struts><package name="itcast" namespace="/control/employee" extends="struts-default"><global-results><result name="message">/WEB-INF/page/message.jspresult>global-results><action name="manage" class="cn.itcast.action.HelloWorldAction" method="add">action><action name="list" class="cn.itcast.action.HelloWorldAction" method="execute"><result name="success" type="redirect">/employeeAdd.jsp?username=${username }result>action><action name="addUI"> <result>/WEB-INF/page/employeeAdd.jspresult> action><action name="redirect"><result type="redirect">/employeeAdd.jspresult>action><action name="redirectAction"><result type="redirectAction"><param name="actionName">xxxparam>    <param name="namespace">/control/departmentparam>result>action><action name="plainText"><result type="plainText"><param name="location">/index.jspparam> <param name="charSet">UTF-8param> result>action>package><package name="other" namespace="/control/department" extends="struts-default"><action name="xxx"><result>/WEB-INF/page/hello.jspresult>action>package>
struts>

接着修改HelloWorldAction类的代码为:

public class HelloWorldAction {private String msg;private String username;public String getMessage() {return msg;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String execute() throws Exception { // execute()的返回值必须是String类型this.username = URLEncoder.encode("李阿昀", "UTF-8"); // 不能再URL中直接传字符串,所以应该编码this.msg = "我的第一个struts2应用";return "success";}public String add() {return "message";}}

最后我们要在WEB-INF/page/目录下创建message.jsp页面。

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title heretitle>
head>
<body>结果<br/>
body>
html>

这样,当我们通过浏览器访问http://localhost:8080/Struts2/control/employee/manage.action该地址时,就能看到如下结果:
这里写图片描述
上面名称为message的结果视图只能为一个包下的所有action所共享,但若要为各个包里面的所有action共同使用,则struts.xml配置文件应修改为:


<struts><package name="base" extends="struts-default"><global-results><result name="message">/WEB-INF/page/message.jspresult>global-results>package><package name="itcast" namespace="/control/employee" extends="base"><action name="manage" class="cn.itcast.action.HelloWorldAction" method="add">action><action name="list" class="cn.itcast.action.HelloWorldAction" method="execute"><result name="success" type="redirect">/employeeAdd.jsp?username=${username }result>action><action name="addUI"> <result>/WEB-INF/page/employeeAdd.jspresult> action><action name="redirect"><result type="redirect">/employeeAdd.jspresult>action><action name="redirectAction"><result type="redirectAction"><param name="actionName">xxxparam>    <param name="namespace">/control/departmentparam>result>action><action name="plainText"><result type="plainText"><param name="location">/index.jspparam> <param name="charSet">UTF-8param> result>action>package><package name="other" namespace="/control/department" extends="base"><action name="manage" class="cn.itcast.action.HelloWorldAction" method="add">action><action name="xxx"><result>/WEB-INF/page/hello.jspresult>action>package>
struts>

为Action的属性注入值

Struts2为Actoin中的属性提供了依赖注入功能,在Struts2的配置文件中,我们可以很方便地为Action的属性注入值。注意:属性必须提供setter方法
我们先将HelloWorldAction类的代码修改为:

public class HelloWorldAction {private String savepath;public String getSavepath() {return savepath;}public void setSavepath(String savepath) {this.savepath = savepath;}public String execute() { // execute()的返回值必须是String类型return "success";}}

再将struts.xml配置文件的内容置为:


<struts><package name="itcast" namespace="/control/employee" extends="struts-default"><action name="list" class="cn.itcast.action.HelloWorldAction" method="execute"><param name="savepath">/imagesparam><result name="success">/WEB-INF/page/message.jspresult>action>package>
struts>

上面通过结点为Action的savepath属性注入“/images”。
最后我们要修改WEB-INF/page/目录下的message.jsp页面为:

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title heretitle>
head>
<body>结果<br/>${savepath }
body>
html>

提示:可在message.jsp页面中使用EL表达式:${savePath }
这样,当我们通过浏览器访问http://localhost:8080/Struts2/control/employee/list.action该地址时,就能看到如下结果:
这里写图片描述

指定需要Struts2处理的请求后缀

默认处理的后缀是可以通过常量”struts.action.extension”进行修改的,如下配置Struts2只处理以.do为后缀的请求路径:

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

如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开。如:

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

定义常量

常量可以在struts.xml或struts.properties中配置,建议在struts.xml中配置,两种配置方式如下:

  • 在struts.xml文件中配置

    <struts><constant name="struts.action.extension" value="do"/>
    struts>
  • 在struts.properties文件中配置

    struts.action.extension=do

通常,Struts2按如下搜索顺序加载Struts2常量:

  1. struts-default.xml
  2. struts-plugin.xml
  3. struts.xml
  4. struts.properties
  5. web.xml

如果在多个文件中配置了同一个常量,则后一个文件中配置的常量值会覆盖前面文件中配置的常量值。

常用的常量

Struts2常用的常量有:

<constant name="struts.i18n.encoding" value="UTF-8"/>

指定默认编码集,作用于HttpServletRequest的setCharacterEncoding方法和freemarker、velocity的输出。

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

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

<constant name="struts.serve.static.browserCache" value="false"/>

设置浏览器是否缓存静态内容,默认值为true(生产环境下使用),开发阶段最好关闭。

<constant name="struts.configuration.xml.reload" value="true"/>

当Struts2的配置文件修改后,系统是否自动重新加载该文件,默认值为false(生产环境下使用),开发阶段最好打开。修改了struts.xml,不需重启服务器。

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

开发模式下使用,这样可以打印出更详细的错误信息。

<constant name="struts.ui.theme" value="simple" />

默认的视图主题。

<constant name="struts.objectFactory" value="spring" />

与Spring集成时,指定由Spring负责action对象的创建。

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

该属性设置Struts2是否支持动态方法调用,该属性的默认值是true。如果需要关闭动态方法调用,则可设置该属性为false。

<constant name="struts.multipart.maxSize" value="10701096">

上传文件()的大小限制。

Struts2的处理流程

Struts2的处理流程图为:
这里写图片描述
StrutsPrepareAndExecuteFilter是Struts2框架的核心控制器,它负责拦截由/*指定的所有用户请求,当用户请求到达时,该Filter会过滤用户请求。默认情况下,如果用户请求的路径中不带后缀或以.action结尾,该请求将被转入Struts2框架处理,否则该请求将略过Struts2框架的处理。当请求转入Struts2框架处理时会先经过一系列的拦截器,然后转到Action。
面试题:Struts1中的Action与Struts2中的Action在管理方式上有什么不同?
答:与Struts1不同,Struts2对用户的每一次请求都会建立一个Action,所以Struts2是线程安全的。Struts2的这种设计模式属于原型设计模式,即每个线程都有一个Action实例。而Struts1中的Action一旦被创建出来,它就会被放到缓存里面去,以后用户的每一次请求都会从缓存中获取Action来处理用户的请求。这种设计模式属于单例设计模式,在应用生命周期内只会存在一个Action实例来处理用户的请求。

为应用指定多个struts配置文件

在大部分应用里,随着应用规模的增加,系统中Action数量也大量增加,导致struts.xml配置文件变得非常臃肿。为了避免struts.xml文件过于庞大、臃肿,提高struts.xml文件的可读性,我们可以将一个struts.xml配置文件按模块分解成多个配置文件,然后在struts.xml文件中包含其他配置文件。下面的struts.xml通过元素指定多个配置文件:


<struts><include file="struts-user.xml"/>     注意:name的唯一性。<include file="struts-order.xml"/>
struts>

通过这种方式,我们就可以将Struts2的Action按模块配置在多个配置文件中。
例如,我们可以将struts.xml配置文件按模块分解成两个配置文件:

  • department.xml

    
    <struts><package name="department" namespace="/control/department" extends="struts-default"><action name="list" class="cn.itcast.action.HelloWorldAction" method="execute"><param name="savepath">departmentparam><result name="success">/WEB-INF/page/message.jspresult>action>package>
    struts>
  • employee.xml

    
    <struts><package name="employee" namespace="/control/employee" extends="struts-default"><action name="list" class="cn.itcast.action.HelloWorldAction" method="execute"><param name="savepath">employeeparam><result name="success">/WEB-INF/page/message.jspresult>action>package>
    struts>

这样,struts.xml配置文件的内容就为:


<struts><constant name="struts.action.extension" value="do,action"/><include file="department.xml">include><include file="employee.xml">include>
struts>

以后struts.xml配置文件只会配置Struts2用到的一些基本信息,很少会配置一些关于某个功能的Action,而是定义一些所有模块都会使用到的公共的一些配置。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部