2011-02-16 13 views
55

Tengo una aplicación web implementada como un archivo WAR en Tomcat 7. La aplicación está construida como un proyecto de varios módulos:¿Puedo servir JSP desde dentro de un JAR en lib, o hay una solución?

  • núcleo - empaquetado como JAR, contiene la mayor parte del código de fondo
  • núcleo- api - empaquetado como JAR, contiene interfaces hacia el núcleo
  • webapp - empaquetado como WAR, contiene código frontend y depende de núcleo
  • cliente-extensiones - módulo opcional, envasados ​​como JAR

Normalmente, podemos poner nuestros archivos JSP en el proyecto de aplicación Web, y hacer referencia a ellos en relación con el contexto:

/WEB-INF/jsp/someMagicalPage.jsp 

La cuestión es qué hacer con los archivos JSP que son específicos para el proyecto del cliente-extensiones, que debe no siempre se incluirá en la GUERRA. Desafortunadamente, no puedo referirme a las JSP dentro de los archivos JAR, parece. Al intentar classpath:jsp/customerMagicalPage.jsp, se produce un archivo que no se encuentra en JspServlet, ya que usa ServletContext.getResource().

Tradicionalmente, hemos "resuelto" esto teniendo maven desempaquetar el archivo JAR de extensiones de cliente, ubicar los JSP y colocarlos en el WAR al construirlo. Pero una situación ideal es cuando solo lanzas un JAR en el WAR explosionado en Tomcat y se descubre la extensión, que funciona para todo menos para los JSP.

¿Hay alguna forma de solucionar esto? ¿Una forma estándar, una forma específica de Tomcat, un truco o una solución alternativa? Por ejemplo, he estado pensando en desempaquetar los JSP al iniciar la aplicación ...

+0

guerra debe contener jsp, js y servlets. –

+0

relacionado: http://forum.springsource.org/showthread.php?t=58441 – Bozho

Respuesta

62

Servlet 3.0 que Tomcat 7 soportes incluye la capacidad para empaquetar JSP en un frasco.

Es necesario:

  • lugar las JSP en META-INF/resources directorio de su frasco de
  • incluir opcionalmente un web-fragment.xml en el directorio META-INF de su frasco de
  • lugar el frasco en WEB-INF/lib directorio de su guerra

Debería poder hacer referencia a su jsps en su contexto. Por ejemplo, si usted tiene un JSP META-INF/resources/test.jsp debe ser capaz referencia esta en la raíz de su contexto como test.jsp

+0

Hola, ¿no creo que también sepa cómo usar la directiva include para archivos JSP en un JAR? Las rutas absolutas hacia/META-INF/etiquetas no parecen correctas e incluso una directiva taglib arroja errores. – shousper

+1

¿Y hay alguna forma de hacerlo con Servlet 2.5 o Tomcat 6? – lucasvc

+0

Sí, ¿es posible con Servlet 2.5 o Tomcat 5.5/6? – MychaL

4

Existe una solución alternativa: puede precompilar sus JSP en servlets. Por lo tanto, obtendrá archivos .class que puede colocar en JAR y asignar en web.xml a algunas URL.

+0

Interesante. No estoy seguro de cómo funcionará esto con Tiles (probablemente debería haber mencionado que usamos eso). No estoy seguro de lo que pondría en mi archivo de definición de teselas. – waxwing

6

Como solución alternativa, creé una clase que abre un archivo jar, busca archivos que coinciden con un patrón determinado y extrae esos archivos en una ubicación determinada en relación con la ruta de contexto.

import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.net.MalformedURLException; 
import java.net.URL; 
import java.util.Enumeration; 
import java.util.jar.JarEntry; 
import java.util.jar.JarFile; 

import javax.annotation.PostConstruct; 
import javax.servlet.ServletContext; 

import org.springframework.util.AntPathMatcher; 
import org.springframework.web.context.ServletContextAware; 

/** 
* Allows extraction of contents of a JAR file. All files matching a given Ant path pattern will be extracted into a 
* specified path. 
*/ 
public class JarFileResourcesExtractor implements ServletContextAware { 

    private String resourcePathPattern; 
    private String jarFile; 
    private String destination; 
    private ServletContext servletContext; 
    private AntPathMatcher pathMatcher = new AntPathMatcher(); 

    /** 
    * Creates a new instance of the JarFileResourcesExtractor 
    * 
    * @param resourcePathPattern 
    *   The Ant style path pattern (supports wildcards) of the resources files to extract 
    * @param jarFile 
    *   The jar file (located inside WEB-INF/lib) to search for resources 
    * @param destination 
    *   Target folder of the extracted resources. Relative to the context. 
    */ 
    private JarFileResourcesExtractor(String resourcePathPattern, String jarFile, String destination) { 
     this.resourcePathPattern = resourcePathPattern; 
     this.jarFile = jarFile; 
     this.destination = destination; 
    } 

    /** 
    * Extracts the resource files found in the specified jar file into the destination path 
    * 
    * @throws IOException 
    *    If an IO error occurs when reading the jar file 
    * @throws FileNotFoundException 
    *    If the jar file cannot be found 
    */ 
    @PostConstruct 
    public void extractFiles() throws IOException { 
     try { 
      String path = servletContext.getRealPath("/WEB-INF/lib/" + jarFile); 
      JarFile jarFile = new JarFile(path); 

      Enumeration<JarEntry> entries = jarFile.entries(); 
      while (entries.hasMoreElements()) { 
       JarEntry entry = entries.nextElement(); 
       if (pathMatcher.match(resourcePathPattern, entry.getName())) { 
        String fileName = entry.getName().replaceFirst(".*\\/", ""); 
        File destinationFolder = new File(servletContext.getRealPath(destination)); 
        InputStream inputStream = jarFile.getInputStream(entry); 
        File materializedJsp = new File(destinationFolder, fileName); 
        FileOutputStream outputStream = new FileOutputStream(materializedJsp); 
        copyAndClose(inputStream, outputStream); 
       } 
      } 

     } 
     catch (MalformedURLException e) { 
      throw new FileNotFoundException("Cannot find jar file in libs: " + jarFile); 
     } 
     catch (IOException e) { 
      throw new IOException("IOException while moving resources.", e); 
     } 
    } 

    @Override 
    public void setServletContext(ServletContext servletContext) { 
     this.servletContext = servletContext; 
    } 

    public static int IO_BUFFER_SIZE = 8192; 

    private static void copyAndClose(InputStream in, OutputStream out) throws IOException { 
     try { 
      byte[] b = new byte[IO_BUFFER_SIZE]; 
      int read; 
      while ((read = in.read(b)) != -1) { 
       out.write(b, 0, read); 
      } 
     } finally { 
      in.close(); 
      out.close(); 
     } 
    } 
} 

Y luego configurarlo como un grano en mi XML de Spring:

<bean id="jspSupport" class="se.waxwing.util.JarFileResourcesExtractor"> 
    <constructor-arg index="0" value="jsp/*.jsp"/> 
    <constructor-arg index="1" value="myJarFile-1.1.0.jar"/> 
    <constructor-arg index="2" value="WEB-INF/classes/jsp"/> 
</bean> 

No es una solución óptima a un problema muy molesto. La pregunta ahora es si el tipo que mantiene este código vendrá y murder me while I sleep for doing this?

+2

No es bonito, pero he visto cosas peores. Sin embargo, es posible que haya un problema que desee abordar: no hay funcionalidad para * eliminar * un JSP cuando se elimina el contenedor que lo contiene. –

1

Ésta es una respuesta a follup waxwing, que he utilizado becuase se utilizó un servidor que no podía hacer nada más alto luego servlet 2.5.

Agregué un método que elimina los archivos agregados cuando se destruye el frijol.

import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.net.MalformedURLException; 
import java.net.URL; 
import java.util.ArrayList; 
import java.util.Enumeration; 
import java.util.List; 
import java.util.jar.JarEntry; 
import java.util.jar.JarFile; 

import javax.annotation.PostConstruct; 
import javax.annotation.PreDestroy; 
import javax.servlet.ServletContext; 

import org.springframework.util.AntPathMatcher; 
import org.springframework.web.context.ServletContextAware; 


import com.sap.tc.logging.Location; 

/** 
* Allows extraction of contents of a JAR file. All files matching a given Ant path pattern will be extracted into a 
* specified path. 
* Copied from http://stackoverflow.com/questions/5013917/can-i-serve-jsps-from-inside-a-jar-in-lib-or-is-there-a-workaround 
*/ 
public class JarFileResourcesExtractor implements ServletContextAware { 

    private final transient Location logger = Location.getLocation(JarFileResourcesExtractor.class); 

    private String resourcePathPattern; 
    private String jarFile; 
    private String destination; 
    private ServletContext servletContext; 
    private AntPathMatcher pathMatcher = new AntPathMatcher(); 
    private List<File> listOfCopiedFiles = new ArrayList<File>(); 

    /** 
    * Creates a new instance of the JarFileResourcesExtractor 
    * 
    * @param resourcePathPattern 
    *   The Ant style path pattern (supports wildcards) of the resources files to extract 
    * @param jarFile 
    *   The jar file (located inside WEB-INF/lib) to search for resources 
    * @param destination 
    *   Target folder of the extracted resources. Relative to the context. 
    */ 
    public JarFileResourcesExtractor(String resourcePathPattern, String jarFile, String destination) { 
     this.resourcePathPattern = resourcePathPattern; 
     this.jarFile = jarFile; 
     this.destination = destination; 
    } 


    @PreDestroy 
    public void removeAddedFiles() throws IOException{ 
     logger.debugT("I removeAddedFiles()"); 
     for (File fileToRemove : listOfCopiedFiles) { 
      if(fileToRemove.delete()){ 
       logger.debugT("Tagit bort filen " + fileToRemove.getAbsolutePath()); 
      } 
     } 
    } 


    /** 
    * Extracts the resource files found in the specified jar file into the destination path 
    * 
    * @throws IOException 
    *    If an IO error occurs when reading the jar file 
    * @throws FileNotFoundException 
    *    If the jar file cannot be found 
    */ 
    @PostConstruct 
    public void extractFiles() throws IOException { 
     try { 
      String path = servletContext.getRealPath("/WEB-INF/lib/" + jarFile); 
      JarFile jarFile = new JarFile(path); 

      Enumeration<JarEntry> entries = jarFile.entries(); 
      while (entries.hasMoreElements()) { 
       JarEntry entry = entries.nextElement(); 
       if (pathMatcher.match(resourcePathPattern, entry.getName())) { 
        String fileName = entry.getName().replaceFirst(".*\\/", ""); 
        File destinationFolder = new File(servletContext.getRealPath(destination)); 
        InputStream inputStream = jarFile.getInputStream(entry); 
        File materializedJsp = new File(destinationFolder, fileName); 
        listOfCopiedFiles.add(materializedJsp); 
        FileOutputStream outputStream = new FileOutputStream(materializedJsp); 
        copyAndClose(inputStream, outputStream); 
       } 
      } 

     } 
     catch (MalformedURLException e) { 
      throw new FileNotFoundException("Cannot find jar file in libs: " + jarFile); 
     } 
     catch (IOException e) { 
      throw new IOException("IOException while moving resources.", e); 
     } 
    } 

    @Override 
    public void setServletContext(ServletContext servletContext) { 
     this.servletContext = servletContext; 
    } 

    public static int IO_BUFFER_SIZE = 8192; 

    private static void copyAndClose(InputStream in, OutputStream out) throws IOException { 
     try { 
      byte[] b = new byte[IO_BUFFER_SIZE]; 
      int read; 
      while ((read = in.read(b)) != -1) { 
       out.write(b, 0, read); 
      } 
     } finally { 
      in.close(); 
      out.close(); 
     } 
    } 
} 

luego hice cambiar el constructor para poder usar toda la configuración de Java:

@Bean 
public JarFileResourcesExtractor jspSupport(){ 
    final JarFileResourcesExtractor extractor = new JarFileResourcesExtractor("WEB-INF/pages/*.jsp","myJarFile-1.1.0.jar","WEB-INF/pages"); 
    return extractor; 
} 

espero que alguien esto ayude a alguien!

Cuestiones relacionadas