ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

JSP+SQL Server登录注册:环境配置、Servlet实现与常见故障排查

JSP+SQL Server登录注册:环境配置、Servlet实现与常见故障排查 简介这是一份基于JSP与SQL Server实现登录注册功能的完整案例包适合初学Java Web、希望理解用户认证流程的开发者。资源围绕数据库设计、JDBC连接、表单提交与处理、错误验证、会话管理及安全措施展开覆盖从建表到会话跟踪的常见闭环可直接导入Eclipse或IntelliJ IDEA运行调试。压缩包共46个文件约581KB其中包含28个JSP页面用于前端交互与业务逻辑另有Java源码、class文件、配置文件XML、classpath、project等以及jar依赖目录结构完整便于对照学习。已有835人学习下载口碑较佳。通过这份资源读者可以获得一套可运行的登录注册示例理解JSP如何通过JDBC操作SQL Server完成用户验证并掌握表单数据解析、密码安全处理以及session维持登录状态等关键技巧为后续开发更完整的Web系统打下基础。1. JSP SQL Server 登录注册为什么老项目还在用以及你该从哪下手拿到一个「JSP sqlserver 登录注册.zip」压缩包别急着解压。先想清楚你面对的是哪一类东西这大概率是某门课程设计、毕业设计或者老企业内部系统的源码包技术栈固定为 JSP Servlet SQL Server。它解决的需求很朴素——用户通过浏览器完成注册、登录、会话保持管理员能在后台看到用户列表。适合的人群也很明确正在做课设、刚接手老旧系统、或者想用最传统的方式把 Java Web 全链路跑通一遍的开发者。我要先给你一个反直觉的结论这种项目在今天依然值得跑通但它的价值不在「技术先进」而在「架构最小且完整」。JSP 直接被浏览器请求、Servlet 处理业务、JDBC 连 SQL Server没有 Spring、没有 MyBatis你反而能把 HTTP 请求、会话、SQL 事务这些底层的逻辑看得一清二楚。坏消息是这套东西对环境极其敏感JDK 版本、Tomcat 版本、SQL Server 的认证模式、JDBC 驱动版本任何一个不匹配登录注册页面就会变成白屏或者 500。这篇文章就沿着这条线先把理论立住再带你一步步把项目跑起来最后把常见的翻车现场挨个点名。2. 从 ZIP 到可运行解压之后先别急着开 IDE2.1 先看目录结构别让 Tomcat 教你做人拿到 ZIP 解压后第一件事不是双击打开 IDE而是先看目录。一个规范的 JSP 课设项目标准结构应该是这样的project-root/ ├── src/ # Java 源码存放 Servlet、DAO、JavaBean ├── web/ # Web 根目录 │ ├── WEB-INF/ │ │ ├── web.xml # Web 应用部署描述符 │ │ └── lib/ # JDBC 驱动等 JAR 包 │ ├── index.jsp # 登录页 │ ├── register.jsp # 注册页 │ ├── success.jsp # 登录成功页 │ └── css/ js/ images/ # 静态资源 └── database/ └── db.sql # 建库建表脚本如果你看到的 ZIP 里只有一堆 .jsp 文件和 .java 文件混在一起没有 web.xml也没有 src 和 web 的区分那这个项目要么是 Eclipse 老版本直接导出的 Web 项目要么是被人手动压缩的产物。这种混排结构在 IDEA 里也能跑但你需要手动配置源目录和 Web 根目录后面我会给具体步骤。这里要给新手一个建议不要直接把这个目录原封不动丢给 Tomcat。Tomcat 要求 Web 应用必须有标准的目录结构否则会报找不到 web.xml 或者声明式异常。先花五分钟理清结构能省掉后面两小时的排查。2.2 用 IDEA 导入项目的最小操作步骤我一般会建议用 IntelliJ IDEA 导入这种老项目因为它对 Web 应用的配置最直观。操作步骤如下第一步新建空项目不要直接 Open打开 IDEA选择 File → New → Project左侧选 Jakarta EE 或者 Java Enterprise右侧 Application Server 选你本机的 Tomcat。如果这里没有 Tomcat 选项先到 Settings → Build, Execution, Deployment → Application Servers 里添加。这一步的核心是让 IDEA 知道你要用哪个 Tomcat 来跑这个应用。第二步把解压内容拷进项目目录把 ZIP 里的 src 目录放入项目根目录web 目录里的内容放入 src/main/webapp。如果你的 ZIP 里没有这么好心的结构那就手动建目录把 .jsp 文件全部拖进 webapp把 .java 文件按包名拖进 src/main/java。第三步添加 JDBC 驱动依赖SQL Server 的 JDBC 驱动是 mssql-jdbc.jar。如果你在 WEB-INF/lib 下找到了就省事没有的话去微软官网下载 JDBC Driver for SQL Server然后把 jar 包放到 webapp/WEB-INF/lib 目录下IDEA 会自动识别为依赖。这一步非常关键因为很多 500 错误都是 ClassNotFoundException 引起的。第四步配置 Artifacts点 File → Project Structure → Artifacts点加号选 Web Application: Exploded然后把 Available Elements 里的项目资源拖到右边。这个步骤决定了 Tomcat 启动时加载哪个目录。很多新手卡在 Tomcat 启动了但访问 404八成是 Artifacts 没配。配置完成后点右上角的 Tomcat 运行按钮浏览器自动打开 http://localhost:8080/你的上下文路径/login.jsp。如果看到页面说明结构没问题接下来才进入数据库环节。2.3 三个必须提前确认的环境变量说句实话JSP 项目跑不起来十次有八次不是代码问题是环境问题。我按踩坑频率排序三个最关键的变量你需要确认JDK 版本。老项目多半是 JDK 1.7 或 1.8 编译的。如果你用的是 JDK 11 以上Tomcat 8.5 以下版本会直接启动失败报 UnsupportedClassVersionError 或者 NoClassDefFoundError。最稳妥的做法是装一个 JDK 1.8并且在 IDEA 的 Project Structure 里把 Project SDK 和 Module SDK 都指到 1.8。千万别指望高版本 JDK 向下兼容JSP 这种老技术栈对版本极其敏感这就是所谓的玄学但其实原因都在版本号上。Tomcat 版本。如果你的 ZIP 里自带 Tomcat 或者是用 Tomcat 9 配的那没问题。但如果你用的是 Tomcat 10 以上要注意Tomcat 10 把默认包名从 javax.servlet 换成了 jakarta.servlet。老项目代码里都是import javax.servlet.http.HttpServlet跑在 Tomcat 10 上会直接编译失败。这个坑我在接手老系统时踩过当时以为是代码损坏后来才发现是 Tomcat 大版本升级把包名换了。解决办法是换回 Tomcat 9或者全局把 javax 替换成 jakarta但后者改动量大不推荐。SQL Server 版本。SQL Server 2012 到 2019 之间JDBC 驱动的用法差异不大但连接字符串有些细节要注意比如是否启用 TCP/IP 协议、是否开启 SQL Server 认证。这些我们在下一章细说。3. 数据库脚本与连接配置登录注册的核心在这一层3.1 建库建表脚本字段设计决定后面的代码量登录注册功能的核心数据库对象无非是一张用户表。但字段怎么设计直接影响 DAO 层的代码复杂度。我见过不少课设代码把注册信息干脆塞了十来个字段然后 DAO 里写了几百行 insert看起来很努力其实没必要。一份最小可用的用户表脚本长这样CREATE DATABASE UserDB; GO USE UserDB; GO CREATE TABLE tb_user ( id INT IDENTITY(1,1) PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, email VARCHAR(100), reg_time DATETIME DEFAULT GETDATE() ); GO逻辑说明id用自增主键方便后续做用户列表和管理功能username必须唯一这会在注册时用到password字段长度设 100 而不是 50是因为后面如果要存 MD5 或 SHA-256 哈希值长度不够会报字符串截断错误reg_time用默认值省掉 Java 层手动传时间参数。这里有个血泪教训很多老代码里的密码字段只留了 20 个字符一旦你对密码做了 MD5 哈希32 位字符塞进去就被截断了注册时能过登录时永远对不上。不是因为算法写错而是字段长度没预留。执行脚本的方式建议用 SQL Server Management Studio 或者 sqlcmd 命令行。如果是 SQL Server 2019 以上版本用 SSMS 打开脚本直接执行即可。执行完确认一下表是否存在USE UserDB; SELECT name FROM sys.tables WHERE name tb_user;返回一行 tb_user 说明建表成功。注意如果你的 SQL Server 实例是全新安装的可能没开 SQL Server 认证模式这会影响 JDBC 连接下一节会讲怎么处理。3.2 JDBC 连接字符串四个参数就说清JSP 里连 SQL Server 的典型方式是在 DAO 类里写一个 getConnection 方法。常见的写法是import java.sql.Connection; import java.sql.DriverManager; public class DBUtil { private static final String DRIVER com.microsoft.sqlserver.jdbc.SQLServerDriver; private static final String URL jdbc:sqlserver://localhost:1433;DatabaseNameUserDB; private static final String USER sa; private static final String PASSWORD 你的密码; static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { throw new RuntimeException(加载 JDBC 驱动失败请检查 mssql-jdbc.jar 是否在 lib 目录); } } public static Connection getConnection() throws Exception { return DriverManager.getConnection(URL, USER, PASSWORD); } }参数说明DRIVER是微软 JDBC 驱动的全限定类名SQL Server 2000 时代是 jdbc.sqlserver.SQLServerDriver2005 之后换成 com.microsoft.sqlserver.jdbc.SQLServerDriver写错的话第 6 行的 Class.forName 就会抛 ClassNotFoundException。URL里的 localhost 换成远程服务器 IP1433 是 SQL Server 默认端口如果安装时改过端口要同步替换。DatabaseNameUserDB指定默认数据库注意这里的键名是 DatabaseName不是大写的 DB。USER和PASSWORD通常用 sa 账号前提是 SQL Server 开了混合认证模式。这里必须提醒一件经常被忽略的事Class.forName(DRIVER)在 JDBC 4.0 之后其实可以省略因为驱动 jar 里的 META-INF/services 会被自动加载。但老代码普遍带着这行留着也不影响只是报错的时候更直观——如果你看到 ClassNotFoundException第一反应应该是去检查 jar 包在不在。3.3 SQL Server 连不上的三大原因端口、协议、认证模式连接不上数据库是登录注册项目最常翻车的环节。现象都一样Tomcat 启动正常页面也能打开但一提交登录就报 Cannot create PoolableConnectionFactory 或者 Connection refused。我总结的排查顺序是先确认 TCP/IP 协议是否启用。SQL Server 安装后默认可能不启用 TCP/IP。打开 SQL Server 配置管理器找到「SQL Server 网络配置」→「MSSQLSERVER 的协议」右键 TCP/IP 选择启用然后重启 SQL Server 服务。很多杀毒软件或精简版安装包会把协议禁用这一条能解决一半的连接失败问题。再确认端口是否被防火墙挡住。在命令行执行telnet localhost 1433如果连接被拒绝去 Windows 防火墙里放行 1433 端口或者检查 SQL Server 是否改过端口。SQL Server 配置管理器里能看到实际监听的端口号默认 1433如果你装的是命名实例端口可能不是 1433那就要在 URL 里写端口。最后确认认证模式。用 sa 账号登录报「用户登录失败」那是因为 SQL Server 是 Windows 身份验证模式。在 SSMS 里右键服务器 → 属性 → 安全性选择「SQL Server 和 Windows 身份验证模式」然后执行ALTER LOGIN sa WITH PASSWORD 新密码; GO改了之后重启 SQL Server 服务才能生效。这一套走完数据库层基本就通了。3.4 字符串转数字和数据格式化SQL Server 里最容易踩的小坑登录注册功能里经常会有这样的需求根据用户名或 ID 查用户。如果用户名是纯数字字符串写 SQL 时容易犯一个错——把字符串隐式转换成数字。比如用户输入username 123你写了WHERE username 123SQL Server 会尝试把 username 列转成数字再比较。如果表里恰好有一行是 abc整个查询会直接抛转换异常。解决办法是写参数化查询Java 端用 PreparedStatement 的 setString 传参不要拼接 SQL。这不仅是防 SQL 注入的问题也是避免类型转换炸掉的问题。另外一个常见需求是把日期格式化显示在注册页或用户列表页。SQL Server 里用 CONVERT 函数SELECT username, CONVERT(VARCHAR(19), reg_time, 120) AS reg_time_str FROM tb_user;样式码 120 表示 yyyy-MM-dd HH:mm:ss 格式。在 JSP 页面用 EL 表达式输出时如果直接取 DATETIME 类型显示格式会带毫秒甚至时区尾巴很难看。我一般习惯在 SQL 层就转好JSP 那边永远拿到的是字符串省心。4. 登录与注册的 Servlet 实现把业务逻辑写对而不是写多4.1 注册的完整流程和必要校验注册功能的核心逻辑是接收表单参数 → 校验非空和格式 → 检查用户名是否已存在 → 插入数据库 → 跳转到登录页或提示错误。先看 Servlet 里的 doPost 方法protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); String username request.getParameter(username); String password request.getParameter(password); String email request.getParameter(email); if (username null || username.trim().isEmpty() || password null || password.trim().isEmpty()) { request.setAttribute(error, 用户名和密码不能为空); request.getRequestDispatcher(register.jsp).forward(request, response); return; } if (password.length() 6) { request.setAttribute(error, 密码长度不能少于6位); request.getRequestDispatcher(register.jsp).forward(request, response); return; } UserDAO dao new UserDAO(); if (dao.isUsernameExist(username)) { request.setAttribute(error, 用户名已被注册); request.getRequestDispatcher(register.jsp).forward(request, response); return; } User user new User(); user.setUsername(username); user.setPassword(password); user.setEmail(email); boolean ok dao.insertUser(user); if (ok) { response.sendRedirect(login.jsp); } else { request.setAttribute(error, 注册失败请稍后重试); request.getRequestDispatcher(register.jsp).forward(request, response); } }逻辑说明第一步setCharacterEncoding(UTF-8)是必须的不设置的话你从表单拿到的中文会乱码接着做基础校验这里只校验了非空和密码长度实际项目还可以加上邮箱格式校验用户名重复检查放在插入之前避免数据库抛唯一约束异常最后根据插入结果决定是重定向到登录页还是回到注册页显示错误信息。参数方面request.getParameter拿到的永远是字符串如果后续要传 ID需要自己处理 null 和空串不然 Integer.parseInt 会直接炸出 NumberFormatException 到页面上。4.2 登录的会话处理比「查出来就放行」多考虑三步登录逻辑看起来只要查数据库比对用户名密码但有三个细节不做后面一定出问题。第一密码存储问题。老项目里十有八九是明文存储直接WHERE username ? AND password ?。你要是交课设没问题但如果是给企业做建议至少做 MD5 加盐。常见做法是注册时password MD5(password salt)salt 可以简单用用户名或注册时间。登录时对输入的密码做同样计算再比对。这么做的好处是数据库泄露也不会直接暴露密码。第二会话失效时间。登录成功后代码里设置 sessionUser user dao.getUserByUsernameAndPassword(username, password); if (user ! null) { HttpSession session request.getSession(); session.setAttribute(user, user); session.setMaxInactiveInterval(1800); // 30分钟无操作自动失效 response.sendRedirect(success.jsp); } else { request.setAttribute(error, 用户名或密码错误); request.getRequestDispatcher(login.jsp).forward(request, response); }setMaxInactiveInterval很关键。不设置的话Tomcat 默认是 30 分钟但有些老系统 Tomcat 配置里会改成永久有效带来安全隐患。设置成 1800 秒也就是半小时是行业常见做法。第三JSP 里的会话判断。受保护页面开头必须检查 session 里有没有 user 对象% Object user session.getAttribute(user); if (user null) { response.sendRedirect(login.jsp); return; } %这行代码放在页面最顶部放在 HTML 标签之前否则页面会闪一下才跳转。这是老 JSP 项目防止未登录直接访问的通用做法简单粗暴但有效。如果你想让代码更规范一点可以把这个检查抽到 Filter 里但课设项目里写在 JSP 顶部完全够用。4.3 用户列表查询把多行合并和排序放在 SQL 里别在 Java 里折腾登录注册之后往往会附带一个用户列表页管理员能看到所有注册用户。常见需求是按注册时间排序用一条 SQL 就能搞定SELECT id, username, email, CONVERT(VARCHAR(19), reg_time, 120) AS reg_time_str FROM tb_user ORDER BY reg_time DESC;如果还要支持按关键字搜索就加 WHERE 条件SELECT id, username, email, CONVERT(VARCHAR(19), reg_time, 120) AS reg_time_str FROM tb_user WHERE username LIKE ? ORDER BY reg_time DESC;这里要用PreparedStatement的setString(1, % keyword %)千万别拼字符串。另外 SQL Server 的 LIKE 默认大小写不敏感对用户名搜索来说这通常是合理的行为。关于多行合并成一行SQL Server 里有别于 MySQL 的 GROUP_CONCAT它用的是 FOR XML PATH 或者 STRING_AGGSQL Server 2017 以上。如果你的列表页需要展示某个用户的多个角色或标签可以直接在 SQL 层合并SELECT u.id, u.username, STUFF(( SELECT , role_name FROM user_role ur WHERE ur.user_id u.id FOR XML PATH()), 1, 1, ) AS roles FROM tb_user u;这条写法的原理是用子查询把多行拼成一行STUFF 去掉开头的逗号。但说实话登录注册这个场景很少用到多行合并我列出来是想提醒你需要做是从数组角度想而不是拿到 Java 里用循环拼字符串后者性能差且代码丑。4.4 用户退出登录一句话但比你想的重要退出功能经常被当成凑数功能写就一句话protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session request.getSession(false); if (session ! null) { session.invalidate(); } response.sendRedirect(login.jsp); }逻辑说明request.getSession(false)表示如果当前没有 session 就返回 null而不是创建一个新的。直接调用invalidate()销毁 session所有登录状态清空。之后重定向回登录页。注意这里用sendRedirect不是forward因为 forward 保持同一个请求用户刷新页面时可能重复执行退出逻辑。5. JSP 页面细节与前端配合登录注册页的四个必调参数5.1 表单提交方式和编码post UTF-8 是底线登录注册页的 form 标签是最容易被忽略的地方。我见过好多次前端页面长得很正常一提交就乱码或者参数丢失最后才发现表单属性写错了。form actionregister methodpost accept-charsetUTF-8 label forusername用户名/label input typetext idusername nameusername required maxlength50 label forpassword密码/label input typepassword idpassword namepassword required minlength6 label foremail邮箱/label input typeemail idemail nameemail button typesubmit注册/button /form参数说明action写 Servlet 的 URL 映射路径注意是 web.xml 里配的url-pattern或者注解里的值不是文件名。methodpost必须写上GET 会把密码暴露在地址栏而且浏览器对 URL 长度有限制。accept-charset设置表单的编码格式配合 Servlet 里的setCharacterEncoding(UTF-8)才能保证中文不乱码。required和minlength是 HTML5 的浏览器端校验能在提交前拦截一部分无效数据但服务端校验不能省。5.2 错误提示的显示方式区分「后端返回」和「前端校验」老 JSP 项目最常见的错误提示做法是在 Servlet 里设置了 request attribute然后在 JSP 里用 EL 表达式输出%-- register.jsp 顶部 --% % page contentTypetext/html;charsetUTF-8 languagejava % html body % String error (String) request.getAttribute(error); if (error ! null) { out.println(p classerror error /p); } % form actionregister methodpost accept-charsetUTF-8 ... /form /body /html这里有一个细节request.getAttribute和session.getAttribute的差别。如果你在 Servlet 里用的是request.setAttribute那么页面直接刷新时错误提示会丢——因为刷新是重新发起 GET 请求不经过 Servlet 的 doPost。如果你用了response.sendRedirect跳转回来那 request 里的 attribute 更是完全没了。这种情况下要么改用 session attribute要么用 forward 跳转回页面。很多老代码在这里用了一个偷懒的做法直接在 JSP 里写 Java 代码判断错误。这在 JSP 2.0 之前很常见今天看来虽然不优雅但能跑。如果你接收的是课设代码大概率就是这样写的不要急着改成 EL先跑通再说。5.3 图片与坐标定位注册页美化时容易忽略的资源路径问题热词里有「jsp图片如何对坐标定位」这在登录注册页面里也碰得到——比如你要在注册页放一个带二维码的推广图或者给表单加一个背景图。JSP 里图片路径是最容易出 bug 的如果你在 webapp/images/logo.png 放了一张图在 login.jsp 里写img srcimages/logo.png那么当 Servlet 转发到 JSP 时浏览器的相对路径基准是当前 URL 的路径不是 JSP 文件所在的路径图片很可能 404。最常见的解决方式是使用绝对路径% String basePath request.getContextPath(); % img src%basePath%/images/logo.png altlogorequest.getContextPath()返回应用的上下文路径比如/myapp这样图片路径无论页面是通过 forward 还是 sendRedirect 打开的都能正确加载。如果你要给图片做精确定位比如把 Logo 固定在表单右上角用 CSS 绝对定位.logo { position: absolute; top: 20px; right: 30px; z-index: 10; }这里的坐标top和right是相对最近的有 position 定位的父元素。我说实话JSP 本身跟坐标定位一毛钱关系都没有它只是 HTML 的模板容器你用什么 HTML 技术它都支持。但为什么这个问题经常被搜因为 JSP 引入静态资源时路径容易写错导致图片显示位置不对看起来就像「定位出了问题」实际是路径问题。5.4 加载完后刷新一次防止重复提交的土办法热词里有一条「jsp页面让加载完后刷新一次」这事在登录注册里对应的实际场景是用户注册成功后你给他sendRedirect到 success.jsp他按 F5 刷新结果浏览器提示「要重新发送表单信息吗」如果点确认就重复插入了一条用户记录。防止重复提交的常见办法有三层一是注册成功后立刻sendRedirect因为重定向是新的 GET 请求刷新不会重新提交 POST 数据二是在 Servlet 里加一个 token 机制注册页生成一个随机 token 存在 session 里提交时比对比对过就清掉第二次提交 token 为空直接拒绝三是在 success.jsp 顶部加一段 JSif (performance.navigation.type 2) { location.reload(); }这段代码的含义是如果当前页面是通过浏览器的前进/后退按钮进入的就强制刷新一次拿到最新的页面状态。它解决不了 POST 重复提交的问题但能避免用户看到过期数据。我个人的建议是用 sendRedirect 兜底 90% 的重复提交问题token 机制解决剩下的 10%前端 JS 那层属于安慰剂可加可不加。6. JSP SQL Server 登录注册避坑与常见问题排查6.1 ClassNotFoundException驱动包在但 Tomcat 就是找不到现象页面访问正常点登录后报 java.lang.ClassNotFoundException: com.microsoft.sqlserver.jdbc.SQLServerDriver。原因分析最常见的是 jar 包放在了项目根目录而不是 WEB-INF/lib 下。IDEA 里还有一种隐蔽情况Artifacts 没有把 lib 目录包含进去导致启动 Tomcat 时虽然工程能看到 jar但 Web 应用运行时 ClassLoader 加载不到。解决检查 jar 是否在webapp/WEB-INF/lib/下然后在 IDEA 的 Project Structure → Artifacts 里确认 Output Layout 的 WEB-INF/lib 列表里有这个 jar。如果没有右键 jar 选择 Put into /WEB-INF/lib。改完重新 Build重启 Tomcat。6.2 无法找到数据库引擎启动句柄SQL Server 服务没起来现象SQL Server 2016/2017/2019 安装后你在 SSMS 里能建库但过一段时间连接时提示「无法找到数据库引擎启动句柄」。原因分析这多半是 SQL Server 服务没有正常启动或者安装过程没把服务设为自动启动。出现这个提示的时候去 Windows 服务管理里看 SQL Server 服务状态通常是「已停止」。解决按 WinR 输入services.msc找到 SQL Server (MSSQLSERVER) 服务右键启动并设置为自动启动。如果启动时报错去 SQL Server 配置管理器里检查协议是否启用再去看系统日志里有没有错误详情。这跟 JDBC 没关系纯粹是数据库服务层的问题。6.3 数据库连接超时或 Connection refused定位三个位置现象Tomcat 启动正常但一执行到 getConnection 就报 Cannot connect to SQL Server。原因分析连接失败通常的三个位置我都见过数据库服务没启动、端口被防火墙拦截、连接字符串主机名或端口写错。还有一种少见原因SQL Server 是命名实例默认监听动态端口没启用 TCP/IP 时 JDBC 根本连不上。解决按这个顺序排查第一SQL Server 配置管理器里确认 TCP/IP 已启用并监听 1433第二命令行执行netstat -ano | findstr 1433看端口是否在监听第三防火墙放行第四把连接 URL 改成jdbc:sqlserver://127.0.0.1:1433;DatabaseNameUserDB用 IP 而不是 localhost避免 DNS 解析问题。6.4 登录时中文乱码三层编码缺一不可现象用户名或邮箱里如果带中文注册成功后再登录永远失败数据库里存的是一堆问号或乱码。原因分析JSP 页面的编码、Servlet 的请求编码、数据库表的字符集三层任何一层不一致就会乱码。老项目里 JSP 页面头部没写contentType或者写了 ISO-8859-1中文必然乱码。解决JSP 页面顶部统一写成% page contentTypetext/html;charsetUTF-8 languagejava %Servlet 里 doPost 开头加request.setCharacterEncoding(UTF-8)数据库建库时指定字符集。SQL Server 的建库语法是CREATE DATABASE UserDB COLLATE Chinese_PRC_CI_AS;这个排序规则支持中文存储。注意如果你是在现有库上改字符集要重新建表因为表的排序规则在建表时就定了。6.5 无法将 varchar 转换为 int类型隐式转换的坑现象执行查询时SQL Server 报 Conversion failed when converting the varchar value abc to data type int。原因分析你写的 SQL 里可能有一个字符串参数被 SQL Server 隐式转换成数字去跟某列比较。典型场景是WHERE username 123而 username 列类型是 varchar但表里存在非数字字符串时SQL Server 会尝试把整列转成 int然后炸掉。还有一种场景是 id 用字符串传参虽然这个不会报错但会浪费一次索引扫描。解决所有传参都用 PreparedStatement 的 setString 或者 setInt确保 SQL 里不要出现隐式类型转换。对已有的脏数据可以用 ISNUMERIC 函数过滤SELECT * FROM tb_user WHERE ISNUMERIC(username) 1 AND CAST(username AS INT) 100;但这种写法性能差只适合修数据不适合做业务查询。7. 进阶用法给老登录注册项目加上 SQL Server 预编译与安全加固跑到这一步你的项目应该已经能正常注册、登录、保持会话了。接下来值得做的是把「能用」变成「耐打」我给三个性价比最高的进阶方向。第一个PreparedStatement 全面替代 Statement。老代码里如果还有Statement.executeQuery拼接 SQL 的地方全部换成预编译写法。SQL Server 对 PreparedStatement 的执行计划复用效果很显著在用户名检索这种重复操作上能明显降低 CPU 开销。具体代码就是把createStatement()换成prepareStatement(sql)参数用setString填充改动量不大收益很直接。第二个给用户名列加索引。登录注册场景最频繁的查询就是WHERE username ?如果用户表数据量涨到十万级全表扫描的代价开始明显。建索引一句话CREATE INDEX idx_username ON tb_user(username);如果你的用户名设了 UNIQUE 约束其实索引已经隐式存在了不需要重复建。但如果你为了兼容老数据没设唯一约束这条索引能救回不少查询性能。第三个用 Filter 统一处理编码和未登录跳转。与其在每个 JSP 页面顶部粘贴那一段 session 判断代码不如写一个 Filterimport javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; WebFilter(urlPatterns {/success.jsp, /user/*}) public class AuthFilter implements Filter { Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req (HttpServletRequest) request; HttpSession session req.getSession(false); if (session null || session.getAttribute(user) null) { ((HttpServletResponse) response).sendRedirect(req.getContextPath() /login.jsp); return; } chain.doFilter(request, response); } }逻辑说明Filter 拦截指定的 URL 模式检查 session 里有没有用户对象没有就重定向到登录页。这样做的好处是新增受保护页面时不需要改动任何 JSP只要在urlPatterns里追加路径即可。Tomcat 9 支持WebFilter注解不用在 web.xml 里写一堆 filter-mapping。最后我说个自己的习惯每改完一个功能我会在 SQL Server Management Studio 里打开 Profiler 或者执行SET STATISTICS TIME ON来确认最耗时的 SQL 是查询还是连接建立。登录注册这种项目数据库压力不大但连接池如果没配每次请求都新建物理连接到并发高了会很惨。如果需求上来了你可以把 DBUtil 换成 HikariCP 连接池几行配置的事但那是下一步的事了。希望这篇笔记能帮你把这个 ZIP 从「解不开的压缩包」变成「能跑、能改、能交差」的项目。老技术栈没有死它只是把原理摊开放在你面前。本文还有配套的精品资源点击获取
返回列表