使用JSP 2避免JSP文件中的Java代码

使用JSP 2避免JSP文件中的Java代码

编码文章call10242025-05-02 16:50:468A+A-

技术背景

在早期的JSP开发中,使用脚本片段(<% %><%! %><%= %>)嵌入Java代码是常见做法,但这种方式存在诸多弊端。随着JSP 2的出现,标签库(如JSTL)和表达式语言(EL)等技术逐渐成熟,使得避免在JSP文件中直接使用Java代码成为可能。

脚本片段的缺点

  • 可复用性差:脚本片段无法复用。
  • 可替换性差:无法将脚本片段抽象化。
  • 面向对象能力弱:难以利用继承和组合。
  • 调试困难:若脚本片段中途抛出异常,页面将显示空白。
  • 可测试性差:脚本片段无法进行单元测试。
  • 维护成本高:混合、杂乱和重复的代码逻辑需要更多时间维护。

实现步骤

1. 定义过滤器处理通用逻辑

若要在每个请求中调用相同的Java代码(如检查用户是否登录),可实现一个过滤器,并在doFilter()方法中编写相应代码。

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class LoginFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        if (((HttpServletRequest) request).getSession().getAttribute("user") == null) {
            ((HttpServletResponse) response).sendRedirect("login"); 
        } else {
            chain.doFilter(request, response); 
        }
    }
}

web.xml中配置过滤器:

<filter>
    <filter-name>LoginFilter</filter-name>
    <filter-class>com.example.LoginFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>LoginFilter</filter-name>
    <url-pattern>*.jsp</url-pattern>
</filter-mapping>

2. 使用Servlet处理GET请求

若要调用Java代码处理GET请求(如从数据库预加载列表以在表格中显示),可实现一个Servlet,并在doGet()方法中编写相应代码。

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;

@WebServlet("/products")
public class ProductServlet extends HttpServlet {
    private ProductService productService = new ProductService();

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            List<Product> products = productService.list();
            request.setAttribute("products", products);
            request.getRequestDispatcher("/WEB-INF/products.jsp").forward(request, response);
        } catch (SQLException e) {
            throw new ServletException("Retrieving products failed!", e);
        }
    }
}

3. 使用Servlet处理POST请求

若要调用Java代码处理POST请求(如收集表单数据并进行业务处理),可实现一个Servlet,并在doPost()方法中编写相应代码。

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    private UserService userService = new UserService();

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        User user = userService.find(username, password);

        if (user != null) {
            request.getSession().setAttribute("user", user);
            response.sendRedirect("home");
        } else {
            request.setAttribute("message", "Unknown username/password. Please retry.");
            request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);
        }
    }
}

4. 使用MVC的前端控制器模式

若要调用Java代码控制请求和响应的执行计划和目标,可根据MVC的前端控制器模式实现一个Servlet。

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class FrontControllerServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            Action action = ActionFactory.getAction(request);
            String view = action.execute(request, response);

            if (view.equals(request.getPathInfo().substring(1))) {
                request.getRequestDispatcher("/WEB-INF/" + view + ".jsp").forward(request, response);
            } else {
                response.sendRedirect(view);
            }
        } catch (Exception e) {
            throw new ServletException("Executing action failed.", e);
        }
    }
}

5. 使用JSTL控制JSP页面流程

若要调用Java代码控制JSP页面内的流程,可使用JSTL核心标签库。

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<table>
    <c:forEach items="${products}" var="product">
        <tr>
            <td>${product.name}</td>
            <td>${product.description}</td>
            <td>${product.price}</td>
        </tr>
    </c:forEach>
</table>

6. 使用EL表达式访问和显示数据

若要调用Java代码访问和显示JSP页面内的“后端”数据,可使用EL表达式。

<input type="text" name="foo" value="${param.foo}" />

7. 使用EL函数调用实用Java代码

若要在JSP页面中直接调用实用Java代码(通常是公共静态方法),可将其定义为EL函数。

<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<input type="text" name="foo" value="${fn:escapeXml(param.foo)}" />

最佳实践

  • 遵循MVC模式:将业务逻辑与表示逻辑分离,JSP作为视图层,专注于页面展示。
  • 使用标签库和EL表达式:尽量使用JSTL标签库和EL表达式替代脚本片段。
  • 禁用脚本片段:在web.xml中添加以下配置,防止开发者使用脚本片段。
<jsp-config>
    <jsp-property-group>
        <url-pattern>*.jsp</url-pattern>
        <scripting-invalid>true</scripting-invalid>
    </jsp-property-group>
</jsp-config>

常见问题

1. 如何处理不遵循getter/setter模式的Java类?

可将这些类包装在自己的JavaBean类中并使用。

2. 使用JSP替代技术有哪些缺点?

  • 学习成本:如JSF、Wicket等框架需要学习新的API和概念。
  • 性能问题:某些框架可能会带来额外的性能开销。
  • 复杂度:框架可能会增加项目的复杂度。

3. 能否完全避免在JSP中使用Java代码?

理论上可以,但实际开发中可能需要根据具体情况进行权衡。一些特殊情况(如临时计算、特定页面的修复)可能仍需要少量Java代码。

点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4