IDEA+Maven+Tomcat:从零创建JSP Web项目完整实战指南
1. 项目概述为什么现在还要学JSP以及你将从这篇文章里得到什么先别急着划走。我知道很多人一看到JSP这仨字母第一反应是这不是上个时代的东西了吗现在不都是前后端分离、Vue/React一把梭吗——这话没毛病但问题是不管前端框架怎么变很多高校的JavaWeb课程、毕业设计、甚至一部分企业内部老系统的维护依然绕不开JSP。我前阵子刚帮一个朋友从他的毕业设计里把一堆JSP页面改造成前后端分离接口改到一半的时候我就想如果当初他能把JSP项目的基本原理吃透改造起来根本不用这么费劲。更要命的是很多新手在IDEA里创建JSP web项目按着网上搜到的教程一步步点结果发现版本不一样、菜单对不上、依赖下载失败、Tomcat配了半天跑不起来……最后全都卡在环境搭建上连JSP长什么样都没见到。这篇文章我打算用一套完整可复现的流程带你从零开始在IntelliJ IDEA里创建一个标准结构的JSP web项目涵盖Maven工程搭建、Tomcat配置、JSP页面编写、Servlet交互、部署运行和常见报错排查。我还会解释每一步背后的原因——比如为什么用Maven而不是直接创建Java项目、为什么JSP本质上是Servlet、为什么你的页面中文乱码的根源不在JSP文件编码而在这几个地方。这些原理层面的东西才是你遇到问题能自己解决的核心能力。适合阅读这篇文章的读者有三类刚学完Java基础、准备进入JavaWeb开发的初学者被学校课程要求用JSP做课程设计、毕业论文的在校生以及工作中突然要接手一个老旧JSP项目、需要快速上手的开发者。2. 项目创建前置准备JDK、Tomcat和IDEA的设置一个都不能少2.1 为什么需要Tomcat用生活类比理解Servlet容器在动手创建项目之前我们要先搞明白一个基础问题为什么JSP项目离不开Tomcat你可以把Tomcat想象成一个餐厅的营业厅。Servlet和JSP就是你餐厅里干活的大厨而你自己写的Java代码是给大厨的菜谱。大厨Servlet不能直接在街上炒菜他必须在营业厅Tomcat里按照规定的位置URL映射、规定的流程请求-响应模型来工作。换句话说Tomcat是一个Servlet容器——它负责接收浏览器发送过来的HTTP请求解析请求内容然后找到对应的Servlet或者JSP页面去处理处理完再把生成的HTML响应回传给浏览器。没有这个容器你的JSP页面根本没人去执行它。我记得自己第一次接触这个的时候也很懵心想我写个HTML文件直接双击打开不就行了为什么JSP就不行原因是HTML是静态文件浏览器直接解析就能显示而JSP文件里有Java代码片段浏览器不认这种混合格式必须由Tomcat先把JSP翻译成Java文件再编译成Class然后执行把执行结果以纯HTML的形式输出给浏览器。这个翻译-编译-执行的过程理解成把菜谱翻译成菜肴更贴切。2.2 JDK版本选择和IDEA版本适配建议以前我们配置JSP项目最稳妥的组合是JDK 8 Tomcat 8/9 IDEA社区版。那时候网上教程最多遇到问题能找到现成答案。但说实话都2025年了如果系统还没装任何开发环境我建议直接JDK 17起步——原因有两个第一JDK 17是长期支持版本IDEA最新几个版本对它的支持非常成熟不会再出现版本警告弹窗第二Tomcat 10及以上版本已经全面适配Jakarta EE规范和较新的JDK兼容性更好。不过这里有个容易踩的大坑我必须提前说清楚Tomcat 10之后的包名变了。老项目里你写的import javax.servlet.http.HttpServlet在Tomcat 10及以上版本里必须改成import jakarta.servlet.http.HttpServlet。如果选了Tomcat 10你还按以前的javax.servlet写代码编译的时候一报一个错。所以如果你是跟着学校教材做作业教材多半是基于Tomcat 8/9的建议你安装Tomcat 9对应JDK 8或JDK 11都行如果你打算自己练手、对接新版生态直接Tomcat 10.1 JDK 17的组合代码里用jakarta.servlet开头导入。2.3 IDEA中配置Tomcat的完整流程安装和下载IDEA、JDK、Tomcat这部分我就不赘述了遇到问题去官网下对应版本就行。重点是配置这个动作本身很多新手在这里卡住。打开IDEA进入SettingsWindows下File - SettingsMac下IntelliJ IDEA - Preferences在左侧导航里找到Build, Execution, Deployment - Application Servers点击右上角号选择Tomcat Server。接下来会让你选择Tomcat的安装目录——注意选的是Tomcat的解压目录而不是里面的bin文件夹。选好之后IDEA会自动识别版本号。如果你这步识别不到通常是Tomcat压缩包没有正确解压或者解压后目录层级有问题——标准结构是Tomcat目录下直接就能看到bin、conf、lib、webapps这几个文件夹不要再多套一层目录。配置好Server之后还有一个容易忽略的地方Settings - Build, Execution, Deployment - Build Tools - Maven确认IDEA里使用的Maven是本地安装版本还是内置版本。我建议用内置捆绑版本就行重点是要把User settings file和Local repository指向你自己的配置位置尤其是阿里云镜像仓库配置好之后后续下载依赖速度天差地别——这个后面细讲。3. 第一个关键决策用Maven创建JSP项目而不是普通Java项目3.1 两种创建方式对比Maven赢在哪在IDEA里创建JSP项目入门教程里主要有三条路在New Project里选Java Enterprise勾选Web Application模板先建一个普通Java项目然后手动右键添加Web支持Add Framework Support用Maven构建一个war类型的Web项目。三种方式都能跑起来JSP但我强烈建议你直接用Maven方式原因很简单依赖管理。JSP项目要跑起来必须引入Servlet API、JSP API这些依赖。如果你用普通Java项目这些jar包需要自己去找、去下载、手动拷到lib目录里——版本一旦下载错或者拷漏一个运行时就是各种ClassNotFoundException。而Maven方式只需要在pom.xml里声明几个依赖坐标Maven自动从仓库下载并关联到项目而且会把你下载到的依赖版本统一管理。更重要的是未来的项目里你迟早要接触Spring Boot、Spring MVC这些框架它们全都是基于Maven/Gradle构建的你现在学会Maven结构等于提前打通了后续所有Java项目的基础。如果你图省事选了Java Enterprise模板IDEA确实会帮你初始化Web目录但那种方式生成的项目配置不够透明出了问题不好排查。我的经验是直接理解Maven项目结构对你以后看任何Java开源项目都有帮助。3.2 Maven项目结构里每一个文件夹是干什么的用Maven创建完之后你的项目骨架大概是这样的jsp-demo/ ├── pom.xml ├── src/ │ ├── main/ │ │ ├── java/ // Java源代码目录 │ │ ├── resources/ // 配置文件目录如数据库配置、日志配置 │ │ └── webapp/ // Web应用根目录 │ │ ├── WEB-INF/ │ │ │ └── web.xml // Web应用部署描述符 │ │ └── index.jsp // 默认首页 │ └── test/ │ └── java/ // 测试代码目录这个结构里src/main/java放Servlet类、业务类src/main/webapp是Web根目录你写的JSP文件都放在这里WEB-INF是受保护目录浏览器不能直接访问它里面的资源所以web.xml这种配置文件必须放这里。web.xml是Web应用部署描述符作用类似于目录索引——它告诉Tomcat这个应用有哪些Servlet、每个Servlet的URL路径是什么、加载顺序是什么、启动时加载哪些配置。在早期的Servlet规范里没有这个文件应用就不知道如何路由请求新版Servlet规范虽然引入了注解方式WebServlet但作为新手我建议你把web.xml留着遇到兼容性问题时它是最稳的兜底方案。3.3 在pom.xml中配置依赖包和Maven镜像打开pom.xml在dependencies节点里加入如下内容我以Tomcat 9 javax规范为例dependencies !-- Servlet API -- dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version4.0.1/version scopeprovided/scope /dependency !-- JSP API -- dependency groupIdjavax.servlet.jsp/groupId artifactIdjavax.servlet.jsp-api/artifactId version2.3.3/version scopeprovided/scope /dependency !-- JSTL 标签库JSP页面常用 -- dependency groupIdjavax.servlet/groupId artifactIdjstl/artifactId version1.2/version /dependency /dependencies注意scope标签用了provided意思是这个依赖在编码和编译的时候需要但最终运行时由Tomcat容器提供不要再打包进你的WAR文件里不然会和Tomcat自带的类冲突。这算是比较常见的坑没多少人告诉你报错表现是java.lang.LinkageError或者NoSuchMethodError排查半天发现是重复的Servlet API jar包。依赖下载慢的问题解决办法是配置Maven镜像。在Maven的settings.xml的mirrors节点中加入阿里云镜像mirror idaliyunmaven/id mirrorOfcentral/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror配置完之后原本需要几分钟的依赖下载基本上几十秒就搞定。这一步看起来和JSP没什么直接关系但省下来的时间都是实实在在的。4. 从零开始完整创建JSP Web项目实操4.1 IDEA新建Maven项目的每一个动作现在开始正经实操。打开IDEA点击New Project。第一步左侧选择Maven确保Build system选的是MavenJDK选择你安装的版本我这里是JDK 17。Name填项目名比如jsp-demoLocation会自动生成可以自己改到顺手的位置。第二步IDEA会自动生成一个Maven项目等待右下角进度条跑完Maven完成初始化和依赖下载。如果这一步报错回到Settings - Maven检查本地仓库路径和镜像配置。第三步这个默认项目还没有Web目录结构需要手动补上。在src/main目录下新建一个文件夹名字必须是webappIDEA的Maven Web项目约定俗成的目录名。在webapp下新建WEB-INF文件夹并在WEB-INF里创建web.xml文件。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 display-namejsp-demo/display-name welcome-file-list welcome-fileindex.jsp/welcome-file /welcome-file-list /web-app需要注意如果你的Tomcat是10.xweb.xml头部应该用xmlnshttps://jakarta.ee/xml/ns/jakartaee、version5.0这种命名空间千万别混用否则应用启动时解析描述符会报错。第四步在webapp目录下创建一个index.jsp文件。IDEA这里如果识别到了Web目录结构会直接有New - JSP/JSPF的选项如果没有就新建普通文件文件名后缀改成.jsp。一个用于测试的最小index.jsp% page contentTypetext/html; charsetUTF-8 pageEncodingUTF-8 % !DOCTYPE html html head title我的第一个JSP页面/title /head body h1JSP项目创建成功/h1 p当前服务器时间% new java.util.Date() %/p /body /html这个页面里% page ... %是JSP指令contentType和pageEncoding都设置成UTF-8是防止中文乱码的第一道防线。% new java.util.Date() %这种写法叫表达式输出它会调用Java代码并把结果直接嵌入到HTML中输出。4.2 配置Tomcat运行环境启动项目并访问项目创建好了接下来要让它在Tomcat里跑起来。这是整个流程里最容易让人崩溃的环节我逐步拆解。点击IDEA顶部工具栏的运行配置下拉框一般显示项目名或Add Configuration选择Edit Configurations。点击左上角号往下翻找到Tomcat Server - Local。在Server标签页里Application server选择你之前配置好的TomcatOpen browser勾选后启动完自动打开浏览器访问。HTTP port默认8080如果被占用改成8081或任意空闲端口即可。切到Deployment标签页点击号选择Artifact然后选中你的项目war包。注意这里有一个IDEA的惯性位置如果你是直接新建的Maven项目IDEA有时候不会自动生成war的Artifact你会发现在列表里找不到它。解决办法是在File - Project Structure - Artifacts里点击号选择Web Application: Exploded开发模式资源和代码热更新更快From modules选你的项目模块然后OK。回到Run配置的Deployment里 - Artifact这次就能看到了。Application context默认是/或者项目名比如/jsp-demo。这个字段决定了访问路径——如果填了/jsp-demo那么浏览器访问地址是http://localhost:8080/jsp-demo/如果是/直接http://localhost:8080/。配置完成点击运行按钮绿色三角。第一次启动可能会慢一些观察IDEA底部Run控制台日志看到类似Artifact is deployed successfully或者Server startup in [xxx] milliseconds的日志说明启动成功。然后浏览器访问你的项目地址看到JSP项目创建成功和动态时间恭喜你的JSP项目正式跑通了。4.3 如何验证JSP项目不是假跑通我知道有些人会在这里产生一个错觉浏览器显示了页面就觉得一切OK了。但如果只是把静态HTML塞进JSP文件里那跟直接建HTML文件有什么区别JSP的核心能力在于动态生成内容所以我们要做一个简单验证通过Servlet接收请求参数再转发到JSP页面渲染这样一套完整的请求链路才算真正跑通。在src/main/java下建一个包比如com.demo.servlet然后新建一个HelloServlet.javapackage com.demo.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 { String name req.getParameter(name); if (name null || name.trim().isEmpty()) { name JSP学习者; } req.setAttribute(name, name); req.getRequestDispatcher(/result.jsp).forward(req, resp); } }然后在webapp下新建一个result.jsp% page contentTypetext/html; charsetUTF-8 pageEncodingUTF-8 % !DOCTYPE html html head title处理结果/title /head body h2你好${name}/h2 p这条数据是Servlet动态写入的。/p /body /html这里有一个细节JSP页面里我用的是${name}这叫EL表达式。Servlet用req.setAttribute把name放进请求作用域JSP再用EL表达式把它取出来这条链路能跑通就说明你对JSP的动态和Servlet的数据流转有了基本的操作认知。重启Tomcat浏览器访问http://localhost:8080/jsp-demo/hello?name张三如果页面显示你好张三说明Servlet和JSP的协作完全正常。注意URL是/hello配的是注解方式而web.xml里没有配置这个Servlet说明新版Servlet规范的注解驱动是生效的。5. JSP核心语法速览脚本、指令和内置对象5.1 三种脚本元素声明、表达式、脚本片段JSP页面之所以能嵌Java代码靠的是三种脚本元素这是每个JSP开发者都必须掌握的基础。声明Declaration格式%! ... %用来声明成员变量和方法。声明的内容会被翻译成Servlet的成员属性所以它在多个请求之间是共享的有并发状态问题——我见过有人拿这里存用户登录信息结果一个用户登录所有用户都被登录了血泪教训。表达式Expression格式% ... %它会计算Java表达式的值然后作为字符串输出到页面上。注意末尾不能加分号这是新手最容易写错的地方。脚本片段Scriptlet格式% ... %里面可以写任意Java语句可以调用内置对象可以定义局部变量。在JSP里页面的_jspService方法中这些片段是顺序拼接的。你还需要理解这三者底层其实都被翻译成了Servlet类的方法代码。一个JSP页面在Tomcat里对应的Java文件本质上是继承HttpJspBase的一个类它把整个页面内容在_jspService方法里通过out.write()逐行输出这也就是为什么JSP能动态拼接HTML。5.2 九大内置对象实际开发中常用的就那几个JSP内置对象是容器给你准备好的、可以在脚本片段中直接使用的变量不需要手动声明。九个内置对象中日常开发和面试常抓的是这五个request类型HttpServletRequest获取请求参数、请求头、请求方法等response类型HttpServletResponse设置响应头、跳转响应等session类型HttpSession跨请求保存用户状态比如登录后记住用户信息application类型ServletContext整个应用全局共享的上下文信息out类型JspWriter向页面输出内容本质就是页面输出流。还记得我们前面写的% new java.util.Date() %吗这个能力是基于out实现的——所有表达式输出最终都是通过out.write()把内容写进响应缓冲区。还有四个内置对象分别是page、pageContext、config、exception前三个理解成页面自身信息和全局配置的载体exception只在isErrorPagetrue的JSP错误页面里使用平时用到的概率不大。5.3 JSTL标签库JSP页面里不要写一堆Java代码其实我前面讲脚本元素的时候心里是有点矛盾的——因为实际开发中尤其是配合Servlet的MVC结构里我们不推荐在JSP页面里写大量Java代码片段。原因有两点一是Java代码和HTML混在一起页面维护性极差二是前端同事看到JSP文件里全是Java代码会直接崩溃。推荐的做法是用JSTLJSP标准标签库来替代大部分脚本片段。我们在pom.xml里已经引入了JSTL依赖用的时候在JSP页面顶部引入标签库% taglib prefixc urihttp://java.sun.com/jsp/jstl/core %常用标签有c:if test${condition}条件判断c:forEach items${list} varitem循环遍历集合c:out value${name} /输出内容同时自带HTML转义防止XSS攻击比直接用${name}更安全。一个简单的使用示例table border1 c:forEach items${userList} varuser varStatusstatus tr td${status.index 1}/td td${user.name}/td td${user.age}/td /tr /c:forEach /table这样页面里的Java代码能减少90%以上代码可读性也强得多。6. 开发过程中必踩的四个大坑及完整排查方案6.1 中文乱码问题根子不在JSP文件编码这是JSP开发里出现频率最高的报错但它通常不止一个原因。乱码的完整链条是JSP文件本身的编码 - 页面响应的编码 - 请求参数的编码 - 数据库连接的编码四环环环相扣任何一环脱节都会乱码。针对页面输出最简单有效的方式是在JSP第一行设置% page contentTypetext/html; charsetUTF-8 pageEncodingUTF-8 %针对请求参数尤其是POST请求在Servlet里获取参数前加上req.setCharacterEncoding(UTF-8);也可以配置一个全局过滤器来统一设置请求编码避免每个Servlet重复写。IDEA中设置JSP文件本身编码的位置在Settings - Editor - File Encodings全部设置为UTF-8。如果你发现这三步全做了还是乱码那多半是Tomcat的server.xml里Connector没有设置URIEncoding找到conf/server.xml中的Connector标签加上URIEncodingUTF-8。6.2 Tomcat启动端口被占用Tomcat图标正常但页面404端口被占用很常见比如之前装的某个服务默认也用了8080。解决办法两种一是把占用端口的进程找出来杀掉二是在IDEA的Run Configuration里把Tomcat的HTTP port改动比如改成8081。改完后还要注意Deployment里的Application context是否和访问路径对得上——项目部署成功但页面404原因多半是URL写错了或者Application context路径没有匹配。另外IDEA里Tomcat运行配置中还有个Active标签页的After launch设置勾选后启动完自动打开浏览器省得每次手动输入URL。6.3 依赖冲突重复的Servlet API引起的LinkageError如果你把pom.xml里Servlet API的scope从provided改成了compile或者通过其他方式引入了额外的Servlet jar包启动时可能会报java.lang.LinkageError或者ClassCastException。原因很好理解Tomcat自带了Servlet API实现而你项目的WEB-INF/lib里又多了一份两个不同版本的类同时存在JVM加载顺序一乱就冲突了。排查方法在IDEA右侧Maven工具窗口里执行dependency:tree查看Servlet API是否被多次引入。如果是将scope改回provided即可。6.4 JSP页面里的Java代码报错突然变成红色如果JSP里嵌入的Java代码在IDEA里大量标红但项目能正常启动运行——这个情况通常不是代码问题而是IDEA对JSP语法检查的误报。常见引起原因是JSP页面顶部的指令或标签库引入写得不对比如% taglib ... %写错或者page指令的编码设置异常。这时候改代码没用先把File - Invalidate Caches / Restart执行一次让IDEA重新索引项目大部分误报就消失了。这是处理IDEA工具层面的假报错最实用的一招。还有一种情况是Java代码真的报错那问题多半是你没有在Project Structure - Modules - Dependencies检查Servlet API是否正确关联到模块。Maven自动导入之后一般没问题但如果你手动调整过项目的依赖顺序有可能把provided依赖的作用范围弄丢了。7. 一个实战练习用JSP实现简易用户列表把请求、业务、视图分离7.1 需求设定和分层思路到这里基础都过了一遍我们用一个小例子把整个项目的思路串起来。需求是这样页面上显示一个用户列表数据是模拟的不需要连数据库。为了让你理解标准JavaWeb项目的分层思路我们做三层结构Servlet层接收请求调用业务逻辑然后把结果放进请求作用域转发到JSP页面模型层Model用一个JavaBean类User表示用户实体视图层ViewJSP页面只负责展示数据。这样的分层就是MVC的雏形也是后期过渡到Spring MVC的桥梁。你现在用JSP搭出来的项目结构直接映射到Spring MVC里几乎不用多想——Controller就是Servlet的升级版Service就是业务逻辑层View就是视图模板。7.2 三个关键文件的具体代码和运行效果先创建一个User.java放在com.demo.model包下package com.demo.model; public class User { private String name; private int age; public User() {} public User(String name, int age) { this.name name; this.age age; } public String getName() { return name; } public void setName(String name) { this.name name; } public int getAge() { return age; } public void setAge(int age) { this.age age; } }再创建一个UserListServlet.java放在com.demo.servlet包下package com.demo.servlet; import com.demo.model.User; 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; import java.util.ArrayList; import java.util.List; WebServlet(/userList) public class UserListServlet extends HttpServlet { Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ListUser users new ArrayList(); users.add(new User(张三, 21)); users.add(new User(李四, 22)); users.add(new User(王五, 23)); req.setAttribute(users, users); req.getRequestDispatcher(/userList.jsp).forward(req, resp); } }最后在webapp下创建userList.jsp% page contentTypetext/html; charsetUTF-8 pageEncodingUTF-8 % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % !DOCTYPE html html head title用户列表/title /head body h2用户列表/h2 table border1 tr th序号/th th姓名/th th年龄/th /tr c:forEach items${users} varuser varStatusstatus tr td${status.index 1}/td td${user.name}/td td${user.age}/td /tr /c:forEach /table /body /html重启Tomcat访问http://localhost:8080/jsp-demo/userList你会看到一张带三条数据的表格。这一步跑通意味着你已经掌握了JSP开发的完整闭环Servlet接收请求 - 构建数据 - 设置属性 - 转发JSP - JSP用EL表达式和JSTL取出数据 - 渲染页面。这个流程和现在主流Web框架的核心思想是一脉相承的——只是框架帮你省去了大量重复劳动。7.3 为什么要在JSP页面里用JSTL而不是Java代码这个练习里我故意用了c:forEach而不是脚本片段循环目的就是想让你直观感受到两者的差别。如果写成脚本片段代码会是这种画风% ListUser users (ListUser) request.getAttribute(users); for (int i 0; i users.size(); i) { User u users.get(i); % trtd% i1 %/tdtd% u.getName() %/tdtd% u.getAge() %/td/tr % } %逻辑没毛病但页面里跟HTML混合着Java代码看两天你就会疯。而JSTL版本只是一行c:forEach items${users} varuser读起来像自然语言维护性高得多。更重要的一点是EL表达式和JSTL在设计时就考虑了安全性像${user.name}这种输出会由JSP容器统一转义处理比脚本片段裸输出更安全。8. 部署上线把项目打成WAR包部署到远程Tomcat8.1 本地打包时pom.xml需要的插件配置开发调试完了项目要真正给别人用通常是打成WAR包部署到服务器上的Tomcat。这就要在pom.xml里配置war打包插件同时确保packagingwar/packaging。一个基础的打包配置packagingwar/packaging build finalNamejsp-demo/finalName plugins plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-war-plugin/artifactId version3.3.2/version /plugin /plugins /buildfinalName决定了打包出来的WAR文件名字比如jsp-demo.war。如果你的项目中存在测试代码建议跳过测试打包命令是mvn package -DskipTests。8.2 WAR包部署到Tomcat的两种方式方式一把WAR文件放到webapps目录下将target目录下打出的jsp-demo.war拷贝到Tomcat的webapps目录下然后启动Tomcat。Tomcat启动时发现WAR包会自动解压并部署。访问URL就是http://服务器IP:8080/jsp-demo/。方式二通过Tomcat Manager应用热部署Tomcat自带的manager应用可以让你在网页上上传WAR包实现热部署。这种方式适合频繁更新的场景但是需要你提前在conf/tomcat-users.xml里配置manager角色的用户不然没有权限访问管理界面。8.3 服务器部署的几个注意点第一端口放行云服务器上如果安全组没有放行8080端口你本地访问不到但服务器上Tomcat明明已经启动了这种远程不可达问题十个人有九个会忽略防火墙配置。第二日志查看WAR包部署后启动报错去Tomcat的logs目录下看localhost.log和catalina.out。catalina.out里通常有完整的异常堆栈根据异常信息定位问题比瞎猜强一万倍。第三数据库连接如果项目连了数据库注意数据库地址、用户名、密码一定不要硬编码在JSP页面里应该放到配置文件中比如src/main/resources下的db.properties读取时用ClassLoader加载。这是项目上线后最重要的安全意识之一。9. 我做了这么久JavaWeb项目最后想对你说的话每次看到网上有人争论JSP是不是该淘汰了我都不太想站队。因为我自己的成长路线就是从JSP起步逐步理解Servlet、Filter、Listener然后又顺着这些基础去掌握Spring、Spring Boot。JSP这个技术本身可能越来越边缘化但它背后包含的Servlet生命周期、请求处理流程、作用域的数据流转、视图层的渲染逻辑这些概念框架到今天依然没有过时。如果你现在只是为了交作业、应付考试那你按着这篇文章走一遍搭个能跑的项目肯定没问题。但如果你愿意多花一个小时把每一步后面的原理看清楚——比如为什么Tomcat能运行JSP、为什么web.xml要有、为什么EL表达式能取值——那你后面学Spring MVC、学任何Java后端框架都会觉得眼熟到不行。我个人在实际操作中的一段经验是初期不要迷信网上所谓最新技术替换旧技术的言论。新技术永远学不完但底层原理是有限的。把JSP项目从创建到部署完完整整走一遍你在命令行打包服务器日志查看端口排错这些环节积累的手感会跟着你走很远。最后分享一个小技巧如果你后续要接手别人的JSP老项目别急着全部重写。先把项目里的Servlet和页面请求链路画出来看清每个JSP是被谁转发的、每个Servlet映射了什么URL再决定动哪里。多数老项目的问题集中在页面里塞了太多业务逻辑而不是JSP本身不好用。带着地图去改代码比上来就是一把梭安全得多。如果你的项目在创建或部署过程中卡住了把你遇到的完整错误日志贴出来——记住是完整错误日志不是报错了三个字。具体到第几行抛了什么异常我们排查起来效率会高很多。

相关新闻

机房UPS备用电源监控实战:电池巡检与告警配置全解析

机房UPS备用电源监控实战:电池巡检与告警配置全解析

说起来有点丢人,我们这套机房UPS备用电源监控系统,是被一次本可以避免的机房掉电事故逼出来的。那会儿机房规模不大,两台某品牌的200kVA主机做11冗余,带大约60多路机柜,负载不算重,约40%左右。当时我们对UP…

2026/10/15 6:14:42 阅读更多 →
对抗样本攻击方法全解析:从FGSM到物理世界攻击

对抗样本攻击方法全解析:从FGSM到物理世界攻击

1. 对抗样本攻击的底层逻辑与整体分类框架搞机器学习安全这块的人,迟早会碰到对抗样本这个绕不开的坎。我第一次接触这个概念是在做一个图像分类的小项目时,模型在测试集上准确率跑到98%以上,结果把一张熊猫照片加上一层肉眼几乎看不出来的噪…

2026/10/15 6:13:42 阅读更多 →
屏幕蓝光与色温调节:Iris护眼软件配置指南

屏幕蓝光与色温调节:Iris护眼软件配置指南

长时间盯着屏幕,眼睛干涩、酸胀、晚上睡不着,这种状态持续了几年之后,我开始认真研究手里的显示设备到底哪里出了问题。折腾过显示器自带的护眼模式,试过系统里的夜间模式,也换过防蓝光眼镜——最后在日常主力设备上长…

2026/10/15 6:13:42 阅读更多 →

最新新闻

SpringBoot+Vue轻量级博客系统设计与实现

SpringBoot+Vue轻量级博客系统设计与实现

1. 项目概述:SpringBootVue轻量级博客系统设计去年帮学弟评审毕业设计时,发现市面上很多博客系统要么功能冗余,要么扩展性差。于是我们决定用SpringBootVue搭建一个轻量级但五脏俱全的在线创作社区。这个系统最核心的特点是采用前后端分离架构…

2026/10/15 6:55:51 阅读更多 →
正念与心流:10分钟呼吸练习,让专注成为生命底色

正念与心流:10分钟呼吸练习,让专注成为生命底色

1. 先说清楚:我们到底在谈什么你有没有过这样的时刻:明明手头有一件重要的事要做,却忍不住五分钟刷一次手机;开会时脑子飘到晚上吃什么;想读几页书,眼睛盯着一行字,心里却已经把明天的待办事项过…

2026/10/15 6:55:51 阅读更多 →
Oracle 数据实时入仓 Doris 和 StarRocks 怎么做?CDC、全量迁移与 5 种方案对比

Oracle 数据实时入仓 Doris 和 StarRocks 怎么做?CDC、全量迁移与 5 种方案对比

在很多企业系统中,Oracle 负责在线事务处理,Doris 或 StarRocks 负责报表、数据分析和实时数据服务。当订单、用户、支付和日志数据持续增长时,直接在 Oracle 上运行复杂统计 SQL,可能影响线上业务。因此,很多团队会建…

2026/10/15 6:55:51 阅读更多 →
SpringBoot+Vue+MyBatis构建企业级电商平台实战

SpringBoot+Vue+MyBatis构建企业级电商平台实战

1. 项目概述"企业级网购平台管理系统"是一个基于SpringBootVueMyBatis技术栈的完整电商解决方案。这套源码包含了电商平台的核心功能模块,采用前后端分离架构设计,数据库使用MySQL,适合快速构建中小型B2C或B2B电商平台。我在实际电…

2026/10/15 6:55:51 阅读更多 →
聚簇索引vs非聚簇索引:从底层原理到实战避坑全解析

聚簇索引vs非聚簇索引:从底层原理到实战避坑全解析

做后端开发这几年,索引相关的坑我踩过不少。面试被问过无数次“聚簇索引和非聚簇索引区别”,带新人的时候也发现,大部分同学对这两个词的理解停留在“一个有序一个无序”或者“聚簇索引就是主键”这种模糊层面。一旦落到实际业务,…

2026/10/15 6:55:51 阅读更多 →
盲盒商城软件开发案例:连接概率说明、微信支付、在线开赏与积分兑换

盲盒商城软件开发案例:连接概率说明、微信支付、在线开赏与积分兑换

盲盒商城的购买过程与普通商品商城有所不同。用户在付款前,需要了解盲盒价格、可抽取内容和相关规则;完成支付后,再进入开赏环节。商品展示、概率说明、支付结果和积分记录之间,需要形成清晰的操作顺序。 某公司的这套盲盒商城软件…

2026/10/15 6:54:51 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →