简介

早期的jsp页面需嵌入大量的Java脚本来显示后台传递的数据,不但大大降低了可读性,而且非常不利于维护。

对于一个MVC框架而言,主要实现两个部分:业务逻辑控制器和视图页面显示。而Struts2 作为一款优秀的开源框架,很好的实现了这两部分。前者交给Action,而后者则由其内置的统一标签库来实现。

struts2_taglib.png

控制标签


control_taglib.png

if/else

  • if/else用法,这个没什么好说的。
      <s:if test="5<3"> <!-- test为变量名,可自定义,即将5<3比较            的结果返回给一个变量,然后由if判断-->
          5<3
      </s:if>
      <s:elseif test="8%2==0">
          <span>8%2==0</span>
      </s:elseif>
      <s:else>
          <p>都不对</p>
      </s:else>

iterator迭代器

  • 标签库同样支持iterator迭代器:

      <table border="2" cellspacing="0" cellpadding="0">
          <s:iterator value="{'JavaWeb','PHP','Python','JavaScript','Android'}" var="language" status="st">
              <s:if test="#st.odd">
                  <tr style="background-color:green">
                      <td><s:property value="language"/></td>
                  </tr>
              </s:if>
              <s:else>
                  <tr style="background-color:gray">
                      <td><s:property value="language"/></td>
                  </tr>
              </s:else>
          </s:iterator>
      </table>

    其中value中的值为一个数组/集合,这里为直接传入,也可以通过嵌入Data标签来传入后台传递过来的一个数组/集合;var中定义一个变量名,代表每次迭代出来的值,即每次迭代都会更新这个language变量;status中定义了一个对象名,此对象可以通过调用方法返回当前迭代状态,以上都是struts2内置的拦截器拦截属性,然后通过注入的方式实现的。

  • status属性调用的方法:

  1. st.count->返回当前已遍历的集合元素个数
  2. st.first->返回boolean类型,是否为集合的第一个元素
  3. st.last->同上,是否为集合中的最后一个元素
  4. st.index->返回当前遍历元素的索引
  5. st.even->返回当前遍历元素的索引是否为偶数
  6. st.odd->同上,…是否为奇数
<%    List<String> str = new ArrayList<String>();
        str.add("one");
        str.add("two");
        request.setAttribute("str", str);
%>
<div>
<center>
    <h3>------------方式二(输出:Servlet API)------------</h3>
    <s:iterator value="#request.str" var="strs">
        <s:property value='strs'/>
    </s:iterator>
</center>
</div>

上述定义了一个集合,然后将其放入request对象中(此request对象并不同于我们以前没有用框架时的servlet那样,是一个HttpServletRequest对象,由于Struts2为了与Servlet API进行解耦,方便模块化测试,将各种各样的映射关系都转化为Map类型的对象,然后放入ContextMap中,有关值栈后面会讲到),在value中通过#键来取出放在ContextMap中的Map类型。

数据标签


data_taglib.png

property标签

<h2>------------property标签------------</h2>
    <s:property value="'<h2>有h2标签(不忽略)</h2>'" escape="false"/><br>
    <s:property value="'<h2>有h2标签</h2>(忽略)'" escape="true"/><br>
    <s:property value="" default="value为null,因此此为默认值"/><br>
    <br><br>
    <span>debug标签:<s:debug></s:debug></span>

数据标签大部分都使用property,其自动将value中的值看做变量或一个key,然后自动到值栈中去取出对应的值,如果只是单纯传入字符串,得加上单引号。

a标签和debug标签

<h2>------------<s:text name="a标签"/>------------</h2>
    <s:a href="success.jsp">success.jsp</s:a><br>
    <s:a namespace="/" action="BlogAction_onCreate" method="post">action</s:a>

a标签比较特别的地方就是可以通过action属性并且指定方法(post/get)来跳转到一个action对象;等会还会讲到s:url标签,也是可以跳转的。

<s:debug>标签用于调试程序时输出更多的调试信息,主要输出ValueStack和StackContext中的信息,其只有一个id属性,一般不使用。

include标签与param标签

<center>
<h2>------------include标签------------</h2>
    <p>包含页</p>
    <s:include value="file.jsp">
        <s:param name="user" value="'test'"/>
    </s:include>
</center>

param标签往往需要嵌入其它标签来进行传参,然后对应的页面通过request.getParameter(name值)来去值(value)。

<!-- file.jsp页面 -->
<body>
<div style="width:400px;margin:20px auto;border-bottom:2px double green;">
    <a href="login.jsp"><%out.print(request.getParameter("user")); %></a>
</div>
</body>

表单标签


form_taglib.png

基本表单标签:

<s:actionerror/>
<s:form action="login" namespace="/" method="post" enctype="application/x-www-form-urlencoded">
<!-- enctype默认值,若有文件上传,则改为multipart/form-data -->
    <s:textfield label="用户名" name="username" required="true"></s:textfield>
    <s:password label="密码" name="password" required="true" maxlength="15" showPassword="true"></s:password>
    <s:submit value="提交" name="submit" action="BlogAction_onCreate"></s:submit>
    <s:reset value="重置" name="reset"></s:reset>
</s:form>

属性基本跟H5没差,H5中输入框只需加上required就可以成为必填项了。只是这里的标签库还应用了Struts2默认的主题xhtml,其将这些控件用table来进行排版布局,其它主题还有simple,css_xhtml。

扩展:

  • 1.x-www-form-urlencoded
    当action为get时候,浏览器用x-www-form-urlencoded的编码方式把form数据转换成一个字串(name1=value1&name2=value2…),然后把这个字串append到url后面,用?分割,加载这个新的url。

  • 2.multipart/form-data
    当action为post时候,浏览器把form数据封装到http body中,然后发送到server。 如果没有type=file的控件,用默认的application/x-www-form-urlencoded就可以了。 但是如果有type=file的话,就要用到multipart/form-data了。浏览器会把整个表单以控件为单位分割,并为每个部分加上Content-Disposition(form-data或者file),Content-Type(默认为text/plain),name(控件name)等信息,并加上分割符(boundary)。

actionerror标签

或许你已经注意到第一行中的s:actionerror标签,其用来显示用户点击提交后服务器反馈回来的信息(如:密码错误等)。

// LoginAction.java
public String execute(){

        ActionContext context = ActionContext.getContext();
        if("zhl".equals(user.getUsername())&&"123".equals(user.getPassword())){
            context.getSession().put("user", user);
            return SUCCESS;
        }else {
            addActionError(getText("oneofthem.error"));
            return INPUT;
        }
    }

其中的addActionError和getText方法是继承自ActionSupport,而oneofthem.error是在同一包下的LoginAction.properties文件中以键值对的形式定义的。

# error message
username.required = 用户名不能为空!
password.required = 密码不能为空!
oneofthem.error = 用户名或密码错误!

其它表单标签

textarea标签

<s:textarea label="备注" name="notes" cols="21" rows="7" style="resize:none"></s:textarea>

21行、7列的文本输入域,不可调整大小。

checkbox与checkboxlist标签

    <s:checkbox label="Java" name="java" value="true" fieldValue="java"></s:checkbox>
    <s:checkbox label="Python" name="python" value="" fieldValue="python"></s:checkbox>

    <s:checkboxlist label="爱好" name="interest" labelposition="left" list="{'音乐2', '篮球2'}"></s:checkboxlist>
    <s:checkboxlist label="爱好" name="interest" labelposition="left" list="#{'0':'音乐','1':'篮球'}"></s:checkboxlist>

    <s:radio label="专业方向" name="major" list="{'JavaEE','Android'}" value="'JavaEE'"/>
    <s:radio label="Gender" name="gender" list="#{0:'male',1:'female'}" value="1"/>

checkbox标签中的value并非像input时那样作为一个值传递,而是像input中的checked一样,true为默认选中(false相反);这里真正传值的是fieldValue属性中的值。

checkbox_list_two.png
由上图可知,checkboxlist中的list属性若是选择传入一个数组,则转换为H5时其中的value值默认与其显示的相同,而传入一个map对象则不同,所以相较之下后者方法比较灵活;

radio标签中的list同上,只是需要注意,设置默认值时若list中为map对象,则直接通过key值进行设置;若为集合/数组,则直接通过值来选择,只不过需要额外加上单引号。第一幅图最下面的action超链接涉及到值栈内容,下面再进行分析。

select和optgroup标签

select_optgroup.png

select_optgroup_h5.png

    <s:select label="所学内容" name="course" size="1" headerKey="-1" headerValue="请选择" list="#{'java web':'java web', '数据库':'数据库' }">
        <s:optgroup label="JAVA WEB" list="#{'jsp':'jsp', 'servlet':'servlet', 'javaBean':'javaBean' }"></s:optgroup>
        <s:optgroup label="JAVA流行框架" list="#{'ssh':'ssh', 'ssm':'ssm' }"></s:optgroup>
    </s:select>

list用法同上

file和hidden标签

    <s:file name="uploadFile" accept="image/png" label="图片"></s:file>
    <s:file name="otherUploadFile" accept="text/plain" label="文本"></s:file>
    <s:hidden name="id" value="5"></s:hidden>

hidden标签在页面上没有显示,可以保存或交换数据,例如:若想提交时传入一个额外的参数,可以用此标签。

非表单标签


  1. <s:actionerror>:上文中出现过,此类标签用法类似,通过action示例调用方法addActionError(String msg)添加,通过action实例中的getActionError方法返回(若不为null则显示信息)。

  2. <s:actionmessage>:通过addActionMessage(String msg)添加,通过action实例中的getActionMessage方法返回(若不为null则显示信息)。

  3. <s:fielderror>:通过addFieldError(String fieldName, String msg)方法添加,如果表单域出现类型转换错误、校验错误,则此标签会输出信息。

Ajax标签


在Struts2中配置ajax

在下载的struts中的lib包下找到struts2-dojo-plugin-xxx.jar,然后加入到build path项目环境中,最后在使用到ajax标签的jsp页面上设置如下两条标签即可:

  1. 页面顶部加入:
    <%@ taglib prefix=”sx” uri=”/struts-dojo-tags” %>
  2. head标签中加入:
    <sx:head debug=”true” compressed=”false”/>

其中debug的作用,顾名思义其是开启了调试模式,会有信息输出;而compressed则将这个像ajax插件一样的东西压缩后再使用。

Test1:通过设置输入流,异步传递信息

Test1_inputStream.png

<!-- url标签 用于生成一个URL地址,使用时用通过%{id标识符}来引用 -->
      <s:url id="time" value="/ajax/time"/>
      <s:url id="welcome" value="/ajax/welcome"/>

      <p>每隔一秒异步访问一次</p><br>
      <sx:div href="%{time}" updateFreq="1000"></sx:div>

      <p>异步访问一次</p><br>
      <sx:div href="%{welcome}" showLoadingText="true" loadingText="正在加载内容,请稍后..." errorText="加载失败,请稍后再试!"></sx:div>
  • 通过页面返回信息

上面通过异步访问了一个action,其中time中的execute方法没做什么事情,只是用来返回页面信息的,下面为返回的页面中的一个脚本。

<%
            //获得当前时间
            long currentTime = System.currentTimeMillis();

            //取出session中存入的现在时间
            Long startTime = (Long) session.getAttribute("currentTime");
            if (startTime == null) {
                //第一次访问
                session.setAttribute("currentTime", currentTime);
            } else {
                //以秒计算计算已用时间
                long used = (currentTime - startTime) / 1000;
                session.setAttribute("used", used);
                //当用户浏览网页时间超过60秒则提示用户休息一下。
                boolean flag = false;
                if (used > 60) {
                    flag = true;
                }
                session.setAttribute("flag", flag);
            }
        %>
        <s:if test="#session.flag==true">
         你该稍微休息一下了。
         </s:if>
        <s:else>
         你已经访问的时间:<s:property value="#session.used" default="0" /></s:else>
  • 通过输入流返回信息

而welcome则通过action中的输入流返回一串字符信息:

public String execute() throws Exception {
    Thread.sleep(3000L);
    inputStream = new ByteArrayInputStream("保存成功!".getBytes("UTF-8"));
    return SUCCESS;
}

下面是struts.xml配置:

<action name="welcome" class="com.livejq.action.WelcomeAction">
    <result type="stream">
        <param name="contentType">text/html</param>
        <param name="inputName">inputStream</param>
    </result>
</action>

inputStream为你在actino中设置的属性名(相应的getter/setter方法)

Test2:点击事件绑定,异步操作

Test2_click.png

<input type="button" id="myButton" value="保存">  
      <sx:bind  id="myBind" href="%{welcome}" sources="myButton" events="onclick" targets="showMsg"></sx:bind>
      <s:div id="showMsg"></s:div>

这里都是通过id值来进行唯一标识的,sources为事件源,events为事件名(这里与JavaScript中的事件名一致,如onchange、onmousedown等),targets为显示事件响应的结果。

Test3:单击超链接异步访问指定Action

Test3_action.gif

<s:url id="login" value="/login.jsp" />
      <sx:a href="%{login}" targets="div1" >登录</sx:a>
      <sx:div id="div1" cssStyle="border:1px solid red;">显示登陆后的信息</sx:div><br>

Test4:日期控件

Test4_calendar.gif

<sx:datetimepicker  
        adjustWeeks="true"  
        displayFormat="yyyy-MM-dd"  
        toggleType="explode"><!-- plain/wipe/explode/fade(不过好像没什么不同。。)-->  
    </sx:datetimepicker>

Test5:自动完成功能的组合框

Test5_complete_auto.gif

<s:a action="/ajax/autocomplete">测试ajax自动完成功能</s:a>

这个是入口链接,只有这样才能在action中取出list数据集合,然后在返回的页面中根据用户输入提示来进行自动显示。

下面是action配置:

<action name="autocomplete" class="com.livejq.action.AutocompleteAction" method="initializeList">
    <result>/welcome.jsp</result>
    <result name="none">
        <param name="location">/autocompleter.jsp</param>
    </result>
</action>

action中的处理是这样的:

package com.livejq.action;

import java.util.ArrayList;
import java.util.List;
import com.opensymphony.xwork2.ActionSupport;
public class AutocompleteAction extends ActionSupport{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    //data members
    private List<String> subjectList;
    private String selectedSubject;

    //business logic
    public String execute(){
        return SUCCESS;    
    }

    //getter setters
    public List<String> getSubjectList() {
        return subjectList;
    }

    public void setSubjectList(List<String> subjectList) {
        this.subjectList = subjectList;
    }

    public String getSelectedSubject() {
        return selectedSubject;
    }

    public void setSelectedSubject(String selectedSubject) {
        this.selectedSubject = selectedSubject;
    }    

    public String initializeList(){
        subjectList = new ArrayList<String>();
        subjectList.add("Java");
        subjectList.add("C");
        subjectList.add("C++");
        subjectList.add("Compiler");
        subjectList.add("DBMS");
        subjectList.add("Data Structure");

        return NONE;
    }    
}

在点击连接时,action中的配置为直接执行AutocompleteAction中的initializeList方法,其构造出一个list集合作为数据返回(加入ObjectStack值栈中),然后跳转到如下页面显示。

这是action返回的结果页面:

<s:form action="auto_submit">
    <sx:autocompleter label="请输入编程语言" 
        list="subjectList" name="selectedSubject" showDownArrow="false"/>
    <s:submit value="Submit"/>
</s:form>

其中属性list中的值(一个字符串集合)就是action中的属性名subjectList,showDownArrow设置为true时,输入框旁边就会有一个下拉按钮,点击即显示集合中的所有值。

  • Struts2 上传下载

    单文件上传Struts2 框架为依据“基于表单的HTML文件上传”所进行的文件处理上传提供了内置支持。当文件上传时,它通常会存储在临时...

    Struts2 上传下载
  • Struts2 值栈、OGNL表达式

    要想全面地理解Struts2中数据的存取,就必须要结合值栈和OGNL表达式一起来理解,而OGNL存取数据的地方就是值栈,值栈是整个St...

    Struts2 值栈、OGNL表达式
  • Struts2 基础

    Struts2 概述Struts2 是目前较为普及和成熟的基于MVC设计模式的web应用程序框架,它不仅仅是Struts1 的升级版本...

    Struts2 基础