Moi ce que je voudrais, c'est pouvoir définir MES valeurs par défaut pour mon application Spring-Boot, que je pourrais surcharger avec un fichier properties.
Donc, je veux surcharger programmatiquement les valeurs par défault de Spring-Boot, et quand même permettre la surcharge par fichier. Dans l'idée, ça marche :
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertiesPropertySource;
import java.util.Properties;
@Configuration
@PropertySource(value = "classpath:application.properties", ignoreResourceNotFound = true)
public class DatabaseConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseConfiguration.class.getCanonicalName());
public static final String DATABASE_URL = "jdbc:h2:./db/dbfile;MODE=MySQL;";
public static final String DATABASE_USER = "sa";
public static final String DATABASE_DRIVER = "org.h2.Driver";
public static final String DATABASE_SCHEMA = "PUBLIC";
@Autowired
private Environment env;
@Value("${spring.datasource.url:}") // Defaulted with empty value
private String databaseUrl;
@Value("${spring.datasource.username:}") // Defaulted with empty value
private String databaseUser;
@Value("${spring.datasource.password:}") // Defaulted with empty value
private String databasePassword;
@Value("${spring.datasource.driver-class-name:}") // Defaulted with empty value
private String databaseDriver;
@Value("${spring.datasource.schema:}") // Defaulted with empty value
private String databaseSchema;
private void overrideProperty(String name, String currentValue, String defaultValue) {
if (currentValue == null || currentValue.isEmpty()) {
currentValue = defaultValue;
ConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment) this.env;
PropertiesPropertySource propertySource = (PropertiesPropertySource) configurableEnvironment.getPropertySources().get("myProps");
Properties myProperties = new Properties();
if (propertySource != null) {
for (String propertyName : propertySource.getPropertyNames()) {
myProperties.put(propertyName, propertySource.getProperty(propertyName));
}
}
myProperties.put(name, currentValue);
configurableEnvironment.getPropertySources().addFirst(new PropertiesPropertySource("myProps", myProperties));
System.out.println("Property " + name + " not found and defaulted to => " + currentValue);
} else {
System.out.println("Property unchanged " + name + " => " + currentValue);
}
}
/**
* I swear to you, I tried to override configuration !!!
*/
@Bean
public void defaultConfiguration() {
this.overrideProperty("spring.datasource.url", this.databaseUrl, DATABASE_URL);
this.overrideProperty("spring.datasource.jdbc-url", this.databaseUrl, DATABASE_URL);
this.overrideProperty("spring.datasource.user", this.databaseUser, DATABASE_USER);
this.overrideProperty("spring.datasource.driver-class-name", this.databaseDriver, DATABASE_DRIVER);
this.overrideProperty("spring.datasource.schema", this.databaseSchema, DATABASE_SCHEMA);
}
}
Mais mon script s'exécute après la création de la DataSource et pas moyen de l'exécuter avant tout le reste T__T
Faut je creuse encore...
Ce binding a été créé pour le cas d'une appli Spring-Boot, Spring-security, se lançant dans un Websphere 8.5.5.
Bean de configuration de l'application récupérant les variables JNDI
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
/**
* The Spring configuration for the application.
*/
@Configuration
@PropertySource(
encoding = "UTF-8",
value = "classpath:application.properties"
)
public class ApplicationConfig extends SpringConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationConfig.class.getCanonicalName());
private static final String JAVA_COMP_ENV = "java:comp/env";
private static final String PATH_STORAGE_FOLDER = "path/toto";
private static final String URL_SERVICE_URL = "url/ServiceUrl";
private static final String MY_DATASOURCE_JNDI_NAME = "my.datasource.jndi.name";
/**
* Load the configuration.
*
* @param environment the Spring environment.
*/
public ApplicationConfig(Environment environment) {
super(environment);
}
/**
* My database datasource.
*
* @return the datasource JNDI name.
*/
@Bean
public String myDatasourceJndiName() {
LOGGER.info("Database JNDI name set to {}", super.getProperty(MY_DATASOURCE_JNDI_NAME, String.class));
return super.getProperty(MY_DATASOURCE_JNDI_NAME, String.class);
}
/**
* Return the JNDI value associated a simple string.
*/
@Bean
public String theNameOfMyBean() {
LOGGER.info("Lonading simple string JNDI variable");
String jndiFoundPath = null;
try {
Context envEntryContext = (Context) new InitialContext().lookup(JAVA_COMP_ENV);
String jndiFoundVariable = (String) envEntryContext.lookup(PATH_STORAGE_FOLDER);
LOGGER.info("Binding JNDI {} gave {}", PATH_STORAGE_FOLDER, jndiFoundVariable);
return jndiFoundVariable;
} catch (NamingException e) {
LOGGER.info("Binding JNDI {} gave null (Naming exception).", PATH_STORAGE_FOLDER);
LOGGER.trace("raised error", e);
//Here you can default value or throw exception
}
LOGGER.info("Binding JNDI Bel storage folder path gave {}", jndiFoundPath);
if (jndiFoundPath == null || "".equals(jndiFoundPath)) {
LOGGER.info("Binding JNDI Bel storage folder path gave null.");
//Here you can default value or throw exception
}
return jndiFoundPath;
}
/**
* Return the JNDI value associated a URL.
*/
@Bean
public String servicesUrl() {
LOGGER.info("Lonading service URL JNDI variable");
String jndiFoundPath = null;
try {
Context envEntryContext = (Context) new InitialContext().lookup(JAVA_COMP_ENV);
URL jndiFoundUrl = (URL) envEntryContext.lookup(URL_SERVICE_URL);
LOGGER.info("Binding JNDI service url gave {}", jndiFoundUrl);
jndiFoundPath = jndiFoundUrl.toString();
} catch (NamingException e) {
LOGGER.info("Binding JNDI ws url gave null.");
LOGGER.trace("raised error", e);
//Here you can default value or throw exception
}
if (jndiFoundPath == null || "".equals(jndiFoundPath)) {
LOGGER.info("Binding JNDI Bel storage folder path gave null.");
//Here you can default value or throw exception
}
return jndiFoundPath;
}
}
Sample pour la datasource :
/**
* Load the Data source for the database.
*
* @return the data source.
*/
@Bean
@Primary
public DataSource dataSource() {
LOGGER.info("Load datasource");
try {
DataSource jndiDataSource = new JndiDataSourceLookup().getDataSource(this.getContext().getBean("myDatasourceJndiName", String.class));
if (jndiDataSource == null) {
LOGGER.info("DB - JNDI datasource returned null object - Default datasource");
jndiDataSource = new BoneCPDataSource(this.connectionPoolConfig());
}
LOGGER.info("DB - JNDI datasource is OK.");
return jndiDataSource;
} catch (BeansException | DataSourceLookupFailureException e) {
LOGGER.info("Error when lookup JNDI datasource => Bone-CP DataSource loaded");
return new BoneCPDataSource(this.connectionPoolConfig());
}
}
Le web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="reviewit-poc">
<display-name>TheNameYouWant</display-name>
<resource-ref>
<res-ref-name>url/ServiceUrl</res-ref-name>
<res-type>java.net.URL</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Unshareable</res-sharing-scope>
</resource-ref>
<resource-env-ref>
<description>BEL Storage Folder</description>
<resource-env-ref-name>path/toto</resource-env-ref-name>
<resource-env-ref-type>java.lang.String</resource-env-ref-type>
</resource-env-ref>
<resource-ref>
<res-ref-name>jdbc/myDatasource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Unshareable</res-sharing-scope>
</resource-ref>
</web-app>
Lorsque l'on doit gérer une application qui communique avec un base de données et plusieurs schémas.
Ce qu'il faut savoir : Hibernate permet de setter un schéma global dynamiquement ou un schéma par entité mais en dur...
Comment gérer le cas ou le nom des schémas change selon l'environnement ?
Je ne dis pas que le besoin est légitime (est-ce une bonne pratique ? probablement pas), en attentant, cette petite page va probablement sauver ma semaine.
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
/**
* The authentication entry point is called when the client makes a call to a resource without proper authentication. In
* other words, the client has not logged in.
* <p>
* If this class is not present in the code, then Spring security opens a default pop-up. We want a 401 error.
*/
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomAuthenticationEntryPoint.class);
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
LOGGER.info("intercepted request : 401 error code.");
response.getWriter().append("Access Denied : " + authException.getMessage());
response.setStatus(401);
}
}
Cette classe est incluse dans la couche sécurité via la configuration du http :
//Override the default login pop-up with a 401 response.
http.exceptionHandling().authenticationEntryPoint(customAuthenticationEntryPoint);
Ne reste plus qu'à configurer la gestion des erreurs 401 avec Angular :
import { Injectable } from '@angular/core';
import { Request, XHRBackend, RequestOptions, Response, Http, RequestOptionsArgs, Headers } from '@angular/http';
import { Router, NavigationEnd, Event } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
/**
* This class handles generically the error on authentication.
*/
@Injectable()
export class AuthenticatedHttpService extends Http {
private router: Router;
constructor(backend: XHRBackend, defaultOptions: RequestOptions, router: Router) {
super(backend, defaultOptions);
this.router = router;
}
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
return super.request(url, options).catch((error: Response) => {
if ((error.status === 401 || error.status === 403) && (window.location.href.match(/\?/g) || []).length < 2) {
if(window.location.href != '/login') {
this.router.navigate(['/login']);
}
else {
return Observable.throw("authentication met an exception");
}
}
return Observable.throw("request authentication");
});
}
}
Dépendances nécessaires :
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<scope>compile</scope>
</dependency>
<!-- Spring DATA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<scope>compile</scope>
</dependency>
<!-- Hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
Définition de l'entité Hibernate :
import java.io.Serializable;
import javax.persistence.*;
import org.hibernate.annotations.GenericGenerator;
/**
* Represents a truc in the database.
*/
@Entity
@Table(name = "TRUCS")
public class Truc implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(generator = "increment")
@GenericGenerator(name = "increment", strategy = "increment")
@Column(name = "id", nullable = false, unique = true)
private Long id;
@Column(name = "name")
private String name;
/**
* Default constructor mandatory for hibernate instanciation.
*/
public Truc() {
super();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Définition du CRUD Manager :
import java.util.List;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
/**
* The technical manager able to make CRUD actions on the truc in the database.
*/
public interface ContactManager extends CrudRepository<Truc, Long> {
/**
* Get all the trucs in the database with the given name.
*
* @param name the name.
* @return the list of all trucs having the name.
*/
@Query("select c from Truc c where lower(c.name) = lower(:name)")
List<Truc> getByName(@Param("name") String name);
}
On utilise les managers via une injection autowired et un scan du package contenant les managers.
Dépendances nécessaire dans Maven :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<scope>compile</scope>
</dependency>
<!-- Pas sure que celle-ci soit nécessaire : -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<scope>compile</scope>
</dependency>
Configuration de la sécurité côté sécurité :
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
@ComponentScan("com.pacakge.security")
public class MyWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(MyWebSecurityConfigurerAdapter.class);
@Autowired
@Qualifier("authenticationProvider")
private AuthenticationProvider authenticationProvider;
@Autowired
@Qualifier("isSecurityDisabled")
private Boolean isSecurityDisabled;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder authenticationProvider) throws Exception {
authenticationProvider.authenticationProvider(this.authenticationProvider);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
LOGGER.debug("configure HttpSecurity");
LOGGER.info("Security is disabled : {}", isSecurityDisabled);
if (isSecurityDisabled) {
http.httpBasic().and()
.authorizeRequests().antMatchers("/index.html", "/", "/logout.html").permitAll().and()
.csrf().disable()
.authorizeRequests()
.antMatchers("/user").permitAll()
.anyRequest().authenticated();
}
else {
http.httpBasic().and()
.authorizeRequests().antMatchers("/index.html", "/", "/logout.html").permitAll().and()
// configure the csrfTokenRepository
.csrf().csrfTokenRepository(csrfTokenRepository()).and()
.authorizeRequests()
.antMatchers("/user").permitAll()
.antMatchers("/contact/**").access("hasRole('ADMIN') and hasRole('DBA')")
.anyRequest().authenticated();
// Add the csrf filter
http.addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class);
}
http.exceptionHandling().accessDeniedPage("/403");
}
/**
* Csrf Token Repository that contains the header named "X-XSRF-TOKEN".
* Angular adds CRSF token headers to keep sure server and client are not talking to someone else.
*
* @return CsrfTokenRepository
*/
private static CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
@Override
public void configure(WebSecurity web) throws Exception {
LOGGER.info("Security is disabled : {}", isSecurityDisabled);
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
// Spring Security should completely ignore URLs starting with
// /static/assets/
web.ignoring().antMatchers("/static/assets/**").and();
web.ignoring().antMatchers("/static/app/**").and();
// Spring Security should completely ignore URLs for the js / images /
// font
web.ignoring().antMatchers("/static/*.ico").and();
web.ignoring().antMatchers("/static/*.eot").and();
web.ignoring().antMatchers("/static/*.svg").and();
web.ignoring().antMatchers("/static/*.ttf").and();
web.ignoring().antMatchers("/static/*.woff").and();
web.ignoring().antMatchers("/static/*.woff2").and();
web.ignoring().antMatchers("/static/*.js").and();
web.ignoring().antMatchers("/static/*.css").and();
web.ignoring().antMatchers("/static/*.map").and();
web.ignoring().antMatchers("/static/*.png").and();
web.ignoring().antMatchers("/static/*.jpg").and();
}
}
Exemple d'Authentication provider :
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
/**
* A mock for authentication provider.
*/
@Component
public class MockAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
private static final Logger CLASS_LOGGER = LoggerFactory.getLogger(MockAuthenticationProvider.class);
//Your own service to manage authentication.
private final AuthentiService authentiService;
private final LDAPUserToSecurityUserConverter lDAPUserToSecurityUserConverter;
/**
* Initialize the Mock authentication provider.
*
* @param authentiService the authent service.
* @param lDAPUserToSecurityUserConverter the converter from LDAP user to security user.
*/
public MockAuthenticationProvider(LDAPUserToSecurityUserConverter lDAPUserToSecurityUserConverter, AuthentiService authentiService) {
CLASS_LOGGER.trace("Set up of mocked authentication provider.");
this.lDAPUserToSecurityUserConverter = lDAPUserToSecurityUserConverter;
this.authentiService = authentiService;
}
@Override
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
@Override
public Authentication authenticate(Authentication authentication) {
CLASS_LOGGER.info("requesting authentication");
String name = authentication.getName();
String password = authentication.getCredentials().toString();
StopWatch stopWatch = new StopWatch();
stopWatch.start();
SecurityUser authenticatedUser = (SecurityUser) this.retrieveUser(name, (UsernamePasswordAuthenticationToken) authentication);
stopWatch.stop();
authenticatedUser.setTimeToSpentOnAuthentication(stopWatch.getTotalTimeMillis());
return new UsernamePasswordAuthenticationToken(authenticatedUser, password, authenticatedUser.getAuthorities());
}
@Override
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) {
String password = (String) authentication.getCredentials();
try {
// Login User
String token = this.authentService.login(username, password);
CLASS_LOGGER.debug("Username : {} got token : {}", username, token);
// Retrieve User Identity + roles + permissions
LDAPUser user = this.authentService.getUserInformation(token);
// Build the AuthenticatedUser object based on all the data
return this.lDAPUserToSecurityUserConverter.convert(user, password, token);
}
catch (Exception e) {
CLASS_LOGGER.debug(e.getMessage(), e);
throw new AuthenticationServiceException("Authentication error", e);
}
}
@Override
protected void additionalAuthenticationChecks(UserDetails arg0, UsernamePasswordAuthenticationToken arg1) throws AuthenticationException {
// Nothing to do.
}
}
Controller d'authentication :
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AuthenticationController {
private static final Logger LOGGER = LoggerFactory.getLogger(AuthenticationController.class);
@RequestMapping(value = "/user", method = RequestMethod.GET)
public SecurityUser user() {
LOGGER.debug("user controller");
SecurityUser authenticationUser = null;
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) {
LOGGER.info("Authentication provider is {}", auth.getClass().getSimpleName());
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = (UsernamePasswordAuthenticationToken) auth;
authenticationUser = (SecurityUser) usernamePasswordAuthenticationToken.getPrincipal();
}
else {
LOGGER.warn("No Authentication found");
}
return authenticationUser;
}
}
Service Angular d'authentication :
import { Injectable } from '@angular/core';
import { Http, Response, Headers, RequestOptions, URLSearchParams } from '@angular/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { Observable } from 'rxjs/Observable';
/**
* This class can request the server to get contact information.
*/
@Injectable()
export class AuthenticationService {
constructor(private http: Http) {
}
authenticate(username: string, password: string): Observable<any> {
//Authentication goes by using headers
const headers = new Headers();
if (username != null && password != null) {
const authorizationValue: string = 'Basic ' + btoa(username + ':' + password);
headers.append('authorization', authorizationValue);
}
return this.http.get('user', {headers: headers})
.map((res: Response) => res.json())
.catch( error => this.handleError(error) );
}
}
Au sein du projet Java, rajouter les classes nécessaires :
Le starter :
@SpringBootApplication
public class SpringBootWebApplication extends SpringBootServletInitializer {
/**
* Configure the server.
*
* @param application the application.
* @return the builder.
*/
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SpringBootWebApplication.class);
}
/**
* Start the server.
*
* @param args the arguments.
*/
public static void main(String[] args) {
SpringApplication.run(SpringBootWebApplication.class, args);
}
}
La configuration Web :
@Configuration
@EnableWebMvc
public class ApplicationWebConfiguration extends WebMvcConfigurerAdapter {
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
private static final int CACHE_PERIOD_ONE_WEEK = 604800;
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS)
.setCachePeriod(CACHE_PERIOD_ONE_WEEK);
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addRedirectViewController("/", "/index.html");
}
// ou
//@Override
//public void addViewControllers(ViewControllerRegistry registry) {
// registry.addViewController("/").setViewName("forward:/index.html");
//}
}
Dans le pom, rajouter le format de packaging et le re-build du projet dans les plugins (spring-boot-maven-plugin).
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itametis</groupId>
<artifactId>itartefactId</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<!-- Spring jar version -->
<spring.version>5.0.4.RELEASE</spring.version>
<spring-boot.version>1.5.10.RELEASE</spring-boot.version>
<!-- Jackson version for Spring -->
<jackson.version>2.9.3</jackson.version>
</properties>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
<scope>compile</scope>
</dependency>
<!-- Jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<!-- War maker -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<mainClass>${project.groupId}.webserver.SpringBootWebApplication</mainClass>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
</plugin>
<!-- Spring boot : re-build the war to carry the tomcat server -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.5.3.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>${project.groupId}.webserver.SpringBootWebApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
Le war généré par le maven-war-plugin sera re-buildé pour embarquer le tomcat et les outils Spring.