把自己的学习过程写下来,和大家一起研究学习.开发环境是JDK5.0+eclipse3.2+myeclipse5.0.
新建项目,项目名:base。先添加struts框架。struts框架用于处理请求,web应用是基于请求驱动的模型,即客户端提交一个请求,服务器端处理请求后把结果返回到客户端。
client request server
页面page -----------do action
jsp等 |
| | ---ajax
|
|____验证,数据封装
尽管spring也能实现大多数struts的功能,甚至有些方面比struts更方便,但考虑到多模块只会用struts实现,还没找到其他的实现方法。---struts框架对多模块开发来说少不了。
在WebRoot目录下新建index.jsp文件,然后部署应用并启动web服务器(tomcat),OK。,可以访问index。这个应用涉及到多模块,暂定为两个模块,用户管理和信息模型,并且还有两外两个框架,大名鼎鼎的hibernate和spring。下面继续配置:
为了把页面存放到各自的文件夹中,我们要在WebRoot下新建两个目录:user和infoModel。统一起见,每个目录中也都新建index.jsp。
配置文件是在服务器启动的时候读入容器,因此在web.xml中增加模块描述:
< web-app xmlns ="http://java.sun.com/xml/ns/j2ee" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" version ="2.4" xsi:schemaLocation ="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" >
< servlet >
< servlet-name > action </ servlet-name >
< servlet-class > org.apache.struts.action.ActionServlet </ servlet-class >
< init-param >
< param-name > config </ param-name >
< param-value > /WEB-INF/struts-config.xml </ param-value >
</ init-param >
<init-param>
<param-name>config/userManage</param-name>
<param-value>/WEB-INF/userManage/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>config/infoModel</param-name>
<param-value>/WEB-INF/infoModel/struts-config.xml</param-value>
</init-param>
< init-param >
< param-name > debug </ param-name >
< param-value > 3 </ param-value >
</ init-param >
< init-param >
< param-name > detail </ param-name >
< param-value > 3 </ param-value >
</ init-param >
< load-on-startup > 0 </ load-on-startup >
</ servlet >
< servlet-mapping >
< servlet-name > action </ servlet-name >
< url-pattern > *.do </ url-pattern >
</ servlet-mapping >
</ web-app >
粗斜体为增加的内容。只在web.xml中增加模块还不够,根据web.xml的配置,在WEB-INF下增加两个目录,infoModel和userManage,在这两个目录中增加xml文件。将WEB-INF目录下的struts-config.xml拷贝到那两目录下就行了,但要更改资源文件,资源文件也是模块应用的一部门,当很多人并行开发的时候,各个用各自的资源文件,不会起冲突。把infoModel下的struts-config.xml中的 改成:
<! DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://struts.apache.org/dtds/struts-config_1_2.dtd" >
< struts-config >
< data-sources />
< form-beans />
< global-exceptions />
< global-forwards >
</ global-forwards >
< action-mappings >
</ action-mappings >
<message-resources parameter="com.base.struts.infomodel.ApplicationResources" />
</ struts-config >
为此,要在src下增加一个包:com.base.struts.infoModel,并把ApplicationResource拷贝过去。userManager下的配置文件也同样处理。
接下来,我们要实现子模块的功能和模块见的跳转。
首先,让主模块中的index.jsp(在WebRoot目录下)可以访问两个子模块的index.jsp。我们在infoModel模块中做些修改:
struts-config.xml:
<! DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://struts.apache.org/dtds/struts-config_1_2.dtd" >
< struts-config >
< data-sources />
< form-beans />
< global-exceptions />
< global-forwards >
</ global-forwards >
< action-mappings >
<action forward="/index.jsp" path="/index" />
</ action-mappings >
< message-resources parameter ="com.base.struts.infomodel.ApplicationResources" />
</ struts-config >
子模块中的action forward 的值不用加模块名作jsp文件的前缀,由系统自动处理。
主模块的index.jsp:
<% @ taglib uri = " http://struts.apache.org/tags-bean " prefix = " bean " %>
<% @ taglib uri = " http://struts.apache.org/tags-html " prefix = " html " %>
<% @ taglib uri = " http://struts.apache.org/tags-logic " prefix = " logic " %>
<% @ taglib uri = " http://struts.apache.org/tags-tiles " prefix = " tiles " %>
<! DOCTYPE HTML PUBLIC " -//W3C//DTD HTML 4.01 Transitional//EN " >
< html:html lang = " true " >
< head >
< html:base />
< title > index.jsp </ title >
< meta http - equiv = " pragma " content = " no-cache " >
< meta http - equiv = " cache-control " content = " no-cache " >
< meta http - equiv = " expires " content = " 0 " >
< meta http - equiv = " keywords " content = " keyword1,keyword2,keyword3 " >
< meta http - equiv = " description " content = " This is my page " >
<!--
< link rel = " stylesheet " type = " text/css " href = " styles.css " >
-->
</ head >
< body >
This a struts page. <br>
index.jsp of main model <br>
<hr>
<html:link module="/infoModel" action="/index">infoModel index</html:link>
<hr>
<html:link action="/index" module="/userManage">userManage index</html:link>
</ body >
</ html:html >
现在启动tomcat,在IE地址栏里输入:http://localhost:8080/base ,可以看到主模块的index页面,并且可以打开子模块中的页面。
接下来,我们要在infoModel中完成一个增加客户的功能。首先在WebRoot/infoModel中增加addBuyer.jsp,
<% @ taglib uri = " http://struts.apache.org/tags-bean " prefix = " bean " %>
<% @ taglib uri = " http://struts.apache.org/tags-html " prefix = " html " %>
<% @ taglib uri = " http://struts.apache.org/tags-logic " prefix = " logic " %>
<% @ taglib uri = " http://struts.apache.org/tags-tiles " prefix = " tiles " %>
<! DOCTYPE HTML PUBLIC " -//W3C//DTD HTML 4.01 Transitional//EN " >
< html:html lang = " true " >
< head >
< html:base />
< title > addBuyer.jsp </ title >
< meta http - equiv = " pragma " content = " no-cache " >
< meta http - equiv = " cache-control " content = " no-cache " >
< meta http - equiv = " expires " content = " 0 " >
< meta http - equiv = " keywords " content = " keyword1,keyword2,keyword3 " >
< meta http - equiv = " description " content = " This is my page " >
<!--
< link rel = " stylesheet " type = " text/css " href = " styles.css " >
-->
</ head >
< body >
< html:form action = "" method = " post " focus = " buyerId " >
< table border = " 0 " >
< tr >
< td > 客户号: </ td >
< td >< html:text property = " buyerId " /></ td >
</ tr >
< tr >
< td > 客户名称: </ td >
< td >< html:password property = " buyerName " /></ td >
</ tr >
< tr >
< td > 客户分类: </ td >
< td >< html:select property = " buyerType " >
< html:option value = " A " />
< html:option value = " B " />
< html:option value = " C " />
< html:option value = " D " />
</ html:select >
</ td >
</ tr >
< tr >
< td > 地址: </ td >
< td >< html:password property = " address " /></ td >
</ tr >
< tr >
< td > 联系人: </ td >
< td >< html:text property = " linkman " /></ td >
</ tr >
< tr >
< td > 联系电话: </ td >
< td >< html:password property = " tel " /></ td >
</ tr >
< tr >
< td colspan = " 2 " align = " center " >< html:submit /></ td >
</ tr >
</ table >
</ html:form >
</ body >
</ html:html >
前面提到,web程序是请求驱动的,客户端(浏览器)提交请求,服务端响应请求并把结果返回客户端。服务端在做处理前,先要对提交的数据进行封装,struts提供了简易方便的封装方法,formbean。这里采用动态带验证的ActionForm,DynaValidatorActionForm。打开infoModel模块的配置文件struts-config.xml,点右键-new-form,name填上addBuyerForm,类型选DynaValidatorActionForm,把addBuyer.jsp中的属性项添加到下面的属性框中,注意名称要一致!修改后的struts-config.xml如下:
<! DOCTYPE struts - config PUBLIC " -//Apache Software Foundation//DTD Struts Configuration 1.2//EN " " http://struts.apache.org/dtds/struts-config_1_2.dtd " >
< struts - config >
< data - sources />
< form - beans >
<form-bean name="addBuyerForm" type="org.apache.struts.validator.DynaValidatorActionForm">
<form-property name="linkman" type="java.lang.String" />
<form-property name="buyerName" type="java.lang.String" />
<form-property name="buyerId" type="java.lang.String" />
<form-property name="address" type="java.lang.String" />
<form-property name="buyerType" type="java.lang.String" />
<form-property name="tel" type="java.lang.String" />
</form-bean>
</ form - beans >
< global - exceptions />
< global - forwards >
</ global - forwards >
< action - mappings >
< action forward = " /index.jsp " path = " /index " />
</ action - mappings >
< message - resources parameter = " com.base.struts.infoModel.ApplicationResources " />
</ struts - config >
数据的封装完成了,接下来是如何完成处理请求的功能了,怎么增加客户?一步一步慢慢来。java中所有的功能都是通过类来实现的。我们也要定义类。先回到addBuyer.jsp,刚才还没有指定action,现在要指定action。
在index.jsp中再增加一个链接,和主模块的index差不多,只是现在都在infoModel中。index.jsp如下:
<% @ taglib uri = " http://struts.apache.org/tags-bean " prefix = " bean " %>
<% @ taglib uri = " http://struts.apache.org/tags-html " prefix = " html " %>
<% @ taglib uri = " http://struts.apache.org/tags-logic " prefix = " logic " %>
<% @ taglib uri = " http://struts.apache.org/tags-tiles " prefix = " tiles " %>
<! DOCTYPE HTML PUBLIC " -//W3C//DTD HTML 4.01 Transitional//EN " >
< html:html lang = " true " >
< head >
< html:base />
< title > index.jsp </ title >
< meta http - equiv = " pragma " content = " no-cache " >
< meta http - equiv = " cache-control " content = " no-cache " >
< meta http - equiv = " expires " content = " 0 " >
< meta http - equiv = " keywords " content = " keyword1,keyword2,keyword3 " >
< meta http - equiv = " description " content = " This is my page " >
<!--
< link rel = " stylesheet " type = " text/css " href = " styles.css " >
-->
</ head >
< body >
This a struts page. < br >
index.jsp of infoModel model. < br >
<html:link action="/AddBuyerPage">增加客户</html:link>
</ body >
</ html:html >
如果不从index.jsp跳转到addBuyer.jsp,直接访问addBuyer.jsp,不成功.现在还没弄清楚什么原因.
完善在struts-config.xml中的配置:
< action forward = " /index.jsp " path = " /index " />
< action
attribute="addBuyerForm"
input ="/infoModel/addBuyer.jsp"
name ="addBuyerForm"
path ="/AddBuyer"
scope ="request"
type ="com.base.struts.infomodel.AddBuyerAction" />
<action forward="/addBuyer.jsp" path="/AddBuyerPage" />
</ action - mappings >
OK,运行tomcat服务器,打开页面,正常。但是提交的时候抛出异常,Resources cannot be null。因为我们使用的validator框架,但还没有导入validator的资源。我们先修改/WEB-INF/infoModel的struts-config.xml:在message-resources 标签后增加plug-in标签:
< set-property property ="pathnames"
value ="/WEB-INF/infoModel/validator-rules.xml,
/WEB-INF/infoModel/validation.xml" />
</ plug-in >
把/WEB-INF/validator-rules.xml 拷贝到/WEB-INF/infoModel/下,并在该目录下新建validation.xml,内容如下:
<! DOCTYPE form-validation PUBLIC
"-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN"
"http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd" >
< form-validation >
<!--
This is a minimal Validator form file with a couple of examples.
-->
< global >
<!-- An example global constant
<constant>
<constant-name>postalCode</constant-name>
<constant-value>^d{5}d*$</constant-value>
</constant>
end example -->
</ global >
< formset >
< form name ="addBuyerForm" >
< field property ="buyerId"
depends ="required" >
< arg0 key ="prompt.buyerId" />
</ field >
< field property ="buyerName"
depends ="required" >
< arg0 key ="prompt.buyerName" />
</ field >
</ form >
</ formset >
</ form-validation >
还要在infoModel的资源包ApplicationResources.properties中添加内容:
# Project P/base
# Struts Validator Error Messages
errors.required={0} is required.
errors.minlength={0} can not be less than {1} characters.
errors.maxlength={0} can not be greater than {1} characters.
errors.invalid={0} is invalid.
errors.byte={0} must be a byte.
errors.short={0} must be a short.
errors.integer={0} must be an integer.
errors.long={0} must be a long.
errors.float={0} must be a float.
errors.double={0} must be a double.
errors.date={0} is not a date.
errors.range={0} is not in the range {1} through {2}.
errors.creditcard={0} is an invalid credit card number.
errors.email={0} is an invalid e-mail address.
prompt.buyerId=buyerId
prompt.buyerName=buyerName
在addBuyer.jsp中增加javascript验证,
<% @ taglib uri = " http://struts.apache.org/tags-bean " prefix = " bean " %>
<% @ taglib uri = " http://struts.apache.org/tags-html " prefix = " html " %>
<% @ taglib uri = " http://struts.apache.org/tags-logic " prefix = " logic " %>
<% @ taglib uri = " http://struts.apache.org/tags-tiles " prefix = " tiles " %>
<! DOCTYPE HTML PUBLIC " -//W3C//DTD HTML 4.01 Transitional//EN " >
< html:html lang = " true " >
< head >
< html:base />
< title > addBuyer.jsp </ title >
< meta http - equiv = " pragma " content = " no-cache " >
< meta http - equiv = " cache-control " content = " no-cache " >
< meta http - equiv = " expires " content = " 0 " >
< meta http - equiv = " keywords " content = " keyword1,keyword2,keyword3 " >
< meta http - equiv = " description " content = " This is my page " >
<!--
< link rel = " stylesheet " type = " text/css " href = " styles.css " >
-->
</ head >
< body >
< html:errors />
< html:form action = " /AddBuyer.do " method = " post " focus = " buyerId " onsubmit ="return validateAddBuyerForm(this);" >
< table border = " 0 " >
< tr >
< td > 客户号: </ td >
< td >< html:text property = " buyerId " /></ td >
</ tr >
< tr >
< td > 客户名称: </ td >
< td >< html:text property = " buyerName " /></ td >
</ tr >
< tr >
< td > 客户分类: </ td >
< td >< html:select property = " buyerType " >
< html:option value = " A " />
< html:option value = " B " />
< html:option value = " C " />
< html:option value = " D " />
</ html:select >
</ td >
</ tr >
< tr >
< td > 地址: </ td >
< td >< html:text property = " address " /></ td >
</ tr >
< tr >
< td > 联系人: </ td >
< td >< html:text property = " linkman " /></ td >
</ tr >
< tr >
< td > 联系电话: </ td >
< td >< html:text property = " tel " /></ td >
</ tr >
< tr >
< td colspan = " 2 " align = " center " >< html:submit /></ td >
</ tr >
</ table >
</ html:form >
<html:javascript formName="AddBuyerForm" cdata="false" />
</ body >
</ html:html >
不过,会发现js的验证没有执行,为什么?研究了两三天,发现把loginForm改成LoginForm,就行了。不知道是不是框架的bug?
接下来要改一下主页面,加入框架,左边是导航菜单.在WebRoot下增加两个文件,menu.jsp和mainFrame.jsp.
menu.jsp(借用其他高手的代码)
< %@ taglib uri ="http://struts.apache.org/tags-bean" prefix ="bean" % >
< %@ taglib uri ="http://struts.apache.org/tags-html" prefix ="html" % >
< %@ taglib uri ="http://struts.apache.org/tags-logic" prefix ="logic" % >
< %@ taglib uri ="http://struts.apache.org/tags-tiles" prefix ="tiles" % >
<! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" >
< html xmlns ="http://www.w3.org/1999/xhtml" >
< head >
<!-- <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> -->
< title > Div+CSS+JS树型菜单,可刷新 </ title >
< meta name ="description" content ="http://www.livepo.com" >
< style type ="text/css" >
<!--
*{margin:0;padding:0;border:0;}
body {
font-family: arial, 宋体, serif;
font-size:12px;
}
#nav {
width:180px;
line-height: 24px;
list-style-type: none;
text-align:left;
/*定义整个ul菜单的行高和背景色*/
}
/*==================一级目录===================*/
#nav a {
width: 160px;
display: block;
padding-left:20px;
/*Width(一定要),否则下面的Li会变形*/
}
#nav li {
background:#CCC; /*一级目录的背景色*/
border-bottom:#FFF 1px solid; /*下面的一条白边*/
float:left;
/*float:left,本不应该设置,但由于在Firefox不能正常显示
继承Nav的width,限制宽度,li自动向下延伸*/
}
#nav li a:hover{
background:#CC0000; /*一级目录onMouseOver显示的背景色*/
}
#nav a:link {
color:#666; text-decoration:none;
}
#nav a:visited {
color:#666;text-decoration:none;
}
#nav a:hover {
color:#FFF;text-decoration:none;font-weight:bold;
}
/*==================二级目录===================*/
#nav li ul {
list-style:none;
text-align:left;
}
#nav li ul li{
background: #EBEBEB; /*二级目录的背景色*/
}
#nav li ul a{
padding-left:20px;
width:160px;
/* padding-left二级目录中文字向右移动,但Width必须重新设置=(总宽度-padding-left)*/
}
/*下面是二级目录的链接样式*/
#nav li ul a:link {
color:#666; text-decoration:none;
}
#nav li ul a:visited {
color:#666;text-decoration:none;
}
#nav li ul a:hover {
color:#F3F3F3;
text-decoration:none;
font-weight:normal;
background:#CC0000;
/* 二级onmouseover的字体颜色、背景色*/
}
/*==============================*/
#nav li:hover ul {
left: auto;
}
#nav li.sfhover ul {
left: auto;
}
#content {
clear: left;
}
#nav ul.collapsed {
display: none;
}
-->
#PARENT{
width:300px;
padding-left:20px;
}
</ style >
</ head >
< body >
< div id ="PARENT" >
< ul id ="nav" >
< li >< a href ="#Menu=ChildMenu1" onclick ="DoMenu('ChildMenu1')" > 信息模型 </ a >
< ul id ="ChildMenu1" class ="collapsed" >
< li >< a href ="http://www.sohu.com" target ="mainFrame" > 搜狐 </ a ></ li >
< html:link module ="/infoModel" action ="/index" target ="mainFrame" > infoModel index </ html:link >
< html:link action ="/index" module ="/userManage" target ="mainFrame" > userManage index </ html:link >
</ ul >
</ li >
</ ul >
</ div >
< div id ="PARENT" >
< ul id ="nav" >
< li >< a href ="#Menu=ChildMenu1" onclick ="DoMenu('ChildMenu2')" > 信息模型 </ a >
< ul id ="ChildMenu2" class ="collapsed" >
< li >< a href ="http://www.sohu.com" target ="mainFrame" > 搜狐 </ a ></ li >
< html:link module ="/infoModel" action ="/index" target ="mainFrame" > infoModel index </ html:link >
< html:link action ="/index" module ="/userManage" target ="mainFrame" > userManage index </ html:link >
</ ul >
</ li >
</ ul >
</ div >
</ body >
</ html >
< script type =text/javascript><!--
var LastLeftID = "" ;
function menuFix() {
var obj = document.getElementById("nav").getElementsByTagName("li");
for (var i =0; i<obj.length; i++) {
obj[i].onmouseover =function() {
this.className+ =(this.className.length>0? " ": "") + "sfhover";
}
obj[i].onMouseDown =function() {
this.className+ =(this.className.length>0? " ": "") + "sfhover";
}
obj[i].onMouseUp =function() {
this.className+ =(this.className.length>0? " ": "") + "sfhover";
}
obj[i].onmouseout =function() {
this.className =this.className.replace(new RegExp("( ?|^)sfhover/b"), "");
}
}
}
function DoMenu(emid)
{
var obj = document.getElementById(emid);
obj.className = (obj.className.toLowerCase() == "expanded"?"collapsed":"expanded");
if((LastLeftID! ="" )&&(emid! =LastLeftID)) //关闭上一个Menu
{
document.getElementById(LastLeftID).className = "collapsed" ;
}
LastLeftID = emid;
}
function GetMenuID()
{
var MenuID ="" ;
var _paramStr = new String(window.location.href);
var _sharpPos = _paramStr.indexOf("#");
if (_sharpPos > = 0 && _sharpPos < _paramStr .length - 1)
{
_paramStr = _paramStr.substring(_sharpPos + 1, _paramStr.length);
}
else
{
_paramStr = "" ;
}
if (_paramStr.length > 0)
{
var _paramArr = _paramStr.split("&");
if (_paramArr.length>0)
{
var _paramKeyVal = _paramArr[0].split("=");
if (_paramKeyVal.length>0)
{
MenuID = _paramKeyVal[1];
}
}
/*
if (_paramArr.length>0)
{
var _arr = new Array(_paramArr.length);
}
//取所有#后面的,菜单只需用到Menu
//for (var i = 0; i < _paramArr .length; i++)
{
var _paramKeyVal = _paramArr[i].split('=');
if (_paramKeyVal.length > 0)
{
_arr[_paramKeyVal[0]] = _paramKeyVal[1];
}
}
*/
}
if(MenuID!="")
{
DoMenu(MenuID)
}
}
GetMenuID(); //*这两个function的顺序要注意一下,不然在Firefox里GetMenuID()不起效果
menuFix();
--> </ script >
mainFrame.jsp
<% @ taglib uri = " http://struts.apache.org/tags-bean " prefix = " bean " %>
<% @ taglib uri = " http://struts.apache.org/tags-html " prefix = " html " %>
<% @ taglib uri = " http://struts.apache.org/tags-logic " prefix = " logic " %>
<% @ taglib uri = " http://struts.apache.org/tags-tiles " prefix = " tiles " %>
< html >
< head >
< meta http - equiv = " Content-Type " content = " text/html; charset=utf-8 " >
< title > mainframe </ title >
</ head >
< body >
</ body >
</ html >
再修改/WebRoot/index.jsp
< %@ taglib uri ="http://struts.apache.org/tags-bean" prefix ="bean" % >
< %@ taglib uri ="http://struts.apache.org/tags-html" prefix ="html" % >
< %@ taglib uri ="http://struts.apache.org/tags-logic" prefix ="logic" % >
< %@ taglib uri ="http://struts.apache.org/tags-tiles" prefix ="tiles" % >
<! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" >
< html >
< head >
< meta http-equiv ="Content-Type" content ="text/html; charset=gb2312" >
< title > index </ title >
</ head >
< frameset rows ="*" cols ="208,*" framespacing ="0" frameborder ="NO" border ="0" >
< frame src ="menu.jsp" name ="leftFrame" >
< frame src ="mainFrame.jsp" name ="mainFrame" >
</ frameset >
< noframes >< body >
</ body ></ noframes >
</ html >
然后再启动tomcat,打开页面,OK.
然后再添加spring和hibernate框架,按向导.hibernate3.0,spring 1.2.修改web.xml,在"/web-app"前添加
< servlet-name > SpringContextServlet </ servlet-name >
< servlet-class > org.springframework.web.context.ContextLoaderServlet </ servlet-class >
< load-on-startup > 1 </ load-on-startup >
</ servlet >
spring框架中需要增加的包是:aop,orm/dao/hibernate3,core,web.