2012-06-03 6 views
28

me gustaría tener mi Inicio de la aplicación JAX-RX en el contexto de la raíz por lo que mis URLs seránJAX-RS Aplicación en el contexto raíz: ¿cómo se puede hacer?

http://example.com/restfullPath

y no

http://example.com/rest/restfullPath

Cambié anotación de mi aplicación de esta

@ApplicationPath("/rest/*") 

a este

@ApplicationPath("/*") 

Pero entonces parece que se hace cargo de servicio de archivos tales como /index.html

¿Hay una forma de ejecutar un JAX-RS en el contexto de aplicación de la raíz, pero todavía han servido las páginas estáticas?

parece que esto era asked before en el foro de JBOSS, pero la solución no es realmente práctico

Respuesta

31

Probablemente no sea tanto un error como una limitación de las especificaciones del Servlet. Los detalles de cómo se maneja una JAX-RS @ApplicationPath son específicos de la implementación, y no puedo hablar de todas las implementaciones, pero supongo que el enfoque típico es simplemente usarlo como un patrón de URL de servlet. Echando un vistazo a la implementación ServletContainerInitializer de Jersey como un ejemplo, encontrará que el addServletWithApplication() method es responsable de crear el servlet y el mapeo para manejar las solicitudes, y puede ver que sí, de hecho, usa la ruta del @ApplicationPath como Jersey ServletContainer's ruta mapeada.

Desafortunadamente, desde tiempos inmemoriales, la especificación de Servlet ha permitido solo un pequeño puñado de maneras de asignar servlets a rutas de URL. Las opciones actuales con Servlet 3.0, dados en Section 12.2 of the spec --sadly sólo está disponible en formato PDF, por lo que no vinculable por sección - son:

  • /.../* donde el /... inicial es cero o más elementos de ruta
  • *.<ext> donde <ext> es un poco de extensión para que coincida con
  • la cadena vacía, que asigna sólo a la raíz vacío ruta/contexto
  • /, la sola barra, lo que indica que el servlet "default" en el contexto, que se ocupa de todo lo que no hace emparejar cualquier otra cosa
  • cualquier otra cadena, que se trata como un valor literal para que coincida con

La misma sección de la especificación también tiene normas específicas para el orden en que deben aplicarse las reglas de coincidencia, pero la versión corta es la siguiente: Para realizar las solicitudes de respuesta de clase de recurso en la raíz de contexto, debe usar / o /* como ruta.Si usa /, está reemplazando el servlet predeterminado del contenedor, que normalmente sería responsable de manejar los recursos estáticos. Si usa /*, entonces lo está haciendo demasiado codicioso y diciendo que debe coincidir todo todo el tiempo, y el servlet predeterminado nunca será invocado.

Así que si aceptamos que estamos dentro del cuadro determinado por las limitaciones de los patrones de servlet URL, nuestras opciones son bastante limitadas. Aquí están los que puedo pensar:

1) Use @ApplicationPath("/"), y explíqueme explícitamente sus recursos estáticos por nombre o por extensión al servlet predeterminado del contenedor (denominado "predeterminado" en Tomcat y Jetty, no estoy seguro de los demás). En un web.xml, que se vería así

<!-- 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> 

o con un ServletContextInitializer, como

public class MyInitializer implements ServletContainerInitializer { 
    public void onStartup(Set<Class<?>> c, ServletContext ctx) { 
     ctx.getServletRegistration("default").addMapping("*.html"); 
     ctx.getServletRegistration("default").addMapping("/index.html"); 
    } 
} 

Debido a la forma en que las reglas de concordancia se escriben, un patrón de extensión gana sobre el servlet por defecto, por lo solo necesitaría agregar una asignación por extensión de archivo estático, siempre que no haya superposición entre esas y las "extensiones" que puedan ocurrir en su API. Esto está muy cerca de la opción indeseable mencionada en la publicación del foro que vinculó, y solo la menciono para completarla y para agregar la parte de ServletContextInitializer.

2) Deje su API asignada al /rest/*, y use un filtro para identificar las solicitudes de la API y reenviarlas a esa ruta. De esta forma, saldrá del cuadro de patrón de URL del servlet y podrá hacer coincidir las URL de la forma que desee. Por ejemplo, suponiendo que todas sus llamadas REST son caminos que comiencen con la letra "/ foo" o son exactamente "/ bar" y todas las demás solicitudes deben ir a los recursos estáticos, a continuación, algo así como:

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() {} 
} 

Con el anterior, se traduce esencialmente solicitudes de la siguiente manera:

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) dan cuenta que la opción anterior es básicamente la reescritura de URL y utiliza una aplicación existente, como Apache's mod_rewrite, la Tuckey rewrite filter, o ocpsoft Rewrite.

1

He encontrado otra solución que implica clases internas de Jersey, supongo que probablemente aún no sea parte de la especificación JAX-RS. (Basado en: 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); 
    } 
} 

Esto parece funcionar, pero me pregunto si es/será parte de la especificación/implementación de JAX-RS.

0

Citando @damo de Jersey 2.0 desde otro post

"Alternativamente, usted podría ser capaz de sacar algo con algún tipo de cambio de dirección. Por ejemplo, con un Pre-matching Filter.Nunca he hecho algo como esto, pero la documentación sugiere que "incluso se puede modificar URI de la solicitud"."

0

Uso @ApplicationPath("/") lugar (sin asterisco). Esto ayudará en su caso.

Aquí es una muestra de servicio REST web:

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"; 
    } 
} 

Utilicé Eclipse para exportar este proyecto web dinámico a un archivo WAR denominado helloservice.war y lo implementé en WildFly, que se estaba ejecutando en mi máquina local. Su URL: http://localhost:8080/helloservice/hello.

Cuando se accede a este enlace ha devuelto:

hello 
+0

No veo cómo esto se ocupa de la cuestión. Pero aquí está el blog del que proviene el código de esta respuesta, si alguien tiene curiosidad: http://buraktas.com/resteasy-example-without-using-a-web-xml/ – Amalgovinus

+0

Lo escribí según mi experiencia. Su enlace no tiene ningún código que crea que sea el mismo para mi código aquí. Mi código es una plantilla genérica, no un código propietario específico. Si desea publicitar, este no es el lugar correcto para hacerlo. –

Cuestiones relacionadas