--- name: ruoyi-vue-plus-code-patterns description: | 基于若依-vue-plus框架的全栈代码规范指南。定义后端Java Spring Boot与前端Vue3 + TypeScript的标准化编码模式。 核心内容: - 后端分层架构规范:Controller/Service/Mapper三层设计,对象流转模式(Bo/DTO → Entity → Vo) - 前端Vue3组合式API规范: ``` **组件封装示例(子组件):** ```vue ``` **使用子组件示例:** ```vue ``` ### 规范3:MyBatis-Plus 使用规范 **核心原则:** - 优先使用 MyBatis-Plus 提供的 CRUD 方法,减少 XML 配置 - 复杂查询使用 LambdaQueryWrapper,避免字符串拼接 - 批量操作使用批处理方法,提升性能 - 自定义 SQL 放在 Mapper.xml 中,保持代码整洁 **常用查询方法:** ```java // 1. 基础查询 SysOrder order = orderMapper.selectById(orderId); List list = orderMapper.selectList(null); // 2. 条件查询(LambdaQueryWrapper - 类型安全) LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); wrapper.eq(SysOrder::getOrderNo, "ORD123") // 等于 .like(SysOrder::getCustomerName, "张三") // 模糊查询 .between(SysOrder::getAmount, 100, 1000) // 区间查询 .in(SysOrder::getStatus, Arrays.asList(1, 2)) // IN 查询 .isNotNull(SysOrder::getCreateTime) // 非空判断 .orderByDesc(SysOrder::getCreateTime); // 排序 List orders = orderMapper.selectList(wrapper); // 3. 动态条件查询(根据条件拼接) wrapper.like(StringUtils.isNotBlank(orderNo), SysOrder::getOrderNo, orderNo) .eq(status != null, SysOrder::getStatus, status) .ge(beginTime != null, SysOrder::getCreateTime, beginTime) .le(endTime != null, SysOrder::getCreateTime, endTime); // 4. 分页查询 Page page = new Page<>(pageNum, pageSize); IPage result = orderMapper.selectPage(page, wrapper); // 5. 只查询特定字段(select) wrapper.select(SysOrder::getOrderId, SysOrder::getOrderNo, SysOrder::getAmount); // 6. 统计查询 Long count = orderMapper.selectCount(wrapper); ``` **增删改操作:** ```java // 1. 新增 SysOrder order = new SysOrder(); order.setOrderNo("ORD123"); order.setAmount(new BigDecimal("999.99")); orderMapper.insert(order); // 返回影响行数,主键会自动回填到 order 对象 // 2. 修改(根据ID) order.setStatus(2); orderMapper.updateById(order); // 只更新非null字段 // 3. 条件修改 LambdaUpdateWrapper updateWrapper = Wrappers.lambdaUpdate(); updateWrapper.set(SysOrder::getStatus, 2) .eq(SysOrder::getOrderNo, "ORD123"); orderMapper.update(null, updateWrapper); // 4. 删除(根据ID) orderMapper.deleteById(orderId); // 5. 批量删除 orderMapper.deleteBatchIds(Arrays.asList(1L, 2L, 3L)); // 6. 条件删除 LambdaQueryWrapper deleteWrapper = Wrappers.lambdaQuery(); deleteWrapper.eq(SysOrder::getStatus, 0); orderMapper.delete(deleteWrapper); ``` **批量操作(高性能):** ```java // 批量插入(推荐使用 Service 的批量方法) List orderList = new ArrayList<>(); // ... 填充数据 orderService.saveBatch(orderList); // 默认批次大小 1000 // 批量更新 orderService.updateBatchById(orderList); // 自定义批次大小 orderService.saveBatch(orderList, 500); // 每批 500 条 ``` **自定义 SQL(Mapper.xml):** ```xml INSERT INTO sys_order (order_no, amount, status, create_time) VALUES (#{item.orderNo}, #{item.amount}, #{item.status}, #{item.createTime}) ``` **Mapper 接口定义:** ```java @Mapper public interface SysOrderMapper extends BaseMapper { /** * 查询订单及关联商品信息 */ List selectOrderWithProducts(@Param("orderNo") String orderNo); /** * 批量插入订单 */ int insertBatch(@Param("list") List orderList); } ``` ### 规范4:事务管理规范 **事务注解使用:** ```java @Service public class SysOrderServiceImpl implements ISysOrderService { /** * 事务方法(标准写法) * rollbackFor: 指定哪些异常触发回滚(必须指定 Exception.class) */ @Override @Transactional(rollbackFor = Exception.class) public boolean createOrder(SysOrderBo bo) { // 1. 插入订单主表 SysOrder order = BeanUtil.copyProperties(bo, SysOrder.class); orderMapper.insert(order); // 2. 插入订单明细 List details = bo.getDetails(); for (OrderDetail detail : details) { detail.setOrderId(order.getOrderId()); orderDetailMapper.insert(detail); } // 3. 扣减库存 for (OrderDetail detail : details) { productService.reduceStock(detail.getProductId(), detail.getQuantity()); } // 如果任何步骤抛出异常,所有操作都会回滚 return true; } /** * 只读事务(查询优化) */ @Override @Transactional(readOnly = true) public List selectOrderList(SysOrderBo bo) { // 只读事务可以提升查询性能 return orderMapper.selectOrderList(bo); } } ``` **事务传播行为:** ```java // REQUIRED(默认):如果当前存在事务则加入,否则新建事务 @Transactional(propagation = Propagation.REQUIRED) // REQUIRES_NEW:总是新建事务,挂起当前事务(用于日志记录) @Transactional(propagation = Propagation.REQUIRES_NEW) // NESTED:嵌套事务,子事务回滚不影响父事务 @Transactional(propagation = Propagation.NESTED) ``` ### 规范5:异常处理与日志规范 **统一异常处理:** ```java @Service public class SysOrderServiceImpl implements ISysOrderService { private static final Logger log = LoggerFactory.getLogger(SysOrderServiceImpl.class); @Override public boolean insertOrder(SysOrder order) { try { // 业务逻辑 orderMapper.insert(order); return true; } catch (DuplicateKeyException e) { // 捕获特定异常,抛出业务异常 log.error("订单号重复: {}", order.getOrderNo(), e); throw new ServiceException("订单号已存在"); } catch (Exception e) { // 记录日志 log.error("创建订单失败", e); throw new ServiceException("创建订单失败,请联系管理员"); } } } ``` **Controller 层异常处理(全局异常处理器已配置):** ```java @RestController public class SysOrderController { @PostMapping public AjaxResult add(@Validated @RequestBody SysOrderBo bo) { // 不需要 try-catch,全局异常处理器会统一处理 // 校验失败会自动返回 400 错误 // ServiceException 会自动返回友好的错误信息 return toAjax(orderService.insertOrder(order)); } } ``` **日志记录规范:** ```java // 1. 使用 Slf4j 注解(推荐) @Slf4j @Service public class SysOrderServiceImpl { public void processOrder(Long orderId) { log.debug("开始处理订单: {}", orderId); // 调试信息 log.info("订单处理成功: {}", orderId); // 一般信息 log.warn("订单库存不足: {}", orderId); // 警告信息 log.error("订单处理失败: {}", orderId, ex); // 错误信息(带异常堆栈) } } // 2. 使用操作日志注解(记录到数据库) @Log(title = "订单管理", businessType = BusinessType.INSERT) @PostMapping public AjaxResult add(@RequestBody SysOrderBo bo) { // 会自动记录操作人、操作时间、操作模块、请求参数等 return toAjax(orderService.insertOrder(order)); } ``` ### 规范6:参数校验规范 **DTO/Bo 对象校验:** ```java import javax.validation.constraints.*; public class SysOrderBo { /** 订单ID(修改时必填) */ @NotNull(message = "订单ID不能为空", groups = {EditGroup.class}) private Long orderId; /** 订单编号(必填,最长50字符) */ @NotBlank(message = "订单编号不能为空") @Size(max = 50, message = "订单编号长度不能超过50个字符") private String orderNo; /** 订单金额(必填,最小0.01,最大99999.99) */ @NotNull(message = "订单金额不能为空") @DecimalMin(value = "0.01", message = "订单金额必须大于0") @DecimalMax(value = "99999.99", message = "订单金额不能超过99999.99") private BigDecimal amount; /** 客户手机号(必填,手机号格式) */ @NotBlank(message = "手机号不能为空") @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确") private String phone; /** 邮箱(可选,邮箱格式) */ @Email(message = "邮箱格式不正确") private String email; /** 订单明细(至少1项) */ @NotEmpty(message = "订单明细不能为空") @Valid // 级联校验 private List details; } ``` **Controller 层校验:** ```java // 1. 使用 @Validated 触发校验 @PostMapping public AjaxResult add(@Validated @RequestBody SysOrderBo bo) { // 校验失败会自动返回 400 错误和错误信息 return toAjax(orderService.insertOrder(order)); } // 2. 分组校验(新增和修改使用不同的校验规则) @PostMapping public AjaxResult add(@Validated(AddGroup.class) @RequestBody SysOrderBo bo) { return toAjax(orderService.insertOrder(order)); } @PutMapping public AjaxResult edit(@Validated(EditGroup.class) @RequestBody SysOrderBo bo) { return toAjax(orderService.updateOrder(order)); } // 3. 路径参数校验 @GetMapping("/{orderId}") public AjaxResult getInfo(@PathVariable @Min(value = 1, message = "订单ID必须大于0") Long orderId) { return success(orderService.selectOrderById(orderId)); } ``` **自定义校验注解:** ```java // 自定义注解 @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = OrderStatusValidator.class) public @interface ValidOrderStatus { String message() default "订单状态值不合法"; Class[] groups() default {}; Class[] payload() default {}; } // 校验器实现 public class OrderStatusValidator implements ConstraintValidator { private static final Set VALID_STATUS = Set.of(0, 1, 2, 3, 4); @Override public boolean isValid(Integer value, ConstraintValidatorContext context) { if (value == null) { return true; // null 值由 @NotNull 校验 } return VALID_STATUS.contains(value); } } // 使用 public class SysOrderBo { @ValidOrderStatus(message = "订单状态只能是0-4之间的值") private Integer status; } ## 禁止事项 ### 后端开发禁止事项 1. **❌ 对象流转违规** - 禁止在Controller层直接返回数据库实体`Entity`,必须使用`Vo`进行数据裁剪 - 禁止Controller直接操作Mapper层,必须通过Service层处理业务逻辑 - 禁止在Entity中添加非数据库字段(应放在Vo中) - 禁止手写大量的setter/getter进行对象拷贝,必须使用`BeanUtil.copyProperties`或MapStruct 2. **❌ Service层违规** - 禁止在Service层中直接使用`HttpServletRequest`获取参数,必须通过Controller层传递 - 禁止在Service层返回`AjaxResult`,应返回业务对象或boolean - 禁止Service方法抛出不明确的`Exception`,应抛出`ServiceException`并附带友好错误信息 - 禁止在无事务方法中进行多表操作,必须添加`@Transactional`注解 3. **❌ MyBatis-Plus违规** - 禁止使用字符串拼接SQL(容易SQL注入),必须使用LambdaQueryWrapper - 禁止在循环中执行单条insert/update(性能低下),应使用批量方法 - 禁止直接使用`selectList(null)`查询全表(数据量大会OOM),必须添加分页或限制条件 - 禁止在Entity上使用`@TableField(exist = false)`定义过多非数据库字段 4. **❌ 事务管理违规** - 禁止忘记添加`rollbackFor = Exception.class`(默认只回滚RuntimeException) - 禁止在事务方法中捕获异常后不抛出(会导致事务不回滚) - 禁止在Controller层方法上添加`@Transactional`(应在Service层) - 禁止事务方法调用同类中的另一个事务方法(事务会失效,应使用AOP代理) 5. **❌ 异常处理违规** - 禁止捕获异常后只打印日志不处理(`e.printStackTrace()`或空catch块) - 禁止抛出Exception基类,应抛出具体异常(`ServiceException`、`BusinessException`等) - 禁止在finally块中使用return(会覆盖try块的返回值和异常) - 禁止使用`System.out.println`打印日志,必须使用Logger 6. **❌ 日志记录违规** - 禁止在生产代码中使用`System.out.println`,必须使用Slf4j - 禁止使用字符串拼接记录日志(`log.info("用户:" + username)`),应使用占位符(`log.info("用户: {}", username)`) - 禁止在高频调用的方法中使用`log.info`(应使用`log.debug`) - 禁止记录敏感信息(密码、身份证号、银行卡号等)到日志 7. **❌ 安全违规** - 禁止在Vo中返回密码、盐值等敏感字段 - 禁止在日志中打印完整的用户敏感信息 - 禁止在前端直接传递SQL语句或表名 - 禁止使用字符串拼接构造SQL(必须使用参数化查询) 8. **❌ 性能违规** - 禁止在循环中调用数据库(N+1查询问题) - 禁止查询大量数据不分页(应使用`PageHelper.startPage()`) - 禁止在MyBatis的`