[JAVA] Verwenden Sie die DynamoDB-Abfragemethode mit Spring Boot

Status

TweetRepository.java


package com.pontsuyo.anyiine.domain.repository;

import com.pontsuyo.anyiine.domain.model.Tweet;
import java.util.List;
import org.socialsignin.spring.data.dynamodb.repository.EnableScan;
import org.springframework.data.repository.CrudRepository;

@EnableScan
public interface TweetRepository extends CrudRepository<Tweet, Long> {
  @Override
  List<Tweet> findAll();

  List<Tweet> findAllByType(String type);  // <-Das ist nicht gut
}

Dies ist die Repository-Klasse, die ich erstellt habe, um DynamoDB als DB für Spring-Anwendungen zu verwenden. Aber ** dies führt dazu, dass die Anwendung nicht gestartet werden kann. ** ** ** Als Gegenmaßnahme werde ich über das Erstellen einer separaten Repository-Klasse sprechen.

Umweltinformationen

Vor

In Spring liegt der Zugriff auf die Datenbank in der Verantwortung des Repositorys. Wenn Sie jedoch eine Klasse erstellen, die die von verschiedenen Bibliotheken bereitgestellte Repository-Schnittstelle erbt, müssen Sie die Methode häufig nicht selbst vorbereiten.

Spring-data-dynamodb ist praktisch, wenn DynamoDB auch als DB ausgewählt ist. Es scheint jedoch, dass ** Datenerfassung durch Abfragespezifikation (Eingrenzung durch andere Felder als Hash-Schlüssel, Bereichsschlüssel usw.) nicht implementiert ist **. Deshalb, Beim Starten der Spring-Anwendung wird ein Fehler ausgegeben und der Start schlägt fehl.

Tatsächlicher Fehler

Der Fehler beim Starten der Anwendung war wie folgt.

Unterkante der Stapelspur


Caused by: java.lang.IllegalStateException: You have defined query method in the repository but you don't have any query lookup strategy defined. The infrastructure apparently does not support query methods!
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:553) ~[spring-data-commons-2.2.7.RELEASE.jar:2.2.7.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:332) ~[spring-data-commons-2.2.7.RELEASE.jar:2.2.7.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:297) ~[spring-data-commons-2.2.7.RELEASE.jar:2.2.7.RELEASE]
	at org.springframework.data.util.Lazy.getNullable(Lazy.java:212) ~[spring-data-commons-2.2.7.RELEASE.jar:2.2.7.RELEASE]
	at org.springframework.data.util.Lazy.get(Lazy.java:94) ~[spring-data-commons-2.2.7.RELEASE.jar:2.2.7.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:300) ~[spring-data-commons-2.2.7.RELEASE.jar:2.2.7.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1855) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1792) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
	... 44 common frames omitted

Wie Sie bei näherer Betrachtung sehen können, wird dieser Fehler im Frühjahr ausgelöst. Wenn Sie den Fehlersatz grob übersetzen, "Ich habe eine Abfragemethode in diesem Repository definiert, aber es ist keine Abfragesuchstrategie definiert. Die Infrastruktur unterstützt die Abfragemethode nicht explizit!" Es wird sein.

Wenn es mit einer von Spring erstellten Bibliothek abgeschlossen ist, wird die Implementierung des Repositorys auch von Spring durchgeführt, und es sollte garantiert werden, dass die Abfragemethode unterstützt wird, aber die diesmal verwendete Spring-Data-Dynamodb unterstützt sie nicht. Es scheint, dass es nicht garantiert ist.

Die erste Lösung, die ich mir vorstellen kann, besteht darin, die Garantieeinstellungen für die Abfragemethode zu ändern, da dies nicht garantiert ist, aber es scheint, dass diese Bibliothek die Abfragemethode nicht wirklich unterstützt. (GitHub-Problem, das diesem Fall entspricht, wurde entfernt, nachdem es in das TODO des Updates auf Version 5.0.3 aufgenommen wurde. Sie können sehen, wie es passiert ist. Es scheint schwierig zu sein ...)

Also, obwohl es gewaltsam ist, habe ich beschlossen, es selbst zu implementieren. (Vielleicht gibt es andere Problemumgehungen.)

Gegenmaßnahmen

Verwenden Sie DynamoDBMapper, um eine Klasse zu definieren, die dem Repository selbst entspricht.

Verwenden Sie den von AWS bereitgestellten DynamoDBMapper, um eine Abfragemethode zu implementieren, die die Abfragesuche von DynamoDB reproduziert. Es wird anhand eines Beispiels in der offiziellen AWS-Dokumentation gezeigt. Bitte beziehen Sie sich darauf. (Bei der Implementierung dieses Links wird das Modell auch in der Klasse implementiert, die dem Repository entspricht, aber ich implementiere das Modell als separate Klasse.) https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/DynamoDBMapper.QueryScanExample.html

Hier ist das Endprodukt. (Wie lautet der Klassenname in einem solchen Fall ...) Daten in DynamoDB werden an anderer Stelle als Tweet-Klasse definiert. Stellen Sie sich vor, die DB hat eine Art Tweet-Information. Diesmal ist es in Ordnung, wenn Sie nur wissen, dass die Tweet-Klasse ein Feld mit dem Namen ** Typ ** hat.

TweetRepositoryPlugin.java


package com.pontsuyo.anyiine.domain.repository;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBScanExpression;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.pontsuyo.anyiine.domain.model.Tweet;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Repository;

/**
 *Feder für den Zugriff auf Dynamo DB-data-In Dynamodb
 *Implementierung nicht unterstützter Methoden (z. B. Scan mit Abfrage)
 *
 * issue: https://github.com/derjust/spring-data-dynamodb/issues/114
 */
@Repository
public class TweetRepositoryPlugin {

  private final DynamoDBMapper mapper;

  public TweetRepositoryPlugin(DynamoDBMapper mapper) {
    this.mapper = mapper;
  }

  public List<Tweet> findAllByType(String type) {
    DynamoDBScanExpression scanExpression =
        new DynamoDBScanExpression()
            // "type"Ist wie ein reserviertes Wort in DynamoDB, also
            //Fügen Sie einen Platzhalter in die Abfragezeichenfolge ein und ersetzen Sie ihn später.
            .withFilterExpression("#t = :val1")
            .withExpressionAttributeNames(     
                Map.of("#t", "type")
            )
            .withExpressionAttributeValues(
                Map.of(":val1", new AttributeValue().withS(type))
            );

    return mapper.scan(Tweet.class, scanExpression);
  }
}

[Über withExpressionAttributeNames](https://qiita.com/ponponpopon/items/9b723d6210a26d512a9f#%E6%B3%A8-withexpressionattributenames%E3%81%AB%E3%81%A4%E3%81%84%E3%81% A6)

Der Instanz-Mapper der DynamoDBMapper-Klasse wird vom Konstruktor injiziert, dies wird jedoch in der separat vorbereiteten und als Bean registrierten Config-Klasse definiert.

DynamoDBConfig.java


package com.pontsuyo.anyiine.config;

import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import org.socialsignin.spring.data.dynamodb.repository.config.EnableDynamoDBRepositories;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableDynamoDBRepositories(basePackages = "com.pontsuyo.anyiine.domain.repository")
public class DynamoDBConfig {

  /**
   *AWS DynamoDB-Einstellungen
   * @see com.amazonaws.auth.DefaultAWSCredentialsProviderChain
   * @return
   */
  @Bean
  public AmazonDynamoDB amazonDynamoDB() {
    return AmazonDynamoDBClientBuilder.standard()
        .withCredentials(DefaultAWSCredentialsProviderChain.getInstance())
        .withRegion(Regions.AP_NORTHEAST_1)
        .build();
  }

  @Bean
  public DynamoDBMapper dynamoDBMapper(){
    return new DynamoDBMapper(amazonDynamoDB());
  }
}

Derzeit ist es eine Service-Klasse, die die diesmal definierte Methode aufruft. Sie sollten bereits ein Repository injiziert haben, fügen Sie also einfach das Element hinzu, das Sie injizieren möchten.

TweetService.java


package com.pontsuyo.anyiine.domain.service;

import com.pontsuyo.anyiine.controller.model.DestroyRequestParameter;
import com.pontsuyo.anyiine.controller.model.UpdateRequestParameter;
import com.pontsuyo.anyiine.domain.model.Tweet;
import com.pontsuyo.anyiine.domain.repository.TweetRepository;
import com.pontsuyo.anyiine.domain.repository.TweetRepositoryPlugin;
import java.util.List;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;

@Slf4j
@Service
public class TweetService {

  private final TweetRepository tweetRepository;
  private final TweetRepositoryPlugin tweetRepositoryPlugin; // <-Dieses Mal wurde das Repository hinzugefügt

  private final Twitter twitter;

  public TweetService(TweetRepository tweetRepository, TweetRepositoryPlugin tweetRepositoryPlugin, Twitter twitter) {
    this.tweetRepository = tweetRepository;
    this.tweetRepositoryPlugin = tweetRepositoryPlugin;  // <-Dieses Mal wurde das Repository hinzugefügt
    this.twitter = twitter;
  }

  //Nachfolgend verschiedene Methodendefinitionen.

abschließend

Das ist es. Offizielle Erklärung erläutert, wie verschiedene Abfragemuster implementiert werden. Wenn die Erklärung in diesem Artikel nicht ausreicht, beziehen Sie sich bitte darauf.

Wenn jemand andere Lösungen kennt, lassen Sie es mich bitte wissen.

Hinweis: Über .withExpressionAttributeNames ()

Ich habe Kommentare in den Code aufgenommen, aber ich verwende **. WithExpressionAttributeNames () **, um die Feldnamen zu ersetzen. Der Grund dafür ist, dass das Feld ** Typ ** in der Suchabfrage, die ich dieses Mal angeben wollte, ein reserviertes Wort für DynamoDB zu sein scheint und der folgende Fehler ursprünglich ausgelöst wurde.

Invalid UpdateExpression: Attribute name is a reserved keyword; reserved keyword: type

Sie können diesen Fehler vermeiden, indem Sie den vorherigen Feldnamen ersetzen.

Referenz: https://note.kiriukun.com/entry/20190212-attribute-name-is-a-reserved-keyword-in-dynamodb

Recommended Posts

Verwenden Sie die DynamoDB-Abfragemethode mit Spring Boot
Servlet-Filter mit Spring Boot verwenden [Spring Boot 1.x, 2.x kompatibel]
Legen Sie den Kontextparameter in Spring Boot fest
Spring Boot 2 Multiprojekt mit Gradle
Verwendung von CommandLineRunner im Spring Batch von Spring Boot
Spring Boot + Springfox Springfox-Boot-Starter 3.0.0 Verwendung
Verwenden Sie Spring JDBC mit Spring Boot
Wichtige Änderungen in Spring Boot 1.5
NoHttpResponseException in Spring Boot + WireMock
Memo zur Spring Boot Controller-Methode
Aufrufen und Verwenden der API in Java (Spring Boot)
Verwenden Sie thymeleaf3 mit parent, ohne Spring-Boot-Starter-Parent in Spring Boot anzugeben
Verwenden Sie im Spring Boot @ControllerAdvice, @ExceptionHandler, HandlerExceptionResolver, um Ausnahmen abzufangen
Wie man Lombok im Frühling benutzt
Verwenden Sie die Standardauthentifizierung mit Spring Boot
Frühlingsstiefel Hallo Welt in Eclipse
Spring Boot-Anwendungsentwicklung in Eclipse
Spring Boot + PostgreSQL-Fehlerbehebungsmethode
Implementieren Sie die REST-API mit Spring Boot
Was ist @Autowired im Spring Boot?
Verwenden Sie DBUnit für den Spring Boot-Test
Implementieren Sie die Spring Boot-Anwendung in Gradle
Verwendung von ModelMapper (Spring Boot)
Beginnend mit Spring Boot 0. Verwenden Sie Spring CLI
Verwendung von Thymeleaf mit Spring Boot
Starten Sie mit IntelliJ ein (altes) Spring Boot-Projekt
Erstellen Sie mit Gradle ein Spring Boot + Docker-Image
Statische Dateizugriffspriorität beim Spring Boot
Spring Boot-Protokoll im JSON-Format ausgeben
Memorandum zum Herunterladen lokaler Dateien mit Spring Boot
Lösen Sie die Thymeleaf-Syntaxprüfung in Spring Boot
[Trainieren! ] Zeigen Sie Hello World mit Spring Boot an
Memo zur Installationsmethode von Spring Boot + Thymeleaf Boot Strap
DI SessionScope Bean im Spring Boot 2-Filter
Verwenden Sie den Cache mit EhCashe 2.x mit Spring Boot
Ändern Sie das Sitzungszeitlimit in Spring Boot
SameSite-Cookie im Spring Boot (Spring Web MVC + Tomcat)
Testen Sie den Controller mit Mock MVC im Spring Boot
Asynchrone Verarbeitung mit regelmäßiger Ausführung in Spring Boot
Verwenden Sie den Thymeleaf-Textvorlagenmodus von Spring Boot
Verwendung von MyBatis2 (iBatis) mit Spring Boot 1.4 (Spring 4)
Führen Sie ein Spring Boot-Projekt mit VS-Code aus
Verwendung des eingebauten h2db mit Federstiefel
Anforderungs- und Antwortprotokolle mit Spring Boot ausgeben
Fordern Sie Spring Boot heraus
So fügen Sie in Spring Boot einen Klassenpfad hinzu
Java-Tipps - Erstellen Sie mit Gradle ein Spring Boot-Projekt
Spring Boot Form
So binden Sie mit einer Eigenschaftendatei in Spring Boot
[JAVA] [Spring] [MyBatis] Verwenden Sie IN () mit SQL Builder
Spring Boot Denken Sie daran
gae + frühlingsstiefel
Anmerkungen, die in Spring Boot-Aufgabenverwaltungstools verwendet werden
Zeigen Sie die Gradle-Aufgabe im Spring Boot-Projekt an
Überprüfen Sie das Verhalten von getOne-, findById- und Abfragemethoden mit Spring Boot + Spring Data JPA
Nehmen Sie das externe Glas mit Spring boot2 + Maven3 in das Paket auf
So erstellen Sie ein Spring Boot-Projekt in IntelliJ
Codieren Sie Abfrageparameter im Frühjahr mit Uri Components Builder
SSO mit GitHub OAuth in der Spring Boot 1.5.x-Umgebung
Testen Sie die Klasse mit Feldinjektion im Spring-Boot-Test, ohne den Spring-Container zu verwenden
Bis Sie mit der Entwicklung mit Spring Boot in Eclipse 1 beginnen