Struts2教程
Posted ErBing
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Struts2教程相关的知识,希望对你有一定的参考价值。
一、初识Struts2
Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。许多框架在大家一开始学习的时候都觉得比较繁琐和多此一举,但大体都有相同的目的,那就是增强可扩展性。Struts2的核心其实就是通过改配置文件的方式将请求和视图(结果)分开。
1.1 开发环境搭建
首先下载Struts2,地址http://struts.apache.org/,我这里下载的版本是2.5.10.1,解压之后有如下4个文件夹
所需的基本jar包有以下9个。struts2-core是开发的核心类库,struts2的UI标签的模板使用freemarker编写,OGNL是对象图导航语言,通过它来读写对象属性。
1.2 Struts2配置文件
①web.xml文件
主要完成对StrutsPrepareAndExecuteFilter的配置,它的实质是一个过滤器,负责初始化整个Struts框架并且处理所有的请求。在2.5以及2.1.3之前的版本filter-class会不同,请自行查询官方文档,filter-name和url-pattern是默认写法,不建议修改。
<filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
②struts.xml文件
Struts2的核心配置文件就是struts.xml文件,在这个配置文件里面我们可以根据需要再包括其它一些配置文件。在通常的应用开发中,我们每个人来写不同的模块,每个人单独配置一个struts.xml文件,最后合并,这样也利于管理和维护。
struts.xml中包含全局属性、用户请求和相应Action之间的对应关系、Action可能用到的参数和返回结果以及各种拦截器的配置,具体将在以下几节中慢慢介绍。
struts.xml可以从解压过后的示例程序里复制,拷贝到工程的src目录下,注释或删除掉struts标签中的内容,来填写我们需要的配置。
③struts.properties(default.properties)
default.properties文件在struts2-core.jar中的org.apache.struts2包下,里面保存着许多Struts是的默认属性,如编码格式、是否启用开发模式等等。当要修改某些属性时,建议在struts2的xml配置文档中进行更改,格式如下面一行代码,而不建议自己新建一个struts.properties文件。
<constant name="" value=""></constant>
④struts-default.xml
此文件是struts2框架默认加载的配置文件,它定义了struts2一些核心bean和拦截器,它会自动包含到struts.xml文件中(实质是通过<package extends="struts-default">),并为我们提供了一些标准的配置。我们可以在struts2-core.jar中找到这个文件。
二、struts.xml配置
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN" "http://struts.apache.org/dtds/struts-2.5.dtd"> <struts> <constant name="struts.ognl.allowStaticMethodAccess" value="true"/> <package name="user" namespace="/user" extends="struts-default"> <action name="user" class="com.dhcc.struts2.action.UserAction"> <result>/user_add_success.jsp</result> </action> </package> </struts>
2.1 配置文件的优先级
在struts2中一些配置(比如常量)可以同时在struts-default.xml(只读性),strtus-plguin.xml(只读性),struts.xml,struts.properties和web.xml文件中配置,它们的优先级逐步升高,即是说后面的配置会覆盖掉前面相同的配置。
以struts.i18n.encoding=UTF-8的配置为例进行说明:
在struts.xml配置形式如下:
<constant name="struts.i18n.encoding" value="gbk"></constant>
在struts.properties的配置形式如下:struts.i18n.encoding=UTF-8
在web.xml中配置如下:
<filter> <filter-name>struts2</filter-name> <filter-class> org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter </filter-class> <init-param> <param-name>struts.i18n.encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter>
2.2 package配置
属性名 |
是否必须 |
说明 |
Name |
是 |
Package的唯一标识,不允许同名 |
Extends |
否 |
指定要继承的包 |
Namespace |
否 |
指定名称空间 |
Abstract |
否 |
声明包为抽象否 |
package元素的namespace属性及action的name属性,它们共同定义了action所映射到的实质文件。
namespace默认值“”,即不配置namespace属性,如果action不能进行完整路径匹配,则会来此namespace下进行匹配。namespace也可以配置成namespace="/"。它代表配置为项目的根。总结action的名称探索顺序:完全对应、逐步追溯到上级目录查找、"/"下查找、默认namespace下查找。
namespace引发的链接问题:当我们为action配置了namespace时,访问此action的形式总会是如下形式:.../webappname/xxx/yyy/ActionName.action,而当此action成功执行跳转到某个jsp页面时,如想在此jsp页面写链接,一定要写绝对路径,因为相对路径是相对.../webappname/xxx/yyy/,而如果以后我们修改了action的namespace时,相对路径又要变,所以链接不能写成相对路径。 可以在建立一个jsp文件时,加上如下内容:
<% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %>
我们写绝对路径可以参此内容。还可以参<head>下的<base href="<%=basePath%>"> 来完成绝对路径的书写。
三、Action
3.1 新建一个Action
第一步,新建一个Class,继承ActionSupport ,ActionSupport实现了execute()方法。
package com.struts2.test; import com.opensymphony.xwork2.ActionSupport; public class UserAction extends ActionSupport { public String add() { return "success"; } public String del() { return "success"; } public String update() { return "success"; } public String query() { return "success"; } }
第二步,配置此Action,在struts.xml中加入如下内容:
<package name="user" extends="struts-default" namespace="/user"> <action name="addUser" class="com.asm.UserAction" method="add"> <result name="success">/user/addUser.jsp</result> </action> <action name="delUser" class="com.asm.UserAction" method="del"> <result name="success">/user/delUser.jsp</result> </action> <action name="updateUser" class="com.asm.UserAction" method="update"> <result name="success">/user/updateUser.jsp</result> </action> <action name="queryUser" class="com.asm.UserAction" method="query"> <result name="success">/user/queryUser.jsp</result> </action> </package>
上面的method方法的值来源于CRUDAction中方法的名字,这样当我们访问上面的每一个Action时,它实质是和method指定的方法关联上。如果没有为action指定class,默认就是ActionSupport类,如果没有为action指定method属性,则默认执行execute方法,如果没有指定result的name属性,默认值为success。
第三步,编写相应的jsp页面,在此略去crud文件夹下的四个跳转jsp页面(addSuccess.jsp等),重点是crud.jsp页面。内容如下:
<html> <% String path=request.getContextPath(); %> <body> <a href="<%=path %>/user/addUser.action">添加数据</a><br> <a href="<%=path %>/user/delUser.action">删除数据</a><br> <a href="<%=path %>/user/queryUser.action">查询数据</a><br> <a href="<%=path %>/user/updateUser.action">修改数据</a><br> </body> </html>
最后发布测试。
3.2 动态调用DMI
不使用method实现统一,我们在struts.xml中增加如下内容:
<action name="op" class="com.struts2.test.UserAction"> <result name="add">/user/addUser.jsp</result> <result name="del">/user/delUser.jsp</result> <result name="query">/user/queryUser.jsp</result> <result name="update">/user/updateUser.jsp</result> </action>
然后再在crud.jsp中定义如下链接:
<a href="<%=path %>/user/op!add.action">添加数据</a><br> <a href="<%=path %>/user/op!del.action">删除数据</a><br> <a href="<%=path %>/user/op!query.action">查询数据</a><br> <a href="<%=path %>/user/op!update.action">修改数据</a><br>
注意查看上面的链接地址,它们都是针对op这个action,然后再加地上“!+UserAction中相应的方法名”,最后再写上.action即可以访问到相应result的name指定的jsp。大家会发现跟上面不同的是,result的name不再都是SUCCESS,这样才能区分开要访问的页面,但千万不要忘记在UserAction中相应的方法也要返回add/del/query/update,而不是SUCCESS。如果不想使用动态方法调用,我们可以通过常量来关闭,即在struts.xml中增加如下配置:
<constant name="struts.enable.DynamicMethodInvocation" value="false"/>
3.3 通配符
为了使用通配符,只需要改写配置文件即可。将3.1节中的配置文件改为如下内容可达到相同的效果:
<package name="user" extends="struts-default" namespace="/user"> <action name="*User" class="com.asm.UserAction" method="{1}"> <result name="success">/crud/{1}User.jsp</result> </package>
当有.../addUser.action请求时,如果不能在当前应用中找到完全相同的addUser名字的Action时,通配符配置这时就起作用了。
其实如果我们有良好的编程命名习惯,所有的Action我们都只需要进行一次配置。举例:规定所有的Action类都用XXXAction来命名,类中所有的CRUD方法都用add/del/update/query。Jsp页面也用add/del/update/query_XXX.jsp这样的形式。即配置文件可以写成如下形式:
<action name="*_*" class="com.struts2.test.{2}Action" method="{1}"> <result name="success">.../{1}_{2}.jsp</result> </action>
name中第一个*代表CRUD操作的名字,第二个*代表类的名字。所以访问链接地址举例如:.../del_User.action将访问到UserAction类的del方法,成功后跳到del_User.jsp页面。说明{0}是代表name中所有的*组合。
3.4 接收参数
①Action属性接收参数
UserAction中建两个属性name和age,并且要生成相应的get/set方法。
public class UserAction extends ActionSupport { private String name; private int age;public int getAge() { return age; } public String getName() { return name; } public void setAge(int age) { this.age = age; } public void setName(String name) { this.name = name; } }
在传参的jsp页面,有一个表单
<form action="<%=request.getContextPath()%>/addUser.action" method="get"> 名字:<input type="text" name="name"><br> 年龄:<input type="text" name="age"><br> <input type="submit" value="login"> </form>
这样name和age就能接收到传入的值。需要注意的是,传参参照的action中的方法名,而非属性名。
②DomainModel接收参数
UserAction中有一个域模型private User user,注意不要自己new对象,User类中有name和age属性和对应的get/set方法。UserAction中要生成User对象对应的get/set方法。
访问http://.../user/user!add?user.name=a&user.age=8 即可对user赋值,相当于调用了user的set方法。
public class UserAction extends ActionSupport { private User user;public User getUser() { return user; } public void setUser(User user) { this.user = user; } }
- 如果传入的参数个数和域模型的属性个数不同,可以用DTO(Data Transfer Object)。比如传入的参数还有一个isAdmin,那么我们建一个UserDTO,包含name,age和isAdmin三个属性,用UserDTO去接收参数,然后用UserDTO再生成相应的User
③ModelDriven接收参数
public class UserAction extends ActionSupport implements ModelDriven<User>{ //需要实现ModelDriven接口 private User user = new User(); //ModelDriven需要自己new @Override public User getModel() { return user; } }
3.5 访问Scope对象(request、session、application,HttpServletRequest、HttpSession、ServletContext)
①与Servlet解耦合的非IOC方式
public class LoginAction extends ActionSupport { ActionContext context; Map request; Map session; Map application; public String execute() throws Exception { context=ActionContext.getContext(); request=(Map) context.get("request"); session=context.getSession(); application=context.getApplication(); request.put("req", "requst属性"); session.put("ses", "sesion属性"); application.put("app", "application属性"); return SUCCESS; } }
②与Servlet解耦合的IOC方式
public class Login2Action extends ActionSupport implements RequestAware,SessionAware,ApplicationAware { //实现XxxAware接口,重写setXxx()方法 Map request; Map session; Map application; public String execute() throws Exception { request.put("req", "requst属性"); session.put("ses", "sesion属性"); application.put("app", "application属性"); return SUCCESS; } public void setRequest(Map<String, Object> request) { this.request=request; } public void setSession(Map<String, Object> session) { this.session=session; } public void setApplication(Map<String, Object> application) { this.application=application; } }
③与Servlet耦合的非IOC方式
public class Login3Action extends ActionSupport { //获取的纯粹的Scope对象,它与容器相关 HttpServletRequest request; HttpSession session; ServletContext application; public String execute() throws Exception { request = ServletActionContext.getRequest(); session = request.getSession(); application = ServletActionContext.getServletContext(); request.setAttribute("req", "requst属性"); session.setAttribute("ses", "sesion属性"); application.setAttribute("app", "application属性"); return SUCCESS; } }
④与Servlet耦合的IOC方式
public class Login4Action extends ActionSupport implements ServletRequestAware,ServletContextAware{ //实现XxxAware接口,重写SetXxx()方法 ActionContext context; HttpServletRequest request; HttpSession session; ServletContext application; public String execute() throws Exception { context=ActionContext.getContext(); session=request.getSession(); request.setAttribute("req", "requst属性"); session.setAttribute("ses", "sesion属性"); application.setAttribute("app", "application属性"); return SUCCESS; } public void setServletRequest(HttpServletRequest request) { System.out.println("测试:"+request); this.request=request; } public void setServletContext(ServletContext application) { System.out.println("测试:"+application); this.application=application; } }
之后可以在jsp中使用EL表达式${requestScope.req}或通过request.getAttribute这样的方式获取对象值
3.6 default-action-ref 配置统一访问
当访问没有找到对应的action时,默认就会调用default-action-ref指定的action。在struts.xml文件的package中增加如下内容:
<default-action-ref name="error"></default-action-ref> <action name="error"> <result>/other/error.jsp</result> </action>
上面一段内容就是说当我们访问的action不能被找到时便指向名为error的action中去,接着我们在下面配置了这个error Action。但是要注意,一个package内只配置一个<default-action-ref>,如果配置多个,就无法预测结果了。此时我们只要输入.../myStruts2/luanFangWen.action这样的形式,它就会去访问这个默认的<default-action-ref>,通常我们会为它配置一个错误页面,以提示用户访问的页面不存在。 在web开发中,我们还可以把这个默认的action访问配置成主页,这样当用户访问一些不存在的action时,总会跳到主页上去。
通过此配置,只要是访问一个不存在的action便会转向到.../other目录下的error.jsp页面。但是如果访问是其它的不存在资源则仍是报tomcat所标识的404错误,我们可以在web.xml中作如下配置:
<error-page> <error-code>404</error-code> <location>/other/404error.jsp</location> </error-page>
四、Result配置
4.1 type类型
在前面的许多案例中我们所用到的Action基本都继承自ActionSupport这个类,而在这个类中我们定义了五个字段:SUCCESS,NONE,ERROR,INPUT,LOGING。我们可以直接返回这些字段值,这些字段值实质是被定义成:String SUCCESS=”success”这样的形式,所以我们只要在Result元素中用它们的小写即可。
<result name="success" type="dispatcher"> <param name="location">/default.jsp</param> </result>
如果我们都采用默认的形式,最终可以简写成:<result>/default.jsp</result>
Type类型值 |
作用说明 |
chain |
用来处理Action链 |
dispatcher |
用来转向页面,通常处理JSP |
redirect |
重定向到一个URL |
redirectAction |
重定向到一个Action |
plainText |
显示源文件内容,如文件源码 |
freemarker |
处理FreeMarker模板 |
httpheader |
控制特殊http行为的结果类型 |
stream
|
向浏览器发送InputSream对象,通常用来处理文件下载,还可用于返回AJAX数据。 |
velocity |
处理Velocity模板 |
xslt |
处理XML/XLST模板 |
json |
序列化action为json |
当一个Action处理后要返回的Result是另一个Action,就需要使用chain和redirectAction。以chain为例,它的param有4个值可配,actionName(默认)、namespace、method和skipActions。namesapace的默认值当前namespace,可以省略不写。method用于指定转向到一个目标action所调用的方法,默认是调用下一个action的execute方法,所以也可以省略。SkipActions是一个可选的属性,一般不用。
<package name="public" extends="struts-default"> <!-- Chain creatAccount to login, using the default parameter --> <action name="createAccount" class="..."> <result type="chain">login</result> </action> <action name="login" class="..."> <!-- Chain to another namespace --> struts2 官方系列教程三:使用struts2 标签 tagmarkdown 打字稿...编码说明,提示,作弊,指南,代码片段和教程文章