Могу ли я обслуживать JSP изнутри банки в lib, или есть обходной путь?
у меня есть веб-приложение, развернутое в war-файл в Tomcat 7. Приложение строится как многомодульный проект:
- ядро-упаковано как JAR, содержит большую часть бэкэнд-кода
- core-api-упакованный как JAR, содержит интерфейсы к core
- webapp-упакован как WAR, содержит frontend код и зависит от core
- клиент-расширения-опционный модуль, упакованный как опарник
нормально, мы можем положить наше ДЖСП файлы в проекте webapp и ссылки на них относительно контекста:
/WEB-INF/jsp/someMagicalPage.jsp
вопрос в том, что мы делаем с файлами JSP, которые специфичны для проекта customer-extensions, которые не всегда должны быть включены в войну. К сожалению, я не могу ссылаться на JSP внутри файлов JAR, похоже. Попытка classpath:jsp/customerMagicalPage.jsp
приводит к файлу, не найденному в JspServlet, так как он использует ServletContext.getResource()
.
традиционно мы "решили" это, когда maven распаковывает клиентские расширения JAR, найдите JSP и поместите их в войну при его строительстве. Но идеальная ситуация - это когда вы просто бросаете банку в взорванную войну в Tomcat, и расширение обнаружено, что работает для всего, кроме JSP.
есть ли в любом случае, чтобы решить эту проблему? Стандартный способ, специфичный для Tomcat способ, Хак или обходной путь? Например, я думал о распаковке JSP при запуске приложения...
5 ответов:
сервлет 3.0, который поддерживает Tomcat 7, включает в себя возможность упаковки JSP в банку.
вам нужно:
- поместите ваш JSP в
META-INF/resources
каталог вашего jar- дополнительно включать в себя
web-fragment.xml
наMETA-INF
каталог вашего jar- поместите банку в
WEB-INF/lib
каталог вашей войнывы должны быть в состоянии ссылаться на JSP в вашем контексте. Например, если у вас есть ОСП
META-INF/resources/test.jsp
вы должны быть возможность ссылаться на это в корне вашего контекста какtest.jsp
в качестве обходного пути я создал класс, который открывает файл jar, находит файлы, соответствующие определенному шаблону, и извлекает эти файлы в заданное место относительно пути контекста.
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(); } } }
и затем я настраиваю его как Боб в моем весеннем XML:
<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>
это не оптимальное решение действительно раздражающей проблемы. Теперь возникает вопрос, придет ли парень, который поддерживает этот код и убить меня, пока я сплю для этого?
есть такой обходной путь - вы можете предварительно скомпилировать свои JSP в сервлеты. Так что вы получите .файлы классов вы можете поместить в банку и карту в интернете.xml для некоторых URL-адресов.
Struts 2 команда добавила плагин для встроенного JSP. Может быть, он может быть использован объявление базы.
это откат к waxwing ответ, который я использовал, потому что мы использовали сервер, который не мог сделать ничего выше, чем сервлет 2.5.
я добавил метод, который удаляет файлы, добавленные при уничтожении Боба.
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(); } } }
затем я изменил конструктор, чтобы я мог использовать всю конфигурацию java:
@Bean public JarFileResourcesExtractor jspSupport(){ final JarFileResourcesExtractor extractor = new JarFileResourcesExtractor("WEB-INF/pages/*.jsp","myJarFile-1.1.0.jar","WEB-INF/pages" ); return extractor; }
Я надеюсь, что кто - то это кому-то помогает!