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