JSP+Servlet制作简易计算器

'# JSP+Servlet制作简易计算器

一、背景与问题

在Web开发早期,JSP(Java Server Pages)和Servlet是构建动态网站的核心技术。它们通过分离业务逻辑与展示层,实现了MVC架构的雏形。本文将以简易计算器为例,深入解析JSP与Servlet的协作机制,并探讨其在实际项目中的适用场景。

一个典型的问题场景是:用户在Web页面输入两个数字和运算符,需要在服务器端完成计算并返回结果。这种需求虽然简单,却能体现JSP和Servlet的典型工作流程。

二、基本原理

JSP与Servlet的协作流程可分为三个阶段:

  1. 请求处理:用户通过浏览器发送HTTP请求,Servlet接收请求并解析参数
  2. 业务处理:Servlet执行计算逻辑,可能涉及数据校验、业务规则
  3. 响应生成:Servlet将结果传递给JSP页面,JSP生成HTML响应返回给浏览器

关键点在于:Servlet负责处理业务逻辑,JSP负责页面展示,二者通过request对象进行数据传递。

三、环境准备

开发环境建议:

  • JDK 1.8+
  • Apache Tomcat 9.x
  • IDE:IntelliJ IDEA 或 Eclipse
  • 项目结构建议:

    webapps/
    └── calculator
        ├── WEB-INF/
        │   └── web.xml
        ├── index.jsp
        └── CalculatorServlet.java

四、核心实现

1. JSP页面:用户交互界面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>简易计算器</title>
</head>
<body>
    <h2>简易计算器</h2>
    <form action="calculator" method="post">
        数字1: <input type="text" name="num1"><br>
        运算符: 
        <select name="operator">
            <option value="+">+</option>
            <option value="-">-</option>
            <option value="*">*</option>
            <option value="/">/</option>
        </select><br>
        数字2: <input type="text" name="num2"><br>
        <input type="submit" value="计算">
    </form>
    <%
        // 显示计算结果
        if (request.getAttribute("result") != null) {
            out.println("<h3>结果: " + request.getAttribute("result") + "</h3>");
        }
    %>
</body>
</html>

关键点分析:

  • 使用<form>标签定义表单提交路径
  • 通过<select>实现运算符选择
  • 使用JSP EL表达式显示计算结果

2. Servlet处理逻辑

@WebServlet("/calculator")
public class CalculatorServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取参数
        String num1Str = request.getParameter("num1");
        String num2Str = request.getParameter("num2");
        String operator = request.getParameter("operator");

        // 数据校验
        if (num1Str == null || num2Str == null || operator == null) {
            request.setAttribute("error", "缺少必要参数");
            request.getRequestDispatcher("index.jsp").forward(request, response);
            return;
        }

        try {
            double num1 = Double.parseDouble(num1Str);
            double num2 = Double.parseDouble(num2Str);
            
            double result = 0;
            switch (operator) {
                case "+": result = num1 + num2; break;
                case "-": result = num1 - num2; break;
                case "*": result = num1 * num2; break;
                case "/": 
                    if (num2 == 0) {
                        request.setAttribute("error", "除数不能为零");
                        request.getRequestDispatcher("index.jsp").forward(request, response);
                        return;
                    }
                    result = num1 / num2; 
                    break;
                default: 
                    request.setAttribute("error", "无效的运算符");
                    request.getRequestDispatcher("index.jsp").forward(request, response);
                    return;
            }
            
            request.setAttribute("result", result);
            request.getRequestDispatcher("index.jsp").forward(request, response);
        } catch (NumberFormatException e) {
            request.setAttribute("error", "请输入有效的数字");
            request.getRequestDispatcher("index.jsp").forward(request, response);
        }
    }
}

关键点分析:

  • 使用@WebServlet注解定义Servlet映射
  • 实现完整的参数校验逻辑
  • 使用switch处理不同运算符
  • 异常处理机制
  • 使用RequestDispatcher实现页面跳转

3. 配置文件:web.xml

<web-app>
    <servlet>
        <servlet-name>CalculatorServlet</servlet-name>
        <servlet-class>CalculatorServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>CalculatorServlet</servlet-name>
        <url-pattern>/calculator</url-pattern>
    </servlet-mapping>
</web-app>

五、完整案例

完整项目结构如下:

webapps/
  └── calculator
      ├── index.jsp
      ├── WEB-INF/
      │   └── web.xml
      └── CalculatorServlet.java

运行步骤:

  1. 部署到Tomcat服务器
  2. 访问http://localhost:8080/calculator/index.jsp
  3. 输入数字和运算符后点击"计算"按钮
  4. 查看计算结果

完整代码示例(Servlet部分):

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

@WebServlet("/calculator")
public class CalculatorServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String num1Str = request.getParameter("num1");
        String num2Str = request.getParameter("num2");
        String operator = request.getParameter("operator");

        if (num1Str == null || num2Str == null || operator == null) {
            request.setAttribute("error", "缺少必要参数");
            request.getRequestDispatcher("index.jsp").forward(request, response);
            return;
        }

        try {
            double num1 = Double.parseDouble(num1Str);
            double num2 = Double.parseDouble(num2Str);
            
            double result = 0;
            switch (operator) {
                case "+": result = num1 + num2; break;
                case "-": result = num1 - num2; break;
                case "*": result = num1 * num2; break;
                case "/": 
                    if (num2 == 0) {
                        request.setAttribute("error", "除数不能为零");
                        request.getRequestDispatcher("index.jsp").forward(request, response);
                        return;
                    }
                    result = num1 / num2; 
                    break;
                default: 
                    request.setAttribute("error", "无效的运算符");
                    request.getRequestDispatcher("index.jsp").forward(request, response);
                    return;
            }
            
            request.setAttribute("result", result);
            request.getRequestDispatcher("index.jsp").forward(request, response);
        } catch (NumberFormatException e) {
            request.setAttribute("error", "请输入有效的数字");
            request.getRequestDispatcher("index.jsp").forward(request, response);
        }
    }
}

六、源码解析

  1. Servlet生命周期:当请求到达时,Servlet容器会创建Servlet实例并调用doPost方法
  2. 参数获取机制:通过request.getParameter()获取表单提交的数据
  3. 异常处理:包含多个异常处理分支,包括空值检查、类型转换异常和运算符校验
  4. 结果传递:使用request.setAttribute()将结果传递给JSP页面
  5. 页面跳转:通过RequestDispatcher实现前后端数据传递

七、进阶使用

1. 历史记录功能

// 在Servlet中添加记录逻辑
List<String> history = (List<String>) getServletContext().getAttribute("history");
if (history == null) {
    history = new ArrayList<>();
}
history.add(num1Str + operator + num2Str + "=" + result);
getServletContext().setAttribute("history", history);

2. 输入验证增强

// 增加正则表达式校验
if (!num1Str.matches("^-?\\d+(\\.\\d+)?$")) {
    request.setAttribute("error", "请输入有效的数字");
    request.getRequestDispatcher("index.jsp").forward(request, response);
    return;
}

3. 使用JSTL标签

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
...
<c:if test="${not empty history}">
    <h3>历史记录:</h3>
    <ul>
        <c:forEach items="${history}" var="item">
            <li>${item}</li>
        </c:forEach>
    </ul>
</c:if>

八、性能与工程实践

1. 性能优化

  • 缓存计算结果:对于重复计算可使用缓存机制
  • 异步处理:对于复杂计算可使用线程池
  • 减少HTTP请求:将部分逻辑移到前端JavaScript处理

2. 安全风险

  • XSS攻击:用户输入未转义可能导致脚本注入
  • CSRF攻击:未验证请求来源可能导致恶意提交
  • SQL注入:虽然本例未涉及数据库,但需注意参数化查询

3. 安全改进

// 使用JSTL的fmt标签转义输出
<fmt:formatNumber value="${result}" type="number" />

九、常见问题与踩坑

1. 常见错误示例

// 错误示例:直接使用out.println()可能导致乱码
out.println("结果: " + result);

问题分析:未设置正确的字符编码,可能导致中文乱码

解决办法

<%@ page contentType="text/html;charset=UTF-8" %>

2. 运算符处理错误

// 错误示例:未处理除法中的除零情况
result = num1 / num2;

问题分析:直接除法可能导致运行时异常

解决办法:增加条件判断

3. 未处理空值

// 错误示例:未检查参数是否为空
double num1 = Double.parseDouble(num1Str);

问题分析:可能导致NumberFormatException

解决办法:增加空值检查

十、最佳实践

  1. 分层架构:将业务逻辑与展示层分离
  2. 输入验证:在多个层进行校验(前端+后端)
  3. 异常处理:统一处理异常,避免直接暴露错误信息
  4. 日志记录:记录关键操作日志,便于调试
  5. 资源管理:及时关闭资源,避免内存泄漏

十一、总结

JSP+Servlet的组合虽然已逐渐被现代框架取代,但在理解Web开发基础原理方面仍具有重要价值。通过简易计算器的实现,我们深入解析了:

  1. HTTP请求的处理流程
  2. JSP与Servlet的协作机制
  3. 业务逻辑与展示层的分离
  4. 异常处理与安全防护
  5. 实际开发中的常见问题

在实际项目中,这种方案适用于:

  • 简单的页面交互需求
  • 无需复杂业务逻辑的场景
  • 需要快速搭建的原型系统

但不推荐用于:

  • 高并发场景
  • 复杂业务系统
  • 需要高安全性的应用

随着技术发展,建议采用Spring MVC、React+Node.js等现代技术栈,以获得更好的开发效率和系统扩展性。

最后修改于:2026年09月16日 15:15

评论已关闭

推荐阅读

AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日
python之plot()和subplot()画图
2024年11月26日
理解 DALL·E 2、Stable Diffusion 和 Midjourney 工作原理
2024年12月01日