18. 基于三层架构的 MVC Web 应用程序 – 示例 4,Postgres
18.1. Postgres 数据库
在此版本中,我们将人员列表存储在 Postgres 数据库表 8.x [http://www.postgres.org] 中。 下文中的屏幕截图来自 EMS PostgreSQL Manager Lite [http://www.sqlmanager.net/fr/products/postgresql/manager] 客户端,这是一个免费的 Postgres 管理客户端。
该数据库名为 [dbpersonnes]。其中包含一个名为 [PERSONNES] 的表:

表 [PERSONNES] 将包含由 Web 应用程序管理的人员列表。该表是通过以下 SQL 命令构建的:
我们不再赘述该表,因其与前文探讨的 Firebird 类型表 [PERSONNES] 类似。 但需注意,列名和表名均需用引号括起。此外,这些名称区分大小写。Postgres 8.x 的这种工作模式可能支持配置,但我尚未深入研究。
表 [PERSONNES] 的内容可能如下:

除了表 [PERSONNES] 之外,数据库 [dbpersonnes] 还包含一个名为 [SEQ_ID] 的序列对象。 该生成器会输出连续的整数,我们将利用这些整数为类 [PERSONNES] 的主键 [ID] 赋值。下面通过一个示例来说明其工作原理:
![]() |
![]() |
我们可以发现,序列 [SEQ_ID] 中的值 [Next value] 已发生变化(双击该值 + F5 以刷新):
![]() |
订单 SQL
因此,序列 [SEQ_ID] 的值如下。我们将它用于文件 [personnes-postgres.xml] 中,该文件汇总了在 SGBD 上发出的 SQL 命令。
18.2. [dao] 和 [service] 层的 Eclipse 项目
为了开发我们应用程序中基于 Postgres 数据库 8.x 的 [dao] 和 [service] 层,我们将使用以下 Eclipse 项目 [spring-mvc-39]:

该项目是一个简单的 Java 项目,并非 Tomcat Web 项目。
文件夹 [src]
该文件夹包含 [dao] 和 [service] 层的源代码:

所有文件名中包含 [postgres] 的文件,相对于 Firebird 版本可能已进行修改,也可能未作修改。下文将描述已修改的文件。
[database] 文件夹
该文件夹包含用于创建人员 Postgres 数据库的脚本:
![]()
文件夹 [lib]
该文件夹包含应用程序所需的存档文件:
![]() |
值得注意的是,其中包含 SGBD Postgres 8.x 的 JDBC 驱动程序。所有这些存档文件均属于 Eclipse 项目的 Classpath 目录。
18.3. [dao] 层
[dao] 层如下:

我们仅列出与 [Firebird] 版本相比的变更内容。
映射文件 [personne-postgres.xml] 如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap
PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-2.dtd">
<!-- 注意 - PostgreSQL 8 要求列名拼写完全一致
et des tables ainsi que des guillemets autour de ces noms -->
<sqlMap>
<!-- 别名类 [Personne] -->
<typeAlias alias="Personne.classe"
type="istia.st.mvc.personnes.entites.Personne"/>
<!-- 映射表 [PERSONNES] - 对象 [Personne] -->
<resultMap id="Personne.map"
class="istia.st.mvc.personnes.entites.Personne">
<result property="id" column="ID" />
<result property="version" column="VERSION" />
<result property="nom" column="NOM"/>
<result property="prenom" column="PRENOM"/>
<result property="dateNaissance" column="DATENAISSANCE"/>
<result property="marie" column="MARIE"/>
<result property="nbEnfants" column="NBENFANTS"/>
</resultMap>
<!-- 所有人员的列表 -->
<select id="Personne.getAll" resultMap="Personne.map" > select "ID",
"VERSION", "NOM", "PRENOM", "DATENAISSANCE", "MARIE", "NBENFANTS" FROM
"PERSONNES"</select>
<!-- 获取特定人员 -->
<select id="Personne.getOne" resultMap="Personne.map" >select "ID",
"VERSION", "NOM", "PRENOM", "DATENAISSANCE", "MARIE", "NBENFANTS" FROM
"PERSONNES" WHERE "ID"=#值#</select>
<!-- 添加人员 -->
<insert id="Personne.insertOne" parameterClass="Personne.classe">
<selectKey keyProperty="id">
SELECT nextval('"SEQ_ID"') as value
</selectKey>
insert into "PERSONNES"("ID", "VERSION",
"NOM", "PRENOM", "DATENAISSANCE", "MARIE", "NBENFANTS") VALUES(#id#,
#版本#, #姓#, #名#, #dateNaissance#, #已婚#, #nbEnfants#)
</insert>
<!-- 更新人员信息 -->
<update id="Personne.updateOne" parameterClass="Personne.classe"> update
"PERSONNES" set "VERSION"=#版本号#+1, "NOM"=#姓#, "PRENOM"=#名#,
"DATENAISSANCE"=#dateNaissance#, "MARIE"=#marie#, "NBENFANTS"=#nbEnfants#
WHERE "ID"=#id# 以及 "VERSION"=#version#</update>
<!-- 删除某人 -->
<delete id="Personne.deleteOne" parameterClass="int"> delete FROM
"PERSONNES" WHERE "ID"=#value# </delete>
</sqlMap>
其内容与 [personnes-firebird.xml] 相同,仅存在以下细微差异:
- 列名和表名均用引号括起,且区分大小写
- 第 34-41 行中的顺序 SQL " Personne.insertOne " 已更改。Postgres 生成主键的方式与 Firebird 不同:
- 第 36 行:顺序 SQL [SELECT nextval('"SEQ_ID"')] 生成主键。必须使用 [as value] 这种语法。[value] 代表生成的主键。 该值将被赋给由属性 [keyProperty](第 35 行)指定的 [Personne] 对象的字段,此处即字段 [id]。
- <insert>标签中的SQL指令将按其出现的顺序执行。因此,SELECT将在INSERT之前执行。 在插入操作进行时,对象 [Personne] 的字段 [id] 因此已被命令 SQL SELECT 更新。
- 第 38-40 行:插入对象 [Personne]
[dao] 层中的实现类 [DaoImplCommon] 即为 [Firebird] 版本中所研究的对象。
[dao] 层的配置已调整为 SGBD [Postgres]。因此,[spring-config-test-dao-postgres.xml] 配置文件如下:
<?xml version="1.0" encoding="ISO_8859-1"?>
<!DOCTYPE beans SYSTEM "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- 数据源 DBCP -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>org.postgresql.Driver</value>
</property>
<property name="url">
<value>jdbc:postgresql:dbpersonnes</value>
</property>
<property name="username">
<value>postgres</value>
</property>
<property name="password">
<value>postgres</value>
</property>
</bean>
<!-- SqlMapCllient -->
<bean id="sqlMapClient"
class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="dataSource">
<ref local="dataSource"/>
</property>
<property name="configLocation">
<value>classpath:sql-map-config-postgres.xml</value>
</property>
</bean>
<!-- 访问 [dao] 层的类 -->
<bean id="dao" class="istia.st.mvc.personnes.dao.DaoImplCommon">
<property name="sqlMapClient">
<ref local="sqlMapClient"/>
</property>
</bean>
</beans>
- 第 5-19 行: Bean [dataSource] 现指向数据库 [Postgres] [dbpersonnes],其管理员为 [postgres],密码为 [postgres]。 读者应根据自身环境修改此配置。
- 第 31 行:类 [DaoImplCommon] 是 [dao] 层的实现类
完成这些修改后,即可进行测试。
18.4. [dao] 和 [service] 层的测试
[dao] 和 [service] 层的测试与 [Firebird] 版本相同。先运行 SGBD Postgres,然后运行 Eclipse 测试。所得结果如下:
![]() |
可以看出,使用 [DaoImplCommon] 实现时,测试已成功通过。我们无需像处理 SGBD 和 [Firebird] 时那样,对该类进行派生。
18.5. [web] 应用程序测试
为了测试基于 SGBD 和 [Postgres] 的 Web 应用程序, 我们构建了一个 Eclipse 项目 [mvc-personnes-04B],其方法与构建基于 Firebird 数据库的 [mvc-personnes-03B] 项目类似(参见第 17.7 节)。 不过,我们无需重新生成 [personnes-dao.jar] 和 [personnes-service.jar] 归档文件。 事实上,我们并未修改 [mvc-personnes-03B] 项目中的任何类。只是 [personnes-dao.jar] 归档文件中包含的 [DaoImplFirebird] 类已变得不再需要。

我们将 Web 项目 [mvc-personnes-04B] 部署到 Tomcat 中:
![]() | ![]() |
现在可以进行 测试了。此时表[PERSONNES]的内容如下:

Tomcat已启动。通过浏览器,我们访问URL [http://localhost:8080/mvc-personnes-04B]:

我们通过 通过链接 [Ajout] 添加一名新用户:
![]() | ![]() |
我们在数据库中验证新增记录:

请读者进行其他测试:[modification, suppression]。








