J'aimerais que mon application JAX-RX démarre au contexte racine afin que mes URL soient
http://example.com/restfullPath
et pas
http://example.com/rest/restfullPath
J'ai changé l'annotation de mon application à partir de ce
@ApplicationPath("/rest/*")
pour ça
@ApplicationPath("/*")
Mais il semble qu'il prenne en charge le service de fichiers tels que /index.html
Existe-t-il un moyen d'exécuter un JAX-RS sur le contexte de l'application racine tout en conservant des pages statiques?
Semble que c'était demandé avant sur le forum JBOSS, mais la solution n'est pas vraiment pratique
Ce n'est probablement pas tant un bug qu'une limitation de la spécification Servlet. Les détails de la gestion d'un JAX-RS @ApplicationPath
Sont spécifiques à l'implémentation, et je ne peux pas parler pour toutes les implémentations, mais je suppose que l'approche typique consiste à simplement l'utiliser comme modèle d'URL de servlet. En jetant un coup d'œil à l'implémentation ServletContainerInitializer de Jersey comme exemple, vous constaterez que la méthode addServletWithApplication()
est responsable de la création de la servlet et du mappage pour gérer les demandes, et vous pouvez voir qu'elle utilise en effet le chemin de @ApplicationPath
comme chemin mappé de Jersey ServletContainer.
Malheureusement, depuis des temps immémoriaux, la spécification Servlet n'a autorisé qu'une petite poignée de façons de mapper les servlets aux chemins URL. Les options actuelles avec Servlet 3.0, données dans Section 12.2 de la spécification - malheureusement uniquement disponible en format PDF, donc non liable par section - sont:
/.../*
Où le /...
Initial est zéro ou plusieurs éléments de chemin*.<ext>
Où <ext>
Est une extension à faire correspondre/
, La barre oblique unique, qui indique le servlet "par défaut" dans le contexte, qui gère tout ce qui ne correspond à rien d'autreLa même section de la spécification a également des règles spécifiques pour l'ordre dans lequel les règles de correspondance doivent s'appliquer, mais la version courte est la suivante: pour que votre classe de ressources réponde aux demandes à la racine du contexte, vous devez utiliser soit /
ou /*
comme chemin. Si vous utilisez /
, Vous remplacez le servlet par défaut du conteneur, qui serait normalement responsable de la gestion des ressources statiques. Si vous utilisez /*
, Vous le rendez trop gourmand et vous dites qu'il doit tout correspondre en permanence, et la servlet par défaut ne sera jamais invoquée.
Donc, si nous acceptons que nous sommes à l'intérieur de la zone déterminée par les limites des modèles d'URL de servlet, nos options sont assez limitées. Voici ceux auxquels je peux penser:
1) Utilisez @ApplicationPath("/")
, et mappez explicitement vos ressources statiques par nom ou par extension au servlet par défaut du conteneur (nommé "default" dans Tomcat et Jetty, pas sûr des autres). Dans un web.xml, cela ressemblerait à
<!-- All html files at any path -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<!-- Specifically index.html at the root -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/index.html</url-pattern>
</servlet-mapping>
ou avec un ServletContextInitializer , comme
public class MyInitializer implements ServletContainerInitializer {
public void onStartup(Set<Class<?>> c, ServletContext ctx) {
ctx.getServletRegistration("default").addMapping("*.html");
ctx.getServletRegistration("default").addMapping("/index.html");
}
}
En raison de la façon dont les règles de correspondance sont écrites, un modèle d'extension l'emporte sur le servlet par défaut, vous n'aurez donc qu'à ajouter un mappage par extension de fichier statique tant qu'il n'y a pas de chevauchement entre celles-ci et les "extensions" qui pourraient se produire dans votre API. C'est assez proche de l'option indésirable mentionnée dans le post du forum que vous avez lié, et je le mentionne juste pour être complet et pour ajouter la partie ServletContextInitializer.
2) Laissez votre API mappée sur /rest/*
Et utilisez un filtre pour identifier les demandes de l'API et les transférer vers ce chemin. De cette façon, vous sortez de la zone de modèle d'URL de servlet et pouvez faire correspondre les URL comme vous le souhaitez. Par exemple, en supposant que tous vos appels REST sont vers des chemins qui commencent par "/ foo" ou sont exactement "/ bar" et que toutes les autres demandes doivent aller vers des ressources statiques, puis quelque chose comme:
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import Java.io.IOException;
import Java.util.regex.Pattern;
@WebFilter(urlPatterns = "/*")
public class PathingFilter implements Filter {
Pattern[] restPatterns = new Pattern[] {
Pattern.compile("/foo.*"),
Pattern.compile("/bar"),
};
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (request instanceof HttpServletRequest) {
String path = ((HttpServletRequest) request).getServletPath();
for (Pattern pattern : restPatterns) {
if (pattern.matcher(path).matches()) {
String newPath = "/rest/" + path;
request.getRequestDispatcher(newPath)
.forward(request, response);
return;
}
}
}
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void destroy() {}
}
Avec ce qui précède, vous traduisez essentiellement les demandes comme suit:
http://example.org/foo -> http://example.org/rest/foo
http://example.org/foox -> http://example.org/rest/foox
http://example.org/foo/anything -> http://example.org/rest/foo/anything
http://example.org/bar -> http://example.org/rest/bar
http://example.org/bart -> http://example.org/bart
http://example.org/index.html -> http://example.org/index.html
3) Réalisez que l'option précédente est essentiellement la réécriture d'URL et utilisez une implémentation existante, telle que mod_rewrite d'Apache , le filtre de réécriture Tuckey , ou ocpsoft Rewrite =.
J'ai trouvé une autre solution qui implique des classes Jersey internes, je suppose que cela ne fait probablement pas encore partie de la spécification JAX-RS. (basé sur: http://www.lucubratory.eu/simple-jerseyrest-and-jsp-based-web-application/ )
web.xml
<web-app version="3.0" xmlns="http://Java.Sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://Java.Sun.com/xml/ns/javaee http://Java.Sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>jersey-rest-jsp-frame-1</display-name>
<filter>
<filter-name>jersey</filter-name>
<filter-class>
com.Sun.jersey.spi.container.servlet.ServletContainer
</filter-class>
<init-param>
<param-name>
com.Sun.jersey.config.property.JSPTemplatesBasePath
</param-name>
<param-value>/WEB-INF/jsp</param-value>
</init-param>
<init-param>
<param-name>
com.Sun.jersey.config.property.WebPageContentRegex
</param-name>
<param-value>
(/(image|js|css)/?.*)|(/.*\.jsp)|(/WEB-INF/.*\.jsp)|
(/WEB-INF/.*\.jspf)|(/.*\.html)|(/favicon\.ico)|
(/robots\.txt)
</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>jersey</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
WEB-INF/jsp/index.jsp
<%@ page contentType="text/html; charset=UTF-8" language="Java" %>
<html>
<body>
<h2>Hello ${it.foo}!</h2>
</body>
</html>
IndexModel.Java
package example;
import com.Sun.jersey.api.view.Viewable;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import Java.net.URI;
import Java.util.HashMap;
@Path("/")
@Produces(MediaType.TEXT_HTML)
public class IndexModel {
@GET
public Response root() {
return Response.seeOther(URI.create("/index")).build();
}
@GET
@Path("index")
public Viewable index(@Context HttpServletRequest request) {
HashMap<String, String> model = new HashMap<String, String>();
model.put("foo","World");
return new Viewable("/index.jsp", model);
}
}
Cela semble fonctionner, mais je me demande si cela fait/fera partie de la spécification/implémentation JAX-RS.
Vous pouvez essayer de rechercher DefaultServlet
de votre conteneur de servlet et ajouter le mappage de servlet à la main dans web.xml
pour gérer les fichiers de page tels que * .html, * .jsp ou tout autre.
Par exemple. pour Tomcat 5.5, il est décrit ici: http://Tomcat.Apache.org/Tomcat-5.5-doc/default-servlet.html .
Citant @damo pour Jersey 2.0 dans un autre article
"Alternativement, vous pourriez être en mesure de retirer quelque chose avec une sorte de redirection. Par exemple, avec un Filtre de pré-correspondance . Je n'ai jamais rien fait de tel, mais la documentation suggère que" vous peut même modifier l'URI de la demande "."
Utilisez plutôt @ApplicationPath("/")
(sans astérisque). Cela vous aidera dans votre cas.
Voici un exemple de service Web REST:
1. JaxRsActivator.Java
package com.stackoverflow;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/")
public class JaxRsActivator extends Application {
}
2. HelloService.Java
package com.stackoverflow;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/hello")
public class HelloService {
@GET
@Produces(MediaType.TEXT_HTML)
public String hello() {
return "hello";
}
}
J'ai utilisé Eclipse pour exporter ce projet Web dynamique vers un fichier WAR nommé helloservice.war
et je l'ai déployé sur WildFly qui s'exécutait sur ma machine locale. Son URL: http://localhost:8080/helloservice/hello
.
En accédant à ce lien, il a renvoyé:
hello