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是开发的核心类库,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="<%=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;
    }
}
依赖注入与控制反转DI/IOC

  之后可以在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 标签 tag

VIM 代码片段插件 ultisnips 使用教程

markdown 打字稿...编码说明,提示,作弊,指南,代码片段和教程文章

Maven搭建SSH(Struts2+Spring+Hibernate)框架入门教程_2

拓薪教育-struts2视频教程-任亮

struts2官方 中文教程 系列十:Form标签