CMS内容管理系统的设计与实现:架构设计

发布于:2025-06-09 ⋅ 阅读:(18) ⋅ 点赞:(0)

一、整体架构方案

(一)架构方案选择(根据项目规模)

1. 中小型项目推荐方案(团队<10人)

管理前端 Vue3+Ruoyi-UI
Spring Boot单体应用
门户前端 Nuxt3+SSR
统一数据库
  • 技术要点
    • 使用 模块化单体架构(非微服务)
    • 通过 package划分 隔离管理/门户API
    • 利用 Profile 实现环境隔离
    • 无需Spring Cloud,保持简单

2. 大型项目方案(团队>20人)

管理前端
API Gateway
门户前端
Admin服务集群
Portal服务集群
管理数据库
门户数据库
  • 技术要点
    • 采用 Spring Cloud Alibaba
    • 通过 Nacos 实现服务发现
    • 使用 Sentinel 做流量控制
    • 需要独立 DBA团队 支持

3.部署方案对比

方案 优点 缺点 适用阶段
单体部署 运维简单,成本低 扩展性受限 初期(<5万UV)
模块分离部署 部分服务可独立伸缩 需要基础监控能力 中期(5-50万UV)
全微服务 弹性扩展,故障隔离 运维复杂,成本高 后期(>50万UV)

(二)演进路线实施建议

2024-01-01 2024-02-01 2024-03-01 2024-04-01 2024-05-01 2024-06-01 基础内容管理 评论模块开发 数据统计模块 服务拆分准备 独立部署门户服务 管理端微服务化 初期阶段 中期阶段 后期阶段 CMS架构演进路线
# 初期:单体模块化
src/
└── main
    └── java
        └── com
            └── company
                └── cms
                    ├── content
                    ├── comment
                    └── statistics

# 中期:子模块拆分
cms-system/
├── cms-content
├── cms-comment
└── cms-statistics

# 后期:微服务化
cms-admin-service/
cms-portal-service/
cms-comment-service/
  1. 初期采用模块化单体

    • 使用 Maven多模块 而非微服务
    • 通过 @Profile(“admin”) 隔离配置
    • 使用 Flyway 管理多环境数据库
  2. 渐进式演进路径

    单体
    模块独立部署
    核心微服务化
    全微服务架构
  3. 监控准备

    • 即使单体架构也要配置 Prometheus+Granfana
    • 日志系统使用 ELK Stack
    • 关键业务指标埋点

可根据实际用户量增长逐步升级架构,避免早期过度设计。

二、模块化分层架构设计

(一)总体划分架构

1.后端目录划分

采用 「业务垂直切分 + 客户端横向隔离 + 技术纵向分层」 的三维结构,具体实现如下:

src/main/java/com/company/cms
├── content                  # 内容业务模块
│   ├── admin               # 管理端实现
│   │   ├── controller
│   │   ├── service
│   │   └── mapper
│   ├── portal              # 门户端实现
│   │   ├── controller
│   │   ├── service
│   │   └── mapper
│   └── domain              # 公共领域对象
│       ├── entity
│       ├── dto
│       └── vo
├── comment                 # 评论业务模块
│   ├── admin
│   ├── portal
│   └── domain
├── statistics              # 统计业务模块
│   ├── admin
│   ├── portal
│   └── domain
└── common                  # CMS公共模块
    ├── config             # 专有配置
    ├── interceptor        # 拦截器
    └── utils              # 工具类

2. 业务垂直切分

CMS系统
内容模块
评论模块
统计模块
管理端
门户端
  • 隔离性:各业务模块可独立开发部署

  • 可维护性:修改影响范围明确

  • 复用性:公共domain对象跨客户端复用

3. 客户端横向隔离

// 内容模块下的权限差异示例
// 管理端Controller
@PreAuthorize("hasRole('CONTENT_ADMIN')")
@PostMapping("/admin/content")
public AjaxResult createContent(...) {
    // 需要审核流程
}

// 门户端Controller 
@RateLimit(100) // 限流注解
@GetMapping("/portal/content")
public ContentVO getContent(...) {
    // 缓存优化实现
}

4. 技术纵向分层

# 典型业务模块内部结构
content/
├── admin
│   ├── controller       # API入口
│   ├── service          # 业务逻辑
│   └── mapper           # 数据持久
├── portal
│   ├── controller
│   ├── service
│   └── mapper
└── domain               # 核心领域模型
    ├── entity          # JPA实体
    ├── dto             # 传输对象
    └── vo              # 视图对象

(二)前后端代码统筹

1.代码仓库管理策略

若是属于少量人开发项目,则推荐单一代码仓库 + 多模块结构的方案进行开发。

my-cms-project/
├── backend/          # Spring Boot后端
│   ├── src/
│   └── pom.xml
├── admin-frontend/   # 管理端Vue3
│   ├── src/
│   └── package.json
└── portal-frontend/  # 门户端Nuxt3
    ├── pages/
    └── package.json

若是多人开发项目,应该分为3个代码仓库,由不同的技术人员开发提交对应的代码。

2.配置示例(.gitignore):

# 通用忽略
*.log
*.iml
.idea/

# 后端忽略
backend/target/

# 前端忽略
admin-frontend/node_modules/
admin-frontend/dist/
portal-frontend/node_modules/
portal-frontend/.nuxt/

三、后端实施建议

(一)领域对象

1.领域对象复用

// 公共实体定义
@Entity
@Table(name = "cms_content")
public class Content {
    @Id
    @GeneratedValue
    private Long id;
    
    // 公共字段
    private String title;
    private String content;
    
    // 管理端特有字段(审计用)
    @Column(name = "audit_status")
    @AdminOnly  // 自定义注解
    private AuditStatus auditStatus;
    
    // 门户端特有字段(展示用)
    @Column(name = "view_count")
    @PortalOnly
    private Integer viewCount;
}

(二)API控制器

1.API路径设计规范

管理端和门户端的api接口需要隔离,用/api/admin和/api/portal区分好,还是用/admin/api和/portal/api区分好?

推荐:/api/admin/api/portal 双前缀模式

管理端: /api/admin/v1/content
门户端: /api/portal/v1/content

优势分析:

  • 路由清晰:/api 明确标识API入口,/admin|portal区分客户端
  • 网关友好:Nginx可统一配置/api路由规则
  • 安全隔离:方便在网关层设置不同安全策略
  • 版本控制:v1支持平滑升级到v2

2.控制器隔离

// 管理端文章控制器
@RestController
@RequestMapping("/api/admin/v1/articles")
public class AdminArticleController {

    @PreAuthorize("hasRole('ADMIN')")
    @PostMapping
    public AjaxResult createArticle(@Valid @RequestBody ArticleCreateDTO dto) {
        // 管理端专用创建逻辑
    }
}

// 门户端文章控制器 
@RestController
@RequestMapping("/api/portal/v1/articles")
public class PortalArticleController {

    @GetMapping("/{id}")
    public ArticleVO getArticle(@PathVariable Long id) {
        // 门户端专用查询逻辑
    }
}

3.API文档管理

// 使用Swagger分组
@Bean
public Docket adminApi() {
    return new Docket(DocumentationType.OAS_30)
        .groupName("管理端API")
        .select()
        .apis(RequestHandlerSelectors.basePackage("com.cms.controller.admin"))
}

(三)服务层

1.服务层复用策略

// 通用服务接口
public interface ArticleBaseService {
    Article getById(Long id);
}

// 管理端服务实现  
@Service
public class AdminArticleService implements ArticleBaseService {
    
    @Override
    public Article getById(Long id) {
        // 管理端专用逻辑(包含审计字段)
    }
    
    public void auditArticle(Long id) {
        // 管理端特有方法
    }
}

// 门户端服务实现
@Service 
public class PortalArticleService implements ArticleBaseService {
    
    @Override
    public Article getById(Long id) {
        // 门户端专用逻辑(缓存优化)
    }
}

2. 服务层差异处理

// 管理端服务实现
@Service
public class AdminContentService {
    
    @AdminAuditRequired // 自定义审核注解
    public void publishContent(Long id) {
        // 包含审核流程
    }
}

// 门户端服务实现
@Service
public class PortalContentService {
    
    @Cacheable("content") // 缓存优化
    public ContentVO getContent(Long id) {
        // 访问统计逻辑
    }
}

(四)安全配置

1.安全配置分离

// 管理端安全配置类
@Configuration
@EnableWebSecurity
@Order(1) // 高优先级
public class AdminSecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/admin/**")
            .authorizeRequests()
            .anyRequest().hasRole("ADMIN")
            .and()
            .formLogin().disable();
    }
}

// 门户端安全配置类  
@Configuration
@Order(2) // 低优先级
public class PortalSecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/portal/**")
            .authorizeRequests()
            .antMatchers(HttpMethod.GET).permitAll()
            .anyRequest().authenticated()
            .and()
            .oauth2ResourceServer().jwt();
    }
}
# application-admin.yml(管理端配置)
security:
  oauth2:
    resource:
      id: admin-api
      user-info-uri: http://auth-server/oauth2/user

# application-portal.yml(门户端配置)  
security:
  oauth2:
    resource:
      id: portal-api
      user-info-uri: http://auth-server/oauth2/openid
# 权限配置示例(admin/portal分离)
security:
  admin:
    roles: [CONTENT_ADMIN, COMMENT_ADMIN]
    access: DENY_AFTER_17:00-08:00 # 管理端时间限制
    
  portal:
    rate-limit: 1000/分钟
    open-apis: [/api/portal/content/*]

(五)异常处理

1.异常处理方案

@RestControllerAdvice(
    basePackages = {
        "com.company.cms.content.admin",
        "com.company.cms.content.portal"
    })
public class ContentExceptionHandler {
    
    @ExceptionHandler(ContentNotFoundException.class)
    public ResponseEntity<ErrorResult> handleNotFound(ContentNotFoundException ex) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
            .body(new ErrorResult("CONTENT_NOT_FOUND", ex.getMessage()));
    }
}

2. 错误码规范示例

模块 错误范围 示例
内容模块 1000-1999 1001=内容不存在
评论模块 2000-2999 2003=评论包含敏感词
统计模块 3000-3999 3005=数据导出失败

(六)配置管理

1.配置管理策略

多环境配置示例

config/
├── application.yml           # 公共配置
├── application-dev.yml       # 开发环境
├── application-prod.yml      # 生产环境
├── content-admin.yml         # 内容管理端特有配置
└── content-portal.yml        # 内容门户端特有配置
# application.yml(公共配置)
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cms
    username: root
    password: 123456

---
# application-admin.yml(管理端特有配置)
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics
  endpoint:
    health:
      show-details: always

---
# application-portal.yml(门户端特有配置)  
spring:
  redis:
    host: portal-redis
    port: 6379

动态配置示例

@Configuration
@ConfigurationProperties(prefix = "cms.content")
public class ContentConfig {
    // 管理端特有配置
    private AdminConfig admin;
    // 门户端特有配置
    private PortalConfig portal;
    
    @Data
    public static class AdminConfig {
        private int auditTimeout = 24; // 审核超时时间(小时)
    }
    
    @Data
    public static class PortalConfig {
        private int cacheTTL = 3600; // 缓存时间(秒)
    }
}

3. 数据库隔离策略
-- 管理表(admin_开头)
CREATE TABLE admin_operation_log (
    id BIGINT PRIMARY KEY,
    user_id BIGINT NOT NULL,
    action VARCHAR(50) NOT NULL
);

-- 门户表(portal_开头)
CREATE TABLE portal_comment (
    id BIGINT PRIMARY KEY,
    article_id BIGINT NOT NULL,
    content TEXT
);

四、前端技术确认

端类型 技术栈 适用场景 示例代码
管理后台 Vue3 + Ruoyi-UI 需要快速开发CRUD界面 使用若依的src/views/system结构
门户网站 Nuxt3 + SSR 需要SEO优化和首屏性能 pages/article/[id].vue动态路由

(一)前端API调用对比

管理端调用示例(Vue3):

// admin-frontend/src/api/content.js
import request from '@/utils/request'

export function getContentList(params) {
  return request({
    url: '/api/admin/v1/content',
    method: 'get',
    params
  })
}

门户端调用示例(Nuxt3):

// portal-frontend/composables/useContent.js
export default () => {
  const getContent = async (id) => {
    return $fetch(`/api/portal/v1/content/${id}`, {
      method: 'GET'
    })
  }
  
  return { getContent }
}

(二)开发环境代理配置

管理端Vite配置(admin-frontend/vite.config.js):

export default defineConfig({
  server: {
    proxy: {
      '/api/admin': {
        target: 'http://localhost:8080', // Spring Boot地址
        changeOrigin: true,
        rewrite: path => path.replace(/^\/api\/admin/, '')
      }
    }
  }
})

门户端Nuxt配置(portal-frontend/nuxt.config.js):

export default defineNuxtConfig({
  devServer: {
    proxy: {
      '/api/portal': 'http://localhost:8080'
    }
  }
})

前端环境变量:

# admin-frontend/.env.development
VITE_API_BASE=/api/admin

# portal-frontend/.env.production
NUXT_PUBLIC_API_BASE=/api/portal

五、其它

1.Nginx统一配置:

server {
    listen 80;
    
    # 管理前端
    location /admin {
        alias /var/www/admin-frontend/dist;
        try_files $uri $uri/ /admin/index.html;
    }
    
    # 门户前端
    location / {
        alias /var/www/portal-frontend/dist;
        try_files $uri $uri/ /index.html;
    }
    
    # API路由
    location /api {
        proxy_pass http://backend-server:8080;
        proxy_set_header Host $host;
        
        # 管理API超时设置
        location ~ ^/api/admin {
            proxy_read_timeout 300s;
        }
        
        # 门户API缓存配置
        location ~ ^/api/portal.*\.(js|css|png)$ {
            expires 30d;
        }
    }
}

2.日常开发流程:

创建功能分支
后端开发
管理前端对接
门户前端对接
本地联调测试
提交到同一分支
创建合并请求
代码评审后合并

在这里插入图片描述