Czy mogę podawać JSP z wnętrza słoika w lib, czy istnieje obejście?
Mam aplikację internetową wdrożoną jako plik wojenny w Tomcat 7. Aplikacja jest budowana jako projekt wielomodułowy:
- core-pakowany jako JAR, zawiera większość kodu backendu
- core-api-pakowane jako JAR, zawiera interfejsy do core
- webapp-pakowany jako WAR, zawiera kod frontend i zależy od rdzenia
- customer-extensions-opcjonalny moduł, pakowany jako JAR
Normalnie możemy umieścić nasze pliki JSP w projekcie webapp, a odwołaj się do nich względem kontekstu:
/WEB-INF/jsp/someMagicalPage.jsp
Pytanie brzmi, co robimy z plikami JSP, które są specyficzne dla projektu customer-extensions, które nie zawsze powinny być uwzględnione w wojnie. Niestety, nie mogę odnieść się do JSP wewnątrz plików JAR, wygląda na to. Próba classpath:jsp/customerMagicalPage.jsp
spowoduje, że plik nie zostanie znaleziony w JspServlet, ponieważ używa ServletContext.getResource()
.
Tradycyjnie "rozwiązaliśmy" to po rozpakowaniu przez Mavena słoika rozszerzeń klienta, zlokalizowaniu JSP i umieszczeniu ich w wojnie, gdy buduję go. Ale idealną sytuacją jest to, że po prostu upuszczasz słoik w wybuchu wojny w Tomcat i odkrywa się rozszerzenie - które działa na wszystko, oprócz JSP.
Czy można to jakoś rozwiązać? Standardowy sposób, specyficzny dla Tomcata sposób, hack, czy obejście? Na przykład myślałem o rozpakowaniu JSP podczas uruchamiania aplikacji...5 answers
Servlet 3.0, który obsługuje Tomcat 7, zawiera możliwość spakowania JSP do jar.
Musisz:
- umieść swoje JSP w
META-INF/resources
katalogu swojego jar - opcjonalnie dołącz
web-fragment.xml
do kataloguMETA-INF
swojego jar - umieść słoik w
WEB-INF/lib
katalogu swojej wojny
Powinieneś być w stanie odwołać się do swoich JSP w swoim kontekście. Na przykład, jeśli masz jsp META-INF/resources/test.jsp
powinieneś być w stanie odwołać się do tego w źródle kontekstu jako test.jsp
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-16 11:34:22
Jako obejście stworzyłem klasę, która otwiera plik jar, wyszukuje pliki pasujące do określonego wzorca i wyodrębnia te pliki do określonej lokalizacji względem ścieżki kontekstowej.
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();
}
}
}
A potem konfiguruję go jako fasolkę w moim Spring 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>
To nie jest optymalne rozwiązanie naprawdę irytującego problemu. Teraz pojawia się pytanie, czy facet, który utrzymuje ten kod, przyjdzie i zamorduje mnie, gdy śpię za zrobienie tego?Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-16 15:09:27
Istnieje takie obejście-możesz wstępnie skompilować swoje JSP do servletów. Więc dostaniesz .pliki klas można umieścić w JAR i map w web.xml do niektórych adresów URL.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-16 08:21:31
Zespół Struts 2 dodał wtyczkę do wbudowanego JSP. Może może być używany jako baza.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-13 14:41:11
To jest follup do waxwing odpowiedź, której użyłem ponieważ użyliśmy serwera, który nie mógł zrobić nic wyższego niż servlet 2.5.
Dodałem metodę, która usuwa pliki dodane po zniszczeniu fasoli.
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();
}
}
}
Potem zmieniłem konstruktor, aby móc korzystać z całej konfiguracji Javy:
@Bean
public JarFileResourcesExtractor jspSupport(){
final JarFileResourcesExtractor extractor = new JarFileResourcesExtractor("WEB-INF/pages/*.jsp","myJarFile-1.1.0.jar","WEB-INF/pages" );
return extractor;
}
Mam nadzieję, że komuś to pomoże!Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-17 15:06:37