1. 概述

Java EE注解通过让开发者声明组件在容器中的行为方式,极大简化了开发工作。这些注解是XML描述符的现代替代方案,能显著减少样板代码。

本文将聚焦Java EE 7中Servlet API 3.1引入的注解,深入探讨它们的作用和实际用法。

2. Web注解一览

Servlet API 3.1引入了一套可在Servlet类中使用的新注解类型:

  • @WebServlet
  • @WebInitParam
  • @WebFilter
  • @WebListener
  • @ServletSecurity
  • @HttpConstraint
  • @HttpMethodConstraint
  • @MultipartConfig

接下来我们将逐一详解这些注解。

3. @WebServlet

简单来说,这个注解能将Java类声明为Servlet:

@WebServlet("/account")
public class AccountServlet extends javax.servlet.http.HttpServlet {
    
    public void doGet(HttpServletRequest request, HttpServletResponse response) 
      throws IOException {
        // ...
    }
 
    public void doPost(HttpServletRequest request, HttpServletResponse response) 
      throws IOException {
        // ...
    }
}

3.1. @WebServlet属性详解

@WebServlet提供多个属性用于定制Servlet:

  • name
  • description
  • urlPatterns
  • initParams

使用示例:

@WebServlet(
  name = "BankAccountServlet", 
  description = "Represents a Bank Account and it's transactions", 
  urlPatterns = {"/account", "/bankAccount" }, 
  initParams = { @WebInitParam(name = "type", value = "savings")})
public class AccountServlet extends javax.servlet.http.HttpServlet {

    String accountType = null;

    public void init(ServletConfig config) throws ServletException {
        // ...
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) 
      throws IOException {
        // ... 
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) 
      throws IOException {
        // ...  
    }
}

name属性会覆盖默认的Servlet名称(默认为全限定类名)。description属性用于描述Servlet功能。urlPatterns指定Servlet可访问的URL(支持多值配置)。

4. @WebInitParam

该注解配合@WebServletinitParams属性使用,用于设置Servlet初始化参数。

示例中设置初始化参数type值为savings

@WebServlet(
  name = "BankAccountServlet", 
  description = "Represents a Bank Account and it's transactions", 
  urlPatterns = {"/account", "/bankAccount" }, 
  initParams = { @WebInitParam(name = "type", value = "savings")})
public class AccountServlet extends javax.servlet.http.HttpServlet {

    String accountType = null;

    public void init(ServletConfig config) throws ServletException {
        accountType = config.getInitParameter("type");
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) 
      throws IOException {
        // ...
    }
}

5. @WebFilter

当需要在不修改Servlet内部逻辑的情况下拦截请求和响应时,@WebFilter就是最佳选择。通过URL模式可将过滤器关联到特定Servlet或静态资源组。

示例使用@WebFilter将未授权访问重定向到登录页:

@WebFilter(
  urlPatterns = "/account/*",
  filterName = "LoggingFilter",
  description = "Filter all account transaction URLs")
public class LogInFilter implements javax.servlet.Filter {
    
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    public void doFilter(
        ServletRequest request, ServletResponse response, FilterChain chain) 
          throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;

        res.sendRedirect(req.getContextPath() + "/login.jsp");
        chain.doFilter(request, response);
    }

    public void destroy() {
    }

}

6. @WebListener

若需监控Servlet及其请求的初始化和变更过程,@WebListener注解就能派上用场。

编写Web监听器需实现以下接口之一:

  • ServletContextListener – 监听ServletContext生命周期
  • ServletContextAttributeListener – 监听ServletContext属性变更
  • ServletRequestListener – 监听资源请求
  • ServletRequestAttributeListener – 监听ServletRequest属性变更
  • HttpSessionListener – 监听会话创建和销毁
  • HttpSessionAttributeListener – 监听会话属性变更

示例展示如何使用ServletContextListener配置Web应用:

@WebListener
public class BankAppServletContextListener 
  implements ServletContextListener {

    public void contextInitialized(ServletContextEvent sce) { 
        sce.getServletContext().setAttribute("ATTR_DEFAULT_LANGUAGE", "english"); 
    } 
    
    public void contextDestroyed(ServletContextEvent sce) { 
        // ... 
    } 
}

7. @ServletSecurity

需要为Servlet指定安全模型(包括角色、访问控制和认证要求)时,使用@ServletSecurity注解。

示例限制AccountServlet的访问权限:

@WebServlet(
  name = "BankAccountServlet", 
  description = "Represents a Bank Account and it's transactions", 
  urlPatterns = {"/account", "/bankAccount" }, 
  initParams = { @WebInitParam(name = "type", value = "savings")})
@ServletSecurity(
  value = @HttpConstraint(rolesAllowed = {"Member"}),
  httpMethodConstraints = {@HttpMethodConstraint(value = "POST", rolesAllowed = {"Admin"})})
public class AccountServlet extends javax.servlet.http.HttpServlet {

    String accountType = null;

    public void init(ServletConfig config) throws ServletException {
        // ...
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) 
      throws IOException {
       // ...
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) 
      throws IOException {        
        double accountBalance = 1000d;

        String paramDepositAmt = request.getParameter("dep");
        double depositAmt = Double.parseDouble(paramDepositAmt);
        accountBalance = accountBalance + depositAmt;

        PrintWriter writer = response.getWriter();
        writer.println("<html> Balance of " + accountType + " account is: " + accountBalance 
        + "</html>");
        writer.flush();
    }
}

调用AccountServlet时,浏览器会弹出登录界面要求输入有效凭据。

@HttpConstraint@HttpMethodConstraint用于指定@ServletSecurityvaluehttpMethodConstraints属性值:

@HttpConstraint:适用于所有HTTP方法,指定默认安全约束

  • value
  • rolesAllowed
  • transportGuarantee
  • 最常用的是rolesAllowed(示例中允许Member角色访问所有方法)

@HttpMethodConstraint:指定特定HTTP方法的安全约束

  • value
  • emptyRoleSemantic
  • rolesAllowed
  • transportGuarantee
  • 示例中限制doPost方法仅Admin角色可访问(存款功能仅管理员可用)

8. @MultipartConfig

处理multipart/form-data请求(通常用于文件上传)时,使用此注解标注Servlet。

该注解会暴露HttpServletRequestgetParts()getPart(name)方法,用于访问所有或单个文件部分。通过调用Part对象的write(fileName)可将上传文件写入磁盘。

示例UploadCustomerDocumentsServlet展示其用法:

@WebServlet(urlPatterns = { "/uploadCustDocs" })
@MultipartConfig(
  fileSizeThreshold = 1024 * 1024 * 20,
  maxFileSize = 1024 * 1024 * 20,
  maxRequestSize = 1024 * 1024 * 25,
  location = "./custDocs")
public class UploadCustomerDocumentsServlet extends HttpServlet {

    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
      throws ServletException, IOException {
        for (Part part : request.getParts()) {
            part.write("myFile");
        }
    }

}

@MultipartConfig包含四个属性:

  • fileSizeThreshold – 文件大小阈值(字节),超过则存磁盘,否则存内存
  • maxFileSize – 单个文件最大大小(字节)
  • maxRequestSize – 整个请求最大大小(字节,含文件和表单数据)
  • location – 文件存储目录

9. 总结

本文深入探讨了Servlet API 3.1引入的Java EE注解及其作用与用法。这些注解能显著简化Web开发,减少配置负担。

⚠️ 实际开发中需注意:

  • 注解虽简化配置,但复杂场景仍需XML配合
  • 安全相关注解需与容器安全策略协同工作
  • 文件上传参数需根据实际需求合理设置

相关源码可在GitHub获取。


原始标题:A Guide to Java EE Web-Related Annotations