Grailsを使ってMVC Webアプリケーションを構築する

Grailsを使用してMVC Webアプリケーションを構築する

 

1. 概要

このチュートリアルでは、Grailsを使用して簡単なWebアプリケーションを作成する方法を学習します。

Grails(より正確には最新のメジャーバージョン)は、Spring Bootプロジェクトの上に構築されたフレームワークであり、ApacheGroovy言語を使用してWebアプリを開発します。

これは、Rubyおよびis built around the convention-over-configuration philosophy which allows reducing boilerplate code用のRailsフレームワークに触発されています。

2. セットアップ

まず、公式ページに行って環境を整えましょう。 このチュートリアルの時点で、最新バージョンは3.3.3です。

簡単に言えば、Grailsをインストールする方法は2つあります。SDKMANを使用する方法と、ディストリビューションをダウンロードしてPATH環境変数にバイナリを追加する方法です。

Grails Docsに詳しく記載されているため、セットアップについては段階的に説明しません。

3. Grailsアプリの構造

このセクションでは、Grailsアプリケーションの構造をより深く理解します。 前述したように、Grailsは構成よりも慣習を優先するため、ファイルの場所によってその目的が決まります。 grails-appディレクトリにあるものを見てみましょう。

  • assets –スタイル、JavaScriptファイル、画像などの静的アセットファイルを保存する場所

  • conf –プロジェクト構成ファイルが含まれています。

    • application.ymlには、データソース、MIMEタイプ、および他のGrailsまたはSpring関連の設定のような標準的なウェブアプリ設定が含まれている。

    • resources.groovy

    • logback.groovyにはログ設定が含まれています

  • controllers –要求の処理と応答の生成、またはビューへの委任を担当します。 慣例により、ファイル名が*Controllerで終わる場合、フレームワークはコントローラークラスで定義された各アクションのデフォルトのURLマッピングを作成します

  • domain –Grailsアプリケーションのビジネスモデルが含まれています。 ここに住んでいる各クラスは、GORMによってデータベーステーブルにマッピングされます

  • i18n –国際化サポートに使用

  • init –アプリケーションのエントリポイント

  • services –アプリケーションのビジネスロジックはここにあります。 慣例により、Grailsは各サービスに対してSpringシングルトンBeanを作成します

  • taglib –カスタムタグライブラリの場所

  • views –ビューとテンプレートが含まれています

4. シンプルなWebアプリケーション

この章では、生徒を管理するためのシンプルなWebアプリを作成します。 まず、アプリケーションスケルトンを作成するためのCLIコマンドを呼び出します。

grails create-app

プロジェクトの基本構造が生成されたら、実際のWebアプリコンポーネントの実装に移りましょう。

4.1. ドメイン層

学生を処理するためのWebアプリケーションを実装しているので、Studentというドメインクラスの生成から始めましょう。

grails create-domain-class com.example.grails.Student

最後に、firstNameプロパティとlastNameプロパティを追加しましょう。

class Student {
    String firstName
    String lastName
}

Grailsはその規則を適用し、grails-app/domainディレクトリにあるすべてのクラスのオブジェクトリレーショナルマッピングを設定します。

さらに、GormEntityトレイト、all domain classes will have access to all CRUD operationsのおかげで、次のセクションでサービスを実装するために使用します。

4.2. サービス層

このアプリケーションは、次のユースケースを処理します。

  • 学生のリストを表示する

  • 新しい生徒を作成する

  • 既存の生徒を削除する

これらのユースケースを実装しましょう。 サービスクラスを生成することから始めます。

grails create-service com.example.grails.Student

grails-app/servicesディレクトリに移動し、適切なパッケージで新しく作成されたサービスを見つけて、必要なすべてのメソッドを追加しましょう。

@Transactional
class StudentService {

    def get(id){
        Student.get(id)
    }

    def list() {
        Student.list()
    }

    def save(student){
        student.save()
    }

    def delete(id){
        Student.get(id).delete()
    }
}

Note that services don’t support transactions by default。 この機能を有効にするには、クラスに@Transactionalアノテーションを追加します。

4.3. コントローラー層

UIでビジネスロジックを使用できるようにするために、次のコマンドを呼び出してStudentControllerを作成しましょう。

grails create-controller com.example.grails.Student

デフォルトでは、Grails injects beans by namesです。 これは、studentsServiceというインスタンス変数を宣言することで、StudentServiceシングルトンインスタンスをコントローラーに簡単に挿入できることを意味します。

これで、生徒の読み取り、作成、削除のアクションを定義できます。

class StudentController {

    def studentService

    def index() {
        respond studentService.list()
    }

    def show(Long id) {
        respond studentService.get(id)
    }

    def create() {
        respond new Student(params)
    }

    def save(Student student) {
        studentService.save(student)
        redirect action:"index", method:"GET"
    }

    def delete(Long id) {
        studentService.delete(id)
        redirect action:"index", method:"GET"
    }
}

慣例により、the index() action from this controller will be mapped to the URI*/student/index*,show()アクションから/student/showなどになります。

4.4. レイヤーを表示

コントローラーアクションをセットアップしたら、UIビューの作成に進むことができます。 生徒をリスト、作成、削除するための3つのGroovyサーバーページを作成します。

慣例により、Grailsはコントローラー名とアクションに基づいてビューをレンダリングします。 たとえば、the index()action from StudentController will resolve to /grails-app/views/student/index.gsp

学生のリストを表示するビュー/grails-app/views/student/index.gspの実装から始めましょう。 タグ<f:table/>を使用して、コントローラーのindex()アクションから返されたすべての生徒を表示するHTMLテーブルを作成します。

慣例により、オブジェクトのリストGrails will add the “List” suffix to the model nameで応答すると、変数studentListを使用して学生オブジェクトのリストにアクセスできます。



    
        
    
    
        
        

次に、ユーザーが新しい学生を作成できるビュー/grails-app/views/student/create.gsp,に進みます。 組み込みの<f:all/>タグを使用します。これは、特定のBeanのすべてのプロパティのフォームを表示します。



    
        
    
    
        

最後に、生徒を表示して最終的に削除するためのビュー/grails-app/views/student/show.gspを作成しましょう。

他のタグの中でも、<f:display/>を利用します。これは、Beanを引数として取り、そのすべてのフィールドを表示します。



    
        
    
    
        
        

4.5. 単体テスト

Grailsは主にテスト目的でSpockを利用します。 Spockに慣れていない場合は、最初にthis tutorialを読むことを強くお勧めします。

StudentController.index()アクションの単体テストから始めましょう

StudentServiceからlist()メソッドをモックし、index()が期待されるモデルを返すかどうかをテストします。

void "Test the index action returns the correct model"() {
    given:
    controller.studentService = Mock(StudentService) {
        list() >> [new Student(firstName: 'John',lastName: 'Doe')]
    }

    when:"The index action is executed"
    controller.index()

    then:"The model is correct"
    model.studentList.size() == 1
    model.studentList[0].firstName == 'John'
    model.studentList[0].lastName == 'Doe'
}

それでは、delete()アクションをテストしてみましょう。 delete()StudentServiceから呼び出されたかどうかを確認し、インデックスページへのリダイレクトを確認します。

void "Test the delete action with an instance"() {
    given:
    controller.studentService = Mock(StudentService) {
      1 * delete(2)
    }

    when:"The domain instance is passed to the delete action"
    request.contentType = FORM_CONTENT_TYPE
    request.method = 'DELETE'
    controller.delete(2)

    then:"The user is redirected to index"
    response.redirectedUrl == '/student/index'
}

4.6. 統合テスト

次に、サービス層の統合テストを作成する方法を見てみましょう。 主に、grails-app/conf/application.yml.で構成されたデータベースとの統合をテストします

この目的のためのBy default, Grails uses the in-memory H2 database

まず、データベースにデータを入力するためのデータを作成するためのヘルパーメソッドの定義から始めましょう。

private Long setupData() {
    new Student(firstName: 'John',lastName: 'Doe')
      .save(flush: true, failOnError: true)
    new Student(firstName: 'Max',lastName: 'Foo')
      .save(flush: true, failOnError: true)
    Student student = new Student(firstName: 'Alex',lastName: 'Bar')
      .save(flush: true, failOnError: true)
    student.id
}

統合テストクラスeach method will run in a separate transaction, which will be rolled back at the end of the test@Rollbackアノテーションに感謝します。

list()メソッドの統合テストをどのように実装したかを見てみましょう。

void "test list"() {
    setupData()

    when:
    List studentList = studentService.list()

    then:
    studentList.size() == 3
    studentList[0].lastName == 'Doe'
    studentList[1].lastName == 'Foo'
    studentList[2].lastName == 'Bar'
}

また、delete()メソッドをテストして、生徒の総数が1つ減ったかどうかを検証しましょう。

void "test delete"() {
    Long id = setupData()

    expect:
    studentService.list().size() == 3

    when:
    studentService.delete(id)
    sessionFactory.currentSession.flush()

    then:
    studentService.list().size() == 2
}

5. 実行と展開

アプリの実行とデプロイは、Grails CLIを介して単一のコマンドを呼び出すことで実行できます。

アプリを実行するには:

grails run-app

デフォルトでは、Grailsはポート8080でTomcatをセットアップします。

http://localhost:8080/student/indexに移動して、Webアプリケーションがどのように表示されるかを確認しましょう。

image

アプリケーションをサーブレットコンテナにデプロイする場合は、次を使用します。

grails war

すぐに展開できる戦争成果物を作成します。

6. 結論

この記事では、Convention-Over-Configuration哲学を使用してGrails Webアプリケーションを作成する方法に焦点を当てました。 また、Spockフレームワークを使用して単体テストと統合テストを実行する方法も確認しました。

いつものように、ここで使用されるすべてのコードはover on GitHubで見つけることができます。