简介:基于 Java 与 JSP 的企业宣传网站毕业设计源码,适用于毕业设计、课程设计或 Java Web 项目实训。项目围绕企业形象展示与信息发布,包含公司简介、产品/服务展示、新闻动态、案例展示、在线留言与后台管理等功能,前台展示与后台数据维护兼备,可帮助初学者理解传统 Java Web 开发全流程。
压缩包为 RAR 格式,共 879 个文件,约 21.27MB。内含 21 个 JSP 页面、10 个 Java 源文件、27 个 class 文件和 66 个 jar 依赖包,同时有 74 个 html、22 个 css、205 个 js 与大量 gif/jpg/png 图片素材,并补充 xml/properties 配置文件和 db/mdf 数据库文件,基本覆盖前端资源、服务端逻辑、第三方类库和数据库脚本等完整项目组成。
研究源码可掌握 Servlet/JSP 与数据库交互、MVC 分层组织和企业信息管理流程;附带的 fckeditor 编辑器组件及数据库脚本有助于快速复现运行环境。已有 164 人学习,适合作为毕业设计参考和二次开发底稿。
1. Java+JSP 企业宣传网站毕业设计:这份源码值不值得当课设底子
刷到这份“基于Java+JSP的企业宣传网站毕业设计实现+源码”时,大部分人心里其实只有两个问题:这东西能不能跑起来,答辩的时候扛不扛得住追问。我的判断是,越是看起来老牌的 JSP+Servlet 项目,反而越适合做课设和毕设底子,因为它把请求、响应、会话、数据库交互全都摊开了,没有任何框架替你遮着,导师想从哪个方向问,你都能拿起代码讲清楚。
整套东西不是那种只有一个静态首页的“企业官网”,而是把公司简介、产品展示、新闻动态、在线留言和后台管理串成了一条完整链路。前台负责展示,后台负责维护,两者共用同一套数据库,很典型的 JavaWeb 课程设计结构。
适合谁呢?一是正在纠结基于 JSP 的毕设选题的大四学生,二是想拿真实项目练一遍 Servlet+JSP+MySQL 联动的新手。如果你已经熟练 Spring Boot,大可不必回头选这种老技术栈,但如果你需要的是能讲透、能改、能过查重的工程代码,这份源码比一堆空壳框架要有用得多。
2. 先把技术栈和目录结构盘明白:Servlet + JSP + MySQL 在毕业设计里怎么分工
2.1 为什么企业宣传网站适合用 JSP+Servlet,而不是一上来就上 Spring Boot
现在不少毕业设计指导老师听到 Spring Boot 反而头大,因为框架已经把很多东西包成了黑匣子。你交上去一个 Spring Boot 项目,对象关系映射、自动配置、依赖注入全被框架接管,答辩时老师问一句“登录状态存在哪里”“这个请求怎么被分发的”,你如果答不上来,整个项目分直接掉一半。
JSP+Servlet 这套组合是没有框架的,请求到达 Tomcat 后,要么走了 servlet 的service()/doGet(),要么被 JSP 直接渲染。整个调用链是透明可见的,你在代码里写一个@WebServlet("/admin/login"),访问路径和 Java 方法之间的映射关系一眼就能看明白。对一个以考察基础能力为目标的毕业设计来说,这种透明反而成了加分项。
企业宣传网站本身也不复杂。它的核心场景就四个:看信息、管信息、发信息、收留言。没有高并发,没有分布式,没有复杂的业务状态,用 JSP+Servlet 足够覆盖全部需求,而且数据库表不会超过六张。把精力花在正确的地方,比盲目上框架更实在。
2.2 打开源码包先看这三个东西:目录结构、数据库脚本、部署配置
拿到压缩包后先别急着往 IDE 里导,按顺序检查以下三个位置。
第一是根目录下的数据库脚本,通常叫db_company.sql或者company.sql。这个脚本是这个项目的地基,它决定了所有页面能看到什么数据。第二个是WEB-INF/web.xml,不管项目用的是注解还是 XML 配置,这个文件都值得完整过一遍,因为部署路径、过滤器、欢迎页都在里面。第三个是src下的 Java 包结构,重点看是不是按entity/dao/servlet/filter/util分层的,分层清晰的项目改起来才顺手。
一个典型的目录结构是这样的:
company/ ├── src/ │ ├── com/company/ │ │ ├── entity/ # 数据实体类:Admin、Product、News、Message │ │ ├── dao/ # 数据访问层:接口 + 实现类 │ │ ├── servlet/ # 控制器层:处理请求跳转 │ │ ├── filter/ # 过滤器:统一编码、登录拦截 │ │ └── util/ # 工具类:数据库连接、字符串处理 ├── WebRoot/ │ ├── admin/ # 后台管理页面 │ ├── css/ js/ images/ # 静态资源 │ ├── fckeditor/ # 富文本编辑器组件 │ ├── index.jsp │ └── WEB-INF/ │ ├── lib/ # mysql-connector-java.jar 等依赖 │ └── web.xml └── db_company.sql注意WebRoot这个目录名,老一代 JavaWeb 项目经常这么叫。如果你用 Eclipse 的 Dynamic Web Project,发布时它会自动把WebRoot当作 web 根目录;但如果你用 IDEA,导入时需要手动把WebRoot标记为 Web 资源目录,否则部署后找不到 JSP。这一步很多人翻车,后面避坑部分我会再提。
2.3 数据库设计:公司简介、产品、新闻、留言,四张核心表怎么建
企业宣传网站看起来是纯展示,但后台要维护,所以表结构必须支持“增删改查”。资料包里的 SQL 脚本通常会把表建好,但你不能只会执行脚本,答辩时老师会让你解释表结构。
核心表一般是四张:管理员表、产品分类表、新闻/产品内容表、留言表。我习惯把它们建成这样:
CREATE DATABASE company_cms DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE company_cms; -- 管理员表 CREATE TABLE t_admin ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE COMMENT '登录账号', password VARCHAR(64) NOT NULL COMMENT 'MD5加密后的密码', real_name VARCHAR(50), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 栏目分类表:新闻和产品共用 CREATE TABLE t_category ( id INT PRIMARY KEY AUTO_INCREMENT, cat_name VARCHAR(100) NOT NULL COMMENT '栏目名称', cat_type VARCHAR(20) NOT NULL COMMENT 'news 或 product', sort_no INT DEFAULT 0 COMMENT '排序,越小越靠前' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 新闻/产品内容表 CREATE TABLE t_content ( id INT PRIMARY KEY AUTO_INCREMENT, category_id INT NOT NULL, title VARCHAR(200) NOT NULL, summary VARCHAR(500) COMMENT '摘要,列表页展示', content MEDIUMTEXT COMMENT '正文,可存富文本HTML', cover_image VARCHAR(255) COMMENT '封面图路径', click_count INT DEFAULT 0, publish_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_category (category_id), CONSTRAINT fk_content_category FOREIGN KEY (category_id) REFERENCES t_category(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 在线留言表 CREATE TABLE t_message ( id INT PRIMARY KEY AUTO_INCREMENT, user_name VARCHAR(50), phone VARCHAR(20), content VARCHAR(500), is_replied TINYINT DEFAULT 0 COMMENT '0未回复 1已回复', create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;这段 SQL 里有几个地方值得注意。t_content表的设计比较讨巧,新闻和产品都算“一条带标题的内容”,用一个category_id区分,而不是拆成两张独立表。这样前台列表页只需要写一个查询逻辑,后台也只需要一套增删改查,整个代码量直接少三分之一。t_message表里加了is_replied字段,这是为了应付“管理员能看到留言并标记已读”这个功能点。
类接口设计这里,我一般建议在dao层只暴露四个方法:findById、findByCategory、insert、delete。不要把业务写得过于复杂,毕业设计要的是完整,不是炫技。你用一个 DAO 把 CRUD 包好,答辩时反而更好讲清楚 JDBC 的PreparedStatement是怎么防 SQL 注入的。
3. 从零把项目跑起来:环境配置、导入编译、Tomcat 部署全流程
3.1 环境准备清单:JDK、Tomcat、MySQL 版本怎么对齐
老项目对环境的敏感程度比想象中大。这份源码用的技术栈决定了你最好用这组版本,踩坑最少:
| 组件 | 推荐版本 | 说明 |
|---|---|---|
| JDK | 1.8 | Java 9 以上模块化带来一堆反射和类加载问题,没必要硬试 |
| Tomcat | 8.5 | 支持 Servlet 3.1,注解和 web.xml 都兼容 |
| MySQL | 5.7 | 5.7 以下字符集问题多,8.0 驱动与连接串要额外处理 |
| Eclipse/IDEA | 随意 | IDEA 需要手动标记 WebRoot |
如果你机器上已经装了 JDK 17 或者 MySQL 8,也不用立刻卸掉重装,后面第 5 章避坑部分有对应解法。但第一次跑通,请严格遵守这套组合,尤其是 JDK 8,别再拿 JDK 11 以上去编译 JSP 项目,你会被各种隐式依赖问题耗光耐心。
3.2 建库导数据:把 db_company.sql 导入 MySQL 的完整命令
打开命令行,先建立数据库并导入数据。假设你的 MySQL 用户名是root,密码是123456:
mysql -uroot -p123456进入 MySQL 提示符后执行:
source D:/company_website/db_company.sql;或者跳过交互式会话,直接在系统命令行里一次性导入:
mysql -uroot -p123456 < D:/company_website/db_company.sql第二种方式适合写进批处理脚本,适合重新配环境时使用。导入成功后,用show tables;确认四张核心表已经在库里。如果直接执行 SQL 后出现中文乱码,请检查你的命令终端字符集是不是 GBK,Windows 的 cmd 默认字符集会让你把 SQL 脚本里的中文注释显示成乱码,但不影响实际数据落库,别被这个表象吓到。
3.3 修改数据库连接和发布路径:配置文件里最容易漏的两个点
JavaWeb 项目常见的做法是把数据库连接信息抽到一个jdbc.properties或db.properties文件里,然后由util/DBUtil.java读取。打开这份源码的配置文件,你会看到类似这样的内容:
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/company_cms?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai jdbc.username=root jdbc.password=123456jdbc.url里有三个参数需要重点解释。characterEncoding=utf8保证 JDBC 写入数据库时中文不乱码;useSSL=false是 MySQL 5.7 之后防止 SSL 握手报错的开关;serverTimezone=Asia/Shanghai是 MySQL 8.0 时区问题的标配。如果你用 MySQL 5.7,第三项可以留空,但我一般建议一律写上,免得以后换库时抓瞎。
改完配置,检查一下WEB-INF/lib里有没有mysql-connector-java.jar。很多源码包会漏掉这个 jar 或者给一个 5.1 老版本,如果你的 MySQL 是 8.0,连接串里还得加allowPublicKeyRetrieval=true,否则启动后报Public Key Retrieval is not allowed。
3.4 用 IDEA 或 Eclipse 导入并部署到 Tomcat
在 IDEA 里导入的关键步骤是:新建一个普通的 Java 项目,然后把src标记为 Sources Root,把WebRoot右键标记为 Web Folder,再配置 Artifacts 时添加Web Application: Exploded。这样 IDEA 生成的部署包结构才是正确的。
配置好之后,把 Tomcat 8.5 加进 Run Configuration,选 Deployment 标签页,添加刚才的 exploded artifact,Application context 填/company。启动前先确认Project Structure -> Libraries里已经把 Tomcat 的 servlet-api 和WEB-INF/lib下的所有 jar 都加入进去了。
如果你手头暂时没有 IDE,想用命令行直接编译运行也可以。先把 Tomcat 解压好,设置CATALINA_HOME,然后回到项目根目录执行:
# 把 src 下所有 java 文件列出来,用 javac 一次性编译到 WEB-INF/classes cd D:/company_website # Windows 下批量列出源码文件 dir /s /b src\*.java > sources.txt javac -encoding UTF-8 -cp "WEB-INF/lib/servlet-api.jar;WEB-INF/lib/mysql-connector-java-5.1.49.jar" -d WEB-INF/classes @sources.txt del sources.txt-encoding UTF-8必须保留,否则中文注释和字符串字面量在编译阶段就变成了乱码。-d WEB-INF/classes表示把编译后的.class按包结构输出到指定目录,Tomcat 只认这个目录下的字节码。@sources.txt是 javac 的批量参数,把文件列表从命令行长度限制里解放出来。
编译完,整个项目已经是一个成熟的 web 应用目录,把它整体复制到 Tomcat 的webapps下,改名为company,然后启动bin/startup.bat。浏览器访问http://localhost:8080/company/index.jsp,看到企业首页就说明部署成功。
3.5 启动后第一步该验证什么
不要急着点后台入口,先按顺序做三件事。第一,在浏览器地址栏访问http://localhost:8080/company/index.jsp,同时打开 Tomcat 的logs/catalina.out,确认没有报ClassNotFoundException。第二,回到 MySQL 命令行,执行select * from t_content;,确认有种子数据,如果一张表都是空的,前台页面会一片空白,你要去db_company.sql里找 INSERT 语句重新执行。第三,访问后台登录页,默认账号密码一般在t_admin表里,用select * from t_admin;查出来,如果有 MD5 密文,记得把登录逻辑理清再去改数据库,不要直接把密文改成明文,否则密码校验永远对不上。
4. 宣传网站前后台实现拆解:登录、栏目管理、富文本编辑和文件上传
4.1 前台模板是怎么做到整站统一的:JSP include 的作用
企业宣传网站的多个页面都有相同的头部导航、侧边栏和底部版权信息,源码里最值得借鉴的做法是把这些公共部分拆出来,再在每个页面用 include 默写进去。
JSP 里有两种引入方式,它们的差异答辩时常被问到。第一种是静态包含:
<%@ page contentType="text/html;charset=UTF-8" %> <html> <head> <title>公司首页</title> </head> <body> <%@ include file="common/header.jsp" %> <div class="main"> <!-- 首页具体内容 --> </div> <%@ include file="common/footer.jsp" %> </body> </html>静态包含是发生在编译期的。<%@ include file="common/header.jsp" %>会把 header.jsp 的源码原样复制到当前页面里,最终合并成一个 Java 文件再编译生成 Servlet。好处是性能好,坏处是两个页面里如果都定义同名变量,编译直接报错。第二种动态包含<jsp:include page="common/header.jsp"/>是运行期请求一次再输出,隔离性更好但性能略差。
对这个宣传网站来说,公共部分没有复杂变量,用静态包含就可以。你改造时要注意一点:如果把 header.jsp 单独打开,它会因为没有上下文参数而报错在整点,这是正常的,因为它的作用是“被包含”,不是独立页面,你不用单独去运行它。
4.2 后台登录与 Session 校验:一个 Filter 挡住未登录请求
后台的每一张页面,都不能让用户绕过登录直接访问。常见做法是写一个过滤器,拦截所有/admin/*路径。拦截逻辑简单直接,代码长这样:
package com.company.filter; import 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("/admin/*") public class LoginFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; // 登录页和登录请求本身要放行,否则会出现死循环 String uri = request.getRequestURI(); if (uri.endsWith("/admin/login.jsp") || uri.endsWith("/admin/login")) { chain.doFilter(req, resp); return; } HttpSession session = request.getSession(false); if (session == null || session.getAttribute("admin") == null) { response.sendRedirect(request.getContextPath() + "/admin/login.jsp"); return; } chain.doFilter(req, resp); } }这段过滤器的关键点有两个。第一个是request.getSession(false)和getSession()的区别,前者在无会话时返回 null,不会强行创建一个新 Session,后者会,习惯用前者更安全。第二个是放行条件,你必须把 login.jsp 和登录的 Servlet 排除在拦截路径之外,否则浏览器访问登录页时会被过滤器重定向到登录页,形成无限循环。项目里如果拦截了静态资源,css/js/images也要加放行逻辑,否则后台页面样式全丢。
4.3 新闻动态的增删改查:从 JSP 表单到 Servlet 到 DAO 的闭环
前台的新闻列表页只是把数据库数据用 JSP 循环输出,真正的复杂度在后台“新增/编辑文章”这条线上。以一个添加产品的 Servlet 为例:
package com.company.servlet; import com.company.dao.ProductDao; import com.company.entity.Product; 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("/admin/product/add") public class ProductAddServlet extends HttpServlet { private ProductDao productDao = new ProductDao(); @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); String title = request.getParameter("title"); String categoryId = request.getParameter("categoryId"); String summary = request.getParameter("summary"); String content = request.getParameter("content"); Product product = new Product(); product.setTitle(title); product.setCategoryId(Integer.parseInt(categoryId)); product.setSummary(summary); product.setContent(content); boolean ok = productDao.insert(product); if (ok) { response.sendRedirect(request.getContextPath() + "/admin/product/list"); } else { request.setAttribute("error", "保存失败,请重试"); request.getRequestDispatcher("/admin/product/add.jsp").forward(request, response); } } }这里有一个不得不提的细节:request.setCharacterEncoding("UTF-8")必须放在读取request.getParameter()之前。如果放错位置,POST 请求里的中文从 Tomcat 解析阶段就是乱码,后面不管怎么设置都没有用。如果你写了一个全局编码过滤器,这个 Servlet 里就不需要再写了,但保留也不算错。
sendRedirect和forward的选择也是个考点。新增完成后我用重定向,是为了避免用户按 F5 刷新页面时再次提交同一份表单,这是最基础的“表单防重提交”手段。而保存失败时用forward保留原本的请求参数,让用户不需要重新填表。
4.4 富文本编辑器:FCKeditor 接入和上传图片路径的配置
编辑新闻正文的时候,如果只有一个<textarea>,用户没法在正文里插图。这份源码选的是 FCKeditor,现在看是有点老,但在毕业设计里很常见,因为它的 JSP 接入方式不复杂,而且能让答辩演示变得好看。
前端页面里引入的代码大致是:
<textarea name="content" id="content" rows="10" cols="80">这里写初始内容</textarea> <script type="text/javascript" src="${pageContext.request.contextPath}/fckeditor/fckeditor.js"></script> <script type="text/javascript"> var oFCKeditor = new FCKeditor('content'); oFCKeditor.BasePath = "${pageContext.request.contextPath}/fckeditor/"; oFCKeditor.Width = "100%"; oFCKeditor.Height = "400"; oFCKeditor.ReplaceTextarea(); </script>BasePath指的是fckeditor.js所在目录的 URL 根路径,如果 esp 和数据这个值,FCK 素材文件会加载不到,编辑器直接显示成普通表格。很多人部署的时候发现编辑器区域是空白,十有八九是 BasePath 里少了项目名的contextPath。
文件上传是另一个容易坏的点。FCKeditor 上传图片后返回一个相对路径,比如/upload/2025/01/xxxx.jpg。你要保证这个路径在浏览器里能访问到。老项目的常见做法是在 Tomcat 的server.xml里配一个虚拟目录:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Context docBase="D:/company_website/upload" path="/company/upload" reloadable="false" /> </Host>docBase是物理路径,path是浏览器访问时的 URL 路径。如果把上传目录放在项目内部,重新部署时会被覆盖,这就是很多源码包上传图片后删掉重发就丢失的原因。配好虚拟目录后,上传文件的保存路径还是物理路径,但页面上的src用的是 URL 路径,这两者的对应关系就是靠<Context>指令建立起来的。
源码里偶尔会看到fckeditor.afp、sample01.afp、config.ascx、class_upload.asp这类文件,初次看到容易被吓到,以为自己下载错了项目。你测过了,那其实是老版编辑器包里自带的跨语言测试示例和上传数据文件,跟 JSP 端逻辑没有关系,直接跳过即可,不影响项目运行。
5. 避坑指南:中文乱码、404、上传路径和 MySQL 兼容问题一次说清
5.1 中文乱码:三处编码不一致,到处都是问号
现象:启动后打开后台新增新闻,输入中文标题保存,列表页显示一堆???,或者页面本身显示中文是好的,提交到数据库后就乱。
原因:JSP 页面编码、Servlet 请求编码、JDBC 连接编码、MySQL 表编码,这四处只要有一处不一致,中文就会在这条链路的某个环节变成乱码。
解决:从上到下统一为 UTF-8。第一,每个 JSP 页面顶部必须有<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>。第二,写一个全局编码过滤器,把每个请求的编码都设置成 UTF-8:
@WebFilter("/*") public class CharacterEncodingFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); chain.doFilter(request, response); } }第三,jdbc.url里带上characterEncoding=utf8。第四,数据库和表在创建时就指定DEFAULT CHARSET=utf8mb4。这四步缺一不可。如果已经出现乱码,把表改成 utf8mb4 后,重新执行一遍增删改查通知数据,老乱码数据不会自动恢复。
5.2 页面 404 或者 500:Servlet 映射和控制台报错对不上
现象:首页index.jsp访问正常,但点击“产品详情”“新闻列表”这些带动态路径的链接时 404;有些页面直接 500,Tomcat 控制台抛出ClassNotFoundException或NoClassDefFoundError。
原因:404 说明请求根本没找到对应的 Servlet,要么web.xml里的<servlet-mapping>写错要么@WebServlet里的路径和 JSP 表单提交的 action 不一致;500 里的 ClassNotFoundException 一般是缺少 jar 包,或者WEB-INF/classes下的.class文件没有随项目发布。
解决:先做最机械的检查,打开浏览器审查元素,找到那个 404 的地址,再去源码里搜索这个 URL,确认它对应到哪个注解或配置标签。对照@WebServlet("/admin/product/list"),请求路径必须包含上下文路径,也就是项目的 contextPath。服务端 500 时,把WEB-INF/classes目录展开,看com/company/servlet下面有没有对应.class文件,如果没有,就是编译阶段失败了,重新执行第三节里的 javac 命令,注意控制台日志里有没有编码 GBK 的不可映射字符这种提示。
5.3 编辑器上传图片显示不出来:物理路径和访问路径是两回事
现象:后台编辑器里选图片,上传成功,编辑器弹窗能看到预览图,但保存后前台页面里图片是裂的,右键属性里看到的是localhost:8080/company/upload/xxx.jpg,打开直接 404。
原因:上传时把文件写到了磁盘的某个物理目录,比如D:/company_website/upload,但浏览器访问/company/upload/xxx.jpg时,Tomcat 根本不知道这个 URL 对应哪个物理目录。项目重新部署后,如果上传目录在项目内部,还会被整个删除。
解决:不要在项目内部保存用户上传的文件。在磁盘固定一个目录当上传根目录,然后在 Tomcat 的server.xml里配了虚拟路径。配好后,页面上的图片地址保持/company/upload/xxx.jpg,物理文件落在D:/company_website/upload/xxx.jpg,两者互不影响。改完server.xml必须重启 Tomcat 才会生效,光 reload 项目不行。
5.4 数据库连接失败:驱动太老、时区问题、MySQL 8 密钥问题
现象:Tomcat 启动后没有报错,但一访问后台登录接口就报Unknown database或者Communications link failure,再要么是Public Key Retrieval is not allowed。
原因:数据库连接串里的参数不匹配。Unknown database说明库里还没导入 SQL 脚本,Communications link failure大概率是 MySQL 服务没起来或者端口不对,Public Key Retrieval is not allowed和serverTimezone是 MySQL 8.0 特有的问题,这话驱动包如果是 5.1 版本也会触发。
解决:先确认 MySQL 服务处于启动状态,再执行一次数据库导入。看 MySQL 版本,用命令select version();把结果记下来。如果是 8.0,驱动 jar 至少要换成mysql-connector-java-8.0.x,且连接串改成这样:
jdbc.url=jdbc:mysql://localhost:3306/company_cms?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true如果是 5.7,保持com.mysql.jdbc.Driver和那个 url 也问题不大。看到serverTimezone报错也不用慌,把这个参数去掉,改成useSSL=false试试。
5.5 改了代码怎么都不生效:class 没有重新编译或者浏览器缓存
现象:上午把登录跳转的地址都改了,重启 Tomcat 后访问页面还是老样子,甚至把源码里某个输出文字改掉,刷新页面依然是旧文案。
原因:JSP 文件 Tomcat 会在第一次访问时编译,后续会自动检测修改,但 Java 类不会。IDEA 里如果没有触发热部署,重启 Tomcat 前必须重新 Build Project,把新编译的.class文件同步到WEB-INF/classes。还有一种可能是浏览器缓存了 CSS 和 JS。
解决:启动多加了一次自动编译后,我习惯做一次“冷部署”,登录后台,访问http://localhost:8080/company/index.jsp,网页源代码放在Tomcat/work/Catalina下,直接右键项目删除 WEB-INF 下的 classes 目录,再 Build Project 重建。浏览器里按 F12 打开开发者工具,Network 面板里勾选 Disable cache,这样静态资源也不会被缓存骗了。
6. 进阶玩法:用 JSTL 和 EL 改造前台页面,让答辩代码更像正式工程
企业宣传网站的 JSP 页面如果写满<% ... %>脚本片段,虽然能跑,但答辩时导师一眼就能看出来你还在用最原始的方式写页面。花一晚上把前台列表页改造成 JSTL + EL,是性价比最高的进阶操作。
EL 表达式负责读取数据,JSTL 标签负责控制循环和逻辑。改造后的产品列表页核心部分长这样:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <c:forEach items="${productList}" var="p"> <div class="product-item"> <h3><a href="${pageContext.request.contextPath}/product/detail?id=${p.id}">${p.title}</a></h3> <p>${p.summary}</p> <span>发布时间:<fmt:formatDate value="${p.publishTime}" pattern="yyyy-MM-dd"/></span> </div> </c:forEach>${productList}是 Servlet 里往 request 作用域放的 List 对象,${p.title}会自动调用 Product 的getTitle()方法,这就是 EL 的基本原理。改造时要注意,Servlet 里跳转前必须写上request.setAttribute("productList", productDao.findAll());,否则页面的empty productList会被判断为空,最终循环输出零条数据。
JSTL 标签库需要你往WEB-INF/lib里加两个 jar:jstl.jar和standard.jar,一些新版本把这两个合并了,你要是找不到,去 Maven 仓库搜javax.servlet:jstl:1.2下载即可。加入后再在 JSP 顶部声明 taglib,否则页面会报Can not find the tag library descriptor for "http://java.sun.com/jsp/jstl/core"。
如果还想更完善,顺手做一个通用的 MySQL 连接工具类,把连接资源都释放掉:
public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USERNAME, PASSWORD); } public static void close(ResultSet rs, Statement stmt, Connection conn) { if (rs != null) { try { rs.close(); } catch (SQLException ignored) {} } if (stmt != null) { try { stmt.close(); } catch (SQLException ignored) {} } if (conn != null) { try { conn.close(); } catch (SQLException ignoredbe) {} } }一个认真负责的数据库访问层,close 方法永远放在最后,避免长时间占用数据库连接池资源。
这套源码本身是一台很“朴素”的 JSP 老项目,正因为朴素,才适合拿来当毕设和课设的底子。对我自己来说,接到这种项目之后,从来不会急着改业务代码,而是先把编码过滤器、数据库连接串、上传虚拟目录这三个全局配置检查一遍,确认地基是稳的再往上加楼层。从那以后我每次跑老项目都会强制走一遍这三个检查,基本能把八成以上的启动问题提前按在萌芽里。希望这份拆解能帮你在启动和答辩的路上少绕几个弯。
本文还有配套的精品资源,点击获取