Struts2的ServletAPI的获取和各种类型的数据获取(三)

勿以恶小而为之,勿以善小而不为--------------------------刘备

劝诸君,多行善事积福报,莫作恶

上一章简单介绍了Action的实现方式和struts.xml配置的详细解释,Struts2的简单执行过程(二),如果没有看过,请观看上一章

Struts2是web层框架,主要有两个方面的作用:

1 . 获取前端的客户端输入

2 . 响应后端输出

常常使用到 Servlet API 中相应的方法。

通常有以下三种方式获取 request,response,session,application 对象信息。

1 . Action 通过 ActionContext() 类访问Servlet API

2 . Action 通过实现 XxxAware 接口直接访问 Servlet API

3 . 使用 ServletActionContext 直接访问 Servlet API

所有的Struts2 文章,都已经在web.xml 中添加了StrutsPrepareAndExecuteFilter 过滤器

<!-- 配置struts2的过滤器 -->
<filter>
        <filter-name>struts</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
        <filter-name>struts</filter-name>
        <url-pattern>/*</url-pattern>
</filter-mapping>

一. 获取Servlet API 对象

一.一 通过 ActionContext() 类访问 Servlet API

一.一.一 ActionContext 类的主要方法

方法 作用
static ActionContext getContext() 静态方法, 获取ActionContext 对象实例
void put(String key,Object value) 设置request范围的属性值,类似于request.setAttribute(String key,Object value)
Object get(Object key) 获取 request 范围的属性值,类似于 request.getAttribute(String name)
Map getSession() 返回Map 对象,模拟了 session对象
Map getApplication() 返回map对象,模拟了application 对象
Map getParameters() 获取所有的请求参数,类似调用 request.getParameterMap() 方法

一.一.二 写Demo验证一下

一.一.二.一 编写Action 类 ActionContextDemo

    public class ActionContextDemo extends ActionSupport{
    private static final long serialVersionUID = 1L;
    // 前端传入一个参数 为 name 
    private String name;
    
    /*
     * 通过此方法,展示一下,将数据放置到 request域,session域,application域的用法。
     * */
    public String showData(){
        
        ActionContext actionContext=ActionContext.getContext();
        
        //获取 application 作用域
        Map<String, Object> applicationData=actionContext.getApplication();
        
        //获取application的值
        Integer count=(Integer)applicationData.get("count");
        if(count==null){    
            count=1;
        }else{
            count=count+1;
        }
        //设置application的值
        applicationData.put("count", count);
        
        //获取session 作用域
        
        Map<String,Object> sessionData=actionContext.getSession();
        
        //放置到session域 
        sessionData.put("loginName",name);
        if("两个蝴蝶飞".equals(sessionData.get("loginName"))){
            
            //放置到request域
            actionContext.put("msg","第一种方式 :欢迎您,"+sessionData.get("loginName"));
            //返回success 
            return SUCCESS;
        }
        //放置到request域
        actionContext.put("msg","服务器提示:登录失败");
        return ERROR;
        
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

一.一.二.二 配置 struts.xml 文件

    <package name="hello" extends="struts-default" namespace="/">
        
        <!-- 配置第一种方式 -->
        <action name="actionContextDemo" class="com.yjl.web.action.ActionContextDemo"
        method="showData">
            <result name="success">/WEB-INF/content/success1.jsp</result>
            <result name="error">/WEB-INF/content/error.jsp</result>
        </action>
    </package> 

一.一.二.三 编写前端文件

success1.jsp 里面的内容为:

<body>
    本站访问次数:${applicationScope.count} <br/>
    ${sessionScope.loginName},您已经成功登录<br/>
    ${requestScope.msg}<br/>
</body>

error.jsp 里面的内容为:

<body>
    ${requestScope.msg}<br/>
</body>

一.一.二.四 重启服务器,进行验证

当输入网址为: http://localhost:8080/Struts_API/actionContextDemo 时,没有name值,提示登录失败

有图片

当输入网址为: http://localhost:8080/Struts_API/actionContextDemo?name=两个蝴蝶飞,name正确,提示登录成功

有图片

当输入网址为: http://localhost:8080/Struts_API/actionContextDemo?name=老蝴蝶,name值错误,提示登录失败

有图片

可以正常的传输数据。

这种方式,只能往request,session和applicaiton中进行存数据,取数据,只能对数据进行维护,不能像真正的request,response对象提供的那些方法一样强大。 如获取客户端ip,添加cookie 等, 用这种方法就无法实现了。

一.二 通过实现XxxAware 接口实现Servlet API 对象

Struts2针对Servlet 的API 对象,提供了三种接口, HttpServletRequestAware 接口,HttpServletResponseAware接口, ServletContextAware 接口。 其中,session对象可以通过request对象进行获取,所以就没有提供关于session的接口。

一.二.一 XxxAware 接口提供的方法

ServletRequestAware 接口提供了一个 setServletRequest() 方法,用于获取request对象

public abstract interface ServletRequestAware
{
  public abstract void setServletRequest(HttpServletRequest paramHttpServletRequest);
}

ServletResponseAware 接口提供了一个 setServletResponse() 方法,用于获取response对象

public abstract interface ServletResponseAware
{
  public abstract void setServletResponse(HttpServletResponse paramHttpServletResponse);
}

ServletContextAware 接口提供了一个 setServletContext()方法,用于获取application对象

public abstract interface ServletContextAware
{
  public abstract void setServletContext(ServletContext paramServletContext);
}

一.二.二 写Demo验证一下

一.二.二.一 编写Action 类 AwareDemo

    public class AwareDemo extends ActionSupport 
implements ServletRequestAware,ServletResponseAware,ServletContextAware{
    private static final long serialVersionUID = 1L;
    
    private String name;
    
    //接收 application
    private ServletContext application;
    //接收request
    private HttpServletRequest request;
    //接收response
    private HttpServletResponse response;
    //session可以通过 request 进行获取
    private HttpSession session;
    
    @Override
    public void setServletContext(ServletContext application) {
        this.application=application;
    }

    @Override
    public void setServletResponse(HttpServletResponse response) {
        this.response=response;
    }

    @Override
    public void setServletRequest(HttpServletRequest request) {
        this.request=request;
        this.session=request.getSession();
    }
    
    public String showData(){

        //获取application的值
        Integer count=(Integer)application.getAttribute("count"); 
        if(count==null){    
            count=1;
        }else{
            count=count+1;
        }
        //设置application的值
        application.setAttribute("count",count);
        
        
        //放置到session域 
        session.setAttribute("loginName",name);
        if("两个蝴蝶飞".equals(session.getAttribute("loginName"))){
            
            //放置到request域
            request.setAttribute("msg","第二种方式:欢迎您,"+session.getAttribute("loginName"));
            //展示ip 地址
            request.setAttribute("ip",request.getLocalAddr());
            
            //通过response 对象,设置cookie 
            
            Cookie cookie=null;
            try {
                cookie = new Cookie("userName",
                        URLEncoder.encode(session.getAttribute("loginName").toString(),"UTF-8"));
            } catch (UnsupportedEncodingException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
            cookie.setMaxAge(60*60);
            cookie.setPath("/");
            response.addCookie(cookie);
            
            //返回success 
            return SUCCESS;
        }
        //放置到request域
        request.setAttribute("msg","服务器提示:登录失败");
        return ERROR;
    }
    
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

里面多提供了 request获取客户端ip和 response添加 cookie的操作

一.二.二.二 配置struts.xml 文件

<!-- 配置第二种方式 -->
<action name="awareDemo" class="com.yjl.web.action.AwareDemo"
method="showData">
    <result name="success">/WEB-INF/content/success2.jsp</result>
    <result name="error">/WEB-INF/content/error.jsp</result>
</action>

一.二.二.三 编写前端界面

success2.jsp, 内容主要是:

<!--引入jquery文件,网络版的 -->
<script src="http://code.jquery.com/jquery-latest.js"></script>

<body>
    本站访问次数:${applicationScope.count} <br/>
    ${sessionScope.loginName},您已经成功登录<br/>
    ${requestScope.msg}<br/>
    ip:${requestScope.ip}<br/>
    cookie值:<span id="cookieValue"></span>
    
    <script>
        $(function(){
            var username = decodeURIComponent("${cookie.userName.value}");//如果为空,使用解码后为空字符串
            if(!username.length==0){
                $("#cookieValue").text(username);
            }
        })
    </script>
</body> 

一.二.二.四 重启服务器,进行验证

输入网址: http://localhost:8080/Struts_API/awareDemo?name=两个蝴蝶飞

有图片

ip地址和cookie 均可以正常获取。

用js 脚本,解决了 cookie 中文乱码的问题。

这种方式,还需要实现接口,重写里面的方法,如果需要同时获取request,response,application对象,那么需要实现三个接口,太复杂。

一.三 使用 ServletActionContext 工具类获取ServletAPI

一.三.一 ServletActionContext 提供方法

方法名 作用
static HttpServletRequest getRequest() 取得request对象
static HttpServletResponse getResponse() 取得response 对象
static ServletContext getServletContext() 取得application 对象

session依旧是通过 request 进行获取的。

一.三.二 编写Demo 验证一下

一.三.二.一 编写Action 类 ServletActionContextDemo

public class ServletActionContextDemo extends ActionSupport{

    private static final long serialVersionUID = 1L;
    private String name;
    public String showData(){
        //获取application对象
        ServletContext application=ServletActionContext.getServletContext();
        //获取request对象
        HttpServletRequest request=ServletActionContext.getRequest();
        //获取response对象
        HttpServletResponse response=ServletActionContext.getResponse();
        //获取session对象
        HttpSession session=request.getSession();
        
        //获取application的值
        Integer count=(Integer)application.getAttribute("count"); 
        if(count==null){    
            count=1;
        }else{
            count=count+1;
        }
        //设置application的值
        application.setAttribute("count",count);
        
        
        //放置到session域 
        session.setAttribute("loginName",name);
        if("两个蝴蝶飞".equals(session.getAttribute("loginName"))){
            
            //放置到request域
            request.setAttribute("msg","第三种方式:欢迎您,"+session.getAttribute("loginName"));
            //展示ip 地址
            request.setAttribute("ip",request.getLocalAddr());
            
            //通过response 对象,设置cookie 
            
            Cookie cookie=null;
            try {
                cookie = new Cookie("userName",
                        URLEncoder.encode(session.getAttribute("loginName").toString(),"UTF-8"));
            } catch (UnsupportedEncodingException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
            cookie.setMaxAge(60*60);
            cookie.setPath("/");
            response.addCookie(cookie);
            
            //返回success 
            return SUCCESS;
        }
        //放置到request域
        request.setAttribute("msg","服务器提示:登录失败");
        return ERROR;
    }
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

一.三.二.二 配置struts.xml 文件

<!-- 配置第三种方式 -->
<action name="servletDemo" class="com.yjl.web.action.ServletActionContextDemo"
method="showData">
    <result name="success">/WEB-INF/content/success2.jsp</result>
    <result name="error">/WEB-INF/content/error.jsp</result>
</action>   

一.三.二.三 编写 jsp文件

用的是上面的 success2.jsp 文件,不需要重复编写。

一.三.二.四 重启服务器,进行验证

输入网址: http://localhost:8080/Struts_API/servletDemo?name=两个蝴蝶飞

有图片

通过 ServletActionContext 工具类,获取request,response,session,application 对象,比较好,一般采用这种方式。

但是不通过这种方式来获取前端传递过来的数据,获取数据,struts2框架提供了更简单的方式。

二. 获取前端数据

二.一. 通过原始的 request 对象进行获取数据

二.一.一 编写Action

public class RequestData extends ActionSupport{
    private static final long serialVersionUID = -477463776005071632L;
    Logger logger=Logger.getLogger(RequestData.class);
    public String getData() {
        //有一个ServletActionContext对象来获取底层的HttpServletRequest
        HttpServletRequest request=ServletActionContext.getRequest();
        //如果获取的是单个数据,如text框,password,hidden,radio性别框,select单选框等。
        String userName=request.getParameter("userName");
        //如果获取的是checkbox,select多选框.
        String []hobbys=request.getParameterValues("hobbys");
        logger.info("姓名是:"+userName);
        if(hobbys!=null) {
            for (String hobby : hobbys) {
                logger.info("爱好有:"+hobby);
            }
        }
        return NONE;
    }
}

二.一.二 配置struts.xml

<!-- 通过获取request来获取前端数据 -->
<action name="requestData" class="com.yjl.web.action.RequestData"
method="getData">

</action>

<!-- 配置跳转页面,要把它放置到最后 -->
<action name="*">
    <result>/WEB-INF/content/{1}.jsp</result>
</action>

二.一.三 编写前端界面

要配置跳转页面的 action

在 /content 文件夹下,创建一个 request.jsp 页面

<body>
  <form action="requestData" method="post">
        用户名:<input type="text" name="userName"><br/>
        爱好: <input type="checkbox" name="hobbys" value="读书"> 读书
        <input type="checkbox" name="hobbys" value="编程"> 编程
        <input type="checkbox" name="hobbys" value="写小说">写小说<br/>
        <input type="submit" value="提交">
      </form>
</body>

二.一.四 重启服务器,进行验证

输入网址: http://localhost:8080/Struts_API/request , 会跳转到 /WEB-INF/content/request.jsp 页面,

有图片

名称填写 两个蝴蝶飞,爱好是编程和写小说

有图片

前端正常跳转,后端控制台打印输出:

有图片

ServletActionContext类可以直接获取request对象,response对象,application 对象,可以通过request.getSession()来获取session对象,

但是这种方式获取数据与Servlet产生了高度耦合,若非一些特殊数据需求,如客户端的ip地址,端口号等,不建议使用这种方式。而是采用 struts2框架提供的方式,来获取数据。

下面的例子,都可以正常访问,就不一 一 贴运行效果图了。struts.xml 的配置也很简单,也不一个一 个贴配置文件了。

二.二 通过 Struts2 框架提供的方式进行获取数据

二.二.一 Struts2获取单个普通的单值,如字符串和Integer 值

二.二.一.一 Demo展示

public class SimpleData extends ActionSupport{
    private static final long serialVersionUID = -477463776005071632L;
    Logger logger=Logger.getLogger(SimpleData.class);
    //name为单个值
    private String name;
    public void setName(String name) {
        this.name=name;
    }
    //多个值,用数组或者是List集合
    private String []hobbys;
    public void setHobbys(String[] hobbys) {
        this.hobbys = hobbys;
    }
    public String single() {
        logger.info("获取的姓名为:"+name);
        if(hobbys!=null) {
            for (String hobby : hobbys) {
                logger.info("爱好有:"+hobby);
            }
        }
        return NONE;
    }
}

前端页面为:

​​​​<form action="simpleData" method="post">
        用户名:<input type="text" name="name"><br/>
        爱好: <input type="checkbox" name="hobbys" value="读书"> 读书
        <input type="checkbox" name="hobbys" value="编程"> 编程
        <input type="checkbox" name="hobbys" value="写小说">写小说<br/>
        <input type="submit" value="提交">
</form>

二.二.一.二 注意事项

其中前端的表单的name值要与Action中属性的值相同,并且还需要在Action中实现相应的setter方法,只有这样,才可以进行封装数据。

如果是单个值,用普通的基本类型进行封装(Struts2自动处理了包装类,所以建议用包装类进行接收。String-->String,int--->Integer. 这样当输入年龄的数字时,可以直接将age转换成数字了。不用Integer.parseInt(age)进行转换了)

如果是多个值,如多选框和多选的select框,那么需要用数组 String []hobbys或者 集合 List []hobbys进行相应的接收。

通过这种setter() 方法的封装,叫做属性驱动。

当前端属性数目小时,可以通过这种方式进行封装, 当属性数目过多时,如员工档案数据,有name,age,email,phone 等大量数据时,就不建议用这种方式了。

二.二.二 表达式封装Bean实体类对象

在一个表单里面,如果表单的元素值过多,如一个注册页面,要传递很多的属性数据,如果都写成setter方法,对每一个属性,单独进行封装,那么在Action中会有很多setter() 方法,导致Action 类 会很麻烦。我们希望Struts2可以直接将表单数据封装成Java Bean对象。

二.二.二.一 Demo 展示

先新建一个User.java对象,里面封装一些基本的属性

     /**
     * @param id 主键编号
     * @param name 姓名
     * @param sex 性别
     * @param age 年龄
     * @param relation 关系
     */
    private Integer id;
    private String name;
    private String sex;
    private Integer age;
    private String relation;
 
    //重写toString()方法,方便查看
    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + ", sex=" + sex + ", age=" + age + ",     relation=" + relation + "]";
    }
    ...
        封装相应的setter 和 getter 方法。
    ...

在User.java 里面,提供封装setter和getter方法,重写toString()方法

新建UserAction类, 在里面封装User user 的属性,实现setter方法

/**
* @description 处理多个数据提交封装Java Bean的类
*/
public class UserAction extends ActionSupport{
    private static final long serialVersionUID = 5018178953781239408L;
    private Logger logger=Logger.getLogger(UserAction.class);
    private User user;
    public void setUser(User user) {
        this.user = user;
    }
    public User getUser() {
        return user;
    }
    public String setData() {
        logger.info("获取信息:"+user.toString());
        return NONE;
    }
}

前端form表单 /content/user.jsp

<body>
    <form action="Request_setData" method="post">
            姓名:<input type="text" name="user.name"><br/>
            性别:<input type="radio" name="user.sex" value="男">男
            <input type="radio" name="user.sex" value="女">女<br/>
            年龄:<input type="text" name="user.age"><br/>
            关系: <select name="user.relation">
                    <option>父子</option>
                    <option>母子</option>
                    <option>姐弟</option>
                    <option>妻弟</option>
                </select>
            <br/>
            <input type="submit" value="提交">
    </form>
</body>

运行Tomcat服务器,填写基本的数据后,控制台可以正常的打印前端输入的数据。

二.二.二.二 注意事项

  1. 实体类中属性值要与前端表单中的值相同(去除user.后),

  2. UserAction中user 只是private User user,并没有将其实例化成private User user=new User(), Struts2会自动将其实例化。

  3. input框中name="对象.属性", 这个对象指的是要将数据封装到哪个实体类对象。如果是private User a; 那么这个时候就是name="a.name"

  4. 在Action中,必须要实现user的setter和getter()方法,只单独实现setter方法是不行的。

  5. 如果在Action中有 user 类和 teacher类,其中 user中有name属性,teacher 类也有name属性,那么 用 user.name 表达员工的姓名,teacher.name 表示教师的名称, 可以很方便的进行区分。

二.二.三 模型驱动封装 Java Bean对象。

需要Action 实现ModelDriven<T>接口

二.二.三.一 ModelDriven 接口定义

public interface ModelDriven<T> {
    T getModel();
}

需要重写里面的 getModel() 方法。

二.二.三.二 Action实现

/
* @description 处理多个数据提交封装Java Bean的类
*/
public class UserAction2 extends ActionSupport
implements ModelDriven<User>{
    private static final long serialVersionUID = 5018178953781239408L;
    private Logger logger=Logger.getLogger(UserAction.class);
    // 需要直接实例化,不然会返回NPE 异常
    private User user=new User();
    @Override
    public User getModel() {
        return user;
    }
    public String setData() {
        logger.info("获取信息:"+user.toString());
        return NONE;
    }
}

前端时,/conent/user2.jsp

<form action="User2_setData" method="post">
    姓名:<input type="text" name="name"><br/>
    性别:<input type="radio" name="sex" value="男">男
    <input type="radio" name="sex" value="女">女<br/>
    年龄:<input type="text" name="age"><br/>
    关系: <select name="relation">
            <option>父子</option>
            <option>母子</option>
            <option>姐弟</option>
            <option>妻弟</option>
        </select>
    <br/>
    <input type="submit" value="提交">
</form>

重启服务器,输入数据,可以正常的接收到数据。

二.二.三.三 注意事项

  1. 实现ModelDriven<T> 接口时,T为具体要封装的类型, 封装到user中,为User. 封装到class中为Class.

  2. user对象需要实例化,必须自己手动实例化. private User user=new User(); 如果不实例,会空指向异常的.

  3. 不需要实现对象的setter和getter方法,只需要重写ModelDriven中的getModel()方法即可,返回相应的对象。

  4. 在前端时,去除封装对象前缀., 因为ModelDriven中只有一个类型,所以知道封装到哪个对象. 在前端jquery动态操作时,也方便使用。

  5. 表单中的属性值必须与类中的属性值完全保持一致。 开发时,为了简便开发,可以将表单数据与实体类属性完全一致,实体类属性与数据库数据基本一致, 数据库字段值最好为类名第一个字母小写+类中的属性。 表名为t+实体类名。

  6. 如果前端既传入user的name,也传入teacher的name, 那么将无法区分name的值。 故同一个表单中元素的name值必须保证唯一。

二.二.四 三种数据封装方式的比较

上面就是Struts2提供的三种数据封装的方式,

  1. setter和getter方法封装属性的属性驱动

  2. 对象.属性名的表达式封装方式

  3. 实现ModelDriven接口的模型驱动方式。

二.二.四.一 三种方式的区别与联系

  1. 表达式封装和模型驱动封装,都可以直接封装成Java Bean实体类对象,表达式封装时前端需要对象.属性,要有对象的前缀.,模型驱动不需要。

  2. 表达式封装,不需要将对象实例化,而模型驱动却必须将封装的对象显式实例化,否则会出现空指向异常。

  3. 表达式可以封装多个对象中相同的属性值

private User user;
private Teacher teacher;
//user和teacher的setter和getter方法

在前端时, user.name, user.age 表示封装到 user对象中
         teacher.name, teacher.age ,表示封装到teacher 对象中 
  1. 模型驱动并不能像表达式封装那样,明确指明哪一个属性属于哪一个对象。 如果有一个name属性,User 对象有,Teacher 对象也有, ModelDriven<User>对象时,那么这个name即使想表示的是Teacher对象的,也会被封装成user对象的。

ModelDriven<Teacher>对象时,那么这个name即使想表示的是User对象的,也会被封装成 teacher 对象的。

  1. 模型驱动封装与属性驱动的顺序

当属性驱动与模型驱动同时存在时,name在User对象中, 进行了模型驱动封装,并且还实现了name的setter和getter方法,那么这个时候:

    private User user=new User();
    @Override
    public User getModel() {
        return user;
    }
    private String name;
    public void setName(String name) {
        this.name = name;
    }
 
    public String setData() {
        //为null
        logger.info("属性驱动:"+name);
        //获取前端传入的值 
        logger.info("模型驱动:"+user.getName());
        return NONE;
    }
image

模型驱动能够取到值。

二.二.五 提供Action公共代码,创建 BaseAction

在开发中,最常用的是模型驱动,因为这样方便一些。 但每一个类都是继承ActionSupport,实现ModelDriven<T> 接口,太麻烦,一般会用一个BaseAction类来实现。

放置在 com.yjl.utils 包下。

BaseAction.java

package com.yjl.utils;
import java.lang.reflect.ParameterizedType;
import org.apache.log4j.Logger;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
/**
* @author 两个蝴蝶飞
* @version 创建时间:2018年8月23日 下午4:40:13
* @description BaseAction的工具类
*/
@SuppressWarnings(value= {"rawtypes","unchecked"})
public class BaseAction<T> extends ActionSupport implements ModelDriven<T>{
    private static final long serialVersionUID = -7180401147510521582L;
    private Logger logger=Logger.getLogger(BaseAction.class);
    private T t;
    private Class clazz;
    public BaseAction() {
        //得到当前的类
        Class class1=this.getClass();
        //得到运行中的父类
        ParameterizedType parameterizedType=(ParameterizedType) class1.getGenericSuperclass();
        clazz=(Class) parameterizedType.getActualTypeArguments()[0];
        try {
            t=(T) clazz.newInstance();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        logger.info("当前类的类:"+clazz.getName()+"完成初始化");
    }
    @Override
    public T getModel() {
        return t;
    }
    
}

然后UserAction类只需要继承BaseAction类即可

public class UserAction extends BaseAction<User>{
    //取user对象时,用 super.getModel()
}

TeacherAction 类只需要继承BaseAction 类即可

public class TeacherAction extends BaseAction<Teacher>{
    //取teacher对象时,用 super.getModel()
}

这样就可以了。

二.二.六 属性驱动封装List 集合

封装list集合,可以批量添加对象时使用,批量修改对象时使用。

/
* @description 处理多个对象数据提交封装List集合
*/
public class UserAction6 extends ActionSupport{
    private static final long serialVersionUID = 5018178953781239408L;
    private Logger logger=Logger.getLogger(UserAction.class);
    private List<User> userList;
    public List<User> getUserList() {
        return userList;
    }
    public void setUserList(List<User> userList) {
        this.userList = userList;
    }
    public String setData() {
        if(userList!=null) {
            for (User user : userList) {
                logger.info(user.toString());
            }
        }
        return NONE;
    }
}

其中前端表示为: /content/user6.jsp

<form action="User6_setData" method="post">
    姓名:<input type="text" name="userList[0].name"><br/>
    性别:<input type="radio" name="userList[0].sex" value="男">男
    <input type="radio" name="userList[0].sex" value="女">女<br/>
    年龄:<input type="text" name="userList[0].age"><br/>
    关系: <select name="userList[0].relation">
            <option>父子</option>
            <option>母子</option>
            <option>姐弟</option>
            <option>妻弟</option>
        </select>
    <br/>
    <hr/>
    姓名:<input type="text" name="userList[1].name"><br/>
    性别:<input type="radio" name="userList[1].sex" value="男">男
    <input type="radio" name="userList[1].sex" value="女">女<br/>
    年龄:<input type="text" name="userList[1].age"><br/>
    关系: <select name="userList[1].relation">
            <option>父子</option>
            <option>母子</option>
            <option>姐弟</option>
            <option>妻弟</option>
        </select>
    <br/>
    <input type="submit" value="提交">
</form>

list数据提交时, name=list属性名[下标].属性值。

二.二.七 属性驱动封装Map 集合

UserAction7.java 封装

/**
* @description 处理多个对象数据提交封装Map
*/
public class UserAction7 extends ActionSupport{
    private static final long serialVersionUID = 5018178953781239408L;
    private Logger logger=Logger.getLogger(UserAction.class);
    private Map<String,User> maps;
    public Map<String, User> getMaps() {
        return maps;
    }
    public void setMaps(Map<String, User> maps) {
        this.maps = maps;
    }
    public String setData() {
        if(maps!=null) {
            /* 
             * 第一种遍历Map的方式  用keySet遍历
             * Set<String> sets=maps.keySet();
            Iterator <String> iterator=sets.iterator();
            while(iterator.hasNext()) {
                String key=iterator.next();
                User value=maps.get(key);
                logger.info(key+"------>"+value.toString());
            }*/
            //用第二种方式 entrySet
          Set<Entry<String,User>> sets=maps.entrySet();
          for (Entry<String, User> entry : sets) {
               String key=entry.getKey();
               User value=entry.getValue();
               logger.info(key+"------>"+value.toString());
            }
        }
        return NONE;
    }
}

前端时: /content/user7.jsp

<form action="User7_setData" method="post">
    姓名:<input type="text" name="maps['one'].name"><br/>
    性别:<input type="radio" name="maps['one'].sex" value="男">男
    <input type="radio" name="maps['one'].sex" value="女">女<br/>
    年龄:<input type="text" name="maps['one'].age"><br/>
    关系: <select name="maps['one'].relation">
            <option>父子</option>
            <option>母子</option>
            <option>姐弟</option>
            <option>妻弟</option>
        </select>
    <br/>
    <hr/>
    姓名:<input type="text" name="maps['two'].name"><br/>
    性别:<input type="radio" name="maps['two'].sex" value="男">男
    <input type="radio" name="maps['two'].sex" value="女">女<br/>
    年龄:<input type="text" name="maps['two'].age"><br/>
    关系: <select name="maps['two'].relation">
            <option>父子</option>
            <option>母子</option>
            <option>姐弟</option>
            <option>妻弟</option>
        </select>
    <br/>
    <input type="submit" value="提交">
</form>

运行输入数据:

image

二.二.八 属性封装到Set中

基本没有使用,简单写一下

UserAction8.java

    @KeyProperty("id")
    private Set<User> userSet=new HashSet<User>();
 
    public Set<User> getUserSet() {
        return userSet;
    }
 
    public void setUserSet(Set<User> userSet) {
        this.userSet = userSet;
    }
    public String setData() {
        if(userSet!=null) {
            System.out.println("不为空"+userSet.size());
            for (User user : userSet) {
                System.out.println(user.toString());
            }
        }else {
            System.out.println("为空");
        }
        return NONE;
    }

jsp页面: /content/user8.jsp

<form action="Request_setData" method="post">
    姓名:<input name="userSet.makeNew[0].name" type="text"/><br/>
    姓名:<input name="userSet.makeNew[1].name" type="text"/><br/>
    <input type="submit" value="提交"/>
</form>

set集合比较特殊,没有顺序,所以不能用[0][1] 下标的方式进行,需要用 set名称.makeNew[下标].属性

并且Action中set需要添加一个注解 @keyProperty("id") 其中id为User类的唯一标识。(建议重写User 类的hashCode和equals()方法)

数据封装所配置的struts.xml 文件为:

<!-- 通过获取request来获取前端数据 -->
    <action name="requestData" class="com.yjl.web.action.RequestData"
    method="getData">
    </action>
    
    <!-- 通过setter 方法封装单值  -->
    <action name="simpleData" class="com.yjl.web.action.SimpleData"
    method="single">
    </action>
    
    <!-- 通过表达式封装java bean 对象 -->
    <action name="User_setData" class="com.yjl.web.action.UserAction"
    method="setData">
    </action>
    
    <!-- 通过模型驱动封装java bean 对象 -->
    <action name="User2_setData" class="com.yjl.web.action.UserAction2"
        method="setData">
    </action>
    
    <!-- 属性驱动封装List 集合 -->
    <action name="User6_setData" class="com.yjl.web.action.UserAction6"
        method="setData">
    </action>
    
    <!-- 属性驱动封装Map 集合 -->
    <action name="User7_setData" class="com.yjl.web.action.UserAction7"
        method="setData">
    </action>
    
    <!-- 属性驱动封装Set 集合 -->
    <action name="User8_setData" class="com.yjl.web.action.UserAction8"
        method="setData">
    </action>

本章节代码链接为:

链接:https://pan.baidu.com/s/1RK1RlGqoKKm51kruKJ5cqg 
提取码:l5d5

谢谢您的观看!!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349