JavaWeb实战--从零搭建个人博客系统全流程手记

📅 发布时间:2026/7/15 18:50:06 👁️ 浏览次数:
JavaWeb实战--从零搭建个人博客系统全流程手记
1. 从零开始搭建你的JavaWeb博客开发环境很多朋友想自己动手做一个博客网站记录技术心得或者生活感悟但又觉得JavaWeb技术栈听起来很复杂什么Servlet、JSP、MySQL感觉无从下手。其实我刚开始学的时候也是这种感觉觉得要配置一堆东西头都大了。但后来我发现只要把环境搭好后面的路就走顺了一大半。今天我就用我这十来年踩坑的经验带你一步步把博客系统的“地基”给打好保证你跟着做就能跑起来。首先你得有个趁手的“工具箱”。JavaWeb开发说白了就是用Java语言写网站的后台逻辑。所以基础的Java开发环境JDK是必须的我推荐你用JDK 8或者JDK 11这两个版本比较稳定社区支持也好。安装好JDK后记得配置一下JAVA_HOME环境变量这个非常关键很多新手启动服务器失败问题就出在这里。你可以打开命令行输入java -version如果能正确显示版本号那就说明JDK装好了。光有JDK还不够我们的博客数据得有个地方存吧这就轮到MySQL数据库上场了。去MySQL官网下载社区版一路“下一步”安装就行。安装过程中会让你设置root用户的密码这个密码一定要记牢后面连接数据库要用。装好之后我建议你再装一个图形化的管理工具比如Navicat或者MySQL Workbench用它们来创建数据库、表会直观很多比在命令行里敲代码舒服。我们的博客系统至少需要几张表用户表存账号密码、文章表存标题、内容、发布时间、分类表等。你可以先不用管具体字段等我们写到那一步的时候再细说。接下来是重头戏Web服务器。Java写的网站不能直接双击运行需要一个容器来托管和运行这个容器就是Web服务器。Tomcat是其中最经典、最常用的一个完全免费开源。你去Apache Tomcat官网下载一个8.5或者9.x版本的Core压缩包zip格式。下载完解压到一个没有中文和特殊符号的目录比如D:\dev\tomcat-9.0.80。这一点我强调三遍路径里千万别有中文很多莫名其妙的错误都源于此。解压后进入bin目录你会看到一堆脚本文件。在Windows下双击startup.bat在Mac或Linux下运行./startup.sh。如果看到一个命令行窗口打开并且最后几行没有报错显示类似Server startup in [xxxx] milliseconds的信息那就恭喜你Tomcat启动成功了。如果窗口一闪而过那八成是JAVA_HOME没配置对回去检查一下。启动成功后打开浏览器输入http://localhost:8080你应该能看到那只著名的“汤姆猫”欢迎页面。看到这个页面你的服务器就跑起来了。最后是集成开发环境IDE。我强烈推荐使用IntelliJ IDEA的社区版它对JavaWeb开发的支持非常友好而且是免费的。在IDEA里创建一个新的Java Enterprise项目选择Web Application模板它会自动帮你生成一个基础的Web项目结构。这个结构里src目录放你的Java源代码web目录或者叫webapp放你的网页文件HTML、JSP和静态资源CSS、JS、图片。创建好项目后我们需要把项目“部署”到刚才启动的Tomcat服务器上。在IDEA里配置Tomcat服务器路径然后设置项目的“上下文路径”比如/myblog。这样你将来访问博客的地址就是http://localhost:8080/myblog了。你还可以在web.xml文件里设置一个默认首页比如叫index.jsp这样访问http://localhost:8080/myblog时就会自动打开这个页面不用再手动输入文件名。2. 动起来的网页JSP与Servlet核心初探环境搭好了我们来聊聊怎么让网页“活”起来。静态的HTML页面只能展示固定内容而我们的博客需要能发布新文章、展示文章列表、处理用户登录这些都需要动态生成内容。在JavaWeb里实现动态网页最经典的技术组合就是JSP和Servlet。你可以把Servlet理解为一个Java类专门用来处理HTTP请求。当用户在浏览器里点击一个链接或者提交一个表单时这个请求就会被发送到对应的Servlet。Servlet里写着处理这个请求的Java代码比如从数据库查数据、做计算、判断用户权限等等。处理完后它再决定把什么内容可能是一个新的HTML页面也可能是一段JSON数据发回给浏览器。Servlet是真正的幕后英雄干的是最核心的“脏活累活”。那JSP又是什么呢JSP的全称是Java Server Pages你可以把它看作一个能写Java代码的HTML文件。它存在的意义是为了方便我们制作动态页面。想象一下如果所有网页内容都要靠Servlet用out.println(“html…/html”)这种一句句拼接的方式输出那简直是一场灾难代码又乱又难维护。JSP允许我们在HTML骨架里直接插入Java代码片段来动态生成内容。当服务器收到一个对JSP页面的请求时它会先把JSP“翻译”成一个Servlet然后再执行。所以JSP本质上是Servlet的一种更便捷的书写形式。在JSP里写Java代码很简单用%和%包裹起来就行。比如我想在网页上显示当前时间p现在时间是% new java.util.Date() %/p这里的% ... %就是一种特殊的脚本元素它的作用是计算表达式的值并直接输出到页面上。再比如我想根据登录状态显示不同的欢迎语% String username (String) session.getAttribute(user); if (username ! null) { % h2欢迎回来% username %/h2 % } else { % h2请先a hreflogin.jsp登录/a。/h2 % } %这段代码从session会话后面会讲里取出用户信息如果有就显示欢迎语如果没有就提示登录。你看逻辑和展示混编在一起对于简单的页面非常直观。但是随着项目变大这种在JSP里大量写Java代码的方式会带来问题比如代码难以阅读、难以测试、前后端职责不清。这就是为什么我们强调要结合使用Servlet和JSP。最佳实践是Servlet负责控制逻辑接收请求、处理业务、准备数据JSP只负责展示渲染接收Servlet传过来的数据呈现成HTML。这种模式就是经典的MVC模式Model-View-Controller在JavaWeb中的体现Servlet充当控制器ControllerJSP充当视图View。我们后面构建博客功能时就会严格遵循这个模式。3. 数据的桥梁连接MySQL与JDBC实战博客的核心是内容内容存在数据库里。所以如何让我们的Java程序跟MySQL数据库“对话”是必须掌握的一环。这个对话的桥梁就是JDBCJava Database Connectivity。首先你需要把MySQL的JDBC驱动包一个mysql-connector-java-xxx.jar文件放到项目的WEB-INF/lib目录下。这个目录是专门放项目依赖的jar包的Tomcat在运行时会自动加载这里的库。没这个驱动包Java就认不得MySQL。连接数据库我习惯写一个工具类把那些繁琐的步骤封装起来。这个工具类主要干四件事获取连接、关闭连接。获取连接需要四个关键信息数据库地址、端口、库名、用户名和密码。下面是我常用的一个工具类雏形public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/my_blog_db?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghai; private static final String USER root; private static final String PASSWORD your_password; static { try { // 加载驱动新版本MySQL可以省略这行 Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } 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(); } } }这里有几个坑点我提一下第一URL里的serverTimezoneAsia/Shanghai很重要不设置可能会遇到时区错误。第二关闭资源的顺序必须是ResultSet-Statement-Connection并且每个关闭都要放在单独的try-catch里避免一个关闭出错导致后面的资源无法关闭造成泄漏。有了连接工具我们就可以进行增删改查CRUD了。以博客文章表为例我们先设计一个Article实体类里面的属性对应数据库表的字段。然后创建一个ArticleDaoData Access Object数据访问对象这里面专门放操作数据库的方法。比如查询所有文章的方法public class ArticleDao { public ListArticle findAllArticles() { ListArticle list new ArrayList(); Connection conn null; PreparedStatement pstmt null; ResultSet rs null; try { conn DBUtil.getConnection(); String sql SELECT id, title, content, author_id, create_time FROM article ORDER BY create_time DESC; pstmt conn.prepareStatement(sql); rs pstmt.executeQuery(); while (rs.next()) { Article article new Article(); article.setId(rs.getInt(id)); article.setTitle(rs.getString(title)); article.setContent(rs.getString(content)); // ... 设置其他字段 list.add(article); } } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.close(conn, pstmt, rs); } return list; } }这里我强烈推荐使用PreparedStatement而不是Statement。因为PreparedStatement可以预编译SQL效率更高而且它能有效防止SQL注入攻击。比如插入文章时参数用?占位String sql INSERT INTO article (title, content, author_id) VALUES (?, ?, ?); pstmt conn.prepareStatement(sql); pstmt.setString(1, article.getTitle()); pstmt.setString(2, article.getContent()); pstmt.setInt(3, article.getAuthorId()); pstmt.executeUpdate();这样即使用户输入里包含恶意的SQL代码也会被当作普通字符串处理不会被执行安全性大大提升。数据库操作是博客系统的基石这块代码的健壮性和安全性一定要写好。4. 用户与内容管理实现博客核心功能基础打牢了现在我们开始砌墙盖瓦实现博客的具体功能。一个最基础的博客系统至少需要用户管理和文章管理两大块。用户管理主要包括注册和登录。注册页面就是一个表单提交用户名、密码最好有确认密码、邮箱等信息到Servlet。Servlet接收到请求后先检查用户名是否已存在防止重复注册然后将密码加密后再存入数据库。千万不要明文存储密码我常用的是BCrypt算法Spring Security里有现成的工具类或者用MD5加盐salt也行。注册成功后通常跳转到登录页。登录流程是用户提交账号密码Servlet调用Dao层方法根据用户名查询出加密后的密码然后与用户输入的密码经过同样算法加密后进行比对。如果一致就在服务器端创建一个Session把用户对象至少是用户ID和用户名存进去。Session你可以理解成服务器为这个用户开辟的一块私有储物柜在这次会话浏览器不关闭的一段时间内随时可以存取东西。登录成功后跳转到博客首页。这里就引出一个关键问题如何保护需要登录才能访问的页面比如文章发布页、个人中心页。我们不可能在每个页面的JSP里都写一段检查Session的代码。这时候过滤器Filter就派上大用场了。我们可以写一个AuthFilter拦截所有请求/*。在过滤器的doFilter方法里检查当前请求的路径。如果是登录、注册、静态资源CSS、JS、图片或者登录接口本身就直接放行。对于其他请求检查Session里有没有用户信息。如果没有就重定向到登录页面如果有才允许继续访问。这样所有需要权限的页面就都被统一保护起来了。文章管理是博客的主体。首先需要一个文章发布页面包含标题输入框和一个富文本编辑器为了简单起步可以用一个多行文本域textarea代替。提交文章时Servlet除了接收标题和内容还要从Session中取出当前登录用户的ID作为文章的作者ID连同当前时间一起存入数据库。文章列表展示页是博客的门面。这里我们需要从数据库分页查询文章数据。分页查询的SQL语句是关键SELECT * FROM article ORDER BY create_time DESC LIMIT ?, ?。第一个问号是起始索引(page-1) * size第二个问号是每页条数。把查询到的ListArticle对象通过request.setAttribute(“articleList”, list)方法传递给JSP页面。在JSP页面里使用JSTL标签库来循环展示这个列表会比直接用% for(...) { %的脚本清晰很多% taglib prefixc urihttp://java.sun.com/jsp/jstl/core % c:forEach items${articleList} vararticle div classpost h3a hrefarticleDetail?id${article.id}${article.title}/a/h3 p classsummary${article.summary}.../p span classinfo作者${article.authorName} | 发布于${article.createTime}/span /div /c:forEach文章详情页则是根据URL传递过来的文章ID如/articleDetail?id123查询出对应的单篇文章然后渲染整个内容。这里要注意处理HTML内容的显示如果文章内容里包含HTML标签直接使用${article.content}可能会被转义需要使用c:out value${article.content} escapeXmlfalse/但要注意这可能有XSS安全风险确保内容可信或已做过滤。对于文章的修改和删除一定要做好权限校验。不是登录了就能删所有文章。在执行修改或删除的Servlet中除了检查用户是否登录还要检查当前登录用户的ID是否与这篇文章的作者ID一致。只有作者本人或管理员才有权操作。这个校验逻辑必须放在服务器端不能依赖前端JS前端是可以被篡改的。5. 优化与进阶让博客更像样实现了基本功能后我们的博客已经能跑起来了但还比较“糙”。下面我们来做一些优化让它更健壮、更好用。首先解决中文乱码这个老问题。乱码通常发生在两个阶段请求参数表单提交和响应输出。对于请求我们可以在过滤器中统一设置编码。创建一个EncodingFilter在doFilter方法最开始加上request.setCharacterEncoding(“UTF-8”)和response.setCharacterEncoding(“UTF-8”)并把这个过滤器配置为拦截所有请求且放在最前面执行。对于JSP页面确保页面开头有% page contentType“text/html;charsetUTF-8” language“java” %。对于Servlet的响应可以在service或doPost/doGet方法里设置response.setContentType(“text/html;charsetUTF-8”)。多管齐下基本就能告别乱码。其次引入JSTL和EL表达式来净化JSP页面。我们之前已经在JSP里写了不少% ... %和% ... %这会让页面变得混乱。EL表达式${}可以极大地简化从域对象request、session等中取值的语法。而JSTL标签库提供了循环、判断、格式化等标签能替代绝大部分Java脚本。比如之前的分页逻辑和循环展示用JSTL写会清晰很多。要使用它们你需要将JSTL的两个jar包jstl.jar和standard.jar也放到WEB-INF/lib目录下并在JSP页面头部引入标签库。然后我们考虑一下项目结构优化。随着Servlet增多一个请求对应一个Servlet的方式会让web.xml文件变得臃肿也不利于管理。我们可以采用“一个模块一个Servlet”的方式比如ArticleServlet处理所有与文章相关的请求增删改查。怎么区分不同的操作呢可以在请求参数里加一个action标志比如/article?actionadd是添加/article?actiondeleteid1是删除。在Servlet的service方法里根据action参数的值调用不同的处理方法。这样代码更集中也更好维护。最后聊聊静态资源分离和前端体验。在实际部署时我们通常会把图片、CSS、JS等静态资源放到独立的目录甚至使用CDN加速。在Tomcat中可以配置一个专门的静态资源处理器。对于博客的编辑器如果觉得原生文本框太简陋可以引入一个轻量级的富文本编辑器比如WangEditor或TinyMCE它们配置简单能提供基本的排版功能。对于列表页的加载如果文章很多一次性全部查出来会慢我们前面提到的分页查询就必须实现并且在页面底部给出分页导航栏。还有一个提升用户体验的点是异步加载。比如文章列表的点赞数、评论数可以在页面主体加载完成后再用Ajax去异步获取并更新这样页面首屏显示会更快。Ajax的实现可以使用原生的JavaScript但更简单的是借助jQuery的$.get或$.post方法。服务器端对应的Servlet则不再转发到JSP而是直接输出数据通常是JSON格式。例如点赞功能可以是一个按钮点击后发送Ajax请求到LikeServletServlet更新数据库后返回最新的点赞数前端JS再更新按钮旁边的数字。整个过程页面无需刷新体验流畅。走到这一步你的个人博客系统已经具备了完整的骨架和不错的外观。当然还有无数可以深挖和扩展的方向比如文章分类与标签、评论回复系统、全文搜索、缓存优化等等。但最重要的是你已经亲手走完了从环境搭建、数据库设计、前后端交互到基础功能实现的完整流程。这个过程里遇到的每一个错误提示、解决的每一个Bug都是最宝贵的经验。我建议你把代码托管到GitHub上一方面是个备份另一方面也能记录你的成长轨迹。接下来就试着为你自己的博客添加第一个新功能吧比如一个简单的文章搜索或者一个夜间模式切换动手去做你会发现并没有想象中那么难。