crud-development
SKILL.md
CRUD 开发指南
通用模板。如果项目有专属技能(如
leniu-crud),优先使用。
核心规范
三层架构
| 层 | 职责 | 命名示例 |
|---|---|---|
| Controller | 接收请求、参数校验、路由分发 | OrderController |
| Service | 业务逻辑、事务管理 | OrderService / OrderServiceImpl |
| Mapper | 数据访问(ORM 映射) | OrderMapper |
标准包结构
[你的包名]/
├── controller/ # 控制器
├── service/
│ └── impl/ # 服务实现
├── mapper/ # 数据访问层
├── entity/ # 实体类
├── dto/ # 请求参数对象
├── vo/ # 响应视图对象
├── enums/ # 枚举常量
└── config/ # 模块配置
代码示例
1. Entity(实体类)
package [你的包名].entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("t_order")
public class Order {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String orderNo;
private Integer status;
private Long amount;
@TableField(fill = FieldFill.INSERT)
private String createBy;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private String updateBy;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableLogic(value = "0", delval = "1")
private Integer deleted;
}
2. DTO(请求参数)
package [你的包名].dto;
import jakarta.validation.constraints.*;
import lombok.Data;
@Data
public class OrderCreateDTO {
@NotBlank(message = "订单号不能为空")
private String orderNo;
@NotNull(message = "金额不能为空")
@Min(value = 1, message = "金额必须大于0")
private Long amount;
}
package [你的包名].dto;
import lombok.Data;
@Data
public class OrderQueryDTO {
private String orderNo;
private Integer status;
private Integer pageNum = 1;
private Integer pageSize = 10;
}
3. VO(响应对象)
package [你的包名].vo;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class OrderVO {
private Long id;
private String orderNo;
private Integer status;
private Long amount;
private LocalDateTime createTime;
}
4. Mapper
package [你的包名].mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import [你的包名].entity.Order;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface OrderMapper extends BaseMapper<Order> {
}
5. Service
package [你的包名].service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import [你的包名].entity.Order;
import [你的包名].dto.OrderCreateDTO;
import [你的包名].dto.OrderQueryDTO;
import [你的包名].vo.OrderVO;
public interface IOrderService extends IService<Order> {
Long createOrder(OrderCreateDTO dto);
void updateOrder(Long id, OrderCreateDTO dto);
OrderVO getOrderDetail(Long id);
Page<OrderVO> pageQuery(OrderQueryDTO query);
}
package [你的包名].service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import [你的包名].dto.OrderCreateDTO;
import [你的包名].dto.OrderQueryDTO;
import [你的包名].entity.Order;
import [你的包名].mapper.OrderMapper;
import [你的包名].service.IOrderService;
import [你的包名].vo.OrderVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
@Service
@RequiredArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {
@Override
@Transactional(rollbackFor = Exception.class)
public Long createOrder(OrderCreateDTO dto) {
Order order = new Order();
// 使用 [你的对象转换工具] 或手动赋值
order.setOrderNo(dto.getOrderNo());
order.setAmount(dto.getAmount());
order.setStatus(0);
this.save(order);
return order.getId();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateOrder(Long id, OrderCreateDTO dto) {
Order order = this.getById(id);
if (order == null) {
throw new [你的业务异常类]("订单不存在");
}
order.setOrderNo(dto.getOrderNo());
order.setAmount(dto.getAmount());
this.updateById(order);
}
@Override
public OrderVO getOrderDetail(Long id) {
Order order = this.getById(id);
if (order == null) {
throw new [你的业务异常类]("订单不存在");
}
OrderVO vo = new OrderVO();
// 使用 [你的对象转换工具] 或手动赋值
vo.setId(order.getId());
vo.setOrderNo(order.getOrderNo());
vo.setStatus(order.getStatus());
vo.setAmount(order.getAmount());
vo.setCreateTime(order.getCreateTime());
return vo;
}
@Override
public Page<OrderVO> pageQuery(OrderQueryDTO query) {
Page<Order> page = new Page<>(query.getPageNum(), query.getPageSize());
LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<Order>()
.like(StringUtils.hasText(query.getOrderNo()), Order::getOrderNo, query.getOrderNo())
.eq(query.getStatus() != null, Order::getStatus, query.getStatus())
.orderByDesc(Order::getCreateTime);
Page<Order> result = this.page(page, wrapper);
// 转换为 VO
Page<OrderVO> voPage = new Page<>(result.getCurrent(), result.getSize(), result.getTotal());
voPage.setRecords(result.getRecords().stream().map(order -> {
OrderVO vo = new OrderVO();
vo.setId(order.getId());
vo.setOrderNo(order.getOrderNo());
vo.setStatus(order.getStatus());
vo.setAmount(order.getAmount());
vo.setCreateTime(order.getCreateTime());
return vo;
}).toList());
return voPage;
}
}
6. Controller
package [你的包名].controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import [你的包名].dto.OrderCreateDTO;
import [你的包名].dto.OrderQueryDTO;
import [你的包名].service.IOrderService;
import [你的包名].vo.OrderVO;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/v1/orders")
@RequiredArgsConstructor
public class OrderController {
private final IOrderService orderService;
@PostMapping
public ResponseEntity<Long> create(@Valid @RequestBody OrderCreateDTO dto) {
return ResponseEntity.ok(orderService.createOrder(dto));
}
@PutMapping("/{id}")
public ResponseEntity<Void> update(@PathVariable Long id,
@Valid @RequestBody OrderCreateDTO dto) {
orderService.updateOrder(id, dto);
return ResponseEntity.ok().build();
}
@GetMapping("/{id}")
public ResponseEntity<OrderVO> detail(@PathVariable Long id) {
return ResponseEntity.ok(orderService.getOrderDetail(id));
}
@GetMapping
public ResponseEntity<Page<OrderVO>> page(OrderQueryDTO query) {
return ResponseEntity.ok(orderService.pageQuery(query));
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
orderService.removeById(id);
return ResponseEntity.ok().build();
}
}
常见错误
| 错误 | 正确做法 |
|---|---|
| Controller 里写业务逻辑 | 业务逻辑放 Service 层 |
| 直接返回 Entity 给前端 | 使用 VO 封装响应数据 |
| 用 Map 传递业务数据 | 使用 DTO/VO 强类型对象 |
忘记加 @Transactional |
写操作方法加事务注解 |
| 逻辑删除字段值搞反 | 确认项目约定(通用:0=正常, 1=删除) |
| 分页参数未设默认值 | DTO 中给 pageNum/pageSize 默认值 |
| Service 之间循环依赖 | 提取公共 Service 或使用事件机制解耦 |
Weekly Installs
4
Repository
xu-cell/ai-engi…ing-initGitHub Stars
8
First Seen
7 days ago
Security Audits
Installed on
gemini-cli4
github-copilot4
codex4
kimi-cli4
cursor4
amp4