7.3. simple-model模块

大多数企业项目需要做的第一件事情是建立对象模型。一个对象模型抓取了系统中一组核心的领域对象。一个银行系统可能会有包括AccountCustomerTransaction 的对象模型。或者有一个对体育比赛比分建模的系统,有一个Team和一个Game对象。不管它是什么,你都需要将你系统中的概念建模成对象模型。在Maven项目中,将这个对象模型分割成单独的项目以被广泛引用,是一种常用的实践。在我们这个系统中,我们将每个对Yahoo! Weather数据源的查询建模成为Weather对象,它本身又引用了四个其它的对象。风向,风速等存储Wind在对象中。地址信息包括邮编,城市等信息存储在Location类中。大气信息如湿度,可见度,气压等存储在Atmosphere类中。而对环境,气温,以及观察日期的文本描述存储在Condition类中。

天气数据的简单对象模型

Figure 7.2. 天气数据的简单对象模型


这个简单对象模型的pom.xml文件含有一个依赖需要一些解释。我们的对象模型用Hibernate标注符标注了。我们用这些标注来映射模型对象至关系数据库中的表。这个依赖是org.hibernate:hibernate-annotations:3.3.0.ga。看一下Example 7.2, “simple-model 的 pom.xml”中显示的pom.xml,然后看接下来几个展示这些标注的例子。

Example 7.2. simple-model 的 pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                      http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.sonatype.mavenbook.ch07</groupId>
    <artifactId>simple-parent</artifactId>
    <version>1.0</version>
  </parent>
  <artifactId>simple-model</artifactId>
  <packaging>jar</packaging>

  <name>Simple Object Model</name>

  <dependencies>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-annotations</artifactId>
      <version>3.3.0.ga</version>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-commons-annotations</artifactId>
      <version>3.3.0.ga</version>
    </dependency>
  </dependencies>
</project>

src/main/java/org/sonatype/mavenbook/weather/model中,有Weather.java,它是一个标注过的Weather型对象。这个Weather对象是一个简单的Java bean。这意味着它的私有成员变量如id, location, condition, wind, atmosphere, 和 date,通过公共的getter和setter方法暴露,并且遵循这样的模式:如果一个属性名为name,那么会有一个公有的无参数方法getName(),还有一个带有一个参数的setter方法setName(String name)。我们只是展示了id属性的getter和setter方法,其它属性的getter和setter方法类似,所以这里跳过了,以节省篇幅。请看Example 7.3, “标注的Weather模型对象”


Example 7.3. 标注的Weather模型对象

package org.sonatype.mavenbook.weather.model;

import javax.persistence.*;

import java.util.Date;

@Entity
@NamedQueries({
  @NamedQuery(name="Weather.byLocation", 
              query="from Weather w where w.location = :location")
})
public class Weather {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;

    @ManyToOne(cascade=CascadeType.ALL)
    private Location location;

    @OneToOne(mappedBy="weather",cascade=CascadeType.ALL)
    private Condition condition;

    @OneToOne(mappedBy="weather",cascade=CascadeType.ALL)
    private Wind wind;

    @OneToOne(mappedBy="weather",cascade=CascadeType.ALL)
    private Atmosphere atmosphere;

    private Date date;
    
    public Weather() {}

    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }

    // All getter and setter methods omitted...
}

Weather类中,我们使用Hibernate标注以为simple-persist项目提供指导。这些标注由Hibernate用来将对象与关系数据库映射。尽管对HIberante标注的完整解释超出了本书的范围,这里是一个为好奇者的简单解释。@Entity标注标记一个类为持久化对象。我们省略了这个类的@Table标注,因此Hibernate将会使用这个类的名字来映射表名。@NamedQueries注解定义了一个simple-persistWeatherDAO使用的查询。@NamedQuery注解中的查询语句是用一个叫做Hibernate查询语言(HQL)编写的。每个成员变量的注解定义了这一列的类型,以及该列暗示的表关联关系。

Id

id属性用@Id进行标注。这标记id属性为一个包含数据库表主键的属性。@GeneratedValue控制新的主键值如何产生。该例中,我们使用IDENTITY GenerationType,它使用了下层数据库的主键生成设施。

Location

每个Weather对象实例对应了一个Location对象。一个Location对象含有一个邮政编码,而@ManyToOne确认所有指向同一个Location对象的Weather对象引用了同样一个实例。@ManyToOnecascade属性确保每次我们持久化一个Weather对象的时候也会持久化一个Location对象。

Condition, Wind, Atmosphere

这些对象的每一个都作为@OneToOne而且CascadeTypeALL进行映射。这意味着每次我们保存一个Weather对象,我们将会往Weather表,Condition表,Wind表,和Atmosphere表,插入一行,

Date

Date没有被标注,这以为着Hibernate将会使用所有列的默认值来定义该映射。列名将会是date,列的类型会是匹配Date对象的适当时间。

Note

如果你有一个希望从表映射中忽略的属性,你可以使用@Transient标注这个属性。

接着,看一下一个二级的模型对象,Condition,如Example 7.4, “simple-model 的 Condition 模型对象”所示。这个类同样也存在于src/main/java/org/sonatype/mavenbook/weather/model

Example 7.4. simple-model 的 Condition 模型对象

package org.sonatype.mavenbook.weather.model;

import javax.persistence.*;

@Entity
public class Condition {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;

    private String text;
    private String code;
    private String temp;
    private String date;

    @OneToOne(cascade=CascadeType.ALL)
    @JoinColumn(name="weather_id", nullable=false)
    private Weather weather;

    public Condition() {}

    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }

    // All getter and setter methods omitted...
}

这个Condition类类似于Weather类。它被标注为一个@Entity,在id属性上也有相似的标注。textcodetemp,和date属性也都使用默认的列设置,weather属性使用了@OneToOne进行标注,而另一个标注通过一个名为weather_id的外键引用关联的Weather对象。