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.
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>
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>
Das Paket von SpringBootServletInitializer
wurde geändert, also importieren Sie es erneut.
Das Paket wurde in "org.springframework.boot.web.servlet" geändert. Importieren Sie es daher erneut
Das Paket hat sich geändert, importieren Sie es also erneut
Ändern Sie erweitert WebMvcConfigurerAdapter
, um WebMvcConfigurer
zu implementieren`
Wechseln Sie zu "@ EnableWebSecurity".
https://docs.spring.io/spring-security/site/docs/current/reference/html/mvc.html
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".
application.properties
usw. geändert werden.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.
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
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
Ich werde es stillschweigend beheben
https://spring.io/blog/2017/06/20/a-preview-on-spring-data-kay#improved-naming-for-crud-repository-methods
import org.springframework.boot.test.autoconfigure.orm.jpa.AutoConfigureTestDatabase;
Von
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
Ändern Sie das Paket in
https://www.thymeleaf.org/doc/articles/thymeleaf3migration.html
Mechanisch so
find src/main/resources -type f -name "*.html" -print | xargs sed -i -e 's/th:substituteby/th:replace/g'
Mechanisch so
find src/main/resources -type f -name "*.html" -print | xargs sed -i -e 's@type=\"text/css\"@@g'
Löschen Sie den Inhalt, während Sie ihn betrachten.
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>
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 {
}
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)
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
<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.
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 ...
@ SessionScope
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 ...
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.
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 ...! !!