struts2 Action (2)

来源:互联网 发布:gommdb数据库编辑器 编辑:程序博客网 时间:2024/06/04 18:12

命名空间

namespace决定了action的访问路径,也就是namespace里面写了什么,你的请求地址栏里就必须要包括什么。

namespace默认为“”,可以接收到所有路径的action,可以写为/,/xxx,/xxx/yyy 对应的访问路径就应该为/xxx/xxx.action,/xxx/yyy/xxx.action

namespace最好用模块来命名。

如下代码:

    <constant name="struts.devMode" value="true" />    <package name="login" namespace="/login" extends="struts-default">        <action name="login">            <result>/login_success.jsp</result>        </action>    </package>

constant name="struts.devMode" value="true" 为调试模式开启(IDEA无法调用此功能,调试须重新部署)

package *name*属性用来区分重名的情况。


=====================================================================

Action

struts配置文件内的Action标签为你的Java操作的导航(个人理解)与返回值的判定和页面的跳转的集合体

struts.xml内代码如下:

    <package name="path" namespace="/path" extends="struts-default">        <action name="path" class="test.example">            <result name="success">                /path.jsp            </result>        </action>    </package>
action标签里的class值为你在src目录创建的JavaAction类的路径

Action操作类我用继承了一个ActionSupport类,类里包含了一些预设好了的对象和属性供开发者利用,后续struts2的Action类也都将继承此类。

在此处我重载了ActionSupport里的execute()方法,返回了一个值为“success”的String对象。

execute()为默认执行的方法,即在上面的配置文件里的action标签内,你不声明method属性时默认执行的方法。

example.java代码如下:

package test;import com.opensymphony.xwork2.ActionSupport;/** * Created by Alex on 2017/5/8. */public class example extends ActionSupport{    @Override    public String execute(){        return "success";//result默认值为success    }}
这个action类返回一个“success”的String至struts.xml,里面的result标签负责接收这个值,其中name属性为结果值,默认为"success" 

也就是说 若返回值为success,那么result标签内就不用再写name属性。

另外一种action类的的写法,此方法为主流方法,可以自定义方法名来进行开发操作,而不仅仅局限与execute()这一种方法。

另外返回值我们利用了SUCCESS这一在父类ActionSupport中接口Action中的变量值,

可看到struts2的源码中为我们内置了这些变量值:

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package com.opensymphony.xwork2;public interface Action {    String SUCCESS = "success";    String NONE = "none";    String ERROR = "error";    String INPUT = "input";    String LOGIN = "login";    String execute() throws Exception;}

Action代码如下:

package action;import com.opensymphony.xwork2.ActionSupport;/** * Created by Alex on 2017/5/9. */public class CourseAction extends ActionSupport {    public String add(){        return SUCCESS; //接口包含变量    }    public String delete(){        return SUCCESS;    }}
可以看到此处我们不在重载execute方法,而是选择自定义命名的方法,那么在struts.xml里面我们应该如何接受返回值?请看

    <package name="actions" namespace="/actions" extends="struts-default">        <action name="course" class="action.CourseAction" method="add">            <result>                /User_add_success.jsp            </result>        </action>        <action name="course" class="action.CourseAction" method="delete">            <result>                /User_delete_success.jsp            </result>        </action>    </package>

可以看到,在此处action标签内我们编写了一个method属性,里面的值就是我们action类里自定义方法的名称

这样一来,我们就可以通过这种方法来调用自定义的方法了。


=====================================================================

通配符

上面的代码大家有没有觉得很冗余,其实我们可以精简一点通配符的运用:

struts.xml

<package name="actions" namespace="/actions" extends="struts-default">        <action name="*_*" class="action.{1}Action" method="{2}" >            <result>                /{1}_{2}_success.jsp            </result>        </action></package>
可以看到action的name值变为了*_*, 这些*就代表了我们要传(要变)的参数,可以为add,可以为delete等等,后面的{1}{2}分别代表了第一个*所代表的值与第二个*所代表的值,依次代入,就可以实现动态接受与判断数据了。

配置代码是不是精简了很多?但是需要遵循约定优于配置这个原则

对应action类与jsp页面



=====================================================================

 用Action的属性接收参数

在JSP页面内,我们如果需要传参数至后端,该如何进行?
如:超链接可以这一样写 http://localhost:8080/xxxxx/user/user!add?name=xxx&age=xxx
其中方法名写在!后面,需要传的参数则写在?后面与平常无异。
在Action类中,我们需要声明变量用来接收参数,变量名最好与参数名一致(也可不一致,get set方法名与参数名一致即可,但不提倡)
并编写get() set() 方法。
UserAction.java写法:
package action;import com.opensymphony.xwork2.ActionSupport;/** * Created by Alex on 2017/5/9. */public class UserAction extends ActionSupport{    private String name;     private int age;    public String add(){        System.out.println("name:"+name);        System.out.println("age:"+age);        return SUCCESS;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }}

可以看到这种方式可以接收到页面传递过来的参数值,并进行处理。但是这种传参模式有缺点,就是如果变量过多,会导致代码异常冗余

针对这点,下面这种方法就对其进行了优化。

用DomainModel接受参数


首先我们需要编写一个实体类,包含我们需要用到的数据,如:
package bean;/** * Created by Alex on 2017/5/9. */public class User {    private String name;    private int age;        public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }}

我们在页面内进行传值的地址链接更改为如下这种:
http://localhost:8080/user/user!add?user.name=xxx&user.age=xxx
将传的参数前加上了我们实体类的名字user,然后.参数名

我们再来看看Action类是如何编写的:
package action;import bean.User;import com.opensymphony.xwork2.ActionSupport;/** * Created by Alex on 2017/5/9. */public class UserAction2 extends ActionSupport{    private User user; //实例化User实体类    public String add(){        System.out.println("username:"+user.getName());        System.out.println("username:"+user.getAge());        return SUCCESS;    }    public User getUser() {        return user;    }    public void setUser(User user) {        this.user = user;    }}
我们可以理解为,参数传过来,调用了set方法,我们使用get方法取值。
在这种方式下,我们使用实体类加载对象,然后在Action里实例化,再直接调用实体类的get方法,就可取到页面传过来的参数了。
这种方式我们称之为 DomainModel 预模型

DTO(VO\DO)

如果我们需要传的参数并不是所有都需要用到,那这些参数我们应该如何处理呢?
Data Transform Object(DTO)数据传输对象 就可以解决此问题

用ModelDriven接收参数

传参地址仍然为:
http://localhost:8080/test/user/user!add?name=xxx&age=xxx

他的Action 是这样写的
package action;import bean.User;import com.opensymphony.xwork2.ActionSupport;import com.opensymphony.xwork2.ModelDriven;/** * Created by Alex on 2017/5/11. */public class UserAction3 extends ActionSupport  implements ModelDriven<User>{    private User user = new User();    public String add(){        System.out.println("name"+user.getName());        System.out.println("name"+user.getAge());        return SUCCESS;    }    @Override    public  User getModel(){        return user;    }}


可以看到,在Action里我们使用了一个叫ModelDriven的接口。这样一来在Action内我们可以重载他的getModel方法,一旦成功
就可以直接使用set方法来传参数至实体类,进而可用get方法来获取参数进行操作。

这种方法实际使用并不多,学习它是因为它包含了一个很重要的设计概念,即MVC模型思想
struts2代表了MVC中的Controller部分

以上三种传参方式,最为常用的为DomainModel这种方式,其余两种了解概念即可

2.1.6版本的中文问题


在传参过程中,我们会发现一个问题,如果我们输入中文,那么传过来的参数会是乱码,这是因为项目本身编码不支持中文,我们需要更改部分配置来进行转码。
我们可以在struts配置文件插入以下配置,可完成中文转码(仅支持struts版本为2.1.7以上,以下的会有BUG)
<constand name=“struts.i18n.encoding" value="utf-8" />
若版本在2.1.7以下,则可用过滤器的方式来进行转码

post请求转码过滤器写法:
package filter;import javax.servlet.*;import javax.servlet.annotation.WebFilter;import java.io.IOException;/** * Created by Alex on 2017/5/11. */@WebFilter(filterName = "EncodingFilter")public class EncodingFilter implements Filter {    public void destroy() {    }//过滤器销毁    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {        req.setCharacterEncoding("utf-8");        resp.setCharacterEncoding("utf-8");        chain.doFilter(req, resp);    }    public void init(FilterConfig config) throws ServletException {    }//过滤器初始化}


get请求转码需要更改Tomcat根目录下server.xml中的 具体位置:tomcat根目录/conf/server.xml
找到
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000"  redirectPort="8443" />
更改为:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"  URLEncoding="utf-8" />
即可修复中文输入乱码问题

简单的数据验证


我们传入的参数需要进行简单的数据验证。接下来我将利用上面的例子进行验证。
首先我们来配置struts.xml文件
    <package name="actions" namespace="/actions" extends="struts-default">        <action name="user2" class="action.UserAction2">            <result> /User_add_success.jsp </result>            <result name="error">/user_add_error.jsp</result>        </action>    </package>
此处有两个result代表了两种处理情况,成功与失败
Action类:
package action;import com.opensymphony.xwork2.ActionSupport;/** * Created by Alex on 2017/5/11. */public class LoginAction  extends ActionSupport {    private String name;    public String add(){       if(name==null || !name.equals("fjnmbb12")){            this.addFieldError("name","name is error");            return ERROR;        }        return SUCCESS;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}
可以看到这里add()内有两种情况,返回了不同的结果。其中发生错误的结果内有一个addFieldError方法,此方法将会发送错误的原因至前端页面。
请看前端页面写法:
<%--  Created by IntelliJ IDEA.  User: Alex  Date: 2017/5/11  Time: 22:32  To change this template use File | Settings | File Templates.--%><%@ page contentType="text/html;charset=UTF-8" language="java" %><%@taglib uri="/struts-tags" prefix="s"%><html><head>    <title>Title</title></head><body>    用户添加异常!    <s:fielderror fieldName="name" theme="simple" /> <br/>    <s:property value="errors.name[0]"/> <br/>    <s:debug></s:debug></body></html>
在前端页面我们引用了struts 的标签,首先在顶部插入引用语,
在内容中即可调用struts标签。
<s:fielderror>标签是输出错误原因,但是有标准格式(不可改)
<s:property>标签是可输出多个错误原因,以Map的方式输出(第一个下标为0),并可自定义格式,截取长度等 ,比较常用。
<s:debug>是嵌入一个超链接 点击可打开struts的调试内容

访问Web元素

struts取request,response(一般不用),session,application的方式
我们先编写前端JSP页面的HTML代码,如下所示:
<%--  Created by IntelliJ IDEA.  User: Alex  Date: 2017/5/10  Time: 16:43  To change this template use File | Settings | File Templates.--%><%@ page contentType="text/html;charset=UTF-8" language="java" %><html>  <head>    <base href="http://localhost:8080/">    <title>$Title$</title>  </head>  <body>  <form action="" id="f" name="f" method="post">    <input type="text" name="name" placeholder="输入用户名" /><br />    <input type="password" name="password" placeholder="输入密码" /> <br />    <input type="button" value="提交1" onclick="javascript:document.f.action='login/login1';document.f.submit();"  />    <input type="button" value="提交2" onclick="javascript:document.f.action='login/login2';document.f.submit();"  />    <input type="button" value="提交3" onclick="javascript:document.f.action='login/login3';document.f.submit();"  />    <input type="button" value="提交4" onclick="javascript:document.f.action='login/login4';document.f.submit();"  />  </form>  </body></html>
效果如下图:
struts配置文件代码:
    <package name="login" namespace="/login" extends="struts-default">        <action name="login*" class="action.LoginAction{1}">            <result>/login_success.jsp</result>        </action>    </package>


第一种访问的方式,为调用ActionSupport内的ActionContext.getContext()方法进行取值,然后重载execute()方法传值。
三大对象在本质上还是Map。
Action1代码:
package action;import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionSupport;import javax.net.ssl.SSLSessionContext;import java.util.Map;/** * Created by Alex on 2017/5/10. */public class LoginAction1 extends ActionSupport{    private Map request;//声明类型为Map的request变量    private Map session;//声明类型为Map的session变量    private Map application;//声明类型为Map的application变量    public LoginAction1(){        //调用ActionSupport内的方法对三大对象进行取值        request = (Map)ActionContext.getContext().get("request");        session=ActionContext.getContext().getSession();        application = ActionContext.getContext().getApplication();    }    @Override    public String execute(){        request.put("r1","r1");        session.put("s1","s1");        application.put("a1","a1");        return SUCCESS;    }}

context:环境,周围环境

第二种访问取值的方式,依赖于struts2, 实现了几个叫做RequestAware,SessionAware,ApplicationAware的接口,不需要再从context中取值。

此处涉及到一个非常重要的设计思想(Spring框架会提到)叫做IoC,全称Inverse of Control(控制反转),也成为DI,全称Dependency Injection(依赖注入


实现了这三个接口后,请求可直接调用set方法访问web元素,非常方便。

Action2代码:
package action;import com.opensymphony.xwork2.ActionSupport;import org.apache.struts2.interceptor.ApplicationAware;import org.apache.struts2.interceptor.RequestAware;import org.apache.struts2.interceptor.SessionAware;import java.util.Map;/** * Created by Alex on 2017/5/10. */public class LoginAction2 extends ActionSupport implements RequestAware,SessionAware,ApplicationAware{    private Map<String,Object> request;    private Map<String,Object> session;    private Map<String,Object> application;    public String execute(){        request.put("r1","r2");        session.put("s1","s2");        application.put("a1","a2");        return SUCCESS;    }    @Override    public void setRequest(Map<String, Object> request) {        this.request = request;    }    @Override    public void setSession(Map<String, Object> session) {        this.session = session;    }    @Override    public void setApplication(Map<String, Object> application) {        this.application = application;    }}

第一种方式是主动去访问主动去拿的,第二种方式是被动询问取值,若实现了接口,则可直接访问与取值。这就是依赖注入的思想。后者是最常用的方法。

其余2种过于简单,不再此论述。

Action总结

Action:
  • 实现一个Action的最常用的方式:从ActionSupport继承
  • DMI动态方法调用 !xxx
  • 通配符配置 * {1} {2}
  1. *_*
  • 接收参数的方法(一般用属性和DomainModel来接收)
  • 简单的数据验证 addFieldError
  1. 一般不使用struts2的ui标签
  • 访问WEB元素
  1. Map类型(1、IoC  2、依赖struts2)
  2. 原始类型 (1、IoC 2、依赖struts2)
  • 包含文件配置(include标签)
  • 默认action处理