App Engine 표준 환경에서 자바와 Datastore 사용

자바용 Bookshelf 가이드의 이 부분에서는 Datastore에서 구조화된 데이터를 만들고, 읽고, 업데이트하고, 삭제하는 방법을 설명합니다.

이 페이지는 여러 페이지로 구성된 가이드의 일부입니다. 처음부터 시작하여 설정 안내를 보려면 자바 Bookshelf 앱으로 이동하세요.

설정 구성

pom.xml 파일에는 Bookshelf 가이드의 모든 부분에 대한 구성 정보가 저장되어 있습니다. 이 가이드 부분에서는 구성 정보를 추가할 필요가 없습니다. 유일한 요구사항은 bookshelf.storageType 속성이 datastore로 설정되어야 한다는 점이며, 이는 이미 자동으로 완료되어 있습니다.

로컬 머신에서 앱 실행

앱을 로컬로 실행하려면 다음 안내를 따르세요.

  1. getting-started-java/bookshelf-standard/2-structured-data 디렉터리에서 다음 명령어를 입력하여 로컬 웹 서버를 시작합니다.

    mvn package appengine:run
  2. 웹브라우저에서 http://localhost:8080으로 이동합니다.

이제 앱의 웹페이지를 찾아보고 도서를 추가, 편집, 삭제할 수 있습니다.

App Engine 표준 환경에 앱 배포

App Engine 표준 환경에 배포하려면 다음 안내를 따르세요.

  1. Bookshelf 앱에 업로드된 Datastore 색인을 만들려면 책을 최소 한 개 이상 만든 후 내 도서를 클릭합니다오. clean 명령어를 사용하여 앱을 빌드하면 로컬 색인이 삭제되므로 배포하려는 앱의 빌드에서 이를 수행합니다.
  2. getting-started-java/bookshelf-standard/2-structured-data 디렉터리에서 다음 명령어를 입력하여 앱을 배포합니다.
    mvn appengine:deploy -Dappengine.appId=[YOUR-PROJECT-ID] -Dappengine.version=[YOUR-VERSION]
    [YOUR-PROJECT-ID]를 프로젝트 ID로 바꾸고 [YOUR-VERSION]을 버전(예: 1 또는 2)으로 바꾸거나 사용하려는 다른 문자열 값으로 바꿉니다.
  3. 웹브라우저에 다음 URL을 입력합니다.

    https://PROJECT_ID.REGION_ID.r.appspot.com

    다음을 바꿉니다.

앱을 업데이트한 후에는 앱을 처음에 배포했을 때와 동일한 명령어를 입력하고 동일한 프로젝트 ID 및 버전을 지정하여 업데이트된 버전을 다시 배포할 수 있습니다. 현재 배포된 앱을 덮어씁니다. 업데이트된 명령줄에 다른 버전 문자열을 지정하면 새 배포에서 앱의 새 버전을 만들어 현재 제공되는 버전으로 승격시킵니다.

제공하지 않는 앱 버전을 삭제하면 비용을 줄일 수 있습니다.

앱 버전을 삭제하려면 다음 안내를 따르세요.

  1. Cloud Console에서 App Engine의 버전 페이지로 이동합니다.

    버전 페이지로 이동

  2. 삭제할 기본이 아닌 앱 버전의 체크박스를 선택합니다.
  3. 삭제 를 클릭하여 앱 버전을 삭제합니다.

청구 가능한 리소스 삭제에 대한 자세한 내용은 이 가이드의 마지막 단계에서 삭제를 참조하세요.

앱 구조

다음 다이어그램은 앱의 구성요소 및 서로 연결된 방식을 보여줍니다.

Bookshelf 앱 배포 프로세스 및 구조

코드 이해하기

이 섹션에서는 앱 코드와 코드의 작동 방식을 살펴봅니다.

Datastore와 상호작용

앱은 승인된 Datastore 서비스 객체를 사용하여 Datastore와 상호작용합니다. 이 객체는 토큰의 Datastore API에 액세스하기 위해 토큰의 사용자 인증 정보를 교환합니다. 이 앱은 Book 유형의 KeyFactory 객체도 만듭니다. 도서는 이 앱이 저장하는 유일한 데이터 유형이지만, 일반적으로 원하는 만큼 많은 유형의 데이터를 저장할 수 있습니다. Datastore는 다양한 종류의 데이터 유형을 지원합니다.

private DatastoreService datastore;
private static final String BOOK_KIND = "Book2";

public DatastoreDao() {
  datastore = DatastoreServiceFactory.getDatastoreService(); // Authorized Datastore service
}

도서 만들기

도서를 저장하기 위해 앱은 Datastore에 항목을 저장합니다. 항목에는 키와 이름/값 쌍 모음이 있습니다. createBook 메소드는 BOOK 유형의 새로운 항목을 만들고 저자, 설명, 발행일, 제목에 사용자 제공 값을 설정합니다. 키는 Datastore에 항목이 추가될 때 항목에 할당됩니다.

@Override
public Long createBook(Book book) {
  Entity incBookEntity = new Entity(BOOK_KIND);  // Key will be assigned once written
  incBookEntity.setProperty(Book.AUTHOR, book.getAuthor());
  incBookEntity.setProperty(Book.DESCRIPTION, book.getDescription());
  incBookEntity.setProperty(Book.PUBLISHED_DATE, book.getPublishedDate());
  incBookEntity.setProperty(Book.TITLE, book.getTitle());

  Key bookKey = datastore.put(incBookEntity); // Save the Entity
  return bookKey.getId();                     // The ID of the Key
}

Datastore에서 읽기

readBook 메서드는 도서 ID를 가져와서 키로 변환합니다. 그런 후 키를 getProperty 메서드로 전달하고 메서드는 Entity 객체를 반환합니다.

@Override
public Book readBook(Long bookId) {
  try {
    Entity bookEntity = datastore.get(KeyFactory.createKey(BOOK_KIND, bookId));
    return entityToBook(bookEntity);
  } catch (EntityNotFoundException e) {
    return null;
  }
}

entityToBook 메서드는 각 유형의 getProperty 메서드를 사용하여 Datastore에서 반환된 항목을 Book 객체로 변환합니다. 이 방법은 항목 생성 중에 사용된 setProperty 방법과 비슷합니다. 속성 이름은 String 값입니다.

public Book entityToBook(Entity entity) {
  return new Book.Builder()                                     // Convert to Book form
      .author((String) entity.getProperty(Book.AUTHOR))
      .description((String) entity.getProperty(Book.DESCRIPTION))
      .id(entity.getKey().getId())
      .publishedDate((String) entity.getProperty(Book.PUBLISHED_DATE))
      .title((String) entity.getProperty(Book.TITLE))
      .build();
}

도서 업데이트

업데이트하려면 put 메서드를 Entity와 함께 호출해야 합니다.

@Override
public void updateBook(Book book) {
  Key key = KeyFactory.createKey(BOOK_KIND, book.getId());  // From a book, create a Key
  Entity entity = new Entity(key);         // Convert Book to an Entity
  entity.setProperty(Book.AUTHOR, book.getAuthor());
  entity.setProperty(Book.DESCRIPTION, book.getDescription());
  entity.setProperty(Book.PUBLISHED_DATE, book.getPublishedDate());
  entity.setProperty(Book.TITLE, book.getTitle());

  datastore.put(entity);                   // Update the Entity
}

도서 삭제

Datastore를 사용하여 도서를 삭제하려면 delete 메서드를 Key와 함께 호출해야 합니다.

@Override
public void deleteBook(Long bookId) {
  Key key = KeyFactory.createKey(BOOK_KIND, bookId);        // Create the Key
  datastore.delete(key);                      // Delete the Entity
}

도서 나열

listBooks 메서드는 URL 보안 Cursor과 함께 도서 목록 10개를 한 번에 반환합니다.

@Override
public Result<Book> listBooks(String startCursorString) {
  FetchOptions fetchOptions = FetchOptions.Builder.withLimit(10); // Only show 10 at a time
  if (startCursorString != null && !startCursorString.equals("")) {
    fetchOptions.startCursor(Cursor.fromWebSafeString(startCursorString)); // Where we left off
  }
  Query query = new Query(BOOK_KIND) // We only care about Books
      .addSort(Book.TITLE, SortDirection.ASCENDING); // Use default Index "title"
  PreparedQuery preparedQuery = datastore.prepare(query);
  QueryResultIterator<Entity> results = preparedQuery.asQueryResultIterator(fetchOptions);

  List<Book> resultBooks = entitiesToBooks(results);     // Retrieve and convert Entities
  Cursor cursor = results.getCursor();              // Where to start next time
  if (cursor != null && resultBooks.size() == 10) {         // Are we paging? Save Cursor
    String cursorString = cursor.toWebSafeString();               // Cursors are WebSafe
    return new Result<>(resultBooks, cursorString);
  } else {
    return new Result<>(resultBooks);
  }
}

색인

이 동작을 변경할 수 있지만 Datastore는 기본적으로 속성마다 색인을 만듭니다. 일부 쿼리에는 위 Query by userordered by Title 쿼리와 같이 완료하기 위해 색인에 속성이 두 개 이상 필요합니다. 사용자는 이러한 쿼리를 수동으로 지원하도록 색인을 만들거나 개발 서버를 사용하여 색인을 만들 수 있습니다.