学习进度条

今日所花时间:一小时
今日代码量:100行
博客量:一篇
了解到的知识点:
巡检工单管理系统的开发与实现

项目概述

巡检工单管理系统主要用于管理设备巡检任务,包括工单的创建、查询、修改和删除等基本CRUD操作,以及根据各种条件筛选工单的高级功能。

技术架构

1. Spring Boot框架

项目基于Spring Boot构建,这是一个流行的Java企业级应用开发框架,大大简化了Spring应用的初始搭建和开发过程。

@RestController
@RequestMapping("/api/inspection-orders/")
@CrossOrigin(origins = "http://localhost:5173")
public class InspectionOrderController {
    // 控制器方法...
}
  • @RestController: 组合了@Controller@ResponseBody,表示这是一个RESTful风格的控制器
  • @RequestMapping: 定义控制器的基础路径
  • @CrossOrigin: 处理跨域请求,允许前端应用访问API

2. MyBatis持久层框架

MyBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。

@Mapper
public interface InspectionOrderMapper {
    @Insert("INSERT INTO inspection_order (order_code, plan_id, device_id, assignee_id, start_time, end_time, " +
            "status, device_status, result_desc) " +
            "VALUES (#{orderCode}, #{planId}, #{deviceId}, #{assigneeId}, #{startTime}, #{endTime}, " +
            "#{status}, #{deviceStatus}, #{resultDesc})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insert(InspectionOrder inspectionOrder);
    
    // 其他SQL操作方法...
}
  • @Mapper: 标识这是一个MyBatis的Mapper接口
  • @Insert/@Delete/@Update/@Select: 定义基本的CRUD操作
  • @Options: 配置主键自动生成并回填到实体对象

3. 动态SQL构建

对于复杂的查询条件,我使用了MyBatis的@SelectProvider注解实现动态SQL构建:

@SelectProvider(type = InspectionOrderSqlProvider.class, method = "selectByCondition")
List<InspectionOrder> selectByCondition(
        @Param("orderCode") String orderCode,
        @Param("planId") Long planId,
        @Param("deviceId") Long deviceId,
        @Param("assigneeId") Long assigneeId,
        @Param("status") Integer status,
        @Param("deviceStatus") String deviceStatus,
        @Param("offset") int offset,
        @Param("pageSize") int pageSize);

对应的SQL提供类:

class InspectionOrderSqlProvider {
    public String selectByCondition(
            @Param("orderCode") String orderCode,
            @Param("planId") Long planId,
            @Param("deviceId") Long deviceId,
            @Param("assigneeId") Long assigneeId,
            @Param("status") Integer status,
            @Param("deviceStatus") String deviceStatus,
            @Param("offset") int offset,
            @Param("pageSize") int pageSize) {
        return new SQL() {{
            SELECT("*");
            FROM("inspection_order");
            if (orderCode != null && !orderCode.isEmpty()) {
                WHERE("order_code LIKE CONCAT('%', #{orderCode}, '%')");
            }
            if (planId != null) {
                WHERE("plan_id = #{planId}");
            }
            // 其他条件...
            ORDER_BY("id DESC");
        }}.toString() + " LIMIT #{offset}, #{pageSize}";
    }
}

这种方法可以根据传入参数动态构建SQL语句,非常灵活。

4. 分页查询实现

我实现了一个通用的分页查询方法:

default PageBean<InspectionOrder> getInspectionOrders(Integer pageNum, Integer pageSize,
                                                      String orderCode, Long planId, Long deviceId,
                                                      Long assigneeId, Integer status, String deviceStatus) {
    PageBean<InspectionOrder> pb = new PageBean<>();
    
    int offset = (pageNum - 1) * pageSize;
    List<InspectionOrder> inspectionOrders = selectByCondition(orderCode, planId, deviceId, assigneeId,
            status, deviceStatus, offset, pageSize);
    pb.setItems(inspectionOrders);
    
    long total = countByCondition(orderCode, planId, deviceId, assigneeId, status, deviceStatus);
    pb.setTotal(total);
    
    return pb;
}

5. 实体类设计

使用JPA注解定义了巡检工单的实体类:

@Entity
@Table(name = "inspection_order", indexes = {
        @Index(name = "idx_plan_id", columnList = "plan_id"),
        @Index(name = "idx_device_id", columnList = "device_id"),
        @Index(name = "idx_status", columnList = "status")
})
public class InspectionOrder {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "order_code", length = 64, nullable = false)
    private String orderCode;
    
    // 其他字段...
}
  • @Entity: 标识这是一个JPA实体类
  • @Table: 指定对应的数据库表名和索引
  • @Id@GeneratedValue: 定义主键及其生成策略
  • @Column: 定义字段属性如长度、是否可为空等

6. 事务管理

在添加工单的方法上使用了@Transactional注解确保操作的原子性:

@PostMapping
@Transactional
public Result<InspectionOrder> addInspectionOrder(@RequestBody InspectionOrder inspectionOrder) {
    try {
        if (inspectionOrder.getOrderCode() == null || inspectionOrder.getDeviceId() == null) {
            return Result.error("工单编号和设备ID不能为空");
        }
        
        int rowsInserted = inspectionOrderMapper.insert(inspectionOrder);
        if (rowsInserted > 0) {
            return Result.success(inspectionOrder);
        } else {
            return Result.error("添加工单失败");
        }
    } catch (Exception e) {
        e.printStackTrace();
        return Result.error("添加工单时发生异常: " + e.getMessage());
    }
}

学到的知识点

  1. RESTful API设计:掌握了如何设计符合RESTful风格的API,包括资源命名、HTTP方法使用和状态码返回。

  2. MyBatis高级特性:学习了MyBatis的动态SQL构建、结果映射和接口绑定等高级特性。

  3. 分页查询实现:理解了分页查询的原理和实现方式,包括计算偏移量和总数统计。

  4. 事务管理:了解了Spring的事务管理机制和@Transactional注解的使用。

  5. 异常处理:学会了在控制器中统一处理异常并返回友好的错误信息。

  6. 跨域处理:掌握了通过@CrossOrigin注解解决前端跨域问题的方法。

  7. JPA实体映射:深入理解了如何通过JPA注解将Java对象映射到数据库表。

总结

通过这个模块的开发,我不仅巩固了Spring Boot和MyBatis的基础知识,还学习了许多高级特性和最佳实践。特别是动态SQL构建和分页查询的实现,让我对复杂查询场景有了更深的理解。这些经验对我未来的项目开发将有很大帮助。

posted @ 2025-05-20 19:44  haoyinuo  阅读(8)  评论(0)    收藏  举报