How to enable connection pooling in spring boot embedded tomcat - spring-boot

I have a spring boot application which is not a web application. In this application i have configured embedded tomcat with the help of following bean.
#Bean
public TomcatServletWebServerFactory tomcatFactory() {
return new TomcatServletWebServerFactory() {
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
tomcat.enableNaming();
return super.getTomcatWebServer(tomcat);
}
protected void postProcessContext(Context context) {
ContextResource contextResource = new ContextResource();
contextResource.setName("jdbc/BPMDB");
contextResource.setType(DataSource.class.getName());
contextResource.setProperty("driverClassName", env.getProperty("bpm.db.driverClassName"));
contextResource.setProperty("url", env.getProperty("bpm.db.url"));
contextResource.setProperty("username", env.getProperty("bpm.db.username"));
contextResource.setProperty("password", env.getProperty("bpm.db.password"));
context.getNamingResources().addResource(contextResource);
}
};
}
How do i do connection pooling for this embedded tomcat. I am using spring boot 2.x which says hikaricp is the default connection pooling but how to set it into this embedded tomcat.
Does this require to set properties like spring.datasource.hikari.initial-size=15
spring.datasource.hikari.max-wait=20000
but again how boot will know and how will i know that these properties are used.
Thanks.

I have got answer for my problem.
Its simple. We just have to make a DataSource reference and autowire it and mention database related properties along with hikari related properties.
Code is below.
#Autowired
public DataSource dataSource;
Add above to your #Configuration marked class and add following properties to application.properties file.
spring.datasource.driver-class=...
spring.datasource.url=jdbc:oracle:thin:....
spring.datasource.username=..
spring.datasource.password=..
spring.datasource.hikari.initial-size=15
spring.datasource.hikari.max-wait=20000
spring.datasource.hikari.max-active=50
spring.datasource.hikari.max-idle=50
spring.datasource.hikari.min-idle=8
Also i have written a test case to check for hikari connection pool. Below is the code.
import javax.sql.DataSource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#SpringBootTest(
properties = "spring.datasource.type=com.zaxxer.hikari.HikariDataSource",
classes = {ApplicationConfiguration.class,PersistenceJpaContext.class}
)
public class HikariConnectionPoolTest {
#Autowired
private DataSource dataSource;
#Test
public void hikariConnectionPoolIsConfigured() {
assertEquals("com.zaxxer.hikari.HikariDataSource", dataSource.getClass().getName());
}
}

Related

spring-boot-starter-jdbc DAO repository object not injected in working legacy webservice

I am new in the spring/boot word and have a working JAX-WS based web-service declared in a springboot project. It is started and configured via web.xml and sun-jaxws.xml. So, no beans included there only endpoints declarations and servlet definitions and mappings.
I just now want to save the items i get in the webservice into the mysql database using spring-boot-starter-jdbc which is not working:
I can't achieve this as the repository is not injected in the webservice implementation.
Followed all steps in other question, but not achieving this!
Normally declaration of the datasource parameters in application.properties and annotating #webservice and #Repository would suffice to get the injection of the repository working in the webservice class. What am i missing ?
Here details of the steps I followed:
the webservice implementation is a package X and i created a #SpringBootApplication in order to use a mysql datasource declared in application.properties.
So i annotated the webservice as a #Component and the data access repository with #Repository and #Component
parent version: spring-boot-starter-parent : 1.5.10.RELEASE
webservice service implementation:
BServiceManager.java
package X;
....
#Component
#WebService(name = "***",***)
#BindingType("http://schemas.xmlsoap.org/wsdl/soap/http")
#XmlSeeAlso({
packagesxxx.class,
....
})
public class BServiceManager
implements xxxxx
{
....
#Autowired
private ItemRepository irepo;
....
#WebMethod(**)
#WebResult(***)
public ResponseDataInfo sendInfo( ){
....
trepo.saveitem(item)
....
}
}
ItemRepository.java
package Y.Z;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
#Component
#Repository
public class ItemRepository {
#Autowired
private JdbcTemplate jdbcTemplate ;
....
public boolean saveitem(Item item) {
....
}
}
Item.java
package Y.Z;
public class Item {
....
}
GetItemsApplication
package Y;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
//#ComponentScan(basePackages={"Y","Y.Z","X"})
#SpringBootApplication
public class GetItemsApplication {
....
public static void main(String[] args) {
SpringApplication.run(GetItemsApplication.class, args);
log.info("--Spring Boot inits done--");
}
}
application.properties
spring.data.jpa.repositories.enabled=false
spring.data.jdbc.repositories.enabled=true
# MySQL properties
spring.datasource.url=****
spring.datasource.username=****
spring.datasource.password=****
....
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
logging.level.org.springframework.jdbc.core.JdbcTemplate=debug
NB: even having datasource bean is not helping :
File: DataSourceConfig.java
package Y.Z;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
//#EnableJdbcRepositories for Spring
#Configuration
public class MDataSourceConfig {
#Bean
public DataSource dataSource() {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
return dataSourceBuilder.build();
}
#Bean
public JdbcTemplate getJdbcTemplate() {
return new JdbcTemplate(dataSource());
}
}
Your Webservice doesn't seem to get created by Spring.
Therefore Spring has no control over its dependencies, so you have to get the dependency programmatically.
There are many ways to do this.
Easy but not very elegant and uses global variables which might cause problems, especially with tests: https://stackoverflow.com/a/18486178/66686
More elegant but requires weaving Spring autowiring using #Configurable

How Do I Unit Test A Jersey REST API Without Running A Server?

I am working with a REST API that is using Jersey with Spring Boot (so no specific application context in XML or Java) and Spring Data JPA.
I want to write unit tests on the GET and POST endpoints, however, I don't want to start a web server as it takes too long.
If I use JerseyTest my Spring Beans don't get loaded into the context.
public class InMemoryContainerPackageTest extends
JerseyTestNg.ContainerPerClassTest {
#Override
protected TestContainerFactory getTestContainerFactory() {
return new InMemoryTestContainerFactory();
}
#Override
public Application configure() {
ResourceConfig config = new ResourceConfig()
.register(SpringLifecycleListener.class)
.register(RequestContextFilter.class)
.register(this)
.register(MyController.class)
.packages("com.my.service");
return config;
}
If I use SpringBootTest it starts up a web server which takes about 30 seconds and ideally I want all my tests to complete in under 5 seconds otherwise developers won't run them.
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class TestNGClass1 extends AbstractTestNGSpringContextTests {
I don't think MockMvc works with Jersey endpoints.
If I use JerseyTest my Spring Beans don't get loaded into the context.
What you can do is set the property "contextConfig" in your ResourceConfig. The value will be a Spring ApplicationContext instance. So if you are using Java configuration, you would just use an AnnotationConfigApplicationContext.
#Override
public ResourceConfig configure() {
return new ResourceConfig()
.register(TestResource.class)
.property("contextConfig",
new AnnotationConfigApplicationContext(SpringConfig.class));
}
Here, SpringConfig is an arbitrary Spring #Configuration class. Below is a complete example.
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.inmemory.InMemoryTestContainerFactory;
import org.glassfish.jersey.test.spi.TestContainerFactory;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
public class SpringTest extends JerseyTest {
public static class MessageService {
public String getMessage() {
return "Hello World";
}
}
#Configuration
public static class SpringConfig {
#Bean
public MessageService service() {
return new MessageService();
}
}
#Path("test")
public static class TestResource {
#Autowired
private MessageService service;
#GET
public String get() {
return service.getMessage();
}
}
#Override
public ResourceConfig configure() {
return new ResourceConfig()
.register(TestResource.class)
.property("contextConfig",
new AnnotationConfigApplicationContext(SpringConfig.class));
}
#Override
public TestContainerFactory getTestContainerFactory() {
return new InMemoryTestContainerFactory();
}
#Test
public void testIt() {
Response res = target("test")
.request()
.get();
String msg = res.readEntity(String.class);
System.out.println(msg);
assertThat(msg).isEqualTo("Hello World");
}
}
As far as the JPA, you are going to have to configure that yourself. When using Spring Boot, all of the JPA bootstrapping is taken care of. If you are going to use Jersey Test Framework, then you are ignoring all Spring Boot configuration.
It's really not that hard to configure JPA yourself. It basically consists of configuring a DataSource, a TransactionManager, a JpaVendorAdaptor, and a LocalContainerEntityManagerFactoryBean. And to enable the Spring Data repositories, you just need to use the #EnableJpaRepositories.
Have a look at this complete example configuration.
Another thing to be wary of is that when we use the Jersey Test Framework, we will not have the test scoped transactions (and rollbacks) that you will get when working with Spring Test. So when you write your tests, you need to take this into consideration.

Enabling Redis cache in spring boot

I have following configuration on my spring boot project.
#SpringBootApplication
#EnableTransactionManagement
#EnableCaching
#EnableScheduling
#EnableAsync
public class Application {
String redisHost = "localhost";
int redisPort = 6379;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory factory = new JedisConnectionFactory();
factory.setHostName(redisHost);
factory.setPort(redisPort);
factory.setUsePool(true);
return factory;
}
#Bean
RedisTemplate<Object, Object> redisTemplate() {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<Object, Object>();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
return redisTemplate;
}
#Bean
public CacheManager cacheManager() {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate());
return cacheManager;
}
}
Also I have following maven dependency on pom.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
I have a separate redis server running on my local machine on defined port. Also in my service classes I have annotations like #Cacheable, #CachePut to support caching.
I can start spring boot application without errors and CRUD operations also works. But seems it is not using the defined redis cache. I used 'redi desktop manger' browsing tool and couldn't find any data on redis. Also I tried with monitoring redis server via redis cli command 'monitor', I can't see any changes on monitor.
So I assume redis caching still not working on my spring boot application. Can someone help me to figure out the issue?
I am using spring boot version 1.4.2.RELEASE
Thanks!
Given you are using Spring Boot, much of your Redis configuration is unnecessary since Spring Boot provides "auto-configuration" support for Redis, both as a data source as well as a caching provider.
You were also not specific about what version of Spring Boot you were using (e.g. 1.5.0.RC1) to run your application, or whether you had any application.properties on your application's classpath, which might make a difference if you explicitly specified spring.cache.type (set to something other than "redis", for instance).
However, in general, I cannot really see much wrong with your Redis or Spring Cache #Configuration class. However, it does seem to be a problem with not explicitly setting cacheManager.setUsePrefix(true). When I set this RedisCacheManager property ('usePrefix`), then everything worked as expected.
I am not (Spring Data) Redis expert so I am not exactly sure why this is needed. However, I based my test configuration on Spring Boot's "auto-configuration" support for Redis caching as well as your #Configuration "Application" class, shown above.
And, because you can eliminate most of your explicit configuration and use Spring Boot's "auto-configuration" support for Redis as a data source as well, I added a "AutoRedisConfiguration" #Configuration class to my test class. I.e. you can use this to configure Redis instead of my other #Configuration class ("CustomRedisConfiguration") which uses your configuration + the fix.
Here is the complete test example...
/*
* Copyright 2017 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.spring.cache;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.PostConstruct;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.spring.cache.CachingWithRedisIntegrationTest.CachingWithRedisConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Profile;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.Assert;
/**
* Integration tests testing Spring's Cache Abstraction using Spring Data Redis auto-configured with Spring Boot.
*
* To run this test, first start a Redis Server on localhost listening on the default port, 6379.
*
* #author John Blum
* #see org.junit.Test
* #since 1.0.0
*/
#RunWith(SpringRunner.class)
#ActiveProfiles("auto")
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
#ContextConfiguration(classes = CachingWithRedisConfiguration.class)
#SuppressWarnings("unused")
public class CachingWithRedisIntegrationTest {
protected static final int REDIS_PORT = 6379;
protected static final String REDIS_HOST = "localhost";
private AtomicBoolean setup = new AtomicBoolean(false);
#Autowired
private MathService mathService;
#Autowired(required = false)
private RedisTemplate<Object, Object> redisTemplate;
#Before
public void setup() {
if (redisTemplate != null && !setup.getAndSet(true)) {
redisTemplate.delete(Arrays.asList(0L, 1L, 2L, 4L, 8L));
}
}
#Test
public void firstCacheMisses() {
assertThat(mathService.factorial(0L)).isEqualTo(1L);
assertThat(mathService.wasCacheMiss()).isTrue();
assertThat(mathService.factorial(1L)).isEqualTo(1L);
assertThat(mathService.wasCacheMiss()).isTrue();
assertThat(mathService.factorial(2L)).isEqualTo(2L);
assertThat(mathService.wasCacheMiss()).isTrue();
assertThat(mathService.factorial(4L)).isEqualTo(24L);
assertThat(mathService.wasCacheMiss()).isTrue();
assertThat(mathService.factorial(8L)).isEqualTo(40320L);
assertThat(mathService.wasCacheMiss()).isTrue();
}
#Test
public void thenCacheHits() {
assertThat(mathService.factorial(0L)).isEqualTo(1L);
assertThat(mathService.wasCacheMiss()).isFalse();
assertThat(mathService.factorial(1L)).isEqualTo(1L);
assertThat(mathService.wasCacheMiss()).isFalse();
assertThat(mathService.factorial(2L)).isEqualTo(2L);
assertThat(mathService.wasCacheMiss()).isFalse();
assertThat(mathService.factorial(4L)).isEqualTo(24L);
assertThat(mathService.wasCacheMiss()).isFalse();
assertThat(mathService.factorial(8L)).isEqualTo(40320L);
assertThat(mathService.wasCacheMiss()).isFalse();
}
interface MathService {
boolean wasCacheMiss();
long factorial(long number);
}
#EnableCaching
#SpringBootConfiguration
#Import({ AutoRedisConfiguration.class, CustomRedisConfiguration.class })
static class CachingWithRedisConfiguration {
#Bean
MathService mathService() {
return new MathService() {
private final AtomicBoolean cacheMiss = new AtomicBoolean(false);
#Override
public boolean wasCacheMiss() {
return cacheMiss.getAndSet(false);
}
#Override
#Cacheable(cacheNames = "Factorials")
public long factorial(long number) {
cacheMiss.set(true);
Assert.isTrue(number >= 0L, String.format("Number [%d] must be greater than equal to 0", number));
if (number <= 2L) {
return (number < 2L ? 1L : 2L);
}
long result = number;
while (--number > 1) {
result *= number;
}
return result;
}
};
}
#Bean
#Profile("none")
CacheManager cacheManager() {
return new ConcurrentMapCacheManager();
}
}
#Profile("auto")
#EnableAutoConfiguration
#SpringBootConfiguration
static class AutoRedisConfiguration {
#PostConstruct
public void afterPropertiesSet() {
System.out.println("AUTO");
}
#Bean
static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer =
new PropertySourcesPlaceholderConfigurer();
propertySourcesPlaceholderConfigurer.setProperties(redisProperties());
return propertySourcesPlaceholderConfigurer;
}
static Properties redisProperties() {
Properties redisProperties = new Properties();
redisProperties.setProperty("spring.cache.type", "redis");
redisProperties.setProperty("spring.redis.host", REDIS_HOST);
redisProperties.setProperty("spring.redis.port", String.valueOf(REDIS_PORT));
return redisProperties;
}
}
#Profile("custom")
#SpringBootConfiguration
static class CustomRedisConfiguration {
#PostConstruct
public void afterPropertiesSet() {
System.out.println("CUSTOM");
}
#Bean
JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory factory = new JedisConnectionFactory();
factory.setHostName(REDIS_HOST);
factory.setPort(REDIS_PORT);
factory.setUsePool(true);
return factory;
}
#Bean
RedisTemplate<Object, Object> redisTemplate() {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
return redisTemplate;
}
#Bean
CacheManager cacheManager() {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate());
cacheManager.setUsePrefix(true); // THIS IS NEEDED!
return cacheManager;
}
}
}
Hope this helps!
Cheers,
John
I am using Spring Boot 2.0 and its very simple to use Redis for simple caching purpose.
Annotate your Spring boot application with #EnableCaching
In your application.properties have these properties
spring.cache.type=redis
redis.host.url=
redis.host.port=
Annotate your methods with #Cacheable.
That's it!!
If you are using AWS Elasticache and you have checked the in-transit encryption then you need to add a RedisConfiguration file to set your ssl to true.
Spring Boot 2.0 now uses LettuceConnectionFactory.
To do the above simply add a class and mark it with #Configuration annotation and add the following bean
#Bean
public LettuceConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
configuration.setHostName(redisHost);
configuration.setPort(redisPort);
return new LettuceConnectionFactory(configuration, LettuceClientConfiguration.builder().useSsl().disablePeerVerification().build());
}
You can check existence of your keys in redis with command in redis-cli: keys *
If there will be your key, everything is OK :)
The methods of your classes should be #Cacheable. Along with #CachePut you should use #CacheEvict with the keys and their values for delete method to flush out the resources. Also the host, port, type and password is needed in application.properties file.
`spring.redis.password= password`
`spring.cache.type=redis`
`spring.redis.host=localhost`
`spring.redis.port=6379`
Also add some more properties like so, as per requirement.
`spring.cache.redis.time-to-live=600000`
`spring.cache.redis.cache-null-values=false`
`spring.cache.redis.use-key-prefix=true

NoUniqueBeanDefinitionException with #EnableExperimentalNeo4jRepositories annotation and SpringBoot 1.4.2

I'm having an issue with Spring boot 1.4.2.M1 and #EnableExperimentalNeo4jRepositories.
It seems to be a conflict between two beans, one spring boot, one spring-data-neo4j.
Here is a stack trace excerpt:
18:12:15.891 [main] DEBUG o.s.b.d.LoggingFailureAnalysisReporter - Application failed to start due to an exception
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.neo4j.ogm.session.Session' available: expected single matching bean but found 2: getSession,org.springframework.data.neo4j.transaction.SharedSessionCreator#0
And another...
Parameter 0 of method setSession in org.springframework.data.neo4j.repository.support.Neo4jRepositoryFactoryBean required a single bean, but 2 were found:
- getSession: defined in BeanDefinition defined in class path resource [org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration$SpringBootNeo4jConfiguration.class]
- org.springframework.data.neo4j.transaction.SharedSessionCreator#0: defined by method 'createSharedSession' in null
Anybody have any idea how to solve this?
Below is my Neo4j Configuration
package com.domain.core.context;
import javax.annotation.PostConstruct;
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;
import org.neo4j.ogm.session.event.Event;
import org.neo4j.ogm.session.event.EventListenerAdapter;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.repository.config.EnableExperimentalNeo4jRepositories;
import org.springframework.data.neo4j.transaction.Neo4jTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import lombok.extern.slf4j.Slf4j;
#Slf4j
#Configuration
#ComponentScan("com.domain")
#EnableExperimentalNeo4jRepositories(basePackages = "com.domain.core.repository")
#EnableTransactionManagement
#SpringBootApplication(exclude = Neo4jDataAutoConfiguration.class)
public class TestPersistenceContext {
#PostConstruct
public void init() {
log.info("TheScene.Co: Initializing Test Neo4jConfig ...");
}
#Bean
public Neo4jTransactionManager transactionManager() throws Exception {
return new Neo4jTransactionManager(sessionFactory());
}
#Bean
public SessionFactory sessionFactory() {
return new SessionFactory(getConfiguration(), "com.domain") {
#Override
public Session openSession() {
Session session = super.openSession();
session.register(new EventListenerAdapter() {
#Override
public void onPreSave(Event event) {
// do something - like set an id on an object
log.debug("***** Saving domain object ********");
}
});
return session;
}
};
}
#Bean
public org.neo4j.ogm.config.Configuration getConfiguration() {
org.neo4j.ogm.config.Configuration config = new org.neo4j.ogm.config.Configuration();
config.driverConfiguration().setCredentials("neo4j", "password")
.setDriverClassName("org.neo4j.ogm.drivers.http.driver.HttpDriver");
return config;
}
}
You must be using Spring Data Neo4j (SDN) version 4.2.0.M1. This milestone release was put out to get feedback on several big changes from 4.1.x.
SDN 4.2.0.RC1 should be out later this week but for now 4.2.0.BUILD-SNAPSHOT is actually quite stable in the lead up to Ingalls release train for Spring Data in Decemeber.
I have written a guide for users coming from SDN 4.0/4.1 which goes over how to upgrade to the snapshot build.
In this guide there is a link to an example project branch which shows how to get this version to work with Spring Boot 1.4.x with a few minor work arounds.
WIth the upcoming release of Spring Boot 1.5, we have updated all the autoconfiguration to work straight out of the box with SDN 4.2. We will update the documenation for Spring Boot closer to release.

Changing default welcome-page for spring-boot application deployed as a war

I was trying to find a way to change the default welcome-page for a spring-boot application that is being deployed as a war in production but I can't find a way to do it without a web.xml file.
According to the documentation we can do it using the EmbeddedServletContainerFactory with this code:
#Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
TomcatContextCustomizer contextCustomizer = new TomcatContextCustomizer() {
#Override
public void customize(Context context) {
context.addWelcomeFile("/<new welcome file>");
}
};
factory.addContextCustomizers(contextCustomizer);
return factory;
}
Although, as we're creating a war file and deploying it to tomcat and not using the Embedded Tomcat, this isn't doing anything.
Any idea? If we really need to add a web.xml file, how can we do it and still using spring boot? Should we specify the Application bean(with the main method) as the application context for DispatcherServlet? The documentation isn't very clear about that.
Older Servlet containers don’t have support for the ServletContextInitializer bootstrap process used in Servlet 3.0. You can still use Spring and Spring Boot in these containers but you are going to need to add a web.xml to your application and configure it to load an ApplicationContext via a DispatcherServlet.
Thanks in advance!
Pedro
It's not too hard to do... you just need to forward the default mapping...
#Configuration
public class DefaultView extends WebMvcConfigurerAdapter{
#Override
public void addViewControllers( ViewControllerRegistry registry ) {
registry.addViewController( "/" ).setViewName( "forward:/yourpage.html" );
registry.setOrder( Ordered.HIGHEST_PRECEDENCE );
super.addViewControllers( registry );
}
}
Well, a few years passed since the last answer - and code evolves..
This won't work on Spring 5 / Java 8+, you should implement the interface and override the default method.
import org.springframework.core.Ordered;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
public class DefaultViewConfig implements WebMvcConfigurer {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("/homepage.html");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
}
Following Michael's tutorial, I was able to just map / to my index.gsp file.
#Controller
class Routes {
#RequestMapping({
"/",
"/bikes",
"/milages",
"/gallery",
"/tracks",
"/tracks/{id:\\w+}",
"/location",
"/about"
})
public String index() {
return "forward:/index.gsp";
}
}
I am doing it as follows.
package org.gwtproject.tutorial.configuration;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* Configure the welcome page
*
*/
#Configuration
public class SpringBootWelcomePageConfiguration extends WebMvcConfigurerAdapter implements WebMvcConfigurer {
/**
* redirect a user to the welcome page when he visits tha app without a
* destination url.
*/
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("forward:/ForExampleAGwtEntrypoint.html");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
super.addViewControllers(registry);
}
}

Resources