Hoje vamos analisar a Exceção e o Tratamento de Erro no Servlet. Algum tempo atrás, escrevi um post sobre o Tratamento de Exceções em Java, mas quando se trata de aplicativos da web, precisamos de mais do que um tratamento de exceção normal em Java.
Exceção Servlet
Se você observar, os métodos doGet() e doPost() lançam javax.servlet.ServletException
e IOException
. Vamos ver o que acontece quando lançamos essas exceções em nossa aplicação. Escreverei um servlet simples que lançará a ServletException.
package com.journaldev.servlet.exception;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/MyExceptionServlet")
public class MyExceptionServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
throw new ServletException("GET method is not supported.");
}
}
Agora, quando invocamos este servlet pelo navegador com o método GET, obtemos uma resposta como a imagem abaixo. Como o navegador entende apenas HTML, quando nossa aplicação lança uma exceção, o contêiner do servlet processa a exceção e gera uma resposta HTML. Essa lógica é específica para o contêiner do servlet. Estou usando o Tomcat e obtendo esta página de erro. Se você usar outros servidores como JBoss ou Glassfish, pode obter uma resposta HTML de erro diferente. O problema com esta resposta é que não tem valor para o usuário. Além disso, está mostrando as classes de nossa aplicação e detalhes do servidor para o usuário, o que não faz sentido para o usuário e não é bom do ponto de vista da segurança.
Erro do Servlet
I am sure you must have seen 404 error when you are trying to hit a URL that doesn’t exists. Let’s see how our servlet container responds to 404 error. If we send request for an invalid URL, we get response HTML like below image. Again it’s a generic HTML generated by server on our application behalf and hold little to no value to the user.
Exceção do Servlet e Manipulação de Erros
A API do Servlet fornece suporte para servlets de manipulação de exceções e erros personalizados que podemos configurar no descritor de implantação. O objetivo principal desses servlets é lidar com a exceção ou erro gerado pela aplicação e enviar uma resposta HTML útil ao usuário. Podemos fornecer um link para a página inicial da aplicação ou alguns detalhes para informar ao usuário o que deu errado. Então, antes de tudo, precisamos criar um servlet de manipulação de exceções e erros personalizados. Podemos ter vários servlets de manipulação de exceções e erros para a aplicação, mas para simplificar, criarei um único servlet e o usarei tanto para exceções quanto para erros. AppExceptionHandler.java
package com.journaldev.servlet.exception;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/AppExceptionHandler")
public class AppExceptionHandler extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
processError(request, response);
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
processError(request, response);
}
private void processError(HttpServletRequest request,
HttpServletResponse response) throws IOException {
// Analisar a exceção do servlet
Throwable throwable = (Throwable) request
.getAttribute("javax.servlet.error.exception");
Integer statusCode = (Integer) request
.getAttribute("javax.servlet.error.status_code");
String servletName = (String) request
.getAttribute("javax.servlet.error.servlet_name");
if (servletName == null) {
servletName = "Unknown";
}
String requestUri = (String) request
.getAttribute("javax.servlet.error.request_uri");
if (requestUri == null) {
requestUri = "Unknown";
}
// Definir tipo de conteúdo da resposta
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.write("Exception/Error Details ");
if(statusCode != 500){
out.write("Error Details
");
out.write("Status Code:"+statusCode+"
");
out.write("Requested URI:"+requestUri);
}else{
out.write("Exception Details
");
out.write("- Servlet Name:"+servletName+"
");
out.write("- Exception Name:"+throwable.getClass().getName()+"
");
out.write("- Requested URI:"+requestUri+"
");
out.write("- Exception Message:"+throwable.getMessage()+"
");
out.write("
");
}
out.write("
");
out.write("Home Page");
out.write("");
}
}
Vamos ver como podemos configurá-lo no descritor de implantação e depois entenderemos sua implementação e como funciona.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://java.sun.com/xml/ns/javaee" xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<display-name>ServletExceptionHandling</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/AppExceptionHandler</location>
</error-page>
<error-page>
<exception-type>javax.servlet.ServletException</exception-type>
<location>/AppExceptionHandler</location>
</error-page>
</web-app>
Como você pode ver, é muito fácil especificar servlets de manipulação de exceções para a aplicação usando o elemento error-page. Cada elemento error-page deve ter o elemento error-code ou exception-type. Nós definimos o servlet de manipulação de exceções no elemento location. Com base na configuração acima, se a aplicação lançar erro 404 ou ServletException, ele será tratado pelo servlet AppExceptionHandler. Quando tal exceção e cenário de erro aparece, o contêiner do servlet invocará o método HTTP correspondente do servlet de Manipulador de Exceções e passará o objeto de requisição e resposta. Note que forneci a implementação tanto do método doGet() quanto doPost() para que ele possa lidar com requisições GET e POST e usar um método comum para processá-las. Antes de o contêiner do servlet invocar o servlet para tratar a exceção, ele define alguns atributos na requisição para obter informações úteis sobre a exceção, alguns deles são javax.servlet.error.exception, javax.servlet.error.status_code, javax.servlet.error.servlet_name e javax.servlet.error.request_uri. Para exceções, o código de status é sempre 500, que corresponde ao “Erro Interno do Servidor”, para outros tipos de erro obtemos diferentes códigos de erro, como 404, 403, etc. Usando o código de status, nossa implementação apresenta diferentes tipos de resposta HTML ao usuário. Ele também fornece um hiperlink para a página inicial da aplicação. Agora, quando acessarmos nosso servlet que está lançando ServletException, obteremos uma resposta como na imagem abaixo. Se tentarmos acessar uma URL inválida que resultará em uma resposta 404, obteremos uma resposta como na imagem abaixo.
Não parece bom e ajuda o usuário a entender facilmente o que aconteceu e fornece um caminho para ir para o local correto. Ele também evita enviar informações sensíveis da aplicação para o usuário. Devemos sempre ter manipuladores de exceção em vigor para nossa aplicação web. Se você deseja lidar com exceções em tempo de execução e todas as outras exceções em um único manipulador de exceções, você pode fornecer exception-type como Throwable.
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/AppExceptionHandler</location>
</error-page>
Se houver várias entradas de página de erro, digamos uma para Throwable e outra para IOException e a aplicação lançar FileNotFoundException, então será tratada pelo manipulador de erros de IOException. Você também pode usar uma página JSP como manipulador de exceções, basta fornecer o local do arquivo jsp em vez do mapeamento de servlet. Isso é tudo para o tratamento de exceções de servlet em aplicativos da web, espero que tenha gostado.
Baixe o Projeto de Exemplo de Tratamento de Exceção de Servlet
Confira outros artigos desta série: