Merge pull request #5879 from vpavic:session-jdbc-initializer
* pr/5879: Polish "Add Spring Session JDBC database initializer" Add Spring Session JDBC database initializer Allow Tomcat context root redirect to be configured via the environment
This commit is contained in:
commit
31a5d7f876
|
|
@ -20,9 +20,13 @@ import javax.sql.DataSource;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Conditional;
|
import org.springframework.context.annotation.Conditional;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.session.SessionRepository;
|
import org.springframework.session.SessionRepository;
|
||||||
import org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessionConfiguration;
|
import org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessionConfiguration;
|
||||||
|
|
||||||
|
|
@ -31,13 +35,23 @@ import org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessi
|
||||||
*
|
*
|
||||||
* @author Eddú Meléndez
|
* @author Eddú Meléndez
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
|
* @author Vedran Pavic
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@ConditionalOnClass(JdbcTemplate.class)
|
||||||
@ConditionalOnMissingBean(SessionRepository.class)
|
@ConditionalOnMissingBean(SessionRepository.class)
|
||||||
@ConditionalOnBean(DataSource.class)
|
@ConditionalOnBean(DataSource.class)
|
||||||
@Conditional(SessionCondition.class)
|
@Conditional(SessionCondition.class)
|
||||||
class JdbcSessionConfiguration {
|
class JdbcSessionConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public JdbcSessionDatabaseInitializer jdbcSessionDatabaseInitializer(
|
||||||
|
SessionProperties properties, DataSource dataSource,
|
||||||
|
ResourceLoader resourceLoader) {
|
||||||
|
return new JdbcSessionDatabaseInitializer(properties, dataSource, resourceLoader);
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public static class SpringBootJdbcHttpSessionConfiguration
|
public static class SpringBootJdbcHttpSessionConfiguration
|
||||||
extends JdbcHttpSessionConfiguration {
|
extends JdbcHttpSessionConfiguration {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2016 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.autoconfigure.session;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
|
||||||
|
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
|
||||||
|
import org.springframework.jdbc.support.JdbcUtils;
|
||||||
|
import org.springframework.jdbc.support.MetaDataAccessException;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializer for Spring Session schema.
|
||||||
|
*
|
||||||
|
* @author Vedran Pavic
|
||||||
|
* @since 1.4.0
|
||||||
|
*/
|
||||||
|
public class JdbcSessionDatabaseInitializer {
|
||||||
|
|
||||||
|
private SessionProperties properties;
|
||||||
|
|
||||||
|
private DataSource dataSource;
|
||||||
|
|
||||||
|
private ResourceLoader resourceLoader;
|
||||||
|
|
||||||
|
public JdbcSessionDatabaseInitializer(SessionProperties properties,
|
||||||
|
DataSource dataSource, ResourceLoader resourceLoader) {
|
||||||
|
Assert.notNull(properties, "SessionProperties must not be null");
|
||||||
|
Assert.notNull(dataSource, "DataSource must not be null");
|
||||||
|
Assert.notNull(resourceLoader, "ResourceLoader must not be null");
|
||||||
|
this.properties = properties;
|
||||||
|
this.dataSource = dataSource;
|
||||||
|
this.resourceLoader = resourceLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
protected void initialize() {
|
||||||
|
if (this.properties.getJdbc().getInitializer().isEnabled()) {
|
||||||
|
String platform = getDatabaseType();
|
||||||
|
if ("hsql".equals(platform)) {
|
||||||
|
platform = "hsqldb";
|
||||||
|
}
|
||||||
|
if ("postgres".equals(platform)) {
|
||||||
|
platform = "postgresql";
|
||||||
|
}
|
||||||
|
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
|
||||||
|
String schemaLocation = this.properties.getJdbc().getSchema();
|
||||||
|
schemaLocation = schemaLocation.replace("@@platform@@", platform);
|
||||||
|
populator.addScript(this.resourceLoader.getResource(schemaLocation));
|
||||||
|
populator.setContinueOnError(true);
|
||||||
|
DatabasePopulatorUtils.execute(populator, this.dataSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDatabaseType() {
|
||||||
|
try {
|
||||||
|
String databaseProductName = JdbcUtils.extractDatabaseMetaData(
|
||||||
|
this.dataSource, "getDatabaseProductName").toString();
|
||||||
|
return JdbcUtils.commonDatabaseName(databaseProductName).toLowerCase();
|
||||||
|
}
|
||||||
|
catch (MetaDataAccessException ex) {
|
||||||
|
throw new IllegalStateException("Unable to detect database type", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -26,6 +26,7 @@ import org.springframework.session.data.redis.RedisFlushMode;
|
||||||
*
|
*
|
||||||
* @author Tommy Ludwig
|
* @author Tommy Ludwig
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
|
* @author Vedran Pavic
|
||||||
* @since 1.4.0
|
* @since 1.4.0
|
||||||
*/
|
*/
|
||||||
@ConfigurationProperties("spring.session")
|
@ConfigurationProperties("spring.session")
|
||||||
|
|
@ -103,11 +104,29 @@ public class SessionProperties {
|
||||||
|
|
||||||
public static class Jdbc {
|
public static class Jdbc {
|
||||||
|
|
||||||
|
private static final String DEFAULT_SCHEMA_LOCATION = "classpath:org/springframework/"
|
||||||
|
+ "session/jdbc/schema-@@platform@@.sql";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Path to the SQL file to use to initialize the database schema.
|
||||||
|
*/
|
||||||
|
private String schema = DEFAULT_SCHEMA_LOCATION;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of database table used to store sessions.
|
* Name of database table used to store sessions.
|
||||||
*/
|
*/
|
||||||
private String tableName = "SPRING_SESSION";
|
private String tableName = "SPRING_SESSION";
|
||||||
|
|
||||||
|
private final Initializer initializer = new Initializer();
|
||||||
|
|
||||||
|
public String getSchema() {
|
||||||
|
return this.schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSchema(String schema) {
|
||||||
|
this.schema = schema;
|
||||||
|
}
|
||||||
|
|
||||||
public String getTableName() {
|
public String getTableName() {
|
||||||
return this.tableName;
|
return this.tableName;
|
||||||
}
|
}
|
||||||
|
|
@ -116,6 +135,27 @@ public class SessionProperties {
|
||||||
this.tableName = tableName;
|
this.tableName = tableName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Initializer getInitializer() {
|
||||||
|
return initializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Initializer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the required session tables on startup if necessary.
|
||||||
|
*/
|
||||||
|
private boolean enabled = true;
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return this.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Mongo {
|
public static class Mongo {
|
||||||
|
|
|
||||||
|
|
@ -646,6 +646,12 @@ public class ServerProperties
|
||||||
*/
|
*/
|
||||||
private int maxHttpHeaderSize = 0; // bytes
|
private int maxHttpHeaderSize = 0; // bytes
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether requests to the context root should be redirected by appending a / to
|
||||||
|
* the path.
|
||||||
|
*/
|
||||||
|
private Boolean redirectContextRoot;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Character encoding to use to decode the URI.
|
* Character encoding to use to decode the URI.
|
||||||
*/
|
*/
|
||||||
|
|
@ -742,6 +748,14 @@ public class ServerProperties
|
||||||
this.portHeader = portHeader;
|
this.portHeader = portHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getRedirectContextRoot() {
|
||||||
|
return this.redirectContextRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRedirectContextRoot(Boolean redirectContextRoot) {
|
||||||
|
this.redirectContextRoot = redirectContextRoot;
|
||||||
|
}
|
||||||
|
|
||||||
public String getRemoteIpHeader() {
|
public String getRemoteIpHeader() {
|
||||||
return this.remoteIpHeader;
|
return this.remoteIpHeader;
|
||||||
}
|
}
|
||||||
|
|
@ -789,6 +803,9 @@ public class ServerProperties
|
||||||
customizeConnectionTimeout(factory,
|
customizeConnectionTimeout(factory,
|
||||||
serverProperties.getConnectionTimeout());
|
serverProperties.getConnectionTimeout());
|
||||||
}
|
}
|
||||||
|
if (this.redirectContextRoot != null) {
|
||||||
|
customizeRedirectContextRoot(factory, this.redirectContextRoot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void customizeConnectionTimeout(
|
private void customizeConnectionTimeout(
|
||||||
|
|
@ -911,6 +928,19 @@ public class ServerProperties
|
||||||
factory.addContextValves(valve);
|
factory.addContextValves(valve);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void customizeRedirectContextRoot(
|
||||||
|
TomcatEmbeddedServletContainerFactory factory,
|
||||||
|
final boolean redirectContextRoot) {
|
||||||
|
factory.addContextCustomizers(new TomcatContextCustomizer() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void customize(Context context) {
|
||||||
|
context.setMapperContextRootRedirectEnabled(redirectContextRoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public static class Accesslog {
|
public static class Accesslog {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2016 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.autoconfigure.session;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
|
|
||||||
|
import org.springframework.beans.DirectFieldAccessor;
|
||||||
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||||
|
import org.springframework.jdbc.BadSqlGrammarException;
|
||||||
|
import org.springframework.jdbc.core.JdbcOperations;
|
||||||
|
import org.springframework.session.jdbc.JdbcOperationsSessionRepository;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JDBC specific tests for {@link SessionAutoConfiguration}.
|
||||||
|
*
|
||||||
|
* @author Vedran Pavic
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
*/
|
||||||
|
public class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfigurationTests {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defaultConfig() {
|
||||||
|
load(Arrays.asList(EmbeddedDataSourceConfiguration.class,
|
||||||
|
DataSourceTransactionManagerAutoConfiguration.class),
|
||||||
|
"spring.session.store-type=jdbc");
|
||||||
|
JdbcOperationsSessionRepository repository = validateSessionRepository(
|
||||||
|
JdbcOperationsSessionRepository.class);
|
||||||
|
assertThat(new DirectFieldAccessor(repository).getPropertyValue("tableName"))
|
||||||
|
.isEqualTo("SPRING_SESSION");
|
||||||
|
assertThat(this.context.getBean(JdbcOperations.class)
|
||||||
|
.queryForList("select * from SPRING_SESSION")).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void disableDatabaseInitializer() {
|
||||||
|
load(Arrays.asList(EmbeddedDataSourceConfiguration.class,
|
||||||
|
DataSourceTransactionManagerAutoConfiguration.class),
|
||||||
|
"spring.session.store-type=jdbc",
|
||||||
|
"spring.session.jdbc.initializer.enabled=false");
|
||||||
|
JdbcOperationsSessionRepository repository = validateSessionRepository(
|
||||||
|
JdbcOperationsSessionRepository.class);
|
||||||
|
assertThat(new DirectFieldAccessor(repository).getPropertyValue("tableName"))
|
||||||
|
.isEqualTo("SPRING_SESSION");
|
||||||
|
this.thrown.expect(BadSqlGrammarException.class);
|
||||||
|
assertThat(this.context.getBean(JdbcOperations.class)
|
||||||
|
.queryForList("select * from SPRING_SESSION")).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void customTableName() {
|
||||||
|
load(Arrays.asList(EmbeddedDataSourceConfiguration.class,
|
||||||
|
DataSourceTransactionManagerAutoConfiguration.class),
|
||||||
|
"spring.session.store-type=jdbc",
|
||||||
|
"spring.session.jdbc.table-name=FOO_BAR",
|
||||||
|
"spring.session.jdbc.schema=classpath:session/custom-schema-h2.sql");
|
||||||
|
JdbcOperationsSessionRepository repository = validateSessionRepository(
|
||||||
|
JdbcOperationsSessionRepository.class);
|
||||||
|
assertThat(new DirectFieldAccessor(repository).getPropertyValue("tableName"))
|
||||||
|
.isEqualTo("FOO_BAR");
|
||||||
|
assertThat(this.context.getBean(JdbcOperations.class)
|
||||||
|
.queryForList("select * from FOO_BAR")).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -29,8 +29,6 @@ import org.junit.rules.ExpectedException;
|
||||||
import org.springframework.beans.DirectFieldAccessor;
|
import org.springframework.beans.DirectFieldAccessor;
|
||||||
import org.springframework.beans.factory.BeanCreationException;
|
import org.springframework.beans.factory.BeanCreationException;
|
||||||
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
|
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
|
|
||||||
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
|
||||||
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
|
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration;
|
import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
@ -39,7 +37,6 @@ import org.springframework.session.ExpiringSession;
|
||||||
import org.springframework.session.MapSessionRepository;
|
import org.springframework.session.MapSessionRepository;
|
||||||
import org.springframework.session.SessionRepository;
|
import org.springframework.session.SessionRepository;
|
||||||
import org.springframework.session.data.mongo.MongoOperationsSessionRepository;
|
import org.springframework.session.data.mongo.MongoOperationsSessionRepository;
|
||||||
import org.springframework.session.jdbc.JdbcOperationsSessionRepository;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.BDDMockito.given;
|
import static org.mockito.BDDMockito.given;
|
||||||
|
|
@ -106,29 +103,6 @@ public class SessionAutoConfigurationTests extends AbstractSessionAutoConfigurat
|
||||||
assertThat(getSessionTimeout(repository)).isNull();
|
assertThat(getSessionTimeout(repository)).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void jdbcSessionStore() {
|
|
||||||
load(Arrays.asList(EmbeddedDataSourceConfiguration.class,
|
|
||||||
DataSourceTransactionManagerAutoConfiguration.class),
|
|
||||||
"spring.session.store-type=jdbc");
|
|
||||||
JdbcOperationsSessionRepository repository = validateSessionRepository(
|
|
||||||
JdbcOperationsSessionRepository.class);
|
|
||||||
assertThat(new DirectFieldAccessor(repository).getPropertyValue("tableName"))
|
|
||||||
.isEqualTo("SPRING_SESSION");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void jdbcSessionStoreCustomTableName() {
|
|
||||||
load(Arrays.asList(EmbeddedDataSourceConfiguration.class,
|
|
||||||
DataSourceTransactionManagerAutoConfiguration.class),
|
|
||||||
"spring.session.store-type=jdbc",
|
|
||||||
"spring.session.jdbc.table-name=FOO_BAR");
|
|
||||||
JdbcOperationsSessionRepository repository = validateSessionRepository(
|
|
||||||
JdbcOperationsSessionRepository.class);
|
|
||||||
assertThat(new DirectFieldAccessor(repository).getPropertyValue("tableName"))
|
|
||||||
.isEqualTo("FOO_BAR");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void hazelcastSessionStore() {
|
public void hazelcastSessionStore() {
|
||||||
load(Collections.<Class<?>>singletonList(HazelcastConfiguration.class),
|
load(Collections.<Class<?>>singletonList(HazelcastConfiguration.class),
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import javax.servlet.ServletException;
|
||||||
import javax.servlet.SessionCookieConfig;
|
import javax.servlet.SessionCookieConfig;
|
||||||
import javax.servlet.SessionTrackingMode;
|
import javax.servlet.SessionTrackingMode;
|
||||||
|
|
||||||
|
import org.apache.catalina.Context;
|
||||||
import org.apache.catalina.Valve;
|
import org.apache.catalina.Valve;
|
||||||
import org.apache.catalina.valves.RemoteIpValve;
|
import org.apache.catalina.valves.RemoteIpValve;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
|
@ -41,6 +42,7 @@ import org.springframework.beans.MutablePropertyValues;
|
||||||
import org.springframework.boot.bind.RelaxedDataBinder;
|
import org.springframework.boot.bind.RelaxedDataBinder;
|
||||||
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
|
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
|
||||||
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
|
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
|
||||||
|
import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer;
|
||||||
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
||||||
import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory;
|
import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory;
|
||||||
import org.springframework.boot.web.servlet.ServletContextInitializer;
|
import org.springframework.boot.web.servlet.ServletContextInitializer;
|
||||||
|
|
@ -150,6 +152,30 @@ public class ServerPropertiesTests {
|
||||||
.isEqualTo("10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}");
|
.isEqualTo("10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void redirectContextRootIsNotConfiguredByDefault() throws Exception {
|
||||||
|
bindProperties(new HashMap<String, String>());
|
||||||
|
ServerProperties.Tomcat tomcat = this.properties.getTomcat();
|
||||||
|
assertThat(tomcat.getRedirectContextRoot()).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void redirectContextRootCanBeConfigured() throws Exception {
|
||||||
|
Map<String, String> map = new HashMap<String, String>();
|
||||||
|
map.put("server.tomcat.redirect-context-root", "false");
|
||||||
|
bindProperties(map);
|
||||||
|
ServerProperties.Tomcat tomcat = this.properties.getTomcat();
|
||||||
|
assertThat(tomcat.getRedirectContextRoot()).isEqualTo(false);
|
||||||
|
TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory();
|
||||||
|
this.properties.customize(container);
|
||||||
|
Context context = mock(Context.class);
|
||||||
|
for (TomcatContextCustomizer customizer : container
|
||||||
|
.getTomcatContextCustomizers()) {
|
||||||
|
customizer.customize(context);
|
||||||
|
}
|
||||||
|
verify(context).setMapperContextRootRedirectEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTrailingSlashOfContextPathIsRemoved() {
|
public void testTrailingSlashOfContextPathIsRemoved() {
|
||||||
new RelaxedDataBinder(this.properties, "server").bind(new MutablePropertyValues(
|
new RelaxedDataBinder(this.properties, "server").bind(new MutablePropertyValues(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
CREATE TABLE FOO_BAR (
|
||||||
|
SESSION_ID CHAR(36),
|
||||||
|
CREATION_TIME BIGINT NOT NULL,
|
||||||
|
LAST_ACCESS_TIME BIGINT NOT NULL,
|
||||||
|
MAX_INACTIVE_INTERVAL INT NOT NULL,
|
||||||
|
PRINCIPAL_NAME VARCHAR(100),
|
||||||
|
CONSTRAINT FOO_BAR_PK PRIMARY KEY (SESSION_ID)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX FOO_BAR_IX1 ON FOO_BAR (LAST_ACCESS_TIME);
|
||||||
|
|
||||||
|
CREATE TABLE FOO_BAR_ATTRIBUTES (
|
||||||
|
SESSION_ID CHAR(36),
|
||||||
|
ATTRIBUTE_NAME VARCHAR(100),
|
||||||
|
ATTRIBUTE_BYTES LONGVARBINARY,
|
||||||
|
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),
|
||||||
|
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES FOO_BAR(SESSION_ID) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX FOO_BAR_ATTRIBUTES_IX1 ON FOO_BAR_ATTRIBUTES (SESSION_ID);
|
||||||
|
|
@ -214,6 +214,7 @@ content into your application; rather pick only the properties that you need.
|
||||||
server.tomcat.port-header=X-Forwarded-Port # Name of the HTTP header used to override the original port value.
|
server.tomcat.port-header=X-Forwarded-Port # Name of the HTTP header used to override the original port value.
|
||||||
server.tomcat.protocol-header= # Header that holds the incoming protocol, usually named "X-Forwarded-Proto".
|
server.tomcat.protocol-header= # Header that holds the incoming protocol, usually named "X-Forwarded-Proto".
|
||||||
server.tomcat.protocol-header-https-value=https # Value of the protocol header that indicates that the incoming request uses SSL.
|
server.tomcat.protocol-header-https-value=https # Value of the protocol header that indicates that the incoming request uses SSL.
|
||||||
|
server.tomcat.redirect-context-root= # Whether requests to the context root should be redirected by appending a / to the path.
|
||||||
server.tomcat.remote-ip-header= # Name of the http header from which the remote ip is extracted. For instance `X-FORWARDED-FOR`
|
server.tomcat.remote-ip-header= # Name of the http header from which the remote ip is extracted. For instance `X-FORWARDED-FOR`
|
||||||
server.tomcat.uri-encoding=UTF-8 # Character encoding to use to decode the URI.
|
server.tomcat.uri-encoding=UTF-8 # Character encoding to use to decode the URI.
|
||||||
server.undertow.accesslog.dir= # Undertow access log directory.
|
server.undertow.accesslog.dir= # Undertow access log directory.
|
||||||
|
|
@ -366,6 +367,8 @@ content into your application; rather pick only the properties that you need.
|
||||||
|
|
||||||
# SPRING SESSION ({sc-spring-boot-autoconfigure}/session/SessionProperties.{sc-ext}[SessionProperties])
|
# SPRING SESSION ({sc-spring-boot-autoconfigure}/session/SessionProperties.{sc-ext}[SessionProperties])
|
||||||
spring.session.hazelcast.map-name=spring:session:sessions # Name of the map used to store sessions.
|
spring.session.hazelcast.map-name=spring:session:sessions # Name of the map used to store sessions.
|
||||||
|
spring.session.jdbc.initializer.enabled=true # Create the required session tables on startup if necessary.
|
||||||
|
spring.session.jdbc.schema=classpath:org/springframework/session/jdbc/schema-@@platform@@.sql # Path to the SQL file to use to initialize the database schema.
|
||||||
spring.session.jdbc.table-name=SPRING_SESSION # Name of database table used to store sessions.
|
spring.session.jdbc.table-name=SPRING_SESSION # Name of database table used to store sessions.
|
||||||
spring.session.mongo.collection-name=sessions # Collection name used to store sessions.
|
spring.session.mongo.collection-name=sessions # Collection name used to store sessions.
|
||||||
spring.session.redis.flush-mode= # Flush mode for the Redis sessions.
|
spring.session.redis.flush-mode= # Flush mode for the Redis sessions.
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,6 @@ public class TomcatEmbeddedServletContainerFactory
|
||||||
: ClassUtils.getDefaultClassLoader());
|
: ClassUtils.getDefaultClassLoader());
|
||||||
try {
|
try {
|
||||||
context.setUseRelativeRedirects(false);
|
context.setUseRelativeRedirects(false);
|
||||||
context.setMapperContextRootRedirectEnabled(true);
|
|
||||||
}
|
}
|
||||||
catch (NoSuchMethodError ex) {
|
catch (NoSuchMethodError ex) {
|
||||||
// Tomcat is < 8.0.30. Continue
|
// Tomcat is < 8.0.30. Continue
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue