1. Introducción al servlet
Servlet es una tecnología proporcionada por Sun Company para desarrollar recursos web dinámicos.
Sun proporciona una interfaz de servlet en su API. Si los usuarios desean enviar un recurso web dinámico (es decir, desarrolle un programa Java para emitir datos al navegador), deben completar los siguientes dos pasos:
1. Escriba una clase Java para implementar la interfaz Servlet.
2. Implemente las clases de Java desarrolladas en el servidor web.
Según un hábito de nombre convencional, generalmente llamamos programas Java que implementan el servlet de interfaz de servlet.
2. El proceso de operación de servlet
El programa de servlet es llamado por el servidor web. Después de que el servidor web recibe la solicitud de acceso al servlet del cliente:
① El servidor web primero verifica si se ha cargado y creado un objeto de instancia del servlet. Si es así, ejecute el paso 4 directamente; De lo contrario, ejecute el paso 2.
② Cargue y cree un objeto de instancia del servlet.
③Tall el método init () del objeto de instancia de servlet.
④ Cree un objeto HTTPservletRequest para encapsular los mensajes de solicitud HTTP y un objeto HTTPServletResponse que represente los mensajes de respuesta HTTP, y luego llame al método Servlet Service () y pase los objetos de solicitud y respuesta como parámetros.
⑤ Antes de que la aplicación web se detenga o reinicie, el motor del servlet desinstalará el servlet y llamará al método Destroy () del servlet antes de desinstalar.
3. Diagrama de llamadas de servlet
4. Desarrollar servlet en eclipse
Cree un nuevo proyecto web en Eclipse, y Eclipse creará automáticamente la estructura del directorio que se muestra en la siguiente figura:
4.1. Clase de implementación de la interfaz de servlet
Servlet Interface Sun Company define dos clases de implementación predeterminadas, a saber: GenericServlet y Httpservlet.
Httpservlet se refiere a un servlet que puede manejar las solicitudes HTTP. Agrega algunos métodos de procesamiento del protocolo HTTP a la interfaz Servlet original, que es más potente que la interfaz Servlet. Por lo tanto, al escribir servlets, los desarrolladores generalmente deben heredar esta clase y evitar implementar directamente la interfaz Servlet.
Cuando httpservlet implementa la interfaz Servlet, sobrescribe el método de servicio. El código en el cuerpo del método determinará automáticamente el método de solicitud del usuario. Si se trata de una solicitud GET, se llama al método de DoGet de httpservlet. Si se trata de una solicitud posterior, se llamará al método DOPOST. Por lo tanto, al escribir servlets, los desarrolladores generalmente solo necesitan sobrescribir el método Doget o Dopost en lugar de sobrescribir el método de servicio.
4.2. Crear y escribir servlets a través de Eclipse
Seleccione el paquete gacl.servlet.study, haga clic con el botón derecho → nuevo → servlet, como se muestra en la figura a continuación:
De esta manera, utilizaremos Eclipse para ayudarnos a crear un servlet con el nombre ServletDemo1. Habrá el siguiente código en el servletdemo01 creado:
paquete gacl.servlet.study; import java.io.ioexception; import java.io.printwriter; import javax.servlet.servletexception; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletRequest; importar; import javax.servlet.http.httpservletResponse; public class ServletDemo1 extiende httpservlet { /*** El método de dietada del servlet. <br> * * Este método se llama cuando un formulario tiene su método de valor de etiqueta es igual a obtener. * * @Param Solicitud La solicitud enviada por el cliente al servidor * @param Respuesta La respuesta envía por el servidor al cliente * @throws ServletException Si ocurrió un error * @throws ioexception si ocurrió un error */ public void doget (httpSeVletRequest solicitud, httpServletResponse Respuesta) ServletException, iOexception {Respuesta. PrintWriter out = Response.getWriter (); out.println ("<! DocType html public/"-// w3c // dtd html 4.01 transitional // en/">"); out.println ("<Ethead> <title> un servlet </title> </head>"); out.println ("<body>"); out.print ("esto es"); out.print (this.getClass ()); out.println (", usando el método get"); out.println ("</body>"); out.println ("</html>"); out.flush (); out.close (); } /*** El método Dopost del servlet. <br> * * Este método se llama cuando un formulario tiene su método de valor de etiqueta es igual a publicar. * * @param Solicitud La solicitud enviada por el cliente al servidor * @param Respuesta La respuesta enviada por el servidor al cliente * @throws ServletException Si ocurrió un error * @throws ioexception si ocurrió un error */ public void dopost (httpservletRequest solicitud, httpServletResponse respuesta) ServletException, ioException { respuesta.setContentType ("Text/html"); PrintWriter out = Response.getWriter (); out.println ("<! DocType html public/"-// w3c // dtd html 4.01 transitional // en/">"); out.println ("<html>"); out.println ("<Ethead> <title> un servlet </title> </head>"); out.println ("<body>"); out.println ("<body>"); out.println ("esto es"); out.print (this.getClass ()); out.println (", usando el método post"); out.println ("</body>"); out.println ("</html>"); out.flush (); out.close (); }}ECLIPSE generan automáticamente estos códigos, y hay dos pares de etiquetas en el archivo web.xml, <ervlet> </servlet> y <servlet-mapping> </servlet-mapping>. Estos dos pares de etiquetas están configurados con servletdemo1, como se muestra en la figura a continuación:
Luego podemos acceder al servletdemo1 servlet a través del navegador, como se muestra en la figura a continuación:
5. Presta atención a los detalles en el desarrollo de servlet
5.1. Configuración de mapeo de URL de acceso a Servlet
Dado que el cliente accede a los recursos en el servidor web a través de una dirección de URL, si el programa Servlet desea acceder por el mundo exterior, debe asignar el programa Servlet a una dirección de URL. Este trabajo se realiza en el archivo web.xml utilizando el elemento <ervlet> y el elemento <servlet-mapping>.
El elemento <servlet> se usa para registrar un servlet. Contiene dos elementos infantiles principales: <Servlet-Name> y <Servlet-Class>, que se utilizan para establecer el nombre de registro del servlet y el nombre de clase completa del servlet respectivamente.
Un elemento <Servlet-Mapping> se usa para asignar una ruta de acceso externo a un servlet registrado. Contiene dos elementos infantiles: <Servlet-name> y <url-pattern>, que se utilizan para especificar el nombre de registro del servlet y la ruta de acceso externo del servlet. Por ejemplo:
<Servlet> <Servlet-name> ServletDemo1 </servlet-name> <ervlet-class> gacl.servlet.study.servletdemo1 </servlet-class> </servlet> <ervlet-mapping> <ervlet-name> servletdemo1 </servlet-name> <url-pattern>/servletdemo1 </url El mismo servlet se puede asignar a múltiples URL, es decir, el valor de configuración del elemento <servlet-name> infantil de múltiples elementos <-mapping> los elementos pueden ser el nombre de registro del mismo servlet. Por ejemplo: <Servlet> <Servlet-name> ServletDemo1 </servlet-name> <ervlet-class> gacl.servlet.study.servletdemo1 </servlet-class> </servlet> <servlet-mapping> <servlet-mapping> <servlet-name> servletdemo1 </servlet-name> <Url-Tattern>/Servlet/ServletDemo1 </url-Pattern> </Servlet-Mapping> <Servlet-Mapping> <Servlet-name> ServletDemo1 </Servlet-Name> <ULL-Pattern> /1.htm </url-Pattern> </servlet-mapping> <ervlet-papping> <ervlet-name> Servletdemo1 </servlet>> <Url-Pattern> /2.jsp </sul-Pattern> </servlet-mapping> <servlet-mapping> <ervlet-mapping> <ervlet-name> servletdemo1 </servlet-name> <url-pattern> /3.php </ url-pattern> </servlet-mapping> <ervlet-mapping> <ervlet-mapping> <ervlet-name> servletdemo1 </servlet-mapping> <URL-Pattern> /4.aspx </url-Pattern> </Servlet Mapping>
A través de la configuración anterior, cuando queremos acceder a un servlet con el nombre ServletDemo1, podemos usar las siguientes direcciones para acceder:
http: // localhost: 8080/javaweb_servlet_study_20140531/servlet/servletdemo1
http: // localhost: 8080/javaweb_servlet_study_20140531/1.htm
http: // localhost: 8080/javaweb_servlet_study_20140531/2.jsp
http: // localhost: 8080/javaweb_servlet_study_20140531/3.php
http: // localhost: 8080/javaweb_servlet_study_20140531/4.aspx
ServletDemo1 se asigna a múltiples URL.
5.2. Use * Mapeo de comodín para URL de acceso al servlet
El*carácter comodín también se puede usar en las URL a las que se mapea el servlet, pero solo puede haber dos formatos fijos: uno es la "extensión*.", Y la otra es el comienzo con una barra de avance (/) y termina con un "/*". Por ejemplo:
<Servlet> <Servlet-name> ServletDemo1 </servlet-name> <ervlet-class> gacl.servlet.study.servletdemo1 </servlet-class> </servlet> <ervlet-mapping> <servlet-name> servletdemo1 </servlet-name> <url-pattern>/*</ url-pattern>
*Puede coincidir con cualquier carácter, por lo que puede usar cualquier URL para acceder al servletdemo1 servlet, como se muestra en la figura a continuación:
Para algunas relaciones de mapeo a continuación:
Servlet1 mapas a /ABC /*
Servlet2 mapas a /*
Servlet3 mapas a /ABC
Servlet4 mapas a *.do
pregunta:
Cuando la URL de solicitud es "/abc/a.html", "/abc/*" y "/*" ambos coinciden, que el servlet responde al motor servlet llamará servlet1.
Cuando la URL de solicitud es "/ABC", tanto "/ABC/*" y "/ABC", que Servlet responde al motor Servlet llamará a Servlet3.
Cuando la URL de solicitud es "/abc/a.do", tanto "/ABC/*" y "*.do", que Servlet responde al motor Servlet llamará a Servlet1.
Cuando la URL de solicitud es "/a.do", tanto "/*" y "*.do", que Servlet responde al motor Servlet llamará a Servlet2.
Cuando la URL de solicitud es "/xxx/yyy/a.do", tanto "/*" y "*.do", que Servlet responde al motor Servlet llamará a Servlet2.
El principio de coincidencia es "quien se vea más como encontrará a quien se vea más"
5.3. La diferencia entre las clases de Servlet y Java ordinarios
Servlet es una clase de Java para la llamada de otros programas Java (motores de servlet). No puede funcionar de forma independiente, y su operación está completamente controlada y programada por el motor Servlet.
Para múltiples solicitudes de servlet del cliente, generalmente el servidor solo creará un objeto de instancia de servlet. Es decir, una vez que se cree el objeto de instancia de servlet, residirá en la memoria y atenderá otras solicitudes posteriores. El objeto de instancia de servlet no se destruirá hasta que salga el contenedor web.
Durante toda la vida de un servlet, el método init del servlet se llama solo una vez. Cada solicitud de acceso a un servlet hace que el motor del servlet llame al método de servicio de servlet una vez. Para cada solicitud de acceso, el motor Servlet creará un nuevo objeto de solicitud HTTPServletRequest y un nuevo objeto de respuesta HTTPServletResponse, y luego pasará estos dos objetos como parámetros al método Servicio () del servlet que llama. El método de servicio luego llama al método Doxxx de acuerdo con el método de solicitud.
Si un elemento <load-on-startup> está configurado en el elemento <ervlet>, entonces cuando se inicia la aplicación web, cargará y creará el objeto de instancia de servlet y llame al método init () del objeto de instancia de servlet.
Por ejemplo:
<Servlet> <Servlet-name> Invoker </servlet-name> <ervlet-class> org.apache.catalina.servlets.invokerservlet </servlet-class> <load-on-shartup> 1 </load-on-startup> </servlet>
Propósito: Escriba un InitServlet para la aplicación web. Este servlet está configurado para cargar en el inicio para crear tablas y datos de base de datos necesarios para toda la aplicación web.
5.4. Servlet predeterminado
Si la ruta de mapeo de un servlet es solo una barra de avance (/), entonces este servlet se convierte en el servlet predeterminado de la aplicación web actual.
Cualquier URL del elemento de <servlet-mapping> que no se puede encontrar en el archivo web.xml, sus solicitudes de acceso se entregarán al servlet predeterminado para el procesamiento, es decir, el servlet predeterminado se usa para manejar las solicitudes de acceso que no son procesadas por otros servlets. Por ejemplo:
<Servlet> <Servlet-name> ServletDemo2 </servlet-name> <ervlet-class> gacl.servlet.study.servletdemo2 </servlet-class> <load-on-startup> 1 </load on-startup> </servlet> <!-Configure ServletDemo2 como el servlet predeterminado-> <ervlet-Papping> <Servlet-Name> ServletDemo2 </servlet-name> <url-pattern>/</url-Pattern> </Servlet-mapping>
Al acceder a un servlet inexistente, el servlet predeterminado configurado se usa para el procesamiento, como se muestra en la figura a continuación:
En el archivo <Directorio de instalación <TomCat> /Conf/Web.XML, se registra un servlet llamado org.apache.catalina.servlets.defaultservlet, y este servlet está configurado como el servlet predeterminado.
<servlet> <servlet-name> default </servlet-name> <ervlet-class> org.apache.catalina.servlets.defaultservlet </servlet-class> <ithparam> <amamname> debug </param-name> <amam-value> 0 </param-value> </initparam> <init-param> <amamame> listings </param-value> 0 </param-value> </initparam> <init-param> <amamame> listings </param-value> 0 </param-value> </initparam> <init-param> <amamame> listings </param-value> 0 </param-value> </initparam> <ic-param> <amamname> listings </param-value> 0 </param-value> </initparam> <ic-param> <Amam-Value> FALSE </param-value> </it-param> <load-on-startup> 1 </load-on-startup> </servlet> <!-la asignación para el servlet predeterminado-> <ervlet-mapping> <servlet-name> default </servlet-name> <url-pattern>/</url-pattern> </servlet mapping>
Al acceder a un archivo e imagen HTML estática en el servidor Tomcat, realmente está accediendo a este servlet predeterminado.
5.5. Problemas de seguridad del hilo de servlet
Cuando varios clientes acceden al mismo servicio al mismo tiempo, el servidor web creará un hilo para la solicitud de acceso de cada cliente y llamará al método de servicio del servlet en este hilo. Por lo tanto, si se accede al mismo recurso en el método de servicio, puede causar problemas de seguridad de subprocesos. Por ejemplo, el siguiente código:
Código que no tiene problemas de seguridad del hilo:
paquete gacl.servlet.study; import java.io.ioException; import javax.servlet.servletException; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletRequest; import javax.servlet.http.httpservletRequest; importar; javax.servlet.http.httpServletResponse; public class ServletDemo3 extiende httpservlet {public void doget (httpservletRequest solicitud, httpservletResponse respuesta) lanza ServletException, ioexception { /*** Cuando múltiples subprocesos acceden al código en este método de manera concurrente, habrá problemas de seguridad de hilo de hilo? La variable I se accede simultáneamente por múltiples subprocesos, pero no hay un problema de seguridad de subprocesos, porque I es una variable local en el método de Doget. * Cuando múltiples subprocesos acceden al método de dietismo simultáneamente, cada hilo tiene su propia variable I, * Cada hilo opera su propia variable I, por lo que no hay un problema de seguridad de subprocesos * Cuando los múltiples hilados acceden a un cierto método de manera simultánea, si algunos recursos (variables, colecciones, etc.) se definen dentro del método * entonces cada hilo tiene estas cosas, por lo que no hay ningún problema de seguridad de hilo */ int i = 1; i ++; Response.getWriter (). Write (i); } public void dopost (httpservletRequest solicitud, respuesta httpservletreSponse) lanza ServletException, ioexception {doget (solicitud, respuesta); }} Código con problemas de seguridad del hilo:
paquete gacl.servlet.study; import java.io.ioException; import javax.servlet.servletException; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletRequest; import javax.servlet.http.httservletResponse; Httpservlet {int i = 1; public void doget (HTTPServletRequest Solicitud, respuesta httpservletResponse) lanza ServLetException, ioException {i ++; intente {thread.sleep (1000*4); } catch (InterruptedException e) {E.PrintStackTrace (); } respuesta.getWriter (). Write (i+""); } public void dopost (httpservletRequest solicitud, respuesta httpservletreSponse) lanza ServletException, ioexception {doget (solicitud, respuesta); }}Definir i como una variable global. Cuando múltiples subprocesos de acceso a la variable I simultáneamente, habrá problemas de seguridad de hilos, como se muestra en la figura a continuación: enciende dos navegadores al mismo tiempo para simular el acceso concurrente al mismo servlet. Normalmente, el primer navegador debe ver 2, y el segundo navegador debe ver 3, pero ambos navegadores ven 3, lo cual no es normal.
Los problemas de seguridad de los subprocesos solo existen cuando múltiples subprocesos operan el mismo recurso al mismo tiempo. Por lo tanto, al escribir un servlet, si se accede a un cierto recurso (variable, colección, etc.) simultáneamente, habrá problemas de seguridad de hilos. Entonces, ¿cómo resolver este problema?
Echemos un vistazo al siguiente código:
paquete gacl.servlet.study; import java.io.ioException; import javax.servlet.servletException; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletRequest; import javax.servlet.http.httservletResponse; Httpservlet {int i = 1; Public void doget (httpservletrequest solicitud, respuesta httpservletResponse) arroja servletException, ioexception { /*** Después de que se agrega sincronizado, no hay problema de seguridad de subprocesos cuando el acceso concurrente a i. * ¿Por qué no hay problema de seguridad de hilo después de agregar sincronizado? * Si hay un hilo que accede al objeto Servlet ahora, primero obtendrá el bloqueo del objeto Servlet* Después de que se ejecute, devolverá el bloqueo al objeto Servlet. Como primero obtiene el bloqueo del objeto Servlet, * por lo que cuando otro hilo accede al objeto Servlet, ya que el hilo anterior ha eliminado el bloqueo, el hilo posterior solo puede esperar en la línea * */sincronizado (esto) {// en Java, cada objeto tiene un bloqueo, y esto aquí se refiere al objeto del servlete I ++; intente {thread.sleep (1000*4); } catch (InterruptedException e) {E.PrintStackTrace (); } respuesta.getWriter (). Write (i+""); }} public void dopost (httpservletRequest solicitud, respuesta httpservletResponse) arroja servletException, ioexception {doget (solicitud, respuesta); }}Ahora, este enfoque es agregar un bloqueo al objeto Servlet, asegurando que solo un hilo acceda a los recursos en el objeto Servlet en cualquier momento, por lo que no habrá problemas de seguridad de subprocesos, como se muestra en la figura a continuación:
Aunque este enfoque resuelve problemas de seguridad de los subprocesos, los servlets de escritura no deben manejar los problemas de seguridad de los subprocesos de esta manera. Si 9999 personas acceden al servlet al mismo tiempo, entonces estas 9999 personas deben hacer cola para acceder en secuencia.
En respuesta al problema de seguridad del hilo de los servlets, Sun proporciona una solución: deje que el servlet implementa una interfaz SinglethreadModel. Si un servlet implementa la interfaz SinglethreadModel, el motor Servlet llamará a su método de servicio en modo de subproceso único.
Mirando la API Sevlet, puede ver que la interfaz SinglethreadModel no define ningún método o constante. En Java, una interfaz que no defina ningún método o constante se llama interfaz de etiqueta. Una de las interfaces de etiqueta más típicas que a menudo ves es "serializable". Esta interfaz tampoco define ningún método o constante. ¿Cuál es el uso de interfaces de etiqueta en Java? La función principal es marcar un objeto y decirle a JVM qué puede hacer este objeto. Por ejemplo, el objeto de la clase que implementa la interfaz "serializable" puede ser serializada, y también hay una interfaz "clonable", que también es una interfaz de etiqueta. Por defecto, los objetos en Java no pueden clonarse, al igual que las personas en la vida real, no se permite la clonación, pero mientras se implementa la interfaz "clonable", el objeto se puede clonar.
Deje que el servlet implementa la interfaz SinglethreadModel, simplemente agregue la declaración para implementar la interfaz SinglethreadModel a la definición de la clase Servlet.
Para los servlets que implementan la interfaz SinglethreadModel, el motor Servlet todavía admite el acceso concurrente múltiple al servlet. El método es generar múltiples objetos de instancia de servlet, y cada subproceso concurrente llama a un objeto de instancia de servlet independiente por separado.
La implementación de la interfaz SinglethreadModel no puede resolver realmente el problema de seguridad de los subprocesos de los servlets, porque el motor Servlet creará múltiples objetos de instancia de servlet, y realmente resolver el problema de seguridad de múltiples subprocesos se refiere al problema de que un objeto de instancia de servlet se llama por múltiples hilos al mismo tiempo. De hecho, en Servlet API 2.4, SinglethreadModel se ha marcado como desapercibido (anticuado).
Lo anterior se trata de este artículo, espero que sea útil para el aprendizaje de todos.