[JAVA] Was ich bei der Migration von der Spring Boot 1.4-Serie zur 2.0-Serie getan habe

Einführung

Letztes Mal wurde von Spring Boot 1.5 auf Spring Boot 2.0 aktualisiert. Dieses Mal werde ich in einem anderen Projekt darüber schreiben, wovon ich süchtig war, als ich es von 1.4 auf 2.0 erhöhte.

Die Hauptschwierigkeit war diesmal

Es ist herum.

Erhöhen Sie die Version von Spring Boot

Aktualisierte Spring-Boot-Starter-Parent-Version

Geben Sie die Spring Boot-Version in pom.xml an.

pom.xml


  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.3.RELEASE</version>
    <relativePath />
  </parent>

Hikari PC-Abhängigkeiten wurden entfernt

Ich habe ursprünglich HikariPC verwendet, daher werde ich es aus den Abhängigkeiten entfernen.

pom.xml


    <dependency>
	<groupId>com.zaxxer</groupId>
	<artifactId>HikariCP</artifactId>
    </dependency>

Kompilieren und zerstören Sie Fehler

SpringBootServletInitializer nicht gefunden

1.png

Das Paket von SpringBootServletInitializer wurde geändert, also importieren Sie es erneut.

Fehlende org.springframework.boot.context.embedded.

2.png

Das Paket wurde in "org.springframework.boot.web.servlet" geändert. Importieren Sie es daher erneut

DataSourceBuilder nicht gefunden

3.png

Das Paket hat sich geändert, importieren Sie es also erneut

WebMvcConfigurerAdapter ist veraltet

Ändern Sie erweitert WebMvcConfigurerAdapter, um WebMvcConfigurer zu implementieren`

@EnableWebMvcSecurity veraltet

Wechseln Sie zu "@ EnableWebSecurity".

https://docs.spring.io/spring-security/site/docs/current/reference/html/mvc.html

org.apache.velocity.app nicht gefunden

4.png

Migrieren Sie von "Geschwindigkeit" zu "Schnurrbart".

pom.xml


-    <dependency>
-	<groupId>org.apache.velocity</groupId>
-	<artifactId>velocity</artifactId>
-    </dependency>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-mustache</artifactId>
+    </dependency>

Ersetzen Sie die Geschwindigkeitsvorlagendatei "* .vm" durch die Schnurrbartvorlagendatei "* .mustache".

Entsprechend dem Format der Schnurrbartvorlage

${hoge}
↓
{{hoge}}

Ersetzen Sie alles so

Sie können sie alle gleichzeitig durch eine Shell ersetzen. Wenn Sie dies jedoch mit dem IntelliJ-Refactor tun, wird auch der Anrufercode gefunden und mitgeteilt. Wenn die Anzahl also klein ist, ist der IntelliJ-Refactor möglicherweise gut.

org.json nicht gefunden

5.png

Fügen Sie die folgende Abhängigkeit hinzu

pom.xml


	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-json</artifactId>
	</dependency>

Mit dem folgenden Paket erneut importieren org.springframework.boot.configurationprocessor.json.JSONObject

Fehler in SpringApplication.run

6.png

Das Argument von SpringApplication.run hat sich geändert

Geändert wie folgt

        public static void main(String[] args) {
-               Object[] objects = { HogeApplication.class, FugaService.class };
-               SpringApplication.run(objects, args);
+               final SpringApplication application = new SpringApplication(HogeApplication.class, FugaService.class);
+               application.run(args);
        }

Erben Sie außerdem die folgende Klasse

SpringBootServletInitializer

Korrespondenz zur Änderung der JPA-Methode

7.png

Ich werde es stillschweigend beheben

https://spring.io/blog/2017/06/20/a-preview-on-spring-data-kay#improved-naming-for-crud-repository-methods

AutoConfigureTestDatabase nicht gefunden

8.png

import org.springframework.boot.test.autoconfigure.orm.jpa.AutoConfigureTestDatabase; Von import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; Ändern Sie das Paket in

Thymeleaf Migration

https://www.thymeleaf.org/doc/articles/thymeleaf3migration.html

Ersetzen Sie th: ersetzen durch th: ersetzen

Mechanisch so

find src/main/resources -type f -name "*.html" -print | xargs sed -i  -e 's/th:substituteby/th:replace/g'

Typ = "text / css" zum Lesen von CSS im Link-Tag wurde entfernt

Mechanisch so

find src/main/resources -type f -name "*.html" -print | xargs sed -i  -e 's@type=\"text/css\"@@g'

Inline = "text" / inline = "inline" löschen

Löschen Sie den Inhalt, während Sie ihn betrachten.

Thymeleaf in Script-Tag wird nicht erweitert

So ein Typ

<script>(window.dataLayer || (window.dataLayer = [])).push(<span th:remove="tag" th:utext="${hoge}"/>)</script>

Repariere es so

<script type="text/javascript" th:inline="javascript">/*<![CDATA[*/
     (window.dataLayer || (window.dataLayer = [])).push(/*[(${hoge})]*/)
 /*]]>*/</script>

Andere

Wenn im Spring Boot @EnableWebMvc angehängt ist, löschen Sie es

SessionScope

Fehler, wenn bei der Ausführung von "onAuthenticationSuccess" von Spring Security nicht auf "@ SessionScope" verwiesen werden kann Error creating bean with name 'user': Scope 'session' is not active for the current thread;

Erstellen Sie die folgende Konfigurationsdatei

WebRequestContextListener.java


package jp.hoge;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextListener;

import javax.servlet.annotation.WebListener;

@Configuration
@WebListener
public class WebRequestContextListener extends RequestContextListener {
}

Fehler in der SaveAndFlush-Methode im Ruhezustand

java.sql.SQLSyntaxErrorException: Table 'hoge.hibernate_sequence' doesn't exist
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:536)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:513)
	at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:115)
	at com.mysql.cj.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:1983)
	at com.mysql.cj.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1826)
	at com.mysql.cj.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1923)
	at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52)

Ändern Sie GenerationType

-    @GeneratedValue(strategy=GenerationType.AUTO)
+    @GeneratedValue(strategy=GenerationType.IDENTITY)

Ruhezustand Fehler während der Ausführung

org.springframework.dao.InvalidDataAccessResourceUsageException: error performing isolated work; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: error performing
 isolated work
        at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:242)
        at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:225)
        at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527)
        at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
        at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
        at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
        at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
        at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
        at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
        at com.sun.proxy.$Proxy127.save(Unknown Source)
        at jp.hoge.service.FugaService.execute(FugaService.java:218)
        at jp.hoge.controller.FugaController.execute(FugaController.java:101)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)

Die Generatorzuordnungen von Hibernate haben sich geändert.

Korrigiert durch Hinzufügen der folgenden Einstellungen zu application.properties

application.properties


spring.jpa.hibernate.use-new-id-generator-mappings=false

Nach dem Einsatz bei STG etc.

Fehler beim Laden des Profils

<SpringProfile> in logback-spring.xml kann das Profil nicht korrekt laden Definieren Sie die ausführbare Datei als "-Dspring-boot.run.profiles = Umgebungsname".

In diesem Projekt werden wir also Krieg gegen Tomcat einsetzen Definieren Sie es in application.properties als spring-boot.run.profiles = Umgebungsname.

Tatsächlich wird das Profil geteilt, wenn die Kriegsdatei in pom.xml generiert wird. Daher wird es wie folgt definiert.

application.properties


spring-boot.run.profiles=${spring.profiles.active}

pom.xml


<profiles>
		<profile>
			<id>local</id>
			<properties>
				<spring.profiles.active>local</spring.profiles.active>
			</properties>
		</profile>
		<profile>
			<id>stg</id>
			<properties>
				<spring.profiles.active>stg</spring.profiles.active>
			</properties>
		</profile>
</profiles>

Profil zur Erstellungszeit

mvn package -Pstg

Mit diesem Gefühl ist es in application.properties eingebettet.

Nach der Anmeldung über Spring Security sind alle Mitgliedsvariablen des Benutzerobjekts nach dem Abrufen der Sitzung null.

NullPointerExepotion tritt auf, wenn versucht wird, auf eine Mitgliedsvariable von User zuzugreifen Selbst wenn Sie sich den Inhalt von Redis ansehen, können Sie ihn nicht lesen, da er serialisiert ist ...

Erstellen Sie einmal einen Serializer, der in JSON konvertiert und in Redis mit dem folgenden Gefühl registriert

HttpSessionConfig.java


@ConditionalOnProperty(name = "spring.session.store-type", havingValue = "redis", matchIfMissing = false)
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 20 * 24 * 60 * 60) //default=1800 -> 20days
@Configuration
public class HttpSessionConfig implements BeanClassLoaderAware {

   @Autowired
   private LettuceConnectionFactory lettuceConnectionFactory;

   private ClassLoader classLoader;

   @Bean
   public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
	final ObjectMapper mapper = new ObjectMapper()
			.registerModules(SecurityJackson2Modules.getModules(classLoader))
			.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
	return new GenericJackson2JsonRedisSerializer(mapper);
  }

      //Für Elasticache
      @Bean
      public static ConfigureRedisAction configureRedisAction() {
          return ConfigureRedisAction.NO_OP;
      }

	@Override
	public void setBeanClassLoader(final ClassLoader classLoader) {
		this.classLoader = classLoader;
	}
}

Beim Übergang zu Controller nach Abschluss der Anmeldung wurde Redis mit allen Feldern null festgelegt.

Der Controller bestimmt nach der Anmeldung, ob die "ID" im "Benutzer" -Objekt null ist, und packt sie neu, wenn sie null ist. Nach dem Anmelden kann ich die Sitzung problemlos abwickeln.

Eigentlich wollte ich Sitzungsinformationen im JSON-Format haben können, aber da die Struktur der User-Klasse eine komplizierte verschachtelte Struktur war, gab ich aus Zeitgründen auf ... Zu viele Informationen in der Benutzerklasse ...

Korrespondenz zum Zeitpunkt der Bereitstellung der Produktion

Es scheint, dass sich die intern für die Serialisierung und Deserialisierung behandelte "SerialVersionUID" mit dem Versions-Upgrade von SpringSession geändert hat. Wenn Sie also den aktualisierten Code bereitstellen, können Benutzer, die bereits angemeldet sind, die Sitzungsinformationen nicht deserialisieren.

Also werde ich beim Deserialisieren die Korrespondenz einfügen.

https://sdqali.in/blog/2016/11/02/handling-deserialization-errors-in-spring-redis-sessions/

Der Artikel ist etwas alt und die abhängigen Bibliotheken haben sich geändert, daher habe ich ihn wie folgt geändert.

HttpSessionConfig.java


- public class HttpSessionConfig {
+ public class HttpSessionConfig extends RedisHttpSessionConfiguration {

+	@Autowired
+	RedisTemplate<Object, Object> redisTemplate;
+ 	@Bean
+	@Override
+	public <S extends Session> SessionRepositoryFilter<? extends Session> springSessionRepositoryFilter(SessionRepository<S> sessionRepository) {
+		return super.springSessionRepositoryFilter(new SafeDeserializationRepository<>(sessionRepository, redisTemplate));
+	}

SafeDeserializationRepository.java


public class SafeDeserializationRepository<S extends Session> implements SessionRepository<S> {
    private final SessionRepository<S> delegate;
    private final RedisTemplate<Object, Object> redisTemplate;
     private static final String BOUNDED_HASH_KEY_PREFIX = "spring:session:sessions:";
     public SafeDeserializationRepository(SessionRepository<S> delegate,
            RedisTemplate<Object, Object> redisTemplate) {
        this.delegate = delegate;
        this.redisTemplate = redisTemplate;
    }
     @Override
    public S createSession() {
        return delegate.createSession();
    }
     @Override
    public void save(S session) {
        delegate.save(session);
    }
     @Override
    public S findById(String id) {
        try {
            return delegate.findById(id);
        } catch(SerializationException e) {
            log.info("Deleting non-deserializable session with key {}", id);
            redisTemplate.delete(BOUNDED_HASH_KEY_PREFIX + id);
            return null;
        }
    }
     @Override
    public void deleteById(String id) {
        delegate.deleteById(id);
    }
}

Auf diese Weise können sich vorhandene Benutzer einmal abmelden, sich erneut anmelden, um neue Sitzungsdaten in Redis zu speichern, und dann darauf verweisen.

Zusammenfassung

Im Allgemeinen hat die oben genannte Unterstützung dazu geführt, dass es in einer Produktionsumgebung funktioniert. (Ich denke, es gibt andere)

Ursprünglich sollte Tomcat auch die Serie 8.5 oder höher sein, aber 8.0 scheint kein Problem zu sein, sodass ich vergessen habe, Tomcat zu aktualisieren.

Wenn Sie einige Hauptversionen von Spring Boot überspringen, wird es sehr schwierig, also lassen Sie uns regelmäßig aktualisieren ...! !!

Referenzseite

Recommended Posts

Was ich bei der Migration von der Spring Boot 1.4-Serie zur 2.0-Serie getan habe
Was ich bei der Migration von der Spring Boot 1.5-Serie zur 2.0-Serie getan habe
Tokoro habe ich in der Migration von Wicket 7 auf 8 umgeschrieben
Rüsten Sie den Federstiefel von der 1.5-Serie auf die 2.0-Serie auf
Die Geschichte der Erhöhung von Spring Boot von 1.5 auf 2.1 Serie Teil2
Die Geschichte der Erhöhung der Spring Boot 1.5-Serie auf die 2.1-Serie
Versuchen Sie Spring Boot von 0 bis 100.
03. Ich habe eine Anfrage von Spring Boot an die Postleitzahlensuch-API gesendet
05. Ich habe versucht, die Quelle von Spring Boot zu löschen
Ich habe versucht, die Kapazität von Spring Boot zu reduzieren
Was ist @Autowired im Spring Boot?
Ich möchte die maximale Dateigröße für das Hochladen von Dateien für jede URL in Spring Boot steuern
02. Ich habe eine API erstellt, um eine Verbindung von Spring Boot zu MySQL (My Batis) herzustellen.
Ich möchte die Standardfehlermeldung von Spring Boot steuern
[Android] Ich möchte den Listener über die Schaltfläche in ListView abrufen
Die Geschichte des Übergangs von Spring Boot 1.5 zu 2.1
Änderungen bei der Migration von Spring Boot 1.5 auf Spring Boot 2.0
Änderungen bei der Migration von Spring Boot 2.0 zu Spring Boot 2.2
Ich war süchtig nach Spring's @Transactional
Ich möchte die Methode des Controllers kennen, bei der die Ausnahme im ExceptionHandler von Spring Boot ausgelöst wurde
[Spring Boot] Ich habe untersucht, wie die Nachbearbeitung der empfangenen Anforderung implementiert werden kann.
Schritte zum Ausführen von Spring Boot beziehen sich auf die Werte in der Eigenschaftendatei
Was ich getan habe, als JSF keine Datenbankinformationen in der Ansicht anzeigen konnte
Mein Memorandum, dass ich ValidationMessages.properties UTF8 in Spring Boot erstellen möchte
So erhalten Sie den Einstellungswert (Eigenschaftswert) aus der Datenbank in Spring Framework
Was ist CHECKSTYLE: OFF in der Java-Quelle? Checkstyle zu wissen von
Zusammenfassung dessen, was ich über Spring Boot gelernt habe
[Rails] Ich habe versucht, die Version von Rails von 5.0 auf 5.2 zu erhöhen
Migration von Eclipse zu IntelliJ (unterwegs)
Ich habe versucht, die Sitzung in Rails zu organisieren
So fügen Sie in Spring Boot einen Klassenpfad hinzu
Was ich getan habe, als ich Java zu Kotlin konvertiert habe
So binden Sie mit einer Eigenschaftendatei in Spring Boot
Versuchen Sie, die Migration mit Spring Boot Flyway zu automatisieren
Ich wollte Spring Boot in einem Multiprojekt gradle
[Spring Boot] So verweisen Sie auf die Eigenschaftendatei
Zusammenfassung dessen, was ich in Spring Batch gelernt habe
Zeigen Sie die Gradle-Aufgabe im Spring Boot-Projekt an
Ich möchte den Wert in Ruby erhalten
[Spring Boot] So rufen Sie Eigenschaften dynamisch aus einer in einer URL enthaltenen Zeichenfolge ab
So legen Sie Umgebungsvariablen in der Eigenschaftendatei der Spring-Boot-Anwendung fest
Was ist ... (3 Punkte) in der Java-Quelle gefunden? Argument mit variabler Länge, von dem man wissen muss
Ich war süchtig nach NoSuchMethodError in Cloud-Endpunkten
Geben Sie die statische Ressourcencodierung in Spring Boot an
Wovon ich süchtig war, als ich eine Spring Boot-Anwendung mit VS Code entwickelte
[Java] Ich möchte die Differenz zum Datum berechnen
Ich möchte eine TraceId in das Protokoll einbetten
Untersuchte asynchrone Ausführung von Abfragen in Spring Boot 1.5.9
paiza Was ich getan habe, um Ruby B Rang zu werden
So erstellen Sie ein Spring Boot-Projekt in IntelliJ
Verwendung von CommandLineRunner im Spring Batch von Spring Boot
Führen Sie swagger-ui in die in Spring Boot implementierte REST-API ein
Stellen Sie das Spring Boot-Projekt in XAMPP für Tomcat bereit
Ich habe versucht, die Methode der gegenseitigen Teilung von Eugrid in Java zu implementieren