Skip to content

5.2 代码生成

奥集能平台的代码生成引擎是其核心生产力工具之一,旨在显著提升应用开发效率,降低基础、重复性编码工作的复杂度。它基于平台定义的元数据模型、业务规则及预置的最佳实践模板,自动化生成高质量、标准化、可直接运行或进一步扩展的源代码。该功能尤其适用于快速构建业务实体、API接口、基础UI组件、数据访问层以及与平台核心服务(如权限、工作流、消息)集成的粘合代码。

核心原理与流程

代码生成并非简单的字符串拼接,而是基于对平台架构和业务语义的深度理解。其流程如下

  • 元数据输入: 开发者通过平台的可视化建模工具或特定DSL(领域特定语言)定义业务对象(如部门、项目、订单)、其属性、关联关系、行为约束、UI表单布局、API端点等元数据。
  • 模板选择与配置: 平台提供一系列针对不同技术栈(如Java/Spring Boot, Node.js, Python/Django, React, Vue等)和功能模块(如CRUD API、管理界面、报表服务)的预置、可定制的代码模板。开发者根据需要选择并微调模板参数。
  • 引擎处理: 代码生成引擎将元数据模型注入选定的模板中。模板引擎(如Freemarker, Velocity)根据模型数据动态填充模板占位符,执行逻辑判断(如根据字段类型生成不同的校验注解),循环生成重复结构(如实体属性列表)。
  • 代码输出与集成: 引擎输出完整的、结构化的源代码文件(如.java, .tsx, .py, .yaml),并自动放置在项目目录的正确位置。生成的代码通常设计为可扩展,留有清晰的扩展点(如// TODO: Add custom business logic here注释或可覆盖的方法),方便开发者注入业务逻辑。

关键功能与代码

元数据驱动的实体与持久层生成

奥集能平台采用模型驱动开发范式,业务实体定义作为系统基石。通过可视化建模工具或DSL声明实体属性、关联关系和约束条件,平台自动生成符合领域驱动设计的领域模型。持久层代码严格遵循JPA规范,包含审计字段、软删除支持和多租户隔离机制,确保数据访问层的一致性和可维护性。 义Employee实体元数据(包含基本字段和关联部门)后,平台可生成对应的领域模型类、数据库迁移脚本(DDL)以及数据访问对象(DAO)或Repository接口。

  • Java (Spring Data JPA) 实体类:
// 生成的文件: src/main/java/com/example/app/domain/Employee.java
package com.example.app.domain;

import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.time.LocalDateTime;

@Entity
@Table(name = "t_employee")
@EntityListeners(AuditingEntityListener.class)
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "emp_name", nullable = false, length = 100)
    private String name;

    @Column(name = "emp_code", unique = true, length = 20)
    private String employeeCode;

    @Column(name = "email", length = 255)
    private String email;

    @Enumerated(EnumType.STRING)
    @Column(name = "status", length = 20)
    private EmployeeStatus status = EmployeeStatus.ACTIVE; // 默认值

    // 关联部门 (Many-to-One)
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "department_id", foreignKey = @ForeignKey(name = "fk_employee_department"))
    private Department department;

    @CreatedDate
    @Column(name = "created_at", updatable = false)
    private LocalDateTime createdAt;

    @LastModifiedDate
    @Column(name = "updated_at")
    private LocalDateTime updatedAt;

    // Getters and Setters (自动生成)
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    // ... 其他getter/setter ...

    // 枚举定义 (通常生成在单独文件或内部类)
    public enum EmployeeStatus {
        ACTIVE, ON_LEAVE, TERMINATED
    }
}
  • Spring Data JPA Repository 接口:
// 生成的文件: src/main/java/com/example/app/repository/EmployeeRepository.java
package com.example.app.repository;

import com.example.app.domain.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import java.util.List;
import java.util.Optional;

public interface EmployeeRepository extends
        JpaRepository<Employee, Long>,
        JpaSpecificationExecutor<Employee> { // 支持动态查询

    Optional<Employee> findByEmployeeCode(String employeeCode);
    List<Employee> findByDepartmentId(Long departmentId);
    List<Employee> findByStatus(Employee.EmployeeStatus status);
    // 根据元数据中定义的查询需求生成更多方法...
}
  • Liquibase 数据库迁移脚本 (YAML格式):
# 生成的文件: src/main/resources/db/changelog/v1.0__create_employee_table.yaml
databaseChangeLog:
  - changeSet:
      id: create-table-employee
      author: orginone-generator
      changes:
        - createTable:
            tableName: t_employee
            columns:
              - column:
                  name: id
                  type: BIGINT
                  autoIncrement: true
                  constraints:
                    primaryKey: true
                    nullable: false
              - column:
                  name: emp_name
                  type: VARCHAR(100)
                  constraints:
                    nullable: false
              - column:
                  name: emp_code
                  type: VARCHAR(20)
                  constraints:
                    unique: true
              - column:
                  name: email
                  type: VARCHAR(255)
              - column:
                  name: status
                  type: VARCHAR(20)
              - column:
                  name: department_id
                  type: BIGINT
              - column:
                  name: created_at
                  type: TIMESTAMP
              - column:
                  name: updated_at
                  type: TIMESTAMP
        - addForeignKeyConstraint:
            baseTableName: t_employee
            baseColumnNames: department_id
            constraintName: fk_employee_department
            referencedTableName: t_department # 假设Department表已存在
            referencedColumnNames: id

RESTful API 控制器与服务层生成

平台生成的API层采用RESTful最佳实践,自动实现CRUD操作、分页查询和条件过滤等通用功能。服务层代码采用接口与实现分离模式,内置事务管理和异常处理机制。生成的API文档符合OpenAPI规范,并自动集成平台统一认证体系,大幅降低API开发复杂度。 基于定义的Employee实体和需要的API操作(CRUD),生成对应的Controller、Service接口及实现类。

  • Spring MVC Controller :
// 生成的文件: src/main/java/com/example/app/controller/EmployeeController.java
package com.example.app.controller;

import com.example.app.domain.Employee;
import com.example.app.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.net.URI;

@RestController
@RequestMapping("/api/employees")
public class EmployeeController {

    private final EmployeeService employeeService;

    @Autowired
    public EmployeeController(EmployeeService employeeService) {
        this.employeeService = employeeService;
    }

    @PostMapping
    public ResponseEntity<Employee> createEmployee(@RequestBody Employee employee) {
        Employee savedEmployee = employeeService.createEmployee(employee);
        return ResponseEntity.created(URI.create("/api/employees/" + savedEmployee.getId())).body(savedEmployee);
    }

    @GetMapping("/{id}")
    public ResponseEntity<Employee> getEmployeeById(@PathVariable Long id) {
        return ResponseEntity.of(employeeService.getEmployeeById(id));
    }

    @GetMapping
    public ResponseEntity<Page<Employee>> getAllEmployees(
            @PageableDefault(size = 20, sort = "name") Pageable pageable) {
        return ResponseEntity.ok(employeeService.getAllEmployees(pageable));
    }

    @PutMapping("/{id}")
    public ResponseEntity<Employee> updateEmployee(@PathVariable Long id, @RequestBody Employee employee) {
        return ResponseEntity.ok(employeeService.updateEmployee(id, employee));
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteEmployee(@PathVariable Long id) {
        employeeService.deleteEmployee(id);
        return ResponseEntity.noContent().build();
    }

    // 根据元数据定义生成更多端点,如按状态查询 /by-status?status=ACTIVE
    @GetMapping("/by-status")
    public ResponseEntity<List<Employee>> getEmployeesByStatus(@RequestParam Employee.EmployeeStatus status) {
        return ResponseEntity.ok(employeeService.getEmployeesByStatus(status));
    }
}
  • Service 接口与实现:
// 生成的文件: src/main/java/com/example/app/service/EmployeeService.java
package com.example.app.service;

import com.example.app.domain.Employee;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.List;
import java.util.Optional;

public interface EmployeeService {
    Employee createEmployee(Employee employee);
    Optional<Employee> getEmployeeById(Long id);
    Page<Employee> getAllEmployees(Pageable pageable);
    Employee updateEmployee(Long id, Employee employee);
    void deleteEmployee(Long id);
    List<Employee> getEmployeesByStatus(Employee.EmployeeStatus status);
}
// 生成的文件: src/main/java/com/example/app/service/impl/EmployeeServiceImpl.java
package com.example.app.service.impl;

import com.example.app.domain.Employee;
import com.example.app.repository.EmployeeRepository;
import com.example.app.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;

@Service
@Transactional
public class EmployeeServiceImpl implements EmployeeService {

    private final EmployeeRepository employeeRepository;

    @Autowired
    public EmployeeServiceImpl(EmployeeRepository employeeRepository) {
        this.employeeRepository = employeeRepository;
    }

    @Override
    public Employee createEmployee(Employee employee) {
        // 此处可添加创建前的业务逻辑校验(如唯一性检查)
        // 生成器通常会留下扩展注释
        // TODO: Add pre-create validation logic if needed (e.g., unique emp_code)
        return employeeRepository.save(employee);
    }

    @Override
    public Optional<Employee> getEmployeeById(Long id) {
        return employeeRepository.findById(id);
    }

    @Override
    public Page<Employee> getAllEmployees(Pageable pageable) {
        return employeeRepository.findAll(pageable);
    }

    @Override
    public Employee updateEmployee(Long id, Employee employeeDetails) {
        Employee existingEmployee = employeeRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Employee not found with id: " + id)); // 更推荐使用自定义异常
        // 更新逻辑:通常只允许更新特定字段
        existingEmployee.setName(employeeDetails.getName());
        existingEmployee.setEmail(employeeDetails.getEmail());
        existingEmployee.setStatus(employeeDetails.getStatus());
        // ... 更新其他允许的字段
        // TODO: Handle department association update if allowed
        return employeeRepository.save(existingEmployee);
    }

    @Override
    public void deleteEmployee(Long id) {
        Employee employee = employeeRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Employee not found with id: " + id));
        // 可能添加软删除标记而非物理删除
        // employee.setStatus(EmployeeStatus.TERMINATED);
        // employeeRepository.save(employee);
        employeeRepository.deleteById(id); // 物理删除
    }

    @Override
    public List<Employee> getEmployeesByStatus(Employee.EmployeeStatus status) {
        return employeeRepository.findByStatus(status);
    }
}

基础前端界面组件生成 (React )

前端组件生成基于平台UI设计系统,自动创建符合企业级应用标准的React组件。生成的界面包含国际化支持、响应式布局和可访问性特性,并深度集成平台前端框架,提供统一的认证管理、权限控制和状态管理方案,确保用户体验的一致性。 根据实体元数据和表单布局定义,生成基础的列表页、详情页、创建/编辑表单的React组件。这些组件通常使用平台提供的UI库(如Ant Design, Material-UI)并集成平台的前端SDK进行API调用和状态管理。

  • Employee列表页组件 (EmployeeList.jsx):
// 生成的文件: src/pages/employee/EmployeeList.jsx
import React, { useState, useEffect } from 'react';
import { Table, Button, Space, Input, Select, message } from 'antd';
import { PlusOutlined, SearchOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
import { Link } from 'react-router-dom';
import EmployeeService from '../../services/EmployeeService'; // 生成的API Service
import PageHeaderWrapper from '../../components/PageHeaderWrapper'; // 平台通用布局组件

const { Column } = Table;
const { Option } = Select;

const EmployeeList = () => {
  const [employees, setEmployees] = useState([]);
  const [loading, setLoading] = useState(false);
  const [pagination, setPagination] = useState({ current: 1, pageSize: 10, total: 0 });
  const [filters, setFilters] = useState({ name: '', status: null });

  useEffect(() => {
    fetchData();
  }, [pagination.current, pagination.pageSize, filters]);

  const fetchData = async () => {
    setLoading(true);
    try {
      const params = {
        page: pagination.current - 1, // Spring Data Pageable 通常0-based
        size: pagination.pageSize,
        ...filters,
      };
      const response = await EmployeeService.getAllEmployees(params); // 调用生成的API Service方法
      setEmployees(response.content);
      setPagination({
        ...pagination,
        total: response.totalElements,
      });
    } catch (error) {
      message.error('Failed to fetch employees: ' + error.message);
    } finally {
      setLoading(false);
    }
  };

  const handleTableChange = (newPagination) => {
    setPagination(newPagination);
  };

  const handleSearch = (field, value) => {
    setFilters({ ...filters, [field]: value });
    setPagination({ ...pagination, current: 1 }); // 重置到第一页
  };

  const handleDelete = async (id) => {
    try {
      await EmployeeService.deleteEmployee(id);
      message.success('Employee deleted successfully');
      fetchData(); // 刷新列表
    } catch (error) {
      message.error('Delete failed: ' + error.message);
    }
  };

  return (
    <PageHeaderWrapper title="Employee Management">
      <Space style={{ marginBottom: 16 }}>
        <Input
          prefix={<SearchOutlined />}
          placeholder="Search by Name"
          value={filters.name}
          onChange={(e) => handleSearch('name', e.target.value)}
          allowClear
        />
        <Select
          placeholder="Filter by Status"
          value={filters.status}
          onChange={(value) => handleSearch('status', value)}
          allowClear
          style={{ width: 180 }}
        >
          <Option value="ACTIVE">Active</Option>
          <Option value="ON_LEAVE">On Leave</Option>
          <Option value="TERMINATED">Terminated</Option>
        </Select>
        <Button type="primary" icon={<PlusOutlined />}>
          <Link to="/employees/new">Create Employee</Link>
        </Button>
      </Space>
      <Table
        dataSource={employees}
        rowKey="id"
        loading={loading}
        pagination={pagination}
        onChange={handleTableChange}
      >
        <Column title="ID" dataIndex="id" key="id" />
        <Column title="Name" dataIndex="name" key="name" />
        <Column title="Employee Code" dataIndex="employeeCode" key="employeeCode" />
        <Column title="Email" dataIndex="email" key="email" />
        <Column
          title="Status"
          dataIndex="status"
          key="status"
          render={(status) => <span>{status}</span>} // 可以美化显示
        />
        <Column
          title="Department"
          dataIndex={['department', 'name']} // 关联对象属性访问
          key="department.name"
        />
        <Column
          title="Action"
          key="action"
          render={(_, record) => (
            <Space size="middle">
              <Link to={`/employees/edit/${record.id}`}>
                <Button type="link" icon={<EditOutlined />}>Edit</Button>
              </Link>
              <Button
                type="link"
                danger
                icon={<DeleteOutlined />}
                onClick={() => {
                  if (window.confirm('Are you sure to delete this employee?')) {
                    handleDelete(record.id);
                  }
                }}
              >
                Delete
              </Button>
            </Space>
          )}
        />
      </Table>
    </PageHeaderWrapper>
  );
};

export default EmployeeList;
  • Employee表单组件示例 (EmployeeForm.jsx - 用于创建/编辑):
// 生成的文件: src/pages/employee/EmployeeForm.jsx
import React, { useState, useEffect } from 'react';
import { Form, Input, Button, Select, message, Spin } from 'antd';
import { useParams, useHistory } from 'react-router-dom';
import DepartmentService from '../../services/DepartmentService'; // 关联服务
import EmployeeService from '../../services/EmployeeService';

const { Item } = Form;
const { Option } = Select;

const EmployeeForm = () => {
  const [form] = Form.useForm();
  const [loading, setLoading] = useState(false);
  const [saving, setSaving] = useState(false);
  const [departments, setDepartments] = useState([]);
  const { id } = useParams(); // 获取路由参数 (编辑时存在)
  const history = useHistory();

  useEffect(() => {
    // 1. 加载关联的部门列表
    const loadDepartments = async () => {
      try {
        const depts = await DepartmentService.getAllDepartments(); // 假设有简单列表方法
        setDepartments(depts);
      } catch (error) {
        message.error('Failed to load departments');
      }
    };
    loadDepartments();

    // 2. 如果是编辑,加载现有员工数据
    if (id) {
      setLoading(true);
      EmployeeService.getEmployeeById(id)
        .then((employee) => {
          if (employee) {
            form.setFieldsValue({
              ...employee,
              departmentId: employee.department?.id, // 关联字段处理
            });
          }
        })
        .catch((error) => message.error('Failed to load employee'))
        .finally(() => setLoading(false));
    }
  }, [id, form]);

  const onFinish = async (values) => {
    setSaving(true);
    try {
      const employeeData = {
        ...values,
        department: values.departmentId ? { id: values.departmentId } : null, // 构建关联对象
      };
      if (id) {
        await EmployeeService.updateEmployee(id, employeeData);
        message.success('Employee updated successfully!');
      } else {
        await EmployeeService.createEmployee(employeeData);
        message.success('Employee created successfully!');
      }
      history.push('/employees'); // 保存成功后返回列表页
    } catch (error) {
      message.error(`Save failed: ${error.message || error}`);
    } finally {
      setSaving(false);
    }
  };

  return (
    <Spin spinning={loading || saving}>
      <Form
        form={form}
        layout="vertical"
        onFinish={onFinish}
        initialValues={{ status: 'ACTIVE' }} // 默认状态
      >
        <Item
          label="Full Name"
          name="name"
          rules={[{ required: true, message: 'Please input the employee name!' }]}
        >
          <Input placeholder="Enter full name" />
        </Item>
        <Item
          label="Employee Code"
          name="employeeCode"
          rules={[{ required: true, message: 'Employee code is required!' }]}
        >
          <Input placeholder="Enter unique employee code" />
        </Item>
        <Item
          label="Email"
          name="email"
          rules={[{ type: 'email', message: 'Please enter a valid email!' }]}
        >
          <Input placeholder="Enter email address" />
        </Item>
        <Item label="Status" name="status">
          <Select>
            <Option value="ACTIVE">Active</Option>
            <Option value="ON_LEAVE">On Leave</Option>
            <Option value="TERMINATED">Terminated</Option>
          </Select>
        </Item>
        <Item label="Department" name="departmentId">
          <Select placeholder="Select department" allowClear>
            {departments.map((dept) => (
              <Option key={dept.id} value={dept.id}>
                {dept.name}
              </Option>
            ))}
          </Select>
        </Item>
        <Item>
          <Button type="primary" htmlType="submit" loading={saving}>
            {id ? 'Update Employee' : 'Create Employee'}
          </Button>
          <Button style={{ marginLeft: 8 }} onClick={() => history.goBack()}>
            Cancel
          </Button>
        </Item>
      </Form>
    </Spin>
  );
};

export default EmployeeForm;

工作流集成代码生成

工作流引擎集成是奥集能平台的核心能力。代码生成器自动创建流程启动器、任务处理器和状态同步机制,将业务流程与业务对象无缝连接。生成的代码处理流程状态转换、任务分配和审批历史,实现业务流程与数据模型的深度集成。 如果实体关联了平台的工作流引擎(如Activiti, Flowable),代码生成器可以创建流程启动表单、任务处理页面以及与流程引擎交互的服务代码。

  • 启动请假流程的表单与服务集成 (简化):
// 在LeaveApplicationController.java 中
@PostMapping("/start")
public ResponseEntity<ProcessInstance> startLeaveProcess(@RequestBody LeaveRequest leaveRequest) {
    // 1. 验证和保存请假申请实体 (假设存在)
    LeaveApplication application = leaveAppService.save(leaveRequest);
    // 2. 使用平台工作流服务启动流程
    ProcessInstance instance = workflowService.startProcessInstanceByKey(
            "leaveApprovalProcess", // 流程定义Key
            application.getId().toString(), // 业务Key
            Map.of( // 设置流程变量
                    "applicantId", getCurrentUserId(),
                    "leaveType", leaveRequest.getType(),
                    "days", leaveRequest.getDays(),
                    "startDate", leaveRequest.getStartDate(),
                    "reason", leaveRequest.getReason()
            )
    );
    // 3. (可选) 关联流程实例ID到业务实体
    application.setProcessInstanceId(instance.getId());
    leaveAppService.update(application);
    return ResponseEntity.ok(instance);
}
// WorkflowService 封装 (部分)
@Service
public class WorkflowServiceImpl implements WorkflowService {

    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RepositoryService repositoryService;

    @Override
    public ProcessInstance startProcessInstanceByKey(String processDefinitionKey, String businessKey, Map<String, Object> variables) {
        return runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variables);
    }

    @Override
    public List<Task> getUserTasks(String userId) {
        return taskService.createTaskQuery().taskAssignee(userId).list();
    }

    @Override
    public void completeTask(String taskId, Map<String, Object> variables) {
        taskService.complete(taskId, variables);
    }
    // ... 其他工作流操作封装
}

平台配置与集成代码

平台集成代码生成确保新模块无缝接入奥集能核心服务,包括权限管理、审计日志、消息总线和文件服务等基础设施。这些代码片段通过注解、拦截器和服务封装实现标准化集成

  • 统一权限控制实现
// 权限控制切面
@Aspect
@Component
public class AuthorizationAspect {
    
    @Autowired
    private PermissionService permissionService;
    
    @Before("@annotation(requiredPermission)")
    public void checkPermission(JoinPoint joinPoint, RequiredPermission requiredPermission) {
        String resource = requiredPermission.resource();
        String action = requiredPermission.action();
        String userId = SecurityContextHolder.getContext().getAuthentication().getName();
        
        if (!permissionService.hasPermission(userId, resource, action)) {
            throw new AccessDeniedException("权限不足: " + resource + ":" + action);
        }
    }
}

// 自定义权限注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequiredPermission {
    String resource(); // 资源标识
    String action();   // 操作类型: read,write,manage
}

// 控制器使用
@RestController
@RequestMapping("/api/sensitive-data")
public class SensitiveDataController {
    
    @RequiredPermission(resource = "SENSITIVE_DATA", action = "read")
    @GetMapping("/{id}")
    public ResponseEntity<SensitiveData> getData(@PathVariable Long id) {
        // 获取敏感数据逻辑
    }
}
  • 审计日志自动记录
// 审计日志实体
@Entity
@Table(name = "sys_audit_log")
public class AuditLog {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String module;      // 操作模块
    private String operation;   // 操作类型
    private String targetId;    // 操作对象ID
    private String operator;    // 操作人
    private LocalDateTime operateTime; // 操作时间
    private String details;     // 操作详情
    private String ipAddress;   // 操作IP
}

// 审计日志切面
@Aspect
@Component
public class AuditLogAspect {
    
    @Autowired
    private AuditLogRepository auditLogRepository;
    
    @AfterReturning(pointcut = "@annotation(auditLog)", returning = "result")
    public void logAfter(JoinPoint joinPoint, AuditLog auditLog, Object result) {
        String operator = SecurityUtils.getCurrentUsername();
        String ip = WebUtils.getRequestIp();
        
        AuditLog log = new AuditLog();
        log.setModule(auditLog.module());
        log.setOperation(auditLog.action());
        log.setOperator(operator);
        log.setOperateTime(LocalDateTime.now());
        log.setIpAddress(ip);
        
        // 解析操作目标ID
        Object[] args = joinPoint.getArgs();
        if (args.length > 0 && args[0] instanceof BaseEntity) {
            log.setTargetId(((BaseEntity) args[0]).getId().toString());
        }
        
        auditLogRepository.save(log);
    }
}

// 自定义审计注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AuditLog {
    String module(); // 模块名称
    String action(); // 操作类型
}

// 服务层使用
@Service
public class DocumentService {
    
    @AuditLog(module = "DOCUMENT", action = "DELETE")
    public void deleteDocument(Long docId) {
        // 删除文档逻辑
    }
}
  • 平台消息总线集成
// 消息生产者服务
@Service
public class EventPublisherService {
    
    @Autowired
    private PlatformMessageTemplate messageTemplate;
    
    public void publishDomainEvent(String eventType, Object payload) {
        PlatformMessage message = new PlatformMessage.Builder()
            .topic("DOMAIN_EVENTS")
            .eventType(eventType)
            .payload(JsonUtils.toJson(payload))
            .sourceService("document-service")
            .build();
        
        messageTemplate.send(message);
    }
}

// 消息消费者
@Component
public class DocumentEventListener {
    
    @PlatformListener(topic = "DOMAIN_EVENTS", eventType = "DOCUMENT_UPDATED")
    public void handleDocumentUpdate(PlatformMessage message) {
        DocumentUpdateEvent event = JsonUtils.fromJson(
            message.getPayload(), DocumentUpdateEvent.class);
        
        // 处理文档更新事件
        cacheService.refreshDocumentCache(event.getDocId());
        notificationService.notifySubscribers(event);
    }
}

// 领域事件发布
@Service
public class DocumentService {
    
    @Autowired
    private EventPublisherService eventPublisher;
    
    @Transactional
    public Document updateDocument(Document document) {
        Document updated = documentRepository.save(document);
        
        // 发布领域事件
        DocumentUpdateEvent event = new DocumentUpdateEvent(
            updated.getId(), 
            updated.getLastModifiedBy(),
            updated.getVersion()
        );
        eventPublisher.publishDomainEvent("DOCUMENT_UPDATED", event);
        
        return updated;
    }
}
  • 统一文件服务集成
// 文件服务客户端
@Service
public class PlatformFileService {
    
    @Autowired
    private FileServiceClient fileServiceClient;
    
    public FileUploadResult uploadFile(MultipartFile file, String businessType) {
        try {
            return fileServiceClient.upload(
                file.getInputStream(),
                file.getOriginalFilename(),
                file.getContentType(),
                file.getSize(),
                businessType,
                SecurityUtils.getCurrentUserId()
            );
        } catch (IOException e) {
            throw new FileUploadException("文件上传失败", e);
        }
    }
    
    public ResponseEntity<Resource> downloadFile(String fileId) {
        FileInfo fileInfo = fileServiceClient.getFileInfo(fileId);
        Resource resource = fileServiceClient.download(fileId);
        
        return ResponseEntity.ok()
            .header(HttpHeaders.CONTENT_DISPOSITION, 
                   "attachment; filename=\"" + fileInfo.getOriginalName() + "\"")
            .contentType(MediaType.parseMediaType(fileInfo.getContentType()))
            .body(resource);
    }
}

// 控制器集成
@RestController
@RequestMapping("/api/documents")
public class DocumentController {
    
    @Autowired
    private PlatformFileService fileService;
    
    @PostMapping("/{docId}/attachments")
    public ResponseEntity<Attachment> uploadAttachment(
            @PathVariable Long docId,
            @RequestParam("file") MultipartFile file) {
        
        FileUploadResult result = fileService.uploadFile(file, "DOCUMENT_ATTACHMENT");
        
        Attachment attachment = new Attachment();
        attachment.setDocumentId(docId);
        attachment.setFileId(result.getFileId());
        attachment.setFileName(result.getOriginalName());
        attachment.setFileSize(result.getFileSize());
        attachment.setMimeType(result.getContentType());
        
        Attachment saved = attachmentRepository.save(attachment);
        return ResponseEntity.created(URI.create("/attachments/" + saved.getId()))
                             .body(saved);
    }
    
    @GetMapping("/attachments/{fileId}/download")
    public ResponseEntity<Resource> downloadAttachment(@PathVariable String fileId) {
        return fileService.downloadFile(fileId);
    }
}

使用建议

  1. 理解生成内容: 开发者需理解生成代码的结构和意图,以便在预留的扩展点正确添加业务逻辑。
  2. 定制模板: 根据组织或项目的特定需求,在平台提供的模板基础上进行定制化开发,形成更符合自身场景的模板库。
  3. 代码审查: 对生成代码进行审查是必要的,特别是涉及安全、性能和复杂业务逻辑的部分。
  4. 版本控制: 将生成的代码纳入版本控制系统管理
  5. 区分生成与自定义:清晰界定哪些文件是生成的(通常不应手动修改,修改会被后续生成覆盖),哪些是自定义扩展的文件。平台通常提供机制(如生成到特定目录、文件头注释)来标记生成文件。对于需要自定义扩展的生成类,应优先考虑继承或组合的方式,而不是直接修改生成的文件本身。
  6. 结合低代码: 对于非常简单的CRUD模块或配置,可考虑使用平台的零/低代码功能直接配置完成,无需生成代码;代码生成更适用于需要深度定制或复杂逻辑的场景。

云原生应用研究院版权所有