1. Introdução ao servlet
O Servlet é uma tecnologia fornecida pela Sun Company para o desenvolvimento de recursos dinâmicos da Web.
A Sun fornece uma interface de servlet em sua API. Se os usuários desejam enviar um recurso dinâmico da Web (ou seja, desenvolver um programa Java para produzir dados para o navegador), eles precisam concluir as duas etapas a seguir:
1. Escreva uma classe Java para implementar a interface do servlet.
2. Implante as classes Java desenvolvidas no servidor da web.
De acordo com um hábito de nome convencional, geralmente chamamos os programas Java que implementam o servlet da interface do servlet.
2. O processo de operação do servlet
O programa Servlet é chamado pelo servidor da web. Depois que o servidor da web recebe a solicitação de acesso do servlet do cliente:
①O servidor da web verifica primeiro se foi carregado e criou um objeto de instância do servlet. Nesse caso, execute a Etapa 4 diretamente; Caso contrário, execute a etapa 2.
② Carregue e crie um objeto de instância do servlet.
③Call o método init () do objeto da instância do servlet.
④ Crie um objeto HttpServletRequest para encapsular mensagens de solicitação HTTP e um objeto HttpServletResponse que representa mensagens de resposta HTTP e, em seguida, ligue para o método Servet's Service () e passe os objetos de solicitação e resposta como parâmetros.
⑤ Antes de o aplicativo da Web ser interrompido ou reiniciado, o mecanismo de servlet desinstala o servlet e chama o método Destroy () do servlet antes de desinstalar.
3. Diagrama de chamada servlet
4. Desenvolva servlet no eclipse
Crie um novo projeto da Web no Eclipse, e o Eclipse criará automaticamente a estrutura de diretório mostrada na figura abaixo:
4.1. Classe de implementação da interface do servlet
A empresa Sun Interface Sun define duas classes de implementação padrão, a saber: GenericServlet e HttpServlet.
O HTTPSERVLET refere -se a um servlet que pode lidar com solicitações HTTP. Ele adiciona alguns métodos de processamento de protocolo HTTP à interface original do servlet, que é mais poderosa que a interface do servlet. Portanto, ao escrever servlets, os desenvolvedores geralmente devem herdar esta classe e evitar a implementação diretamente da interface do servlet.
Quando o HTTPServlet implementa a interface do servlet, ele substitui o método de serviço. O código no corpo do método determinará automaticamente o método de solicitação do usuário. Se for uma solicitação GET, o método do Doget de HttpServlet é chamado. Se for uma solicitação de postagem, o método dopost será chamado. Portanto, ao escrever servlets, os desenvolvedores geralmente só precisam substituir o método doget ou dopost, em vez de substituir o método de serviço.
4.2. Crie e escreva servlets através do Eclipse
Selecione o pacote gacl.servlet.study, clique com o botão direito do mouse → novo → Servlet, como mostrado na figura abaixo:
Dessa forma, usaremos o Eclipse para nos ajudar a criar um servlet com o nome ServletDemo1. Haverá o seguinte código no servletDemo01 criado:
pacote gacl.servlet.study; importar java.io.ioexception; importar java.io.printwriter; importar javax.servlet.servletexception; importar javax.servlet.http.httpSletLe; import javax.servlet.http.httlestlest; javax.servlet.http.httpServletResponse; classe pública servletDemo1 estende httpServlet { /*** o método doget do servlet. <br> * * Este método é chamado quando um formulário possui seu método de valor de tag é igual a obter. * * @param solicitação A solicitação enviada pelo cliente para o servidor * @param Resposta A resposta enviada pelo servidor para o cliente * @throws servletexception Se ocorreu um erro * @THOWSows IoException Se ocorreu um erro */ public void Doget (httpServleTeQuest Solicy, httpsletResponse Response) Throwsceptionception, Ioxception (IOxception (iOx. Response.setContentType ("Text/html"); PrintWriter out = Response.getWriter (); out.println ("<! doctype html public/"-// w3c // dtd html 4.01 transitório // en/">"); out.println ("<head> <title> um servlet </ititle> </ad Head>"); out.println ("<body>"); out.print ("This Is"); out.print (this.getClass ()); out.println (", usando o método get"); out.println ("</body>"); out.println ("</html>"); out.flush (); out.Close (); } /*** O método dopost do servlet. <br> * * Este método é chamado quando um formulário possui seu método de valor de tag é igual a postar. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Response.setContentType ("Text/html"); PrintWriter out = Response.getWriter (); out.println ("<! doctype html public/"-// w3c // dtd html 4.01 transitório // en/">"); out.println ("<html>"); out.println ("<head> <title> um servlet </ititle> </ad Head>"); out.println ("<body>"); out.println ("<body>"); out.println ("isto é"); out.print (this.getClass ()); out.println (", usando o método post"); out.println ("</body>"); out.println ("</html>"); out.flush (); out.Close (); }}Esses códigos são gerados automaticamente pelo Eclipse, e existem dois pares de tags no arquivo web.xml, <Verlet> </servlet> e <Verlet-Mapping> </Servlet-Mapping>. Esses dois pares de tags são configurados com servletDemo1, conforme mostrado na figura abaixo:
Em seguida, podemos acessar o servlet servletDemo1 através do navegador, conforme mostrado na figura abaixo:
5. Preste atenção aos detalhes no desenvolvimento de servlet
5.1. Configuração de mapeamento de URL de acesso para servlet
Como o cliente acessa recursos no servidor da Web por meio de um endereço de URL, se o programa Servlet quiser ser acessado pelo mundo exterior, ele deverá mapear o programa do servlet para um endereço de URL. Este trabalho é realizado no arquivo web.xml usando o elemento <Servlet> e <ervlet-mapping>.
O elemento <Verlet> é usado para registrar um servlet. Ele contém dois elementos filhos principais: <ame-name> e <vlett-class>, que são usados para definir o nome do registro do servlet e o nome completo da classe do servlet, respectivamente.
Um elemento <Servlet-Mapping> é usado para mapear um caminho de acesso externo para um servlet registrado. Ele contém dois elementos filhos: <ame-name> e <url-padrão>, que são usados para especificar o nome do registro do servlet e o caminho de acesso externo do servlet. Por exemplo:
</servlet> <Verlet-name> servletDemo1 </servlet-name> <Servlet-class> gacl.servlet.study.servletdemo1 </servlet-class> </servlet> <url-patning> <ervlet-name> servletDemo1 </-servlet> <url-patntern>/servlet> servletdemo1 </-) O mesmo servlet pode ser mapeado para vários URLs, ou seja, o valor de configuração do elemento filho <nome da servlet> de vários elementos <Vapping-mapping> pode ser o nome de registro do mesmo servlet. Por exemplo: </servlet> <Servlet-name> servletDemo1 </vetlet-name> <Servlet-class> gacl.servlet.study.servletdemo1 </servlet-class> </servlet> <Verlet-Mapping> <Vopor-Mapping> </servlet-name> servletDemo1 <//Name> <url-pattern>/servlet/servletDemo1 </url-tattern> </servlet-mapping> <Servlet-mapping> <Servlet-name> servletDemo1 </ervlet-name> <url-Pattern> /1.htm </url-tattern> </servlet> <let-Name-klet-Name> <let-name-kletnam-let-Name> <LeverNeNk-Name> <Levern1T-Name> <Levern1T-Name> <LeverNeNk-Name> <LeverNeNk-Name> <LeverNken-Nlet-Name> <Let-Name> <Let-Name> <Let-Name> <Let-Name> <Let-Name> <Let-Name> <letnet-Name> <letnet-Name> <Lever-Name> <Let-Name> <Let-Name> <url-Pattern> /2.jsp </url-pattern> </servlet-mapping> <Servlet-Mapping> <Servlet-Mapping> <Vertlet-Name> servletDemo1 </servlet-name <url Serl-Pattern> /3.php </url-tattern> </servlet> <ervlet-MapTapTn> <url-pattern> /4.aspx </url-tattern> </servlet-mapping>
Através da configuração acima, quando queremos acessar um servlet com o nome ServletDemo1, podemos usar os seguintes endereços para acessar:
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 é mapeado para vários URLs.
5.2. Use * mapeamento curinga para URLs de acesso a servlet
O caráter curinga também pode ser usado nos URLs nos quais o servlet mapas, mas só pode haver dois formatos fixos: um é a "*. Extensão", e o outro é o início com uma barra para frente (/) e terminando com um "/*". Por exemplo:
<Verlet> <Verlet-name> servletdemo1 </vletname> <Servlet-class-Class> gacl.servlet.study.servletdemo1 </servlet-class> </servlet> <url-mapping> <sutlet-name> servletdemo1 </servirname> <url-Pattern>/*/url-Pattern> </url-Pattern> </url-Pattern> </url-Pattern> </url-Pattern> </url-Pattern> </url-tattern> </ar Servlet> </servlet> <vattern> </url-patnattern> </irtlet-name> servletdemo1 </servlet>
*Ele pode corresponder a qualquer caractere, para que você possa usar qualquer URL para acessar o servlet de servletDemo1, conforme mostrado na figura abaixo:
Para alguns relacionamentos de mapeamento abaixo:
Servlet1 mapeia para /abc /*
Servlet2 mapeia para /*
Servlet3 mapeia para /abc
Servlet4 mapeia para *.do
pergunta:
Quando o URL da solicitação é "/abc/a.html", "/abc/*" e "/*", ambos correspondem, que o servlet responde ao mecanismo do servlet chamará o servlet1.
Quando o URL da solicitação é "/ABC", ambos "/ABC/*" e "/ABC", que o servlet responde ao mecanismo do servlet chamará o servlet3.
Quando o URL da solicitação é "/abc/a.do", ambos "/abc/*" e "*.do", que o servlet responde ao mecanismo do servlet chamará o servlet1.
Quando o URL da solicitação for "/A.DO", ambos "/*" e "*.do", que o servlet responde ao mecanismo do servlet ligará para o servlet2.
Quando o URL da solicitação for "/xxx/yyy/a.do", ambos "/*" e "*.do", que o servlet responde ao servlet mecanismo chamará o servlet2.
O princípio da correspondência é "quem se parece mais com quem encontrará quem parece mais"
5.3. A diferença entre as classes de servlet e java comum
Servlet é uma classe Java para chamada por outros programas Java (Motores Servlet). Ele não pode funcionar de forma independente e sua operação é completamente controlada e agendada pelo mecanismo de servlet.
Para várias solicitações de servlet do cliente, geralmente o servidor criará apenas um objeto de instância do servlet. Ou seja, uma vez que o objeto da instância do servlet for criado, ele residirá na memória e atenderá a outras solicitações subsequentes. O objeto da instância do servlet não será destruído até que o contêiner da web saia.
Durante toda a vida de um servlet, o método init do servlet é chamado apenas uma vez. Cada solicitação de acesso a um servlet faz com que o mecanismo do servlet ligue para o método do serviço de servlet uma vez. Para cada solicitação de acesso, o mecanismo do servlet criará um novo objeto de solicitação HTTPSERVletRequest e um novo objeto de resposta HTTPSERVletResponse e, em seguida, passará esses dois objetos como parâmetros para o método Service () do servlet que ele chama. O método de serviço chama o método Doxxx de acordo com o método de solicitação.
Se um elemento <adar load-on-startup> estiver configurado no elemento <Verlet>, quando o aplicativo da Web iniciar, ele carregará e criará o objeto da instância do servlet e chamará o método init () do objeto da instância do servlet.
Por exemplo:
<Verlet> <Verlet-name> Invocador </vlect-name> <Servlet-class> org.apache.catalina.servlets.invokerServlet </servlet-class> <adound-on-startup> 1 </olload-on-startup> </ervlet>
Objetivo: Escreva um InitServlet para o aplicativo da web. Este servlet está configurado para carregar na inicialização para criar as tabelas e dados necessários do banco de dados para todo o aplicativo da Web.
5.4. Servlet padrão
Se o caminho de mapeamento de um servlet for apenas uma barra para a frente (/), esse servlet se tornará o servlet padrão do aplicativo Web atual.
Qualquer URL do elemento correspondente <Servlet-mapping> que não pode ser encontrado no arquivo web.xml, suas solicitações de acesso serão entregues ao servlet padrão para processamento, ou seja, o servlet padrão é usado para lidar com solicitações de acesso que não são processadas por outros servlets. Por exemplo:
<Verlet> <Verlet-name> servletdemo2 </vletname> <Servlet-class-Class> gacl.servlet.study.servletdemo2 </servlet-class> <adound-on-startup> 1 </load-on-startup> </servlet> <!-configure servletemo2 como defaultlet- <Verlet-name> servletDemo2 </ervlet-name> <url-tattern>/</url-tattern> </servlet-mapping>
Ao acessar um servlet inexistente, o servlet padrão configurado é usado para processamento, conforme mostrado na figura abaixo:
No <TomCat Instalation Directory> /conf/web.xml, um servlet chamado org.apache.catalina.servlets.defaultServlet está registrado e este servlet é definido como o servlet padrão.
<Verlet> <Verlet-name> padrão </servlet-name> <Servlet-class> org.apache.catalina.servlets.defaultServlet </servlet-class> <iit-param> <ininte> Debug </param-name> <aam-value> 0 </param-value> </iret-Param> </param-name> <aam-value> 0 </param-value> <otinte> <amam-value> false </param-value> </irit-param> <adarble-on-startup> 1 </load-on-startup> </servlet> <!-o mapeamento para o servlet padrão-> <sutlet-mapping> <ar Servlet-name> padrão </servlet-name> <url-tattern>/<//</url-PLATTN>
Ao acessar um arquivo e imagem HTML estática no servidor Tomcat, você está realmente acessando esse servlet padrão.
5.5. Problemas de segurança do tópico de servlet
Quando vários clientes acessarem o mesmo servlet simultaneamente, o servidor da Web cria um thread para a solicitação de acesso de cada cliente e chama o método de serviço do servlet neste thread. Portanto, se o mesmo recurso for acessado no método de serviço, poderá causar problemas de segurança de threads. Por exemplo, o seguinte código:
Código que não possui problemas de segurança de threads:
package 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;import javax.servlet.http.httpServletResponse; classe pública servletDemo3 estende httpServlet {public void Doget (httpServletRequest Solicy, httpServletResponse Response) lança o horário de ser servidor, que a concepção de servException {** *** quando múltiplos linhas de segurança) lança o código da servidor, o número da concepção de servleTurException {** *** quando múltiplos A variável I é acessada simultaneamente por vários threads, mas não há problema de segurança de threads, porque eu é uma variável local no método Doget. * Quando vários threads acessam o método Doget simultaneamente, cada thread possui sua própria variável I, * cada thread opera sua própria variável I, para que não haja problema de segurança de thread * quando os vários threads acessam um determinado método simultaneamente, se alguns recursos (variáveis, coleções, etc.) são definidos dentro do método *, então todos os thread têm essas coisas, portanto, não houver um problema de segurança */ INT i/ INT i; i ++; resposta.getWriter (). Write (i); } public void DoPost (solicitação httpServletRequest, httpServletResponse resposta) lança servletexception, ioexception {doget (solicitação, resposta); }} Código com problemas de segurança de thread:
pacote gacl.servlet.study; importar java.io.ioException; importar javax.servlet.servletexception; importar javax.servlet.http.httpServlet; import javax.servlet.htttp.httpsletrequest; javax.servlet.Servlet.htttp.htttpsletrequest; javax.servlet.Servlet.httlet.http.htttServLetReRestlet; estende HttpServlet {int i = 1; Public void Doget (solicitação httpServletRequest, httpServletResponse Response) lança servletexception, ioexception {i ++; tente {thread.sleep (1000*4); } catch (interruptedException e) {e.printStackTrace (); } Response.getWriter (). Write (i+""); } public void DoPost (solicitação httpServletRequest, httpServletResponse resposta) lança servletexception, ioexception {doget (solicitação, resposta); }}Defina I como uma variável global. Quando vários threads acessam a variável I simultaneamente, haverá problemas de segurança de threads, como mostrado na figura abaixo: ligue dois navegadores ao mesmo tempo para simular o acesso simultâneo ao mesmo servlet. Normalmente, o primeiro navegador deve ver 2, e o segundo navegador deve ver 3, mas os dois navegadores veem 3, o que não é normal.
Os problemas de segurança do thread existem apenas quando vários threads operam o mesmo recurso simultaneamente. Portanto, ao escrever um servlet, se um determinado recurso (variável, coleção etc.) for acessado simultaneamente, haverá problemas de segurança de threads. Então, como resolver esse problema?
Vamos dar uma olhada no seguinte código:
pacote gacl.servlet.study; importar java.io.ioException; importar javax.servlet.servletexception; importar javax.servlet.http.httpServlet; import javax.servlet.htttp.httpsletrequest; javax.servlet.Servlet.htttp.htttpsletrequest; javax.servlet.Servlet.httlet.http.htttServLetReRestlet; estende HttpServlet {int i = 1; Public void Doget (solicitação httpServletRequest, resposta httpServletResponse) lança servletexception, ioexception { /*** após a adição de sincronizado, não há problema de segurança de thread quando o acesso simultâneo a i. * Por que não há problema de segurança de thread após a adição sincronizada? * Se houver um thread que acesse o objeto Servlet agora, ele primeiro receberá o bloqueio do objeto do servlet* depois que ele for executado, retornará o bloqueio ao objeto Servlet. Como ele primeiro recebe o bloqueio do objeto servlet, * então, quando outro thread acessa o objeto Servlet, uma vez que o bloqueio foi retirado pelo thread anterior, o encadeamento subsequente só pode esperar na linha * */sincronizado (this) {// em java, cada objeto tem um bloqueio, e isso aqui se refere ao objeto servlet i ++; tente {thread.sleep (1000*4); } catch (interruptedException e) {e.printStackTrace (); } Response.getWriter (). Write (i+""); }} public void DoPost (solicitação httpServletRequest, httpServletResponse resposta) lança servletexception, ioexception {doget (solicitação, resposta); }}Agora, essa abordagem é adicionar um bloqueio ao objeto Servlet, garantindo que apenas um thread esteja acessando os recursos no objeto do servlet a qualquer momento, para que não haja problemas de segurança de thread, como mostrado na figura abaixo:
Embora essa abordagem resolva problemas de segurança de threads, a redação de servlets não deve lidar com problemas de segurança de threads dessa maneira. Se 9999 pessoas acessarem o servlet ao mesmo tempo, essas 9999 pessoas devem fazer fila para acessar em sequência.
Em resposta ao problema de segurança dos threads dos servlets, a Sun fornece uma solução: deixe o servlet implementar uma interface SingleThreadModel. Se um servlet implementar a interface SingleThReadModel, o mecanismo do servlet chamará seu método de serviço no modo de tiro único.
Olhando para a API do SEVLET, você pode ver que a interface SingleThreadModel não define nenhum método ou constante. Em Java, uma interface que não define quaisquer métodos ou constantes é chamada de interface de tag. Uma das interfaces de tags mais típicas que você costuma ver é "serializável". Essa interface também não define nenhum método ou constante. Qual é o uso de interfaces de tags em Java? A principal função é marcar um objeto e informar à JVM o que esse objeto pode fazer. Por exemplo, o objeto da classe que implementa a interface "serializável" pode ser serializada e também há uma interface "clonável", que também é uma interface de tag. Por padrão, os objetos em Java não podem ser clonados, assim como as pessoas na vida real, a clonagem não é permitida, mas enquanto a interface "clonável" for implementada, o objeto poderá ser clonado.
Deixe o servlet implementar a interface SingleThreadModel, basta adicionar a declaração para implementar a interface SingleThreadModel à definição da classe Servlet.
Para servlets que implementam a interface SingleThreadModel, o mecanismo de servlet ainda suporta acesso simultâneo com vários thread ao servlet. O método é gerar vários objetos de instância do servlet e cada encadeamento simultâneo chama um objeto de instância de servlet independente separadamente.
A implementação da interface SingleThReadModel não pode realmente resolver o problema de segurança dos threads dos servlets, porque o mecanismo de servlet criará vários objetos de instância do servlet e realmente resolvendo o problema de segurança de vários thread refere-se ao problema que um objeto de instância do servlet é chamado por vários threads ao mesmo tempo. De fato, na API do servlet 2.4, o SingleThReadModel foi marcado como depreciado (desatualizado).
O exposto acima é tudo sobre este artigo, espero que seja útil para o aprendizado de todos.