Grailsを使用してMVCWebアプリケーションを構築する
1. 概要
このチュートリアルでは、Grailsを使用して簡単なWebアプリケーションを作成する方法を学習します。
Grails(より正確には最新のメジャーバージョン)は、Spring Bootプロジェクトの上に構築されたフレームワークであり、ApacheGroovy言語を使用してWebアプリを開発します。
これは、Rails Framework for Rubyに触発されており、は、定型コードの削減を可能にする設定より規約の哲学に基づいて構築されています。
2. 設定
まずは公式ページに行って環境を整えましょう。 このチュートリアルの時点で、最新バージョンは3.3.3です。
簡単に言うと、Grailsをインストールする方法は2つあります。SDKMANを使用する方法と、ディストリビューションをダウンロードしてPATH環境変数にバイナリを追加する方法です。
Grails Docs で十分に文書化されているため、セットアップについては段階的に説明しません。
3. Grailsアプリの構造
このセクションでは、Grailsアプリケーションの構造について理解を深めます。 前述したように、Grailsは設定より規約を優先するため、ファイルの場所によって目的が決まります。 grails-appディレクトリにあるものを見てみましょう。
- Assets –スタイル、JavaScriptファイル、画像などの静的アセットファイルを保存する場所
- conf –プロジェクト構成ファイルが含まれています。
- application.yml には、データソース、mimeタイプ、その他のGrailsまたはSpring関連の設定などの標準のWebアプリ設定が含まれています
- resources.groovy には、SpringBeanの定義が含まれています
- 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. ドメインレイヤー
Studentを処理するためのWebアプリケーションを実装しているので、Studentというドメインクラスの生成から始めましょう。
grails create-domain-class com.baeldung.grails.Student
最後に、firstNameプロパティとlastNameプロパティを追加しましょう。
class Student {
String firstName
String lastName
}
Grailsはその規則を適用し、 grails-app /domainディレクトリにあるすべてのクラスのオブジェクトリレーショナルマッピングを設定します。
さらに、 GormEntity 特性のおかげで、すべてのドメインクラスがすべてのCRUD操作にアクセスできるようになります。これは、次のセクションでサービスを実装するために使用します。
4.2. サービスレイヤー
このアプリケーションは、次のユースケースを処理します。
- 学生のリストを表示する
- 新しい学生を作成する
- 既存の学生を削除する
これらのユースケースを実装しましょう。 まず、サービスクラスを生成します。
grails create-service com.baeldung.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()
}
}
サービスはデフォルトでトランザクションをサポートしないことに注意してください。 この機能を有効にするには、@Transactionalアノテーションをクラスに追加します。
4.3. コントローラレイヤー
UIでビジネスロジックを使用できるようにするために、次のコマンドを呼び出してStudentControllerを作成しましょう。
grails create-controller com.baeldung.grails.Student
デフォルトでは、Grailsは名前でBeanを注入します。 これは、 studentService というインスタンス変数を宣言することで、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"
}
}
慣例により、このコントローラーからの index()アクションはURI / student / indexにマップされ、 show()アクションは/にマップされます。学生/ショーなど。
4.4. ビューレイヤー
コントローラアクションを設定したら、UIビューの作成に進むことができます。 生徒の一覧表示、作成、削除のために3つのGroovyサーバーページを作成します。
慣例により、Grailsはコントローラー名とアクションに基づいてビューをレンダリングします。 たとえば、StudentControllerからの index() アクションは、/ grails-app / views / student /index.gspに解決されます。
ビュー/grails-app/views/student/index.gspの実装から始めましょう。これにより、学生のリストが表示されます。 タグを使用します
慣例により、オブジェクトのリストで応答すると、 Grailsはモデル名に「List」サフィックスを追加して、変数studentListを使用して学生オブジェクトのリストにアクセスできるようにします。 :
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="main" />
</head>
<body>
<div class="nav" role="navigation">
<ul>
<li><g:link class="create" action="create">Create</g:link></li>
</ul>
</div>
<div id="list-student" class="content scaffold-list" role="main">
<f:table collection="${studentList}"
properties="['firstName', 'lastName']" />
</div>
</body>
</html>
次に、ビュー / grails-app / views / student / create.gsp、に進みます。これにより、ユーザーは新しい学生を作成できます。 ビルトインを使用します
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="main" />
</head>
<body>
<div id="create-student" class="content scaffold-create" role="main">
<g:form resource="${this.student}" method="POST">
<fieldset class="form">
<f:all bean="student"/>
</fieldset>
<fieldset class="buttons">
<g:submitButton name="create" class="save" value="Create" />
</fieldset>
</g:form>
</div>
</body>
</html>
最後に、ビュー / grails-app / views / student / show.gsp を作成して、学生を表示し、最終的に削除します。
他のタグの中で、私たちは利用します
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="main" />
</head>
<body>
<div class="nav" role="navigation">
<ul>
<li><g:link class="list" action="index">Students list</g:link></li>
</ul>
</div>
<div id="show-student" class="content scaffold-show" role="main">
<f:display bean="student" />
<g:form resource="${this.student}" method="DELETE">
<fieldset class="buttons">
<input class="delete" type="submit" value="delete" />
</fieldset>
</g:form>
</div>
</body>
</html>
4.5. ユニットテスト
Grailsは、主にSpockをテスト目的で利用します。 Spockに慣れていない場合は、最初にこのチュートリアルを読むことを強くお勧めします。
ユニットテストから始めましょう索引() 私たちの行動
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はこの目的でメモリ内のH2データベースを使用します。
まず、データベースにデータを入力するためのデータを作成するためのヘルパーメソッドの定義から始めましょう。
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
}
統合テストクラスの@Rollbackアノテーションのおかげで、各メソッドは個別のトランザクションで実行され、テストの最後にロールバックされます。
list()メソッドの統合テストをどのように実装したかを見てみましょう。
void "test list"() {
setupData()
when:
List<Student> 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. 実行と展開
アプリの実行とデプロイは、GrailsCLIを介して単一のコマンドを呼び出すことで実行できます。
アプリを実行するには、次を使用します。
grails run-app
デフォルトでは、Grailsはポート8080でTomcatをセットアップします。
http:// localhost:8080 / student / index に移動して、Webアプリケーションがどのように表示されるかを確認しましょう。
アプリケーションをサーブレットコンテナにデプロイする場合は、次を使用します。
grails war
すぐにデプロイできるwarアーティファクトを作成します。
6. 結論
この記事では、設定より規約の哲学を使用してGrailsWebアプリケーションを作成する方法に焦点を当てました。 また、Spockフレームワークを使用してユニットテストと統合テストを実行する方法も確認しました。
いつものように、ここで使用されるすべてのコードは、GitHubのにあります。