﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-Denis's Java Library</title><link>http://www.blogjava.net/DenisLing/</link><description>The only documentation is the code itself</description><language>zh-cn</language><lastBuildDate>Thu, 30 Apr 2026 06:21:35 GMT</lastBuildDate><pubDate>Thu, 30 Apr 2026 06:21:35 GMT</pubDate><ttl>60</ttl><item><title>Spring中的DAO和Service</title><link>http://www.blogjava.net/DenisLing/archive/2006/02/05/daoAndServiceInSpring.html</link><dc:creator>DenisLing</dc:creator><author>DenisLing</author><pubDate>Sun, 05 Feb 2006 09:17:00 GMT</pubDate><guid>http://www.blogjava.net/DenisLing/archive/2006/02/05/daoAndServiceInSpring.html</guid><wfw:comment>http://www.blogjava.net/DenisLing/comments/29620.html</wfw:comment><comments>http://www.blogjava.net/DenisLing/archive/2006/02/05/daoAndServiceInSpring.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/DenisLing/comments/commentRss/29620.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/DenisLing/services/trackbacks/29620.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 我们开发程序的目的是为了完成业务功能, 理想的情况下程序中的每一条语句都应该是与业务直接相关的, 例如程序中不应该出现连接数据库, 读取某个字段等纯技术性的操作, 而应该是得到用户A的基本信息等具有业务含义的操作. dao(data access object)层存在的意。。。。。&nbsp;&nbsp;<a href='http://www.blogjava.net/DenisLing/archive/2006/02/05/daoAndServiceInSpring.html'>阅读全文</a><img src ="http://www.blogjava.net/DenisLing/aggbug/29620.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/DenisLing/" target="_blank">DenisLing</a> 2006-02-05 17:17 <a href="http://www.blogjava.net/DenisLing/archive/2006/02/05/daoAndServiceInSpring.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>数据库设计的范式大纲及一个小的实例说明</title><link>http://www.blogjava.net/DenisLing/archive/2005/12/20/24725.html</link><dc:creator>DenisLing</dc:creator><author>DenisLing</author><pubDate>Tue, 20 Dec 2005 02:54:00 GMT</pubDate><guid>http://www.blogjava.net/DenisLing/archive/2005/12/20/24725.html</guid><wfw:comment>http://www.blogjava.net/DenisLing/comments/24725.html</wfw:comment><comments>http://www.blogjava.net/DenisLing/archive/2005/12/20/24725.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/DenisLing/comments/commentRss/24725.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/DenisLing/services/trackbacks/24725.html</trackback:ping><description><![CDATA[
<p class="MsoNormal" style="margin-bottom: 12pt;"><b><span style="font-size: 14pt; font-family: 宋体;" lang="EN-US"><o:p>&nbsp;</o:p></span></b></p>

<p class="MsoNormal" style="text-align: center;" align="center"><b><span style="font-size: 26pt; font-family: 黑体; color: red;">数据库设计的范式大纲 </span></b><span style="font-size: 26pt; font-family: 黑体;" lang="EN-US"><o:p></o:p></span></p>

<p class="MsoNormal" style=""><span style="font-size: 14pt; font-family: 宋体;">第一范式<span lang="EN-US">:<o:p></o:p></span></span></p>

<p class="MsoNormal" style="text-indent: 0.5in;"><span style="font-size: 14pt; font-family: 宋体;">对于表中的每一行，必须且仅仅有唯一的行值<span lang="EN-US">.</span>在一行中的每一列仅有唯一的值并且具有原子性<span lang="EN-US">.<o:p></o:p></span></span></p>

<p class="MsoNormal" style=""><span style="font-size: 14pt; font-family: 宋体;">第二范式<span lang="EN-US">:<o:p></o:p></span></span></p>

<p class="MsoNormal" style="text-indent: 0.5in;"><span style="font-size: 14pt; font-family: 宋体;">第二范式要求非主键列是主键的子集，非主键列活动必须完全依赖整个主键。主键必须有唯一性的元素<span lang="EN-US">,</span>一个主键可以由一个或更多的组成唯一值的列组成。一旦创建，主键无法改变，外键关联一个表的主键。主外键关联意味着一对多的关系<span lang="EN-US">.<o:p></o:p></span></span></p>

<p class="MsoNormal" style=""><span style="font-size: 14pt; font-family: 宋体;">第三范式<span lang="EN-US">:<o:p></o:p></span></span></p>

<p class="MsoNormal" style="text-indent: 0.5in;"><span style="font-size: 14pt; font-family: 宋体;">第三范式要求非主键列互不依赖<span lang="EN-US">.<o:p></o:p></span></span></p>

<p class="MsoNormal" style=""><span style="font-size: 14pt; font-family: 宋体;">第四范式<span lang="EN-US">:<o:p></o:p></span></span></p>

<p class="MsoNormal" style="text-indent: 0.5in;"><span style="font-size: 14pt; font-family: 宋体;">第四范式禁止主键列和非主键列一对多关系不受约束<span lang="EN-US"><o:p></o:p></span></span></p>

<p class="MsoNormal" style=""><span style="font-size: 14pt; font-family: 宋体;">第五范式<span lang="EN-US">:<o:p></o:p></span></span></p>

<p class="MsoNormal" style="text-indent: 0.5in;"><span style="font-size: 14pt; font-family: 宋体;">第五范式将表分割成尽可能小的块，为了排除在表中所有的冗余<span lang="EN-US">.<o:p></o:p></span></span></p>

<p class="MsoNormal" style="margin-bottom: 12pt;"><b><span style="font-family: 宋体;" lang="EN-US"><o:p>&nbsp;</o:p></span></b></p>









<p class="MsoNormal" style="margin-bottom: 12pt;"><b><span style="font-family: 宋体;" lang="EN-US"><font color="#ff0000">下面先讨论前<span lang="EN-US">3</span>个范式：</font><o:p></o:p></span></b><span lang="EN-US"><o:p><br></o:p></span></p>



<p class="MsoNormal" style="margin-bottom: 12pt;"><b><span style="font-family: 宋体;" lang="EN-US"><o:p>&nbsp;</o:p></span></b></p>

<p class="MsoNormal" style="margin-bottom: 12pt;"><b><span style="font-family: 宋体;">引言</span></b><span style="font-family: 宋体;" lang="EN-US"><br>
<br>
</span><span style="font-family: 宋体;">　　数据库的设计范式是数据库设计所需要满足的规范，满足这些规范的数据库是简洁的、结构明晰的，同时，不会发生插入
（<span lang="EN-US">insert</span>）、删除（<span lang="EN-US">delete</span>）和更新（<span lang="EN-US">update</span>）操作异常。反之则是乱七八糟，不仅给数据库的编程人员制造麻烦，而且面目可憎，可能存储了 大量不需要的冗余信息。<span lang="EN-US"><br>
<br>
</span>　　设计范式是不是很难懂呢？非也，大学教材上给我们一堆数学公式我们当然看不懂，也记不住。所以我们很多人就根本不按照范式来设计数据库。<span lang="EN-US"><br>
<br>
</span>　　实质上，设计范式用很形象、很简洁的话语就能说清楚，道明白。本文将对范式进行通俗地说明，并以笔者曾经设计的一个简单论坛的数据库为例来讲解怎样将这些范式应用于实际工程。<span lang="EN-US"><br>
<br>
</span>　　<b>范式说明</b><span lang="EN-US"><br>
<br>
</span>　　第一范式（<span lang="EN-US">1NF</span>）：数据库表中的字段都是单一属性的，不可再分。这个单一属性由基本类型构成，包括整型、实数、字符型、逻辑型、日期型等。<span lang="EN-US"><br>
<br>
</span>　　例如，如下的数据库表是符合第一范式的：<span lang="EN-US"><o:p></o:p></span></span></p>

<div align="center">

<table class="MsoNormalTable" style="width: 90%;" border="1" cellpadding="0" cellspacing="0" width="90%">
 <tbody><tr style="">
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">字段<span lang="EN-US">1 <o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">字段<span lang="EN-US">2 <o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">字段<span lang="EN-US">3 <o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">字段<span lang="EN-US">4<o:p></o:p></span></span></p>
  </td>
 </tr>
 <tr style="">
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;" lang="EN-US">&nbsp;<o:p></o:p></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;" lang="EN-US">&nbsp;<o:p></o:p></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;" lang="EN-US">&nbsp;<o:p></o:p></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;" lang="EN-US">&nbsp;<o:p></o:p></span></p>
  </td>
 </tr>
</tbody></table>

</div>

<p class="MsoNormal" style="margin-bottom: 12pt;"><span style="font-family: 宋体;" lang="EN-US"><br>
</span><span style="font-family: 宋体;">　　而这样的数据库表是不符合第一范式的：<span lang="EN-US"><o:p></o:p></span></span></p>

<div align="center">

<table class="MsoNormalTable" style="width: 90%;" border="1" cellpadding="0" cellspacing="0" width="90%">
 <tbody><tr style="">
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">字段<span lang="EN-US">1 <o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">字段<span lang="EN-US">2 <o:p></o:p></span></span></p>
  </td>
  <td colspan="2" style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">字段<span lang="EN-US">3 <o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">字段<span lang="EN-US">4<o:p></o:p></span></span></p>
  </td>
 </tr>
 <tr style="">
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;" lang="EN-US">&nbsp;<o:p></o:p></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;" lang="EN-US">&nbsp;<o:p></o:p></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">字段<span lang="EN-US">3.1<o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">字段<span lang="EN-US">3.2 <o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;" lang="EN-US">&nbsp;<o:p></o:p></span></p>
  </td>
 </tr>
 <!--[if !supportMisalignedColumns]-->
 <tr height="0">
  <td style="border: medium none ;" width="119"><br></td>
  <td style="border: medium none ;" width="119"><br></td>
  <td style="border: medium none ;" width="157"><br></td>
  <td style="border: medium none ;" width="157"><br></td>
  <td style="border: medium none ;" width="119"><br></td>
 </tr>
 <!--[endif]-->
</tbody></table>

</div>

<p class="MsoNormal"><span style="font-family: 宋体;" lang="EN-US"><br>
</span><span style="font-family: 宋体;">　　很显然，在当前的任何关系数据库管理系统（<span lang="EN-US">DBMS</span>）中，傻瓜也不可能做出不符合第一范式的数据库，因为这些<span lang="EN-US">DBMS</span>不允许你把数据库表的一列再分成二列或多列。因此，你想在现有的<span lang="EN-US">DBMS</span>中设计出不符合第一范式的数据库都是不可能的。<span lang="EN-US"><br>
<br>
</span>　　第二范式（<span lang="EN-US">2NF</span>）：数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖（部分函数依赖指的是存在组合关键字中的某些字段决定非关键字段的情况），也即所有非关键字段都完全依赖于任意一组候选关键字。<span lang="EN-US"><br>
<br>
</span>　　假定选课关系表为<span lang="EN-US">SelectCourse(</span>学号<span lang="EN-US">, </span>姓名<span lang="EN-US">, </span>年龄<span lang="EN-US">, </span>课程名称<span lang="EN-US">, </span>成绩<span lang="EN-US">, </span>学分<span lang="EN-US">)</span>，关键字为组合关键字<span lang="EN-US">(</span>学号<span lang="EN-US">, </span>课程名称<span lang="EN-US">)</span>，因为存在如下决定关系：<span lang="EN-US"><br>
<br>
</span>　　<span lang="EN-US">(</span>学号<span lang="EN-US">, </span>课程名称<span lang="EN-US">) → (</span>姓名<span lang="EN-US">, </span>年龄<span lang="EN-US">, </span>成绩<span lang="EN-US">, </span>学分<span lang="EN-US">)<br>
<br>
</span>　　这个数据库表不满足第二范式，因为存在如下决定关系：<span lang="EN-US"><br>
<br>
</span>　　<span lang="EN-US">(</span>课程名称<span lang="EN-US">) → (</span>学分<span lang="EN-US">)<br>
<br>
</span>　　<span lang="EN-US">(</span>学号<span lang="EN-US">) → (</span>姓名<span lang="EN-US">, </span>年龄<span lang="EN-US">)<br>
<br>
</span>　　即存在组合关键字中的字段决定非关键字的情况。<span lang="EN-US"><br>
<br>
</span>　　由于不符合<span lang="EN-US">2NF</span>，这个选课关系表会存在如下问题：<span lang="EN-US"><br>
<br>
</span>　　<span lang="EN-US">(1) </span>数据冗余：<span lang="EN-US"><br>
<br>
</span>　　同一门课程由<span lang="EN-US">n</span>个学生选修，<span lang="EN-US">"</span>学分<span lang="EN-US">"</span>就重复<span lang="EN-US">n-1</span>次；同一个学生选修了<span lang="EN-US">m</span>门课程，姓名和年龄就重复了<span lang="EN-US">m-1</span>次。<span lang="EN-US"><br>
<br>
</span>　　<span lang="EN-US">(2) </span>更新异常：<span lang="EN-US"><br>
<br>
</span>　　若调整了某门课程的学分，数据表中所有行的<span lang="EN-US">"</span>学分<span lang="EN-US">"</span>值都要更新，否则会出现同一门课程学分不同的情况。<span lang="EN-US"><br>
<br>
</span>　　<span lang="EN-US">(3) </span>插入异常：<span lang="EN-US"><br>
<br>
</span>　　假设要开设一门新的课程，暂时还没有人选修。这样，由于还没有<span lang="EN-US">"</span>学号<span lang="EN-US">"</span>关键字，课程名称和学分也无法记录入数据库。<span lang="EN-US"><br>
<br>
</span>　　<span lang="EN-US">(4) </span>删除异常：<span lang="EN-US"><br>
<br>
</span>　　假设一批学生已经完成课程的选修，这些选修记录就应该从数据库表中删除。但是，与此同时，课程名称和学分信息也被删除了。很显然，这也会导致插入异常。<span lang="EN-US"> <br>
<br>
</span>　　把选课关系表<span lang="EN-US">SelectCourse</span>改为如下三个表：<span lang="EN-US"><br>
<br>
</span>　　学生：<span lang="EN-US">Student(</span>学号<span lang="EN-US">, </span>姓名<span lang="EN-US">, </span>年龄<span lang="EN-US">)</span>；<span lang="EN-US"><br>
<br>
</span>　　课程：<span lang="EN-US">Course(</span>课程名称<span lang="EN-US">, </span>学分<span lang="EN-US">)</span>；<span lang="EN-US"><br>
<br>
</span>　　选课关系：<span lang="EN-US">SelectCourse(</span>学号<span lang="EN-US">, </span>课程名称<span lang="EN-US">, </span>成绩<span lang="EN-US">)</span>。<span lang="EN-US"><br>
<br>
</span>　　这样的数据库表是符合第二范式的，消除了数据冗余、更新异常、插入异常和删除异常。<span lang="EN-US"><br>
<br>
</span>　　另外，所有单关键字的数据库表都符合第二范式，因为不可能存在组合关键字。<span lang="EN-US"><br>
<br>
</span>　 　第三范式（<span lang="EN-US">3NF</span>）：在第二范式的基础上，数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖则符合第三范式。所谓传递函数依赖，指的是如
果存在<span lang="EN-US">"A → B → C"</span>的决定关系，则<span lang="EN-US">C</span>传递函数依赖于<span lang="EN-US">A</span>。因此，满足第三范式的数据库表应该不存在如下依赖关系：<span lang="EN-US"><br>
<br>
</span>　　关键字段<span lang="EN-US"> → </span>非关键字段<span lang="EN-US">x → </span>非关键字段<span lang="EN-US">y<br>
<br>
</span>　　假定学生关系表为<span lang="EN-US">Student(</span>学号<span lang="EN-US">, </span>姓名<span lang="EN-US">, </span>年龄<span lang="EN-US">, </span>所在学院<span lang="EN-US">, </span>学院地点<span lang="EN-US">, </span>学院电话<span lang="EN-US">)</span>，关键字为单一关键字<span lang="EN-US">"</span>学号<span lang="EN-US">"</span>，因为存在如下决定关系：<span lang="EN-US"><br>
<br>
</span>　　<span lang="EN-US">(</span>学号<span lang="EN-US">) → (</span>姓名<span lang="EN-US">, </span>年龄<span lang="EN-US">, </span>所在学院<span lang="EN-US">, </span>学院地点<span lang="EN-US">, </span>学院电话<span lang="EN-US">)<br>
<br>
</span>　　这个数据库是符合<span lang="EN-US">2NF</span>的，但是不符合<span lang="EN-US">3NF</span>，因为存在如下决定关系：<span lang="EN-US"><br>
<br>
</span>　　<span lang="EN-US">(</span>学号<span lang="EN-US">) → (</span>所在学院<span lang="EN-US">) → (</span>学院地点<span lang="EN-US">, </span>学院电话<span lang="EN-US">)<br>
<br>
</span>　　即存在非关键字段<span lang="EN-US">"</span>学院地点<span lang="EN-US">"</span>、<span lang="EN-US">"</span>学院电话<span lang="EN-US">"</span>对关键字段<span lang="EN-US">"</span>学号<span lang="EN-US">"</span>的传递函数依赖。<span lang="EN-US"><br>
<br>
</span>　　它也会存在数据冗余、更新异常、插入异常和删除异常的情况，读者可自行分析得知。<span lang="EN-US"><br>
<br>
</span>　　把学生关系表分为如下两个表：<span lang="EN-US"><br>
<br>
</span>　　学生：<span lang="EN-US">(</span>学号<span lang="EN-US">, </span>姓名<span lang="EN-US">, </span>年龄<span lang="EN-US">, </span>所在学院<span lang="EN-US">)</span>；<span lang="EN-US"><br>
<br>
</span>　　学院：<span lang="EN-US">(</span>学院<span lang="EN-US">, </span>地点<span lang="EN-US">, </span>电话<span lang="EN-US">)</span>。<span lang="EN-US"><br>
<br>
</span>　　这样的数据库表是符合第三范式的，消除了数据冗余、更新异常、插入异常和删除异常。<span lang="EN-US"><br>
<br>
</span>　　鲍依斯<span lang="EN-US">-</span>科得范式（<span lang="EN-US">BCNF</span>）：在第三范式的基础上，数据库表中如果不存在任何字段对任一候选关键字段的传递函数依赖则符合第三范式。<span lang="EN-US"><br>
<br>
</span>　　假设仓库管理关系表为<span lang="EN-US">StorehouseManage(</span>仓库<span lang="EN-US">ID,
</span>存储物品<span lang="EN-US">ID, </span>管理员<span lang="EN-US">ID, </span>数量<span lang="EN-US">)</span>，且有一个管理员只在一个仓库工作；一个仓库可以存储多种物品。这个数据库表中存在如下决定关系：<span lang="EN-US"><br>
<br>
</span>　　<span lang="EN-US">(</span>仓库<span lang="EN-US">ID, </span>存储物品<span lang="EN-US">ID) →(</span>管理员<span lang="EN-US">ID, </span>数量<span lang="EN-US">)<br>
<br>
</span>　　<span lang="EN-US">(</span>管理员<span lang="EN-US">ID, </span>存储物品<span lang="EN-US">ID) → (</span>仓库<span lang="EN-US">ID, </span>数量<span lang="EN-US">)<br>
<br>
</span>　　所以，<span lang="EN-US">(</span>仓库<span lang="EN-US">ID, </span>存储物品<span lang="EN-US">ID)</span>和<span lang="EN-US">(</span>管理员<span lang="EN-US">ID, </span>存储物品<span lang="EN-US">ID)</span>都是<span lang="EN-US">StorehouseManage</span>的候选关键字，表中的唯一非关键字段为数量，它是符合第三范式的。但是，由于存在如下决定关系：<span lang="EN-US"><br>
<br>
</span>　　<span lang="EN-US">(</span>仓库<span lang="EN-US">ID) → (</span>管理员<span lang="EN-US">ID)<br>
<br>
</span>　　<span lang="EN-US">(</span>管理员<span lang="EN-US">ID) → (</span>仓库<span lang="EN-US">ID)<br>
<br>
</span>　　即存在关键字段决定关键字段的情况，所以其不符合<span lang="EN-US">BCNF</span>范式。它会出现如下异常情况：<span lang="EN-US"><br>
<br>
</span>　　<span lang="EN-US">(1) </span>删除异常：<span lang="EN-US"><br>
<br>
</span>　　当仓库被清空后，所有<span lang="EN-US">"</span>存储物品<span lang="EN-US">ID"</span>和<span lang="EN-US">"</span>数量<span lang="EN-US">"</span>信息被删除的同时，<span lang="EN-US">"</span>仓库<span lang="EN-US">ID"</span>和<span lang="EN-US">"</span>管理员<span lang="EN-US">ID"</span>信息也被删除了。<span lang="EN-US"><br>
<br>
</span>　　<span lang="EN-US">(2) </span>插入异常：<span lang="EN-US"><br>
<br>
</span>　　当仓库没有存储任何物品时，无法给仓库分配管理员。<span lang="EN-US"><br>
<br>
</span>　　<span lang="EN-US">(3) </span>更新异常：<span lang="EN-US"><br>
<br>
</span>　　如果仓库换了管理员，则表中所有行的管理员<span lang="EN-US">ID</span>都要修改。<span lang="EN-US"><br>
<br>
</span>　　把仓库管理关系表分解为二个关系表：<span lang="EN-US"><br>
<br>
</span>　　仓库管理：<span lang="EN-US">StorehouseManage(</span>仓库<span lang="EN-US">ID, </span>管理员<span lang="EN-US">ID)</span>；<span lang="EN-US"><br>
<br>
</span>　　仓库：<span lang="EN-US">Storehouse(</span>仓库<span lang="EN-US">ID, </span>存储物品<span lang="EN-US">ID, </span>数量<span lang="EN-US">)</span>。<span lang="EN-US"><br>
<br>
</span>　　这样的数据库表是符合<span lang="EN-US">BCNF</span>范式的，消除了删除异常、插入异常和更新异常。<b><span lang="EN-US"><o:p></o:p></span></b></span></p>

<p class="MsoNormal"><b><span style="font-family: 宋体;">范式应用<span lang="EN-US"><br>
<br>
</span></span></b><span style="font-family: 宋体;">　　我们来逐步搞定一个论坛的数据库，有如下信息：<span lang="EN-US"><br>
<br>
</span>　　（<span lang="EN-US">1</span>） 用户：用户名，<span lang="EN-US">email</span>，主页，电话，联系地址<span lang="EN-US"><br>
<br>
</span>　　（<span lang="EN-US">2</span>） 帖子：发帖标题，发帖内容，回复标题，回复内容<span lang="EN-US"> <br>
<br>
</span>　　第一次我们将数据库设计为仅仅存在表：<span lang="EN-US"><br>
</span>　　<span lang="EN-US"> <o:p></o:p></span></span></p>

<div align="center">

<table class="MsoNormalTable" style="width: 90%;" border="1" cellpadding="0" cellspacing="0" width="90%">
 <tbody><tr style="">
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">用户名<span lang="EN-US"> <o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;" lang="EN-US">email <o:p></o:p></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">主页<span lang="EN-US"><o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">电话<span lang="EN-US"><o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">联系地址<span lang="EN-US"><o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">发帖标题<span lang="EN-US"><o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">发帖内容<span lang="EN-US"><o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">回复标题<span lang="EN-US"><o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">回复内容<span lang="EN-US"><o:p></o:p></span></span></p>
  </td>
 </tr>
</tbody></table>

</div>

<p class="MsoNormal" style="margin-bottom: 12pt;"><span style="font-family: 宋体;" lang="EN-US"><br>
</span><span style="font-family: 宋体;">　　这个数据库表符合第一范式，但是没有任何一组候选关键字能决定数据库表的整行，唯一的关键字段用户名也不能完全决定整个元组。我们需要增加<span lang="EN-US">"</span>发帖<span lang="EN-US">ID"</span>、<span lang="EN-US">"</span>回复<span lang="EN-US">ID"</span>字段，即将表修改为：<span lang="EN-US"><o:p></o:p></span></span></p>

<div align="center">

<table class="MsoNormalTable" style="width: 90%;" border="1" cellpadding="0" cellspacing="0" width="90%">
 <tbody><tr style="">
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">用户名<span lang="EN-US"><o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;" lang="EN-US">email<o:p></o:p></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">主页<span lang="EN-US"><o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">电话<span lang="EN-US"><o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">联系地址<span lang="EN-US"><o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">发帖<span lang="EN-US">ID<o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">发帖标题<span lang="EN-US"><o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">发帖内容<span lang="EN-US"><o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">回复<span lang="EN-US">ID<o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">回复标题<span lang="EN-US"><o:p></o:p></span></span></p>
  </td>
  <td style="padding: 1.5pt;">
  <p class="MsoNormal"><span style="font-family: 宋体;">回复内容<span lang="EN-US"><o:p></o:p></span></span></p>
  </td>
 </tr>
</tbody></table>

</div>

<p class="MsoNormal"><span style="font-family: 宋体;" lang="EN-US"><br>
</span><span style="font-family: 宋体;">　　这样数据表中的关键字<span lang="EN-US">(</span>用户名，发帖<span lang="EN-US">ID</span>，回复<span lang="EN-US">ID)</span>能决定整行：<span lang="EN-US"><br>
<br>
</span>　　<span lang="EN-US">(</span>用户名<span lang="EN-US">,</span>发帖<span lang="EN-US">ID,</span>回复<span lang="EN-US">ID) → (email,</span>主页<span lang="EN-US">,</span>电话<span lang="EN-US">,</span>联系地址<span lang="EN-US">,</span>发帖标题<span lang="EN-US">,</span>发帖内容<span lang="EN-US">,</span>回复标题<span lang="EN-US">,</span>回复内容<span lang="EN-US">)<br>
<br>
</span>　　但是，这样的设计不符合第二范式，因为存在如下决定关系：<span lang="EN-US"><br>
<br>
</span>　　<span lang="EN-US">(</span>用户名<span lang="EN-US">) → (email,</span>主页<span lang="EN-US">,</span>电话<span lang="EN-US">,</span>联系地址<span lang="EN-US">)<br>
<br>
</span>　　<span lang="EN-US">(</span>发帖<span lang="EN-US">ID) → (</span>发帖标题<span lang="EN-US">,</span>发帖内容<span lang="EN-US">)<br>
<br>
</span>　　<span lang="EN-US">(</span>回复<span lang="EN-US">ID) → (</span>回复标题<span lang="EN-US">,</span>回复内容<span lang="EN-US">)<br>
<br>
</span>　　即非关键字段部分函数依赖于候选关键字段，很明显，这个设计会导致大量的数据冗余和操作异常。<span lang="EN-US"><br>
<br>
</span>　　我们将数据库表分解为（带下划线的为关键字）：<span lang="EN-US"><br>
<br>
</span>　　（<span lang="EN-US">1</span>） 用户信息：用户名，<span lang="EN-US">email</span>，主页，电话，联系地址<span lang="EN-US"><br>
<br>
</span>　　（<span lang="EN-US">2</span>） 帖子信息：发帖<span lang="EN-US">ID</span>，标题，内容<span lang="EN-US"><br>
<br>
</span>　　（<span lang="EN-US">3</span>） 回复信息：回复<span lang="EN-US">ID</span>，标题，内容<span lang="EN-US"><br>
<br>
</span>　　（<span lang="EN-US">4</span>） 发贴：用户名，发帖<span lang="EN-US">ID<br>
<br>
</span>　　（<span lang="EN-US">5</span>） 回复：发帖<span lang="EN-US">ID</span>，回复<span lang="EN-US">ID<br>
<br>
</span>　　这样的设计是满足第<span lang="EN-US">1</span>、<span lang="EN-US">2</span>、<span lang="EN-US">3</span>范式和<span lang="EN-US">BCNF</span>范式要求的，但是这样的设计是不是最好的呢？<span lang="EN-US"><br>
<br>
</span>　　不一定。<span lang="EN-US"><br>
<br>
</span>　 　观察可知，第<span lang="EN-US">4</span>项<span lang="EN-US">"</span>发帖<span lang="EN-US">"</span>中的<span lang="EN-US">"</span>用户名<span lang="EN-US">"</span>和<span lang="EN-US">"</span>发帖<span lang="EN-US">ID"</span>之间是<span lang="EN-US">1</span>：<span lang="EN-US">N</span>的关系，因此我们可以把<span lang="EN-US">"</span>发帖<span lang="EN-US">"</span>合并到第<span lang="EN-US">2</span>项的<span lang="EN-US">"</span>帖子信息<span lang="EN-US">"</span>中；第<span lang="EN-US">5</span>项<span lang="EN-US">"</span>回复<span lang="EN-US">"</span>中的<span lang="EN-US"> "</span>发帖<span lang="EN-US">ID"</span>和<span lang="EN-US">"</span>回复<span lang="EN-US">ID"</span>之间也是<span lang="EN-US">1</span>：<span lang="EN-US">N</span>的关系，因此我们可以把<span lang="EN-US">"</span>回复<span lang="EN-US">"</span>合并到第<span lang="EN-US">3</span>项的<span lang="EN-US">"</span>回复信息<span lang="EN-US">"</span>中。这样可以一定量地减少数据冗余，新的设计为：<span lang="EN-US"><br>
<br>
</span>　　（<span lang="EN-US">1</span>） 用户信息：用户名，<span lang="EN-US">email</span>，主页，电话，联系地址<span lang="EN-US"><br>
<br>
</span>　　（<span lang="EN-US">2</span>） 帖子信息：用户名，发帖<span lang="EN-US">ID</span>，标题，内容<span lang="EN-US"><br>
<br>
</span>　　（<span lang="EN-US">3</span>） 回复信息：发帖<span lang="EN-US">ID</span>，回复<span lang="EN-US">ID</span>，标题，内容<span lang="EN-US"><br>
<br>
</span>　　数据库表<span lang="EN-US">1</span>显然满足所有范式的要求；<span lang="EN-US"><br>
<br>
</span>　　数据库表<span lang="EN-US">2</span>中存在非关键字段<span lang="EN-US">"</span>标题<span lang="EN-US">"</span>、<span lang="EN-US">"</span>内容<span lang="EN-US">"</span>对关键字段<span lang="EN-US">"</span>发帖<span lang="EN-US">ID"</span>的部分函数依赖，即不满足第二范式的要求，但是这一设计并不会导致数据冗余和操作异常；<span lang="EN-US"><br>
<br>
</span>　　数据库表<span lang="EN-US">3</span>中也存在非关键字段<span lang="EN-US">"</span>标题<span lang="EN-US">"</span>、<span lang="EN-US">"</span>内容<span lang="EN-US">"</span>对关键字段<span lang="EN-US">"</span>回复<span lang="EN-US">ID"</span>的部分函数依赖，也不满足第二范式的要求，但是与数据库表<span lang="EN-US">2</span>相似，这一设计也不会导致数据冗余和操作异常。<span lang="EN-US"><br>
<br>
</span>　　由此可以看出，并不一定要强行满足范式的要求，对于<span lang="EN-US">1</span>：<span lang="EN-US">N</span>关系，当<span lang="EN-US">1</span>的一边合并到<span lang="EN-US">N</span>的那边后，<span lang="EN-US">N</span>的那边就不再满足第二范式了，但是这种设计反而比较好！<span lang="EN-US"><br>
<br>
</span>　　对于<span lang="EN-US">M</span>：<span lang="EN-US">N</span>的关系，不能将<span lang="EN-US">M</span>一边或<span lang="EN-US">N</span>一边合并到另一边去，这样会导致不符合范式要求，同时导致操作异常和数据冗余。<span lang="EN-US"> <br>
</span>对于<span lang="EN-US">1</span>：<span lang="EN-US">1</span>的关系，我们可以将左边的<span lang="EN-US">1</span>或者右边的<span lang="EN-US">1</span>合并到另一边去，设计导致不符合范式要求，但是并不会导致操作异常和数据冗余。<span lang="EN-US"><br>
<br>
</span>　　<b>结论</b><span lang="EN-US"><br>
<br>
</span>　　满足范式要求的数据库设计是结构清晰的，同时可避免数据冗余和操作异常。这并意味着不符合范式要求的设计一定是错误的，在数据库表中存在<span lang="EN-US">1</span>：<span lang="EN-US">1</span>或<span lang="EN-US">1</span>：<span lang="EN-US">N</span>关系这种较特殊的情况下，合并导致的不符合范式要求反而是合理的。<span lang="EN-US"><br>
<br>
</span>　　在我们设计数据库的时候，一定要时刻考虑范式的要求。</span></p>

<img src ="http://www.blogjava.net/DenisLing/aggbug/24725.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/DenisLing/" target="_blank">DenisLing</a> 2005-12-20 10:54 <a href="http://www.blogjava.net/DenisLing/archive/2005/12/20/24725.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对spring事务类型详解的一点补充（关于嵌套事务）</title><link>http://www.blogjava.net/DenisLing/archive/2005/12/19/extendsOfSpring.html</link><dc:creator>DenisLing</dc:creator><author>DenisLing</author><pubDate>Mon, 19 Dec 2005 08:02:00 GMT</pubDate><guid>http://www.blogjava.net/DenisLing/archive/2005/12/19/extendsOfSpring.html</guid><wfw:comment>http://www.blogjava.net/DenisLing/comments/24641.html</wfw:comment><comments>http://www.blogjava.net/DenisLing/archive/2005/12/19/extendsOfSpring.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/DenisLing/comments/commentRss/24641.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/DenisLing/services/trackbacks/24641.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 可能大家对PROPAGATION_NESTED还不怎么了解，觉得有必要再补充一下^_^！&nbsp;&nbsp;<a href='http://www.blogjava.net/DenisLing/archive/2005/12/19/extendsOfSpring.html'>阅读全文</a><img src ="http://www.blogjava.net/DenisLing/aggbug/24641.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/DenisLing/" target="_blank">DenisLing</a> 2005-12-19 16:02 <a href="http://www.blogjava.net/DenisLing/archive/2005/12/19/extendsOfSpring.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring事务类型祥解</title><link>http://www.blogjava.net/DenisLing/archive/2005/12/18/spring.html</link><dc:creator>DenisLing</dc:creator><author>DenisLing</author><pubDate>Sun, 18 Dec 2005 08:30:00 GMT</pubDate><guid>http://www.blogjava.net/DenisLing/archive/2005/12/18/spring.html</guid><wfw:comment>http://www.blogjava.net/DenisLing/comments/24503.html</wfw:comment><comments>http://www.blogjava.net/DenisLing/archive/2005/12/18/spring.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/DenisLing/comments/commentRss/24503.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/DenisLing/services/trackbacks/24503.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 大家可能在spring中经常看到这样的定义：<br><br><br><prop key="load*">PROPAGATION_REQUIRED,readOnly</prop><prop key="store*">PROPAGATION_REQUIRED</prop><br><br>估计有好多朋友还没有弄清楚里面的值的意思，仔细看完下面应该知道自己什么情况下面应该使用什么样的声明。^_^&nbsp;&nbsp;<a href='http://www.blogjava.net/DenisLing/archive/2005/12/18/spring.html'>阅读全文</a><img src ="http://www.blogjava.net/DenisLing/aggbug/24503.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/DenisLing/" target="_blank">DenisLing</a> 2005-12-18 16:30 <a href="http://www.blogjava.net/DenisLing/archive/2005/12/18/spring.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>spring声明式事务管理祥述</title><link>http://www.blogjava.net/DenisLing/archive/2005/12/01/22096.html</link><dc:creator>DenisLing</dc:creator><author>DenisLing</author><pubDate>Thu, 01 Dec 2005 03:47:00 GMT</pubDate><guid>http://www.blogjava.net/DenisLing/archive/2005/12/01/22096.html</guid><wfw:comment>http://www.blogjava.net/DenisLing/comments/22096.html</wfw:comment><comments>http://www.blogjava.net/DenisLing/archive/2005/12/01/22096.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/DenisLing/comments/commentRss/22096.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/DenisLing/services/trackbacks/22096.html</trackback:ping><description><![CDATA[<p>Spring也提供了声明式事务管理。这是通过Spring AOP实现的。</p><p>Spring
中进行事务管理的通常方式是利用AOP（面向切片编程）的方式，为普通java类封装事务控制，它是通过动态代理实现的，由于接口是延迟实例化的，
spring在这段时间内通过拦截器，加载事务切片。原理就是这样，具体细节请参考jdk中有关动态代理的文档。本文主要讲解如何在spring中进行事
务控制。<br>动态代理的一个重要特征是，它是针对接口的，所以我们的dao要通过动态代理来让spring接管事务，就必须在dao前面抽象出一个接口，当然如果没有这样的接口，那么spring会使用CGLIB来解决问题，但这不是spring推荐的方式，所以不做讨论.</p><p><i><span class="remark">大多数Spring用户选择声明式事务管理。这是最少影响应用代码的选择， 因而这是和<span class="emphasis"><em>非侵入性</em></span>的轻量级容器的观念是一致的。 </span></i></p><p>从考虑EJB CMT和Spring声明式事务管理的相似以及不同之处出发是很有益的。 它们的基本方法是相似的：都可以指定事务管理到单独的方法；如果需要可以在事务上 下文调用<tt class="literal"><font face="新宋体">setRollbackOnly()</font></tt>方法。不同之处如下：</p><div class="itemizedlist"><ul type="disc"><li><p>不象EJB CMT绑定在JTA上，Spring声明式事务管理可以在任何环境下使用。 只需更改配置文件，它就可以和JDBC、JDO、Hibernate或其他的事务机制一起工作 </p></li><li><p>Spring可以使声明式事务管理应用到普通Java对象，不仅仅是特殊的类，如EJB</p></li><li><p>Spring提供声明式<span class="emphasis"><em>回滚规则</em></span>：EJB没有对应的特性， 我们将在下面讨论这个特性。回滚可以声明式控制，不仅仅是编程式的 </p></li><li><p>Spring允许你通过AOP定制事务行为。例如，如果需要，你可以在事务 回滚中插入定制的行为。你也可以增加任意的通知，就象事务通知一样。使用 EJB CMT，除了使用<tt class="literal"><font face="新宋体">setRollbackOnly()</font></tt>，你没有办法能 够影响容器的事务管理</p></li><li><p>Spring不提供高端应用服务器提供的跨越远程调用的事务上下文传播。如 果你需要这些特性，我们推荐你使用EJB。然而，不要轻易使用这些特性。通常我 们并不希望事务跨越远程调用</p></li></ul></div><p>回滚规则的概念是很重要的：它们使得我们可以指定哪些异常应该发起自 动回滚。我们在配置文件中，而不是Java代码中，以声明的方式指定。因此，虽然我们仍 然可以编程调用<tt class="literal"><font face="新宋体">TransactionStatus</font></tt>对象的 <tt class="literal"><font face="新宋体">setRollbackOnly()</font></tt>方法来回滚当前事务，多数时候我们可以 指定规则，如<tt class="literal"><font face="新宋体">MyApplicationException</font></tt>应该导致回滚。 这有显著的优点，业务对象不需要依赖事务基础设施。例如，它们通常不需要引 入任何Spring API，事务或其他任何东西。</p><p>EJB的默认行为是遇到<span class="emphasis"><em>系统异常</em></span>（通常是运行时异常）， EJB容器自动回滚事务。EJB CMT遇到<span class="emphasis"><em>应用程序异常</em></span> （除了<span class="emphasis"><em>java.rmi.RemoteException</em></span>外的checked异常）时不 会自动回滚事务。虽然Spring声明式事务管理沿用EJB的约定（遇到unchecked 异常自动回滚事务），但是这是可以定制的。</p><p>按照我们的测试，Spring声明式事务管理的性能要胜过EJB CMT。</p><p>通
常通过TransactionProxyFactoryBean设置Spring事务代理。我们需
要一个目标对象包装在事务代理中。这个目标对象一般是一个普通Java对象的bean。当我
们定义TransactionProxyFactoryBean时，必须提供一个相关的 PlatformTransactionManager的引用和<span class="bold"><b>事务属性</b></span>。 <span class="bold"><b>事务属性</b></span>含有上面描述的事务定义。</p><pre class="programlisting">&lt;bean id="petStore" <br>    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"&gt;<br>    &lt;property name="transactionManager"&gt;&lt;ref bean="transactionManager"/&gt;&lt;/property&gt;<br>    &lt;property name="target"&gt;&lt;ref bean="petStoreTarget"/&gt;&lt;/property&gt;<br>    &lt;property name="transactionAttributes"&gt;<br>        &lt;props&gt;<br>            &lt;prop key="insert*"&gt;PROPAGATION_REQUIRED,-MyCheckedException&lt;/prop&gt;<br>            &lt;prop key="update*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br>            &lt;prop key="*"&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;<br>        &lt;/props&gt;<br>    &lt;/property&gt;<br>&lt;/bean&gt;</pre><p>事
务代理会实现目标对象的接口：这里是id为petStoreTarget的bean。（使用
CGLIB也可以实现具体类的代理。只要设置proxyTargetClass属性为true就可以。
如果目标对象没有实现任何接口，这将自动设置该属性为true。通常，我们希望面向接口而不是
类编程。）使用proxyInterfaces属性来限定事务代理来代 理指定接口也是可以的（一般来说是个好想法）。也可以通过从 <tt class="literal"><font face="新宋体">org.springframework.aop.framework.ProxyConfig</font></tt>继承或所有AOP代理工厂共享 的属性来定制TransactionProxyFactoryBean的行为。 </p><p>这里的transactionAttributes属性定义在 <tt class="literal"><font face="新宋体">org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource</font></tt> 中的属性格式来设置。这个包括通配符的方法名称映射是很直观的。注意 insert*的映射的值包括回滚规则。添加的<tt class="literal"><font face="新宋体">-MyCheckedException</font></tt> 指定如果方法抛出<tt class="literal"><font face="新宋体">MyCheckedException</font></tt>或它的子类，事务将 会自动回滚。可以用逗号分隔定义多个回滚规则。<font color="#ff0000"><strong>-前缀强制回滚，+前缀指定提交</strong></font>（这允许即使抛出unchecked异常时也可以提交事务，当然你自己要明白自己 在做什么）。</p><p><tt class="literal"><font face="新宋体">TransactionProxyFactoryBean</font></tt>允许你通过 “preInterceptors”和“postInterceptors”属性设置“前”或“后”通知来提供额外的 拦截行为。可以设置任意数量的“前”和“后”通知，它们的类型可以是 <tt class="literal"><font face="新宋体">Advisor</font></tt>（可以包含一个切入点）， <tt class="literal"><font face="新宋体">MethodInterceptor</font></tt>或被当前Spring配置支持的通知类型 （例如<tt class="literal"><font face="新宋体">ThrowAdvice</font></tt>， <tt class="literal"><font face="新宋体">AfterReturningtAdvice</font></tt>或<tt class="literal"><font face="新宋体">BeforeAdvice</font></tt>， 这些都是默认支持的）。这些通知必须支持实例共享模式。如果你需要高级AOP特 性来使用事务，如有状态的maxin，那最好使用通用的 <tt class="literal"><font face="新宋体">org.springframework.aop.framework.ProxyFactoryBean</font></tt>， 而不是<tt class="literal"><font face="新宋体">TransactionProxyFactoryBean</font></tt>实用代理创建者。</p><p>也可以设置自动代理：配置AOP框架，不需要单独的代理定义类就可以生成类的 代理。</p>附两个spring的事务配置例子：<br>&lt;prop key="add"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp; PROPAGATION_REQUIRES_NEW, -MyException <br>&lt;/prop&gt;<br>注：上面的意思是add方法将独占一个事务，当事务处理过程中产生MyException异常或者该异常的子类将回滚该事务。<br><br>&lt;prop key="loadAll"&gt;<br>&nbsp;&nbsp;&nbsp; PROPAGATION_SUPPORTS, ISOLATION_READ_COMMITED, Readonly<br>&lt;/prop&gt;<br>注：表示loadAll方法支持事务，而且不会读取没有提交事务的数据。它的数据为只读（这样有助于提高读取的性能）<br><br>附A Spring中的所有事务策略<br><br>PROPAGATION_MANDATORY<br>PROPAGATION_NESTED <br>PROPAGATION_NEVER <br>PROPAGATION_NOT_SUPPORTED<br>PROPAGATION_REQUIRED<br>PROPAGATION_REQUIRED_NEW<br>PROPAGATION_SUPPORTS<br><br>附B Spring中所有的隔离策略：<br><br>ISOLATION_DEFAULT<br>ISOLATION_READ_UNCOMMITED<br>ISOLATION_COMMITED<br>ISOLATION_REPEATABLE_READ<br>ISOLATION_SERIALIZABLE<img src ="http://www.blogjava.net/DenisLing/aggbug/22096.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/DenisLing/" target="_blank">DenisLing</a> 2005-12-01 11:47 <a href="http://www.blogjava.net/DenisLing/archive/2005/12/01/22096.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>webwork开发团队加入Struts（吃惊）</title><link>http://www.blogjava.net/DenisLing/archive/2005/11/28/21596.html</link><dc:creator>DenisLing</dc:creator><author>DenisLing</author><pubDate>Mon, 28 Nov 2005 00:47:00 GMT</pubDate><guid>http://www.blogjava.net/DenisLing/archive/2005/11/28/21596.html</guid><wfw:comment>http://www.blogjava.net/DenisLing/comments/21596.html</wfw:comment><comments>http://www.blogjava.net/DenisLing/archive/2005/11/28/21596.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.blogjava.net/DenisLing/comments/commentRss/21596.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/DenisLing/services/trackbacks/21596.html</trackback:ping><description><![CDATA[<h3 class="entry-header">早上一过来看到下面的新闻感觉惊讶的要死！不知道和我一样在struts和webwork之间一直在徘徊的朋友们看了由什么感觉。本来我的态度是想慢慢放弃struts的…… 看样子要重新看待struts了。原文如下：<br>
</h3>
<h3 class="entry-header">WebWork joining Struts<br>
</h3>
<br>
Yes, <a href="http://www.mail-archive.com/dev%40struts.apache.org/msg13815.html">it's true</a>.
The WebWork development team (Jason and I) have been working with the
Struts development team (Don Brown and Ted Husted) and have come to the
conclusion that the best thing for Java community would be to merge
WebWork in to Struts.

<p>Read Ted's email <a href="http://www.mail-archive.com/dev%40struts.apache.org/msg13815.html">here</a>,
but the gist of it is this: WebWork is a great technology, and Struts
is a great community. It's a perfect match and bringing the two
together will only be better for WebWork and Struts users alike. The
only down side for me is that I'll be working less with OpenSymphony,
but I believe that is a small price for all the great benefits that
come from this merger.</p>


<p>Just to be clear, WebWork is <strong>not</strong> going away.
WebWork 2.2 is still coming out any day now, and there may even be a
WebWork 2.3. But new minor/major versions won't be coming out under the
WebWork name for much longer. Instead, they will be released under the
Struts incubator program with the intent to eventually become Struts
Action Framework 2.0.</p>


<p>So don't worry, WebWork 2.1.8, 2.2.1, and other bug fix releases
will continue to come out and we will support the WebWork community as
long as needed. In addition, we'll make compatibility with both Struts
and WebWork a high priority, so future releases may help with that. To
be clear: <strong>no one is leaving WebWork and it will continue to be supported for a very long time</strong>.</p>


<p>With this renewed energy, larger development team, and larger
community, the combined efforts of Struts and WebWork will surely make
the Struts platform the easiest, fastest, and most powerful Java web
framework available. We hope that all the WebWork users and developers
are as excited about this as we are and are ready to take WebWork to
the next level.<br>
</p>
<p>原文地址：http://www.opensymphony.com/webwork/<br>
</p>
<p>以前一直在struts和webwork之间犹豫，看来struts气数未尽呀。apache组织还是比较只值得信赖的。呵呵!<br>
</p>

<img src ="http://www.blogjava.net/DenisLing/aggbug/21596.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/DenisLing/" target="_blank">DenisLing</a> 2005-11-28 08:47 <a href="http://www.blogjava.net/DenisLing/archive/2005/11/28/21596.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>自定义标签获取struts中action的全部路径（原创）</title><link>http://www.blogjava.net/DenisLing/archive/2005/11/21/20781.html</link><dc:creator>DenisLing</dc:creator><author>DenisLing</author><pubDate>Mon, 21 Nov 2005 07:52:00 GMT</pubDate><guid>http://www.blogjava.net/DenisLing/archive/2005/11/21/20781.html</guid><wfw:comment>http://www.blogjava.net/DenisLing/comments/20781.html</wfw:comment><comments>http://www.blogjava.net/DenisLing/archive/2005/11/21/20781.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/DenisLing/comments/commentRss/20781.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/DenisLing/services/trackbacks/20781.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由于项目里面由需要一个form可以提交多个action（本来可以用
dispatch值来实现，后来考虑到要使用validator框架验证）。后来考虑的方案为使用js来控制form的流向，例如<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><span style="color: rgb(0, 0, 0);">form.action</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">'/bookstore/checkId.</span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);">'</span></div>
<br>
不过新的问题来了！如何能不用hardcode而拿到我要的action的实际路径呢？比如我定义的struts-config文件里面的action是&nbsp; <br>

<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><span style="color: rgb(0, 0, 0);">path</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">/checkId</span><span style="color: rgb(0, 0, 0);">"</span></div>
但是实际解释后的path是：<br>

<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><span style="color: rgb(0, 0, 0);">action＝'</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">bookstore</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">checkId.</span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);">'</span></div>
前
缀和后面的后缀.do都是根据你的项目部署的路径和你在web.xml中配置的mapping的后缀有关系，如果我把内容写死到jsp中那以后我要是想把
checkId.do改成checkId.action那就要更改jsp，由于struts本来提供的几个taglib里面的<br>
<br>

<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">html:form&nbsp;action</span><span style="color: rgb(0, 0, 0);">="</span><span style="color: rgb(0, 0, 0);">/checkId"</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">&gt;</span></div>
<br>
综合了一下决定还是自己写个taglib来实现，其实只需要照着struts 中的 FormTag.java 文件依葫芦画瓢就可以了，一下为本人的代码部分<br>
<br>
StrutsActionCustomTag.java<br>

<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><span style="color: rgb(0, 0, 255);">package</span><span style="color: rgb(0, 0, 0);">&nbsp;com.denis.framework.common.taglib.strutsActionExt;<br><br></span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);">&nbsp;javax.servlet.http.HttpServletResponse;<br></span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);">&nbsp;javax.servlet.jsp.JspException;<br></span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);">&nbsp;javax.servlet.jsp.tagext.TagSupport;<br><br></span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);">&nbsp;org.apache.struts.taglib.TagUtils;<br><br><img id="Codehighlighter1_288_1030_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_288_1030_Closed_Text.style.display='none'; Codehighlighter1_288_1030_Open_Image.style.display='inline'; Codehighlighter1_288_1030_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">&nbsp;StrutsActionCustomTag&nbsp;</span><span style="color: rgb(0, 0, 255);">extends</span><span style="color: rgb(0, 0, 0);">&nbsp;TagSupport&nbsp;</span><span id="Codehighlighter1_288_1030_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif"></span><span id="Codehighlighter1_288_1030_Open_Text"><span style="color: rgb(0, 0, 0);">{<br><br>&nbsp;&nbsp;&nbsp; </span><span style="color: rgb(0, 0, 255);">protected</span><span style="color: rgb(0, 0, 0);">&nbsp;String&nbsp;actionName&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">null</span><span style="color: rgb(0, 0, 0);">;<br>&nbsp;&nbsp;&nbsp; <br><img id="Codehighlighter1_370_394_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_370_394_Closed_Text.style.display='none'; Codehighlighter1_370_394_Open_Image.style.display='inline'; Codehighlighter1_370_394_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;String&nbsp;getActionName()&nbsp;</span><span id="Codehighlighter1_370_394_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif"></span><span id="Codehighlighter1_370_394_Open_Text"><span style="color: rgb(0, 0, 0);">{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">&nbsp;actionName;<br>&nbsp;&nbsp;&nbsp; }</span></span><span style="color: rgb(0, 0, 0);"><br><br><img id="Codehighlighter1_443_478_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_443_478_Closed_Text.style.display='none'; Codehighlighter1_443_478_Open_Image.style.display='inline'; Codehighlighter1_443_478_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;setActionName(String&nbsp;actionName)&nbsp;</span><span id="Codehighlighter1_443_478_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif"></span><span id="Codehighlighter1_443_478_Open_Text"><span style="color: rgb(0, 0, 0);">{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.actionName&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;actionName;<br>&nbsp;&nbsp;&nbsp; }</span></span><span style="color: rgb(0, 0, 0);"><br><br><img id="Codehighlighter1_526_934_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_526_934_Closed_Text.style.display='none'; Codehighlighter1_526_934_Open_Image.style.display='inline'; Codehighlighter1_526_934_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">&nbsp;doStartTag()&nbsp;</span><span style="color: rgb(0, 0, 255);">throws</span><span style="color: rgb(0, 0, 0);">&nbsp;JspException&nbsp;</span><span id="Codehighlighter1_526_934_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif"></span><span id="Codehighlighter1_526_934_Open_Text"><span style="color: rgb(0, 0, 0);">{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; StringBuffer&nbsp;results&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;StringBuffer();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HttpServletResponse&nbsp;response&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (HttpServletResponse)&nbsp;</span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.pageContext.getResponse();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
results.append(response.encodeURL(&nbsp;TagUtils.getInstance().getActionMappingURL(&nbsp;</span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.actionName&nbsp;,&nbsp;</span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.pageContext))&nbsp;);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TagUtils.getInstance().write(pageContext,&nbsp;results.toString());<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">&nbsp;(EVAL_BODY_INCLUDE);<br>&nbsp;&nbsp;&nbsp; }</span></span><span style="color: rgb(0, 0, 0);"><br><br><img id="Codehighlighter1_963_1028_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_963_1028_Closed_Text.style.display='none'; Codehighlighter1_963_1028_Open_Image.style.display='inline'; Codehighlighter1_963_1028_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;release()&nbsp;</span><span id="Codehighlighter1_963_1028_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif"></span><span id="Codehighlighter1_963_1028_Open_Text"><span style="color: rgb(0, 0, 0);">{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: rgb(0, 0, 255);">super</span><span style="color: rgb(0, 0, 0);">.release();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.actionName&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">null</span><span style="color: rgb(0, 0, 0);">&nbsp;;<br><br>&nbsp;&nbsp;&nbsp; }</span></span><span style="color: rgb(0, 0, 0);"><br>}</span></span></div>
<br>
<br>
tld定义部分<br>
<br>
framework-struts.tld<br>

<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><span style="color: rgb(0, 0, 255);">&lt;?</span><span style="color: rgb(255, 0, 255);">xml&nbsp;version="1.0"&nbsp;encoding="UTF-8"</span><span style="color: rgb(0, 0, 255);">?&gt;</span><span style="color: rgb(0, 0, 0);"><br><br></span><span style="color: rgb(0, 0, 255);">&lt;!</span><span style="color: rgb(255, 0, 255);">DOCTYPE&nbsp;taglib&nbsp;PUBLIC&nbsp;"-//Sun&nbsp;Microsystems,&nbsp;Inc.//DTD&nbsp;JSP&nbsp;Tag&nbsp;Library&nbsp;1.1//EN"&nbsp;"http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">taglib</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><br></span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">tlibversion</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">1.0</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">tlibversion</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 0, 255);">&nbsp;&nbsp;&nbsp; &lt;</span><span style="color: rgb(128, 0, 0);">jspversion</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">1.1</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">jspversion</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 0, 255);">&nbsp;&nbsp;&nbsp; &lt;</span><span style="color: rgb(128, 0, 0);">shortname</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">framework</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">shortname</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 0, 255);">&nbsp;&nbsp;&nbsp; &lt;</span><span style="color: rgb(128, 0, 0);">uri</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">http://www.denisFramework.org/Framework-Tag</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">uri</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 0, 255);">&nbsp;&nbsp;&nbsp; &lt;</span><span style="color: rgb(128, 0, 0);">tag</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 0, 255);">&nbsp;&nbsp;&nbsp; &lt;</span><span style="color: rgb(128, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">getActionUrl</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 0, 255);">&nbsp;&nbsp;&nbsp; &lt;</span><span style="color: rgb(128, 0, 0);">tagclass</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">com.denis.framework.common.taglib.strutsActionExt.StrutsActionCustomTag</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">tagclass</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 0, 255);">&nbsp;&nbsp;&nbsp; &lt;</span><span style="color: rgb(128, 0, 0);">bodycontent</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">empty</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bodycontent</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 0, 255);">&nbsp;&nbsp;&nbsp; &lt;</span><span style="color: rgb(128, 0, 0);">attribute</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 0, 255);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;</span><span style="color: rgb(128, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">actionName</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 0, 255);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;</span><span style="color: rgb(128, 0, 0);">required</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">true</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">required</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 0, 255);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;</span><span style="color: rgb(128, 0, 0);">rtexprvalue</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">true</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">rtexprvalue</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 0, 255);">&nbsp;&nbsp;&nbsp; &lt;/</span><span style="color: rgb(128, 0, 0);">attribute</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">tag</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><br></span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">taglib</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><br><br>
</span></div>
<br>
ok ! 直接在jsp中如下使用即可取到action的真正路径<br>
<br>

<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><span style="color: rgb(0, 0, 0);">&nbsp;<br><img id="Codehighlighter1_4_25_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_4_25_Closed_Text.style.display='none'; Codehighlighter1_4_25_Open_Image.style.display='inline'; Codehighlighter1_4_25_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span style="color: rgb(0, 0, 0); background-color: rgb(255, 255, 0);">&lt;%</span><span id="Codehighlighter1_4_25_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif"></span><span id="Codehighlighter1_4_25_Open_Text"><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">@&nbsp;page&nbsp;language</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">=</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">"</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">java</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">"</span></span><span style="color: rgb(0, 0, 0); background-color: rgb(255, 255, 0);">%&gt;</span><span style="color: rgb(0, 0, 0);"><br><img id="Codehighlighter1_31_101_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_31_101_Closed_Text.style.display='none'; Codehighlighter1_31_101_Open_Image.style.display='inline'; Codehighlighter1_31_101_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span style="color: rgb(0, 0, 0); background-color: rgb(255, 255, 0);">&lt;%</span><span id="Codehighlighter1_31_101_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif"></span><span id="Codehighlighter1_31_101_Open_Text"><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">@&nbsp;taglib&nbsp;uri</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">=</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">"</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">http://jakarta.apache.org/struts/tags-bean</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">"</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">&nbsp;prefix</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">=</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">"</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">bean</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">"</span></span><span style="color: rgb(0, 0, 0); background-color: rgb(255, 255, 0);">%&gt;</span><span style="color: rgb(0, 0, 0);">&nbsp;<br><img id="Codehighlighter1_108_178_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_108_178_Closed_Text.style.display='none'; Codehighlighter1_108_178_Open_Image.style.display='inline'; Codehighlighter1_108_178_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span style="color: rgb(0, 0, 0); background-color: rgb(255, 255, 0);">&lt;%</span><span id="Codehighlighter1_108_178_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif"></span><span id="Codehighlighter1_108_178_Open_Text"><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">@&nbsp;taglib&nbsp;uri</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">=</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">"</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">http://jakarta.apache.org/struts/tags-html</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">"</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">&nbsp;prefix</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">=</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">"</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">html</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">"</span></span><span style="color: rgb(0, 0, 0); background-color: rgb(255, 255, 0);">%&gt;</span><span style="color: rgb(0, 0, 0);"><br><img id="Codehighlighter1_184_247_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_184_247_Closed_Text.style.display='none'; Codehighlighter1_184_247_Open_Image.style.display='inline'; Codehighlighter1_184_247_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span style="color: rgb(0, 0, 0); background-color: rgb(255, 255, 0);">&lt;%</span><span id="Codehighlighter1_184_247_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif"></span><span id="Codehighlighter1_184_247_Open_Text"><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">@&nbsp;taglib&nbsp;uri</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">=</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">"</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">/WEB-INF/framework-struts.tld</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">"</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">&nbsp;prefix</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">=</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">"</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">framework</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">"</span><span style="color: rgb(0, 0, 0); background-color: rgb(245, 245, 245);">&nbsp;</span></span><span style="color: rgb(0, 0, 0); background-color: rgb(255, 255, 0);">%&gt;</span><span style="color: rgb(0, 0, 0);"><br>&nbsp;<br></span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">html</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">&nbsp;<br>&nbsp;&nbsp;&nbsp; </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">head</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">title</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">JSP&nbsp;for&nbsp;loginForm&nbsp;form</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">title</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br>&nbsp;&nbsp;&nbsp; </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">head</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br>&nbsp;&nbsp;&nbsp; </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">body</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">framework:getActionUrl&nbsp;</span><span style="color: rgb(255, 0, 0);">actionName</span><span style="color: rgb(0, 0, 255);">="login"</span><span style="color: rgb(255, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">html:form&nbsp;</span><span style="color: rgb(255, 0, 0);">action</span><span style="color: rgb(0, 0, 255);">="/login"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name&nbsp;:&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">html:text&nbsp;</span><span style="color: rgb(255, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">="name"</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;</span><span style="color: rgb(128, 0, 0);">html:errors&nbsp;</span><span style="color: rgb(255, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">="name"</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;</span><span style="color: rgb(128, 0, 0);">br</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; password&nbsp;:&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">html:password&nbsp;</span><span style="color: rgb(255, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">="password"</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;</span><span style="color: rgb(128, 0, 0);">html:errors&nbsp;</span><span style="color: rgb(255, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">="password"</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;</span><span style="color: rgb(128, 0, 0);">br</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">html:submit</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;</span><span style="color: rgb(128, 0, 0);">html:cancel</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">html:form</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br>&nbsp;&nbsp;&nbsp; </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">body</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">html</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><br>
</span></div>
<br>
<br>
大家要是有更好的解决方法希望能指正！谢谢！<img src ="http://www.blogjava.net/DenisLing/aggbug/20781.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/DenisLing/" target="_blank">DenisLing</a> 2005-11-21 15:52 <a href="http://www.blogjava.net/DenisLing/archive/2005/11/21/20781.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用 Spring 更好地处理 Struts 动作 (转自ibm 个人感觉受益非浅)</title><link>http://www.blogjava.net/DenisLing/archive/2005/11/21/20779.html</link><dc:creator>DenisLing</dc:creator><author>DenisLing</author><pubDate>Mon, 21 Nov 2005 07:42:00 GMT</pubDate><guid>http://www.blogjava.net/DenisLing/archive/2005/11/21/20779.html</guid><wfw:comment>http://www.blogjava.net/DenisLing/comments/20779.html</wfw:comment><comments>http://www.blogjava.net/DenisLing/archive/2005/11/21/20779.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/DenisLing/comments/commentRss/20779.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/DenisLing/services/trackbacks/20779.html</trackback:ping><description><![CDATA[<blockquote><font size="2"><i>Struts Recipes</i> 的合著者 George Franciscus 将介绍另一个重大的
Struts 整合窍门 —— 这次是将 Struts 应用程序导入 Spring 框架。请跟随 George，他将向您展示如何改变
Struts 动作，使得管理 Struts 动作就像管理 Spring beans 那样。结果是一个增强的 web
框架，这个框架可以方便地利用 Spring AOP 的优势。</font></blockquote>
<p><font size="2">您肯定已经听说过控制反转 (IOC)
设计模式，因为很长一段时间以来一直在流传关于它的信息。如果您在任何功能中使用过 Spring
框架，那么您就知道其原理的作用。在本文中，我利用这一原理把一个 Struts 应用程序注入 Spring 框架，您将亲身体会到 IOC
模式的强大。</font></p>
<p><font size="2">将一个 Struts 应用程序整合进 Spring 框架具有多方面的优点。首先，Spring 是为解决一些关于
JEE 的真实世界问题而设计的，比如复杂性、低性能和可测试性，等等。第二，Spring 框架包含一个 AOP
实现，允许您将面向方面技术应用于面向对象的代码。第三，一些人可能会说 Spring 框架只有<i>处理</i> Struts 比 Struts 处理自己好。但是这是观点问题，我演示三种将 Struts 应用程序整合到 Spring 框架的方法后，具体由您自己决定使用哪一种。</font></p>
<p><font size="2">我所演示的方法都是执行起来相对简单的，但是它们却具有明显不同的优点。我为每一种方法创建了一个独立而可用的例子，这样您就可以完全理解每种方法。
请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-sr2.html#resources">下载</a> 部分获得完整例子源代码。请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-sr2.html#resources">参考资料</a>，下载 Struts MVC 和 Spring 框架。</font></p>
<p><font size="2"><a name="IDAFEWW"><span class="atitle">为什么 Spring 这么了不起？</span></a></font></p>
<p><font size="2">Spring
的创立者 Rod Johnson 以一种批判的眼光看待 Java™ 企业软件开发，并且提议很多企业难题都能够通过战略地使用 IOC
模式（也称作依赖注入）来解决。当 Rod 和一个具有奉献精神的开放源码开发者团队将这个理论应用于实践时，结果就产生了 Spring
框架。简言之，Spring 是一个轻型的容器，利用它可以使用一个外部 XML 配置文件方便地将对象连接在一起。每个对象都可以通过显示一个
JavaBean 属性收到一个到依赖对象的引用，留给您的简单任务就只是在一个 XML 配置文件中把它们连接好。</font></p>
<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
<tbody><tr><td width="10"><font size="2"><img src="http://www.ibm.com/i/c.gif" alt="" height="1" width="10"></font></td><td><table border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td bgcolor="#eeeeee"><font size="2"><a name="IDAMEWW"><b>IOC 和 Spring</b></a><br>
            </font><p><font size="2">IOC 是一种使应用程序逻辑外在化的设计模式，所以它是被注入而不是被写入客户机代码中。将 IOC 与接口编程应用结合，就像 Spring 框架那样，产生了一种架构，这种架构能够减少客户机对特定实现逻辑的依赖。请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-sr2.html#resources">参考资料</a> 了解更多关于 IOC 和 Spring 的信息。</font></p></td></tr></tbody></table></td></tr></tbody>
</table>
<p><font size="2">依
赖注入是一个强大的特性，但是 Spring 框架能够提供更多特性。Spring
支持可插拔的事务管理器，可以给您的事务处理提供更广泛的选择范围。它集成了领先的持久性框架，并且提供一个一致的异常层次结构。Spring
还提供了一种使用面向方面代码代替正常的面向对象代码的简单机制。</font></p>
<p><font size="2">Spring AOP 允许您使用<i>拦截器</i> 在一个或多个执行点上拦截应用程序逻辑。加强应用程序在拦截器中的日志记录逻辑会产生一个更可读的、实用的代码基础，所以拦截器广泛用于日志记录。您很快就会看到，为了处理横切关注点，Spring AOP 发布了它自己的拦截器，您也可以编写您自己的拦截器。</font></p>
<font size="2"><br>
</font>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody><tr><td><font size="2"><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></font></td></tr></tbody>
</table>
<table class="no-print" align="right" cellpadding="0" cellspacing="0">
<tbody><tr align="right"><td><font size="2"><br>
      </font></td></tr></tbody>
</table>
<font size="2"><br>
<br>
</font>
<p><font size="2"><a name="IDA2EWW"><span class="atitle">整合 Struts 和 Spring</span></a></font></p>
<p><font size="2">与
Struts 相似，Spring 可以作为一个 MVC 实现。这两种框架都具有自己的优点和缺点，尽管大部分人同意 Struts 在 MVC
方面仍然是最好的。很多开发团队已经学会在时间紧迫的时候利用 Struts 作为构造高品质软件的基础。Struts
具有如此大的推动力，以至于开发团队宁愿整合 Spring 框架的特性，而不愿意转换成 Spring
MVC。没必要进行转换对您来说是一个好消息。Spring 架构允许您将 Struts 作为 Web 框架连接到基于 Spring
的业务和持久层。最后的结果就是现在一切条件都具备了。</font></p>
<p><font size="2">在接下来的小窍门中，您将会了解到三种将 Struts MVC 整合到 Spring 框架的方法。我将揭示每种方法的缺陷并且对比它们的优点。 一旦您了解到所有三种方法的作用，我将会向您展示一个令人兴奋的应用程序，这个程序使用的是这三种方法中我最喜欢的一种。</font></p>
<font size="2"><br>
</font>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody><tr><td><font size="2"><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></font></td></tr></tbody>
</table>
<table class="no-print" align="right" cellpadding="0" cellspacing="0">
<tbody><tr align="right"><td><font size="2"><br>
      </font></td></tr></tbody>
</table>
<font size="2"><br>
<br>
</font>
<p><font size="2"><a name="IDADFWW"><span class="atitle">三个小窍门</span></a></font></p>
<p><font size="2">接下来的每种整合技术（或者窍门）都有自己的优点和特点。我偏爱其中的一种，但是我知道这三种都能够加深您对 Struts 和 Spring 的理解。在处理各种不同情况的时候，这将给您提供一个广阔的选择范围。方法如下：</font></p>
<ul>
<li><font size="2">使用 Spring 的 <font size="3"><code>ActionSupport</code> </font>类整合 Structs</font></li><li><font size="2">使用 Spring 的 <font size="3"><code>DelegatingRequestProcessor</code> </font>覆盖 Struts 的 <code> <font size="3">RequestProcessor </font></code></font></li><li><font size="2">将 Struts <font size="3"><code>Action</code> </font>管理委托给 Spring 框架</font></li>
</ul>
<p><font size="2"><a name="IDAAGWW"><span class="smalltitle">装载应用程序环境</span></a></font></p>
<p><font size="2">无论您使用哪种技术，都需要使用 Spring 的 <code>ContextLoaderPlugin</code> 为 Struts 的 <code>ActionServlet</code> 装载 Spring 应用程序环境。就像添加任何其他插件一样，简单地向您的 struts-config.xml 文件添加该插件，如下所示：</font></p>
<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
<tbody><tr><td><pre><font size="2"><code class="section"><br><font size="3">&lt;plug-in className=<br>  "org.springframework.web.struts.ContextLoaderPlugIn"&gt;<br>    &lt;set-property property=<br>      "contextConfigLocation" value="/WEB-INF/beans.xml"/&gt;<br> &lt;/plug-in&gt;</font><br></code></font></pre></td></tr></tbody>
</table>
<font size="2"><br>
</font>
<p><font size="2">前面已经提到过，在 <a href="http://www-128.ibm.com/developerworks/cn/java/j-sr2.html#download">下载</a> 部分，您能够找到这三个完全可使用的例子的完整源代码。每个例子都为一个书籍搜索应用程序提供一种不同的 Struts 和 Spring 的整合方法。您可以在这里看到例子的要点，但是您也可以下载应用程序以查看所有的细节。</font></p>
<font size="2"><br>
</font>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody><tr><td><font size="2"><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></font></td></tr></tbody>
</table>
<table class="no-print" align="right" cellpadding="0" cellspacing="0">
<tbody><tr align="right"><td><font size="2"><br>
      </font></td></tr></tbody>
</table>
<font size="2"><br>
<br>
</font>
<p><font size="2"><a name="IDAZGWW"><span class="atitle">窍门 1. 使用 Spring 的 ActionSupport</span></a></font></p>
<p><font size="2">手动创建一个 Spring 环境是一种整合 Struts 和 Spring 的最直观的方式。为了使它变得更简单，Spring 提供了一些帮助。为了方便地获得 Spring 环境，<font size="3"><code>org.springframework.web.struts.ActionSupport</code></font> 类提供了一个 <font size="3"><code>getWebApplicationContext()</code></font> 方法。您所做的只是从 Spring 的 <font size="3"><code>ActionSupport</code> </font>而不是<font size="3"> Struts <code>Action</code></font> 类扩展您的动作，如清单 1 所示：</font></p>
<font size="2"><br>
<a name="IDAUHWW"><b>清单 1. 使用 ActionSupport 整合 Struts</b></a><br>
</font>
<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
<tbody><tr><td><pre><font size="2"><code class="section"><br><font size="3">package ca.nexcel.books.actions;<br><br>import java.io.IOException;<br><br>import javax.servlet.ServletException;<br>import javax.servlet.http.HttpServletRequest;<br>import javax.servlet.http.HttpServletResponse;<br><br>import org.apache.struts.action.ActionError;<br>import org.apache.struts.action.ActionErrors;<br>import org.apache.struts.action.ActionForm;<br>import org.apache.struts.action.ActionForward;<br>import org.apache.struts.action.ActionMapping;<br>import org.apache.struts.action.DynaActionForm;<br>import org.springframework.context.ApplicationContext;<br>import org.springframework.web.struts.ActionSupport;<br><br>import ca.nexcel.books.beans.Book;<br>import ca.nexcel.books.business.BookService;<br><br>public class SearchSubmit extends ActionSupport {   <span class="boldcode">|(1)</span><br><br><br>  public ActionForward execute(<br>    ActionMapping mapping,<br>    ActionForm form,<br>    HttpServletRequest request,<br>    HttpServletResponse response)<br>    throws IOException, ServletException {<br><br>    DynaActionForm searchForm = (DynaActionForm) form;<br>    String isbn = (String) searchForm.get("isbn");<br>		<br>    //the old fashion way<br>    //BookService bookService = new BookServiceImpl();<br>		<br>    ApplicationContext ctx = <br>      getWebApplicationContext();    <span class="boldcode">|(2)</span><br>    BookService bookService = <br>      (BookService) ctx.getBean("bookService");   <span class="boldcode">|(3)</span><br>        <br>  Book book = bookService.read(isbn.trim());<br><br>    if (null == book) {<br>      ActionErrors errors = new ActionErrors();<br>      errors.add(ActionErrors.GLOBAL_ERROR,new ActionError<br>        ("message.notfound"));<br>      saveErrors(request, errors);<br>      return mapping.findForward("failure") ;<br>  }<br><br>    request.setAttribute("book", book);<br>    return mapping.findForward("success");<br>  }<br>}</font><br></code></font></pre></td></tr></tbody>
</table>
<font size="2"><br>
</font>
<p><font size="2">让我们快速思考一下这里到底发生了什么。在 (1) 处，我通过从 Spring 的 <font size="3"><code>ActionSupport</code> </font>类而不是 Struts 的 <code>Action</code> 类进行扩展，创建了一个新的 <font size="3"><code>Action</code>。</font>在 (2) 处，我使用 <font size="3"><code>getWebApplicationContext()</code></font> 方法获得一个 <font size="3"><code>ApplicationContext</code>。</font>为了获得业务服务，我使用在 (2) 处获得的环境在 (3) 处查找一个 Spring bean。</font></p>
<p><font size="2">这
种技术很简单并且易于理解。不幸的是，它将 Struts 动作与 Spring 框架耦合在一起。如果您想替换掉
Spring，那么您必须重写代码。并且，由于 Struts 动作不在 Spring 的控制之下，所以它不能获得 Spring AOP
的优势。当使用多重独立的 Spring 环境时，这种技术可能有用，但是在大多数情况下，这种方法不如另外两种方法合适。</font></p>
<font size="2"><br>
</font>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody><tr><td><font size="2"><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></font></td></tr></tbody>
</table>
<table class="no-print" align="right" cellpadding="0" cellspacing="0">
<tbody><tr align="right"><td><font size="2"><br>
      </font></td></tr></tbody>
</table>
<font size="2"><br>
<br>
</font>
<p><font size="2"><a name="IDA0A4W"><span class="atitle">窍门 2. 覆盖 RequestProcessor</span></a></font></p>
<p><font size="2">将 Spring 从 Struts 动作中分离是一个更巧妙的设计选择。分离的一种方法是使用 <font size="3"><code>org.springframework.web.struts.DelegatingRequestProcessor</code></font> 类来覆盖 Struts 的<font size="3"> <code>RequestProcessor</code> </font>处理程序，如清单 2 所示：</font></p>
<font size="2"><br>
<a name="IDANB4W"><b>清单 2. 通过 Spring 的 DelegatingRequestProcessor 进行整合</b></a><br>
</font>
<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
<tbody><tr><td><pre><font size="2"><code class="section"><br><font size="3">&lt;?xml version="1.0" encoding="ISO-8859-1" ?&gt;<br><br>&lt;!DOCTYPE struts-config PUBLIC<br>          "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"<br>          "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"&gt;<br><br>&lt;struts-config&gt;<br> &lt;form-beans&gt;<br>    &lt;form-bean name="searchForm" <br>      type="org.apache.struts.validator.DynaValidatorForm"&gt;<br>               &lt;form-property name="isbn"    type="java.lang.String"/&gt;<br>    &lt;/form-bean&gt;<br>  <br>  &lt;/form-beans&gt;<br><br> &lt;global-forwards type="org.apache.struts.action.ActionForward"&gt;<br>     &lt;forward   name="welcome"                path="/welcome.do"/&gt;<br>     &lt;forward   name="searchEntry"            path="/searchEntry.do"/&gt;<br>     &lt;forward   name="searchSubmit"           path="/searchSubmit.do"/&gt;<br> &lt;/global-forwards&gt;<br><br> &lt;action-mappings&gt;<br>    &lt;action    path="/welcome" forward="/WEB-INF/pages/welcome.htm"/&gt;<br>    &lt;action    path="/searchEntry" forward="/WEB-INF/pages/search.jsp"/&gt;<br>    &lt;action    path="/searchSubmit" <br>               type="ca.nexcel.books.actions.SearchSubmit"<br>               input="/searchEntry.do"<br>               validate="true"<br>               name="searchForm"&gt;<br>              &lt;forward name="success" path="/WEB-INF/pages/detail.jsp"/&gt;<br>              &lt;forward name="failure" path="/WEB-INF/pages/search.jsp"/&gt;<br>    &lt;/action&gt;  <br><br> &lt;/action-mappings&gt;<br><br> &lt;message-resources parameter="ApplicationResources"/&gt;<br><br> &lt;controller processorClass="org.springframework.web.struts.<br>   DelegatingRequestProcessor"/&gt; <span class="boldcode">|(1)</span><br><br> &lt;plug-in className="org.apache.struts.validator.ValidatorPlugIn"&gt;<br>    &lt;set-property property="pathnames" <br>      value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/&gt;<br> &lt;/plug-in&gt;<br><br><br> &lt;plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"&gt;<br>    &lt;set-property property="csntextConfigLocation" value="/WEB-INF/beans.xml"/&gt;<br> &lt;/plug-in&gt;<br> <br>&lt;/struts-config&gt;</font><br></code></font></pre></td></tr></tbody>
</table>
<font size="2"><br>
</font>
<p><font size="2">我利用了<font size="3"> <code>&lt;controller&gt;</code></font> 标记来用 <font size="3"><code>DelegatingRequestProcessor</code> </font>覆盖默认的 Struts <font size="3"><code>RequestProcessor</code>。</font>下一步是在我的 Spring 配置文件中注册该动作，如清单 3 所示：</font></p>
<font size="2"><br>
<a name="IDAGC4W"><b>清单 3. 在 Spring 配置文件中注册一个动作</b></a><br>
</font>
<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
<tbody><tr><td><pre><font size="2"><code class="section"><br><font size="3">&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br>&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" <br>  "http://www.springframework.org/dtd/spring-beans.dtd"&gt;<br><br>&lt;beans&gt;<br>  &lt;bean id="bookService" class="ca.nexcel.books.business.BookServiceImpl"/&gt;<br><br>  &lt;bean name="/searchSubmit" <br>    class="ca.nexcel.books.actions.SearchSubmit"&gt; <span class="boldcode">|(1)</span><br>     &lt;property name="bookService"&gt;<br>        &lt;ref bean="bookService"/&gt;<br>     &lt;/property&gt;<br>  &lt;/bean&gt;<br>&lt;/beans&gt;</font><br></code></font></pre></td></tr></tbody>
</table>
<font size="2"><br>
</font>
<p><font size="2">注意：在 (1) 处，我使用名称属性注册了一个 bean，以匹配 struts-config 动作映射名称。<code>SearchSubmit</code> 动作揭示了一个 JavaBean 属性，允许 Spring 在运行时填充属性，如清单 4 所示：</font></p>
<font size="2"><br>
<a name="IDAXC4W"><b>清单 4. 具有 JavaBean 属性的 Struts 动作</b></a><br>
</font>
<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
<tbody><tr><td><pre><font size="2"><code class="section"><br><font size="3">package ca.nexcel.books.actions;<br><br>import java.io.IOException;<br><br>import javax.servlet.ServletException;<br>import javax.servlet.http.HttpServletRequest;<br>import javax.servlet.http.HttpServletResponse;<br><br>import org.apache.struts.action.Action;<br>import org.apache.struts.action.ActionError;<br>import org.apache.struts.action.ActionErrors;<br>import org.apache.struts.action.ActionForm;<br>import org.apache.struts.action.ActionForward;<br>import org.apache.struts.action.ActionMapping;<br>import org.apache.struts.action.DynaActionForm;<br><br>import ca.nexcel.books.beans.Book;<br>import ca.nexcel.books.business.BookService;<br><br>public class SearchSubmit extends Action {<br>	<br>  private BookService bookService;<br>  public BookService getBookService() {<br>    return bookService;<br>  }<br><br>  public void setBookService(BookService bookService) { <span class="boldcode">| (1)</span><br>    this.bookService = bookService; <br>  } <br><br>  public ActionForward execute(<br>    ActionMapping mapping,<br>    ActionForm form,<br>    HttpServletRequest request,<br>    HttpServletResponse response)<br>    throws IOException, ServletException {<br><br>    DynaActionForm searchForm = (DynaActionForm) form;<br>    String isbn = (String) searchForm.get("isbn");<br>		<br>  Book book = getBookService().read(isbn.trim());  <span class="boldcode">|(2)</span><br><br>    if (null == book) {<br>      ActionErrors errors = new ActionErrors();<br>      errors.add(ActionErrors.GLOBAL_ERROR,new ActionError("message.notfound"));<br>      saveErrors(request, errors);<br>      return mapping.findForward("failure") ;<br>  }<br><br>      request.setAttribute("book", book);<br>      return mapping.findForward("success");<br>  }<br><br>}</font><br></code></font></pre></td></tr></tbody>
</table>
<font size="2"><br>
</font>
<p><font size="2">在清单 4 中，您可以了解到如何创建 Struts 动作。在 (1) 处，我创建了一个 JavaBean 属性。<code>DelegatingRequestProcessor</code>自
动地配置这种属性。这种设计使 Struts 动作并不知道它正被 Spring 管理，并且使您能够利用 Sping
的动作管理框架的所有优点。由于您的 Struts 动作注意不到 Spring 的存在，所以您不需要重写您的 Struts
代码就可以使用其他控制反转容器来替换掉 Spring。</font></p>
<p><font size="2"><font size="3"><code>DelegatingRequestProcessor</code> </font>方法的确比第一种方法好，但是仍然存在一些问题。如果您使用一个不同的 <font size="3"><code>RequestProcessor</code>，</font>则需要手动整合 Spring 的 <font size="3"><code>DelegatingRequestProcessor</code>。</font>添加的代码会造成维护的麻烦并且将来会降低您的应用程序的灵活性。此外，还有过一些使用一系列命令来代替 Struts <font size="3"><code>RequestProcessor</code> </font>的传闻。 这种改变将会对这种解决方法的使用寿命造成负面的影响。</font></p>
<font size="2"><br>
</font>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody><tr><td><font size="2"><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></font></td></tr></tbody>
</table>
<table class="no-print" align="right" cellpadding="0" cellspacing="0">
<tbody><tr align="right"><td><font size="2"><br>
      </font></td></tr></tbody>
</table>
<font size="2"><br>
<br>
</font>
<p><font size="2"><a name="IDAYD4W"><span class="atitle">窍门 3. 将动作管理委托给 Spring</span></a></font></p>
<p><font size="2">一个更好的解决方法是将 Strut 动作管理委托给 Spring。您可以通过在 <code>struts-config</code> 动作映射中注册一个代理来实现。代理负责在 Spring 环境中查找 Struts 动作。由于动作在 Spring 的控制之下，所以它可以填充动作的 JavaBean 属性，并为应用诸如 Spring 的 AOP 拦截器之类的特性带来了可能。
</font></p>
<p><font size="2">清单 5 中的 <code>Action</code> 类与清单 4 中的相同。但是 struts-config 有一些不同：</font></p>
<font size="2"><br>
<a name="IDANE4W"><b>清单 5. Spring 整合的委托方法</b></a><br>
</font>
<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
<tbody><tr><td><pre><font size="2"><code class="section"><br><font size="3">&lt;?xml version="1.0" encoding="ISO-8859-1" ?&gt;<br><br>&lt;!DOCTYPE struts-config PUBLIC<br>          "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"<br>          "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"&gt;<br><br>&lt;struts-config&gt;<br> &lt;form-beans&gt;<br>    &lt;form-bean name="searchForm" <br>      type="org.apache.struts.validator.DynaValidatorForm"&gt;<br>               &lt;form-property name="isbn"    type="java.lang.String"/&gt;<br>    &lt;/form-bean&gt;<br>  <br>  &lt;/form-beans&gt;<br><br> &lt;global-forwards type="org.apache.struts.action.ActionForward"&gt;<br>     &lt;forward   name="welcome"                path="/welcome.do"/&gt;<br>     &lt;forward   name="searchEntry"            path="/searchEntry.do"/&gt;<br>     &lt;forward   name="searchSubmit"           path="/searchSubmit.do"/&gt;<br> &lt;/global-forwards&gt;<br><br> &lt;action-mappings&gt;<br>    &lt;action    path="/welcome" forward="/WEB-INF/pages/welcome.htm"/&gt;<br>    &lt;action    path="/searchEntry" forward="/WEB-INF/pages/search.jsp"/&gt;<br>    &lt;action    path="/searchSubmit" <br>             type="org.springframework.web.struts.DelegatingActionProxy" <span class="boldcode">|(1)</span><br>             input="/searchEntry.do"<br>             validate="true"<br>             name="searchForm"&gt;<br>             &lt;forward name="success" path="/WEB-INF/pages/detail.jsp"/&gt;<br>             &lt;forward name="failure" path="/WEB-INF/pages/search.jsp"/&gt;<br>    &lt;/action&gt;  <br><br> &lt;/action-mappings&gt;<br><br> &lt;message-resources parameter="ApplicationResources"/&gt;<br><br><br> &lt;plug-in className="org.apache.struts.validator.ValidatorPlugIn"&gt;<br>    &lt;set-property <br>    property="pathnames" <br>    value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/&gt;<br> &lt;/plug-in&gt;<br><br><br> &lt;plug-in <br>    className="org.springframework.web.struts.ContextLoaderPlugIn"&gt;<br>    &lt;set-property property="contextConfigLocation" value="/WEB-INF/beans.xml"/&gt;<br> &lt;/plug-in&gt;<br><br> <br>&lt;/struts-config&gt;</font><br></code></font></pre></td></tr></tbody>
</table>
<font size="2"><br>
</font>
<p><font size="2">清单 5 是一个典型的
struts-config.xml 文件，只有一个小小的差别。它注册 Spring
代理类的名称，而不是声明动作的类名，如（1）处所示。DelegatingActionProxy 类使用动作映射名称查找 Spring
环境中的动作。这就是我们使用 <code>ContextLoaderPlugIn</code> 声明的环境。</font></p>
<p><font size="2">将一个 Struts 动作注册为一个 Spring bean 是非常直观的，如清单 6 所示。我利用动作映射使用 <code>&lt;bean&gt;</code> 标记的名称属性（在这个例子中是 "<code>/searchSubmit</code>"）简单地创建了一个 bean。这个动作的 JavaBean 属性像任何 Spring bean 一样被填充：
</font></p>
<font size="2"><br>
<a name="IDAIF4W"><b>清单 6. 在 Spring 环境中注册一个 Struts 动作</b></a><br>
</font>
<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
<tbody><tr><td><pre><font size="2"><code class="section"><br><font size="3">&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br>&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" <br> "http://www.springframework.org/dtd/spring-beans.dtd"&gt;<br><br>&lt;beans&gt;<br>  &lt;bean id="bookService" class="ca.nexcel.books.business.BookServiceImpl"/&gt;<br><br>  &lt;bean name="/searchSubmit"   <br>        class="ca.nexcel.books.actions.SearchSubmit"&gt;<br>     &lt;property name="bookService"&gt;<br>        &lt;ref bean="bookService"/&gt;<br>     &lt;/property&gt;<br>  &lt;/bean&gt;<br><br>&lt;/beans&gt;</font><br></code></font></pre></td></tr></tbody>
</table>
<font size="2"><br>
<br>
</font>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody><tr><td><font size="2"><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></font></td></tr></tbody>
</table>
<table class="no-print" align="right" cellpadding="0" cellspacing="0">
<tbody><tr align="right"><td><font size="2"><br>
      </font></td></tr></tbody>
</table>
<font size="2"><br>
<br>
</font>
<p><font size="2"><a name="IDAOF4W"><span class="atitle">动作委托的优点</span></a></font></p>
<p><font size="2">动作委托解决方法是这三种方法中最好的。Struts 动作不了解 Spring，不对代码作任何改变就可用于非 Spring 应用程序中。<font size="3"><code>RequestProcessor</code> </font>的改变不会影响它，并且它可以利用 Spring AOP 特性的优点。
</font></p>
<p><font size="2">动作委托的优点不止如此。一旦让 Spring 控制您的 Struts 动作，您就可以使用 Spring 给动作补充更强的活力。例如，没有 Spring 的话，所有的 Struts 动作都必须是线程安全的。如果您设置 <code>&lt;bean&gt;</code>
标记的 singleton
属性为“false”，那么不管用何种方法，您的应用程序都将在每一个请求上有一个新生成的动作对象。您可能不需要这种特性，但是把它放在您的工具箱中也
很好。您也可以利用 Spring 的生命周期方法。例如，当实例化 Struts 动作时，<code>&lt;bean&gt;</code> 标记的 init-method 属性被用于运行一个方法。类似地，在从容器中删除 bean 之前，destroy-method 属性执行一个方法。这些方法是管理昂贵对象的好办法，它们以一种与 Servlet 生命周期相同的方式进行管理。</font></p>
<font size="2"><br>
</font>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody><tr><td><font size="2"><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></font></td></tr></tbody>
</table>
<table class="no-print" align="right" cellpadding="0" cellspacing="0">
<tbody><tr align="right"><td><font size="2"><br>
      </font></td></tr></tbody>
</table>
<font size="2"><br>
<br>
</font>
<p><font size="2"><a name="IDAEG4W"><span class="atitle">拦截 Struts</span></a></font></p>
<p><font size="2">前
面提到过，通过将 Struts 动作委托给 Spring 框架而整合 Struts 和 Spring 的一个主要的优点是：您可以将
Spring 的 AOP 拦截器应用于您的 Struts 动作。通过将 Spring 拦截器应用于 Struts
动作，您可以用最小的代价处理横切关注点。</font></p>
<p><font size="2">虽然 Spring 提供很多内置拦截器，但是我将向您展示如何创建自己的拦截器并把它应用于一个 Struts 动作。为了使用拦截器，您需要做三件事：</font></p>
<ol>
<li><font size="2">创建拦截器。</font></li><li><font size="2">注册拦截器。</font></li><li><font size="2">声明在何处拦截代码。</font></li>
</ol>
<p><font size="2">这看起来非常简单的几句话却非常强大。例如，在清单 7 中，我为 Struts 动作创建了一个日志记录拦截器。 
这个拦截器在每个方法调用之前打印一句话：</font></p>
<font size="2"><br>
<a name="IDAUG4W"><b>清单 7. 一个简单的日志记录拦截器</b></a><br>
</font>
<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
<tbody><tr><td><pre><font size="2"><code class="section"><br><font size="3">package ca.nexcel.books.interceptors;<br><br>import org.springframework.aop.MethodBeforeAdvice;<br><br>import java.lang.reflect.Method;<br><br>public class LoggingInterceptor implements MethodBeforeAdvice {<br><br>   public void before(Method method, Object[] objects, Object o) throws Throwable {<br>        System.out.println("logging before!");<br>    }<br>}</font><br></code></font></pre></td></tr></tbody>
</table>
<font size="2"><br>
</font>
<p><font size="2">这个拦截器非常简单。<code>before()</code> 方法在拦截点中每个方法之前运行。在本例中，它打印出一句话，其实它可以做您想做的任何事。下一步就是在 Spring 配置文件中注册这个拦截器，如清单 8 所示：</font></p>
<font size="2"><br>
<a name="IDADH4W"><b>清单 8. 在 Spring 配置文件中注册拦截器</b></a><br>
</font>
<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
<tbody><tr><td><pre><font size="2"><code class="section"><br><font size="3">&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br>&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" <br>  "http://www.springframework.org/dtd/spring-beans.dtd"&gt;<br><br>&lt;beans&gt;<br>  &lt;bean id="bookService" class="ca.nexcel.books.business.BookServiceImpl"/&gt;<br><br>  &lt;bean name="/searchSubmit" <br>        class="ca.nexcel.books.actions.SearchSubmit"&gt;<br>     &lt;property name="bookService"&gt;<br>        &lt;ref bean="bookService"/&gt;<br>     &lt;/property&gt;<br>  &lt;/bean&gt;<br><br>  &lt;!--  Interceptors --&gt; <br>  &lt;bean name="logger"    <br>    class="ca.nexcel.books.interceptors.LoggingInterceptor"/&gt; <span class="boldcode">|(1)</span><br><br>  &lt;!-- AutoProxies --&gt;<br>  &lt;bean name="loggingAutoProxy" <br>        class="org.springframework.aop.framework.autoproxy.<br>          BeanNameAutoProxyCreator"&gt; <span class="boldcode">|(2)</span><br>    &lt;property name="beanNames"&gt;<br>          &lt;value&gt;/searchSubmit&lt;/valuesgt; <span class="boldcode">|(3)</span><br>    &lt;/property&gt;<br>    &lt;property name="interceptorNames"&gt;<br>        &lt;list&gt;<br>          &lt;value&gt;logger&lt;/value&gt; <span class="boldcode">|(4)</span><br>        &lt;/list&gt;<br>    &lt;/property&gt;<br>   &lt;/bean&gt;<br><br>&lt;/beans&gt;</font><br></code></font></pre></td></tr></tbody>
</table>
<font size="2"><br>
</font>
<p><font size="2">您可能已经注意到了，清单 8 扩展了 <a href="http://www-128.ibm.com/developerworks/cn/java/j-sr2.html#code6">清单 6</a> 中所示的应用程序以包含一个拦截器。具体细节如下：</font></p>
<ul>
<li><font size="2">在 (1) 处，我注册了这个拦截器。</font></li><li><font size="2">在 (2) 处，我创建了一个 bean 名称自动代理，它描述如何应用拦截器。还有其他的方法定义拦截点，但是这种方法常见而简便。</font></li><li><font size="2">在 (3) 处，我将 Struts 动作注册为将被拦截的 bean。如果您想要拦截其他的 Struts 动作，则只需要在 "beanNames" 下面创建附加的 <code>&lt;value&gt;</code> 标记。</font></li><li><font size="2">在 (4) 处，当拦截发生时，我执行了在 (1) 处创建的拦截器 bean 的名称。这里列出的所有拦截器都应用于“beanNames”。</font></li>
</ul>
<p><font size="2">就是这样。就像这个例子所展示的，将您的 Struts 动作置于 Spring 框架的控制之下，为处理您的 Struts 应用程序提供了一系列全新的选择。在本例中，使用动作委托可以轻松地利用 Spring 拦截器提高 Struts 应用程序中的日志记录能力。</font></p>
<font size="2"><br>
</font>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody><tr><td><font size="2"><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></font></td></tr></tbody>
</table>
<table class="no-print" align="right" cellpadding="0" cellspacing="0">
<tbody><tr align="right"><td><font size="2"><br>
      </font></td></tr></tbody>
</table>
<font size="2"><br>
<br>
</font>
<p><font size="2"><a name="IDAFI4W"><span class="atitle">结束语</span></a></font></p>
<p><font size="2">在本文中，您已经学习了将 Struts 动作整合到 Spring 框架中的三种窍门。使用 Spring 的 <font size="3"><code>ActionSupport</code> </font>来整合 Struts（第一种窍门中就是这样做的）简单而快捷，但是会将 Struts 动作与 Spring 框架耦合在一起。如果您需要将应用程序移植到一个不同的框架，则需要重写代码。第二种解决方法通过委托 <font size="3"><code>RequestProcessor</code>
</font>巧妙地解开代码的耦合，但是它的可扩展性不强，并且当 Struts 的 <font size="3"><code>RequestProcessor</code></font></font><font size="3"> </font>变成一系列命令时，这种方法就持续不了很长时间。第三种方法是这三种方法中最好的：将 Struts 动作委托给 Spring 框架可以使代码解耦，从而使您可以在您的 Struts 应用程序中利用 Spring 的特性（比如日志记录拦截器）。</p>
<p><font size="2">三种 Struts-Spring 整合窍门中的每一种都被实现成一个完整可用的应用程序。请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-sr2.html#download">下载</a> 部分仔细研究它们。</font></p>
<font size="2"><br>
<br>
</font>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody><tr><td><font size="2"><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></font></td></tr></tbody>
</table>
<table style="width: 1px; height: 20px;" class="no-print" align="right" cellpadding="0" cellspacing="0">
<tbody><tr align="right"><td><font size="2"><br>
      </font></td></tr><tr>
      <td style="vertical-align: top;"><font size="2"><br>
      </font></td>
    </tr>
</tbody>
</table>
<font size="2"><br>
<span class="atitle"><a name="download">下载</a></span></font>
<table class="data-table-1" border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody><tr><th><font size="2">描述</font></th><th><font size="2">名字</font></th><th style="text-align: right;"><font size="2">大小</font></th><th><font size="2">&nbsp;下载方法</font></th></tr><tr><td class="tb-row"><font size="2">ActionSupport sample code</font></td><td nowrap="nowrap"><font size="2">j-sr2-actionsupport.zip</font></td><td style="text-align: right;" nowrap="nowrap"><font size="2">5 MB</font></td><td nowrap="nowrap"><font size="2">
&nbsp;<a class="fbox" href="ftp://www6.software.ibm.com/software/developer/library/j-sr2-actionsupport.zip"><b>FTP</b></a></font></td></tr><tr><td class="tb-row"><font size="2">RequestProcessor  sample code</font></td><td nowrap="nowrap"><font size="2">j-sr2-requestprocessor.zip</font></td><td style="text-align: right;" nowrap="nowrap"><font size="2">5 MB</font></td><td nowrap="nowrap"><font size="2">
&nbsp;<a class="fbox" href="ftp://www6.software.ibm.com/software/developer/library/j-sr2-requestprocessor.zip"><b>FTP</b></a></font></td></tr><tr><td class="tb-row"><font size="2">Delegate sample code</font></td><td nowrap="nowrap"><font size="2">j-sr2-delegate.zip</font></td><td style="text-align: right;" nowrap="nowrap"><font size="2">5 MB</font></td><td nowrap="nowrap"><font size="2">
&nbsp;<a class="fbox" href="ftp://www6.software.ibm.com/software/developer/library/j-sr2-delegate.zip"><b>FTP</b></a></font></td></tr></tbody>
</table>
<img src ="http://www.blogjava.net/DenisLing/aggbug/20779.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/DenisLing/" target="_blank">DenisLing</a> 2005-11-21 15:42 <a href="http://www.blogjava.net/DenisLing/archive/2005/11/21/20779.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>