Top

JAVA Struts2 DAY04

  1. 资费名唯一性校验-1
  2. 资费名唯一性校验-2
  3. 资费修改
  4. 使用简单的UI标签
  5. 使用复杂的UI标签

1 资费名唯一性校验-1

1.1 问题

在资费新增页面,输入完资费名称后,光标切换时,验证资费名称是否重复,并在资费名文本框后面给与提示。

1.2 方案

该需求中包含2个请求,一个是打开新增资费页面,另一个是输入完资费名称后进行唯一性校验。

其中打开资费页面很简单,参考打开登录页面完成即可,本案例中要完成该请求。

输入完资费名后在光标切换时验证资费名是否重复,这需要发起一次新请求,并且页面不能刷新,因此需要采用异步的方式来实现。而对于异步请求,我们需要在页面上使用JQuery发起请求,在Action中处理请求并使用json类型的result处理请求,将结果发送给异步请求的回调函数。

本案例中要求完成异步请求的服务端代码,包括DAO、Action、struts.xml,其中

1.3 步骤

实现此案例需要按照如下步骤进行。

请求1:打开新增页面

步骤一:在struts.xml中配置请求action

在struts.xml中,配置打开新增资费页面的请求action,代码如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
    "/struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
	
	<!-- 
		资费模块配置信息:
		一般情况下,一个模块的配置单独封装在一个package下,
		并且以模块名来命名package的name和namespace。
	 -->
	<package name="cost" namespace="/cost" extends="struts-default">
		<!—此处略去其他Action的配置... -->
#cold_bold		<!-- 打开资费新增页 -->
#cold_bold		<action name="toAddCost">
#cold_bold			<result name="success">
#cold_bold				/WEB-INF/cost/add_cost.jsp
#cold_bold			</result>
#cold_bold		</action>
	</package>
	
	<!-- 登录模块 -->
	<package name="login" namespace="/login" extends="struts-default">
		<!—此处略去其他Action的配置... -->
	</package>
	
</struts>

步骤二:创建新增资费页面

在WEB-INF/cost下,创建add_cost.jsp,并将静态页面的代码复制到该JSP中,代码如下:

<%@page pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "/www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="/www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title></title>
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global.css" />
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global_color.css" />
        <script language="javascript" type="text/javascript">
            //保存结果的提示
            function showResult() {
                showResultDiv(true);
                window.setTimeout("showResultDiv(false);", 3000);
            }
            function showResultDiv(flag) {
                var divResult = document.getElementById("save_result_info");
                if (flag)
                    divResult.style.display = "block";
                else
                    divResult.style.display = "none";
            }

            //切换资费类型
            function feeTypeChange(type) {
                var inputArray = document.getElementById("main").getElementsByTagName("input");
                if (type == 1) {
                    inputArray[4].readonly = true;
                    inputArray[4].value = "";
                    inputArray[4].className += " readonly";
                    inputArray[5].readonly = false;
                    inputArray[5].className = "width100";
                    inputArray[6].readonly = true;
                    inputArray[6].className += " readonly";
                    inputArray[6].value = "";
                }
                else if (type == 2) {
                    inputArray[4].readonly = false;
                    inputArray[4].className = "width100";
                    inputArray[5].readonly = false;
                    inputArray[5].className = "width100";
                    inputArray[6].readonly = false;
                    inputArray[6].className = "width100";
                }
                else if (type == 3) {
                    inputArray[4].readonly = true;
                    inputArray[4].value = "";
                    inputArray[4].className += " readonly";
                    inputArray[5].readonly = true;
                    inputArray[5].value = "";
                    inputArray[5].className += " readonly";
                    inputArray[6].readonly = false;
                    inputArray[6].className = "width100";
                }
            }
        </script>
    </head>
    <body>
        <!--Logo区域开始-->
        <div id="header">
            <img src="../images/logo.png" alt="logo" class="left"/>
            <a href="#">[退出]</a>            
        </div>
        <!--Logo区域结束-->
        <!--导航区域开始-->
        <div id="navi">
            <ul id="menu">
                <li><a href="../index.html" class="index_off"></a></li>
                <li><a href="../role/role_list.html" class="role_off"></a></li>
                <li><a href="../admin/admin_list.html" class="admin_off"></a></li>
                <li><a href="../fee/fee_list.html" class="fee_on"></a></li>
                <li><a href="../account/account_list.html" class="account_off"></a></li>
                <li><a href="../service/service_list.html" class="service_off"></a></li>
                <li><a href="../bill/bill_list.html" class="bill_off"></a></li>
                <li><a href="../report/report_list.html" class="report_off"></a></li>
                <li><a href="../user/user_info.html" class="information_off"></a></li>
                <li><a href="../user/user_modi_pwd.html" class="password_off"></a></li>
            </ul>
        </div>
        <!--导航区域结束-->
        <!--主要区域开始-->
        <div id="main">            
            <div id="save_result_info" class="save_fail">保存失败,资费名称重复!</div>
            <form action="" method="" class="main_form">
                <div class="text_info clearfix"><span>资费名称:</span></div>
                <div class="input_info">
                    <input type="text" class="width300" value=""/>
                    <span class="required">*</span>
                    <div class="validate_msg_short">50长度的字母、数字、汉字和下划线的组合</div>
                </div>
                <div class="text_info clearfix"><span>资费类型:</span></div>
                <div class="input_info fee_type">
                    <input type="radio" name="radFeeType" id="monthly" onclick="feeTypeChange(1);" />
                    <label for="monthly">包月</label>
                    <input type="radio" name="radFeeType" checked="checked" id="package" onclick="feeTypeChange(2);" />
                    <label for="package">套餐</label>
                    <input type="radio" name="radFeeType" id="timeBased" onclick="feeTypeChange(3);" />
                    <label for="timeBased">计时</label>
                </div>
                <div class="text_info clearfix"><span>基本时长:</span></div>
                <div class="input_info">
                    <input type="text" value="" class="width100" />
                    <span class="info">小时</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long">1-600之间的整数</div>
                </div>
                <div class="text_info clearfix"><span>基本费用:</span></div>
                <div class="input_info">
                    <input type="text" value="" class="width100" />
                    <span class="info">元</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long error_msg">0-99999.99之间的数值</div>
                </div>
                <div class="text_info clearfix"><span>单位费用:</span></div>
                <div class="input_info">
                    <input type="text" value="" class="width100" />
                    <span class="info">元/小时</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long error_msg">0-99999.99之间的数值</div>
                </div>
                <div class="text_info clearfix"><span>资费说明:</span></div>
                <div class="input_info_high">
                    <textarea class="width300 height70"></textarea>
                    <div class="validate_msg_short error_msg">100长度的字母、数字、汉字和下划线的组合</div>
                </div>                    
                <div class="button_info clearfix">
                    <input type="button" value="保存" class="btn_save"  onclick="showResult();" />
                    <input type="button" value="取消" class="btn_save" />
                </div>
            </form>  
        </div>
        <!--主要区域结束-->
        <div id="footer">
            <span>[源自北美的技术,最优秀的师资,最真实的企业环境,最适用的实战项目]</span>
            <br />
            <span>版权所有(C) </span>
        </div>
    </body>
</html>

步骤三:列表页面上给增加按钮指定跳转的URL

在列表页面find_cost.jsp中,给增加按钮设置访问路径,代码如下:

<%@page pageEncoding="utf-8" isELIgnored="false"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "/www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="/www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title></title>
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global.css" />
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global_color.css" />
        <script language="javascript" type="text/javascript">
            //排序按钮的点击事件
            function sort(btnObj) {
                if (btnObj.className == "sort_desc")
                    btnObj.className = "sort_asc";
                else
                    btnObj.className = "sort_desc";
            }

            //启用
            function startFee() {
                var r = window.confirm("确定要启用此资费吗?资费启用后将不能修改和删除。");
                document.getElementById("operate_result_info").style.display = "block";
            }
            //删除
            function deleteFee(id) {
                var r = window.confirm("确定要删除此资费吗?");
                if(r) {
                	// 如果用户确认,则调用删除资费action
                	window.location.href = "deleteCost?id="+id;
                }
            }
        </script>        
    </head>
    <body>
        <!--Logo区域开始-->
        <div id="header">
            <img src="../images/logo.png" alt="logo" class="left"/>
            <a href="#">[退出]</a>            
        </div>
        <!--Logo区域结束-->
        <!--导航区域开始-->
        <div id="navi">                        
            <ul id="menu">
                <li><a href="../index.html" class="index_off"></a></li>
                <li><a href="../role/role_list.html" class="role_off"></a></li>
                <li><a href="../admin/admin_list.html" class="admin_off"></a></li>
                <li><a href="../fee/fee_list.html" class="fee_on"></a></li>
                <li><a href="../account/account_list.html" class="account_off"></a></li>
                <li><a href="../service/service_list.html" class="service_off"></a></li>
                <li><a href="../bill/bill_list.html" class="bill_off"></a></li>
                <li><a href="../report/report_list.html" class="report_off"></a></li>
                <li><a href="../user/user_info.html" class="information_off"></a></li>
                <li><a href="../user/user_modi_pwd.html" class="password_off"></a></li>
            </ul>            
        </div>
        <!--导航区域结束-->
        <!--主要区域开始-->
        <div id="main">
            <form action="" method="">
                <!--排序-->
                <div class="search_add">
                    <div>
                        <!--<input type="button" value="月租" class="sort_asc" onclick="sort(this);" />-->
                        <input type="button" value="基费" class="sort_asc" onclick="sort(this);" />
                        <input type="button" value="时长" class="sort_asc" onclick="sort(this);" />
                    </div>
#cold_bold                    <input type="button" value="增加" class="btn_add" onclick="location.href='toAddCost';" />
                </div> 
                <!--启用操作的操作提示-->
                <div id="operate_result_info" class="operate_success">
                    <img src="../images/close.png" onclick="this.parentNode.style.display='none';" />
                    删除成功!
                </div>    
                <!--数据区域:用表格展示数据-->     
                <div id="data">            
                    <table id="datalist">
                        <tr>
                            <th>资费ID</th>
                            <th class="width100">资费名称</th>
                            <th>基本时长</th>
                            <th>基本费用</th>
                            <th>单位费用</th>
                            <th>创建时间</th>
                            <th>开通时间</th>
                            <th class="width50">状态</th>
                            <th class="width200"></th>
                        </tr>       
                        
                        <!-- 使用Struts2标签遍历集合,使用OGNL表达式输出内容。 -->               
                        <s:iterator value="costs">                 
	                        <tr>
	                            <td><s:property value="id"/></td>
	                            <td><a href="fee_detail.html"><s:property value="name"/></a></td>
	                            <td><s:property value="baseDuration"/></td>
	                            <td><s:property value="baseCost"/></td>
	                            <td><s:property value="unitCost"/></td>
	                            <td><s:property value="createTime"/></td>
	                            <td><s:property value="startTime"/></td>
	                            <td>
	                            	<s:if test="status==0">开通</s:if>
	                            	<s:else>暂停</s:else>
	                            </td>
	                            <td>                                
	                                <input type="button" value="启用" class="btn_start" onclick="startFee();" />
	                                <input type="button" value="修改" class="btn_modify" onclick="location.href='fee_modi.html';" />
	                                <input type="button" value="删除" class="btn_delete" onclick="deleteFee(<s:property value="id"/>);" />
	                            </td>
	                        </tr>
                       </s:iterator>
                       
                    </table>
                    <p>业务说明:<br />
                    1、创建资费时,状态为暂停,记载创建时间;<br />
                    2、暂停状态下,可修改,可删除;<br />
                    3、开通后,记载开通时间,且开通后不能修改、不能再停用、也不能删除;<br />
                    4、业务账号修改资费时,在下月底统一触发,修改其关联的资费ID(此触发动作由程序处理)
                    </p>
                </div>
                <!--分页-->
                <div id="pages">
        	        <a href="#">上一页</a>
                    <a href="#" class="current_page">1</a>
                    <a href="#">2</a>
                    <a href="#">3</a>
                    <a href="#">4</a>
                    <a href="#">5</a>
                    <a href="#">下一页</a>
                </div>
            </form>
        </div>
        <!--主要区域结束-->
        <div id="footer">
            <p>[源自北美的技术,最优秀的师资,最真实的企业环境,最适用的实战项目]</p>
            <p>版权所有(C) </p>
        </div>
    </body>
</html>

步骤四:测试

重新部署项目并重启tomcat,打开资费列表页面,点击增加按钮,效果如下图:

图-1

请求2:资费名称唯一性校验

步骤一:导包

由于需要使用json类型的result,因此需要导入新的包,名为struts2-json-plugin-2.1.8.jar。

步骤二:在DAO中追加根据名称查询资费的方法

在ICostDao中,追加根据名称查询资费的方法,代码如下:

package com.netctoss.dao;

import java.util.List;

import com.netctoss.entity.Cost;

/**
 * 资费DAO接口
 */
public interface ICostDao {

// 此处略去其他方法的声明...	
#cold_bold	/**
#cold_bold	 * 根据名称查询资费
#cold_bold	 * @param name 资费名
#cold_bold	 * @return
#cold_bold	 */
#cold_bold	Cost findByName(String name);

}

在CostDaoImpl类中,实现根据名称查询资费的方法,代码如下:

package com.netctoss.dao;

import java.util.ArrayList;
import java.util.List;

import com.netctoss.entity.Cost;

/**
 *	当前阶段学习重点是Struts2,对于DAO的实现就模拟实现了。
 *	同学们可以使用JDBC/MyBatis自行实现该DAO。
 */
public class CostDaoImpl implements ICostDao {

// 此处略去其他方法的实现...
#cold_bold	@Override
#cold_bold	public Cost findByName(String name) {
#cold_bold		// 模拟根据名称查询资费数据,假设资费表中只有一条名为tarena的数据
#cold_bold		if("tarena".equals(name)) {
#cold_bold			Cost c = new Cost();
#cold_bold			c.setId(97);
#cold_bold			c.setName("tarena");
#cold_bold			c.setBaseDuration(99);
#cold_bold			c.setBaseCost(9.9);
#cold_bold			c.setUnitCost(0.9);
#cold_bold			c.setDescr("tarena套餐");
#cold_bold			c.setStatus("0");
#cold_bold			c.setCostType("2");
#cold_bold			return c;
#cold_bold		}
#cold_bold		return null;
#cold_bold	}
}

步骤三:追加校验资费名Action

在com.netctoss.action包下,创建资费名称校验Action类CheckCostNameAction,该Action的输入属性是资费名,输出属性设置为一个Map,这样方便封装多个输出内容。在业务方法中根据资费名查询资费数据,并从结果是否为空来判断资费名是否重复,最终将判断结果封装于Map中输出给回调函数,代码如下:

package com.netctoss.action;

import java.util.HashMap;
import java.util.Map;

import com.netctoss.dao.DAOFactory;
import com.netctoss.dao.ICostDao;
import com.netctoss.entity.Cost;

public class CheckCostNameAction {

	// input
	private String name; // 资费名

	// output
	private Map<String, Object> info = new HashMap<String, Object>(); // 提示信息

	public String execute() {
		ICostDao dao = DAOFactory.getCostDAO();
		Cost cost = null;
		try {
			cost = dao.findByName(name);
		} catch (Exception e) {
			e.printStackTrace();
			/*
			 * 由于是异步请求,并通过json类型的result处理结果,
			 * 那么该result一定会把结构发给回调函数,因此这里
			 * 不要返回error了,否则result会把error.jsp中的代码
			 * 发给回调函数,因此这里只给出提示信息即可。
			 * */
			info.put("success", false);
			info.put("message", "系统发生异常,请联系管理员.");
		}
		
		if(cost == null) {
			// 没找到资费,说明名称没重复
			info.put("success", true);
			info.put("message", "有效的资费名称.");
		} else {
			//找到了资费数据,说明名称重复了
			info.put("success", false);
			info.put("message", "资费名称已存在.");
		}

		return "success";
	}

	public String getName() {
		return name;
	}

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

	public Map<String, Object> getInfo() {
		return info;
	}

	public void setInfo(Map<String, Object> info) {
		this.info = info;
	}

}

步骤四:在struts.xml中配置校验资费名Action

在struts.xml中,配置资费名校验action。由于该action需要使用json类型的result,因此需要先将它所在的package继承修改为json-default,然后再配置资费名校验action,并使用json类型的result将结果输出给回调函数,代码如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
    "/struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
	
	<!-- 
		资费模块配置信息:
		一般情况下,一个模块的配置单独封装在一个package下,
		并且以模块名来命名package的name和namespace。
	 -->
#cold_bold	<package name="cost" namespace="/cost" extends="json-default">
		<!—此处略去其他Action的配置... -->
#cold_bold		<!-- 资费名唯一性校验 -->
#cold_bold		<action name="checkCostName" 
#cold_bold			class="com.netctoss.action.CheckCostNameAction">
#cold_bold			<!-- 使用json类型的result把结果输出给回调函数 -->
#cold_bold			<result name="success" type="json">
#cold_bold				<param name="root">info</param>
#cold_bold			</result>
#cold_bold		</action>
	</package>
	
	<!-- 登录模块 -->
	<package name="login" namespace="/login" extends="struts-default">
		<!—此处略去其他Action的配置... -->
	</package>
	
</struts>

步骤五:测试

在浏览器中,直接输入地址访问此action,并给name参数赋值,路径为/localhost:8088/NETCTOSS/cost/checkCostName?name=aaa,通过观察浏览器中的内容可以达到测试目的。注意,有些浏览器可能不是直接显示结果,而是将接收的结果保存到文件中,这是浏览器设置的问题,也可以将内容保存后再行浏览。效果如下图:

图-2

1.4 完整代码

本案例的完整代码如下。

ICostDao完整代码:

package com.netctoss.dao;

import java.util.List;

import com.netctoss.entity.Cost;

/**
 * 资费DAO接口
 */
public interface ICostDao {

	/**
	 * 查询全部资费数据
	 */
	List<Cost> findAll();
	
	/**
	 * 删除一条资费数据
	 * @param id 主键
	 */
	void delete(int id);
	
	/**
	 * 根据名称查询资费
	 * @param name 资费名
	 * @return
	 */
	Cost findByName(String name);

}

CostDaoImpl完整代码:

package com.netctoss.dao;

import java.util.ArrayList;
import java.util.List;

import com.netctoss.entity.Cost;

/**
 *	当前阶段学习重点是Struts2,对于DAO的实现就模拟实现了。
 *	同学们可以使用JDBC/MyBatis自行实现该DAO。
 */
public class CostDaoImpl implements ICostDao {

	@Override
	public List<Cost> findAll() {
		// 模拟查询全部资费数据
		List<Cost> list = new ArrayList<Cost>();
		
		Cost c1 = new Cost();
		c1.setId(95);
		c1.setName("6元套餐");
		c1.setBaseDuration(66);
		c1.setBaseCost(6.6);
		c1.setUnitCost(0.6);
		c1.setDescr("6元套餐");
		c1.setStatus("0");
		c1.setCostType("2");
		list.add(c1);
		
		Cost c2 = new Cost();
		c2.setId(96);
		c2.setName("8元套餐");
		c2.setBaseDuration(88);
		c2.setBaseCost(8.8);
		c2.setUnitCost(0.8);
		c2.setDescr("8元套餐");
		c2.setStatus("0");
		c2.setCostType("2");
		list.add(c2);
		
		Cost c3 = new Cost();
		c3.setId(97);
		c3.setName("tarena");
		c3.setBaseDuration(99);
		c3.setBaseCost(9.9);
		c3.setUnitCost(0.9);
		c3.setDescr("tarena套餐");
		c3.setStatus("0");
		c3.setCostType("2");
		list.add(c3);
		
		return list;
	}

	@Override
	public void delete(int id) {
		// 模拟根据id删除资费数据
		System.out.println("删除ID为[" + id + "]的资费数据.");
	}

	@Override
	public Cost findByName(String name) {
		// 模拟根据名称查询资费数据,假设资费表中只有一条名为tarena的数据
		if("tarena".equals(name)) {
			Cost c = new Cost();
			c.setId(97);
			c.setName("tarena");
			c.setBaseDuration(99);
			c.setBaseCost(9.9);
			c.setUnitCost(0.9);
			c.setDescr("tarena套餐");
			c.setStatus("0");
			c.setCostType("2");
			return c;
		}
		return null;
	}
}

CheckCostNameAction完整代码:

package com.netctoss.action;

import java.util.HashMap;
import java.util.Map;

import com.netctoss.dao.DAOFactory;
import com.netctoss.dao.ICostDao;
import com.netctoss.entity.Cost;

public class CheckCostNameAction {

	// input
	private String name; // 资费名

	// output
	private Map<String, Object> info = new HashMap<String, Object>(); // 提示信息

	public String execute() {
		ICostDao dao = DAOFactory.getCostDAO();
		Cost cost = null;
		try {
			cost = dao.findByName(name);
		} catch (Exception e) {
			e.printStackTrace();
			/*
			 * 由于是异步请求,并通过json类型的result处理结果,
			 * 那么该result一定会把结构发给回调函数,因此这里
			 * 不要返回error了,否则result会把error.jsp中的代码
			 * 发给回调函数,因此这里只给出提示信息即可。
			 * */
			info.put("success", false);
			info.put("message", "系统发生异常,请联系管理员.");
		}
		
		if(cost == null) {
			// 没找到资费,说明名称没重复
			info.put("success", true);
			info.put("message", "有效的资费名称.");
		} else {
			//找到了资费数据,说明名称重复了
			info.put("success", false);
			info.put("message", "资费名称已存在.");
		}

		return "success";
	}

	public String getName() {
		return name;
	}

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

	public Map<String, Object> getInfo() {
		return info;
	}

	public void setInfo(Map<String, Object> info) {
		this.info = info;
	}

}

struts.xml完整代码:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
    "/struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
	
	<!-- 
		资费模块配置信息:
		一般情况下,一个模块的配置单独封装在一个package下,
		并且以模块名来命名package的name和namespace。
	 -->
	<package name="cost" namespace="/cost" extends="json-default">
		<!-- 查询资费数据 -->
		<action name="findCost" class="com.netctoss.action.FindCostAction">
			<!-- 
				正常情况下跳转到资费列表页面。
				一般一个模块的页面要打包在一个文件夹下,并且文件夹以模块名命名。
			 -->
			<result name="success">
				/WEB-INF/cost/find_cost.jsp
			</result>
			<!-- 
				错误情况下,跳转到错误页面。
				错误页面可以被所有模块复用,因此放在main下,
				该文件夹用于存放公用的页面。
			 -->
			<result name="error">
				/WEB-INF/main/error.jsp
			</result>
		</action>
		<!-- 删除资费 -->
		<action name="deleteCost" 
			class="com.netctoss.action.DeleteCostAction">
			<!-- 删除完之后,重定向到查询action -->
			<result name="success" type="redirectAction">
				findCost
			</result>
			<result name="error">
				/WEB-INF/main/error.jsp
			</result>
		</action>
		<!-- 打开资费新增页 -->
		<action name="toAddCost">
			<result name="success">
				/WEB-INF/cost/add_cost.jsp
			</result>
		</action>
		<!-- 资费名唯一性校验 -->
		<action name="checkCostName" 
			class="com.netctoss.action.CheckCostNameAction">
			<!-- 使用json类型的result把结果输出给回调函数 -->
			<result name="success" type="json">
				<param name="root">info</param>
			</result>
		</action>
	</package>
	
	<!-- 登录模块 -->
	<package name="login" namespace="/login" extends="struts-default">
		<!-- 
			打开登录页面:
			1、action的class属性可以省略,省略时Struts2
			   会自动实例化默认的Action类ActionSupport,
			   该类中有默认业务方法execute,返回success。
			2、action的method属性可以省略,省略时Struts2
			   会自动调用execute方法。
		-->
		<action name="toLogin">
			<result name="success">
				/WEB-INF/main/login.jsp
			</result>
		</action>
		<!-- 登录校验 -->
		<action name="login" class="com.netctoss.action.LoginAction">
			<!-- 校验成功,跳转到系统首页 -->
			<result name="success">
				/WEB-INF/main/index.jsp
			</result>
			<!-- 登录失败,跳转回登录页面 -->
			<result name="fail">
				/WEB-INF/main/login.jsp
			</result>
			<!-- 报错,跳转到错误页面 -->
			<result name="error">
				/WEB-INF/main/error.jsp
			</result>
		</action>
		<!-- 生成验证码 -->
		<action name="createImage" class="com.netctoss.action.CreateImageAction">
			<!-- 使用stream类型的result -->
			<result name="success" type="stream">
				<!-- 指定输出的内容 -->
				<param name="inputName">imageStream</param>
			</result>
		</action>
	</package>
	
</struts>

find_cost.jsp完整代码:

<%@page pageEncoding="utf-8" isELIgnored="false"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "/www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="/www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title></title>
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global.css" />
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global_color.css" />
        <script language="javascript" type="text/javascript">
            //排序按钮的点击事件
            function sort(btnObj) {
                if (btnObj.className == "sort_desc")
                    btnObj.className = "sort_asc";
                else
                    btnObj.className = "sort_desc";
            }

            //启用
            function startFee() {
                var r = window.confirm("确定要启用此资费吗?资费启用后将不能修改和删除。");
                document.getElementById("operate_result_info").style.display = "block";
            }
            //删除
            function deleteFee(id) {
                var r = window.confirm("确定要删除此资费吗?");
                if(r) {
                	// 如果用户确认,则调用删除资费action
                	window.location.href = "deleteCost?id="+id;
                }
            }
        </script>        
    </head>
    <body>
        <!--Logo区域开始-->
        <div id="header">
            <img src="../images/logo.png" alt="logo" class="left"/>
            <a href="#">[退出]</a>            
        </div>
        <!--Logo区域结束-->
        <!--导航区域开始-->
        <div id="navi">                        
            <ul id="menu">
                <li><a href="../index.html" class="index_off"></a></li>
                <li><a href="../role/role_list.html" class="role_off"></a></li>
                <li><a href="../admin/admin_list.html" class="admin_off"></a></li>
                <li><a href="../fee/fee_list.html" class="fee_on"></a></li>
                <li><a href="../account/account_list.html" class="account_off"></a></li>
                <li><a href="../service/service_list.html" class="service_off"></a></li>
                <li><a href="../bill/bill_list.html" class="bill_off"></a></li>
                <li><a href="../report/report_list.html" class="report_off"></a></li>
                <li><a href="../user/user_info.html" class="information_off"></a></li>
                <li><a href="../user/user_modi_pwd.html" class="password_off"></a></li>
            </ul>            
        </div>
        <!--导航区域结束-->
        <!--主要区域开始-->
        <div id="main">
            <form action="" method="">
                <!--排序-->
                <div class="search_add">
                    <div>
                        <!--<input type="button" value="月租" class="sort_asc" onclick="sort(this);" />-->
                        <input type="button" value="基费" class="sort_asc" onclick="sort(this);" />
                        <input type="button" value="时长" class="sort_asc" onclick="sort(this);" />
                    </div>
                    <input type="button" value="增加" class="btn_add" onclick="location.href='toAddCost';" />
                </div> 
                <!--启用操作的操作提示-->
                <div id="operate_result_info" class="operate_success">
                    <img src="../images/close.png" onclick="this.parentNode.style.display='none';" />
                    删除成功!
                </div>    
                <!--数据区域:用表格展示数据-->     
                <div id="data">            
                    <table id="datalist">
                        <tr>
                            <th>资费ID</th>
                            <th class="width100">资费名称</th>
                            <th>基本时长</th>
                            <th>基本费用</th>
                            <th>单位费用</th>
                            <th>创建时间</th>
                            <th>开通时间</th>
                            <th class="width50">状态</th>
                            <th class="width200"></th>
                        </tr>       
                        
                        <!-- 使用Struts2标签遍历集合,使用OGNL表达式输出内容。 -->               
                        <s:iterator value="costs">                 
	                        <tr>
	                            <td><s:property value="id"/></td>
	                            <td><a href="fee_detail.html"><s:property value="name"/></a></td>
	                            <td><s:property value="baseDuration"/></td>
	                            <td><s:property value="baseCost"/></td>
	                            <td><s:property value="unitCost"/></td>
	                            <td><s:property value="createTime"/></td>
	                            <td><s:property value="startTime"/></td>
	                            <td>
	                            	<s:if test="status==0">开通</s:if>
	                            	<s:else>暂停</s:else>
	                            </td>
	                            <td>                                
	                                <input type="button" value="启用" class="btn_start" onclick="startFee();" />
	                                <input type="button" value="修改" class="btn_modify" onclick="location.href='fee_modi.html';" />
	                                <input type="button" value="删除" class="btn_delete" onclick="deleteFee(<s:property value="id"/>);" />
	                            </td>
	                        </tr>
                       </s:iterator>
                       
                    </table>
                    <p>业务说明:<br />
                    1、创建资费时,状态为暂停,记载创建时间;<br />
                    2、暂停状态下,可修改,可删除;<br />
                    3、开通后,记载开通时间,且开通后不能修改、不能再停用、也不能删除;<br />
                    4、业务账号修改资费时,在下月底统一触发,修改其关联的资费ID(此触发动作由程序处理)
                    </p>
                </div>
                <!--分页-->
                <div id="pages">
        	        <a href="#">上一页</a>
                    <a href="#" class="current_page">1</a>
                    <a href="#">2</a>
                    <a href="#">3</a>
                    <a href="#">4</a>
                    <a href="#">5</a>
                    <a href="#">下一页</a>
                </div>
            </form>
        </div>
        <!--主要区域结束-->
        <div id="footer">
            <p>[源自北美的技术,最优秀的师资,最真实的企业环境,最适用的实战项目]</p>
            <p>版权所有(C) </p>
        </div>
    </body>
</html>

add_cost.jsp完整代码:

<%@page pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "/www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="/www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title></title>
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global.css" />
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global_color.css" />
        <script language="javascript" type="text/javascript">
            //保存结果的提示
            function showResult() {
                showResultDiv(true);
                window.setTimeout("showResultDiv(false);", 3000);
            }
            function showResultDiv(flag) {
                var divResult = document.getElementById("save_result_info");
                if (flag)
                    divResult.style.display = "block";
                else
                    divResult.style.display = "none";
            }

            //切换资费类型
            function feeTypeChange(type) {
                var inputArray = document.getElementById("main").getElementsByTagName("input");
                if (type == 1) {
                    inputArray[4].readonly = true;
                    inputArray[4].value = "";
                    inputArray[4].className += " readonly";
                    inputArray[5].readonly = false;
                    inputArray[5].className = "width100";
                    inputArray[6].readonly = true;
                    inputArray[6].className += " readonly";
                    inputArray[6].value = "";
                }
                else if (type == 2) {
                    inputArray[4].readonly = false;
                    inputArray[4].className = "width100";
                    inputArray[5].readonly = false;
                    inputArray[5].className = "width100";
                    inputArray[6].readonly = false;
                    inputArray[6].className = "width100";
                }
                else if (type == 3) {
                    inputArray[4].readonly = true;
                    inputArray[4].value = "";
                    inputArray[4].className += " readonly";
                    inputArray[5].readonly = true;
                    inputArray[5].value = "";
                    inputArray[5].className += " readonly";
                    inputArray[6].readonly = false;
                    inputArray[6].className = "width100";
                }
            }
        </script>
    </head>
    <body>
        <!--Logo区域开始-->
        <div id="header">
            <img src="../images/logo.png" alt="logo" class="left"/>
            <a href="#">[退出]</a>            
        </div>
        <!--Logo区域结束-->
        <!--导航区域开始-->
        <div id="navi">
            <ul id="menu">
                <li><a href="../index.html" class="index_off"></a></li>
                <li><a href="../role/role_list.html" class="role_off"></a></li>
                <li><a href="../admin/admin_list.html" class="admin_off"></a></li>
                <li><a href="../fee/fee_list.html" class="fee_on"></a></li>
                <li><a href="../account/account_list.html" class="account_off"></a></li>
                <li><a href="../service/service_list.html" class="service_off"></a></li>
                <li><a href="../bill/bill_list.html" class="bill_off"></a></li>
                <li><a href="../report/report_list.html" class="report_off"></a></li>
                <li><a href="../user/user_info.html" class="information_off"></a></li>
                <li><a href="../user/user_modi_pwd.html" class="password_off"></a></li>
            </ul>
        </div>
        <!--导航区域结束-->
        <!--主要区域开始-->
        <div id="main">            
            <div id="save_result_info" class="save_fail">保存失败,资费名称重复!</div>
            <form action="" method="" class="main_form">
                <div class="text_info clearfix"><span>资费名称:</span></div>
                <div class="input_info">
                    <input type="text" class="width300" value=""/>
                    <span class="required">*</span>
                    <div class="validate_msg_short">50长度的字母、数字、汉字和下划线的组合</div>
                </div>
                <div class="text_info clearfix"><span>资费类型:</span></div>
                <div class="input_info fee_type">
                    <input type="radio" name="radFeeType" id="monthly" onclick="feeTypeChange(1);" />
                    <label for="monthly">包月</label>
                    <input type="radio" name="radFeeType" checked="checked" id="package" onclick="feeTypeChange(2);" />
                    <label for="package">套餐</label>
                    <input type="radio" name="radFeeType" id="timeBased" onclick="feeTypeChange(3);" />
                    <label for="timeBased">计时</label>
                </div>
                <div class="text_info clearfix"><span>基本时长:</span></div>
                <div class="input_info">
                    <input type="text" value="" class="width100" />
                    <span class="info">小时</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long">1-600之间的整数</div>
                </div>
                <div class="text_info clearfix"><span>基本费用:</span></div>
                <div class="input_info">
                    <input type="text" value="" class="width100" />
                    <span class="info">元</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long error_msg">0-99999.99之间的数值</div>
                </div>
                <div class="text_info clearfix"><span>单位费用:</span></div>
                <div class="input_info">
                    <input type="text" value="" class="width100" />
                    <span class="info">元/小时</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long error_msg">0-99999.99之间的数值</div>
                </div>
                <div class="text_info clearfix"><span>资费说明:</span></div>
                <div class="input_info_high">
                    <textarea class="width300 height70"></textarea>
                    <div class="validate_msg_short error_msg">100长度的字母、数字、汉字和下划线的组合</div>
                </div>                    
                <div class="button_info clearfix">
                    <input type="button" value="保存" class="btn_save"  onclick="showResult();" />
                    <input type="button" value="取消" class="btn_save" />
                </div>
            </form>  
        </div>
        <!--主要区域结束-->
        <div id="footer">
            <span>[源自北美的技术,最优秀的师资,最真实的企业环境,最适用的实战项目]</span>
            <br />
            <span>版权所有(C) </span>
        </div>
    </body>
</html>

2 资费名唯一性校验-2

2.1 问题

完成资费名唯一性校验。

2.2 方案

在资费新增页面上,给资费名文本框增加光标移除事件,并绑定资费名唯一性校验函数。该函数中,使用JQuery发送异步请求访问资费名校验action,并在回调函数中根据返回结果设置提示信息。

2.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:引入JQuery

在WebRoot下创建js文件夹,将jquery-1.4.3.js文件复制到此文件夹下,完成后WebRoot结构如下图:

图-3

步骤二:新增页面上发起异步校验请求

在add_cost.jsp上,给资费名称文本框的onblur事件绑定资费名唯一性校验函数check_name,然后在<head>通过script标记引入JQuery,并实现check_name函数中的异步校验逻辑,代码如下:

<%@page pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "/www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="/www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title></title>
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global.css" />
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global_color.css" />
#cold_bold        <script language="javascript" type="text/javascript" src="../js/jquery-1.4.3.js"></script>
        <script language="javascript" type="text/javascript">
#cold_bold        	//校验资费名是否重复
#cold_bold        	function check_name() {
#cold_bold        		var cost_name = $("#cost_name").val();
#cold_bold        		// 校验资费名是否为空
#cold_bold        		if(cost_name == "") {
#cold_bold        			$("#name_msg").text("资费名不能为空.").addClass("error_msg");
#cold_bold        			return;
#cold_bold        		}
#cold_bold        		// 异步校验资费名是否重复
#cold_bold        		$.post(
#cold_bold        			"checkCostName",
#cold_bold        			{"name":cost_name},
#cold_bold        			function(data) { 
#cold_bold        				// 回调函数的参数就是返回的info属性
#cold_bold        				var info = data;
#cold_bold        				// 根据返回值设置提示信息
#cold_bold        				if(info.success) {
#cold_bold        					//  验证通过,设置提示信息并移除错误样式
#cold_bold        					$("#name_msg").text(info.message).removeClass("error_msg");
#cold_bold        				} else {
#cold_bold        					// 验证失败,设置提示信息并添加错误样式
#cold_bold        					$("#name_msg").text(info.message).addClass("error_msg");
#cold_bold        				}
#cold_bold        			}
#cold_bold        		);
#cold_bold        	}
        	
            //保存结果的提示
            function showResult() {
                showResultDiv(true);
                window.setTimeout("showResultDiv(false);", 3000);
            }
            function showResultDiv(flag) {
                var divResult = document.getElementById("save_result_info");
                if (flag)
                    divResult.style.display = "block";
                else
                    divResult.style.display = "none";
            }

            //切换资费类型
            function feeTypeChange(type) {
                var inputArray = document.getElementById("main").getElementsByTagName("input");
                if (type == 1) {
                    inputArray[4].readonly = true;
                    inputArray[4].value = "";
                    inputArray[4].className += " readonly";
                    inputArray[5].readonly = false;
                    inputArray[5].className = "width100";
                    inputArray[6].readonly = true;
                    inputArray[6].className += " readonly";
                    inputArray[6].value = "";
                }
                else if (type == 2) {
                    inputArray[4].readonly = false;
                    inputArray[4].className = "width100";
                    inputArray[5].readonly = false;
                    inputArray[5].className = "width100";
                    inputArray[6].readonly = false;
                    inputArray[6].className = "width100";
                }
                else if (type == 3) {
                    inputArray[4].readonly = true;
                    inputArray[4].value = "";
                    inputArray[4].className += " readonly";
                    inputArray[5].readonly = true;
                    inputArray[5].value = "";
                    inputArray[5].className += " readonly";
                    inputArray[6].readonly = false;
                    inputArray[6].className = "width100";
                }
            }
        </script>
    </head>
    <body>
        <!--Logo区域开始-->
        <div id="header">
            <img src="../images/logo.png" alt="logo" class="left"/>
            <a href="#">[退出]</a>            
        </div>
        <!--Logo区域结束-->
        <!--导航区域开始-->
        <div id="navi">
            <ul id="menu">
                <li><a href="../index.html" class="index_off"></a></li>
                <li><a href="../role/role_list.html" class="role_off"></a></li>
                <li><a href="../admin/admin_list.html" class="admin_off"></a></li>
                <li><a href="../fee/fee_list.html" class="fee_on"></a></li>
                <li><a href="../account/account_list.html" class="account_off"></a></li>
                <li><a href="../service/service_list.html" class="service_off"></a></li>
                <li><a href="../bill/bill_list.html" class="bill_off"></a></li>
                <li><a href="../report/report_list.html" class="report_off"></a></li>
                <li><a href="../user/user_info.html" class="information_off"></a></li>
                <li><a href="../user/user_modi_pwd.html" class="password_off"></a></li>
            </ul>
        </div>
        <!--导航区域结束-->
        <!--主要区域开始-->
        <div id="main">            
            <div id="save_result_info" class="save_fail">保存失败,资费名称重复!</div>
            <form action="" method="" class="main_form">
                <div class="text_info clearfix"><span>资费名称:</span></div>
                <div class="input_info">
#cold_bold                    <input type="text" class="width300" id="cost_name" onblur="check_name();"/>
                    <span class="required">*</span>
                    <div class="validate_msg_short" id="name_msg">50长度的字母、数字、汉字和下划线的组合</div>
                </div>
                <div class="text_info clearfix"><span>资费类型:</span></div>
                <div class="input_info fee_type">
                    <input type="radio" name="radFeeType" id="monthly" onclick="feeTypeChange(1);" />
                    <label for="monthly">包月</label>
                    <input type="radio" name="radFeeType" checked="checked" id="package" onclick="feeTypeChange(2);" />
                    <label for="package">套餐</label>
                    <input type="radio" name="radFeeType" id="timeBased" onclick="feeTypeChange(3);" />
                    <label for="timeBased">计时</label>
                </div>
                <div class="text_info clearfix"><span>基本时长:</span></div>
                <div class="input_info">
                    <input type="text" value="" class="width100" />
                    <span class="info">小时</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long">1-600之间的整数</div>
                </div>
                <div class="text_info clearfix"><span>基本费用:</span></div>
                <div class="input_info">
                    <input type="text" value="" class="width100" />
                    <span class="info">元</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long error_msg">0-99999.99之间的数值</div>
                </div>
                <div class="text_info clearfix"><span>单位费用:</span></div>
                <div class="input_info">
                    <input type="text" value="" class="width100" />
                    <span class="info">元/小时</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long error_msg">0-99999.99之间的数值</div>
                </div>
                <div class="text_info clearfix"><span>资费说明:</span></div>
                <div class="input_info_high">
                    <textarea class="width300 height70"></textarea>
                    <div class="validate_msg_short error_msg">100长度的字母、数字、汉字和下划线的组合</div>
                </div>                    
                <div class="button_info clearfix">
                    <input type="button" value="保存" class="btn_save"  onclick="showResult();" />
                    <input type="button" value="取消" class="btn_save" />
                </div>
            </form>  
        </div>
        <!--主要区域结束-->
        <div id="footer">
            <span>[源自北美的技术,最优秀的师资,最真实的企业环境,最适用的实战项目]</span>
            <br />
            <span>版权所有(C) </span>
        </div>
    </body>
</html>

步骤三:测试

重新部署项目并重启tomcat,打开新增页面,输入一个已存在的资费名称,切换光标时效果如下图:

图-4

2.4 完整代码

本案例的完整代码如下。

add_cost.jsp完整代码:

<%@page pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "/www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="/www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title></title>
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global.css" />
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global_color.css" />
        <script language="javascript" type="text/javascript" src="../js/jquery-1.4.3.js"></script>
        <script language="javascript" type="text/javascript">
        	//校验资费名是否重复
        	function check_name() {
        		var cost_name = $("#cost_name").val();
        		// 校验资费名是否为空
        		if(cost_name == "") {
        			$("#name_msg").text("资费名不能为空.").addClass("error_msg");
        			return;
        		}
        		// 异步校验资费名是否重复
        		$.post(
        			"checkCostName",
        			{"name":cost_name},
        			function(data) { 
        				// 回调函数的参数就是返回的info属性
        				var info = data;
        				// 根据返回值设置提示信息
        				if(info.success) {
        					//  验证通过,设置提示信息并移除错误样式
        					$("#name_msg").text(info.message).removeClass("error_msg");
        				} else {
        					// 验证失败,设置提示信息并添加错误样式
        					$("#name_msg").text(info.message).addClass("error_msg");
        				}
        			}
        		);
        	}
        	
            //保存结果的提示
            function showResult() {
                showResultDiv(true);
                window.setTimeout("showResultDiv(false);", 3000);
            }
            function showResultDiv(flag) {
                var divResult = document.getElementById("save_result_info");
                if (flag)
                    divResult.style.display = "block";
                else
                    divResult.style.display = "none";
            }

            //切换资费类型
            function feeTypeChange(type) {
                var inputArray = document.getElementById("main").getElementsByTagName("input");
                if (type == 1) {
                    inputArray[4].readonly = true;
                    inputArray[4].value = "";
                    inputArray[4].className += " readonly";
                    inputArray[5].readonly = false;
                    inputArray[5].className = "width100";
                    inputArray[6].readonly = true;
                    inputArray[6].className += " readonly";
                    inputArray[6].value = "";
                }
                else if (type == 2) {
                    inputArray[4].readonly = false;
                    inputArray[4].className = "width100";
                    inputArray[5].readonly = false;
                    inputArray[5].className = "width100";
                    inputArray[6].readonly = false;
                    inputArray[6].className = "width100";
                }
                else if (type == 3) {
                    inputArray[4].readonly = true;
                    inputArray[4].value = "";
                    inputArray[4].className += " readonly";
                    inputArray[5].readonly = true;
                    inputArray[5].value = "";
                    inputArray[5].className += " readonly";
                    inputArray[6].readonly = false;
                    inputArray[6].className = "width100";
                }
            }
        </script>
    </head>
    <body>
        <!--Logo区域开始-->
        <div id="header">
            <img src="../images/logo.png" alt="logo" class="left"/>
            <a href="#">[退出]</a>            
        </div>
        <!--Logo区域结束-->
        <!--导航区域开始-->
        <div id="navi">
            <ul id="menu">
                <li><a href="../index.html" class="index_off"></a></li>
                <li><a href="../role/role_list.html" class="role_off"></a></li>
                <li><a href="../admin/admin_list.html" class="admin_off"></a></li>
                <li><a href="../fee/fee_list.html" class="fee_on"></a></li>
                <li><a href="../account/account_list.html" class="account_off"></a></li>
                <li><a href="../service/service_list.html" class="service_off"></a></li>
                <li><a href="../bill/bill_list.html" class="bill_off"></a></li>
                <li><a href="../report/report_list.html" class="report_off"></a></li>
                <li><a href="../user/user_info.html" class="information_off"></a></li>
                <li><a href="../user/user_modi_pwd.html" class="password_off"></a></li>
            </ul>
        </div>
        <!--导航区域结束-->
        <!--主要区域开始-->
        <div id="main">            
            <div id="save_result_info" class="save_fail">保存失败,资费名称重复!</div>
            <form action="" method="" class="main_form">
                <div class="text_info clearfix"><span>资费名称:</span></div>
                <div class="input_info">
                    <input type="text" class="width300" id="cost_name" onblur="check_name();"/>
                    <span class="required">*</span>
                    <div class="validate_msg_short" id="name_msg">50长度的字母、数字、汉字和下划线的组合</div>
                </div>
                <div class="text_info clearfix"><span>资费类型:</span></div>
                <div class="input_info fee_type">
                    <input type="radio" name="radFeeType" id="monthly" onclick="feeTypeChange(1);" />
                    <label for="monthly">包月</label>
                    <input type="radio" name="radFeeType" checked="checked" id="package" onclick="feeTypeChange(2);" />
                    <label for="package">套餐</label>
                    <input type="radio" name="radFeeType" id="timeBased" onclick="feeTypeChange(3);" />
                    <label for="timeBased">计时</label>
                </div>
                <div class="text_info clearfix"><span>基本时长:</span></div>
                <div class="input_info">
                    <input type="text" value="" class="width100" />
                    <span class="info">小时</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long">1-600之间的整数</div>
                </div>
                <div class="text_info clearfix"><span>基本费用:</span></div>
                <div class="input_info">
                    <input type="text" value="" class="width100" />
                    <span class="info">元</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long error_msg">0-99999.99之间的数值</div>
                </div>
                <div class="text_info clearfix"><span>单位费用:</span></div>
                <div class="input_info">
                    <input type="text" value="" class="width100" />
                    <span class="info">元/小时</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long error_msg">0-99999.99之间的数值</div>
                </div>
                <div class="text_info clearfix"><span>资费说明:</span></div>
                <div class="input_info_high">
                    <textarea class="width300 height70"></textarea>
                    <div class="validate_msg_short error_msg">100长度的字母、数字、汉字和下划线的组合</div>
                </div>                    
                <div class="button_info clearfix">
                    <input type="button" value="保存" class="btn_save"  onclick="showResult();" />
                    <input type="button" value="取消" class="btn_save" />
                </div>
            </form>  
        </div>
        <!--主要区域结束-->
        <div id="footer">
            <span>[源自北美的技术,最优秀的师资,最真实的企业环境,最适用的实战项目]</span>
            <br />
            <span>版权所有(C) </span>
        </div>
    </body>
</html>

3 资费修改

3.1 问题

增加资费的修改功能,用于修改一条资费数据。本案例中只要求打开修改页面,并将要修改的内容默认显示在修改页面表单的文本框中即可。

3.2 方案

打开修改页面逻辑与打开新增页面一致,但同时要查询出要修改的数据并发送给修改页面,在修改页面上将这些数据默认显示在表单上。

对于数据的默认显示,我们可以使用Struts2提供的UI标签来做,UI标签的作用是可以生产框体同时设置其默认值。

3.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:在DAO中追加根据ID查询资费的方法

在ICostDao中追加根据ID查询资费的方法,代码如下:

package com.netctoss.dao;

import java.util.List;

import com.netctoss.entity.Cost;

/**
 * 资费DAO接口
 */
public interface ICostDao {

// 此处略去其他方法的声明...	
#cold_bold	/**
#cold_bold	 * 根据主键查询资费
#cold_bold	 * @param id 主键
#cold_bold	 * @return
#cold_bold	 */
#cold_bold	Cost findById(int id);

}

在CostDaoImpl中实现该方法,代码如下:

package com.netctoss.dao;

import java.util.ArrayList;
import java.util.List;

import com.netctoss.entity.Cost;

/**
 *	当前阶段学习重点是Struts2,对于DAO的实现就模拟实现了。
 *	同学们可以使用JDBC/MyBatis自行实现该DAO。
 */
public class CostDaoImpl implements ICostDao {

	// 此处略去其他方法的实现...

#cold_bold	@Override
#cold_bold	public Cost findById(int id) {
#cold_bold		// 模拟根据id查询资费数据
#cold_bold		Cost c = new Cost();
#cold_bold		c.setId(97);
#cold_bold		c.setName("tarena");
#cold_bold		c.setBaseDuration(99);
#cold_bold		c.setBaseCost(9.9);
#cold_bold		c.setUnitCost(0.9);
#cold_bold		c.setDescr("tarena套餐");
#cold_bold		c.setStatus("0");
#cold_bold		c.setCostType("2");
#cold_bold		return c;
#cold_bold	}

}

步骤二:创建打开修改页面的Action

在com.netctoss.action包下,创建打开修改页面的类ToUpdateCostAction,在该Action下定义输入属性为资费id,输出属性为资费实体对象,并在业务方法中调用DAO根据id查询出资费的实体对象。代码如下:

package com.netctoss.action;

import com.netctoss.dao.DAOFactory;
import com.netctoss.dao.ICostDao;
import com.netctoss.entity.Cost;

public class ToUpdateCostAction {

	// input
	private int id;

	// output
	private Cost cost;

	public String execute() {
		ICostDao dao = DAOFactory.getCostDAO();
		try {
			cost = dao.findById(id);
		} catch (Exception e) {
			e.printStackTrace();
			return "error";
		}
		return "success";
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public Cost getCost() {
		return cost;
	}

	public void setCost(Cost cost) {
		this.cost = cost;
	}

}

步骤三:在struts.xml中配置该action

在struts.xml中,配置打开修改页面的action,代码如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
    "/struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
	
	<!-- 
		资费模块配置信息:
		一般情况下,一个模块的配置单独封装在一个package下,
		并且以模块名来命名package的name和namespace。
	 -->
	<package name="cost" namespace="/cost" extends="json-default">
		<!—此处略去其他Action的配置... -->
#cold_bold		<!--  打开修改页面 -->
#cold_bold		<action name="toUpdateCost" 
#cold_bold			class="com.netctoss.action.ToUpdateCostAction">
#cold_bold			<result name="success">
#cold_bold				/WEB-INF/cost/update_cost.jsp
#cold_bold			</result>
#cold_bold			<result name="error">
#cold_bold				/WEB-INF/main/error.jsp
#cold_bold			</result>
#cold_bold		</action>
	</package>
	
	<!-- 登录模块 -->
	<package name="login" namespace="/login" extends="struts-default">
		<!—此处略去其他Action的配置... -->
	</package>
	
</struts>

步骤四:创建资费修改页面

在WEB-INF/cost下,创建资费修改页面update_cost.jsp,并将静态页面代码复制到此JSP中。代码如下:

<%@page pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "/www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="/www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title></title>
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global.css" />
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global_color.css" />
        <script language="javascript" type="text/javascript">
            //保存结果的提示
            function showResult() {
                showResultDiv(true);
                window.setTimeout("showResultDiv(false);", 3000);
            }
            function showResultDiv(flag) {
                var divResult = document.getElementById("save_result_info");
                if (flag)
                    divResult.style.display = "block";
                else
                    divResult.style.display = "none";
            }

            //切换资费类型
            function feeTypeChange(type) {
                var inputArray = document.getElementById("main").getElementsByTagName("input");
                if (type == 1) {
                    inputArray[5].readonly = true;
                    inputArray[5].value = "";
                    inputArray[5].className += " readonly";
                    inputArray[6].readonly = false;
                    inputArray[6].className = "width100";
                    inputArray[7].readonly = true;
                    inputArray[7].className += " readonly";
                    inputArray[7].value = "";
                }
                else if (type == 2) {
                    inputArray[5].readonly = false;
                    inputArray[5].className = "width100";
                    inputArray[6].readonly = false;
                    inputArray[6].className = "width100";
                    inputArray[7].readonly = false;
                    inputArray[7].className = "width100";
                }
                else if (type == 3) {
                    inputArray[5].readonly = true;
                    inputArray[5].value = "";
                    inputArray[5].className += " readonly";
                    inputArray[6].readonly = true;
                    inputArray[6].value = "";
                    inputArray[6].className += " readonly";
                    inputArray[7].readonly = false;
                    inputArray[7].className = "width100";
                }
            }
        </script>
    </head>
    <body>
        <!--Logo区域开始-->
        <div id="header">
            <img src="../images/logo.png" alt="logo" class="left"/>
            <a href="#">[退出]</a>            
        </div>
        <!--Logo区域结束-->
        <!--导航区域开始-->
        <div id="navi">
            <ul id="menu">
                <li><a href="../index.html" class="index_off"></a></li>
                <li><a href="../role/role_list.html" class="role_off"></a></li>
                <li><a href="../admin/admin_list.html" class="admin_off"></a></li>
                <li><a href="../fee/fee_list.html" class="fee_on"></a></li>
                <li><a href="../account/account_list.html" class="account_off"></a></li>
                <li><a href="../service/service_list.html" class="service_off"></a></li>
                <li><a href="../bill/bill_list.html" class="bill_off"></a></li>
                <li><a href="../report/report_list.html" class="report_off"></a></li>
                <li><a href="../user/user_info.html" class="information_off"></a></li>
                <li><a href="../user/user_modi_pwd.html" class="password_off"></a></li>
            </ul>
        </div>
        <!--导航区域结束-->
        <!--主要区域开始-->
        <div id="main">            
            <div id="save_result_info" class="save_success">保存成功!</div>
            <form action="" method="" class="main_form">
                <div class="text_info clearfix"><span>资费ID:</span></div>
                <div class="input_info"><input type="text" class="readonly" readonly value="1" /></div>
                <div class="text_info clearfix"><span>资费名称:</span></div>
                <div class="input_info">
                    <input type="text" class="width300" value="包 20 小时"/>
                    <span class="required">*</span>
                    <div class="validate_msg_short">50长度的字母、数字、汉字和下划线的组合</div>
                </div>
                <div class="text_info clearfix"><span>资费类型:</span></div>
                <div class="input_info fee_type">
                    <input type="radio" name="radFeeType" id="monthly" onclick="feeTypeChange(1);" />
                    <label for="monthly">包月</label>
                    <input type="radio" name="radFeeType" checked="checked" id="package" onclick="feeTypeChange(2);" />
                    <label for="package">套餐</label>
                    <input type="radio" name="radFeeType" id="timeBased" onclick="feeTypeChange(3);" />
                    <label for="timeBased">计时</label>
                </div>
                <div class="text_info clearfix"><span>基本时长:</span></div>
                <div class="input_info">
                    <input type="text" value="" class="width100" />
                    <span class="info">小时</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long">1-600之间的整数</div>
                </div>
                <div class="text_info clearfix"><span>基本费用:</span></div>
                <div class="input_info">
                    <input type="text" value="" class="width100" />
                    <span class="info">元</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long">0-99999.99之间的数值</div>
                </div>
                <div class="text_info clearfix"><span>单位费用:</span></div>
                <div class="input_info">
                    <input type="text" value="" class="width100" />
                    <span class="info">元/小时</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long">0-99999.99之间的数值</div>
                </div>   
                <div class="text_info clearfix"><span>资费说明:</span></div>
                <div class="input_info_high">
                    <textarea class="width300 height70">没有启用的资费,可以修改除 ID 以外的所有信息
                    </textarea>
                    <div class="validate_msg_short">100长度的字母、数字、汉字和下划线的组合</div>
                </div>                    
                <div class="button_info clearfix">
                    <input type="button" value="保存" class="btn_save"  onclick="showResult();" />
                    <input type="button" value="取消" class="btn_save" />
                </div>
            </form>
        </div>
        <!--主要区域结束-->
        <div id="footer">
            <span>[源自北美的技术,最优秀的师资,最真实的企业环境,最适用的实战项目]</span>
            <br />
            <span>版权所有(C) </span>
        </div>
    </body>
</html>

步骤五:设置修改按钮URL

在find_cost.jsp上,设置修改按钮的请求路径为打开修改页面的action,并传入参数id。代码如下:

<%@page pageEncoding="utf-8" isELIgnored="false"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "/www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="/www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title></title>
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global.css" />
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global_color.css" />
        <script language="javascript" type="text/javascript">
            //排序按钮的点击事件
            function sort(btnObj) {
                if (btnObj.className == "sort_desc")
                    btnObj.className = "sort_asc";
                else
                    btnObj.className = "sort_desc";
            }

            //启用
            function startFee() {
                var r = window.confirm("确定要启用此资费吗?资费启用后将不能修改和删除。");
                document.getElementById("operate_result_info").style.display = "block";
            }
            //删除
            function deleteFee(id) {
                var r = window.confirm("确定要删除此资费吗?");
                if(r) {
                	// 如果用户确认,则调用删除资费action
                	window.location.href = "deleteCost?id="+id;
                }
            }
        </script>        
    </head>
    <body>
        <!--Logo区域开始-->
        <div id="header">
            <img src="../images/logo.png" alt="logo" class="left"/>
            <a href="#">[退出]</a>            
        </div>
        <!--Logo区域结束-->
        <!--导航区域开始-->
        <div id="navi">                        
            <ul id="menu">
                <li><a href="../index.html" class="index_off"></a></li>
                <li><a href="../role/role_list.html" class="role_off"></a></li>
                <li><a href="../admin/admin_list.html" class="admin_off"></a></li>
                <li><a href="../fee/fee_list.html" class="fee_on"></a></li>
                <li><a href="../account/account_list.html" class="account_off"></a></li>
                <li><a href="../service/service_list.html" class="service_off"></a></li>
                <li><a href="../bill/bill_list.html" class="bill_off"></a></li>
                <li><a href="../report/report_list.html" class="report_off"></a></li>
                <li><a href="../user/user_info.html" class="information_off"></a></li>
                <li><a href="../user/user_modi_pwd.html" class="password_off"></a></li>
            </ul>            
        </div>
        <!--导航区域结束-->
        <!--主要区域开始-->
        <div id="main">
            <form action="" method="">
                <!--排序-->
                <div class="search_add">
                    <div>
                        <!--<input type="button" value="月租" class="sort_asc" onclick="sort(this);" />-->
                        <input type="button" value="基费" class="sort_asc" onclick="sort(this);" />
                        <input type="button" value="时长" class="sort_asc" onclick="sort(this);" />
                    </div>
                    <input type="button" value="增加" class="btn_add" onclick="location.href='toAddCost';" />
                </div> 
                <!--启用操作的操作提示-->
                <div id="operate_result_info" class="operate_success">
                    <img src="../images/close.png" onclick="this.parentNode.style.display='none';" />
                    删除成功!
                </div>    
                <!--数据区域:用表格展示数据-->     
                <div id="data">            
                    <table id="datalist">
                        <tr>
                            <th>资费ID</th>
                            <th class="width100">资费名称</th>
                            <th>基本时长</th>
                            <th>基本费用</th>
                            <th>单位费用</th>
                            <th>创建时间</th>
                            <th>开通时间</th>
                            <th class="width50">状态</th>
                            <th class="width200"></th>
                        </tr>       
                        
                        <!-- 使用Struts2标签遍历集合,使用OGNL表达式输出内容。 -->               
                        <s:iterator value="costs">                 
	                        <tr>
	                            <td><s:property value="id"/></td>
	                            <td><a href="fee_detail.html"><s:property value="name"/></a></td>
	                            <td><s:property value="baseDuration"/></td>
	                            <td><s:property value="baseCost"/></td>
	                            <td><s:property value="unitCost"/></td>
	                            <td><s:property value="createTime"/></td>
	                            <td><s:property value="startTime"/></td>
	                            <td>
	                            	<s:if test="status==0">开通</s:if>
	                            	<s:else>暂停</s:else>
	                            </td>
	                            <td>                                
	                                <input type="button" value="启用" class="btn_start" onclick="startFee();" />
#cold_bold	                                <input type="button" value="修改" class="btn_modify" onclick="location.href='toUpdateCost?id=<s:property value="id"/>';" />
	                                <input type="button" value="删除" class="btn_delete" onclick="deleteFee(<s:property value="id"/>);" />
	                            </td>
	                        </tr>
                       </s:iterator>
                       
                    </table>
                    <p>业务说明:<br />
                    1、创建资费时,状态为暂停,记载创建时间;<br />
                    2、暂停状态下,可修改,可删除;<br />
                    3、开通后,记载开通时间,且开通后不能修改、不能再停用、也不能删除;<br />
                    4、业务账号修改资费时,在下月底统一触发,修改其关联的资费ID(此触发动作由程序处理)
                    </p>
                </div>
                <!--分页-->
                <div id="pages">
        	        <a href="#">上一页</a>
                    <a href="#" class="current_page">1</a>
                    <a href="#">2</a>
                    <a href="#">3</a>
                    <a href="#">4</a>
                    <a href="#">5</a>
                    <a href="#">下一页</a>
                </div>
            </form>
        </div>
        <!--主要区域结束-->
        <div id="footer">
            <p>[源自北美的技术,最优秀的师资,最真实的企业环境,最适用的实战项目]</p>
            <p>版权所有(C) </p>
        </div>
    </body>
</html>

步骤六:阶段测试

重新部署项目并重启tomcat,打开资费列表页面,点击任意的修改按钮,效果如下图:

图-5

步骤七:在修改页面上使用UI标签回显修改数据

在update_cost.jsp上,使用UI标签生成框体并给框体设置默认值。代码如下:

<%@page pageEncoding="utf-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "/www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="/www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title></title>
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global.css" />
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global_color.css" />
        <script language="javascript" type="text/javascript">
            //保存结果的提示
            function showResult() {
                showResultDiv(true);
                window.setTimeout("showResultDiv(false);", 3000);
            }
            function showResultDiv(flag) {
                var divResult = document.getElementById("save_result_info");
                if (flag)
                    divResult.style.display = "block";
                else
                    divResult.style.display = "none";
            }

            //切换资费类型
            function feeTypeChange(type) {
                var inputArray = document.getElementById("main").getElementsByTagName("input");
                if (type == 1) {
                    inputArray[5].readonly = true;
                    inputArray[5].value = "";
                    inputArray[5].className += " readonly";
                    inputArray[6].readonly = false;
                    inputArray[6].className = "width100";
                    inputArray[7].readonly = true;
                    inputArray[7].className += " readonly";
                    inputArray[7].value = "";
                }
                else if (type == 2) {
                    inputArray[5].readonly = false;
                    inputArray[5].className = "width100";
                    inputArray[6].readonly = false;
                    inputArray[6].className = "width100";
                    inputArray[7].readonly = false;
                    inputArray[7].className = "width100";
                }
                else if (type == 3) {
                    inputArray[5].readonly = true;
                    inputArray[5].value = "";
                    inputArray[5].className += " readonly";
                    inputArray[6].readonly = true;
                    inputArray[6].value = "";
                    inputArray[6].className += " readonly";
                    inputArray[7].readonly = false;
                    inputArray[7].className = "width100";
                }
            }
        </script>
    </head>
    <body>
        <!--Logo区域开始-->
        <div id="header">
            <img src="../images/logo.png" alt="logo" class="left"/>
            <a href="#">[退出]</a>            
        </div>
        <!--Logo区域结束-->
        <!--导航区域开始-->
        <div id="navi">
            <ul id="menu">
                <li><a href="../index.html" class="index_off"></a></li>
                <li><a href="../role/role_list.html" class="role_off"></a></li>
                <li><a href="../admin/admin_list.html" class="admin_off"></a></li>
                <li><a href="../fee/fee_list.html" class="fee_on"></a></li>
                <li><a href="../account/account_list.html" class="account_off"></a></li>
                <li><a href="../service/service_list.html" class="service_off"></a></li>
                <li><a href="../bill/bill_list.html" class="bill_off"></a></li>
                <li><a href="../report/report_list.html" class="report_off"></a></li>
                <li><a href="../user/user_info.html" class="information_off"></a></li>
                <li><a href="../user/user_modi_pwd.html" class="password_off"></a></li>
            </ul>
        </div>
        <!--导航区域结束-->
        <!--主要区域开始-->
        <div id="main">            
            <div id="save_result_info" class="save_success">保存成功!</div>
            <form action="" method="" class="main_form">
                <div class="text_info clearfix"><span>资费ID:</span></div>
                <div class="input_info">
#cold_bold                	<s:textfield name="cost.id" cssClass="readonly" readonly="true"/>
                </div>
                <div class="text_info clearfix"><span>资费名称:</span></div>
                <div class="input_info">
#cold_bold                    <s:textfield name="cost.name" cssClass="width300" />
                    <span class="required">*</span>
                    <div class="validate_msg_short">50长度的字母、数字、汉字和下划线的组合</div>
                </div>
                <div class="text_info clearfix"><span>资费类型:</span></div>
                <div class="input_info fee_type">
#cold_bold                    <s:radio name="cost.costType" list="#{'1':'包月','2':'套餐','3':'计时' }" onclick="feeTypeChange(this.value)"/>
                </div>
                <div class="text_info clearfix"><span>基本时长:</span></div>
                <div class="input_info">
#cold_bold                    <s:textfield name="cost.baseDuration" cssClass="width100"/>
                    <span class="info">小时</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long">1-600之间的整数</div>
                </div>
                <div class="text_info clearfix"><span>基本费用:</span></div>
                <div class="input_info">
#cold_bold                    <s:textfield name="cost.baseCost" cssClass="width100"/>
                    <span class="info">元</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long">0-99999.99之间的数值</div>
                </div>
                <div class="text_info clearfix"><span>单位费用:</span></div>
                <div class="input_info">
#cold_bold                    <s:textfield name="cost.unitCost" cssClass="width100"/>
                    <span class="info">元/小时</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long">0-99999.99之间的数值</div>
                </div>   
                <div class="text_info clearfix"><span>资费说明:</span></div>
                <div class="input_info_high">
#cold_bold                   <s:textarea name="cost.descr" cssClass="width300 height70"/>
                    <div class="validate_msg_short">100长度的字母、数字、汉字和下划线的组合</div>
                </div>                    
                <div class="button_info clearfix">
                    <input type="button" value="保存" class="btn_save"  onclick="showResult();" />
                    <input type="button" value="取消" class="btn_save" />
                </div>
            </form>
        </div>
        <!--主要区域结束-->
        <div id="footer">
            <span>[源自北美的技术,最优秀的师资,最真实的企业环境,最适用的实战项目]</span>
            <br />
            <span>版权所有(C) </span>
        </div>
    </body>
</html>

步骤八:测试

重新访问资费列表页面并点击修改按钮,效果如下图:

图-6

3.4 完整代码

本案例的完整代码如下。

ICostDao完整代码:

package com.netctoss.dao;

import java.util.List;

import com.netctoss.entity.Cost;

/**
 * 资费DAO接口
 */
public interface ICostDao {

	/**
	 * 查询全部资费数据
	 */
	List<Cost> findAll();

	/**
	 * 删除一条资费数据
	 * @param id 主键
	 */
	void delete(int id);
	
	/**
	 * 根据名称查询资费
	 * @param name 资费名
	 * @return
	 */
	Cost findByName(String name);
	
	/**
	 * 根据主键查询资费
	 * @param id 主键
	 * @return
	 */
	Cost findById(int id);

}

CostDaoImpl完整代码:

package com.netctoss.dao;

import java.util.ArrayList;
import java.util.List;

import com.netctoss.entity.Cost;

/**
 *	当前阶段学习重点是Struts2,对于DAO的实现就模拟实现了。
 *	同学们可以使用JDBC/MyBatis自行实现该DAO。
 */
public class CostDaoImpl implements ICostDao {

	@Override
	public List<Cost> findAll() {
		// 模拟查询全部资费数据
		List<Cost> list = new ArrayList<Cost>();
		
		Cost c1 = new Cost();
		c1.setId(95);
		c1.setName("6元套餐");
		c1.setBaseDuration(66);
		c1.setBaseCost(6.6);
		c1.setUnitCost(0.6);
		c1.setDescr("6元套餐");
		c1.setStatus("0");
		c1.setCostType("2");
		list.add(c1);
		
		Cost c2 = new Cost();
		c2.setId(96);
		c2.setName("8元套餐");
		c2.setBaseDuration(88);
		c2.setBaseCost(8.8);
		c2.setUnitCost(0.8);
		c2.setDescr("8元套餐");
		c2.setStatus("0");
		c2.setCostType("2");
		list.add(c2);
		
		Cost c3 = new Cost();
		c3.setId(97);
		c3.setName("tarena");
		c3.setBaseDuration(99);
		c3.setBaseCost(9.9);
		c3.setUnitCost(0.9);
		c3.setDescr("tarena套餐");
		c3.setStatus("0");
		c3.setCostType("2");
		list.add(c3);
		
		return list;
	}

	@Override
	public void delete(int id) {
		// 模拟根据id删除资费数据
		System.out.println("删除ID为[" + id + "]的资费数据.");
	}

	@Override
	public Cost findByName(String name) {
		// 模拟根据名称查询资费数据,假设资费表中只有一条名为tarena的数据
		if("tarena".equals(name)) {
			Cost c = new Cost();
			c.setId(97);
			c.setName("tarena");
			c.setBaseDuration(99);
			c.setBaseCost(9.9);
			c.setUnitCost(0.9);
			c.setDescr("tarena套餐");
			c.setStatus("0");
			c.setCostType("2");
			return c;
		}
		return null;
	}

	@Override
	public Cost findById(int id) {
		// 模拟根据id查询资费数据
		Cost c = new Cost();
		c.setId(97);
		c.setName("tarena");
		c.setBaseDuration(99);
		c.setBaseCost(9.9);
		c.setUnitCost(0.9);
		c.setDescr("tarena套餐");
		c.setStatus("0");
		c.setCostType("2");
		return c;
	}

}

ToUpdateCostAction完整代码:

package com.netctoss.action;

import com.netctoss.dao.DAOFactory;
import com.netctoss.dao.ICostDao;
import com.netctoss.entity.Cost;

public class ToUpdateCostAction {

	// input
	private int id;

	// output
	private Cost cost;

	public String execute() {
		ICostDao dao = DAOFactory.getCostDAO();
		try {
			cost = dao.findById(id);
		} catch (Exception e) {
			e.printStackTrace();
			return "error";
		}
		return "success";
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public Cost getCost() {
		return cost;
	}

	public void setCost(Cost cost) {
		this.cost = cost;
	}

}

struts.xml完整代码:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
    "/struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
	
	<!-- 
		资费模块配置信息:
		一般情况下,一个模块的配置单独封装在一个package下,
		并且以模块名来命名package的name和namespace。
	 -->
	<package name="cost" namespace="/cost" extends="json-default">
		<!-- 查询资费数据 -->
		<action name="findCost" class="com.netctoss.action.FindCostAction">
			<!-- 
				正常情况下跳转到资费列表页面。
				一般一个模块的页面要打包在一个文件夹下,并且文件夹以模块名命名。
			 -->
			<result name="success">
				/WEB-INF/cost/find_cost.jsp
			</result>
			<!-- 
				错误情况下,跳转到错误页面。
				错误页面可以被所有模块复用,因此放在main下,
				该文件夹用于存放公用的页面。
			 -->
			<result name="error">
				/WEB-INF/main/error.jsp
			</result>
		</action>
		<!-- 删除资费 -->
		<action name="deleteCost" 
			class="com.netctoss.action.DeleteCostAction">
			<!-- 删除完之后,重定向到查询action -->
			<result name="success" type="redirectAction">
				findCost
			</result>
			<result name="error">
				/WEB-INF/main/error.jsp
			</result>
		</action>
		<!-- 打开资费新增页 -->
		<action name="toAddCost">
			<result name="success">
				/WEB-INF/cost/add_cost.jsp
			</result>
		</action>
		<!-- 资费名唯一性校验 -->
		<action name="checkCostName" 
			class="com.netctoss.action.CheckCostNameAction">
			<!-- 使用json类型的result把结果输出给回调函数 -->
			<result name="success" type="json">
				<param name="root">info</param>
			</result>
		</action>
		<!--  打开修改页面 -->
		<action name="toUpdateCost" 
			class="com.netctoss.action.ToUpdateCostAction">
			<result name="success">
				/WEB-INF/cost/update_cost.jsp
			</result>
			<result name="error">
				/WEB-INF/main/error.jsp
			</result>
		</action>
	</package>
	
	<!-- 登录模块 -->
	<package name="login" namespace="/login" extends="struts-default">
		<!-- 
			打开登录页面:
			1、action的class属性可以省略,省略时Struts2
			   会自动实例化默认的Action类ActionSupport,
			   该类中有默认业务方法execute,返回success。
			2、action的method属性可以省略,省略时Struts2
			   会自动调用execute方法。
		-->
		<action name="toLogin">
			<result name="success">
				/WEB-INF/main/login.jsp
			</result>
		</action>
		<!-- 登录校验 -->
		<action name="login" class="com.netctoss.action.LoginAction">
			<!-- 校验成功,跳转到系统首页 -->
			<result name="success">
				/WEB-INF/main/index.jsp
			</result>
			<!-- 登录失败,跳转回登录页面 -->
			<result name="fail">
				/WEB-INF/main/login.jsp
			</result>
			<!-- 报错,跳转到错误页面 -->
			<result name="error">
				/WEB-INF/main/error.jsp
			</result>
		</action>
		<!-- 生成验证码 -->
		<action name="createImage" class="com.netctoss.action.CreateImageAction">
			<!-- 使用stream类型的result -->
			<result name="success" type="stream">
				<!-- 指定输出的内容 -->
				<param name="inputName">imageStream</param>
			</result>
		</action>
	</package>
	
</struts>

find_cost.jsp完整代码:

<%@page pageEncoding="utf-8" isELIgnored="false"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "/www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="/www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title></title>
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global.css" />
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global_color.css" />
        <script language="javascript" type="text/javascript">
            //排序按钮的点击事件
            function sort(btnObj) {
                if (btnObj.className == "sort_desc")
                    btnObj.className = "sort_asc";
                else
                    btnObj.className = "sort_desc";
            }

            //启用
            function startFee() {
                var r = window.confirm("确定要启用此资费吗?资费启用后将不能修改和删除。");
                document.getElementById("operate_result_info").style.display = "block";
            }
            //删除
            function deleteFee(id) {
                var r = window.confirm("确定要删除此资费吗?");
                if(r) {
                	// 如果用户确认,则调用删除资费action
                	window.location.href = "deleteCost?id="+id;
                }
            }
        </script>        
    </head>
    <body>
        <!--Logo区域开始-->
        <div id="header">
            <img src="../images/logo.png" alt="logo" class="left"/>
            <a href="#">[退出]</a>            
        </div>
        <!--Logo区域结束-->
        <!--导航区域开始-->
        <div id="navi">                        
            <ul id="menu">
                <li><a href="../index.html" class="index_off"></a></li>
                <li><a href="../role/role_list.html" class="role_off"></a></li>
                <li><a href="../admin/admin_list.html" class="admin_off"></a></li>
                <li><a href="../fee/fee_list.html" class="fee_on"></a></li>
                <li><a href="../account/account_list.html" class="account_off"></a></li>
                <li><a href="../service/service_list.html" class="service_off"></a></li>
                <li><a href="../bill/bill_list.html" class="bill_off"></a></li>
                <li><a href="../report/report_list.html" class="report_off"></a></li>
                <li><a href="../user/user_info.html" class="information_off"></a></li>
                <li><a href="../user/user_modi_pwd.html" class="password_off"></a></li>
            </ul>            
        </div>
        <!--导航区域结束-->
        <!--主要区域开始-->
        <div id="main">
            <form action="" method="">
                <!--排序-->
                <div class="search_add">
                    <div>
                        <!--<input type="button" value="月租" class="sort_asc" onclick="sort(this);" />-->
                        <input type="button" value="基费" class="sort_asc" onclick="sort(this);" />
                        <input type="button" value="时长" class="sort_asc" onclick="sort(this);" />
                    </div>
                    <input type="button" value="增加" class="btn_add" onclick="location.href='toAddCost';" />
                </div> 
                <!--启用操作的操作提示-->
                <div id="operate_result_info" class="operate_success">
                    <img src="../images/close.png" onclick="this.parentNode.style.display='none';" />
                    删除成功!
                </div>    
                <!--数据区域:用表格展示数据-->     
                <div id="data">            
                    <table id="datalist">
                        <tr>
                            <th>资费ID</th>
                            <th class="width100">资费名称</th>
                            <th>基本时长</th>
                            <th>基本费用</th>
                            <th>单位费用</th>
                            <th>创建时间</th>
                            <th>开通时间</th>
                            <th class="width50">状态</th>
                            <th class="width200"></th>
                        </tr>       
                        
                        <!-- 使用Struts2标签遍历集合,使用OGNL表达式输出内容。 -->               
                        <s:iterator value="costs">                 
	                        <tr>
	                            <td><s:property value="id"/></td>
	                            <td><a href="fee_detail.html"><s:property value="name"/></a></td>
	                            <td><s:property value="baseDuration"/></td>
	                            <td><s:property value="baseCost"/></td>
	                            <td><s:property value="unitCost"/></td>
	                            <td><s:property value="createTime"/></td>
	                            <td><s:property value="startTime"/></td>
	                            <td>
	                            	<s:if test="status==0">开通</s:if>
	                            	<s:else>暂停</s:else>
	                            </td>
	                            <td>                                
	                                <input type="button" value="启用" class="btn_start" onclick="startFee();" />
	                                <input type="button" value="修改" class="btn_modify" onclick="location.href='toUpdateCost?id=<s:property value="id"/>';" />
	                                <input type="button" value="删除" class="btn_delete" onclick="deleteFee(<s:property value="id"/>);" />
	                            </td>
	                        </tr>
                       </s:iterator>
                       
                    </table>
                    <p>业务说明:<br />
                    1、创建资费时,状态为暂停,记载创建时间;<br />
                    2、暂停状态下,可修改,可删除;<br />
                    3、开通后,记载开通时间,且开通后不能修改、不能再停用、也不能删除;<br />
                    4、业务账号修改资费时,在下月底统一触发,修改其关联的资费ID(此触发动作由程序处理)
                    </p>
                </div>
                <!--分页-->
                <div id="pages">
                	<!-- 
                		如果当前页是第一页,则不允许再点上一页。
                		否则点击上一页时访问page-1页。
                	-->
                	<s:if test="page==1">
                		<a href="#">上一页</a>
                	</s:if>
                	<s:else>
                		<a href="findCost?page=<s:property value="page-1"/>">上一页</a>
                	</s:else>
        	        
        	        <!-- 循环输出页码 -->
        	        <s:iterator begin="1" end="totalPage" var="p">
        	        	<!-- 
        	        		1.如果循环页码等于当前页,则给与当前页样式current_page
        	        		2.链接findCost是相对路径,相对于当前浏览器地址栏的路径,
        	        			如果findCost的路径与地址栏路径的namespace相同,
        	        			则可以将namespace及之前的部分省略。
        	        	 -->
        	        	<s:if test="#p==page">
        	        		<a href="findCost?page=<s:property value="#p"/>" 
        	        				class="current_page"><s:property value="#p"/></a>
        	        	</s:if>
        	        	<s:else>
        	        		<a href="findCost?page=<s:property value="#p"/>"><s:property value="#p"/></a>
        	        	</s:else>
                    </s:iterator>
                    
                    <!-- 
                		如果当前页是最后一页,则不允许再点下一页。
                		否则点击下一页时访问page+1页。
                	-->
                	<s:if test="page==totalPage">
                		<a href="#">下一页</a>
                	</s:if>
                	<s:else>
                		<a href="findCost?page=<s:property value="page+1"/>">下一页</a>
                	</s:else>
                </div>
            </form>
        </div>
        <!--主要区域结束-->
        <div id="footer">
            <p>[源自北美的技术,最优秀的师资,最真实的企业环境,最适用的实战项目]</p>
            <p>版权所有(C) </p>
        </div>
    </body>
</html>

update_cost.jsp完整代码:

<%@page pageEncoding="utf-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "/www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="/www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title></title>
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global.css" />
        <link type="text/css" rel="stylesheet" media="all" href="../styles/global_color.css" />
        <script language="javascript" type="text/javascript">
            //保存结果的提示
            function showResult() {
                showResultDiv(true);
                window.setTimeout("showResultDiv(false);", 3000);
            }
            function showResultDiv(flag) {
                var divResult = document.getElementById("save_result_info");
                if (flag)
                    divResult.style.display = "block";
                else
                    divResult.style.display = "none";
            }

            //切换资费类型
            function feeTypeChange(type) {
                var inputArray = document.getElementById("main").getElementsByTagName("input");
                if (type == 1) {
                    inputArray[5].readonly = true;
                    inputArray[5].value = "";
                    inputArray[5].className += " readonly";
                    inputArray[6].readonly = false;
                    inputArray[6].className = "width100";
                    inputArray[7].readonly = true;
                    inputArray[7].className += " readonly";
                    inputArray[7].value = "";
                }
                else if (type == 2) {
                    inputArray[5].readonly = false;
                    inputArray[5].className = "width100";
                    inputArray[6].readonly = false;
                    inputArray[6].className = "width100";
                    inputArray[7].readonly = false;
                    inputArray[7].className = "width100";
                }
                else if (type == 3) {
                    inputArray[5].readonly = true;
                    inputArray[5].value = "";
                    inputArray[5].className += " readonly";
                    inputArray[6].readonly = true;
                    inputArray[6].value = "";
                    inputArray[6].className += " readonly";
                    inputArray[7].readonly = false;
                    inputArray[7].className = "width100";
                }
            }
        </script>
    </head>
    <body>
        <!--Logo区域开始-->
        <div id="header">
            <img src="../images/logo.png" alt="logo" class="left"/>
            <a href="#">[退出]</a>            
        </div>
        <!--Logo区域结束-->
        <!--导航区域开始-->
        <div id="navi">
            <ul id="menu">
                <li><a href="../index.html" class="index_off"></a></li>
                <li><a href="../role/role_list.html" class="role_off"></a></li>
                <li><a href="../admin/admin_list.html" class="admin_off"></a></li>
                <li><a href="../fee/fee_list.html" class="fee_on"></a></li>
                <li><a href="../account/account_list.html" class="account_off"></a></li>
                <li><a href="../service/service_list.html" class="service_off"></a></li>
                <li><a href="../bill/bill_list.html" class="bill_off"></a></li>
                <li><a href="../report/report_list.html" class="report_off"></a></li>
                <li><a href="../user/user_info.html" class="information_off"></a></li>
                <li><a href="../user/user_modi_pwd.html" class="password_off"></a></li>
            </ul>
        </div>
        <!--导航区域结束-->
        <!--主要区域开始-->
        <div id="main">            
            <div id="save_result_info" class="save_success">保存成功!</div>
            <form action="" method="" class="main_form">
                <div class="text_info clearfix"><span>资费ID:</span></div>
                <div class="input_info">
                	<s:textfield name="cost.id" cssClass="readonly" readonly="true"/>
                </div>
                <div class="text_info clearfix"><span>资费名称:</span></div>
                <div class="input_info">
                    <s:textfield name="cost.name" cssClass="width300" />
                    <span class="required">*</span>
                    <div class="validate_msg_short">50长度的字母、数字、汉字和下划线的组合</div>
                </div>
                <div class="text_info clearfix"><span>资费类型:</span></div>
                <div class="input_info fee_type">
                    <s:radio name="cost.costType" list="#{'1':'包月','2':'套餐','3':'计时' }" onclick="feeTypeChange(this.value)"/>
                </div>
                <div class="text_info clearfix"><span>基本时长:</span></div>
                <div class="input_info">
                    <s:textfield name="cost.baseDuration" cssClass="width100"/>
                    <span class="info">小时</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long">1-600之间的整数</div>
                </div>
                <div class="text_info clearfix"><span>基本费用:</span></div>
                <div class="input_info">
                    <s:textfield name="cost.baseCost" cssClass="width100"/>
                    <span class="info">元</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long">0-99999.99之间的数值</div>
                </div>
                <div class="text_info clearfix"><span>单位费用:</span></div>
                <div class="input_info">
                    <s:textfield name="cost.unitCost" cssClass="width100"/>
                    <span class="info">元/小时</span>
                    <span class="required">*</span>
                    <div class="validate_msg_long">0-99999.99之间的数值</div>
                </div>   
                <div class="text_info clearfix"><span>资费说明:</span></div>
                <div class="input_info_high">
                   <s:textarea name="cost.descr" cssClass="width300 height70"/>
                    <div class="validate_msg_short">100长度的字母、数字、汉字和下划线的组合</div>
                </div>                    
                <div class="button_info clearfix">
                    <input type="button" value="保存" class="btn_save"  onclick="showResult();" />
                    <input type="button" value="取消" class="btn_save" />
                </div>
            </form>
        </div>
        <!--主要区域结束-->
        <div id="footer">
            <span>[源自北美的技术,最优秀的师资,最真实的企业环境,最适用的实战项目]</span>
            <br />
            <span>版权所有(C) </span>
        </div>
    </body>
</html>

4 使用简单的UI标签

4.1 问题

练习使用简单的UI标签生成框体,并给框体赋默认值,标签包含:

  1. 表单标签
  2. 提交按钮
  3. 文本框
  4. 密码框
  5. 文本域
  6. 布尔框

4.2 方案

UI标签最核心的功能是用于回显数据,因此往往被使用在修改功能中。为了贴合实际业务,我们模拟修改客户的场景,在修改客户的页面上使用上述标签来回显查询出的客户数据。

由于本案例侧重点在UI标签的使用,因此是模拟修改客户的场景,简化打开修改页面的代码即可,这里我们不需要设计数据库以及查询数据库,仅仅是模拟一份数据即可。

为了保证能够在模拟的场景中使用到每一个UI标签,因此客户实体类中要包含每一类的数据,这样的模拟并不符合真实的业务,而仅仅是为了练习标签做的假设,请同学们注意这一点。

4.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:创建项目

先创建项目StrutsDay04,然后导入Struts2核心包,接下来在web.xml中配置前端控制器,最后在src下创建struts.xml,即StrutsDay01中的Struts2使用步骤。

步骤二:准备项目

模拟出客户修改的功能,先建包entity,在包下创建客户实体类Customer,代码如下:

package entity;

import java.util.List;

public class Customer {

	private String name; // 姓名
	private String password; // 密码
	private String desc; // 简介
	private boolean marry; // 是否已婚

	private String sex; // 性别
	private List<String> travelCities; // 去过的城市
	private String home; // 家乡

	public String getName() {
		return name;
	}

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

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getDesc() {
		return desc;
	}

	public void setDesc(String desc) {
		this.desc = desc;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public boolean isMarry() {
		return marry;
	}

	public void setMarry(boolean marry) {
		this.marry = marry;
	}

	public String getHome() {
		return home;
	}

	public List<String> getTravelCities() {
		return travelCities;
	}

	public void setTravelCities(List<String> travelCities) {
		this.travelCities = travelCities;
	}

	public void setHome(String home) {
		this.home = home;
	}

}

然后创建客户DAO,并模拟根据id查询客户的方法,代码如下:

package dao;

import java.util.ArrayList;
import java.util.List;
import entity.Customer;

/**
 * 模拟客户DAO
 */
public class CustomerDAO {

	/**
	 * 模拟根据ID查询客户
	 */
	public Customer findById() {
		// 实例化客户实体类
		Customer c = new Customer();
		// 设置一些默认值
		c.setName("Tarena");
		c.setPassword("123");
		c.setDesc("中华人民共和国公民");
		c.setSex("F");
		c.setMarry(true);

		List<String> list = new ArrayList<String>();
		list.add("beijing");
		list.add("guangzhou");
		c.setTravelCities(list);

		c.setHome("shanghai");
		return c;
	}

}

接下来,创建打开修改页面Action类ToUpdateCustomerAction,在此Action中模拟处理打开修改页面,查询客户的请求,代码如下:

package action;

import dao.CustomerDAO;
import entity.Customer;

public class ToUpdateCustomerAction {

	// output
	private Customer customer;

	public String execute() {
		CustomerDAO dao = new CustomerDAO();
		// 模拟查询客户
		customer = dao.findById();
		return "success";
	}

	public Customer getCustomer() {
		return customer;
	}

	public void setCustomer(Customer customer) {
		this.customer = customer;
	}

}

接下来,在struts.xml中配置打开修改页面action,代码如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
    "/struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>

	<!-- 客户配置信息 -->
	<package name="customer" 
		namespace="/customer" extends="struts-default">
		<!-- 打开修改页面 -->
		<action name="toUpdateCustomer" 
			class="action.ToUpdateCustomerAction">
			<result name="success">
				/WEB-INF/customer/update_customer.jsp
			</result>
		</action>
	</package>

</struts>

最后,在WEB-INF下创建customer文件夹,并在此文件夹下创建修改客户的页面update_customer.jsp,该页面简化处理,先输出一句话“模拟修改客户”即可,代码如下:

<%@page pageEncoding="utf-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<html>
<head></head>
<body>
	<h1>模拟修改客户</h1>
	
</body>
</html>

完成上述模拟修改客户的代码后,项目结构如下图:

图-7

部署项目并启动tomcat,在浏览器中访问修改客户,效果如下图:

图-8

步骤三:表单标签

在update_customer.jsp上,使用表单标签生成form表单,代码如下:

<%@page pageEncoding="utf-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<html>
<head></head>
<body>
	<h1>模拟修改客户</h1>
	
#cold_bold	<%-- 1.表单标签 --%>
#cold_bold	<s:form action="#" method="post">
#cold_bold		
#cold_bold	</s:form>	
	
</body>
</html>

刷新浏览器,修改页面效果如下:

图-9

步骤四:文本框标签

在update_customer.jsp上,使用文本框标签生成文本框,并在框内显示客户名称,代码如下:

<%@page pageEncoding="utf-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<html>
<head></head>
<body>
	<h1>模拟修改客户</h1>
	
	<%-- 1.表单标签 --%>
	<s:form action="#" method="post">
#cold_bold		<!-- 
#cold_bold			2.文本框标签
#cold_bold			 1)生成文本框
#cold_bold			 2)根据OGNL(customer.name)取值给文本框赋值
#cold_bold		-->
#cold_bold		<s:textfield name="customer.name" label="姓名"/>
		
	</s:form>	
	
</body>
</html>

刷新浏览器,修改页面效果如下:

图-10

步骤五:密码框标签

在update_customer.jsp上,使用密码框标签生成密码框,并在框内显示客户密码,代码如下:

<%@page pageEncoding="utf-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<html>
<head></head>
<body>
	<h1>模拟修改客户</h1>
	
	<%-- 1.表单标签 --%>
	<s:form action="#" method="post">
		<!--此处略去其他标签...-->
#cold_bold		<!-- 
#cold_bold			3.密码框标签
#cold_bold			 1)生成密码框
#cold_bold			 2)根据OGNL(customer.password)取值给密码框赋值
#cold_bold		-->
#cold_bold		<s:password name="customer.password" label="密码" showPassword="true"/>
		
	</s:form>	
	
</body>
</html>

刷新浏览器,修改页面效果如下:

图-11

步骤六:文本域标签

在update_customer.jsp上,使用文本域标签生成文本域,并在框内显示客户简介,代码如下:

<%@page pageEncoding="utf-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<html>
<head></head>
<body>
	<h1>模拟修改客户</h1>
	
	<%-- 1.表单标签 --%>
	<s:form action="#" method="post">
		<!--此处略去其他标签...-->
#cold_bold		<!-- 
#cold_bold			4.文本域标签
#cold_bold			 1)生成文本域
#cold_bold			 2)根据OGNL(customer.desc)取值给文本域赋值
#cold_bold		-->
#cold_bold		<s:textarea name="customer.desc" cols="30" rows="5" label="简介"/>
		
	</s:form>	
	
</body>
</html>

刷新浏览器,修改页面效果如下:

图-12

步骤七:布尔框标签

在update_customer.jsp上,使用布尔框标签生成选择框,并根据客户是否已婚来决定是否勾选该选择框,代码如下:

<%@page pageEncoding="utf-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<html>
<head></head>
<body>
	<h1>模拟修改客户</h1>
	
	<%-- 1.表单标签 --%>
	<s:form action="#" method="post">
		<!--此处略去其他标签...-->
#cold_bold		<!-- 
#cold_bold			5.布尔标签
#cold_bold			 1)生成一个checkbox
#cold_bold			 2)根据OGNL(customer.marry)取值(布尔型)来确定是否勾选
#cold_bold		-->
#cold_bold		<s:checkbox name="customer.marry" label="是否已婚" labelposition="left"/>
		
	</s:form>	
	
</body>
</html>

刷新浏览器,修改页面效果如下:

图-13

4.4 完整代码

本案例的完整代码如下。

Customer完整代码:

package entity;

import java.util.List;

public class Customer {

	private String name; // 姓名
	private String password; // 密码
	private String desc; // 简介
	private boolean marry; // 是否已婚

	private String sex; // 性别
	private List<String> travelCities; // 去过的城市
	private String home; // 家乡

	public String getName() {
		return name;
	}

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

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getDesc() {
		return desc;
	}

	public void setDesc(String desc) {
		this.desc = desc;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public boolean isMarry() {
		return marry;
	}

	public void setMarry(boolean marry) {
		this.marry = marry;
	}

	public String getHome() {
		return home;
	}

	public List<String> getTravelCities() {
		return travelCities;
	}

	public void setTravelCities(List<String> travelCities) {
		this.travelCities = travelCities;
	}

	public void setHome(String home) {
		this.home = home;
	}

}

CustomerDAO完整代码:

package dao;

import java.util.ArrayList;
import java.util.List;
import entity.Customer;

/**
 * 模拟客户DAO
 */
public class CustomerDAO {

	/**
	 * 模拟根据ID查询客户
	 */
	public Customer findById() {
		// 实例化客户实体类
		Customer c = new Customer();
		// 设置一些默认值
		c.setName("Tarena");
		c.setPassword("123");
		c.setDesc("中华人民共和国公民");
		c.setSex("F");
		c.setMarry(true);

		List<String> list = new ArrayList<String>();
		list.add("beijing");
		list.add("guangzhou");
		c.setTravelCities(list);

		c.setHome("shanghai");
		return c;
	}

}

ToUpdateCustomerAction完整代码:

package action;

import dao.CustomerDAO;
import entity.Customer;

public class ToUpdateCustomerAction {

	// output
	private Customer customer;

	public String execute() {
		CustomerDAO dao = new CustomerDAO();
		// 模拟查询客户
		customer = dao.findById();
		return "success";
	}

	public Customer getCustomer() {
		return customer;
	}

	public void setCustomer(Customer customer) {
		this.customer = customer;
	}

}

struts.xml完整代码:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
    "/struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>

	<!-- 客户配置信息 -->
	<package name="customer" 
		namespace="/customer" extends="struts-default">
		<!-- 打开修改页面 -->
		<action name="toUpdateCustomer" 
			class="action.ToUpdateCustomerAction">
			<result name="success">
				/WEB-INF/customer/update_customer.jsp
			</result>
		</action>
	</package>

</struts>

update_customer.jsp完整代码:

<%@page pageEncoding="utf-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<html>
<head></head>
<body>
	<h1>模拟修改客户</h1>
	
	<%-- 1.表单标签 --%>
	<s:form action="#" method="post">
		<!-- 
			2.文本框标签 
			 1)生成文本框
			 2)根据OGNL(customer.name)取值给文本框赋值
		-->
		<s:textfield name="customer.name" label="姓名"/>
		<!-- 
			3.密码框标签 
			 1)生成密码框
			 2)根据OGNL(customer.password)取值给密码框赋值
		-->
		<s:password name="customer.password" label="密码" showPassword="true"/>
		<!-- 
			4.文本域标签 
			 1)生成文本域
			 2)根据OGNL(customer.desc)取值给文本域赋值
		-->
		<s:textarea name="customer.desc" cols="30" rows="5" label="简介"/>
		<!-- 
			5.布尔标签 
			 1)生成一个checkbox
			 2)根据OGNL(customer.marry)取值(布尔型)来确定是否勾选
		-->
		<s:checkbox name="customer.marry" label="是否已婚" labelposition="left"/>
		
	</s:form>	
	
</body>
</html>

5 使用复杂的UI标签

5.1 问题

练习使用简单的UI标签生成框体,并给框体赋默认值,标签包含:

  1. 单选框标签
  2. 多选框标签
  3. 下拉选标签

5.2 方案

在StrutsDay04案例的模拟修改客户功能基础上,模拟数据,练习使用这3类标签。

5.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:单选框标签

单选框有2种用法,根据其初始化radio方式的不同,可以分为静态和动态2种方式。首先我们使用静态方式来初始化客户性别选项,并根据客户数据勾选客户性别,需要在update_customer.jsp上使用单选框标签来实现。代码如下:

<%@page pageEncoding="utf-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<html>
<head></head>
<body>
	<h1>模拟修改客户</h1>
	
	<%-- 1.表单标签 --%>
	<s:form action="#" method="post">
		<!--此处略去其他标签...-->
#cold_bold		<!-- 
#cold_bold			6.1单选框标签(静态)
#cold_bold			 1)根据OGNL(list属性值)创建的Map生成一组radio,
#cold_bold			其中Map的可以生成radio的value值,Map的value生成radio的label值。
#cold_bold			 2)根据OGNL(customer.marry)取值来与生成radio的value比较,
#cold_bold				若与哪个radio的value值一致,则将其勾选。
#cold_bold		-->
#cold_bold		<s:radio name="customer.sex" list="#{'M':'男','F':'女' }" label="性别"/>
		
	</s:form>	
	
</body>
</html>

刷新浏览器,修改页面效果如下:

图-14

静态方式初始化radio时是通过静态代码创建Map来实现的,很多时候这些选项不是固定的,是需要查询数据库得到的,即需要通过动态的方式来进行初始化选项,那么需要采用动态方式来实现。

要实现动态初始化选项,先要创建选项实体类,来封装选项信息,因此这里我们要创建性别的实体类Sex,当然就这个场景而言并不合理,仅是出于练习的目的,大家了解这种用法即可。代码如下:

package entity;

public class Sex {

	private String code;
	private String name;

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public String getName() {
		return name;
	}

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

}

然后在CustomerDAO中追加查询全部性别的方法,这个方法是模拟的方法,并且不符合真实的业务场景,仅用于练习知识点。代码如下:

package dao;

import java.util.ArrayList;
import java.util.List;
import entity.Customer;
import entity.Sex;

/**
 * 模拟客户DAO
 */
public class CustomerDAO {

//此处略去其他方法	...
#cold_bold	/**
#cold_bold	 * 模拟查询所有的性别,并不符合真实业务,仅仅是用于练习知识点
#cold_bold	 */
#cold_bold	public List<Sex> findAllSex() {
#cold_bold		List<Sex> list = new ArrayList<Sex>();
#cold_bold		
#cold_bold		Sex s1 = new Sex();
#cold_bold		s1.setCode("M");
#cold_bold		s1.setName("男");
#cold_bold		list.add(s1);
#cold_bold		
#cold_bold		Sex s2 = new Sex();
#cold_bold		s2.setCode("F");
#cold_bold		s2.setName("女");
#cold_bold		list.add(s2);
#cold_bold		
#cold_bold		Sex s3 = new Sex();
#cold_bold		s3.setCode("O");
#cold_bold		s3.setName("其他");
#cold_bold		list.add(s3);
#cold_bold		
#cold_bold		return list;
#cold_bold	}

}

然后在ToUpdateCustomerAction中模拟查询所有的性别,代码如下:

package action;

import java.util.List;

import dao.CustomerDAO;
import entity.Customer;
import entity.Sex;

public class ToUpdateCustomerAction {

	// output
	private Customer customer; // 客户
#cold_bold	private List<Sex> sexes; // 性别

	public String execute() {
		CustomerDAO dao = new CustomerDAO();
		// 模拟查询客户
		customer = dao.findById();
#cold_bold		// 模拟查询全部的性别
#cold_bold		sexes = dao.findAllSex();
		return "success";
	}

	public Customer getCustomer() {
		return customer;
	}

	public void setCustomer(Customer customer) {
		this.customer = customer;
	}

#cold_bold	public List<Sex> getSexes() {
#cold_bold		return sexes;
#cold_bold	}
#cold_bold
#cold_bold	public void setSexes(List<Sex> sexes) {
#cold_bold		this.sexes = sexes;
#cold_bold	}

}

最后,在update_customer.jsp上,使用动态的单选框标签,根据Action中返回的所有性别生成性别选项,并根据客户信息设置默认勾选,代码如下:

<%@page pageEncoding="utf-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<html>
<head></head>
<body>
	<h1>模拟修改客户</h1>
	
	<%-- 1.表单标签 --%>
	<s:form action="#" method="post">
		<!--此处略去其他标签...-->
#cold_bold		<!-- 
#cold_bold			6.2单选框标签(动态)
#cold_bold			 1)根据OGNL(list属性值)的取值初始化一组radio,
#cold_bold				并根据listKey指定的实体类中的属性来生成radio的value值,
#cold_bold				根据listValue指定的实体类中的属性来生成radio的label值。
#cold_bold			 2)根据OGNL(customer.marry)取值来与生成radio的value比较,
#cold_bold				若与哪个radio的value值一致,则将其勾选。
#cold_bold		-->
		<s:radio name="customer.sex" 
			list="sexes" listKey="code" listValue="name" label="性别"/>
		
	</s:form>	
	
</body>
</html>

重新部署项目并重启tomcat,重新访问修改客户,效果如下图:

图-15

步骤二:多选框标签

多选框的用法与单选框用法类似,也分为静态初始化和动态初始化2种,区别在于对checkbox初始化方式的不同。

首先,我们通过静态初始化的方式生成一组城市的复选框,然后根据客户去过的城市来勾选这些城市。代码如下:

<%@page pageEncoding="utf-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<html>
<head></head>
<body>
	<h1>模拟修改客户</h1>
	
	<%-- 1.表单标签 --%>
	<s:form action="#" method="post">
		<!--此处略去其他标签...-->
#cold_bold		<!-- 
#cold_bold			7.1多选框标签(静态)
#cold_bold			 1)根据OGNL(list属性值)创建的Map生成一组checkbox,其中Map的key
#cold_bold				生成checkbox的value值,Map的value生成checkbox的label值。
#cold_bold			 2)根据OGNL(customer.travelCities)取值来与生成checkbox的
#cold_bold				value比较,若与哪个checkbox的value值一致,则将其勾选。
#cold_bold		-->
#cold_bold		<s:checkboxlistname="customer.travelCities"
#cold_bold			list="#{'beijing':'北京','shanghai':'上海','guangzhou':'广州','shenzhen':'深圳','chongqing':'重庆','diaoyudao':'钓鱼岛' }" label="旅游过的城市"/>
		
	</s:form>	
	
</body>
</html>

刷新浏览器,效果如下图:

图-16

接下来,我们在看看如何动态的初始化多选框的选项。先创建城市的实体类City,用于封装所有的城市数据,代码如下:

package entity;

public class City {

	private String code;
	private String name;

	public City(String code, String name) {
		super();
		this.code = code;
		this.name = name;
	}

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public String getName() {
		return name;
	}

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

}

然后在CustomerDAO中模拟查询全部的城市,代码如下:

package dao;

import java.util.ArrayList;
import java.util.List;
import entity.City;
import entity.Customer;
import entity.Sex;

/**
 * 模拟客户DAO
 */
public class CustomerDAO {

	// 此处略去其他方法...	
	
#cold_bold	/**
#cold_bold	 * 模拟查询所有的城市
#cold_bold	 */
#cold_bold	public List<City> findAllCities() {
#cold_bold		List<City> cities = new ArrayList<City>();
#cold_bold		City c1 = new City("beijing", "北京");
#cold_bold		City c2 = new City("shanghai", "上海");
#cold_bold		City c3 = new City("guangzhou", "广州");
#cold_bold		City c4 = new City("shenzhen", "深圳");
#cold_bold		City c5 = new City("chongqing", "重庆");
#cold_bold		City c6 = new City("diaoyudao", "钓鱼岛");
#cold_bold		cities.add(c1);
#cold_bold		cities.add(c2);
#cold_bold		cities.add(c3);
#cold_bold		cities.add(c4);
#cold_bold		cities.add(c5);
#cold_bold		cities.add(c6);
#cold_bold		return cities;
#cold_bold	}

}

然后在ToUpdateCustomerAction中查询出全部的城市,代码如下:

package action;

import java.util.List;

import dao.CustomerDAO;
import entity.City;
import entity.Customer;
import entity.Sex;

public class ToUpdateCustomerAction {

	// output
	private Customer customer; // 客户
	private List<Sex> sexes; // 性别
#cold_bold	private List<City> cities; // 城市

	public String execute() {
		CustomerDAO dao = new CustomerDAO();
		// 模拟查询客户
		customer = dao.findById();
		// 模拟查询全部的性别
		sexes = dao.findAllSex();
#cold_bold		// 模拟查询全部的城市
#cold_bold		cities = dao.findAllCities();
		return "success";
	}

	public Customer getCustomer() {
		return customer;
	}

	public void setCustomer(Customer customer) {
		this.customer = customer;
	}

	public List<Sex> getSexes() {
		return sexes;
	}

	public void setSexes(List<Sex> sexes) {
		this.sexes = sexes;
	}

#cold_bold	public List<City> getCities() {
#cold_bold		return cities;
#cold_bold	}
#cold_bold
#cold_bold	public void setCities(List<City> cities) {
#cold_bold		this.cities = cities;
#cold_bold	}

}

最后,在update_customer.jsp上,使用动态的多选框标签,根据Action中返回的所有城市生成城市选项,并根据客户信息设置默认勾选,代码如下:

<%@page pageEncoding="utf-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<html>
<head></head>
<body>
	<h1>模拟修改客户</h1>
	
	<%-- 1.表单标签 --%>
	<s:form action="#" method="post">
		<!--此处略去其他标签...-->
#cold_bold		<!-- 
#cold_bold			7.2多选框标签(动态)
#cold_bold			 1)根据OGNL(list属性值)的取值初始化一组checkbox,
#cold_bold				并根据listKey指定的实体类中的属性来生成checkbox的value值,
#cold_bold				根据listValue指定的实体类中的属性来生成checkbox的label值。
#cold_bold			 2)根据OGNL(customer.travelCities)取值来与生成radio的value比较,
#cold_bold				若与哪个radio的value值一致,则将其勾选。
#cold_bold		-->
#cold_bold		<s:checkboxlist name="customer.travelCities" list="cities" listKey="code" listValue="name" label="旅游过的城市"/>
		
	</s:form>	
	
</body>
</html>

重新部署项目并重启tomcat,重新访问修改客户页面,效果如下图:

图-17

步骤三:下拉选标签

下拉选标签的用法与单选框标签、多选框标签也类似,分为静态初始化和动态初始化2种方式。首先我们来使用静态的方式来初始化下拉选选项,代码如下:

<%@page pageEncoding="utf-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<html>
<head></head>
<body>
	<h1>模拟修改客户</h1>
	
	<%-- 1.表单标签 --%>
	<s:form action="#" method="post">
		<!--此处略去其他标签...-->
#cold_bold		<!-- 
#cold_bold			8.1下拉选标签(静态)
#cold_bold			 1)根据OGNL(list属性值)创建的Map生成一组option,其中Map的key
#cold_bold				生成option的value值,Map的value生成option的显示值。
#cold_bold			 2)根据OGNL(customer.home)取值来与生成option的
#cold_bold				value比较,若与哪个option的value值一致,则将其勾选。
#cold_bold		-->
#cold_bold		<s:select name="customer.home" 
#cold_bold			list="#{'beijing':'北京','shanghai':'上海','guangzhou':'广州','shenzhen':'深圳','chongqing':'重庆','diaoyudao':'钓鱼岛' }" 
#cold_bold			label="家乡" headerKey="-1" headerValue="请选择"/>
		
	</s:form>	
	
</body>
</html>

刷新浏览器,显示效果如下图:

图-18

对于动态的初始化的方式,我们还是使用全部的城市来初始化选项,代码如下:

<%@page pageEncoding="utf-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<html>
<head></head>
<body>
	<h1>模拟修改客户</h1>
	
	<%-- 1.表单标签 --%>
	<s:form action="#" method="post">
		<!--此处略去其他标签...-->
#cold_bold		<!-- 
#cold_bold			8.2下拉选标签(动态)
#cold_bold			 1)根据OGNL(list属性值)的取值初始化一组option,
#cold_bold				并根据listKey指定的实体类中的属性来生成option的value值,
#cold_bold				根据listValue指定的实体类中的属性来生成option的label值。
#cold_bold			 2)根据OGNL(customer.home)取值来与生成option的value比较,
#cold_bold				若与哪个option的value值一致,则将其勾选。
#cold_bold		-->
#cold_bold		<s:select name="customer.home" list="cities" listKey="code" listValue="name" 
#cold_bold			label="家乡" headerKey="" headerValue="请选择"/>
		
	</s:form>	
	
</body>
</html>

刷新浏览器,显示效果如下图:

图-19

5.4 完整代码

本案例的完整代码如下。

Customer完整代码:

package entity;

import java.util.List;

public class Customer {

	private String name; // 姓名
	private String password; // 密码
	private String desc; // 简介
	private boolean marry; // 是否已婚

	private String sex; // 性别
	private List<String> travelCities; // 去过的城市
	private String home; // 家乡

	public String getName() {
		return name;
	}

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

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getDesc() {
		return desc;
	}

	public void setDesc(String desc) {
		this.desc = desc;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public boolean isMarry() {
		return marry;
	}

	public void setMarry(boolean marry) {
		this.marry = marry;
	}

	public String getHome() {
		return home;
	}

	public List<String> getTravelCities() {
		return travelCities;
	}

	public void setTravelCities(List<String> travelCities) {
		this.travelCities = travelCities;
	}

	public void setHome(String home) {
		this.home = home;
	}

}

Sex完整代码:

package entity;

public class Sex {

	private String code;
	private String name;

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public String getName() {
		return name;
	}

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

}

City完整代码:

package entity;

public class City {

	private String code;
	private String name;

	public City(String code, String name) {
		super();
		this.code = code;
		this.name = name;
	}

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public String getName() {
		return name;
	}

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

}

CustomerDAO完整代码:

package dao;

import java.util.ArrayList;
import java.util.List;

import entity.City;
import entity.Customer;
import entity.Sex;

/**
 * 模拟客户DAO
 */
public class CustomerDAO {

	/**
	 * 模拟根据ID查询客户
	 */
	public Customer findById() {
		// 实例化客户实体类
		Customer c = new Customer();
		// 设置一些默认值
		c.setName("Tarena");
		c.setPassword("123");
		c.setDesc("中华人民共和国公民");
		c.setSex("F");
		c.setMarry(true);

		List<String> list = new ArrayList<String>();
		list.add("beijing");
		list.add("guangzhou");
		c.setTravelCities(list);

		c.setHome("shanghai");
		return c;
	}
	
	/**
	 * 模拟查询所有的性别,并不符合真实业务,仅仅是用于练习知识点
	 */
	public List<Sex> findAllSex() {
		List<Sex> list = new ArrayList<Sex>();
		
		Sex s1 = new Sex();
		s1.setCode("M");
		s1.setName("男");
		list.add(s1);
		
		Sex s2 = new Sex();
		s2.setCode("F");
		s2.setName("女");
		list.add(s2);
		
		Sex s3 = new Sex();
		s3.setCode("O");
		s3.setName("其他");
		list.add(s3);
		
		return list;
	}
	
	/**
	 * 模拟查询所有的城市
	 */
	public List<City> findAllCities() {
		List<City> cities = new ArrayList<City>();
		City c1 = new City("beijing", "北京");
		City c2 = new City("shanghai", "上海");
		City c3 = new City("guangzhou", "广州");
		City c4 = new City("shenzhen", "深圳");
		City c5 = new City("chongqing", "重庆");
		City c6 = new City("diaoyudao", "钓鱼岛");
		cities.add(c1);
		cities.add(c2);
		cities.add(c3);
		cities.add(c4);
		cities.add(c5);
		cities.add(c6);
		return cities;
	}

}

ToUpdateCustomerAction完整代码:

package action;

import java.util.List;

import dao.CustomerDAO;
import entity.City;
import entity.Customer;
import entity.Sex;

public class ToUpdateCustomerAction {

	// output
	private Customer customer; // 客户
	private List<Sex> sexes; // 性别
	private List<City> cities; // 城市

	public String execute() {
		CustomerDAO dao = new CustomerDAO();
		// 模拟查询客户
		customer = dao.findById();
		// 模拟查询全部的性别
		sexes = dao.findAllSex();
		// 模拟查询全部的城市
		cities = dao.findAllCities();
		return "success";
	}

	public Customer getCustomer() {
		return customer;
	}

	public void setCustomer(Customer customer) {
		this.customer = customer;
	}

	public List<Sex> getSexes() {
		return sexes;
	}

	public void setSexes(List<Sex> sexes) {
		this.sexes = sexes;
	}

	public List<City> getCities() {
		return cities;
	}

	public void setCities(List<City> cities) {
		this.cities = cities;
	}

}

struts.xml完整代码:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
    "/struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>

	<!-- 客户配置信息 -->
	<package name="customer" 
		namespace="/customer" extends="struts-default">
		<!-- 打开修改页面 -->
		<action name="toUpdateCustomer" 
			class="action.ToUpdateCustomerAction">
			<result name="success">
				/WEB-INF/customer/update_customer.jsp
			</result>
		</action>
	</package>

</struts>

update_customer.jsp完整代码:

<%@page pageEncoding="utf-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<html>
<head></head>
<body>
	<h1>模拟修改客户</h1>
	
	<%-- 1.表单标签 --%>
	<s:form action="#" method="post">
		<!-- 
			2.文本框标签 
			 1)生成文本框
			 2)根据OGNL(customer.name)取值给文本框赋值
		-->
		<s:textfield name="customer.name" label="姓名"/>
		<!-- 
			3.密码框标签 
			 1)生成密码框
			 2)根据OGNL(customer.password)取值给密码框赋值
		-->
		<s:password name="customer.password" label="密码" showPassword="true"/>
		<!-- 
			4.文本域标签 
			 1)生成文本域
			 2)根据OGNL(customer.desc)取值给文本域赋值
		-->
		<s:textarea name="customer.desc" cols="30" rows="5" label="简介"/>
		<!-- 
			5.布尔框标签 
			 1)生成一个checkbox
			 2)根据OGNL(customer.marry)取值(布尔型)来确定是否勾选
		-->
		<s:checkbox name="customer.marry" label="是否已婚" labelposition="left"/>
		<!-- 
			6.1单选框标签(静态) 
			 1)根据OGNL(list属性值)创建的Map生成一组radio,
			       其中Map的可以生成radio的value值,Map的value生成radio的label值。
			 2)根据OGNL(customer.marry)取值来与生成radio的value比较,
				若与哪个radio的value值一致,则将其勾选。
		-->
		<s:radio name="customer.sex" list="#{'M':'男','F':'女' }" label="性别"/>
		<!-- 
			6.2单选框标签(动态) 
			 1)根据OGNL(list属性值)的取值初始化一组radio,
				并根据listKey指定的实体类中的属性来生成radio的value值,
				根据listValue指定的实体类中的属性来生成radio的label值。
			 2)根据OGNL(customer.marry)取值来与生成radio的value比较,
				若与哪个radio的value值一致,则将其勾选。
		-->
		<s:radio name="customer.sex" 
			list="sexes" listKey="code" listValue="name" label="性别"/>
		<!-- 
			7.1多选框标签(静态) 
			 1)根据OGNL(list属性值)创建的Map生成一组checkbox,其中Map的key
				生成checkbox的value值,Map的value生成checkbox的label值。
			 2)根据OGNL(customer.travelCities)取值来与生成checkbox的
				value比较,若与哪个checkbox的value值一致,则将其勾选。
		-->
		<s:checkboxlist name="customer.travelCities" 
			list="#{'beijing':'北京','shanghai':'上海','guangzhou':'广州','shenzhen':'深圳','chongqing':'重庆','diaoyudao':'钓鱼岛' }" label="旅游过的城市"/>
		<!-- 
			7.2多选框标签(动态) 
			 1)根据OGNL(list属性值)的取值初始化一组checkbox,
				并根据listKey指定的实体类中的属性来生成checkbox的value值,
				根据listValue指定的实体类中的属性来生成checkbox的label值。
			 2)根据OGNL(customer.travelCities)取值来与生成radio的value比较,
				若与哪个radio的value值一致,则将其勾选。
		-->
		<s:checkboxlist name="customer.travelCities" list="cities" listKey="code" listValue="name" label="旅游过的城市"/>
		<!-- 
			8.1下拉选标签(静态) 
			 1)根据OGNL(list属性值)创建的Map生成一组option,其中Map的key
				生成option的value值,Map的value生成option的显示值。
			 2)根据OGNL(customer.home)取值来与生成option的
				value比较,若与哪个option的value值一致,则将其勾选。
		-->
		<s:select name="customer.home" 
			list="#{'beijing':'北京','shanghai':'上海','guangzhou':'广州','shenzhen':'深圳','chongqing':'重庆','diaoyudao':'钓鱼岛' }" 
			label="家乡" headerKey="-1" headerValue="请选择"/>
		<!-- 
			8.2下拉选标签(动态) 
			 1)根据OGNL(list属性值)的取值初始化一组option,
				并根据listKey指定的实体类中的属性来生成option的value值,
				根据listValue指定的实体类中的属性来生成option的label值。
			 2)根据OGNL(customer.home)取值来与生成option的value比较,
				若与哪个option的value值一致,则将其勾选。
		-->
		<s:select name="customer.home" list="cities" listKey="code" listValue="name" 
			label="家乡" headerKey="" headerValue="请选择"/>
		
	</s:form>	
	
</body>
</html>