Spring Boot 之 Spring Data JPA(一)

今天,我们用一个最简单的例子上手Spring Data JPA的开发。

1、新建工程

首先,我们使用STS建一个工程:


Paste_Image.png

这里我们示例使用H2数据库,主要是因为简单,使用其他数据库也是一样的,如果你用Web作为用户界面的话把Web选上,我们这里使用JUnit测试,所以不选也行。


Paste_Image.png

2、配置数据库

Spring Boot的配置内容参考官方文档:Appendix A. Common application properties
其中,我们关心的是:

# JPA (JpaBaseConfiguration, HibernateJpaAutoConfiguration)
# DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.continue-on-error=false # Do not stop if an error occurs while initializing the database.
spring.datasource.data= # Data (DML) script resource references.
spring.datasource.data-username= # User of the database to execute DML scripts (if different).
spring.datasource.data-password= # Password of the database to execute DML scripts (if different).
spring.datasource.dbcp2.*= # Commons DBCP2 specific settings
spring.datasource.driver-class-name= # Fully qualified name of the JDBC driver. Auto-detected based on the URL by default.
spring.datasource.generate-unique-name=false # Generate a random datasource name.
spring.datasource.hikari.*= # Hikari specific settings
spring.datasource.initialize=true # Populate the database using 'data.sql'.
spring.datasource.jmx-enabled=false # Enable JMX support (if provided by the underlying pool).
spring.datasource.jndi-name= # JNDI location of the datasource. Class, url, username & password are ignored when set.
spring.datasource.name=testdb # Name of the datasource.
spring.datasource.password= # Login password of the database.
spring.datasource.platform=all # Platform to use in the schema resource (schema-${platform}.sql).
spring.datasource.schema= # Schema (DDL) script resource references.
spring.datasource.schema-username= # User of the database to execute DDL scripts (if different).
spring.datasource.schema-password= # Password of the database to execute DDL scripts (if different).
spring.datasource.separator=; # Statement separator in SQL initialization scripts.
spring.datasource.sql-script-encoding= # SQL scripts encoding.
spring.datasource.tomcat.*= # Tomcat datasource specific settings
spring.datasource.type= # Fully qualified name of the connection pool implementation to use. By default, it is auto-detected from the classpath.
spring.datasource.url= # JDBC url of the database.
spring.datasource.username= # Login user of the database.
spring.datasource.xa.data-source-class-name= # XA datasource fully qualified name.
spring.datasource.xa.properties= # Properties to pass to the XA data source.

# H2 Web Console (H2ConsoleProperties)
spring.h2.console.enabled=false # Enable the console.
spring.h2.console.path=/h2-console # Path at which the console will be available.
spring.h2.console.settings.trace=false # Enable trace output.
spring.h2.console.settings.web-allow-others=false # Enable remote access.

# JOOQ (JooqAutoConfiguration)
spring.jooq.sql-dialect= # SQLDialect JOOQ used when communicating with the configured datasource. For instance `POSTGRES`

# JPA (JpaBaseConfiguration, HibernateJpaAutoConfiguration)
spring.data.jpa.repositories.enabled=true # Enable JPA repositories.
spring.jpa.database= # Target database to operate on, auto-detected by default. Can be alternatively set using the "databasePlatform" property.
spring.jpa.database-platform= # Name of the target database to operate on, auto-detected by default. Can be alternatively set using the "Database" enum.
spring.jpa.generate-ddl=false # Initialize the schema on startup.
spring.jpa.hibernate.ddl-auto= # DDL mode. This is actually a shortcut for the "hibernate.hbm2ddl.auto" property. Default to "create-drop" when using an embedded database, "none" otherwise.
spring.jpa.hibernate.naming.implicit-strategy= # Hibernate 5 implicit naming strategy fully qualified name.
spring.jpa.hibernate.naming.physical-strategy= # Hibernate 5 physical naming strategy fully qualified name.
spring.jpa.hibernate.naming.strategy= # Hibernate 4 naming strategy fully qualified name. Not supported with Hibernate 5.
spring.jpa.hibernate.use-new-id-generator-mappings= # Use Hibernate's newer IdentifierGenerator for AUTO, TABLE and SEQUENCE.
spring.jpa.open-in-view=true # Register OpenEntityManagerInViewInterceptor. Binds a JPA EntityManager to the thread for the entire processing of the request.
spring.jpa.properties.*= # Additional native properties to set on the JPA provider.
spring.jpa.show-sql=false # Enable logging of SQL statements.

其实不止这些,但我们不会完全学完所有知识才能应用,以下的配置就可以让我们访问数据库了:

spring.datasource.url=jdbc:h2:file:d:/h2/data.db;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform= org.hibernate.dialect.H2Dialect
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.open-in-view=true 
spring.jpa.show-sql=false
spring.h2.console.enabled=false

3、代码结构

理论上我们可以任意的组织代码,Spring Boot给出了一个建议:

com
 +- example
     +- myproject
         +- Application.java
         |
         +- domain
         |   +- Customer.java
         |   +- CustomerRepository.java
         |
         +- service
         |   +- CustomerService.java
         |
         +- web
             +- CustomerController.java

从上图可以看出:domain放置实体和Repository,service放置业务逻辑,web放置Controller。我更习惯于另为一种组织,将domain拆分为entity和repo,将实体和Repository分别安放。Repository可以看作是DAO/DAL数据访问层或者数据访问对象。

4、从数据到逻辑

用上面的代码结构我们可以看出,一个Spring业务流程包括:数据结构(entity)、数据访问(repo/dal)、业务逻辑(service)和用户交互界面(web)。我们接下来按此顺序一一讲解

4.1、实体对象Entity

实体对象很简单,是和数据库表的映射,但框架已经把数据库操作封装了,且Java强调的面向对象,我认为实体直接看作是可以持久化的数据对象就好了,和数据库的关系只要心里明白就行。我们先实现一个记录数据的描述,这个记录没有什么实际意义,仅为演示Spring Data JPA的使用。代码如下:

@Entity
public class Records {
    @Id
    @GeneratedValue
    private Long id;
    @Column
    private String title;
    @Column
    private String description;
    @Column
    private Date updateDate;
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public Date getUpdateDate() {
        return updateDate;
    }
    public void setUpdateDate(Date updateDate) {
        this.updateDate = updateDate;
    }    
}

在实体类上使用@Entity注解说明这是一个实体类,@Id注解说明这是主键,@Column说明是普通字段,@GenerateValue主键生成策略默认native,H2是自增的。
这就是整个数据结构,包含了主键、标题、描述和更新时间。

4.2、Repository的实现

数据结构有了,接下来我们我操作这些数据,说白了就是增删查改、分页等等。要感谢Spring,这些功能大部分都为我们实现了,我们只需要扩展一个接口就行,不信看下面的代码:

@Repository
public interface RecordsRepo extends JpaRepository<Records, Long> {
}

看见没,不超过三行代码。@Repository说明这个接口是一个repository,也就是DAO/DAL。接口JpaRepository是一个很全的功能接口,我们不用实现它,Spring会自动为我们适配实现。

4.3、业务逻辑的实现

当我们可以操作数据时,就可以通过处理数据来实现业务逻辑了,代码如下:

@Service
public class RecordsService {

    @Autowired
    RecordsRepo recRepo;

    public Records save(Records rec) {
        return recRepo.save(rec);
    }

    public List<Records> list() {
        return recRepo.findAll();
    }

    public void delete(Records rec) {
        recRepo.delete(rec);
    }

    public Records get(Long id) {
        return recRepo.findOne(id);
    }
}

同样,这里也有一个@Service注解说明这是一个服务Bean,通过@Autowired注解将RecordsRepo注入到服务中,这样就能操作Records数据了。这时候我们就可以根据我们的需求和业务来编写我买的业务方法,因为这里只是一个demo,所以我们就简单的调用了repository方法。

4.4、检验成果

测试通常是通过对比输出值和期望值来进行检验的。简单的,我们只是通过用户界面来进行判断,例如:

4.4.1、Web页面操作测试

我们,通过Controller实现几个用户功能,代码如下:

@SpringBootApplication
@RestController
public class SpringBootJpaApplication {

    @Autowired
    RecordsService recSevc;

    public static void main(String[] args) {
        SpringApplication.run(SpringBootJpaApplication.class, args);
    }

    @RequestMapping("new")
    public Records newRecords() {
        Records rec = new Records();
        rec.setTitle("title" + Math.random());
        rec.setDescription("desc" + Math.random());
        rec.setUpdateDate(Calendar.getInstance().getTime());
        rec = recSevc.save(rec);
        return rec;
    }

    @RequestMapping("update")
    public Records updateRecords() {
        Records rec = recSevc.get(1l);
        rec.setTitle("modified");
        recSevc.save(rec);
        return rec;
    }

    @RequestMapping("delete")
    public String deleteRecords() {
        Records rec = recSevc.get(1l);
        recSevc.delete(rec);
        return "deleted";
    }
}

这里,注入了RecordsService,并通过用户请求实现了增改删功能。我们可以浏览器返回值查看返回值。另外,我们可以在H2控制台中查看数据库的变化,什么是H2控制台,如果你用过phpMyAdmin或其他数据库管理工具就明白了,这里不深入讨论。我们先配置一下application.properties:

spring.h2.console.enabled=true
spring.h2.console.path=/h2 #默认是/h2_console

我们先启动服务:


运行程序


在项目名称上,右键,Run As,Java Application 或者 Spring Boot App。
然后,我们在浏览器中输入http://host:port/[new|update|delete] 试试看。
同时,我们可以在浏览器中输入http://host:port/h2 看看数据库中数据的变化是否与预期一致:


H2控制台

4.4.2、JUnit单元测试

另外一种更专业的测试方法是我们可以写单元测试,这样我买的测试就可以不断迭代,而且有相应的工具帮我们进行测试分析,代码如下:

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootJpaApplicationTests {

    @Autowired
    RecordsService recSevc;

    @Test
    public void contextLoads() {
    }

    @Test
    public void testJpaRecords() {
        Records rec = new Records();
        rec.setTitle("title" + Math.random());
        rec.setDescription("desc" + Math.random());
        rec.setUpdateDate(Calendar.getInstance().getTime());
        rec = recSevc.save(rec);
        Long id = rec.getId();
        assertThat(rec.getId()).isNotNull();
        rec.setTitle("modified");
        rec = recSevc.save(rec);
        assertThat(rec.getTitle()).isEqualTo("modified");
        assertThat(rec.getId()).isEqualTo(id);

        List<Records> recs = recSevc.list();
        int size = recs.size();
        assertThat(size).isGreaterThan(0);

        rec = recSevc.get(id);
        assertThat(rec.getId()).isEqualTo(id);

        recSevc.delete(rec);
        rec = recSevc.get(id);
        assertThat(rec).isNull();
    }
}

同样是注解,这个@Test说明我们的执行的测试方法是testJpaRecords,不过这次我们运行的是JUnit Test,如下图所示:


启动执行测试用列

运行结果一闪而过,结果如何呢?请看:


JUnit窗口


IDE里面的JUnit 视图窗口,运行了两个测试方法,全部通过。这里仅是示例,实际测试应更复杂,需分析测试覆盖率等。

总结

回过头来再复习一遍,很简单,设计好你要操作的数据结构,编写操作数据的接口,在业务逻辑中操作数据,将数据处理结果返回给用户。

转载请注明:
http://www.techcave.cn
http://tedeum.iteye.com
http://www.jianshu.com/u/befd4004b0a4

==============================================================

Ionic 2 实例开发


Ionic 2 安装
环境安装
创建Ionic项目
测试运行项目
Ionic 2 项目结构
./src/index.html
./src/
./src/app/app.html
Ionic 2 应用剖析
0 开始之前
1 创建一个新的Ionic 2 应用
2 目录结构
Root Components 模版
App Module
总结
Ionic 2 添加页面
创建页面
创建附加页面
使用 Ionic 2 开发Todo应用
0 开始之前
1 创建新的Ionic 2工程
2. 设置主页(Home page)
3 持久化数据保存
4 总结
Ionic 2 实现列表滑动删除按钮
1.创建Ionic2应用
2.准备列表数据
3.修改主页(HOME)的模版
4.创建方法删除数据
5.添加一个编辑按钮
总结
Angular 2 新概念和语法
Angular 2 & Ionic 2 概念
Angular 2 语法
Ionic 2 导航简明指南
入栈出栈(Pushing and Popping)
什么时候使用导航栈?什么时候使用rootPage?
Ionic 2 基本导航功能
总结
Ionic 2 中使用管道处理数据
1.生成一个新应用
2.创建一个管道
3.使用管道
总结
Ionic 2 中使用HTTP与远程服务器交互数据
开始之前
我们需要一个列表
3.获取远程数据
4.推送数据到服务器
总结
Ionic 2 中的样式与主题
Ionic 2主题简介
创建Ionic 2应用主题的方式
没有苹果电脑打包iOS平台的 Ionic 2程序
开始之前
1 创建一个Ionic 2的应用
2 建立Ionic Cloud
3 生成证书和创建一个安全概要
4 使用Ionic Package 命令
总结
Ionic 2中使用百度地图和Geolocation
新建项目
加入百度地图SDK库
加载地图
获取定位
坐标转换
地图定位
激活百度地图导航
总结
在Ionic 2 Native中使用Cordova插件
Ionic 和 Cordova 的误解
使用Ionic Native
使用没有包含在Ionic Native中的插件
Ionic 2 中添加图表
1. 照例新建一个项目
2. 安装Chart.js
3. 在模版中使用
总结
Ionic 2 中的创建一个闪视卡片组件
1. 创建一个新的应用作为例子
2. 什么是组件?
3. 创建组件模版
4. 创建组件类
5. 创建 CSS 动画
6. 添加组件到模版
总结
Ionic 2 中创建一个照片倾斜浏览组件
1. 创建一个新的应用
2. 实现照片倾斜浏览组件
3. 使用照片倾斜浏览组件
总结
Ionic 2 中实现一个简单的进度条
理解 自定义组件中的 Input 和 output
1.创建一个新的应用
2.创建组件
修改src/components/progress-bar/progress-bar.ts如下:
3.使用这个组件
总结
使用VS Code在Chrome中调试Ionic 2
优化你的Ionic2应用
打开Angular产品模式
修改(click) 为 (tap)
使用 --prod 参数编译
总结
Ionic 2 开发遇到的问题及处理集
Console.log 不输出
编译Android报错:compileArmv7DebugJavaWithJavac
一些更新命令
错误:Error: listen EADDRINUSE 0.0.0.0:53703

猜你喜欢

转载自tedeum.iteye.com/blog/2372998