这个基于Java技术栈的博客系统,是一个典型的全栈Web应用开发案例。我花了三个月时间从零构建这个系统,期间经历了三次架构调整和五次UI改版,最终形成了现在这个稳定版本。系统采用SpringBoot作为基础框架,整合了SSM(Spring+SpringMVC+MyBatis)技术栈,实现了从内容管理到用户交互的完整博客功能链。
这个系统最核心的价值在于:它不是一个简单的CRUD演示项目,而是包含了生产环境中真正需要的各种细节处理。比如文章自动保存、Markdown双栏预览、访客行为分析这些实际博客运营中必不可少的功能。后台管理模块采用RBAC权限模型,支持多级菜单配置,前端则使用Thymeleaf模板引擎实现服务端渲染,兼顾了开发效率和页面性能。
选择SpringBoot 2.7作为基础框架有几个关键考量:
java复制// 典型的SpringBoot启动类配置
@SpringBootApplication
@MapperScan("com.blog.dao")
@EnableCaching
public class BlogApplication {
public static void main(String[] args) {
SpringApplication.run(BlogApplication.class, args);
}
}
MyBatis的灵活SQL编写能力特别适合内容管理系统:
xml复制<!-- 文章分页查询的动态SQL示例 -->
<select id="selectArticlePage" resultMap="ArticleResult">
SELECT * FROM blog_article
<where>
<if test="categoryId != null">AND category_id = #{categoryId}</if>
<if test="tagId != null">AND id IN (SELECT article_id FROM blog_article_tag WHERE tag_id = #{tagId})</if>
<if test="keyword != null">AND (title LIKE CONCAT('%',#{keyword},'%') OR summary LIKE CONCAT('%',#{keyword},'%'))</if>
</where>
ORDER BY is_top DESC, create_time DESC
</select>
文章编辑采用前后端分离设计:
java复制// 文章自动保存服务实现
@Scheduled(fixedRate = 30000)
public void autoSaveArticles() {
draftCache.forEach((userId, draft) -> {
if(draft.isModified()) {
articleService.saveDraft(userId, draft);
draft.setModified(false);
}
});
}
采用RBAC模型实现精细化的权限管理:
java复制// 权限检查切面
@Aspect
@Component
public class PermissionAspect {
@Before("@annotation(requiresPermission)")
public void checkPermission(RequiresPermission requiresPermission) {
String permission = requiresPermission.value();
if(!SecurityUtils.getSubject().isPermitted(permission)) {
throw new UnauthorizedException();
}
}
}
采用多级缓存架构:
重要提示:缓存更新策略采用"先更新数据库再删除缓存"的模式,避免并发写导致的脏数据问题
针对博客系统的特点做了以下优化:
sql复制-- 优化的文章表结构
CREATE TABLE `blog_article` (
`id` BIGINT PRIMARY KEY,
`title` VARCHAR(100) NOT NULL,
`summary` VARCHAR(255),
`category_id` INT,
`user_id` INT NOT NULL,
`create_time` DATETIME NOT NULL,
`update_time` DATETIME,
`status` TINYINT DEFAULT 1,
INDEX `idx_category_status` (`category_id`, `status`),
INDEX `idx_user` (`user_id`)
);
CREATE TABLE `blog_article_content` (
`article_id` BIGINT PRIMARY KEY,
`content` LONGTEXT,
FOREIGN KEY (`article_id`) REFERENCES `blog_article`(`id`)
);
推荐使用Docker Compose进行容器化部署:
yaml复制version: '3'
services:
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql/data:/var/lib/mysql
redis:
image: redis:6
ports:
- "6379:6379"
app:
build: .
ports:
- "8080:8080"
depends_on:
- mysql
- redis
集成Spring Boot Actuator和Prometheus:
properties复制# application-prod.properties
management.endpoints.web.exposure.include=health,info,metrics,prometheus
management.metrics.tags.application=blog-system
最初直接存储原始Markdown导致的问题:
最终解决方案:
第一版采用简单的平铺结构导致:
改进后的MPTT模型实现:
java复制public class Comment {
private Long id;
private String content;
private Long left;
private Long right;
private Long depth;
// 其他字段...
public boolean isRoot() {
return depth == 1;
}
}
对比了三种实现方式后选择Elasticsearch:
java复制// ES文章索引服务
public interface ArticleSearchService {
void indexArticle(Article article);
void deleteArticle(Long id);
Page<Article> search(String query, Pageable pageable);
}
基于切面的无侵入式统计:
java复制@Aspect
@Component
public class VisitCounterAspect {
@Autowired
private VisitService visitService;
@AfterReturning("execution(* com.blog.web.controller.ArticleController.detail(..)) && args(id,..)")
public void countVisit(Long id) {
String ip = IpUtils.getIpAddr();
if(!visitService.isTodayVisited(id, ip)) {
visitService.recordVisit(id, ip);
}
}
}
这个博客系统从技术选型到功能实现都经过精心设计,特别是在内容处理、权限控制和性能优化方面有很多值得参考的实践。系统目前每天能稳定处理10万+PV,峰值时期也能保持良好的响应速度。