侧边栏壁纸
博主头像
liveJQ博主等级

沒有乐趣,何来开始

  • 累计撰写 146 篇文章
  • 累计创建 60 个标签
  • 累计收到 2 条评论

SSH之Struts2标签库

liveJQ
2019-03-25 / 0 评论 / 0 点赞 / 571 阅读 / 12,430 字 / 正在检测是否收录...
广告 广告

简介

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

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

20190325_struts2_taglib.png

控制标签


20190325_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类型。

数据标签


20190325_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>

表单标签


20190325_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中输入框只需加上requi

  • 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属性中的值。

20190325_checkbox_list_two.png

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

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

select和optgroup标签

20190325_select_optgroup.png

20190325_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:通过设置输入流,异步传递信息

20190325_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:点击事件绑定,异步操作

20190325_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

20190325_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:日期控件

20190325_Test4_calendar.gif

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

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

20190325_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时,输入框旁边就会有一个下拉按钮,点击即显示集合中的所有值。

0

评论区