1. 模板继承与布局系统
1.1 模板继承核心系统
go
package main
import (
"fmt"
"html/template"
"strings"
"sync"
"time"
"path/filepath"
"io/ioutil"
"errors"
)
// TemplateInheritance 模板继承系统
type TemplateInheritance struct {
// 布局模板存储
layouts map[string]*template.Template
// 模板构建器
builder *TemplateBuilder
// 缓存管理器
cache *TemplateCache
// 性能监控器
monitor *PerformanceMonitor
mutex sync.RWMutex
}
// LayoutConfig 布局配置
type LayoutConfig struct {
Name string // 布局名称
Path string // 布局文件路径
Blocks []string // 定义的块名称
Extends string // 继承的父布局
Variables map[string]string // 布局变量
Metadata map[string]interface{} // 元数据
}
// TemplateBuilder 模板构建器
type TemplateBuilder struct {
baseDir string
funcMap template.FuncMap
layouts map[string]*LayoutConfig
partials map[string]string
cache bool
mutex sync.RWMutex
}
// NewTemplateInheritance 创建模板继承系统
func NewTemplateInheritance(baseDir string) *TemplateInheritance {
return &TemplateInheritance{
layouts: make(map[string]*template.Template),
builder: NewTemplateBuilder(baseDir),
cache: NewTemplateCache(),
monitor: NewPerformanceMonitor(),
}
}
// NewTemplateBuilder 创建模板构建器
func NewTemplateBuilder(baseDir string) *TemplateBuilder {
return &TemplateBuilder{
baseDir: baseDir,
funcMap: make(template.FuncMap),
layouts: make(map[string]*LayoutConfig),
partials: make(map[string]string),
cache: true,
}
}
// RegisterLayout 注册布局模板
func (ti *TemplateInheritance) RegisterLayout(config *LayoutConfig) error {
ti.mutex.Lock()
defer ti.mutex.Unlock()
// 验证布局配置
if err := ti.validateLayout(config); err != nil {
return fmt.Errorf("布局验证失败: %w", err)
}
// 构建模板
tmpl, err := ti.builder.BuildLayout(config)
if err != nil {
return fmt.Errorf("构建布局失败: %w", err)
}
ti.layouts[config.Name] = tmpl
return nil
}
// validateLayout 验证布局配置
func (ti *TemplateInheritance) validateLayout(config *LayoutConfig) error {
if config.Name == "" {
return errors.New("布局名称不能为空")
}
if config.Path == "" {
return errors.New("布局路径不能为空")
}
// 检查文件是否存在
fullPath := filepath.Join(ti.builder.baseDir, config.Path)
if _, err := ioutil.ReadFile(fullPath); err != nil {
return fmt.Errorf("布局文件不存在: %s", fullPath)
}
// 检查继承关系
if config.Extends != "" {
if _, exists := ti.layouts[config.Extends]; !exists {
return fmt.Errorf("父布局不存在: %s", config.Extends)
}
}
return nil
}
// SetupBaseLayouts 设置基础布局
func (ti *TemplateInheritance) SetupBaseLayouts() error {
// 主布局
mainLayout := &LayoutConfig{
Name: "main",
Path: "layouts/main.html",
Blocks: []string{"title", "head", "content", "scripts"},
Variables: map[string]string{
"charset": "UTF-8",
"lang": "zh-CN",
},
}
// 管理后台布局
adminLayout := &LayoutConfig{
Name: "admin",
Path: "layouts/admin.html",
Extends: "main",
Blocks: []string{"sidebar", "content", "footer"},
Variables: map[string]string{
"theme": "admin-dark",
},
}
// 移动端布局
mobileLayout := &LayoutConfig{
Name: "mobile",
Path: "layouts/mobile.html",
Extends: "main",
Blocks: []string{"header", "content", "navigation"},
Variables: map[string]string{
"viewport": "width=device-width, initial-scale=1",
},
}
// 注册布局
layouts := []*LayoutConfig{mainLayout, adminLayout, mobileLayout}
for _, layout := range layouts {
if err := ti.RegisterLayout(layout); err != nil {
return err
}
}
return nil
}
// BuildLayout 构建布局模板
func (tb *TemplateBuilder) BuildLayout(config *LayoutConfig) (*template.Template, error) {
tb.mutex.Lock()
defer tb.mutex.Unlock()
// 读取布局文件
fullPath := filepath.Join(tb.baseDir, config.Path)
content, err := ioutil.ReadFile(fullPath)
if err != nil {
return nil, fmt.Errorf("读取布局文件失败: %w", err)
}
// 创建模板
tmpl := template.New(config.Name).Funcs(tb.funcMap)
// 处理继承
if config.Extends != "" {
parentConfig, exists := tb.layouts[config.Extends]
if !exists {
return nil, fmt.Errorf("父布局不存在: %s", config.Extends)
}
// 合并父布局内容
content = tb.mergeLayouts(parentConfig, config, content)
}
// 解析模板
tmpl, err = tmpl.Parse(string(content))
if err != nil {
return nil, fmt.Errorf("解析模板失败: %w", err)
}
// 缓存布局配置
tb.layouts[config.Name] = config
return tmpl, nil
}
// mergeLayouts 合并布局
func (tb *TemplateBuilder) mergeLayouts(parent, child *LayoutConfig, childContent []byte) []byte {
// 简化的布局合并逻辑
// 实际应用中需要更复杂的模板解析和合并
parentPath := filepath.Join(tb.baseDir, parent.Path)
parentContent, err := ioutil.ReadFile(parentPath)
if err != nil {
return childContent
}
// 合并变量
mergedVars := make(map[string]string)
for k, v := range parent.Variables {
mergedVars[k] = v
}
for k, v := range child.Variables {
mergedVars[k] = v
}
// 替换变量占位符
result := string(parentContent)
for key, value := range mergedVars {
placeholder := fmt.Sprintf("{{.%s}}", key)
result = strings.ReplaceAll(result, placeholder, value)
}
// 插入子模板内容
contentPlaceholder := "{{block \"content\" .}}{{end}}"
result = strings.ReplaceAll(result, contentPlaceholder, string(childContent))
return []byte(result)
}
// AddFunction 添加模板函数
func (tb *TemplateBuilder) AddFunction(name string, fn interface{}) {
tb.mutex.Lock()
defer tb.mutex.Unlock()
tb.funcMap[name] = fn
}
// SetCacheEnabled 设置缓存启用状态
func (tb *TemplateBuilder) SetCacheEnabled(enabled bool) {
tb.mutex.Lock()
defer tb.mutex.Unlock()
tb.cache = enabled
}
1.2 部分模板管理系统
go
// PartialManager 部分模板管理器
type PartialManager struct {
partials map[string]*PartialTemplate
baseDir string
funcMap template.FuncMap
mutex sync.RWMutex
}
// PartialTemplate 部分模板
type PartialTemplate struct {
Name string
Path string
Content string
Dependencies []string
CacheKey string
LastModified time.Time
Metadata map[string]interface{}
}
// NewPartialManager 创建部分模板管理器
func NewPartialManager(baseDir string) *PartialManager {
return &PartialManager{
partials: make(map[string]*PartialTemplate),
baseDir: baseDir,
funcMap: make(template.FuncMap),
}
}
// RegisterPartial 注册部分模板
func (pm *PartialManager) RegisterPartial(name, path string) error {
pm.mutex.Lock()
defer pm.mutex.Unlock()
fullPath := filepath.Join(pm.baseDir, path)
content, err := ioutil.ReadFile(fullPath)
if err != nil {
return fmt.Errorf("读取部分模板失败: %w", err)
}
// 获取文件信息
fileInfo, err := ioutil.Stat(fullPath)
if err != nil {
return fmt.Errorf("获取文件信息失败: %w", err)
}
partial := &PartialTemplate{
Name: name,
Path: path,
Content: string(content),
Dependencies: pm.extractDependencies(string(content)),
CacheKey: pm.generateCacheKey(name, path),
LastModified: fileInfo.ModTime(),
Metadata: make(map[string]interface{}),
}
pm.partials[name] = partial
return nil
}
// extractDependencies 提取依赖关系
func (pm *PartialManager) extractDependencies(content string) []string {
var dependencies []string
// 查找模板引用 {{template "name" .}}
templatePattern := `{{template\s+"([^"]+)"`
re := regexp.MustCompile(templatePattern)
matches := re.FindAllStringSubmatch(content, -1)
for _, match := range matches {
if len(match) > 1 {
dependencies = append(dependencies, match[1])
}
}
return dependencies
}
// generateCacheKey 生成缓存键
func (pm *PartialManager) generateCacheKey(name, path string) string {
return fmt.Sprintf("partial:%s:%s", name, path)
}
// SetupCommonPartials 设置常用部分模板
func (pm *PartialManager) SetupCommonPartials() error {
commonPartials := map[string]string{
"pagination": "partials/pagination.html",
"breadcrumb": "partials/breadcrumb.html",
"article_card": "partials/article_card.html",
"comment": "partials/comment.html",
"sidebar": "partials/sidebar.html",
"footer": "partials/footer.html",
"header": "partials/header.html",
"navigation": "partials/navigation.html",
}
for name, path := range commonPartials {
if err := pm.RegisterPartial(name, path); err != nil {
return fmt.Errorf("注册部分模板 %s 失败: %w", name, err)
}
}
return nil
}
// GetPartial 获取部分模板
func (pm *PartialManager) GetPartial(name string) (*PartialTemplate, error) {
pm.mutex.RLock()
defer pm.mutex.RUnlock()
partial, exists := pm.partials[name]
if !exists {
return nil, fmt.Errorf("部分模板不存在: %s", name)
}
return partial, nil
}
// ReloadPartial 重新加载部分模板
func (pm *PartialManager) ReloadPartial(name string) error {
pm.mutex.Lock()
defer pm.mutex.Unlock()
partial, exists := pm.partials[name]
if !exists {
return fmt.Errorf("部分模板不存在: %s", name)
}
fullPath := filepath.Join(pm.baseDir, partial.Path)
content, err := ioutil.ReadFile(fullPath)
if err != nil {
return fmt.Errorf("重新读取部分模板失败: %w", err)
}
// 更新内容
partial.Content = string(content)
partial.Dependencies = pm.extractDependencies(string(content))
partial.LastModified = time.Now()
return nil
}
// TemplateComposer 模板组合器
type TemplateComposer struct {
inheritance *TemplateInheritance
partials *PartialManager
funcMap template.FuncMap
mutex sync.RWMutex
}
// NewTemplateComposer 创建模板组合器
func NewTemplateComposer(inheritance *TemplateInheritance, partials *PartialManager) *TemplateComposer {
tc := &TemplateComposer{
inheritance: inheritance,
partials: partials,
funcMap: make(template.FuncMap),
}
// 设置默认函数
tc.setupDefaultFunctions()
return tc
}
// setupDefaultFunctions 设置默认函数
func (tc *TemplateComposer) setupDefaultFunctions() {
tc.funcMap["partial"] = tc.renderPartial
tc.funcMap["block"] = tc.renderBlock
tc.funcMap["extend"] = tc.extendLayout
tc.funcMap["include"] = tc.includeTemplate
tc.funcMap["yield"] = tc.yieldContent
}
// renderPartial 渲染部分模板
func (tc *TemplateComposer) renderPartial(name string, data interface{}) (template.HTML, error) {
partial, err := tc.partials.GetPartial(name)
if err != nil {
return "", err
}
tmpl, err := template.New(name).Funcs(tc.funcMap).Parse(partial.Content)
if err != nil {
return "", fmt.Errorf("解析部分模板失败: %w", err)
}
var buf strings.Builder
if err := tmpl.Execute(&buf, data); err != nil {
return "", fmt.Errorf("执行部分模板失败: %w", err)
}
return template.HTML(buf.String()), nil
}
// renderBlock 渲染块
func (tc *TemplateComposer) renderBlock(name string, data interface{}) (template.HTML, error) {
// 块渲染逻辑
return template.HTML(fmt.Sprintf("<!-- Block: %s -->", name)), nil
}
// extendLayout 扩展布局
func (tc *TemplateComposer) extendLayout(layoutName string) (template.HTML, error) {
// 布局扩展逻辑
return template.HTML(fmt.Sprintf("<!-- Extend: %s -->", layoutName)), nil
}
// includeTemplate 包含模板
func (tc *TemplateComposer) includeTemplate(templateName string, data interface{}) (template.HTML, error) {
// 模板包含逻辑
return template.HTML(fmt.Sprintf("<!-- Include: %s -->", templateName)), nil
}
// yieldContent 输出内容
func (tc *TemplateComposer) yieldContent(blockName string) (template.HTML, error) {
// 内容输出逻辑
return template.HTML(fmt.Sprintf("<!-- Yield: %s -->", blockName)), nil
}
2. 模板组合与部分模板
2.1 高级逻辑控制系统
go
// ConditionalLogic 条件逻辑控制器
type ConditionalLogic struct {
conditions map[string]ConditionFunc
operators map[string]OperatorFunc
mutex sync.RWMutex
}
// ConditionFunc 条件函数类型
type ConditionFunc func(interface{}) bool
// OperatorFunc 操作符函数类型
type OperatorFunc func(interface{}, interface{}) bool
// NewConditionalLogic 创建条件逻辑控制器
func NewConditionalLogic() *ConditionalLogic {
cl := &ConditionalLogic{
conditions: make(map[string]ConditionFunc),
operators: make(map[string]OperatorFunc),
}
// 设置默认条件和操作符
cl.setupDefaultConditions()
cl.setupDefaultOperators()
return cl
}
// setupDefaultConditions 设置默认条件
func (cl *ConditionalLogic) setupDefaultConditions() {
cl.conditions["isEmpty"] = func(v interface{}) bool {
if v == nil {
return true
}
switch val := v.(type) {
case string:
return val == ""
case []interface{}:
return len(val) == 0
case map[string]interface{}:
return len(val) == 0
default:
return false
}
}
cl.conditions["isNumber"] = func(v interface{}) bool {
switch v.(type) {
case int, int8, int16, int32, int64:
return true
case uint, uint8, uint16, uint32, uint64:
return true
case float32, float64:
return true
default:
return false
}
}
cl.conditions["isString"] = func(v interface{}) bool {
_, ok := v.(string)
return ok
}
cl.conditions["isBool"] = func(v interface{}) bool {
_, ok := v.(bool)
return ok
}
cl.conditions["isEven"] = func(v interface{}) bool {
if num, ok := v.(int); ok {
return num%2 == 0
}
return false
}
cl.conditions["isOdd"] = func(v interface{}) bool {
if num, ok := v.(int); ok {
return num%2 != 0
}
return false
}
}
// setupDefaultOperators 设置默认操作符
func (cl *ConditionalLogic) setupDefaultOperators() {
cl.operators["eq"] = func(a, b interface{}) bool {
return fmt.Sprintf("%v", a) == fmt.Sprintf("%v", b)
}
cl.operators["ne"] = func(a, b interface{}) bool {
return fmt.Sprintf("%v", a) != fmt.Sprintf("%v", b)
}
cl.operators["gt"] = func(a, b interface{}) bool {
return compareNumbers(a, b) > 0
}
cl.operators["gte"] = func(a, b interface{}) bool {
return compareNumbers(a, b) >= 0
}
cl.operators["lt"] = func(a, b interface{}) bool {
return compareNumbers(a, b) < 0
}
cl.operators["lte"] = func(a, b interface{}) bool {
return compareNumbers(a, b) <= 0
}
cl.operators["contains"] = func(a, b interface{}) bool {
aStr := fmt.Sprintf("%v", a)
bStr := fmt.Sprintf("%v", b)
return strings.Contains(aStr, bStr)
}
cl.operators["startsWith"] = func(a, b interface{}) bool {
aStr := fmt.Sprintf("%v", a)
bStr := fmt.Sprintf("%v", b)
return strings.HasPrefix(aStr, bStr)
}
cl.operators["endsWith"] = func(a, b interface{}) bool {
aStr := fmt.Sprintf("%v", a)
bStr := fmt.Sprintf("%v", b)
return strings.HasSuffix(aStr, bStr)
}
}
// compareNumbers 比较数字
func compareNumbers(a, b interface{}) int {
aFloat := toFloat64(a)
bFloat := toFloat64(b)
if aFloat > bFloat {
return 1
} else if aFloat < bFloat {
return -1
}
return 0
}
// toFloat64 转换为float64
func toFloat64(v interface{}) float64 {
switch val := v.(type) {
case int:
return float64(val)
case int64:
return float64(val)
case float32:
return float64(val)
case float64:
return val
case string:
if f, err := strconv.ParseFloat(val, 64); err == nil {
return f
}
}
return 0
}
// RegisterCondition 注册条件
func (cl *ConditionalLogic) RegisterCondition(name string, fn ConditionFunc) {
cl.mutex.Lock()
defer cl.mutex.Unlock()
cl.conditions[name] = fn
}
// RegisterOperator 注册操作符
func (cl *ConditionalLogic) RegisterOperator(name string, fn OperatorFunc) {
cl.mutex.Lock()
defer cl.mutex.Unlock()
cl.operators[name] = fn
}
// EvaluateCondition 评估条件
func (cl *ConditionalLogic) EvaluateCondition(name string, value interface{}) bool {
cl.mutex.RLock()
defer cl.mutex.RUnlock()
if fn, exists := cl.conditions[name]; exists {
return fn(value)
}
return false
}
// EvaluateOperator 评估操作符
func (cl *ConditionalLogic) EvaluateOperator(name string, a, b interface{}) bool {
cl.mutex.RLock()
defer cl.mutex.RUnlock()
if fn, exists := cl.operators[name]; exists {
return fn(a, b)
}
return false
}
// LoopControl 循环控制器
type LoopControl struct {
iterators map[string]IteratorFunc
filters map[string]FilterFunc
sorters map[string]SorterFunc
mutex sync.RWMutex
}
// IteratorFunc 迭代器函数类型
type IteratorFunc func(interface{}) []interface{}
// FilterFunc 过滤器函数类型
type FilterFunc func(interface{}) bool
// SorterFunc 排序器函数类型
type SorterFunc func([]interface{}) []interface{}
// NewLoopControl 创建循环控制器
func NewLoopControl() *LoopControl {
lc := &LoopControl{
iterators: make(map[string]IteratorFunc),
filters: make(map[string]FilterFunc),
sorters: make(map[string]SorterFunc),
}
// 设置默认迭代器、过滤器和排序器
lc.setupDefaultIterators()
lc.setupDefaultFilters()
lc.setupDefaultSorters()
return lc
}
// setupDefaultIterators 设置默认迭代器
func (lc *LoopControl) setupDefaultIterators() {
lc.iterators["range"] = func(v interface{}) []interface{} {
switch val := v.(type) {
case []interface{}:
return val
case map[string]interface{}:
result := make([]interface{}, 0, len(val))
for _, value := range val {
result = append(result, value)
}
return result
case int:
result := make([]interface{}, val)
for i := 0; i < val; i++ {
result[i] = i
}
return result
default:
return []interface{}{v}
}
}
lc.iterators["chars"] = func(v interface{}) []interface{} {
if str, ok := v.(string); ok {
result := make([]interface{}, len(str))
for i, char := range str {
result[i] = string(char)
}
return result
}
return []interface{}{}
}
lc.iterators["chunk"] = func(v interface{}) []interface{} {
// 分块迭代器,将数组分成固定大小的块
if arr, ok := v.([]interface{}); ok {
chunkSize := 3 // 默认块大小
var result []interface{}
for i := 0; i < len(arr); i += chunkSize {
end := i + chunkSize
if end > len(arr) {
end = len(arr)
}
result = append(result, arr[i:end])
}
return result
}
return []interface{}{}
}
}
// setupDefaultFilters 设置默认过滤器
func (lc *LoopControl) setupDefaultFilters() {
lc.filters["notEmpty"] = func(v interface{}) bool {
if v == nil {
return false
}
switch val := v.(type) {
case string:
return val != ""
case []interface{}:
return len(val) > 0
case map[string]interface{}:
return len(val) > 0
default:
return true
}
}
lc.filters["isNumber"] = func(v interface{}) bool {
switch v.(type) {
case int, int8, int16, int32, int64:
return true
case uint, uint8, uint16, uint32, uint64:
return true
case float32, float64:
return true
default:
return false
}
}
lc.filters["isPositive"] = func(v interface{}) bool {
return toFloat64(v) > 0
}
lc.filters["isNegative"] = func(v interface{}) bool {
return toFloat64(v) < 0
}
}
// setupDefaultSorters 设置默认排序器
func (lc *LoopControl) setupDefaultSorters() {
lc.sorters["asc"] = func(items []interface{}) []interface{} {
result := make([]interface{}, len(items))
copy(result, items)
sort.Slice(result, func(i, j int) bool {
return fmt.Sprintf("%v", result[i]) < fmt.Sprintf("%v", result[j])
})
return result
}
lc.sorters["desc"] = func(items []interface{}) []interface{} {
result := make([]interface{}, len(items))
copy(result, items)
sort.Slice(result, func(i, j int) bool {
return fmt.Sprintf("%v", result[i]) > fmt.Sprintf("%v", result[j])
})
return result
}
lc.sorters["shuffle"] = func(items []interface{}) []interface{} {
result := make([]interface{}, len(items))
copy(result, items)
// 简单的洗牌算法
for i := len(result) - 1; i > 0; i-- {
j := int(time.Now().UnixNano()) % (i + 1)
result[i], result[j] = result[j], result[i]
}
return result
}
}
// RegisterIterator 注册迭代器
func (lc *LoopControl) RegisterIterator(name string, fn IteratorFunc) {
lc.mutex.Lock()
defer lc.mutex.Unlock()
lc.iterators[name] = fn
}
// RegisterFilter 注册过滤器
func (lc *LoopControl) RegisterFilter(name string, fn FilterFunc) {
lc.mutex.Lock()
defer lc.mutex.Unlock()
lc.filters[name] = fn
}
// RegisterSorter 注册排序器
func (lc *LoopControl) RegisterSorter(name string, fn SorterFunc) {
lc.mutex.Lock()
defer lc.mutex.Unlock()
lc.sorters[name] = fn
}
// Iterate 执行迭代
func (lc *LoopControl) Iterate(name string, value interface{}) []interface{} {
lc.mutex.RLock()
defer lc.mutex.RUnlock()
if fn, exists := lc.iterators[name]; exists {
return fn(value)
}
return []interface{}{}
}
// Filter 执行过滤
func (lc *LoopControl) Filter(items []interface{}, filterName string) []interface{} {
lc.mutex.RLock()
defer lc.mutex.RUnlock()
if fn, exists := lc.filters[filterName]; exists {
var result []interface{}
for _, item := range items {
if fn(item) {
result = append(result, item)
}
}
return result
}
return items
}
// Sort 执行排序
func (lc *LoopControl) Sort(items []interface{}, sorterName string) []interface{} {
lc.mutex.RLock()
defer lc.mutex.RUnlock()
if fn, exists := lc.sorters[sorterName]; exists {
return fn(items)
}
return items
}
3. 高级逻辑控制
3.1 模板缓存与性能优化
go
// TemplateCache 模板缓存系统
type TemplateCache struct {
strategy CacheStrategy
config *CacheConfig
entries map[string]*CacheEntry
stats *CacheStats
mutex sync.RWMutex
}
// CacheStrategy 缓存策略
type CacheStrategy int
const (
CacheNone CacheStrategy = iota
CacheMemory
CacheFile
CacheRedis
CacheHybrid
)
// CacheConfig 缓存配置
type CacheConfig struct {
Strategy CacheStrategy
MaxSize int64
TTL time.Duration
CleanupInterval time.Duration
RedisAddr string
RedisDB int
FileDir string
}
// CacheEntry 缓存条目
type CacheEntry struct {
Key string
Content []byte
Size int64
CreatedAt time.Time
AccessedAt time.Time
AccessCount int64
TTL time.Duration
}
// CacheStats 缓存统计
type CacheStats struct {
Hits int64
Misses int64
Evictions int64
TotalSize int64
EntryCount int64
mutex sync.RWMutex
}
// NewTemplateCache 创建模板缓存
func NewTemplateCache() *TemplateCache {
config := &CacheConfig{
Strategy: CacheMemory,
MaxSize: 100 * 1024 * 1024, // 100MB
TTL: time.Hour,
CleanupInterval: time.Minute * 10,
}
tc := &TemplateCache{
strategy: config.Strategy,
config: config,
entries: make(map[string]*CacheEntry),
stats: &CacheStats{},
}
// 启动清理协程
go tc.startCleanup()
return tc
}
// Get 获取缓存
func (tc *TemplateCache) Get(key string) ([]byte, bool) {
tc.mutex.RLock()
defer tc.mutex.RUnlock()
entry, exists := tc.entries[key]
if !exists {
tc.stats.recordMiss()
return nil, false
}
// 检查是否过期
if tc.isExpired(entry) {
tc.stats.recordMiss()
return nil, false
}
// 更新访问信息
entry.AccessedAt = time.Now()
entry.AccessCount++
tc.stats.recordHit()
return entry.Content, true
}
// Set 设置缓存
func (tc *TemplateCache) Set(key string, content []byte, ttl time.Duration) {
tc.mutex.Lock()
defer tc.mutex.Unlock()
// 检查是否需要清理空间
if tc.needEviction(int64(len(content))) {
tc.evictLRU()
}
entry := &CacheEntry{
Key: key,
Content: content,
Size: int64(len(content)),
CreatedAt: time.Now(),
AccessedAt: time.Now(),
AccessCount: 1,
TTL: ttl,
}
// 如果键已存在,更新统计
if oldEntry, exists := tc.entries[key]; exists {
tc.stats.TotalSize -= oldEntry.Size
tc.stats.EntryCount--
}
tc.entries[key] = entry
tc.stats.TotalSize += entry.Size
tc.stats.EntryCount++
}
// isExpired 检查是否过期
func (tc *TemplateCache) isExpired(entry *CacheEntry) bool {
if entry.TTL <= 0 {
return false
}
return time.Since(entry.CreatedAt) > entry.TTL
}
// needEviction 检查是否需要清理
func (tc *TemplateCache) needEviction(newSize int64) bool {
return tc.stats.TotalSize+newSize > tc.config.MaxSize
}
// evictLRU 清理最少使用的条目
func (tc *TemplateCache) evictLRU() {
if len(tc.entries) == 0 {
return
}
var oldestKey string
var oldestTime time.Time = time.Now()
for key, entry := range tc.entries {
if entry.AccessedAt.Before(oldestTime) {
oldestTime = entry.AccessedAt
oldestKey = key
}
}
if oldestKey != "" {
entry := tc.entries[oldestKey]
delete(tc.entries, oldestKey)
tc.stats.TotalSize -= entry.Size
tc.stats.EntryCount--
tc.stats.Evictions++
}
}
// cleanup 清理过期条目
func (tc *TemplateCache) cleanup() {
tc.mutex.Lock()
defer tc.mutex.Unlock()
for key, entry := range tc.entries {
if tc.isExpired(entry) {
delete(tc.entries, key)
tc.stats.TotalSize -= entry.Size
tc.stats.EntryCount--
}
}
}
// startCleanup 启动清理协程
func (tc *TemplateCache) startCleanup() {
ticker := time.NewTicker(tc.config.CleanupInterval)
defer ticker.Stop()
for range ticker.C {
tc.cleanup()
}
}
// GetStats 获取缓存统计
func (tc *TemplateCache) GetStats() CacheStats {
tc.stats.mutex.RLock()
defer tc.stats.mutex.RUnlock()
return *tc.stats
}
// Clear 清空缓存
func (tc *TemplateCache) Clear() {
tc.mutex.Lock()
defer tc.mutex.Unlock()
tc.entries = make(map[string]*CacheEntry)
tc.stats.TotalSize = 0
tc.stats.EntryCount = 0
}
// Stop 停止缓存
func (tc *TemplateCache) Stop() {
tc.Clear()
}
// recordHit 记录命中
func (cs *CacheStats) recordHit() {
cs.mutex.Lock()
defer cs.mutex.Unlock()
cs.Hits++
}
// recordMiss 记录未命中
func (cs *CacheStats) recordMiss() {
cs.mutex.Lock()
defer cs.mutex.Unlock()
cs.Misses++
}
// PerformanceMonitor 性能监控器
type PerformanceMonitor struct {
metrics map[string]*TemplateMetrics
alerts map[string]*AlertConfig
mutex sync.RWMutex
}
// TemplateMetrics 模板性能指标
type TemplateMetrics struct {
Name string
RenderCount int64
TotalDuration time.Duration
AvgDuration time.Duration
MaxDuration time.Duration
MinDuration time.Duration
ErrorCount int64
CacheHits int64
CacheMisses int64
LastRender time.Time
}
// AlertConfig 告警配置
type AlertConfig struct {
MaxDuration time.Duration
MaxErrorRate float64
MinCacheRate float64
Callback func(*TemplateMetrics)
}
// NewPerformanceMonitor 创建性能监控器
func NewPerformanceMonitor() *PerformanceMonitor {
return &PerformanceMonitor{
metrics: make(map[string]*TemplateMetrics),
alerts: make(map[string]*AlertConfig),
}
}
// RecordRender 记录渲染性能
func (pm *PerformanceMonitor) RecordRender(templateName string, duration time.Duration, err error) {
pm.mutex.Lock()
defer pm.mutex.Unlock()
metrics, exists := pm.metrics[templateName]
if !exists {
metrics = &TemplateMetrics{
Name: templateName,
MinDuration: duration,
}
pm.metrics[templateName] = metrics
}
// 更新指标
metrics.RenderCount++
metrics.TotalDuration += duration
metrics.AvgDuration = time.Duration(int64(metrics.TotalDuration) / metrics.RenderCount)
metrics.LastRender = time.Now()
if duration > metrics.MaxDuration {
metrics.MaxDuration = duration
}
if duration < metrics.MinDuration {
metrics.MinDuration = duration
}
if err != nil {
metrics.ErrorCount++
}
// 检查告警
pm.checkAlerts(templateName, metrics)
}
// RecordCacheHit 记录缓存命中
func (pm *PerformanceMonitor) RecordCacheHit(templateName string, hit bool) {
pm.mutex.Lock()
defer pm.mutex.Unlock()
metrics, exists := pm.metrics[templateName]
if !exists {
metrics = &TemplateMetrics{Name: templateName}
pm.metrics[templateName] = metrics
}
if hit {
metrics.CacheHits++
} else {
metrics.CacheMisses++
}
}
// checkAlerts 检查告警
func (pm *PerformanceMonitor) checkAlerts(templateName string, metrics *TemplateMetrics) {
alert, exists := pm.alerts[templateName]
if !exists {
return
}
// 检查渲染时间告警
if alert.MaxDuration > 0 && metrics.AvgDuration > alert.MaxDuration {
if alert.Callback != nil {
go alert.Callback(metrics)
}
}
// 检查错误率告警
if alert.MaxErrorRate > 0 && metrics.RenderCount > 0 {
errorRate := float64(metrics.ErrorCount) / float64(metrics.RenderCount)
if errorRate > alert.MaxErrorRate {
if alert.Callback != nil {
go alert.Callback(metrics)
}
}
}
// 检查缓存命中率告警
if alert.MinCacheRate > 0 {
totalCache := metrics.CacheHits + metrics.CacheMisses
if totalCache > 0 {
cacheRate := float64(metrics.CacheHits) / float64(totalCache)
if cacheRate < alert.MinCacheRate {
if alert.Callback != nil {
go alert.Callback(metrics)
}
}
}
}
}
// GetMetrics 获取指定模板的性能指标
func (pm *PerformanceMonitor) GetMetrics(templateName string) *TemplateMetrics {
pm.mutex.RLock()
defer pm.mutex.RUnlock()
if metrics, exists := pm.metrics[templateName]; exists {
// 返回副本
result := *metrics
return &result
}
return nil
}
// GetAllMetrics 获取所有性能指标
func (pm *PerformanceMonitor) GetAllMetrics() map[string]*TemplateMetrics {
pm.mutex.RLock()
defer pm.mutex.RUnlock()
result := make(map[string]*TemplateMetrics)
for name, metrics := range pm.metrics {
// 返回副本
result[name] = &TemplateMetrics{
Name: metrics.Name,
RenderCount: metrics.RenderCount,
TotalDuration: metrics.TotalDuration,
AvgDuration: metrics.AvgDuration,
MaxDuration: metrics.MaxDuration,
MinDuration: metrics.MinDuration,
ErrorCount: metrics.ErrorCount,
CacheHits: metrics.CacheHits,
CacheMisses: metrics.CacheMisses,
LastRender: metrics.LastRender,
}
}
return result
}
// SetAlertThreshold 设置告警阈值
func (pm *PerformanceMonitor) SetAlertThreshold(templateName string, config *AlertConfig) {
pm.mutex.Lock()
defer pm.mutex.Unlock()
pm.alerts[templateName] = config
}
// PrintReport 打印性能报告
func (pm *PerformanceMonitor) PrintReport() {
pm.mutex.RLock()
defer pm.mutex.RUnlock()
fmt.Println("=== 模板性能报告 ===")
fmt.Printf("%-20s %-10s %-15s %-15s %-15s %-10s %-10s\n",
"模板名称", "渲染次数", "平均耗时", "最大耗时", "最小耗时", "错误数", "缓存命中率")
fmt.Println(strings.Repeat("-", 100))
for _, metrics := range pm.metrics {
totalCache := metrics.CacheHits + metrics.CacheMisses
cacheRate := "N/A"
if totalCache > 0 {
cacheRate = fmt.Sprintf("%.2f%%", float64(metrics.CacheHits)/float64(totalCache)*100)
}
fmt.Printf("%-20s %-10d %-15s %-15s %-15s %-10d %-10s\n",
metrics.Name,
metrics.RenderCount,
metrics.AvgDuration,
metrics.MaxDuration,
metrics.MinDuration,
metrics.ErrorCount,
cacheRate,
)
}
}
// Reset 重置性能指标
func (pm *PerformanceMonitor) Reset() {
pm.mutex.Lock()
defer pm.mutex.Unlock()
pm.metrics = make(map[string]*TemplateMetrics)
}
4. 模板缓存与性能优化
4.1 实战项目:CMS内容管理系统
go
// CMSSystem CMS内容管理系统
type CMSSystem struct {
inheritance *TemplateInheritance
partials *PartialManager
composer *TemplateComposer
cache *TemplateCache
monitor *PerformanceMonitor
conditional *ConditionalLogic
loop *LoopControl
// 数据模型
posts []Post
categories []Category
users []User
tags []Tag
mutex sync.RWMutex
}
// Post 文章模型
type Post struct {
ID int `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
Summary string `json:"summary"`
AuthorID int `json:"author_id"`
CategoryID int `json:"category_id"`
Tags []string `json:"tags"`
Status string `json:"status"` // draft, published, archived
ViewCount int `json:"view_count"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
PublishedAt *time.Time `json:"published_at,omitempty"`
}
// Category 分类模型
type Category struct {
ID int `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Description string `json:"description"`
PostCount int `json:"post_count"`
ParentID *int `json:"parent_id,omitempty"`
}
// User 用户模型
type User struct {
ID int `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
Name string `json:"name"`
Avatar string `json:"avatar"`
Role string `json:"role"` // admin, editor, author
}
// Tag 标签模型
type Tag struct {
ID int `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
PostCount int `json:"post_count"`
}
// NewCMSSystem 创建CMS系统
func NewCMSSystem(baseDir string) *CMSSystem {
inheritance := NewTemplateInheritance(baseDir)
partials := NewPartialManager(baseDir)
composer := NewTemplateComposer(inheritance, partials)
cms := &CMSSystem{
inheritance: inheritance,
partials: partials,
composer: composer,
cache: NewTemplateCache(),
monitor: NewPerformanceMonitor(),
conditional: NewConditionalLogic(),
loop: NewLoopControl(),
}
// 初始化系统
cms.initialize()
return cms
}
// initialize 初始化CMS系统
func (cms *CMSSystem) initialize() error {
// 设置基础布局
if err := cms.inheritance.SetupBaseLayouts(); err != nil {
return fmt.Errorf("设置基础布局失败: %w", err)
}
// 设置部分模板
if err := cms.partials.SetupCommonPartials(); err != nil {
return fmt.Errorf("设置部分模板失败: %w", err)
}
// 设置CMS专用模板
if err := cms.setupCMSTemplates(); err != nil {
return fmt.Errorf("设置CMS模板失败: %w", err)
}
// 初始化示例数据
cms.setupSampleData()
return nil
}
// setupSampleData 设置示例数据
func (cms *CMSSystem) setupSampleData() {
// 用户数据
cms.users = []User{
{ID: 1, Username: "admin", Email: "admin@example.com", Name: "管理员", Role: "admin"},
{ID: 2, Username: "editor", Email: "editor@example.com", Name: "编辑", Role: "editor"},
{ID: 3, Username: "author", Email: "author@example.com", Name: "作者", Role: "author"},
}
// 分类数据
cms.categories = []Category{
{ID: 1, Name: "技术", Slug: "tech", Description: "技术相关文章", PostCount: 5},
{ID: 2, Name: "生活", Slug: "life", Description: "生活感悟", PostCount: 3},
{ID: 3, Name: "教程", Slug: "tutorial", Description: "教程文章", PostCount: 4},
}
// 标签数据
cms.tags = []Tag{
{ID: 1, Name: "Go", Slug: "go", PostCount: 8},
{ID: 2, Name: "Web开发", Slug: "web-dev", PostCount: 6},
{ID: 3, Name: "模板", Slug: "template", PostCount: 4},
{ID: 4, Name: "性能优化", Slug: "performance", PostCount: 3},
}
// 文章数据
cms.posts = []Post{
{
ID: 1, Title: "Go Web模板系统详解",
Content: "这是一篇关于Go Web模板系统的详细教程...",
Summary: "深入了解Go Web模板系统的使用方法",
AuthorID: 1, CategoryID: 1, Tags: []string{"Go", "Web开发", "模板"},
Status: "published", ViewCount: 150,
CreatedAt: time.Now().AddDate(0, 0, -7),
UpdatedAt: time.Now().AddDate(0, 0, -1),
},
{
ID: 2, Title: "模板缓存与性能优化",
Content: "本文介绍如何优化模板渲染性能...",
Summary: "提升模板渲染性能的实用技巧",
AuthorID: 2, CategoryID: 3, Tags: []string{"性能优化", "模板"},
Status: "published", ViewCount: 89,
CreatedAt: time.Now().AddDate(0, 0, -5),
UpdatedAt: time.Now().AddDate(0, 0, -2),
},
{
ID: 3, Title: "CMS系统架构设计",
Content: "分享CMS系统的架构设计思路...",
Summary: "从零开始设计一个CMS系统",
AuthorID: 3, CategoryID: 1, Tags: []string{"架构", "CMS"},
Status: "draft", ViewCount: 0,
CreatedAt: time.Now().AddDate(0, 0, -3),
UpdatedAt: time.Now().AddDate(0, 0, -1),
},
}
}
// setupCMSTemplates 设置CMS专用模板
func (cms *CMSSystem) setupCMSTemplates() error {
// 首页模板
homeTemplate := &LayoutConfig{
Name: "home",
Path: "cms/home.html",
Extends: "main",
Blocks: []string{"hero", "featured", "recent", "sidebar"},
Variables: map[string]string{
"page_type": "home",
"title": "首页",
},
}
// 文章详情模板
postTemplate := &LayoutConfig{
Name: "post",
Path: "cms/post.html",
Extends: "main",
Blocks: []string{"content", "sidebar", "comments"},
Variables: map[string]string{
"page_type": "post",
},
}
// 分类页面模板
categoryTemplate := &LayoutConfig{
Name: "category",
Path: "cms/category.html",
Extends: "main",
Blocks: []string{"header", "posts", "pagination"},
Variables: map[string]string{
"page_type": "category",
},
}
// 管理后台首页模板
adminDashboardTemplate := &LayoutConfig{
Name: "admin_dashboard",
Path: "cms/admin/dashboard.html",
Extends: "admin",
Blocks: []string{"stats", "recent_posts", "quick_actions"},
Variables: map[string]string{
"page_type": "admin_dashboard",
"title": "管理后台",
},
}
// 注册模板
templates := []*LayoutConfig{
homeTemplate, postTemplate, categoryTemplate, adminDashboardTemplate,
}
for _, tmpl := range templates {
if err := cms.inheritance.RegisterLayout(tmpl); err != nil {
return fmt.Errorf("注册模板 %s 失败: %w", tmpl.Name, err)
}
}
return nil
}
// RenderHomePage 渲染首页
func (cms *CMSSystem) RenderHomePage() (string, error) {
start := time.Now()
// 检查缓存
cacheKey := "home_page"
if cached, found := cms.cache.Get(cacheKey); found {
cms.monitor.RecordCacheHit("home", true)
return string(cached), nil
}
cms.monitor.RecordCacheHit("home", false)
// 准备数据
data := map[string]interface{}{
"title": "欢迎来到我们的博客",
"featured_posts": cms.getFeaturedPosts(3),
"recent_posts": cms.getRecentPosts(5),
"categories": cms.categories,
"popular_tags": cms.getPopularTags(10),
"stats": cms.getStatistics(),
}
// 渲染模板
tmpl, exists := cms.inheritance.layouts["home"]
if !exists {
return "", errors.New("首页模板不存在")
}
var buf strings.Builder
err := tmpl.Execute(&buf, data)
// 记录性能
duration := time.Since(start)
cms.monitor.RecordRender("home", duration, err)
if err != nil {
return "", fmt.Errorf("渲染首页失败: %w", err)
}
result := buf.String()
// 缓存结果
cms.cache.Set(cacheKey, []byte(result), time.Hour)
return result, nil
}
// RenderPost 渲染文章详情
func (cms *CMSSystem) RenderPost(postID int) (string, error) {
start := time.Now()
// 检查缓存
cacheKey := fmt.Sprintf("post_%d", postID)
if cached, found := cms.cache.Get(cacheKey); found {
cms.monitor.RecordCacheHit("post", true)
return string(cached), nil
}
cms.monitor.RecordCacheHit("post", false)
// 查找文章
var post *Post
for i := range cms.posts {
if cms.posts[i].ID == postID {
post = &cms.posts[i]
break
}
}
if post == nil {
return "", errors.New("文章不存在")
}
// 准备数据
data := map[string]interface{}{
"post": post,
"author": cms.getUserByID(post.AuthorID),
"category": cms.getCategoryByID(post.CategoryID),
"related_posts": cms.getRelatedPosts(post.ID, 3),
"prev_post": cms.getAdjacentPosts(post.ID, "prev"),
"next_post": cms.getAdjacentPosts(post.ID, "next"),
"title": post.Title,
}
// 渲染模板
tmpl, exists := cms.inheritance.layouts["post"]
if !exists {
return "", errors.New("文章模板不存在")
}
var buf strings.Builder
err := tmpl.Execute(&buf, data)
// 记录性能
duration := time.Since(start)
cms.monitor.RecordRender("post", duration, err)
if err != nil {
return "", fmt.Errorf("渲染文章失败: %w", err)
}
result := buf.String()
// 缓存结果
cms.cache.Set(cacheKey, []byte(result), time.Hour*2)
return result, nil
}
// RenderCategory 渲染分类页面
func (cms *CMSSystem) RenderCategory(categoryID int, page int) (string, error) {
start := time.Now()
// 检查缓存
cacheKey := fmt.Sprintf("category_%d_page_%d", categoryID, page)
if cached, found := cms.cache.Get(cacheKey); found {
cms.monitor.RecordCacheHit("category", true)
return string(cached), nil
}
cms.monitor.RecordCacheHit("category", false)
// 查找分类
var category *Category
for i := range cms.categories {
if cms.categories[i].ID == categoryID {
category = &cms.categories[i]
break
}
}
if category == nil {
return "", errors.New("分类不存在")
}
// 准备数据
posts := cms.getPostsByCategory(categoryID, page, 10)
data := map[string]interface{}{
"category": category,
"posts": posts,
"current_page": page,
"total_pages": (category.PostCount + 9) / 10, // 向上取整
"title": fmt.Sprintf("%s - 分类", category.Name),
}
// 渲染模板
tmpl, exists := cms.inheritance.layouts["category"]
if !exists {
return "", errors.New("分类模板不存在")
}
var buf strings.Builder
err := tmpl.Execute(&buf, data)
// 记录性能
duration := time.Since(start)
cms.monitor.RecordRender("category", duration, err)
if err != nil {
return "", fmt.Errorf("渲染分类页面失败: %w", err)
}
result := buf.String()
// 缓存结果
cms.cache.Set(cacheKey, []byte(result), time.Minute*30)
return result, nil
}
// RenderAdminDashboard 渲染管理后台首页
func (cms *CMSSystem) RenderAdminDashboard() (string, error) {
start := time.Now()
// 管理后台不使用缓存,确保数据实时性
// 准备数据
data := map[string]interface{}{
"stats": cms.getStatistics(),
"recent_posts": cms.getRecentPosts(10),
"draft_posts": cms.getDraftPosts(),
"categories": cms.categories,
"users": cms.users,
"title": "管理后台",
}
// 渲染模板
tmpl, exists := cms.inheritance.layouts["admin_dashboard"]
if !exists {
return "", errors.New("管理后台模板不存在")
}
var buf strings.Builder
err := tmpl.Execute(&buf, data)
// 记录性能
duration := time.Since(start)
cms.monitor.RecordRender("admin_dashboard", duration, err)
if err != nil {
return "", fmt.Errorf("渲染管理后台失败: %w", err)
}
return buf.String(), nil
}
// 辅助方法
// getFeaturedPosts 获取推荐文章
func (cms *CMSSystem) getFeaturedPosts(limit int) []Post {
var featured []Post
count := 0
for _, post := range cms.posts {
if post.Status == "published" && post.ViewCount > 100 {
featured = append(featured, post)
count++
if count >= limit {
break
}
}
}
return featured
}
// getRecentPosts 获取最新文章
func (cms *CMSSystem) getRecentPosts(limit int) []Post {
var recent []Post
count := 0
// 按创建时间倒序
for i := len(cms.posts) - 1; i >= 0 && count < limit; i-- {
if cms.posts[i].Status == "published" {
recent = append(recent, cms.posts[i])
count++
}
}
return recent
}
// getRelatedPosts 获取相关文章
func (cms *CMSSystem) getRelatedPosts(postID int, limit int) []Post {
var related []Post
var currentPost *Post
// 找到当前文章
for i := range cms.posts {
if cms.posts[i].ID == postID {
currentPost = &cms.posts[i]
break
}
}
if currentPost == nil {
return related
}
count := 0
for _, post := range cms.posts {
if post.ID != postID && post.Status == "published" && count < limit {
// 简单的相关性判断:同分类或有共同标签
if post.CategoryID == currentPost.CategoryID {
related = append(related, post)
count++
}
}
}
return related
}
// getAdjacentPosts 获取相邻文章
func (cms *CMSSystem) getAdjacentPosts(postID int, direction string) *Post {
for i, post := range cms.posts {
if post.ID == postID {
if direction == "prev" && i > 0 {
return &cms.posts[i-1]
} else if direction == "next" && i < len(cms.posts)-1 {
return &cms.posts[i+1]
}
break
}
}
return nil
}
// getPostsByCategory 按分类获取文章
func (cms *CMSSystem) getPostsByCategory(categoryID, page, pageSize int) []Post {
var posts []Post
for _, post := range cms.posts {
if post.CategoryID == categoryID && post.Status == "published" {
posts = append(posts, post)
}
}
// 分页
start := (page - 1) * pageSize
end := start + pageSize
if start >= len(posts) {
return []Post{}
}
if end > len(posts) {
end = len(posts)
}
return posts[start:end]
}
// getDraftPosts 获取草稿文章
func (cms *CMSSystem) getDraftPosts() []Post {
var drafts []Post
for _, post := range cms.posts {
if post.Status == "draft" {
drafts = append(drafts, post)
}
}
return drafts
}
// getUserByID 根据ID获取用户
func (cms *CMSSystem) getUserByID(userID int) *User {
for i := range cms.users {
if cms.users[i].ID == userID {
return &cms.users[i]
}
}
return nil
}
// getCategoryByID 根据ID获取分类
func (cms *CMSSystem) getCategoryByID(categoryID int) *Category {
for i := range cms.categories {
if cms.categories[i].ID == categoryID {
return &cms.categories[i]
}
}
return nil
}
// getAllCategories 获取所有分类
func (cms *CMSSystem) getAllCategories() []Category {
return cms.categories
}
// getPopularTags 获取热门标签
func (cms *CMSSystem) getPopularTags(limit int) []Tag {
// 简单返回前N个标签
if limit > len(cms.tags) {
limit = len(cms.tags)
}
return cms.tags[:limit]
}
// getStatistics 获取统计信息
func (cms *CMSSystem) getStatistics() map[string]interface{} {
publishedCount := 0
draftCount := 0
totalViews := 0
for _, post := range cms.posts {
if post.Status == "published" {
publishedCount++
totalViews += post.ViewCount
} else if post.Status == "draft" {
draftCount++
}
}
return map[string]interface{}{
"total_posts": len(cms.posts),
"published_posts": publishedCount,
"draft_posts": draftCount,
"total_categories": len(cms.categories),
"total_tags": len(cms.tags),
"total_users": len(cms.users),
"total_views": totalViews,
}
}
// RunCMSDemo 运行CMS演示
func RunCMSDemo() {
fmt.Println("=== CMS内容管理系统演示 ===")
// 创建CMS系统
cms := NewCMSSystem("templates")
// 渲染首页
fmt.Println("\n1. 渲染首页...")
homePage, err := cms.RenderHomePage()
if err != nil {
fmt.Printf("渲染首页失败: %v\n", err)
} else {
fmt.Printf("首页渲染成功,长度: %d 字符\n", len(homePage))
}
// 渲染文章详情
fmt.Println("\n2. 渲染文章详情...")
postPage, err := cms.RenderPost(1)
if err != nil {
fmt.Printf("渲染文章失败: %v\n", err)
} else {
fmt.Printf("文章渲染成功,长度: %d 字符\n", len(postPage))
}
// 渲染分类页面
fmt.Println("\n3. 渲染分类页面...")
categoryPage, err := cms.RenderCategory(1, 1)
if err != nil {
fmt.Printf("渲染分类页面失败: %v\n", err)
} else {
fmt.Printf("分类页面渲染成功,长度: %d 字符\n", len(categoryPage))
}
// 渲染管理后台
fmt.Println("\n4. 渲染管理后台...")
adminPage, err := cms.RenderAdminDashboard()
if err != nil {
fmt.Printf("渲染管理后台失败: %v\n", err)
} else {
fmt.Printf("管理后台渲染成功,长度: %d 字符\n", len(adminPage))
}
// 显示性能报告
fmt.Println("\n5. 性能监控报告:")
cms.monitor.PrintReport()
// 显示缓存统计
fmt.Println("\n6. 缓存统计:")
stats := cms.cache.GetStats()
fmt.Printf("缓存命中: %d, 未命中: %d, 命中率: %.2f%%\n",
stats.Hits, stats.Misses,
float64(stats.Hits)/float64(stats.Hits+stats.Misses)*100)
fmt.Printf("缓存条目: %d, 总大小: %d KB\n",
stats.EntryCount, stats.TotalSize/1024)
}
// main 主函数演示
func main() {
RunCMSDemo()
}
5. 实战项目:CMS内容管理系统
5.1 章节总结
本章深入探讨了Go Web模板的高级特性,包括模板继承、组合、逻辑控制和性能优化。通过构建一个完整的CMS内容管理系统,我们学习了:
核心内容回顾
-
模板继承与布局系统
- 模板继承机制的设计与实现
- 布局配置与验证系统
- 模板构建器的灵活应用
- 多层次布局的组合策略
-
部分模板管理
- 部分模板的注册与管理
- 依赖关系的自动解析
- 模板组合器的统一调度
- 常用组件的模块化设计
-
高级逻辑控制
- 条件逻辑的扩展与定制
- 循环控制的多样化实现
- 迭代器、过滤器、排序器的组合使用
- 模板函数的动态注册机制
-
缓存与性能优化
- 多策略缓存系统设计
- LRU算法的内存管理
- 性能监控与告警机制
- 缓存命中率的统计分析
-
CMS实战项目
- 完整的内容管理系统架构
- 数据模型的设计与关联
- 多页面类型的渲染策略
- 缓存策略的差异化应用
技术特色
- 模块化设计:每个组件都具有独立的职责和清晰的接口
- 中文注释:所有关键代码都有详细的中文说明
- 最佳实践:遵循Go语言的编程规范和设计模式
- 性能优化:从缓存、监控到内存管理的全方位优化
实际应用价值
- Web开发:为复杂的Web应用提供强大的模板支持
- 多端适配:支持PC、移动端、管理后台的差异化布局
- 系统集成:可以轻松集成到现有的Go Web框架中
- 扩展性:提供了丰富的扩展点和自定义机制
5.2 下一章预告
下一章我们将学习 "Go Web 编程快速入门 · 08 - JSON API:编码、解码与内容协商",内容包括:
-
JSON数据处理
- 高级编码解码技术
- 自定义类型处理器
- 流式JSON处理
- Schema验证机制
-
RESTful API设计
- API框架架构设计
- 路由与中间件系统
- 版本管理策略
- 错误处理机制
-
内容协商
- 多格式内容支持
- Accept头解析
- 响应格式自动选择
- 压缩与编码处理
-
实战项目
- 电商API系统构建
- 商品管理接口
- 订单处理流程
- 性能监控与优化
通过下一章的学习,您将掌握构建高性能、可扩展的JSON API服务的完整技能栈!
本章完整代码可在项目仓库中找到,建议结合实际项目进行练习和扩展。