首页 » Spring Boot实战 » Spring Boot实战全文在线阅读

《Spring Boot实战》6.1 使用GORM进行数据持久化

关灯直达底部

Grails里最让人着迷的恐怕就是GORM了。GORM将数据库相关工作简化到和声明要持久化的实体一样容易。例如,代码清单6-1演示了阅读列表里的Book该如何用Groovy写成GORM实体。

代码清单6-1 GORM Book实体

package readinglistimport grails.persistence.*@Entity          ←---这是一个GORM实体class Book {  Reader reader  String isbn  String title  String author  String description}  

就和Book的Java版本一样,这个类里有很多描述图书的属性。但又与Java版本不一样,这里没有分号、publicprivate修饰符、setter和getter方法或其他Java中常见的代码噪声。是Grails的@Entity注解让这个类变成了GORM实例。这个简单的实体可干了不少事,包括将对象映射到数据库,为Book添加持久化方法,通过这些方法可以存取图书。

要在Spring Boot项目里使用GORM,必须在项目里添加GORM依赖。在Maven中,<dependency>看起来是这样的:

<dependency>  <groupId>org.grails</groupId>  <artifactId>gorm-hibernate4-spring-boot</artifactId>  <version>1.1.0.RELEASE</version></dependency>  

一样的依赖,在Gradle里是这样的:

compile(/"org.grails:gorm-hibernate4-spring-boot:1.1.0.RELEASE/")  

这个库自带了一些Spring Boot自动配置,会自动配置所有支持GORM所需的Bean。你只管写代码就好了。

GORM在Spring Boot里的另一个选择

正如其名,gorm-hibernate4-spring-boot是通过Hibernate开启GORM数据持久化的。对很多项目而言,这很好。但如果你想用MongoDB,那你会对Spring Boot里的MongoDB GORM支持很感兴趣。

它的Maven依赖是这样的:

<dependency>  <groupId>org.grails</groupId>  <artifactId>gorm-mongodb-spring-boot</artifactId>  <version>1.1.0.RELEASE</version></dependency>  

下面是相同的Gradle依赖:

compile(/"org.grails:gorm-mongodb-spring-boot:1.1.0.RELEASE/")  

GORM的工作原理要求实体类必须用Groovy来编写。我们已经在代码清单6-1里写了一个Book实体,下面再写一个Reader实体,如代码清单6-2所示。

代码清单6-2 GORM Reader实体

package readinglistimport grails.persistence.*import org.springframework.security.core.GrantedAuthorityimport    org.springframework.security.core.authority.SimpleGrantedAuthorityimport org.springframework.security.core.userdetails.UserDetails@Entity                      ←---这是一个实体class Reader implements UserDetails {  String username  String fullname  String password  Collection<? extends GrantedAuthority> getAuthorities {    Arrays.asList(new SimpleGrantedAuthority(/"READER/"))  }  boolean isAccountNonExpired {   ←---实现了UserDetails    true  }  boolean isAccountNonLocked {    true  }  boolean isCredentialsNonExpired {    true  }  boolean isEnabled {    true  }}  

现在,我们的阅读列表应用程序里有了两个GORM实体,我们需要重写剩下的应用程序来使用这两个实体。因为使用Groovy是如此令人愉悦(和Grails十分相似),所以其他类我们也会用Groovy来编写。

首先是ReadingListController,如代码清单6-3所示。

代码清单6-3 Groovy的ReadingListController

package readinglistimport org.springframework.beans.factory.annotation.Autowiredimport    org.springframework.boot.context.properties.ConfigurationPropertiesimport org.springframework.http.HttpStatusimport org.springframework.stereotype.Controllerimport org.springframework.ui.Modelimport org.springframework.web.bind.annotation.ExceptionHandlerimport org.springframework.web.bind.annotation.RequestMappingimport org.springframework.web.bind.annotation.RequestMethodimport org.springframework.web.bind.annotation.ResponseStatus@Controller@RequestMapping(/"//")@ConfigurationProperties(/"amazon/")class ReadingListController {  @Autowired  AmazonProperties amazonProperties  @ExceptionHandler(value=RuntimeException.class)  @ResponseStatus(value=HttpStatus.BANDWIDTH_LIMIT_EXCEEDED)  def error {    /"error/"  }  @RequestMapping(method=RequestMethod.GET)  def readersBooks(Reader reader, Model model) {    List<Book> readingList = Book.findAllByReader(reader)   ←---查找读者的全部图书    model.addAttribute(/"reader/", reader)    if (readingList) {      model.addAttribute(/"books/", readingList)      model.addAttribute(/"amazonID/", amazonProperties.getAssociateId)    }    /"readingList/"  }  @RequestMapping(method=RequestMethod.POST)  def addToReadingList(Reader reader, Book book) {    Book.withTransaction {      book.setReader(reader)      book.save       ←---保存一本书    }    /"redirect://"  }} 

这个版本的ReadingListController和第3章里的相比,最明显的不同之处在于,它是用Groovy写的,没有Java的那些代码噪声。最重要的不同之处在于,无需再注入ReadingListRepository,它直接通过Book类型持久化。

readersBooks方法里,它调用了BookfindAllByReader静态方法,传入了指定的读者信息。虽然代码清单6-1没有提供findAllByReader方法,但这段代码仍然可以执行,因为GORM会为我们实现这个方法。

与之类似,addToReadingList方法使用了静态方法withTransaction和实例方法save。这两个方法也是GORM提供的,用于将Book保存到数据库里。

我们所要做的就是声明一些属性,在Book上添加@Entity注解。如果你问我怎么看——我觉得这笔买卖很划算。

SecurityConfig也要做类似的修改,通过GORM而非ReadingListRepository来获取Reader。代码清单6-4就是新的SecurityConfig

代码清单6-4 Groovy版本的SecurityConfig

package readinglistimport org.springframework.context.annotation.Configurationimport org.springframework.security.config.annotation.authentication.                                  builders.AuthenticationManagerBuilderimport org.springframework.security.config.annotation.web.                                                  builders.HttpSecurityimport org.springframework.security.config.annotation.web.                             configuration.WebSecurityConfigurerAdapterimport org.springframework.security.core.userdetails.UserDetailsService@Configurationclass SecurityConfig extends WebSecurityConfigurerAdapter {  void configure(HttpSecurity http) throws Exception {    http      .authorizeRequests        .antMatchers(/"//").access(/"hasRole(/'READER/')/")        .antMatchers(/"/**/").permitAll      .and      .formLogin        .loginPage(/"/login/")        .failureUrl(/"/login?error=true/")  }  void configure(AuthenticationManagerBuilder auth) throws Exception {    auth      .userDetailsService(        { username -> Reader.findByUsername(username) }    ←---根据用户名查找读者        as UserDetailsService)  }}  

除了用Groovy重写,SecurityConfig里最明显的变化无疑就是第二个configure方法。如你所见,它使用了一个闭包(UserDetailsService的实现类),其中调用静态方法findByUsername来查找Reader,这个功能是GORM提供的。

你也许会好奇——在这个GORM版本的应用程序里,ReadingListRepository变成什么了?GORM替我们处理了所有的持久化工作,这里已经不再需要ReadingListRepository了,它的实现也都不需要了。我想你会同意代码越少越好这个观点。

应用程序中剩余的代码也应该用Groovy重写,这样才能和我们的变更相匹配。但它们和GORM没什么关系,也不在本章的讨论范围内。如果想要完整的代码,可以到示范代码页面里去下载。

此刻,你可以通过各种运行Spring Boot应用程序的方法来启动阅读列表应用程序。启动后,应用程序应该能像从前一样工作。只有你我知道持久化机制已经被改变了。

除了GORM,Grails应用程序通常还会用Groovy Server Pages将模型数据以HTML的方式呈现给浏览器。6.2节应用程序的Grails化还会继续。我们会把Thymeleaf替换为等价的GSP。