java - ejemplos - que es un servlet y para que sirve
Cómo acceder a recursos estáticos al mapear un servlet de controlador frontal global en/* (17)
A partir de 3.0.4, debe poder usar mvc:resources
en combinación con mvc:default-servlet-handler
como se describe en la documentación de primavera para lograr esto.
He asignado el asignador de Spring MVC como un servlet de controlador frontal global en /*
.
<servlet>
<servlet-name>home</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>home</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
Sin embargo, esta asignación detiene el acceso a archivos estáticos como CSS, JS, imágenes, etc. que están todos en la carpeta /res/
.
¿Cómo puedo acceder a ellos de todos modos?
Agregue las carpetas que no desea desencadenar el procesamiento de servlets a la sección <static-files>
de su archivo appengine-web.xml.
Acabo de hacer esto y parece que las cosas están empezando a funcionar bien. Aquí está mi estructura:
/
/pages/<.jsp archivos>
/ css
Agregué "/ pages / **" y "/ css / **" a la sección <static-files>
y ahora puedo reenviar a un archivo .jsp desde dentro de un servlet doGet sin causar un bucle infinito.
Asigne el servlet del controlador a un url-pattern
más específico como /pages/*
, coloque el contenido estático en una carpeta específica como /static
y cree un Filter
escuche en /*
que continúe de forma transparente la cadena para cualquier contenido estático y envíe solicitudes al servlet del controlador para otro contenido.
En una palabra:
<filter>
<filter-name>filter</filter-name>
<filter-class>com.example.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>controller</servlet-name>
<servlet-class>com.example.Controller</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>controller</servlet-name>
<url-pattern>/pages/*</url-pattern>
</servlet-mapping>
con lo siguiente en filtro doFilter()
:
HttpServletRequest req = (HttpServletRequest) request;
String path = req.getRequestURI().substring(req.getContextPath().length());
if (path.startsWith("/static")) {
chain.doFilter(request, response); // Goes to default servlet.
} else {
request.getRequestDispatcher("/pages" + path).forward(request, response);
}
No, esto no termina con /pages
en la barra de direcciones del navegador. Es completamente transparente. Si es necesario, puede convertir "/static"
y / o "/pages"
un init-param
del filtro.
Con Spring 3.0.4.RELEASE y superior puede usar
<mvc:resources mapping="/resources/**" location="/public-resources/"/>
Como se ve en Spring Reference .
Después de probar el enfoque de filtro sin éxito (por algún motivo, no ingresé a la función doFilter ()) cambié un poco mi configuración y encontré una solución muy simple para el problema del servidor de la raíz:
En lugar de servir "/ *" en mi Servlet principal, ahora solo escucho los prefijos del idioma dedicado "EN", "EN / *", "DE", "DE / *"
El contenido estático se sirve con el Servlet predeterminado y las solicitudes de raíz vacías van al index.jsp que llama a mi Servlet principal con el idioma predeterminado:
<jsp: incluir página = "/ EN /" /> (ningún otro contenido en la página de índice).
El motivo de la colisión parece ser que, por defecto, la raíz de contexto, "/", debe ser manejada por org.apache.catalina.servlets.DefaultServlet. Este servlet está destinado a manejar solicitudes de recursos estáticos.
Si decide quitarlo del camino con su propio servlet, con la intención de manejar solicitudes dinámicas, ese servlet de nivel superior también debe llevar a cabo cualquier tarea realizada por el controlador original de "DefaultServlet" de catalina.
Si lee los documentos de tomcat, menciona que True Apache (httpd) es mejor que Apache Tomcat para manejar contenido estático, ya que está diseñado específicamente para hacer eso. Mi suposición es porque Tomcat usa de manera predeterminada org.apache.catalina.servlets.DefaultServlet para manejar solicitudes estáticas. Como todo está envuelto en una JVM, y Tomcat está destinado a ser un contenedor Servlet / JSP, probablemente no escribieron esa clase como un controlador de contenido estático súper optimizado. Está allá. Hace el trabajo. Suficientemente bueno.
Pero eso es lo que maneja el contenido estático y vive en "/". Entonces, si pone algo más allí, y esa cosa no maneja las solicitudes estáticas, WHOOPS, ahí van sus recursos estáticos.
He buscado alto y bajo para la misma respuesta y la respuesta que estoy recibiendo en todas partes es "si no quieres que haga eso, no hagas eso".
En pocas palabras, su configuración está desplazando al manejador de recursos estático predeterminado con algo que no es un manejador de recursos estático. Tendrá que probar una configuración diferente para obtener los resultados que está buscando (como lo haré yo).
En Embedded Jetty logré lograr algo similar al agregar una asignación para el directorio "css" en web.xml. Explícitamente diciéndole que use DefaultServlet:
<servlet>
<servlet-name>DefaultServlet</servlet-name>
<servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DefaultServlet</servlet-name>
<url-pattern>/css/*</url-pattern>
</servlet-mapping>
Encontré que usando
<mvc:default-servlet-handler />
en la primavera, el archivo de definición MVC servlet bean funciona para mí. Pasa cualquier solicitud que no sea manejada por un controlador MVC registrado al manejador predeterminado original del contenedor, que debe servir como contenido estático. Solo asegúrate de no tener ningún controlador registrado que maneje todo, y debería funcionar bien. No estoy seguro de por qué @logixplayer sugiere la reescritura de URL; puede lograr el efecto que está buscando de manera adecuada solo con Spring MVC.
Encontré una solución más simple con un archivo de índice ficticio.
Cree un servlet (o use el que desea responder a "/") que se asigna a "/index.html" (las soluciones mencionadas aquí usan la asignación a través de XML, utilicé la versión 3.0 con la anotación @WebServlet) Luego, cree una estática (vacío) archivo en la raíz del contenido estático llamado "index.html"
Estaba usando Jetty, y lo que sucedió fue que el servidor reconoció el archivo en lugar de enumerar el directorio, pero cuando se le preguntó por el recurso, mi Servlet tomó el control en su lugar. El resto del contenido estático no se vio afectado.
La aplicación no puede acceder directamente a los archivos ''Estáticos'' en App Engine. Debe cargarlos dos veces o servir los archivos estáticos usted mismo, en lugar de usar un controlador estático.
La mejor manera de manejar esto es usar algún tipo de reescritura de URL. De esta manera, puede tener URL tranquilas, y NO con extensiones, es decir, abc.com/welcom/register en lugar de abc.com/welcome/resister.html
Uso Tuckey URL, que es genial.
Tiene instrucciones sobre cómo configurar su aplicación web. Lo he configurado con mi aplicación web Spring MVC. Por supuesto, todo estaba bien hasta que quise usar anotaciones para validaciones de Spring 3 como @Email
o @Null
para objetos de dominio.
Cuando agrego las directivas Spring mvc:
< mvc:annotation-driven />
< mvc:default-servlet-handler />
.. rompe el buen código Tuckey. Aparentemente, < mvc:default-servlet-handler />
reemplaza Tuckey, que aún estoy tratando de resolver.
Lo que debes hacer es agregar un archivo de bienvenida en tu web.xml
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
Y luego agréguelo a sus asignaciones de servlet para que cuando alguien vaya a la raíz de su aplicación, se envíe a index.html internamente y luego la asignación se envíe internamente al servlet al que se lo asigna.
<servlet-mapping>
<servlet-name>MainActions</servlet-name>
<url-pattern>/main</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>MainActions</servlet-name>
<url-pattern>/index.html</url-pattern>
</servlet-mapping>
Resultado final: visita / Aplicación, pero se le presenta el servlet / Application / MainActions sin interrumpir ninguna otra solicitud raíz.
¿Consíguelo? Por lo tanto, su aplicación aún se encuentra en una url secundaria, pero se presenta automáticamente cuando el usuario va a la raíz de su sitio. Esto le permite hacer que /images/bob.img siga yendo al lugar habitual, pero "/" es su aplicación.
Me encontré con esto también y nunca encontré una gran solución. Terminé mapeando mi servlet un nivel más alto en la jerarquía de URL:
<servlet-mapping>
<servlet-name>home</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
Y ahora todo en el contexto base (y en su directorio / res) puede ser servido por su contenedor.
Recomiendo tratar de usar un filtro en lugar de un servlet predeterminado siempre que sea posible.
Otras dos posibilidades:
Escriba un FileServlet usted mismo. Encontrará muchos ejemplos, solo debe abrir el archivo por URL y escribir sus contenidos en la secuencia de salida. Luego, úselo para atender solicitudes de archivos estáticos.
Crea una instancia de una clase FileServlet utilizada por Google App Engine y llama al servicio (solicitud, respuesta) en ese FileServlet cuando necesites servir el archivo estático en una URL determinada.
Puede asignar / res / * a YourFileServlet o lo que sea para excluirlo del manejo de DispatcherServlets, o llamarlo directamente desde DispatcherServlet.
Y, tengo que preguntar, ¿qué dice la documentación de Spring sobre esta colisión? Nunca lo he usado
Servir contenido estático con el sufijo apropiado en múltiples definiciones de mapeo de servlets solucionó el problema de seguridad que se menciona en uno de los comentarios en una de las respuestas publicadas. Citado a continuación:
Este fue un agujero de seguridad en Tomcat (los contenidos de WEB-INF y META-INF son accesibles de esta manera) y se ha corregido en 7.0.4 (y también será portado a 5.x y 6.x). - BalusC 2 de noviembre de 2010 a las 22:44
que me ayudó mucho Y así es como lo resolví:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
Si usa Tomcat, puede asignar recursos al servlet predeterminado:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/static/*</url-pattern>
</servlet-mapping>
y acceda a sus recursos con url http: // {context path} / static / res / ...
También funciona con Jetty, no está seguro acerca de otros contenedores de servlets.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<mvc:default-servlet-handler/>
</beans>
y si desea utilizar la configuración basada en anotaciones, use el código siguiente
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}