ARTICLE DETAIL

资讯详情

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

基于Java+JSP的企业宣传网站毕业设计:从零搭建到答辩避坑全指南

基于Java+JSP的企业宣传网站毕业设计:从零搭建到答辩避坑全指南 简介这份资源是面向高校计算机相关专业学生与Java Web初学者的企业宣传网站毕业设计完整源码包基于Java与JSP技术栈实现可用于课程设计、毕业设计参考或Java Web入门实战练习。压缩包共收录879个文件约21.27MB涵盖gif、jpg、png等图片素材js、css、html等前端资源以及jsp页面、java类文件、jar依赖包、xml配置与数据库脚本等完整呈现了从前端展示到后端业务逻辑的项目结构。目前已有164人学习下载。源码中可看到公司简介、产品展示、新闻发布、联系我们等典型企业站点模块的实现方式读者可借此理解Servlet与JSP标签的配合、MVC分层思路、数据库连接与配置文件的组织并对照实际项目学习页面布局、交互效果与服务器端编程的落地写法对提升Java Web开发能力与完成同类课题具有较高参考价值。1. 企业宣传网站为什么还在用 JSP一个被低估的毕设选题很多同学一提到毕业设计选 Java Web第一反应就是 Spring Boot 加 Vue 前后端分离觉得 JSP 是上个时代的东西拿不出手。但我带过几届学生的实际情况恰恰相反基于 JavaJSP 的企业宣传网站是计算机毕业设计里性价比最高、最容易跑通、答辩时最不容易被问穿的选题之一。原因很直接——企业宣传网站的业务模型天然简单无非是首页展示、产品列表、新闻动态、关于我们、留言板、后台管理这几块没有复杂的并发和分布式要求而 JSP 的请求响应模型、内置对象、标签库刚好能把「页面展示 数据读取」这件事讲得清清楚楚。这篇文章要解决的就是拿到「基于 JavaJSP 的企业宣传网站毕业设计」这个题目之后怎么从零把它做出来、源码结构怎么组织、数据库怎么设计、部署怎么落地以及答辩前哪些坑必须提前填掉。适合两类人一是正在做基于 JSP 的毕设选题、需要一套能跑通的完整思路的同学二是 Java 基础刚学完、想找一个真实项目练手 JSP 入门和 Java Web 头歌实训内容的初学者。我不会给你画大饼只讲我实际搭过、部署过、被答辩老师追问过的那些细节。2. 技术选型与工程结构为什么这套组合现在依然能打2.1 为什么是 JSP 而不是纯 Servlet 或 Spring Boot先把这个选型问题说透因为答辩时老师十有八九会问。纯 Servlet 的问题是所有 HTML 都得在 Java 代码里用out.println拼字符串一个产品列表页能写出几百行维护起来是灾难。Spring Boot 的问题是对于企业宣传网站这种体量引入依赖注入、自动配置、Maven 多模块学习成本和调试成本陡增一个刚学完 Java 基础的同学很容易卡在环境配置上出不来。JSP 的定位刚好卡在中间它本质还是 Servlet容器会把它编译成 Servlet 执行但写法上允许你在 HTML 里嵌入 Java 代码和标签页面结构和数据填充能放在一起写。对于「展示为主、交互为辅」的企业宣传网站这个模型非常顺手。常见做法是 JSP 负责视图渲染Servlet 负责接收请求和调度JavaBean 负责数据封装DAO 负责数据库访问这就是经典的 Model1 或 Model2MVC结构。我一般推荐用 Model2也就是 MVC 三层JSP 只做展示Servlet 做控制器JavaBean DAO 做模型。这样答辩时你能清楚地说出「视图、控制、模型分离」比 Model1 那种 JSP 里直接写数据库代码要专业得多也更容易扩展。2.2 工程目录结构怎么组织一个能直接跑、结构清晰的企业宣传网站工程目录大致是这样组织的。这里以 Eclipse 动态 Web 项目为例IDEA 新建 JSP 项目的结构逻辑一致只是目录名略有差别。EnterpriseSite/ ├── src/ │ └── com/company/ │ ├── dao/ // 数据访问层 │ │ ├── NewsDao.java │ │ └── ProductDao.java │ ├── model/ // 实体类 JavaBean │ │ ├── News.java │ │ └── Product.java │ ├── servlet/ // 控制器 │ │ ├── NewsServlet.java │ │ └── ProductServlet.java │ └── util/ // 工具类 │ └── DBUtil.java ├── WebContent/ │ ├── css/ │ ├── js/ │ ├── images/ │ ├── WEB-INF/ │ │ ├── web.xml // 部署描述符 │ │ └── lib/ // 第三方 jar │ ├── index.jsp // 首页 │ ├── news.jsp // 新闻列表 │ ├── product.jsp // 产品展示 │ └── admin/ // 后台管理页面 └── ...这个结构的关键点在于WEB-INF目录下的内容浏览器无法直接访问所以把web.xml和第三方 jar 放这里是安全的而 JSP 页面放在WebContent根目录下才能被直接请求。src下的包按职责分层答辩时打开工程一眼就能看出你的架构意识。2.3 数据库表设计五张表撑起整个网站企业宣传网站的数据模型不复杂五张表基本够用。下面给出建表语句字段类型和长度都是我在实际项目里验证过的可以直接抄。-- 新闻资讯表 CREATE TABLE news ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(200) NOT NULL, content TEXT, author VARCHAR(50), publish_time DATETIME DEFAULT CURRENT_TIMESTAMP, category VARCHAR(50) ); -- 产品表 CREATE TABLE product ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(200) NOT NULL, description TEXT, price DECIMAL(10,2), image_url VARCHAR(500), category VARCHAR(50), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 管理员表 CREATE TABLE admin ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) UNIQUE NOT NULL, password VARCHAR(100) NOT NULL, real_name VARCHAR(50) ); -- 留言表 CREATE TABLE message ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50), email VARCHAR(100), content TEXT, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, is_read TINYINT DEFAULT 0 ); -- 单页内容表关于我们、联系方式等 CREATE TABLE page_content ( id INT PRIMARY KEY AUTO_INCREMENT, page_key VARCHAR(50) UNIQUE, page_title VARCHAR(200), content TEXT, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP );参数说明news表的category用来区分「公司新闻」「行业动态」前端可以按分类筛选product表的image_url存图片相对路径而不是二进制避免数据库膨胀admin表的password长度给到 100是为了后面存 MD5 或加盐哈希留空间不要用明文page_content表用page_key做唯一键这样「关于我们」这种单页内容可以通过 key 直接查不用为每个单页建一张表。2.4 数据库连接工具类的写法数据库连接是 JSP 项目最容易翻车的地方很多同学在每个 Servlet 里都写一遍DriverManager.getConnection结果连接泄漏、代码重复。正确做法是抽一个DBUtil工具类统一管理连接获取和释放。package com.company.util; import java.sql.*; public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/enterprise_site?useSSLfalseserverTimezoneUTCcharacterEncodingutf8; private static final String USER root; private static final String PASSWORD your_password; static { try { Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { throw new RuntimeException(MySQL驱动加载失败, e); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } public static void close(Connection conn, Statement stmt, ResultSet rs) { try { if (rs ! null) rs.close(); } catch (SQLException e) { e.printStackTrace(); } try { if (stmt ! null) stmt.close(); } catch (SQLException e) { e.printStackTrace(); } try { if (conn ! null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }逻辑说明静态代码块在类加载时执行一次注册驱动避免每次获取连接都反射加载。close方法按 ResultSet、Statement、Connection 的顺序关闭这是 JDBC 资源释放的标准顺序反过来关会报错。参数上serverTimezoneUTC是 MySQL 8 驱动必须带的不带会抛时区异常characterEncodingutf8保证中文不乱码。注意your_password要换成你自己的数据库密码这个类不要提交到公开仓库。3. 核心功能实现从首页展示到后台管理的完整链路3.1 首页数据加载Servlet 查数据JSP 只负责渲染首页通常要展示最新新闻、推荐产品、公司简介三块内容。正确做法是写一个IndexServlet在doGet里查好数据塞进 request 域然后转发到index.jsp。package com.company.servlet; import com.company.dao.NewsDao; import com.company.dao.ProductDao; import com.company.model.News; import com.company.model.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; import java.util.List; WebServlet(/index) public class IndexServlet extends HttpServlet { private NewsDao newsDao new NewsDao(); private ProductDao productDao new ProductDao(); Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ListNews latestNews newsDao.findLatest(5); ListProduct hotProducts productDao.findByCategory(推荐, 6); req.setAttribute(latestNews, latestNews); req.setAttribute(hotProducts, hotProducts); req.getRequestDispatcher(/index.jsp).forward(req, resp); } }逻辑说明WebServlet(/index)是 Servlet 3.0 的注解方式不用在web.xml里再配一遍这是现在的主流写法。findLatest(5)和findByCategory(推荐, 6)是 DAO 层方法分别取最新 5 条新闻和 6 个推荐产品。req.setAttribute把数据放进请求域forward转发到 JSP注意这里必须用 forward 而不是 redirect因为 redirect 会丢失 request 域的数据。对应的index.jsp里用 JSTL 标签遍历不要用 Java 脚本片段% page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % % taglib prefixfmt urihttp://java.sun.com/jsp/jstl/fmt % html headtitle企业宣传网站/title/head body div classnews-list c:forEach items${latestNews} varnews div classnews-item h3a hrefnewsDetail?id${news.id}${news.title}/a/h3 span classtime fmt:formatDate value${news.publishTime} patternyyyy-MM-dd/ /span /div /c:forEach /div /body /html参数说明c:forEach的items对应 request 域里的latestNewsvar是循环变量名。fmt:formatDate用来格式化日期pattern里yyyy-MM-dd是年月日注意MM必须大写小写mm是分钟这是新手最常犯的错。用 JSTL 而不是% %脚本片段是因为 JSTL 更清晰也符合 MVC 里 JSP 只做展示的原则。3.2 新闻列表分页三个参数决定翻页是否正常新闻列表页数据量大必须分页。分页的核心是三个参数当前页码pageNo、每页条数pageSize、总记录数totalCount。DAO 层用LIMIT实现。public ListNews findByPage(int pageNo, int pageSize) { ListNews list new ArrayList(); String sql SELECT * FROM news ORDER BY publish_time DESC LIMIT ?, ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setInt(1, (pageNo - 1) * pageSize); ps.setInt(2, pageSize); ResultSet rs ps.executeQuery(); while (rs.next()) { News n new News(); n.setId(rs.getInt(id)); n.setTitle(rs.getString(title)); n.setPublishTime(rs.getTimestamp(publishTime)); list.add(n); } } catch (SQLException e) { e.printStackTrace(); } return list; }逻辑说明LIMIT的第一个参数是偏移量计算公式是(pageNo - 1) * pageSize第二个参数是每页条数。比如第 2 页、每页 10 条偏移量就是 10取第 11 到 20 条。这里用PreparedStatement而不是字符串拼接是为了防 SQL 注入答辩时这一点一定要能说出来。try-with-resources语法会自动关闭 Connection 和 PreparedStatement比手动 close 更安全。分页还需要一个查总数的 SQLSELECT COUNT(*) FROM news返回totalCount然后总页数totalPage (totalCount pageSize - 1) / pageSize。这个向上取整公式要记住用totalCount / pageSize直接除会少一页。3.3 后台登录与权限拦截Filter 是绕不过去的一环后台管理页面不能让任何人直接访问必须做登录校验。做法是写一个LoginFilter拦截/admin/*路径检查 session 里有没有登录标记。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; HttpSession session request.getSession(); Object admin session.getAttribute(admin); if (admin null) { response.sendRedirect(request.getContextPath() /admin/login.jsp); return; } chain.doFilter(req, resp); } }逻辑说明WebFilter(/admin/*)拦截 admin 目录下所有请求。session.getAttribute(admin)取登录时存进去的管理员对象为空说明没登录重定向到登录页。注意request.getContextPath()会返回项目部署路径比如/EnterpriseSite拼上/admin/login.jsp才是完整路径直接写/admin/login.jsp在非根路径部署时会 404。登录成功后要session.setAttribute(admin, adminObj)退出时session.invalidate()。3.4 留言板功能表单提交与防重复提交留言板是企业和访客互动的入口实现上要注意两点一是表单提交后要防止刷新重复插入二是留言内容要过滤特殊字符。WebServlet(/message/add) public class MessageAddServlet extends HttpServlet { private MessageDao messageDao new MessageDao(); Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding(UTF-8); String name req.getParameter(name); String email req.getParameter(email); String content req.getParameter(content); if (name null || name.trim().isEmpty() || content null || content.trim().isEmpty()) { req.setAttribute(error, 姓名和留言内容不能为空); req.getRequestDispatcher(/message.jsp).forward(req, resp); return; } Message msg new Message(); msg.setName(name.trim()); msg.setEmail(email); msg.setContent(content.trim()); messageDao.insert(msg); resp.sendRedirect(req.getContextPath() /message?success1); } }逻辑说明req.setCharacterEncoding(UTF-8)必须在取参数之前调用否则中文乱码。参数校验先做为空就转发回表单页并带错误提示。插入成功后用sendRedirect重定向这是防重复提交的关键——重定向后浏览器地址栏变成列表页用户刷新也不会重复提交表单。如果这里用 forward刷新就会重复插入这是血泪经验。4. 部署与打包传统 JSP 项目怎么打成 war 跑起来4.1 用 Maven 打包 war 的标准配置传统 JSP 项目打包成 war 是部署的标准动作。用 Maven 的话pom.xml里关键配置如下packagingwar/packaging dependencies dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version4.0.1/version scopeprovided/scope /dependency dependency groupIdjavax.servlet.jsp/groupId artifactIdjavax.servlet.jsp-api/artifactId version2.3.3/version scopeprovided/scope /dependency dependency groupIdjavax.servlet/groupId artifactIdjstl/artifactId version1.2/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.28/version /dependency /dependencies参数说明packagingwar/packaging声明打包类型是 war。servlet-api 和 jsp-api 的scope必须是provided因为 Tomcat 容器里已经有这两个包了打进去会冲突。jstl 和 mysql 驱动必须是compile默认作用域要打进 war 的WEB-INF/lib下。执行mvn clean package后target目录下会生成EnterpriseSite.war。4.2 部署到 Tomcat 的两种方式第一种是直接把 war 包丢进 Tomcat 的webapps目录启动 Tomcat 会自动解压部署访问路径是http://localhost:8080/EnterpriseSite/。第二种是在 Tomcat 的conf/server.xml里配 Context指定docBase指向你的项目目录适合开发阶段热部署。# 方式一拷贝 war 到 webapps cp target/EnterpriseSite.war $CATALINA_HOME/webapps/ # 启动 Tomcat $CATALINA_HOME/bin/startup.sh # Linux/Mac $CATALINA_HOME\bin\startup.bat # Windows注意如果访问 404先看 Tomcat 的logs/catalina.out有没有报错最常见的是数据库连不上导致 Servlet 初始化失败。如果访问出现中文乱码检查 JSP 页面头部的pageEncoding和数据库连接串的characterEncoding是否都是 UTF-8。4.3 数据库初始化与配置分离部署到新环境时数据库连接信息不能写死在代码里。常见做法是把jdbc.properties放在src下用类加载器读取。jdbc.urljdbc:mysql://localhost:3306/enterprise_site?useSSLfalseserverTimezoneUTCcharacterEncodingutf8 jdbc.usernameroot jdbc.passwordyour_password jdbc.drivercom.mysql.cj.jdbc.Driverpublic class DBUtil { private static Properties props new Properties(); static { try (InputStream in DBUtil.class.getClassLoader() .getResourceAsStream(jdbc.properties)) { props.load(in); Class.forName(props.getProperty(jdbc.driver)); } catch (Exception e) { throw new RuntimeException(数据库配置加载失败, e); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection( props.getProperty(jdbc.url), props.getProperty(jdbc.username), props.getProperty(jdbc.password)); } }逻辑说明getResourceAsStream(jdbc.properties)从 classpath 根目录读取配置文件Maven 项目里src/main/resources下的文件会被复制到 classpath。这样换环境只改配置文件不用重新编译代码。注意配置文件里的密码不要提交到公开仓库答辩演示时用本地库就行。5. 避坑与排查答辩前必须填掉的五个坑5.1 中文乱码三个地方都要设 UTF-8现象页面显示问号或乱码表单提交的中文存进数据库变成乱码。原因JSP 页面编码、请求编码、数据库连接编码三者不一致。JSP 默认可能是 ISO-8859-1请求默认也是数据库表可能是 latin1。解决JSP 头部写% page contentTypetext/html;charsetUTF-8 pageEncodingUTF-8 %Servlet 里doPost第一行写req.setCharacterEncoding(UTF-8)数据库连接串加characterEncodingutf8建表时指定DEFAULT CHARSETutf8mb4。四个地方全对上乱码基本消失。5.2 404 错误路径和部署名对不上现象访问某个 Servlet 或 JSP 报 404。原因一是WebServlet的路径和访问路径不一致二是重定向时没加getContextPath()三是 war 包没部署成功。解决先看 Tomcat 的webapps目录下有没有解压出项目文件夹再看访问路径是否带了项目名比如/EnterpriseSite/news而不是/news重定向统一用request.getContextPath() /xxx。如果用了web.xml配 Servlet检查url-pattern和注解是否重复冲突。5.3 数据库连接失败驱动和时区是重灾区现象启动报ClassNotFoundException或The server time zone value is unrecognized。原因MySQL 8 的驱动类名是com.mysql.cj.jdbc.Driver不是老的com.mysql.jdbc.Driver连接串没带serverTimezone。解决驱动类名改成com.mysql.cj.jdbc.Driver连接串加serverTimezoneUTC。如果还是连不上检查 MySQL 服务是否启动、端口是否 3306、用户名密码是否正确、mysql-connector-java的 jar 是否在WEB-INF/lib下。5.4 JSTL 标签不解析jar 包没打进 war现象JSP 页面直接把c:forEach当文本输出或者报The absolute uri cannot be resolved。原因jstl 的 jar 没在 classpath 里或者 scope 写成了 provided。解决确认pom.xml里 jstl 依赖的 scope 是默认的 compile打包后检查 war 里的WEB-INF/lib下有没有jstl-1.2.jar和standard-1.1.2.jar。如果是非 Maven 项目手动把这两个 jar 拷到WEB-INF/lib下。5.5 后台越权访问Filter 路径配错等于没拦现象没登录也能直接访问/admin/newsList看到后台数据。原因Filter 的urlPatterns写成了/admin而不是/admin/*只拦了 admin 根路径子路径没拦住。解决WebFilter(/admin/*)星号不能少。另外登录页本身要排除在拦截之外否则会死循环重定向。可以在 Filter 里判断请求路径如果是login.jsp或login就放行。答辩时老师很可能会手动输 URL 测试越权这个坑一定要提前堵上。6. 让答辩加分的一个技巧把静态页面改成可配置的单页内容大部分同学做企业宣传网站「关于我们」「联系方式」这些页面都是写死的 HTML改个电话号还得改代码重新部署。我在实际项目里会多做一步把这些单页内容也存进数据库后台可编辑前台动态读取。这个改动不大但答辩时是个明显的加分项因为它体现了「内容可维护」的产品思维。具体做法是复用第 2 章建的page_content表写一个PageContentServlet根据pageKey查内容转发到统一的page.jsp渲染。WebServlet(/page) public class PageContentServlet extends HttpServlet { private PageContentDao pageDao new PageContentDao(); Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String key req.getParameter(key); if (key null || key.trim().isEmpty()) { resp.sendError(HttpServletResponse.SC_NOT_FOUND); return; } PageContent pc pageDao.findByKey(key); if (pc null) { resp.sendError(HttpServletResponse.SC_NOT_FOUND); return; } req.setAttribute(page, pc); req.getRequestDispatcher(/page.jsp).forward(req, resp); } }逻辑说明前台访问/page?keyabout就能看到「关于我们」访问/page?keycontact看到联系方式。page.jsp里用${page.content}输出注意如果内容里含 HTML 标签要用c:out value${page.content} escapeXmlfalse/才能渲染默认escapeXmltrue会把标签转义成文本。后台再加一个编辑页管理员改完update一下前台立刻生效不用重启 Tomcat。对应的后台编辑表单核心代码form actionpageUpdate methodpost input typehidden namepageKey value${page.pageKey}/ input typetext namepageTitle value${page.pageTitle}/ textarea namecontent rows15${page.content}/textarea button typesubmit保存/button /form参数说明pageKey用隐藏域传保证更新的是同一条记录textarea里直接放${page.content}注意不要有多余空格否则每次保存都会多出空白。更新 SQL 用UPDATE page_content SET page_title?, content? WHERE page_key?。这个技巧的价值在于它把「静态展示」升级成了「动态可维护」答辩时你可以说「企业宣传网站的核心诉求是内容更新及时所以我把单页内容也做成了后台可配置」。这句话一说老师就知道你不是照着模板抄的而是想过业务。我自己做这类项目最大的教训是不要一上来就追求功能多先把首页、列表、详情、后台登录这四条主链路跑通再考虑留言板、单页配置这些加分项。很多同学卡在环境配置和乱码上耗掉一周最后功能没做完答辩时演示都跑不起来。先把最小可运行版本跑起来再迭代这个习惯比任何技术细节都重要。希望帮到你。本文还有配套的精品资源点击获取
返回列表