news 2026/10/27 4:02:38

JSP+Servlet实现商城登录注册系统开发指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JSP+Servlet实现商城登录注册系统开发指南

1. 项目概述

这个JSP+Servlet简易商城登录注册系统是一个典型的Java Web入门实战项目。作为电商系统的基础模块,登录注册功能承载着用户身份验证和权限控制的核心职责。我十年前刚入行时做的第一个项目就是类似的商城系统,当时踩了不少坑,现在回想起来依然记忆犹新。

使用JSP+Servlet技术栈搭建这类系统有几个明显优势:首先,这是Java EE最基础的技术组合,学习曲线平缓;其次,不需要引入复杂的框架,适合理解Web开发底层原理;最后,整个项目可以运行在轻量级的Tomcat服务器上,开发环境搭建非常简单。不过要注意的是,现代企业级项目通常会采用Spring等框架,这个简易版更适合教学和练手。

2. 技术选型与准备

2.1 开发环境配置

基础环境需要准备:

  • JDK 1.8+(推荐OpenJDK 11)
  • Apache Tomcat 9.x
  • MySQL 5.7+或MariaDB
  • Eclipse/IntelliJ IDEA开发工具

重要提示:Tomcat版本要与JDK版本匹配,JDK11建议使用Tomcat 9.x,避免兼容性问题。

数据库表设计是登录注册系统的核心,这里给出用户表的基础结构:

CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL, `password` varchar(100) NOT NULL, `email` varchar(100) NOT NULL, `phone` varchar(20) DEFAULT NULL, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `username_UNIQUE` (`username`), UNIQUE KEY `email_UNIQUE` (`email`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

2.2 项目目录结构

标准的Maven Web项目结构如下:

src/ ├── main/ │ ├── java/ # Java源代码 │ │ └── com/ │ │ └── example/ │ │ └── servlet/ # Servlet类 │ ├── resources/ # 配置文件 │ └── webapp/ # Web资源 │ ├── WEB-INF/ │ │ ├── lib/ # 依赖库 │ │ └── web.xml # 部署描述符 │ ├── css/ # 样式表 │ ├── js/ # JavaScript │ └── jsp/ # JSP页面 └── test/ # 测试代码

3. 核心功能实现

3.1 用户注册模块

注册流程的关键点:

  1. 前端表单验证(JS)
  2. 服务端二次验证
  3. 密码加密存储
  4. 异常处理

注册Servlet示例代码:

@WebServlet("/register") public class RegisterServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); String password = request.getParameter("password"); String email = request.getParameter("email"); // 参数校验 if(StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) { request.setAttribute("error", "用户名和密码不能为空"); request.getRequestDispatcher("/register.jsp").forward(request, response); return; } // 密码加密 String encryptedPwd = DigestUtils.md5Hex(password + SALT); // 用户对象封装 User user = new User(); user.setUsername(username); user.setPassword(encryptedPwd); user.setEmail(email); // 数据库操作 try { UserService userService = new UserServiceImpl(); boolean result = userService.register(user); if(result) { response.sendRedirect("register_success.jsp"); } else { request.setAttribute("error", "注册失败,用户名可能已存在"); request.getRequestDispatcher("/register.jsp").forward(request, response); } } catch (SQLException e) { throw new ServletException("数据库操作异常", e); } } }

3.2 用户登录模块

登录功能需要注意的安全要点:

  1. 防止SQL注入
  2. 密码比对方式
  3. Session管理
  4. 登录失败处理

登录验证的核心逻辑:

public boolean login(String username, String password) throws SQLException { Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { conn = dataSource.getConnection(); String sql = "SELECT password FROM users WHERE username = ?"; stmt = conn.prepareStatement(sql); stmt.setString(1, username); rs = stmt.executeQuery(); if(rs.next()) { String dbPassword = rs.getString("password"); String inputPassword = DigestUtils.md5Hex(password + SALT); return dbPassword.equals(inputPassword); } return false; } finally { // 关闭资源 } }

4. 前端页面实现

4.1 注册页面关键代码

<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>用户注册</title> <style> .error { color: red; } </style> </head> <body> <h2>用户注册</h2> <form action="register" method="post" onsubmit="return validateForm()"> <div> <label>用户名:</label> <input type="text" name="username" id="username"> <span id="usernameError" class="error"></span> </div> <div> <label>密码:</label> <input type="password" name="password" id="password"> <span id="passwordError" class="error"></span> </div> <div> <label>邮箱:</label> <input type="email" name="email" id="email"> </div> <button type="submit">注册</button> </form> <script> function validateForm() { let valid = true; const username = document.getElementById('username').value; const password = document.getElementById('password').value; if(username.length < 4) { document.getElementById('usernameError').innerText = '用户名至少4个字符'; valid = false; } else { document.getElementById('usernameError').innerText = ''; } if(password.length < 6) { document.getElementById('passwordError').innerText = '密码至少6个字符'; valid = false; } else { document.getElementById('passwordError').innerText = ''; } return valid; } </script> </body> </html>

5. 系统优化与安全

5.1 密码安全增强

  1. 使用更安全的加密算法:
public static String encrypt(String password) { int iterations = 10000; char[] chars = password.toCharArray(); byte[] salt = getSalt(); PBEKeySpec spec = new PBEKeySpec(chars, salt, iterations, 64 * 8); SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); byte[] hash = skf.generateSecret(spec).getEncoded(); return iterations + ":" + toHex(salt) + ":" + toHex(hash); }

5.2 防止重复提交

在注册页面添加Token机制:

<% String token = UUID.randomUUID().toString(); session.setAttribute("TOKEN_IN_SESSION", token); %> <input type="hidden" name="token" value="<%=token%>">

然后在Servlet中验证:

String clientToken = request.getParameter("token"); String serverToken = (String) request.getSession().getAttribute("TOKEN_IN_SESSION"); if(serverToken == null || !serverToken.equals(clientToken)) { // 重复提交处理 return; } request.getSession().removeAttribute("TOKEN_IN_SESSION");

6. 常见问题排查

6.1 JSP文件未生成问题

如果发现Tomcat的work目录没有生成JSP对应的Java文件,可以检查:

  1. 确认Tomcat配置文件中<Host>标签的autoDeploy和reloadable属性为true
  2. 检查JSP文件是否有语法错误
  3. 查看Tomcat日志中的编译错误
  4. 确认JSP文件放在了正确的位置(webapp目录下)

6.2 数据库连接池配置

推荐使用Tomcat JDBC连接池,在context.xml中添加:

<Resource name="jdbc/ShopDB" auth="Container" type="javax.sql.DataSource" maxTotal="100" maxIdle="30" maxWaitMillis="10000" username="root" password="123456" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/shop_db?useSSL=false&amp;characterEncoding=utf8"/>

然后在web.xml中引用:

<resource-ref> <description>DB Connection</description> <res-ref-name>jdbc/ShopDB</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref>

7. 项目部署与测试

7.1 Tomcat部署步骤

  1. 将项目打包成WAR文件:
mvn clean package
  1. 将生成的WAR文件复制到Tomcat的webapps目录

  2. 启动Tomcat:

./catalina.sh run
  1. 访问应用:
http://localhost:8080/your-project-name/

7.2 基础功能测试用例

测试场景测试步骤预期结果
正常注册输入合规的用户名、密码和邮箱注册成功,跳转到成功页面
用户名重复输入已存在的用户名提示"用户名已存在"
密码太短输入5位密码提示"密码至少6位"
正常登录使用正确凭据登录登录成功,建立会话
错误密码使用错误密码登录提示"用户名或密码错误"

8. 扩展与进阶

8.1 添加验证码功能

使用Kaptcha库实现验证码:

  1. 添加依赖:
<dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <version>2.3.2</version> </dependency>
  1. 在web.xml中配置:
<servlet> <servlet-name>Kaptcha</servlet-name> <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Kaptcha</servlet-name> <url-pattern>/kaptcha.jpg</url-pattern> </servlet-mapping>
  1. JSP页面中使用:
<img src="kaptcha.jpg" onclick="this.src='kaptcha.jpg?'+Math.random()"> <input type="text" name="kaptcha">

8.2 记住我功能实现

使用Cookie实现记住登录状态:

// 登录成功后 if("on".equals(request.getParameter("remember"))) { Cookie usernameCookie = new Cookie("username", username); usernameCookie.setMaxAge(7 * 24 * 60 * 60); // 7天 response.addCookie(usernameCookie); }

在登录页面自动填充:

<% Cookie[] cookies = request.getCookies(); String savedUsername = ""; if(cookies != null) { for(Cookie cookie : cookies) { if("username".equals(cookie.getName())) { savedUsername = cookie.getValue(); break; } } } %> <input type="text" name="username" value="<%=savedUsername%>">

9. 性能优化建议

  1. 使用Filter实现Gzip压缩:
@WebFilter("/*") public class CompressionFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; String encodings = request.getHeader("Accept-Encoding"); if(encodings != null && encodings.contains("gzip")) { CompressionResponseWrapper wrappedResp = new CompressionResponseWrapper(response); wrappedResp.setHeader("Content-Encoding", "gzip"); chain.doFilter(request, wrappedResp); wrappedResp.finish(); } else { chain.doFilter(request, response); } } }
  1. 启用浏览器缓存静态资源:
<filter> <filter-name>ExpiresFilter</filter-name> <filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class> <init-param> <param-name>ExpiresByType text/css</param-name> <param-value>access plus 1 week</param-value> </init-param> <init-param> <param-name>ExpiresByType application/javascript</param-name> <param-value>access plus 1 month</param-value> </init-param> </filter>

10. 项目总结与反思

这个简易商城登录注册系统虽然功能基础,但涵盖了Java Web开发的多个核心知识点。在实际开发过程中,我发现有几个关键点特别值得注意:

  1. 密码安全绝对不能马虎,简单的MD5加密已经不够安全,应该使用加盐的PBKDF2或者bcrypt算法。

  2. 输入验证要前后端同时进行,前端验证提升用户体验,后端验证保证数据安全。

  3. 错误处理要友好,不能直接把异常信息暴露给用户,但开发时应该记录详细日志。

  4. 数据库连接等资源一定要正确关闭,否则会导致内存泄漏。

这个项目还可以进一步扩展,比如添加手机短信验证、第三方登录(微信/QQ)、权限管理等功能。对于想学习Java Web开发的新手来说,从这样一个具体的小项目入手,逐步扩展功能,是很好的学习路径。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/27 4:02:14

UE5中Actor组件初始化与资源动静态加载最佳实践

1. 项目概述&#xff1a;为什么UE中Actor的组件初始化与资源加载必须“动静结合”在Unreal Engine的C开发实践中&#xff0c;“UECActor添加组件初始化和静动态加载资源”这个标题看似平实&#xff0c;实则直击中大型项目落地时最常被低估、却最容易引发线上事故的核心环节。我…

作者头像 李华
网站建设 2026/10/27 4:01:36

impeccable一词详解:从词源到搭配,掌握高级英语表达

前阵子刷手机&#xff0c;看到一条英文帖子下面有人评论&#xff1a;"Your taste in music is impeccable." 底下有人跟着问&#xff0c;impeccable 到底是夸人还是骂人&#xff0c;怎么用才能不被老外笑话。我当时就想&#xff0c;这个词确实值得好好聊一聊。它不像…

作者头像 李华
网站建设 2026/10/27 4:01:34

e2e测试落地:profile1配置档案与稳定性实战指南

做e2e测试的人&#xff0c;大概都会经历一种类似的状态&#xff1a;一开始觉得“不就是把用户操作流程点一遍嘛”&#xff0c;真正动手落地之后才发现&#xff0c;每个环节都在跟不确定性较劲——环境动不动就脏、元素说消失就消失、昨天还全绿的用例今天红成一片。尤其是当团队…

作者头像 李华
网站建设 2026/10/27 4:01:34

端到端测试实战:从核心链路到e2e profile1配置指南

先说个现象&#xff1a;过去两年我面试、带团队、和同行交流&#xff0c;“有没有做端到端测试”几乎成了技术盘点必问的一道题。但当你追问“你们的e2e是怎么跑的、跑多久、稳不稳定”&#xff0c;大部分人就开始含糊了。其实e2e这个缩写背后的含义很宽&#xff0c;它既指软件…

作者头像 李华
网站建设 2026/10/27 4:01:31

axios与jsdom实现服务端网页抓取与解析

1. 当HTTP请求遇上DOM解析&#xff1a;axios与jsdom的化学反应最近在重构一个需要从第三方网站抓取数据并实时解析的项目时&#xff0c;我遇到了一个典型的前端工程难题&#xff1a;如何在不依赖浏览器环境的情况下&#xff0c;既能发送复杂的HTTP请求&#xff0c;又能像在浏览…

作者头像 李华
网站建设 2026/10/27 4:01:22

Criteo广告推荐系统架构与机器学习优化实践

1. 项目背景与核心价值Criteo项目是互联网广告领域最具代表性的实战案例之一。作为全球领先的效果营销平台&#xff0c;Criteo每天要处理超过60亿次广告展示决策&#xff0c;这对实时计算系统提出了极高要求。我在2018年首次接触这个项目时&#xff0c;就被它精巧的工程架构所震…

作者头像 李华