Struts第二阶段

struts2

Struts2访问Servlet的API

完全解耦和的方式实现Servlet的API的访问

  • 获取ActionContext
    ActionContext actionContex=ActionContext.getContext();

  • 接受参数:
    解耦和的方式通过ActionContext中的方法实现:

1
2
3
4
5
6
7
8
9
10
11
12
Map<String,Object> getParamters(); //Object是一个字符串类型的数组
Map<String,Object> getSession();
Map<String,Object> getApplication();
void setSession(Map<String,Object> session);
void setApplication(Map<String,Object> application);
//向request中存数据
actionContext.put(String name,Object object);
//向session中存数据
actionContext.getSession.put(String name,Object object);
//向application中存数据(ServletContext对象)
actionContext.getApplication().put(String name,Object object);
  • post提交不用管中文action会管了,get提交需要设置

通过实现特定的接口来实现Servlet的API的访问

  • 让action类去实现ServletRequestAware接口,然后在成员位置定义一个HttpServletRequest变量,下边重写一个setServletRequest方法,让成员的request等于方法中的,可以当作正常的request用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class RequestDemo2Action extends ActionSupport implements ServletRequestAware,ServletContextAware{
    private HttpServletRequest request ;
    private ServletContext application;
    @Override
    public String execute() throws Exception {
        // 接收参数:需要使用request对象。
        Map<String, String[]> parameterMap = request.getParameterMap();
        for (String key : parameterMap.keySet()) {
            String[] value = parameterMap.get(key);
            System.out.println(key+"   "+Arrays.toString(value));
        }
        // 向request域中存值:
        request.setAttribute("reqName", "r郝天一");
        // 向session域中存值:
        request.getSession().setAttribute("sessName", "s郝思聪");
        // 向application域中存值:
        application.setAttribute("appName", "a郝冠希");
        return SUCCESS;
    }
    @Override
    public void setServletRequest(HttpServletRequest request) {
        this.request = request;
    }
    @Override
    public void setServletContext(ServletContext application) {
        this.application = application;
    }
}
  • 如果想用ServletContext对象,则在实现一个ServletContextAwre接口,方式跟上边的一样。

通过ServletActionContext的静态方法实现Servlet的API的访问

struts核心包中的api

1
2
3
4
5
//获取request对象
HttpServletRequest request = ServletActionContext.getRequest();
Map(String,String[]) paramterMap=request.getParameterMap();
//获取ServletContext参数
ServletContext application=ServletActionContext.getServletContext();

Struts2的数据的封装

Struts2的多例

  • 因为action是多例的,意思就是每次刷新页面都会重新执行action类
    多例的话就可以使用成员变量,创建Service的时候,就可以放成全局。

属性驱动

Struts既有控制层,又有模型层。

  • 提供属性的set方法完成数据的封装
    • 在action类中,定义要接受的属性的成员变量,只提供set方法,即可获取属性值
    • 这种方式应用的不多,因为还需要手动装到对象中。

  • 在页面中提供表达式(OGNL)的方式完成数据封装(直接封装到实体对象中)

    • 在页面中这样写name,前面的user必须跟action中成员方式的对象名一致。

    • 在action类中的成员位置加一个实体类对象,并提供get跟set方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     public class User2Action  extends ActionSupport{
       private User user;
       // 需要提供get和set方法:
       public User getUser() {
           return user;
       }
       public void setUser(User user) {
           this.user = user;
       }
       @Override
       public String execute() throws Exception {
           System.out.println(user);
           return NONE;
       }
    }
  • 注:

    • 在第二种方法中,必须有get set方法
    • 因为属性驱动是在拦截器中执行的,他需要把action中的对象实例化,所以要get到,如果不给提供get方法,则,每次封装的时候都会自动创建一个新的实例对象,这样会导致使用这个对象时只会有第一个封装进来的值
    • 拦截器在strut-default.xml中

模型驱动

采用模型驱动的方式来实现(推荐):

  • 页面即用普通页面。
  • 让action来实现一个 ModelDriver/ 接口,里面必须手动构建对象。
    T是要封装的那个实体的类型

  • OGNL表达式的方式和模型驱动都有使用的。
    模型驱动通常会使用的方式。有一个缺点,就是只能封装到一个对象中,如果想封装到多个对象,就需要用到OGNL

Struts2中复杂类型数据的封装

封装到List集合中

页面:

1
2
3
4
5
6
7
8
9
10
<h1>批量插入商品</h1>
<form action="${ pageContext.request.contextPath }/product1Action.action" method="post">
    商品名称:<input type="text" name="list[0].name"><br/>
    商品价格:<input type="text" name="list[0].price"><br/>
    商品名称:<input type="text" name="list[1].name"><br/>
    商品价格:<input type="text" name="list[1].price"><br/>
    商品名称:<input type="text" name="list[2].name"><br/>
    商品价格:<input type="text" name="list[2].price"><br/>
    <input type="submit" value="批量导入">
</form>

Action:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
 * Struts2复杂数据类型的封装:封装到List集合中
 * @author jt
 *
 */
public class Product1Action extends ActionSupport{
    private List<Product> list;
    
    public List<Product> getList() {
        return list;
    }
    public void setList(List<Product> list) {
        this.list = list;
    }
    @Override
    public String execute() throws Exception {
        for (Product product : list) {
            System.out.println(product);
        }
        return NONE;
    }
}

封装到Map集合

页面:

1
2
3
4
5
6
7
8
9
10
<h1>批量插入商品:封装到Map集合</h1>
<form action="${ pageContext.request.contextPath }/product2Action.action" method="post">
    商品名称:<input type="text" name="map['one'].name"><br/>
    商品价格:<input type="text" name="map['one'].price"><br/>
    商品名称:<input type="text" name="map['two'].name"><br/>
    商品价格:<input type="text" name="map['two'].price"><br/>
    商品名称:<input type="text" name="map['three'].name"><br/>
    商品价格:<input type="text" name="map['three'].price"><br/>
    <input type="submit" value="批量导入">
</form>

Action:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
 * Struts2的复杂数据的封装:Map集合的封装
 * @author jt
 *
 */
public class Product2Action extends ActionSupport{
    private Map<String,Product> map;
    
    public Map<String, Product> getMap() {
        return map;
    }
    public void setMap(Map<String, Product> map) {
        this.map = map;
    }
    @Override
    public String execute() throws Exception {
        for (String key : map.keySet()) {
            Product product = map.get(key);
            System.out.println(key+"   "+product);
        }
        return NONE;
    }
}

Struts中结果页面的配置

结果页面的分类:

  • 全局结果页面
    • 可以对所有的action都有效
  • 局部结果页面
    • 在 /< action /> 内部配置 /< result /> ,只会对当前的Action有效。

如果有全局页面跟局部页面同时存在的时候,首先要看局部页面。

全局结果页面的配置
1
2
3
4
5
<package>
  <global-results>
    <result name="success">地址。。。</result>
  </global-results>
</package>
局部结果页面的配置
1
2
3
4
5
<package>
  <action>
    <result name="success">地址。。。</result>
  </action>
</package>

Struts2结果页面类型的配置

  • /< result /> 标签上还有一个属性:
    • name :逻辑视图名称。
    • type :页面跳转的类型
      • dispather :默认值,转发,转发到jsp页面
      • chain :转发到一个Action
      • redirect :重定向。重定向到jsp
      • redirectAction :重定向到一个Action,重定向的时候如果不是在一个命名空间中,可以自己加上属性,(在result下面加param标签)
      • stream :文件下载的时候

struts2中内置数据类型的转换

  • 会把传过来的特殊数据类型转换为实体中需要的类型,integer,date都能封装。 都是在拦截器执行的。

  • 当转换失败时,会到Workflow拦截器,然后查看是否有这个错误,如果有会运行一个input视图中有错误信息,跳转到input的页面中。 例如Integer中添了一个字母。

    • 可以在配置文件中,设置一个input的跳转页面,当有错误时,会跳转到这个页面
    • 这个页面中可以加一个标签,显示错误信息
1
2
3
4
   <%@ taglib uri="/struts-tags" prefix="s" %>
   //可以加两个标签,是哪个错误会显示哪个错误
   <s:actionerror/>
   <s:fielderror/>

注:

  • 有的时候elipse会编译前一段时间的代码,修改之后不会及时编译最新的,可以把tomcat中的webapps项目中的class文件删除,然后再在elispe中,project/build all手动编译一下。

  • struts2中的带的log4j是2.2版本的,hibernate中是1.几版本的,所以不能把hibernate中的配置文件中copy过来直接用,可以在struts2提供的项目模板中找一个,2.2版本的配置文件是 .xml 的

张冲 wechat
欢迎扫一扫上面的微信关注我,一起交流!
坚持原创技术分享,您的支持将鼓励我继续创,点击打赏!