ARTICLE DETAIL

资讯详情

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

2023版IDEA创建JavaWeb项目全流程:从环境配置到Servlet+JSP+MySQL实战

2023版IDEA创建JavaWeb项目全流程:从环境配置到Servlet+JSP+MySQL实战 我整理这份JavaWeb笔记的时候正好有个学弟问我“2023版IDEA到底怎么创建JavaWeb项目”他说网上教程东一榔头西一棒子跟着做总是卡壳。我想了想干脆把从环境搭建到第一个程序跑通的完整过程写下来顺便把Servlet、JSP、MySQL连接这些核心知识点串一遍。这份笔记适合刚学完JavaSE、准备进入Web开发阶段的同学也适合那些被各种碎片教程折磨得晕头转向的自学者。你不需要有很深的功底只要Java基础语法过关能看懂简单的SQL就能跟着一步步把JavaWeb项目跑起来。我先把丑话说在前面JavaWeb这块内容网上资料多但杂很多教程还停留在Eclipse时代用的还是老版IDEA界面。这篇笔记我以2023版IntelliJ IDEA为例结合黑马程序员那套非常经典的课程体系来写但我会把思路讲透让你换个IDE、换个版本也能自己搞定这才是真正重要的能力。1. JavaWeb到底是什么以及为什么你绕不开它1.1 从静态页面到动态交互一段必要的认知铺垫先说个我在教学中反复强调的观点JavaWeb不是一门“新语言”而是一整套用Java解决Web开发问题的技术组合。很多初学者被“JavaWeb”这四个字吓住觉得它是一座大山但实际上拆开看它就是Java语言在网络编程、数据库操作、前端交互这些场景下的综合应用。理解JavaWeb最好的切入点是先搞清楚它解决了什么问题。你打开一个网页看到的可能是静态的HTML页面这种页面写死了内容十个人访问看到的东西一模一样。但如果你打开购物网站每个人看到的购物车、推荐列表、订单状态都不同这就是动态页面。动态页面意味着服务器端需要根据不同的请求去查数据库、做计算、拼HTML最后把结果返回给浏览器。JavaWeb干的就是这件事。从技术栈来看JavaWeb是一个典型的“全家桶”组合前端部分HTML、CSS、JavaScript负责页面展示和用户交互后端部分Servlet、JSP现在JSP已经逐渐被前端模板或前后端分离替代但学习阶段还是建议了解、Filter、Listener服务器部分Tomcat最常用的Servlet容器数据库部分MySQL JDBC或者MyBatis等框架工程化部分Maven项目构建和依赖管理工具新版IDEA创建项目时核心依赖它这套组合就是你后面学习Spring Boot、Spring Cloud这些企业级框架的基础。我经常跟学生打比方JavaWeb是摆地摊Spring Boot是开店。地摊虽然简陋但进货、摆摊、吆喝、收钱的全流程你都亲手做过后面开店只是把这套流程标准化、规模化而已。如果直接上来学Spring Boot你会发现很多东西都是“黑盒”出了问题完全不知道怎么排查。1.2 为什么Tomcat是绕不开的那道坎在JavaWeb的世界里Tomcat的地位相当于“网页的容器”。你写好的Servlet类本质上是一个Java类但它不能独立运行必须放到Tomcat这个容器里由Tomcat负责接收浏览器的请求、创建Servlet实例、调用Servlet方法、把结果返回给浏览器。这里我想多聊几句Tomcat的工作原理因为这对你理解后续的很多操作都有帮助。Tomcat本身是用Java写的所以运行它要求你的机器上已经装好JDK。当你通过IDEA把一个Web项目部署到Tomcat上时实际上做的是三件事把项目的Web目录打成war包或直接发布到Tomcat的webapps目录、启动Tomcat进程、监听8080端口。我见过太多初学者卡在这几个环节要么是JDK环境变量没配好Tomcat启动报错要么是8080端口被其他程序占用了页面一直打不开要么是项目部署路径配置错了访问的时候404。这些都不是什么高深的问题但确实很磨人。这篇笔记里我会把每个坑都踩一遍给你看你就不会再怕了。2. 环境准备把2023版IDEA配到“开箱即用”的状态2.1 JDK安装与配置最基础也最容易出错的一步我一直认为JDK的安装和配置是JavaWeb开发的第一道关卡也是很多初学者的“分手关”。明明代码写得没问题环境一配就是一上午心态直接崩掉。其实这里面的逻辑很简单你只要理解了三个关键词就不会再配错JAVA_HOME、PATH、CLASSPATH。JAVA_HOME是告诉系统“JDK装在哪儿”的指针PATH是让你在命令行里直接输入java、javac就能找到可执行文件CLASSPATH是告诉JVM“类库在哪儿找”。对于现代JDK8及以上CLASSPATH其实不需要手动配置了JVM会自动查找所以初学者只需要配好JAVA_HOME和PATH就足够了。具体操作是这样的去官网这里要特别注意别随便在第三方网站下载JDK最好去Oracle官网或者国内大厂的镜像站下载JDK推荐JDK 8或者JDK 11这两个版本最成熟稳定企业用的多教程也多对初学者最友好。下载的是一个安装包双击安装记住安装路径比如C:\Program Files\Java\jdk-11.0.18。安装完成后打开系统环境变量设置Win10/11右键“此电脑” - “属性” - “高级系统设置” - “环境变量”新建一个系统变量变量名填JAVA_HOME变量值填你的JDK安装路径。然后在Path变量中新增一行%JAVA_HOME%\bin。注意配置完环境变量后必须重新打开命令行窗口才能生效。检查是否配置成功在命令行输入java -version如果出现版本信息就说明搞定了。我见过有人配置完后不重开终端一直报“不是内部或外部命令”其实就是一个很低级的疏忽。2.2 Tomcat的下载与IDEA集成绑定接下来是Tomcat。Tomcat的版本要和JDK版本匹配这一点很多人会忽略。比如JDK 8对应Tomcat 9.xJDK 11对应Tomcat 10.x不过Tomcat 10把包名从javax.servlet改成了jakarta.servlet和很多老教程对不上所以新手我建议直接用Tomcat 9配合JDK 8最丝滑。去Apache官网下载Tomcat 9的zip压缩包解压到一个没有中文和空格的路径下比如D:\apache-tomcat-9.0.83。解压后目录结构大致是bin启动和关闭脚本、conf配置文件核心是server.xml、libTomcat运行所需的jar包、webapps部署应用的地方、logs日志文件。我建议你先不急着用IDEA直接进bin目录双击startup.bat启动一次试试。启动成功后浏览器访问http://localhost:8080能看到Tomcat的默认首页就说明环境没问题。这里有个小细节启动窗口如果一闪而过多半是JAVA_HOME没配好双击startup.bat的时候系统找不着Java环境。这时候去logs目录看日志比瞎猜效率高得多。IDEA集成Tomcat就更简单了。打开IDEA进入Settings - Build, Execution, Deployment - Application Servers点加号选Tomcat Server把Tomcat的安装路径指过去IDEA会自动识别版本。这一步做完你的开发环境就算“通电”了。2.3 为什么我不建议你现在就去研究Maven新版IDEA创建JavaWeb项目时经常会遇到Maven的问题。Maven是一个项目管理和构建工具它的核心作用是帮你管理第三方jar包依赖不用再手动把jar包一个个下载下来扔到lib目录里。我看到很多初学者在环境准备阶段就被Maven劝退了其实这完全没必要。创建项目如果选择Maven骨架IDEA会自动帮你生成一个pom.xml文件你只需要在这里面声明需要什么库比如MySQL驱动、JSTL标签库Maven就会自动下载并关联到项目里。这个过程第一次会比较慢因为要下载很多插件和依赖是正常现象不要以为卡死了。如果你用的是2023版IDEA创建项目时选Maven Archetype然后选择org.apache.maven.archetypes:maven-archetype-webapp这个骨架IDEA就会帮你生成一个带web.xml的标准Web项目结构。我有必要提醒你IDEA内置的Maven版本可能和你系统里装的不一致但没关系IDEA自带的Maven就能用初学者完全没必要单独装一个Maven徒增烦恼。3. 创建你的第一个JavaWeb项目手把手实操3.1 从新建项目到目录结构看清每一层的作用现在进入正题我用2023版IDEA如果你用的版本稍有不同界面文字可能有点变化但逻辑是一样的带你走一遍创建流程。第一步打开IDEA点击New Project。左侧选择Maven勾选Create from archetype在列表里找到org.apache.maven.archetypes:maven-archetype-webapp。这一步很关键这个骨架会生成一个标准的Web项目结构省去你手动创建一堆目录的麻烦。第二步填写GroupId和ArtifactId。GroupId一般填公司域名倒写比如com.exampleArtifactId填项目名比如javaweb-demo。这俩概念不用背你就理解成给项目起个唯一身份证就行。填完后设置项目的存储路径点FinishIDEA就开始自动创建项目并下载Maven依赖了。等右下角进度条跑完你会看到这样一个目录结构javaweb-demo ├── pom.xml ├── src │ └── main │ ├── resources │ └── webapp │ ├── WEB-INF │ │ └── web.xml │ └── index.jsp项目根目录下的pom.xml是Maven的配置文件src/main/java骨架可能不会自动创建需要手动建一个放你的Java源码src/main/resources放配置文件src/main/webapp是Web根目录放JSP、HTML、CSS、JS等前端资源和WEB-INF目录。WEB-INF目录下的web.xml是Web项目最核心的配置文件在JavaEE规范中叫“部署描述符”。早期版本的Servlet需要在web.xml里配置映射关系Servlet 3.0之后虽然可以用注解代替但web.xml依然存在它是Web容器识别你的项目合法性的标志。注意WEB-INF目录下的文件浏览器是访问不到的这是Servlet容器的一种安全机制。你的JSP页面如果放在WEB-INF里就必须通过服务器端跳转来访问适合放一些需要权限控制的页面。平时练习的时候JSP直接放webapp根目录下就行。3.2 配置Tomcat并部署项目这一步通了整个项目就活了一半项目创建好了还是“死”的得把它部署到Tomcat里跑起来才知道行不行。点击IDEA顶部工具栏右侧的Add Configuration一个下拉框写着“Add Configuration...”然后点左上角加号找到Tomcat Server - Local。在Server选项卡里如果前面已经把IDEA和Tomcat绑定好了这里应用服务器会自动关联Deployment选项卡里点加号选Artifact把项目添加进去。Application context可以改成/访问时直接http://localhost:8080即可不需要加路径或者保留默认的/javaweb-demo_war_exploded访问时需要带上一段长路径。这里我想展开聊一下war和war exploded的区别因为几乎每个新手都会困惑。war是打包好的压缩包部署的时候Tomcat会解压它再运行war exploded是“展开”的不是打包的目录结构开发时用这个模式最方便因为修改代码后IDEA可以快速把变更的文件同步到Tomcat的部署目录支持热部署不用每次改一行代码就重启服务器。配置好之后点右上角的绿色三角形运行按钮。IDEA会启动Tomcat在浏览器里自动打开一个页面如果你没设置默认浏览器需要自己手动访问http://localhost:8080/index.jsp。看到Hello World!的JSP页面恭喜你你的第一个JavaWeb项目已经跑起来了。3.3 热部署这个小功能能帮你节省大量无谓的等待时间很多人在开发时有个坏习惯改一行代码重启一次Tomcat。改一个前端页面还好如果改了Java代码重启Tomcat可能要等好几秒甚至十几秒时间一长整个人的心气儿就没了。IDEA实际上提供了“热部署”功能就在Tomcat配置的Server选项卡里。On Update action和On frame deactivation这两个选项前者是“手动更新时干什么”后者是“IDEA窗口失去焦点比如你切回浏览器时干什么”。我通常把两者都设为Update classes and resources这样修改Java代码后按CtrlF10或者直接从IDEA切到浏览器变更就会被自动同步不需要重启Tomcat。不过这个功能有一个限制它只能更新方法内部的内容。如果你改了方法的签名比如加参数、改返回值类型、新增了类、或者改了web.xml配置热部署就不管用了必须重启。这个道理也不难理解方法内部的字节码可以动态替换但类的结构变了JVM需要重新加载类这必须重启容器才能完成。4. ServletJavaWeb的“心脏”你必须亲手写一遍4.1 从生活场景理解Servlet的生命周期假如你现在已经在Tomcat上部署了项目也看到了JSP页面但这还不算真正进入JavaWeb开发因为你还没亲手写过Servlet。Servlet是JavaWeb最核心的组件没有之一理解了Servlet你后面学Spring MVC就轻松很多。Servlet本质上是一个Java类它是怎么被Tomcat“接客”的呢我们可以用一个生活化的类比Tomcat就像一个酒店的前台Servlet就是酒店里的服务员。一个客人浏览器请求来了前台Tomcat会叫一个服务员Servlet实例来接待。服务员不是客人来了才现招的而是酒店里早就备好的——Servlet在第一次被访问或者容器启动的时候就已经创建好了后面所有客人都共用这一个服务员。这个类比可以帮助你理解Servlet的生命周期。Servlet的完整生命周期由三个方法定义init()Servlet被创建时调用只调用一次。就像服务员入职时的培训只做一次后面直接上岗。service()每次请求都会调用是所有请求的入口。在这里根据请求的HTTP方法GET、POST等决定调用doGet还是doPost。destroy()Servlet被销毁时调用只调用一次。比如Tomcat关闭的时候给服务员发“离职通知”。很多人不理解“Servlet单实例多线程”这个概念。默认情况下Tomcat只会为一个Servlet创建一个实例对象但会有多个线程同时调用这个实例的service()方法。这意味着你的Servlet存在线程安全问题——如果在Servlet里定义了成员变量并对其进行修改多个线程同时访问时就会产生数据混乱。实战建议不要在Servlet里使用成员变量来存储请求相关的数据一律使用局部变量或者把数据存在request、session域对象里。这个问题在面试里也是高频考点每次问必倒一片。4.2 手写第一个Servlet并完成请求转发与重定向现在我们来写第一个Servlet。在src/main/java下建包com.example.servlet新建一个类HelloServlet.javapackage com.example.servlet; 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(/hello) public class HelloServlet extends HttpServlet { Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType(text/html;charsetUTF-8); resp.getWriter().write(h1Hello JavaWeb!/h1); } Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }注意第12行的WebServlet(/hello)这是Servlet 3.0引入的注解式配置作用和在web.xml里写servlet标签完全一样都是把/hello这个URL路径和这个Servlet类绑定起来。如果你用的是Tomcat 9及以下版本用javax.servlet包名要是换成Tomcat 10就变成了jakarta.servlet写代码时导入的包名对应不上就会编译报错。启动项目浏览器访问http://localhost:8080/hello应该能看到大标题Hello JavaWeb!。如果看到404多半是URL路径对不上检查一下注解里的路径和访问地址是否一致这是最常见的问题。接下来聊两个在开发中天天用到的知识点请求转发和重定向。**请求转发forward**是服务器内部的跳转浏览器地址栏不会变化整个过程只发起一次请求。代码写法是req.getRequestDispatcher(/index.jsp).forward(req, resp)。这种行为像是部门没处理完把活给另一个同事客户浏览器完全不知道换了人。**重定向redirect**是服务器告诉浏览器“你别找我了去这个新地址”浏览器会重新发起一次新的请求。代码写法是resp.sendRedirect(/index.jsp)地址栏会变成新地址整个过程有两次请求。我当年学这两个概念时也迷糊过后来找到一个记忆方法转发是“代办”重定向是“转告”。你要办事转发是办事员帮你直接搞定你不用动重定向是办事员告诉你“你走错门了去隔壁”你得自己再跑去隔壁。在实际开发里表单提交后保存数据、操作成功要跳转页面一般用重定向这样可以避免刷新页面时表单重复提交在Servlet里查询出数据后要带着数据去渲染一个JSP页面一般用转发。4.3 请求域、会话域和应用域数据到底该放哪?Servlet里经常需要在一个请求的不同组件之间传递数据或者在一个用户的多次请求之间保持状态。这种数据的“暂存地”称为域对象JavaWeb中有三个最常用的域request域一次请求之内有效请求转发时也能带过去。适合放查询结果、表单参数等一次性的数据。session域同一个用户浏览器的多次请求之间有效默认30分钟过期。适合放登录状态、购物车等会话级数据。application域 / ServletContext整个应用只有一份所有用户共享。适合放全局配置、访问计数等数据。我见过一个典型的初学者错误把用户登录信息放request里但用户刷新一下页面就丢了于是觉得“JavaWeb真难”。其实不是难是你没选对域。登录信息是跨请求、同会话的放到session里才对。这三个域总结成一句话能用request就不要用session能用session就不要用application。域开得越大数据生命周期越长内存占用越高出现混乱和安全隐患的概率也越大。5. JSP与数据交互让Web页面“活”起来5.1 创建你的第一个动态JSP页面JavaWeb传统模式中JSP负责展示数据。JSP的全称是Jakarta Server Pages以前叫JavaServer Pages本质上是一个“能写Java代码的HTML页面”。Tomcat会把JSP翻译成一个Servlet对它本身就是一个Servlet然后执行后生成HTML返回给浏览器。在src/main/webapp下新建一个login.jsp我来演示怎么把Java代码嵌进页面% page contentTypetext/html;charsetUTF-8 languagejava % html head title登录页/title /head body % String message (String) request.getAttribute(message); if (message ! null) { % p stylecolor:red;% message %/p % } % form action/login methodpost 用户名input typetext nameusernamebr 密码input typepassword namepasswordbr input typesubmit value登录 /form /body /html注意开头的% page %指令它定义了这个JSP页面的属性比如字符集、语言、是否允许使用session等。% %里面写的是Java脚本片段scriptlet% %则是输出表达式相当于Java里的out.print()。这里我要由衷地建议你JSP里的Java代码越少越好。早期的项目会在JSP里写大量业务逻辑结果页面和Java代码纠缠在一起改个业务逻辑要在HTML标签里翻半天Java代码维护起来简直要命。规范的做法是Servlet负责接收请求、调用业务逻辑、获取结果然后把结果存到request里再转发到JSPJSP里只负责用EL表达式或JSTL标签把数据显示出来。5.2 Servlet JSP JDBC完成一个完整的登录功能现在到了这篇文章的重头戏用Servlet JSP JDBC MySQL做一个小而完整的登录功能。这个例子虽然没有用到框架但麻雀虽小五脏俱全你能看清一条数据从前端表单到后端处理再到数据库的完整链路。首先准备MySQL数据库。你已经建好了javaweb_demo库执行下面的SQL建表CREATE TABLE user ( id int NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL, password varchar(50) NOT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; INSERT INTO user (username, password) VALUES (admin, 123456);然后写一个工具类DBUtils来拿数据库连接package com.example.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DBUtils { private static final String URL jdbc:mysql://localhost:3306/javaweb_demo?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingUTF-8; private static final String USERNAME root; private static final String PASSWORD 你自己的密码; static { try { Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USERNAME, PASSWORD); } }这里有两个容易踩的坑一是使用MySQL 8.x以上版本驱动类是com.mysql.cj.jdbc.Driver注意中间多了cj老教程里写的com.mysql.jdbc.Driver会报ClassNotFoundException二是连接URL里必须加上serverTimezoneAsia/Shanghai否则会报时区错误这也是很多新手第一次连数据库时最常见的报错。接着在pom.xml里添加MySQL驱动依赖dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency然后写登录的Servlet和Servlet里的逻辑package com.example.servlet; import com.example.util.DBUtils; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.*; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; WebServlet(/login) public class LoginServlet extends HttpServlet { Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username req.getParameter(username); String password req.getParameter(password); try (Connection conn DBUtils.getConnection(); PreparedStatement ps conn.prepareStatement( SELECT * FROM user WHERE username ? AND password ?)) { ps.setString(1, username); ps.setString(2, password); try (ResultSet rs ps.executeQuery()) { if (rs.next()) { HttpSession session req.getSession(); session.setAttribute(username, username); resp.sendRedirect(/success.jsp); } else { req.setAttribute(message, 用户名或密码错误); req.getRequestDispatcher(/login.jsp).forward(req, resp); } } } catch (SQLException e) { e.printStackTrace(); req.setAttribute(message, 系统异常请稍后再试); req.getRequestDispatcher(/login.jsp).forward(req, resp); } } }这个例子虽然简单但包含了几个重要的开发规范第一使用PreparedStatement而不是Statement。用?占位符替代拼接字符串可以有效防止SQL注入攻击。如果你没见过SQL注入想象一下用户在密码框里输入 OR 11如果用字符串拼接SQL就变成了SELECT * FROM user WHERE username admin AND password OR 11后面永远为真直接就能登录成功。PreparedStatement用预编译参数绑定从根源上杜绝了这个问题。第二用try-with-resources自动关闭资源。Java 7之后实现了AutoCloseable接口的资源Connection、PreparedStatement、ResultSet放在try的括号里声明代码块结束时会自动调用close()方法。这是防止连接泄漏的最有效手段。很多人初学JDBC时习惯手动close一忙起来就忘了关ResultSet或PreparedStatement埋下连接数耗尽的隐患。第三密码不能明文存储在数据库。这个Demo为了简洁用了明文密码真实项目中必须用MD5加盐或BCrypt等算法对密码加密存储否则数据库一旦泄露用户密码全部暴露。这一点我在教学时一定会强调哪怕Demo再简陋安全意识要从第一天养成。5.3 JSP里的EL表达式和JSTL数据展示的正确姿势JSP脚本% %虽然能干活但页面里嵌了大量Java代码会非常丑陋。规范的JavaWeb开发应该用EL表达式Expression Language和JSTL标签库来替代脚本。EL表达式的语法是${key}可以非常简洁地取出域对象中的数据。比如在Servlet里存了req.setAttribute(message, 用户名或密码错误)JSP里直接用${message}就能取出来比写% String message (String)request.getAttribute(message); %舒服太多了。EL表达式还可以访问JavaBean的属性比如${user.username}等价于调用了user对象的getUsername()方法这背后是JavaBean规范在起作用。再配合JSTL标签库可以在页面里做循环和条件判断而完全不需要写Java脚本。先把依赖加到pom.xmldependency groupIdjstl/groupId artifactIdjstl/artifactId version1.2/version /dependency然后JSP页面顶部引入标签库% taglib prefixc urihttp://java.sun.com/jsp/jstl/core %循环输出数据就可以这样写c:forEach items${userList} varuser tr td${user.id}/td td${user.username}/td /tr /c:forEach整个页面看不到一行% %既干净又清晰。我自己的体会是学JSP阶段就把EL和JSTL用熟价值非常大因为这套思维在模板里循环、条件判断、读取值和后面学Spring Boot时用的Thymeleaf、FreeMarker非常相似可以说是“一次学习终身受用”。6. 完整案例一个支持增删改查的用户管理模块6.1 从登录到列表展示把前面的知识点串成一个闭环登录功能做完你可能还是觉得零散。为了把Servlet、JSP、JDBC、Request转发、重定向这些知识串成一个真正有业务逻辑的闭环我建议你动手做一个“用户管理模块”这个模块在企业后台里是最常见的管理员登录后能看到用户列表可以新增用户、删除用户、编辑用户信息。我先不贴全部代码而是把设计思路和流程讲清楚你跟着这个思路去自己实现一遍效果会比直接抄代码好一百倍。登录用户提交表单Servlet验证账号密码成功后把用户信息存session重定向到列表页。查询列表列表页发出请求Servlet查询数据库用户表把结果set到request里转发给list.jsp渲染成表格。新增用户填写表单提交到ServletServlet校验参数后执行INSERT操作完了重定向到列表页。这里用重定向是为了防止浏览器刷新时重复提交这是必须养成的习惯。删除用户列表页每行一个“删除”按钮URL带上用户idServlet拿到id执行DELETE操作完成后重定向回列表页。编辑用户先根据id查询该用户数据set到request里转发到编辑页面表单提交后执行UPDATE操作再重定向回列表页。你有没有发现这里面的流程有一个高度重复的模式接收请求获取参数调用数据库操作根据结果存数据或跳转转发或重定向这就是很多框架尤其是Spring MVC底层的“请求处理模型”。你在JavaWeb阶段把这个流程练得滚瓜烂熟到后面学框架时你会惊喜地发现框架只是把这个流程的“重复部分”给封装了而你早就知道每一步内部发生了什么。反过来如果跳过了这个阶段直接学Spring Boot你会连“为什么Controller里返回一个字符串就能跳到页面”“为什么加个注解就能操作数据库”这些基本问题都想不明白。6.2 接口设计原则把公共代码抽出来别复制粘贴做这个模块的时候我强烈建议你做到“不复制粘贴代码”。比如DBUtils里获取连接的方法你已经在多个Servlet里重复用了。但还有一个更值得抽取的地方增删改查的通用CRUD代码。public class BaseServlet extends HttpServlet { protected void write(HttpServletResponse resp, String data) throws IOException { resp.setContentType(text/html;charsetUTF-8); resp.getWriter().write(data); } protected User parseUser(HttpServletRequest req) { String username req.getParameter(username); String password req.getParameter(password); User user new User(); user.setUsername(username); user.setPassword(password); return user; } }然后把LoginServlet改成继承BaseServlet公共逻辑一下子清爽了很多。这一步不是什么高端技巧但它是面向对象思想“封装、继承”在真实项目里最朴素的应用。很多同学学JavaSE时觉得“继承”这个特性没什么用等你看多了这种重复代码抽取的过程就会明白为什么Java设计者要把继承放到语言核心的位置上。6.3 数据查询的进阶要点分页其实没那么神秘如果你照着上面的思路做完了用户管理模块你会有一种“不过如此”的感觉。但一旦用户表里的数据超过一百条你就会发现列表页一口气全展示出来非常笨重这时候就需要分页了。分页的原理并不复杂核心就两件事一是在SQL层面用LIMIT offset, sizeMySQL的写法控制查多少条二是在页面上展示“上一页”“下一页”的链接。这里的关键是计算offset假设每页显示5条数据当前是第3页那offset (3-1) * 5 10也就是从第11条开始取5条。核心SQL写出来是这样的SELECT * FROM user LIMIT #{offset}, #{pageSize}查询总条数再用一条SELECT COUNT(*) FROM user然后用“总条数 / 每页条数”算出总页数把当前页、总页数、每页大小都set到request里在JSP页面里用JSTL的c:forEach输出页码链接。整个过程不需要任何框架纯Servlet JDBC就能搞定。我记得第一次给项目加分页功能时SQL怎么连表查询、怎么算总数折腾了整整一下午后来才发现其实就是一个LIMIT加一个COUNT的事。分页这种“小学算术级别”的逻辑一旦你想清楚就能举一反三理解很多框架里的分页插件比如PageHelper不过是帮你自动拼了这条SQL而已。7. 项目运行中的常见问题与排查技巧7.1 这些高频报错的解法我建议你收藏JavaWeb开发中遇到的报错来来回回就那么几类我把最高频的整理成表格按“报错现象 - 原因 - 解法”三步来排查报错现象常见原因解决办法启动Tomcat时端口被占用之前服务没关或其他程序占用8080找到占用进程并结束或修改conf/server.xml里的端口号访问项目返回404URL路径写错或者应用上下文路径不对检查WebServlet路径和访问地址检查IDEA Deployment里的Application context访问页面报500控制台提示ClassNotFoundExceptionMaven依赖没有下载完整或没有引入检查pom.xml对应依赖Maven - Reload ProjectJDBC连接数据库报中文乱码连接URL没有指定编码或数据库表本身不是utf8URL里加characterEncodingUTF-8创建库时指定utf8mb4Tomcat启动后黑板报“找不到JDK”环境变量JAVA_HOME未配置或配置错误重新配置JAVA_HOME并确认路径里没有多出来的空格或引号JSP页面里的标签全部显示成文本页面头部忘了加% taglib %指令在JSP开头加上对应的taglib引用这里我再多说一句关于404和500的区别。404是“资源不存在”服务器想找你要的那个页面或Servlet没找到500是“服务器内部错误”找到了程序但程序执行时抛异常了。很多人一看到500就慌其实500反而是好事因为控制台会打印详细的异常堆栈信息你顺着堆栈把BUG揪出来反而是可查的。最让人头大的是404因为404通常意味着你要访问的路径和实际注册的路径对不上需要你把URL、注解、配置文件挨个检查。7.2 自测与排障心法别迷信“重启试试”“重启大法”在JavaWeb开发中确实有效但我不建议你无脑重启。遇到问题首先要做的事是看控制台日志。IDEA的控制台会打出Tomcat启动日志、项目运行日志、堆栈异常信息这是你排查问题的第一手证据。有一个排查思路很笨但极度有效二分法。当页面报错的时候你先把login.jsp改成纯静态HTML去掉所有JSP标签访问如果能打开说明Tomcat部署没问题问题出在JSP标签或Servlet再把Servlet里所有数据库操作注释掉写一个假数据返回如果能通说明问题在SQL或数据库配置。一层一层把“代码”和“环境”剥开问题范围就缩小了。再分享一个经验值如果JSP页面改了但是浏览器显示的还是旧内容大概率是浏览器缓存。开发阶段按CtrlF5强制刷新或者把浏览器设置为禁用缓存能省掉很多莫名其妙的“灵异事件”。8. 写在最后JavaWeb只是开始但这步走稳了后面才快如果你坚持看到了这里并且亲手把登录功能和用户管理模块都跑通了说明你已经迈过了JavaWeb最关键的入门门槛。从Servlet生命周期到请求转发和重定向从JDBC连接到JSP数据渲染你已经亲手打通了一条完整的Web数据处理链路。我在带学生和带新人的过程中越来越确认一件事JavaWeb阶段真不是为了让你用它去做项目而是为了让你看清Web开发的底层逻辑。你踩过的每一个坑——端口被占用、时区报错、中文乱码、404和500——都是值得的因为这些坑背后隐藏的是网络协议、编码规范、资源管理、安全防御这些永远不会过时的基础。接下来你可以顺着两条线继续走一条是向前端延伸学一学JavaScript、Ajax理解前后端交互的更多细节另一条是向后端框架延伸开始接触Maven的高级用法、MyBatis、Spring、Spring MVC最后进入Spring Boot。等你用上Spring Boot的那一刻你会感谢现在这个亲手写过Servlet、亲手配过Tomcat、亲手敲过PreparedStatement的自己因为你不是在用框架而是在真正理解框架。最后送你一个我个人坚持了很多年的小习惯遇到报错先读日志再动手先复现再修复先搜资料再问人。这套方法论比任何具体的技术知识点都值钱它能陪你走完整个程序员生涯。
返回列表