Spring Boot ne sert pas les ressources statiques

Rédigé par gorki - - Aucun commentaire

Le problème :

Avec une stack JHipster, spring-boot n'affiche pas les ressources statiques en mode développement.

Ddonc par exemple pas de index.html...

Pour autant si on lance la commande avec le war serverless (cf spring-boot-maven-plugin), ça fonctionne.

Je suis sous Intellij, à l'évidence quelque chose manque dans le lancement de la tâche Intellij spring-boot

L'architecture est mavenisé donc le root contexte est sous : src/main/webapp

Cependant spring-boot semble chercher ses ressources ailleurs : cf la documentation

Par quelle magie spring-boot doit-il trouver ses ressources dans src/main/webapp ??

Solution :

Beaucoup de recherches, de debug et autre (il y a un peu de spring-secu dans le lot). Au final les services jhipster classiques (health, dump, etc...) fonctionnent mais toujours pas de ressources statiques.

Vérification :

  • de la tâche de lancement Intellij, elle semble correcte.
  • des classpaths (on met src/main/webapp dans le classpath, on l'enlève) 
  • des paramètres de lancement (profil Spring et autre)

Au final la mise en debug m'a permis de trouver un log perdu parmi les autres :

[DEBUG] org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory - None of the document roots [src/main/webapp, public, static] point to a directory and will be ignored.

Tiens donc le Tomcat embarqué de spring-boot a ses propres chemins de recherches... (pas tout à fait décrit dans la doc Spring ci-dessus).

Breakpoint, watch, et paf, le chemin vers src/main/webapp en absolu n'est pas le bon.

Tout ça parce que le répertoire de travail de ma tâche spring-boot sous Intellij n'était pas fixé. Comment Intellij détermine cette valeur ? Mystère. En mettant donc le répertoire de travail égal au répertoire qui contient le src/main/webapp, tout roule.

[DEBUG] org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory - Document root: /home/qwbt2550/projets/portailLCRI/lcri-portal/src/main/webapp

 

 

Spring Boot et CXF

Rédigé par gorki - - Aucun commentaire

Le problème :

SpringBoot c'est assez pratique, le REST est géré de base avec Spring Boot MVC, mais parfois on a aussi besoin d'un serveur SOAP et là souvent CXF est utilisé plutôt que Spring MVC...)

Petit pense bête car les solutions trouvées sur le net me semble :

- compliquée : en utilisant Spring integration

- incomplète : déclaration simple

Solution :

En trois étapes :

  1. - Utiliser un fichier spring externe à Spring Boot
  2. - Déclarer la servlet CXF
  3. - Configurer Spring et CXF

Point 1 et 2 : dans l'application Spring Boot

Attention :
- dans notre exemple, CXF va gérer les URLs commençant par /soap/
- ne pas oublier de démarrer la servlet CXF

package com.test.springboot.cxf

import javax.annotation.PreDestroy;

import org.apache.cxf.transport.servlet.CXFServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

/**
 *
 */
@Configuration
@ImportResource("classpath:spring-cxf.xml")
@ComponentScan
@EnableAutoConfiguration()
public class SpringBootCxf {
    private static final Logger LOGGER = LoggerFactory.getLogger(SpringBootCxf.class);

    public static void main(final String[] args) throws Exception {
        SpringApplication.run(SpringBootCxf.class, args);
    }

    @Bean
    public ServletRegistrationBean cxfServlet() {
        ServletRegistrationBean servletDef = new ServletRegistrationBean(new CXFServlet(), "/soap/*");
        servletDef.setLoadOnStartup(1);
        return servletDef;
    }

    @PreDestroy
    public void exit() {
        LOGGER.info("Exiting");
    }
}

Point 3 : Le fichier de configuration Spring - CXF

Attention :
- le point important ici est le lien entre le fichier XML et le composant qui implémente le service :

implementor="#eventServiceSoap"

Fichier XML complet :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
	xmlns:soap="http://cxf.apache.org/bindings/soap"
	xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
            http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

	<!-- these are included in the dependency jar -->
	<import resource="classpath:META-INF/cxf/cxf.xml" />
	<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

	<!-- event -->
	<jaxws:endpoint id="eventServiceEndpoint" implementor="#eventServiceSoap"
		address="/event">
		<jaxws:properties>
			<entry key="schema-validation-enabled" value="false" />
		</jaxws:properties>
		<jaxws:binding>
			<soap:soapBinding version="1.2" mtomEnabled="true" />
		</jaxws:binding>
	</jaxws:endpoint>	
</beans>

Ensuite on peut utiliser un composant "Autowired" by Spring :
- EventManagerBean est le résultat de la génération WSDL2Java

@Component("eventServiceSoap")
public class EventServiceImpl implements EventManagerBean {

    /** The Constant LOGGER. */
    private static final Logger LOGGER = LoggerFactory.getLogger(EventServiceImpl.class);

    @Autowired
    EventRepository eventRepository;

    ...

 

 

 

 

Fil RSS des articles de ce mot clé