1. 项目概述:诗文爱好者交流平台的技术架构
这个基于SSM框架的Java Web项目,本质上是一个垂直领域的知识社区。我去年为本地诗词协会开发过类似平台,核心诉求很明确:既要满足古典文学爱好者分享赏析的需求,又要具备现代社交平台的互动功能。采用SSM(Spring+SpringMVC+MyBatis)这套经典组合,主要考虑到中小型文化类网站的技术适配性——开发效率、维护成本和性能表现三者间的平衡。
平台包含六大核心模块:用户中心(会员注册/权限管理)、内容管理(诗文发布/分类)、互动模块(评论/收藏)、学习工具(格律检测/注解批注)、数据统计(热门排行)以及后台管理系统。其中JSP主要负责视图渲染,配合EL表达式和JSTL标签库实现动态内容展示,而复杂的业务逻辑全部交给Spring管理的JavaBean处理。
技术选型心得:相比直接使用SpringBoot,传统SSM架构在定制化开发时更灵活。比如我们需要实现特殊的平仄校验算法,在SpringMVC中可以通过自定义Interceptor优雅地实现。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术栈深度解析
2.1 SSM框架协同工作机制
Spring作为IoC容器,通过XML配置(或注解)管理着整个应用的对象生命周期。在我的实现中,特别优化了Bean的加载顺序——先初始化数据校验相关的工具类,再加载Service层组件,最后才是Controller。这种显式控制避免了诗文提交时校验工具未初始化的尴尬情况。
SpringMVC采用经典的Front Controller模式。配置时我特别增加了:
xml复制<mvc:annotation-driven>
<mvc:message-converters>
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
这样前端传参既支持传统的form-data,也能处理JSON格式的诗文数据。对于JSP视图解析,配置了多视图解析器链:
java复制@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setOrder(2); // 优先级低于Thymeleaf
return resolver;
}
2.2 JSP的现代化改造
虽然现在流行前后端分离,但文化类平台的特殊性在于:
- 需要服务端渲染复杂的排版(如竖排诗词)
- 大量使用传统表单提交
- SEO友好度要求高
我们采用改良方案:
- 基础页面框架用JSP
- 动态交互部分通过jQuery Ajax加载
- 复杂排版使用PDF.js嵌入
一个典型的诗文详情页包含:
jsp复制<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<div class="poem-container">
<h2>${poem.title}</h2>
<p class="author">${poem.author}</p>
<div class="content">${poem.content}</div>
<c:if test="${not empty user}">
<button onclick="collectPoem(${poem.id})">收藏</button>
</c:if>
</div>
<script>
function collectPoem(id) {
$.post('/poem/collect', {poemId: id}, function(res){
alert(res.success ? '收藏成功' : '操作失败');
});
}
</script>
2.3 MySQL设计中的文化特性
诗文数据的关系模型需要特殊设计:
sql复制CREATE TABLE `t_poem` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
`author` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
`dynasty` enum('唐','宋','元','明','清','现代') COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`content` text COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '正文',
`format_type` tinyint(4) DEFAULT '1' COMMENT '1-横排 2-竖排',
`rhythm` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '平仄格律',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
FULLTEXT KEY `ft_idx` (`title`,`author`,`content`) WITH PARSER ngram
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
关键设计点:
- 使用utf8mb4_unicode_ci字符集支持生僻字
- 全文检索采用ngram分词器处理文言文
- dynasty字段使用枚举限制朝代范围
- rhythm字段存储平仄模式用于格律校验
3. 核心功能实现细节
3.1 智能格律检测算法
在Service层实现的检测逻辑:
java复制public class RhythmChecker {
private static final String PING = "平";
private static final String ZE = "仄";
public boolean check(String content, String standardPattern) {
String actualPattern = analyze(content);
return match(actualPattern, standardPattern);
}
private String analyze(String text) {
StringBuilder pattern = new StringBuilder();
for (char c : text.toCharArray()) {
if (isPing(c)) {
pattern.append(PING);
} else {
pattern.append(ZE);
}
}
return pattern.toString();
}
private boolean isPing(char c) {
// 实现基于Unicode编码的平仄判断
int code = (int)c;
return (code >= 0x4E00 && code <= 0x9FFF) &&
(平声字Unicode范围判断);
}
}
3.2 高并发收藏处理
采用Redis+MySQL双写策略:
java复制@Transactional
public void collectPoem(Integer userId, Integer poemId) {
// 先写Redis
String key = "user:collect:" + userId;
redisTemplate.opsForSet().add(key, poemId.toString());
// 异步写MySQL
asyncTaskExecutor.execute(() -> {
CollectRecord record = new CollectRecord();
record.setUserId(userId);
record.setPoemId(poemId);
collectMapper.insert(record);
});
}
3.3 敏感词过滤机制
结合传统文化特点设计的过滤方案:
- 基础词库:政治敏感词+不雅词汇
- 扩展词库:历史人物评价敏感词
- 智能过滤:上下文关联分析
实现示例:
java复制public class ContentFilter {
private static final SensitiveWordFilter filter = new SensitiveWordFilter();
public FilterResult filter(String content) {
FilterResult result = new FilterResult();
result.setOriginal(content);
// 基础过滤
String temp = filter.replace(content);
// 文化内容特殊处理
if (containsForbiddenHistoryRef(temp)) {
result.setPassed(false);
result.setReason("包含敏感历史内容");
return result;
}
result.setContent(temp);
result.setPassed(true);
return result;
}
}
4. 性能优化实践
4.1 静态资源处理
针对诗文图片的特殊优化:
xml复制<mvc:resources mapping="/assets/**" location="/WEB-INF/assets/"
cache-period="31536000" resource-chain="true">
<mvc:resolvers>
<bean class="org.springframework.web.servlet.resource.GzipResourceResolver"/>
<bean class="org.springframework.web.servlet.resource.VersionResourceResolver">
<property name="strategyMap">
<map>
<entry key="/**" value-ref="contentVersionStrategy"/>
</map>
</property>
</bean>
</mvc:resolvers>
</mvc:resources>
4.2 SQL优化案例
典型慢查询优化前后对比:
sql复制-- 优化前(执行时间1.8s)
SELECT * FROM t_poem
WHERE content LIKE '%明月%'
ORDER BY create_time DESC
LIMIT 20;
-- 优化后(执行时间0.02s)
SELECT p.* FROM t_poem p
JOIN (
SELECT id FROM t_poem
WHERE MATCH(content) AGAINST('明月' IN BOOLEAN MODE)
ORDER BY create_time DESC
LIMIT 20
) tmp ON p.id = tmp.id;
4.3 JSP编译加速
在tomcat/conf/web.xml添加:
xml复制<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>development</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>compilerClassName</param-name>
<param-value>org.apache.jasper.compiler.JDTCompiler</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
5. 典型问题排查实录
5.1 中文乱码问题
完整解决方案:
- 数据库连接串添加参数:
code复制jdbc:mysql://localhost:3306/poem?useUnicode=true&characterEncoding=UTF-8 - 在Spring配置中设置:
java复制@Bean public Filter characterEncodingFilter() { CharacterEncodingFilter filter = new CharacterEncodingFilter(); filter.setEncoding("UTF-8"); filter.setForceEncoding(true); return filter; } - JSP页面头部添加:
jsp复制<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
5.2 MyBatis缓存失效
症状:诗文更新后页面显示旧数据
根本原因:二级缓存与Spring事务未正确配合
解决方案:
xml复制<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="localCacheScope" value="STATEMENT"/>
</settings>
<!-- 在Mapper.xml中明确配置 -->
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
5.3 JSP包含路径问题
正确引用方式:
jsp复制<%-- 绝对路径从WebRoot开始 --%>
<%@ include file="/WEB-INF/include/header.jsp" %>
<%-- 动态包含 --%>
<jsp:include page="${contextPath}/include/footer.jsp"/>
6. 项目部署实践
6.1 多环境配置
使用Profile管理不同环境:
xml复制<profiles>
<profile>
<id>dev</id>
<properties>
<db.url>jdbc:mysql://dev-db:3306/poem</db.url>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>prod</id>
<properties>
<db.url>jdbc:mysql://prod-db:3306/poem</db.url>
</properties>
</profile>
</profiles>
6.2 日志分割方案
logback.xml配置示例:
xml复制<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/poem.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/poem.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>50MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
6.3 内存泄漏排查
添加JVM参数:
code复制-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/tmp/poem_heap.hprof
分析步骤:
- 使用jstat观察GC情况
- 用MAT分析堆转储文件
- 重点关注JSP编译产生的类对象
7. 安全防护措施
7.1 SQL注入防护
MyBatis的防御方案:
java复制// 使用#{}而非${}
@Select("SELECT * FROM t_user WHERE username = #{name}")
User findByUsername(@Param("name") String name);
// 模糊查询安全写法
@Select("SELECT * FROM t_poem WHERE title LIKE CONCAT('%',#{title},'%')")
List<Poem> searchByTitle(String title);
7.2 XSS防御
三层防御体系:
- 前端过滤:使用DOMPurify库
- 后端处理:
java复制public String cleanXSS(String value) { return HtmlUtils.htmlEscape(value); } - 存储层:MySQL开启严格的SQL模式
7.3 CSRF防护
Spring Security配置:
java复制@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.headers().contentSecurityPolicy("script-src 'self'");
}
8. 扩展功能实现
8.1 微信小程序对接
核心接口示例:
java复制@RestController
@RequestMapping("/api/wechat")
public class WechatController {
@GetMapping("/login")
public Result wechatLogin(@RequestParam String code) {
String url = "https://api.weixin.qq.com/sns/jscode2session?"
+ "appid=" + appId
+ "&secret=" + secret
+ "&js_code=" + code
+ "&grant_type=authorization_code";
// 调用微信接口获取openid
String response = restTemplate.getForObject(url, String.class);
return Result.success(parseOpenid(response));
}
}
8.2 诗文OCR识别
集成百度AI实现:
java复制public class OCRService {
public String recognizePoem(MultipartFile image) {
String url = "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic";
String imgStr = Base64Util.encode(image.getBytes());
String param = "image=" + URLEncoder.encode(imgStr);
String accessToken = getAccessToken();
String result = HttpUtil.post(url + "?access_token=" + accessToken, param);
return parseOCRResult(result);
}
}
8.3 智能推荐算法
基于用户行为的协同过滤:
java复制public List<Poem> recommendPoems(Integer userId) {
// 1. 获取用户收藏记录
Set<Integer> collectedPoems = getCollections(userId);
// 2. 查找相似用户
List<Integer> similarUsers = findSimilarUsers(userId);
// 3. 合并推荐结果
return similarUsers.stream()
.flatMap(u -> getCollections(u).stream())
.filter(pid -> !collectedPoems.contains(pid))
.distinct()
.limit(10)
.map(this::getPoemById)
.collect(Collectors.toList());
}
9. 监控与运维
9.1 健康检查端点
Spring Boot Actuator配置:
properties复制management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=always
management.metrics.tags.application=poem-platform
9.2 慢SQL监控
Druid配置:
properties复制# 开启监控统计
spring.datasource.druid.filter.stat.enabled=true
# 慢SQL阈值(ms)
spring.datasource.druid.filter.stat.slow-sql-millis=1000
# 合并相同SQL
spring.datasource.druid.filter.stat.merge-sql=true
9.3 性能指标采集
Micrometer + Prometheus配置:
java复制@Bean
public MeterRegistryCustomizer<PrometheusMeterRegistry> metricsCommonTags() {
return registry -> registry.config().commonTags(
"application", "poem-platform",
"region", System.getProperty("user.timezone")
);
}
10. 项目演进路线
10.1 技术债清理计划
- JSP逐步替换为Thymeleaf
- 引入Spring Cloud组件实现微服务化
- 前端架构升级为Vue+Webpack
10.2 文化内容扩展
- 增加书法碑帖模块
- 开发诗词创作辅助工具
- 构建古典文学知识图谱
10.3 商业化探索
- 会员增值服务(专业赏析、名师讲解)
- 文化周边电商集成
- 线下活动报名系统
实施建议:文化类平台切忌盲目追求技术新颖,核心是要保证内容的专业性和社区氛围。我们采用灰度发布策略,所有功能更新先在"诗人专区"小范围测试,确认无文化表达问题后再全量发布。
