1. 为什么选择SSM框架开发博客系统
在Java Web开发领域,SSM(Spring+SpringMVC+MyBatis)框架组合一直是企业级应用开发的中坚力量。作为一个从2013年就开始使用SSM框架的老兵,我见证了这个技术栈从最初的配置繁琐到如今SpringBoot加持下的便捷开发全过程。
博客系统作为典型的CRUD应用,看似简单实则暗藏玄机。它需要处理文章管理、用户认证、评论互动等核心功能,同时还要考虑性能优化和扩展性。SSM框架的轻量级特性使其成为这类中小型项目的理想选择:
- Spring:提供了强大的IoC容器和AOP支持,让业务逻辑解耦变得简单
- SpringMVC:优雅的MVC架构模式,处理Web请求游刃有余
- MyBatis:灵活的SQL映射框架,既保留了SQL的灵活性又简化了数据库操作
提示:虽然现在SpringBoot+MyBatis-Plus的组合更流行,但掌握原生SSM框架能让你更深入理解框架底层原理。这也是我坚持用原生SSM教学的原因。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 项目初始化:从零搭建SSM环境
2.1 创建Maven项目结构
我习惯使用IntelliJ IDEA作为开发工具,以下是创建项目的标准流程:
- 新建Maven项目,选择
maven-archetype-webapp原型 - 补全目录结构(手动创建java和resources目录)
- 修改pom.xml引入核心依赖:
xml复制<!-- Spring核心依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.18</version>
</dependency>
<!-- SpringMVC依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.18</version>
</dependency>
<!-- MyBatis核心 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<!-- MyBatis-Spring整合包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
2.2 配置web.xml与Spring配置文件
在web.xml中配置DispatcherServlet和ContextLoaderListener:
xml复制<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
注意:这里我特意将Spring配置和SpringMVC配置分开,这是为了避免后续出现循环引用问题。很多新手会把所有配置都放在spring-mvc.xml中,这会导致事务管理等Spring功能失效。
2.3 数据库设计与MyBatis配置
博客系统至少需要以下几张表:
| 表名 | 主要字段 | 说明 |
|---|---|---|
| blog_article | id, title, content, create_time, update_time | 文章表 |
| blog_category | id, name | 分类表 |
| blog_comment | id, article_id, content, create_time | 评论表 |
| blog_user | id, username, password | 用户表 |
在applicationContext.xml中配置数据源和MyBatis:
xml复制<!-- 数据源配置 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/blog_db?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!-- MyBatis SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>
<!-- Mapper扫描配置 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.example.blog.mapper"/>
</bean>
3. 基础功能实现:文章管理模块
3.1 实体类与Mapper接口设计
首先创建文章实体类:
java复制public class Article {
private Long id;
private String title;
private String content;
private Date createTime;
private Date updateTime;
// 省略getter/setter
}
然后定义Mapper接口:
java复制public interface ArticleMapper {
int insert(Article article);
int updateById(Article article);
int deleteById(Long id);
Article selectById(Long id);
List<Article> selectAll();
}
对应的Mapper XML文件:
xml复制<mapper namespace="com.example.blog.mapper.ArticleMapper">
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO blog_article(title, content, create_time, update_time)
VALUES(#{title}, #{content}, #{createTime}, #{updateTime})
</insert>
<select id="selectById" resultType="Article">
SELECT * FROM blog_article WHERE id = #{id}
</select>
</mapper>
3.2 Service层实现业务逻辑
Service层是业务逻辑的核心,这里我们实现文章的基本CRUD操作:
java复制@Service
public class ArticleService {
@Autowired
private ArticleMapper articleMapper;
public void saveArticle(Article article) {
if(article.getId() == null) {
article.setCreateTime(new Date());
articleMapper.insert(article);
} else {
article.setUpdateTime(new Date());
articleMapper.updateById(article);
}
}
public Article getArticleById(Long id) {
return articleMapper.selectById(id);
}
// 其他方法省略...
}
3.3 Controller层处理HTTP请求
SpringMVC的Controller负责接收和响应HTTP请求:
java复制@Controller
@RequestMapping("/article")
public class ArticleController {
@Autowired
private ArticleService articleService;
@GetMapping("/{id}")
public String detail(@PathVariable Long id, Model model) {
Article article = articleService.getArticleById(id);
model.addAttribute("article", article);
return "article/detail";
}
@PostMapping("/save")
public String save(Article article) {
articleService.saveArticle(article);
return "redirect:/article/" + article.getId();
}
}
4. 视图层:Thymeleaf模板集成
4.1 配置Thymeleaf视图解析器
在spring-mvc.xml中添加配置:
xml复制<bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
<bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver"/>
</bean>
<bean id="templateResolver" class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
4.2 编写文章详情页模板
创建/WEB-INF/views/article/detail.html:
html复制<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title th:text="${article.title}">文章标题</title>
</head>
<body>
<h1 th:text="${article.title}"></h1>
<div th:utext="${article.content}"></div>
<p>发布时间:<span th:text="${#dates.format(article.createTime, 'yyyy-MM-dd HH:mm')}"></span></p>
</body>
</html>
5. 开发中的常见问题与解决方案
5.1 事务管理配置
很多SSM项目忘记配置事务管理,导致数据库操作没有事务保障。正确做法是在applicationContext.xml中添加:
xml复制<!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 开启注解驱动的事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
然后在Service方法上添加@Transactional注解:
java复制@Transactional
public void saveArticle(Article article) {
// 业务逻辑
}
5.2 静态资源访问问题
SpringMVC会拦截所有请求,导致静态资源无法访问。解决方案是在spring-mvc.xml中添加:
xml复制<mvc:resources mapping="/static/**" location="/static/"/>
5.3 MyBatis映射文件热加载
开发过程中修改Mapper XML后需要重启应用才能生效,可以通过以下配置实现热加载:
xml复制<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
<property name="configurationProperties">
<props>
<prop key="cacheEnabled">false</prop>
</props>
</property>
</bean>
6. 项目结构优化建议
经过多年SSM项目开发,我总结出以下项目结构最佳实践:
code复制src/main/java
├── com.example.blog
│ ├── config # 配置类
│ ├── controller # 控制器
│ ├── service # 服务层
│ ├── mapper # MyBatis Mapper接口
│ ├── entity # 实体类
│ └── util # 工具类
src/main/resources
├── spring # Spring配置文件
├── mapper # MyBatis映射文件
└── static # 静态资源
这种结构清晰明了,适合中小型项目。对于大型项目,可以按功能模块进一步划分。
