こんばんは、エキサイト株式会社の中尾です。
前回の続きです。
mybatisを入れていきます。
mybatisにはserviceと同様@Singleton
をつけて、@Inject
で呼び出します。
その際、repositoryを間に挟みます。
まず、必要なextentionをgradleに追加します。
implementation 'io.quarkiverse.mybatis:quarkus-mybatis:0.0.10' implementation 'io.quarkus:quarkus-jdbc-mysql:0.26.1'
続いてデータベースの設定です。
CREATE schema test; CREATE TABLE book ( id integer not null primary key, title varchar(80) not null, author varchar(80) not null, created DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ); INSERT INTO `test`.`book` (`id`, `title`, `author`) VALUES (1, 'hobby', 's-nakao');
続いてアプリケーションの設定です、
- application.properties
quarkus.datasource.db-kind=mysql quarkus.datasource.username=YYYYYYY quarkus.datasource.password=XXXXXXX quarkus.datasource.jdbc.url=jdbc:mysql://localhost/test
※サンプルです。
- repository interface
package org.my.hobby.repository; import org.my.hobby.core.Book; public interface BookRepository { Book find(String title); }
- repository impl
package org.my.hobby.repository; import javax.inject.Inject; import javax.inject.Singleton; import java.util.Optional; import org.my.hobby.core.Book; import org.my.hobby.persistence.BookDto; import org.my.hobby.persistence.BookMapper; @Singleton public class BookRepositoryImpl implements BookRepository { @Inject BookMapper bookMapper; @Override public Book find(String title) { final Optional<BookDto> book = bookMapper.getBook(title); return book .map(bookDto -> new Book(bookDto.getTitle(), bookDto.getAuthor())) .orElse(new Book("", "")); } }
- persistence interface
テキストブロック使います。 簡単なselectでも私はsql書きたい人です。 persistenceに全てのSQLをできるだけ書きたいです。
package org.my.hobby.persistence; import java.util.Optional; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; @Mapper public interface BookMapper { @Select(""" SELECT id, title, author, created FROM book WHERE title = #{title} """) Optional<BookDto> getBook(String title); }
- persistence dto
package org.my.hobby.persistence; import java.time.LocalDateTime; public class BookDto{ private Integer id; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public LocalDateTime getCreated() { return created; } public void setCreated(LocalDateTime created) { this.created = created; } private String title; private String author; private LocalDateTime created; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } }
- service impl
シンプルになります。
package org.my.hobby.service; import javax.inject.Inject; import javax.inject.Singleton; import org.my.hobby.core.Book; import org.my.hobby.repository.BookRepository; @Singleton public class BookServiceImpl implements BookService { @Inject BookRepository bookRepository; @Override public Book find(String title) { return bookRepository.find(title); } }
- コントローラー
前回のコントローラーは変わりません。
package org.my.hobby; import javax.inject.Inject; import javax.validation.ConstraintViolation; import javax.validation.Validator; import javax.validation.constraints.NotBlank; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import java.util.Set; import java.util.stream.Collectors; import org.my.hobby.core.Book; import org.my.hobby.service.BookService; record BookSearchRequest( @NotBlank(message = "Title may not be blank") String title) { } record BookSearchResponse( boolean success, String message, Book book) { record Book(String title, String author) { } } @Path("/book/search") public class BookController { @Inject Validator validator; @Inject BookService bookService; @POST @Produces(MediaType.APPLICATION_JSON) public BookSearchResponse search(BookSearchRequest bookSearchRequest) { Set<ConstraintViolation<BookSearchRequest>> violations = validator.validate(bookSearchRequest); if (!violations.isEmpty()) { final String errorMessage = violations .stream() .map(e -> e.getMessage()) .collect(Collectors.joining(",")); final BookSearchResponse.Book hobbyBook = new BookSearchResponse.Book("", ""); return new BookSearchResponse(false, errorMessage, hobbyBook); } final Book book = bookService.find(bookSearchRequest.title()); final BookSearchResponse.Book hobbyBook = new BookSearchResponse.Book(book.title(), book.author()); return new BookSearchResponse(book.isFind(), book.message(), hobbyBook); } }
- curlでアクセス
shogo.nakao@localhost:(App-Db-Blog-Fan) $ curl --location --request POST 'http://localhost:8080/book/search' \ --header 'Content-Type: application/json' \ --data-raw '{ "title": "hobby" }' {"success":true,"message":"","book":{"title":"hobby","author":"s-nakao"}}% shogo.nakao@localhost:(App-Db-Blog-Fan) $ curl --location --request POST 'http://localhost:8080/book/search' \ --header 'Content-Type: application/json' \ --data-raw '{ "title": "s-nakao" }' {"success":false,"message":"not found book","book":{"title":"","author":""}}% shogo.nakao@localhost:(App-Db-Blog-Fan) $ curl --location --request POST 'http://localhost:8080/book/search' \ --header 'Content-Type: application/json' \ --data-raw '{ }' {"success":false,"message":"Title may not be blank","book":{"title":"","author":""}}%
取得できました!よかったですね!
一通り、controller,servie,repositoryができました。簡単でしたね。
quarkusでmybatisの設定は以下を参考にしてください。
Quarkus - Using MyBatis :: Quarkiverse Documentation
最後に、弊社では採用もバシバシ実施しているので興味のあるかたがいましたらご応募ください。
Advent Calendar 2021を引き続き楽しんでいただけると嬉しいです。