首页 > 代码库 > Struts2教程

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是开发的核心类库,struts2UI标签的模板使用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="http://www.mamicode.com/"> 来完成绝对路径的书写。

三、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 访问web元素(request、session、application,HttpServletRequest、)

 

未完待续。。。

Struts2教程