---
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 extends Payload>[] 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的`