当前位置: 首页 > article >正文

通讯录系统数据库设计与实现

1. 数据库设计与配置1.1 数据库建表 SQL-- 创建数据库使用UTF-8编码 CREATE DATABASE IF NOT EXISTS contact_system DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci; USE contact_system; -- 用户表 CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 用户ID, user_name VARCHAR(50) NOT NULL UNIQUE COMMENT 用户名, password VARCHAR(50) NOT NULL COMMENT 密码明文存储便于调试, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表; -- 联系人表 CREATE TABLE tb_contact ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 联系人ID, name VARCHAR(50) NOT NULL COMMENT 姓名, phone VARCHAR(20) NOT NULL COMMENT 电话, email VARCHAR(100) COMMENT 邮箱, group_name ENUM(家人,同事,朋友,其他) DEFAULT 其他 COMMENT 分组, remark VARCHAR(500) COMMENT 备注, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 添加时间, user_id INT NOT NULL COMMENT 所属用户ID, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT联系人表; -- 插入测试数据 INSERT INTO users (user_name, password) VALUES (admin, 123456), (user1, 123456); INSERT INTO tb_contact (name, phone, email, group_name, remark, user_id) VALUES (张三, 13800138000, zhangsanexample.com, 同事, 技术部同事, 1), (李四, 13900139000, lisiexample.com, 朋友, 大学同学, 1), (王五, 13600136000, wangwuexample.com, 家人, 父亲, 2);1.2 Navicat 连接步骤打开Navicat点击连接 → MySQL配置连接参数连接名任意如ContactSystem主机localhost本地或远程IP端口3306默认用户名root或自定义用户密码数据库密码点击测试连接成功后点击确定双击新创建的连接右键选择运行SQL文件执行上述建表SQL2. 项目结构搭建2.1 标准项目目录结构ContactSystem/ ├── src/ │ ├── entity/ │ │ ├── Users.java │ │ └── Contact.java │ ├── servlet/ │ │ ├── LoginServlet.java │ │ ├── LogoutServlet.java │ │ ├── AddContactServlet.java │ │ ├── UpdateContactServlet.java │ │ ├── DeleteContactServlet.java │ │ └── SelectContactServlet.java │ ├── service/ │ │ ├── UserBo.java │ │ └── ContactBo.java │ ├── dao/ │ │ ├── DBUtil.java │ │ ├── UserDao.java │ │ └── ContactDao.java │ └── common/ │ └── Validate.java ├── WebContent/ │ ├── WEB-INF/ │ │ ├── lib/ │ │ │ └── mysql-connector-java-8.0.xx.jar │ │ └── web.xml │ ├── login.jsp │ ├── index.jsp │ ├── addContact.jsp │ ├── editContact.jsp │ └── contactList.jsp └── 项目配置文件2.2 IDEA项目创建步骤打开IDEA → File → New → Project选择Java Enterprise → Web Application项目名ContactSystem不使用MavenApplication Server选择Tomcat 9.x创建完成后手动创建上述目录结构下载MySQL驱动jar包放入WEB-INF/lib目录3. 核心代码实现3.1 实体类entity层Users.javapackage entity; import java.util.Date; public class Users { private int id; private String userName; private String password; private Date createTime; // 构造方法 public Users() {} public Users(String userName, String password) { this.userName userName; this.password password; } // Getter和Setter方法 public int getId() { return id; } public void setId(int id) { this.id id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password password; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime createTime; } }Contact.javapackage entity; import java.util.Date; public class Contact { private int id; private String name; private String phone; private String email; private String groupName; private String remark; private Date createTime; private int userId; // 构造方法 public Contact() {} public Contact(String name, String phone, String email, String groupName, String remark, int userId) { this.name name; this.phone phone; this.email email; this.groupName groupName; this.remark remark; this.userId userId; } // Getter和Setter方法略参考Users.java格式 }3.2 数据库工具类dao层DBUtil.javapackage dao; import java.sql.*; public class DBUtil { private static final String DRIVER com.mysql.cj.jdbc.Driver; private static final String URL jdbc:mysql://localhost:3306/contact_system?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghai; private static final String USERNAME root; private static final String PASSWORD 你的数据库密码; // 加载数据库驱动 static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { e.printStackTrace(); } } // 获取数据库连接 public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USERNAME, PASSWORD); } // 关闭资源 public static void close(Connection conn, Statement stmt, ResultSet rs) { try { if (rs ! null) rs.close(); if (stmt ! null) stmt.close(); if (conn ! null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } } // 开启事务 public static void beginTransaction(Connection conn) throws SQLException { if (conn ! null) { conn.setAutoCommit(false); } } // 提交事务 public static void commitTransaction(Connection conn) throws SQLException { if (conn ! null) { conn.commit(); } } // 回滚事务 public static void rollbackTransaction(Connection conn) { try { if (conn ! null) { conn.rollback(); } } catch (SQLException e) { e.printStackTrace(); } } }3.3 数据访问层dao层UserDao.javapackage dao; import entity.Users; import java.sql.*; public class UserDao { // 用户登录验证 public Users login(String userName, String password) { Connection conn null; PreparedStatement pstmt null; ResultSet rs null; Users user null; try { conn DBUtil.getConnection(); // 使用PreparedStatement防止SQL注入 String sql SELECT id, user_name, password FROM users WHERE user_name ? AND password ?; pstmt conn.prepareStatement(sql); pstmt.setString(1, userName); pstmt.setString(2, password); rs pstmt.executeQuery(); if (rs.next()) { user new Users(); user.setId(rs.getInt(id)); user.setUserName(rs.getString(user_name)); user.setPassword(rs.getString(password)); } } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.close(conn, pstmt, rs); } return user; } // 用户注册扩展功能 public boolean register(Users user) { Connection conn null; PreparedStatement pstmt null; boolean success false; try { conn DBUtil.getConnection(); String sql INSERT INTO users (user_name, password) VALUES (?, ?); pstmt conn.prepareStatement(sql); pstmt.setString(1, user.getUserName()); pstmt.setString(2, user.getPassword()); int rows pstmt.executeUpdate(); success rows 0; } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.close(conn, pstmt, null); } return success; } }ContactDao.javapackage dao; import entity.Contact; import java.sql.*; import java.util.ArrayList; import java.util.List; public class ContactDao { // 添加联系人 public boolean addContact(Contact contact) { Connection conn null; PreparedStatement pstmt null; boolean success false; try { conn DBUtil.getConnection(); String sql INSERT INTO tb_contact (name, phone, email, group_name, remark, user_id) VALUES (?, ?, ?, ?, ?, ?); pstmt conn.prepareStatement(sql); pstmt.setString(1, contact.getName()); pstmt.setString(2, contact.getPhone()); pstmt.setString(3, contact.getEmail()); pstmt.setString(4, contact.getGroupName()); pstmt.setString(5, contact.getRemark()); pstmt.setInt(6, contact.getUserId()); int rows pstmt.executeUpdate(); success rows 0; } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.close(conn, pstmt, null); } return success; } // 分页查询联系人 public ListContact getContactsByPage(int userId, int page, int pageSize, String keyword) { ListContact contacts new ArrayList(); Connection conn null; PreparedStatement pstmt null; ResultSet rs null; try { conn DBUtil.getConnection(); StringBuilder sql new StringBuilder( SELECT * FROM tb_contact WHERE user_id ? ); // 添加搜索条件 if (keyword ! null !keyword.trim().isEmpty()) { sql.append( AND (name LIKE ? OR phone LIKE ? OR email LIKE ?)); } sql.append( ORDER BY create_time DESC LIMIT ?, ?); pstmt conn.prepareStatement(sql.toString()); int paramIndex 1; pstmt.setInt(paramIndex, userId); if (keyword ! null !keyword.trim().isEmpty()) { String likeKeyword % keyword %; pstmt.setString(paramIndex, likeKeyword); pstmt.setString(paramIndex, likeKeyword); pstmt.setString(paramIndex, likeKeyword); } pstmt.setInt(paramIndex, (page - 1) * pageSize); pstmt.setInt(paramIndex, pageSize); rs pstmt.executeQuery(); while (rs.next()) { Contact contact new Contact(); contact.setId(rs.getInt(id)); contact.setName(rs.getString(name)); contact.setPhone(rs.getString(phone)); contact.setEmail(rs.getString(email)); contact.setGroupName(rs.getString(group_name)); contact.setRemark(rs.getString(remark)); contact.setCreateTime(rs.getTimestamp(create_time)); contact.setUserId(rs.getInt(user_id)); contacts.add(contact); } } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.close(conn, pstmt, rs); } return contacts; } // 获取联系人总数用于分页 public int getContactCount(int userId, String keyword) { Connection conn null; PreparedStatement pstmt null; ResultSet rs null; int count 0; try { conn DBUtil.getConnection(); StringBuilder sql new StringBuilder( SELECT COUNT(*) FROM tb_contact WHERE user_id ? ); if (keyword ! null !keyword.trim().isEmpty()) { sql.append( AND (name LIKE ? OR phone LIKE ? OR email LIKE ?)); } pstmt conn.prepareStatement(sql.toString()); int paramIndex 1; pstmt.setInt(paramIndex, userId); if (keyword ! null !keyword.trim().isEmpty()) { String likeKeyword % keyword %; pstmt.setString(paramIndex, likeKeyword); pstmt.setString(paramIndex, likeKeyword); pstmt.setString(paramIndex, likeKeyword); } rs pstmt.executeQuery(); if (rs.next()) { count rs.getInt(1); } } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.close(conn, pstmt, rs); } return count; } // 其他CRUD方法updateContact、deleteContact、getContactById略参考上述方法实现 }3.4 业务逻辑层service层UserBo.javapackage service; import dao.UserDao; import entity.Users; public class UserBo { private UserDao userDao new UserDao(); // 用户登录业务逻辑 public Users login(String userName, String password) { // 参数校验 if (userName null || userName.trim().isEmpty() || password null || password.trim().isEmpty()) { return null; } // 调用DAO层进行验证 return userDao.login(userName.trim(), password.trim()); } // 用户注册业务逻辑 public boolean register(Users user) { // 业务规则校验 if (user.getUserName() null || user.getUserName().trim().isEmpty() || user.getPassword() null || user.getPassword().trim().isEmpty()) { return false; } // 用户名长度限制 if (user.getUserName().length() 3 || user.getUserName().length() 20) { return false; } return userDao.register(user); } }ContactBo.javapackage service; import dao.ContactDao; import entity.Contact; import java.util.List; public class ContactBo { private ContactDao contactDao new ContactDao(); // 添加联系人业务逻辑 public boolean addContact(Contact contact) { // 参数校验 if (contact null || contact.getName() null || contact.getName().trim().isEmpty() || contact.getPhone() null || contact.getPhone().trim().isEmpty()) { return false; } // 手机号格式校验 if (!contact.getPhone().matches(^1[3-9]\\d{9}$)) { return false; } // 邮箱格式校验可选 if (contact.getEmail() ! null !contact.getEmail().trim().isEmpty()) { if (!contact.getEmail().matches(^[A-Za-z0-9_.-][A-Za-z0-9.-]$)) { return false; } } return contactDao.addContact(contact); } // 分页查询联系人 public ListContact getContactsByPage(int userId, int page, int pageSize, String keyword) { // 参数校验 if (userId 0 || page 0 || pageSize 0) { return null; } // 限制最大页数 if (pageSize 100) { pageSize 100; } return contactDao.getContactsByPage(userId, page, pageSize, keyword); } // 获取总页数 public int getTotalPages(int userId, int pageSize, String keyword) { int total contactDao.getContactCount(userId, keyword); return (int) Math.ceil((double) total / pageSize); } }3.5 工具类common层Validate.javapackage common; import javax.servlet.http.HttpServletRequest; public class Validate { // 检查字符串是否为空或null public static boolean isEmpty(String str) { return str null || str.trim().isEmpty(); } // 检查手机号格式 public static boolean isPhoneValid(String phone) { if (isEmpty(phone)) return false; return phone.matches(^1[3-9]\\d{9}$); } // 检查邮箱格式 public static boolean isEmailValid(String email) { if (isEmpty(email)) return false; return email.matches(^[A-Za-z0-9_.-][A-Za-z0-9.-]$); } // 防止XSS攻击过滤特殊字符 public static String filterXSS(String input) { if (isEmpty(input)) return input; return input.replaceAll(, lt;) .replaceAll(, gt;) .replaceAll(\, quot;) .replaceAll(, #x27;) .replaceAll(/, #x2F;); } // 从请求参数中安全获取值 public static String getParameter(HttpServletRequest request, String paramName) { String value request.getParameter(paramName); if (value ! null) { value filterXSS(value.trim()); } return value; } }3.6 Servlet控制器servlet层LoginServlet.javapackage servlet; import entity.Users; import service.UserBo; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException; WebServlet(/LoginServlet) public class LoginServlet extends HttpServlet { private UserBo userBo new UserBo(); Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置编码兼容GB2312和UTF-8 request.setCharacterEncoding(UTF-8); response.setContentType(text/html;charsetUTF-8); // 获取参数 String userName request.getParameter(userName); String password request.getParameter(password); // 参数校验 if (userName null || userName.trim().isEmpty() || password null || password.trim().isEmpty()) { request.setAttribute(error, 用户名和密码不能为空); request.getRequestDispatcher(login.jsp).forward(request, response); return; } // 业务处理 Users user userBo.login(userName, password); if (user ! null) { // 登录成功创建Session HttpSession session request.getSession(); session.setAttribute(user, user); session.setMaxInactiveInterval(30 * 60); // 30分钟超时 // 重定向到首页 response.sendRedirect(index.jsp); } else { // 登录失败安全提示 request.setAttribute(error, 用户名或密码错误); request.getRequestDispatcher(login.jsp).forward(request, response); } } Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 防止直接访问 response.sendRedirect(login.jsp); } }SelectContactServlet.javapackage servlet; import entity.Contact; import entity.Users; import service.ContactBo; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException; import java.util.List; WebServlet(/SelectContactServlet) public class SelectContactServlet extends HttpServlet { private ContactBo contactBo new ContactBo(); Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 登录拦截检查 HttpSession session request.getSession(false); if (session null || session.getAttribute(user) null) { response.sendRedirect(login.jsp); return; } // 设置编码 request.setCharacterEncoding(UTF-8); response.setContentType(text/html;charsetUTF-8); // 获取当前用户 Users user (Users) session.getAttribute(user); int userId user.getId(); // 获取分页参数 String pageStr request.getParameter(page); String keyword request.getParameter(keyword); int page 1; int pageSize 10; if (pageStr ! null !pageStr.trim().isEmpty()) { try { page Integer.parseInt(pageStr); if (page 1) page 1; } catch (NumberFormatException e) { page 1; } } // 获取搜索关键词 if (keyword ! null) { keyword keyword.trim(); } // 查询数据 ListContact contacts contactBo.getContactsByPage(userId, page, pageSize, keyword); int totalPages contactBo.getTotalPages(userId, pageSize, keyword); // 设置请求属性 request.setAttribute(contacts, contacts); request.setAttribute(currentPage, page); request.setAttribute(totalPages, totalPages); request.setAttribute(keyword, keyword); // 转发到列表页面 request.getRequestDispatcher(contactList.jsp).forward(request, response); } }3.7 JSP页面实现login.jsp% page contentTypetext/html;charsetUTF-8 languagejava % html head title通讯录管理系统 - 登录/title style body { font-family: Arial, sans-serif; background: #f5f5f5; } .login-box { width: 300px; margin: 100px auto; padding: 20px; background: white; border-radius: 5px; box-shadow: 0 0 10px rgba(0,0,0,0.1); } .form-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; } input { width: 100%; padding: 8px; box-sizing: border-box; } .error { color: red; font-size: 12px; } .btn { width: 100%; padding: 10px; background: #007bff; color: white; border: none; border-radius: 3px; cursor: pointer; } /style /head body div classlogin-box h2用户登录/h2 form actionLoginServlet methodpost div classform-group label用户名:/label input typetext nameuserName required /div div classform-group label密码:/label input typepassword namepassword required /div div classform-group button typesubmit classbtn登录/button /div % if (request.getAttribute(error) ! null) { % div classerror% request.getAttribute(error) %/div % } % /form p测试账号admin/123456 或 user1/123456/p /div /body /htmlindex.jsp% page contentTypetext/html;charsetUTF-8 languagejava % % page importentity.Users % % // 登录检查 Users user (Users) session.getAttribute(user); if (user null) { response.sendRedirect(login.jsp); return; } % html head title通讯录管理系统 - 首页/title style body { font-family: Arial, sans-serif; margin: 0; padding: 20px; } .header { background: #007bff; color: white; padding: 10px; margin-bottom: 20px; } .menu a { margin-right: 15px; color: #007bff; text-decoration: none; } .welcome { float: right; } /style /head body div classheader h1通讯录管理系统/h1 div classwelcome 欢迎% user.getUserName() % | a hrefLogoutServlet stylecolor: white;退出登录/a /div /div div classmenu a hrefSelectContactServlet联系人列表/a a hrefaddContact.jsp添加联系人/a /div div classcontent h2系统功能/h2 ul li联系人管理增删改查/li li联系人分组家人/同事/朋友/其他/li li分页显示和搜索功能/li li用户会话管理/li /ul /div /body /htmlcontactList.jsp% page contentTypetext/html;charsetUTF-8 languagejava % % page importentity.Contact, java.util.List % % // 登录检查 if (session.getAttribute(user) null) { response.sendRedirect(login.jsp); return; } ListContact contacts (ListContact) request.getAttribute(contacts); Integer currentPage (Integer) request.getAttribute(currentPage); Integer totalPages (Integer) request.getAttribute(totalPages); String keyword (String) request.getAttribute(keyword); if (keyword null) keyword ; % html head title联系人列表/title style table { width: 100%; border-collapse: collapse; margin-top: 20px; } th, td { border: 1px solid #ddd; padding: 8px; text-align: left; } th { background-color: #f2f2f2; } .pagination { margin-top: 20px; } .search-box { margin-bottom: 20px; } /style /head body h2联系人列表/h2 div classsearch-box form actionSelectContactServlet methodget input typetext namekeyword value% keyword % placeholder搜索姓名/电话/邮箱 button typesubmit搜索/button a hrefaddContact.jsp添加联系人/a /form /div table tr th姓名/th th电话/th th邮箱/th th分组/th th备注/th th操作/th /tr % if (contacts ! null !contacts.isEmpty()) { for (Contact contact : contacts) { % tr td% contact.getName() %/td td% contact.getPhone() %/td td% contact.getEmail() ! null ? contact.getEmail() : %/td td% contact.getGroupName() %/td td% contact.getRemark() ! null ? contact.getRemark() : %/td td a hrefeditContact.jsp?id% contact.getId() %编辑/a a hrefDeleteContactServlet?id% contact.getId() % onclickreturn confirm(确定删除吗)删除/a /td /tr % } } else { % tr td colspan6 styletext-align: center;暂无联系人数据/td /tr % } % /table % if (totalPages ! null totalPages 0) { % div classpagination % for (int i 1; i totalPages; i) { if (i currentPage) { % span% i %/span % } else { % a hrefSelectContactServlet?page% i %keyword% keyword %% i %/a % } } % /div % } % pa hrefindex.jsp返回首页/a/p /body /html3.8 web.xml配置?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd version4.0 !-- 字符编码过滤器 -- filter filter-nameCharacterEncodingFilter/filter-name filter-classfilter.CharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param /filter filter-mapping filter-nameCharacterEncodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping !-- 登录拦截过滤器 -- filter filter-nameLoginFilter/filter-name filter-classfilter.LoginFilter/filter-class /filter filter-mapping filter-nameLoginFilter/filter-name url-pattern/contactList.jsp/url-pattern url-pattern/addContact.jsp/url-pattern url-pattern/editContact.jsp/url-pattern url-pattern/SelectContactServlet/url-pattern url-pattern/AddContactServlet/url-pattern url-pattern/UpdateContactServlet/url-pattern url-pattern/DeleteContactServlet/url-pattern /filter-mapping !-- Servlet映射 -- servlet servlet-nameLoginServlet/servlet-name servlet-classservlet.LoginServlet/servlet-class /servlet servlet-mapping servlet-nameLoginServlet/servlet-name url-pattern/LoginServlet/url-pattern /servlet-mapping servlet servlet-nameSelectContactServlet/servlet-name servlet-classservlet.SelectContactServlet/servlet-class /servlet servlet-mapping servlet-nameSelectContactServlet/servlet-name url-pattern/SelectContactServlet/url-pattern /servlet-mapping !-- 欢迎页面 -- welcome-file-list welcome-filelogin.jsp/welcome-file /welcome-file-list !-- 会话超时配置30分钟 -- session-config session-timeout30/session-timeout /session-config /web-app4. Tomcat部署与配置4.1 Tomcat 9.x部署步骤下载Tomcat 9.x从Apache官网下载Tomcat 9.x压缩包解压到指定目录如D:\apache-tomcat-9.0.x环境变量配置新建CATALINA_HOME值为Tomcat安装目录在Path中添加%CATALINA_HOME%\bin启动Tomcat# Windows %CATALINA_HOME%\bin\startup.bat # Linux/Mac $CATALINA_HOME/bin/startup.sh验证启动访问http://localhost:8080看到Tomcat首页即成功4.2 IDEA项目部署配置TomcatRun → Edit Configurations → 点击 → Tomcat Server → Local配置Tomcat Home目录Deployment标签页添加Artifact项目部署配置File → Project Structure → Artifacts点击 → Web Application: Exploded → From Modules选择项目模块设置Output directory运行项目点击Run按钮启动Tomcat访问http://localhost:8080/ContactSystem/login.jsp5. 常见问题排查方案5.1 404错误问题原因解决方案URL路径错误检查web.xml中的servlet映射配置项目未正确部署检查Tomcat的webapps目录是否有项目文件夹文件路径错误确保JSP文件在WebContent目录下上下文路径错误检查IDEA中Deployment的Application Context设置5.2 登录失败问题问题现象排查步骤提示用户名或密码错误1. 检查数据库用户数据2. 查看控制台SQL日志3. 验证UserDao.login方法登录后Session丢失1. 检查session.setMaxInactiveInterval设置2. 验证web.xml中session-timeout配置密码验证失败1. 检查数据库密码字段长度2. 验证密码是否包含特殊字符5.3 乱码问题乱码场景解决方案表单提交中文乱码Servlet中添加request.setCharacterEncoding(UTF-8)数据库读取乱码连接URL添加characterEncodingUTF-8参数JSP页面显示乱码页面顶部添加% page contentTypetext/html;charsetUTF-8 %响应乱码Servlet中添加response.setContentType(text/html;charsetUTF-8)5.4 SQL连接问题// 常见连接错误排查 public static void testConnection() { try { Connection conn DBUtil.getConnection(); if (conn ! null !conn.isClosed()) { System.out.println(数据库连接成功); conn.close(); } } catch (SQLException e) { System.err.println(连接失败 e.getMessage()); // 检查1. MySQL服务是否启动 2. 用户名密码是否正确 3. 数据库名是否正确 } }5.5 Tomcat启动失败端口占用检查8080端口是否被占用参考来源Java Web实现用户登录功能【JAVA项目实战】【图书管理系统】用户查询功能【Servlet】【Jsp】【Mysql】java web简单的注册登录界面实现(servletmysqljspidea)jspdaobeanservletMVC模式实现简单用户登录和注册页面连接数据库登录页面包含验证码两周内免登陆等功能IDEAJavaJSPMysqlTomcat实现Web学生信息管理系统JSPservletJDBC实现简单的注册登录功能

相关文章:

通讯录系统数据库设计与实现

1. 数据库设计与配置 1.1 数据库建表 SQL -- 创建数据库,使用UTF-8编码 CREATE DATABASE IF NOT EXISTS contact_system DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;USE contact_system;-- 用户表 CREATE TABLE users (id INT PRIMARY …...

大型语言模型开发的环境成本与优化策略

1. 语言模型开发的环境成本全景图当我们惊叹于ChatGPT流畅的对话能力或Midjourney惊人的图像生成质量时,很少有人会思考这些AI能力背后的环境代价。事实上,大型语言模型的开发正悄然成为数字时代的"高碳产业"——训练一个130亿参数的模型所产生…...

NS-USBLoader完整指南:Switch文件管理、RCM注入与游戏传输的一站式解决方案

NS-USBLoader完整指南:Switch文件管理、RCM注入与游戏传输的一站式解决方案 【免费下载链接】ns-usbloader Awoo Installer and GoldLeaf uploader of the NSPs (and other files), RCM payload injector, application for split/merge files. 项目地址: https://…...

PT助手Plus终极指南:3步实现浏览器PT下载自动化

PT助手Plus终极指南:3步实现浏览器PT下载自动化 【免费下载链接】PT-Plugin-Plus PT 助手 Plus,为 Microsoft Edge、Google Chrome、Firefox 浏览器插件(Web Extensions),主要用于辅助下载 PT 站的种子。 项目地址: …...

终极OpenSpeedy游戏加速教程:5分钟解锁老游戏流畅体验

终极OpenSpeedy游戏加速教程:5分钟解锁老游戏流畅体验 【免费下载链接】OpenSpeedy 🎮 An open-source game speed modifier. 项目地址: https://gitcode.com/gh_mirrors/op/OpenSpeedy 还在为经典老游戏在现代电脑上运行卡顿而烦恼吗&#xff1f…...

ModTheSpire终极指南:为《杀戮尖塔》构建安全高效的模组生态

ModTheSpire终极指南:为《杀戮尖塔》构建安全高效的模组生态 【免费下载链接】ModTheSpire External mod loader for Slay The Spire 项目地址: https://gitcode.com/gh_mirrors/mo/ModTheSpire 在游戏模组开发领域,安全性与扩展性往往难以兼得。…...

Baichuan-7B开源大模型:从环境搭建、推理调优到LoRA微调实战

1. 项目概述:一个值得深入研究的开源大语言模型最近在开源社区里,Baichuan-7B这个名字的讨论热度一直不低。作为一个长期关注大模型技术动向的从业者,我自然也对它进行了一番深入的“把玩”和研究。简单来说,Baichuan-7B是由百川智…...

CAN 总线技术综合研究报告

CAN总线技术综合研究报告 报告日期: 2026年5月14日 引言 在当今高度信息化和自动化的世界中,设备内部以及设备之间的可靠通信是实现复杂功能的基石。从汽车的动力控制到工厂的自动化生产线,都需要一个高效、可靠的通信网络来协调各个控制单元的工作。控制器局域网(Contr…...

户外Wi-Fi天线系统热管理方案与优化实践

1. 户外Wi-Fi天线系统热管理挑战解析 在户外通信设备领域,热管理一直是个令人头疼的问题。我经手过多个基站项目,最深切的体会就是:那些在实验室里运行良好的设备,一到实际户外环境就频频出现热关机。以这个案例中的Wi-Fi天线系统…...

AI智能体扩展实战:基于MCP协议构建AlterLab工具箱服务器

1. 项目概述:一个为AI智能体打造的“工具箱”服务器最近在折腾AI智能体(Agent)的开发,发现一个挺有意思的项目:RapierCraft/alterlab-mcp-server。简单来说,这是一个实现了模型上下文协议(Model…...

UVa 215 Spreadsheet Calculator

题目分析 本题要求实现一个简单的电子表格计算器。电子表格是一个矩形网格,每个单元格包含一个整数或者一个表达式。表达式由整数常量、单元格引用以及 和 - 运算符组成,计算时遵循从左到右的结合顺序。 输入首先给出行数 rrr 和列数 ccc,其…...

GPU渲染管线ROP单元优化与体积渲染性能提升

1. GPU渲染管线中的ROP单元深度解析在图形渲染管线中,Render Output Unit(ROP)扮演着至关重要的角色。作为渲染流程的最后阶段,ROP负责执行深度测试(Z-Test)、模板测试(Stencil Test&#xff09…...

构建数据科学AI代理规则库:从自动化到智能化的关键路径

1. 项目概述:一个为数据科学工作流定制的智能代理规则库最近在GitHub上看到一个挺有意思的项目,叫ds-agent-rules。光看名字,你可能觉得这又是一个平平无奇的规则文件集合。但作为一个在数据科学和自动化领域摸爬滚打多年的从业者&#xff0c…...

芯片高加速温湿度测试HAST:从步骤到报告讲解

其可靠性和稳定性成为消费者和制造商关注的焦点。高加速温湿度测试(Highly Accelerated Stress Test, HAST)作为一种有效的可靠性测试方法,近年来在行业内得到了广泛的应用。本文将从HAST测试的步骤、实际案例以及如何生成详细的测试报告等方…...

Linux串口通信终极指南:3步搞定CH341SER驱动安装,让Arduino开发不再卡壳

Linux串口通信终极指南:3步搞定CH341SER驱动安装,让Arduino开发不再卡壳 【免费下载链接】CH341SER CH341SER driver with fixed bug 项目地址: https://gitcode.com/gh_mirrors/ch/CH341SER 你是否曾经兴奋地拿起一块Arduino开发板,准…...

使用Taotoken平台后API调用延迟与稳定性的实际体感观察

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 使用Taotoken平台后API调用延迟与稳定性的实际体感观察 1. 迁移背景与初始考量 我们团队的一个内部知识库问答应用,原…...

FreeRTOS和RT-Thread的内存管理实战:如何正确使用pvPortMalloc与rt_malloc替代C库malloc

FreeRTOS与RT-Thread内存管理实战:从标准库陷阱到RTOS最佳实践 在嵌入式实时操作系统开发中,动态内存分配就像高空走钢丝——一步失误可能导致系统崩溃。传统C库的malloc/free在RTOS环境中如同穿着拖鞋走钢丝,而pvPortMalloc和rt_malloc则是专…...

Origin 9 绘图避坑指南:7个高频问题解决,让你的科研图表一次成型

Origin 9 科研绘图实战:7个高频问题深度解析与优化方案 科研绘图是数据可视化的重要环节,而Origin 9作为经典的科学绘图软件,其功能强大但操作细节繁多。许多用户在初次接触或日常使用中常会遇到各种棘手问题,导致绘图效率低下、图…...

开源作战室框架OpenClaw-Warroom:构建高效事件响应与团队协作平台

1. 项目概述:从“作战室”到开源协作的实战推演如果你在开源社区或者技术团队里待过一段时间,大概率听过“作战室”这个词。它听起来有点军事化,但在现代软件开发和应急响应场景里,它代表的是一个高度聚焦、信息透明、行动同步的虚…...

任天堂Switch游戏文件管理终极指南:NSC_BUILDER一站式解决方案

任天堂Switch游戏文件管理终极指南:NSC_BUILDER一站式解决方案 【免费下载链接】NSC_BUILDER Nintendo Switch Cleaner and Builder. A batchfile, python and html script based in hacbuild and Nuts python libraries. Designed initially to erase titlerights …...

openclaw-nerve:构建自包含应用包,彻底解决跨平台部署难题

1. 项目概述与核心价值最近在折腾一些自动化脚本和工具链,发现很多开源项目在依赖管理、环境配置和跨平台部署上,依然存在不小的摩擦。一个典型的场景是:你从GitHub上clone了一个看起来很酷的项目,满心欢喜地准备跑起来看看效果&a…...

告别虚拟机卡顿:在Proxmox VE 7.0上丝滑安装中兴新支点NewStartOS 4.3.8社区版

告别虚拟机卡顿:在Proxmox VE 7.0上丝滑安装中兴新支点NewStartOS 4.3.8社区版 虚拟化技术已成为现代IT基础设施的核心组件,而Proxmox VE作为开源的虚拟化管理平台,凭借其稳定性和灵活性赢得了众多技术团队的青睐。在众多虚拟化应用场景中&am…...

AI编程助手统一工作空间框架:声明式配置提升开发效率

1. 项目概述:为AI编程助手打造的统一工作空间框架如果你和我一样,每天都在用Cursor、GitHub Copilot这类AI编程助手,那你肯定也遇到过这个痛点:每次开新项目,或者切换到一个稍微复杂点的多项目工作区,都得从…...

从Arduino官网的‘eagle-files’说起:给硬件新手的Autodesk Eagle PCB设计入门指南

从Eagle文件到PCB设计:开源硬件爱好者的实战入门指南 在开源硬件社区里,Arduino项目的"eagle-files"文件夹常常让新手感到困惑又好奇。这些文件背后隐藏着一个强大的工具链——Autodesk Eagle,它是欧美开源硬件生态中PCB设计的通用…...

别再手撸流程图了!用Vue-super-flow + Element UI 10分钟搞定审批流原型

用Vue-super-flow Element UI快速构建企业级审批流原型 在企业内部管理系统中,审批流程是最常见的功能需求之一。传统的手工绘制流程图方式不仅效率低下,而且难以与业务系统无缝集成。现在,借助Vue-super-flow这一强大的Vue流程图组件&#…...

AI代理如何通过MCP协议实现DeFi自动化操作与策略执行

1. 项目概述:当DeFi遇上AI代理,Robocular/defi-mcp的诞生最近在捣鼓链上自动化策略和AI代理,发现了一个挺有意思的项目——Robocular/defi-mcp。简单来说,这是一个专门为AI代理(特别是那些基于MCP,也就是Mo…...

RedBox容器编排工具:在Docker与K8s间的轻量级生产实践

1. 项目概述与核心价值最近在折腾一个挺有意思的开源项目,叫Jamailar/RedBox。乍一看这个名字,你可能会联想到一个红色的盒子,或者某种特定的工具。实际上,它确实是一个“盒子”,一个用于构建、管理和部署容器化应用的…...

从玩具到工具:Dobot Magician桌面机械臂开箱与Blockly图形化编程初体验

从玩具到工具:Dobot Magician桌面机械臂开箱与Blockly图形化编程初体验 第一次见到Dobot Magician时,它安静地躺在包装箱里,像一件精致的工业艺术品。作为一款定位教育和个人创客市场的桌面级机械臂,它的价格只有工业机械臂的零头…...

NeumAI向量检索平台:构建生产级RAG应用的端到端Pipeline实践

1. 项目概述:从“Neum”到“AI”,一个向量检索系统的诞生最近在折腾RAG(检索增强生成)应用,发现向量检索这块的性能和成本,简直是决定项目成败的“命门”。自己从零开始搭一套,从数据清洗、向量…...

基于LLM与Playwright的智能网页自动化:Web-Use项目实战解析

1. 项目概述:一个能“看懂”网页的智能体 如果你也厌倦了那些重复、繁琐的网页操作——比如在不同电商平台比价、手动填写表单、或者从一堆搜索结果里筛选信息——那么今天聊的这个项目,你可能会非常感兴趣。它叫 Web-Use ,本质上是一个 …...