基于现有的告警列表查询接口,在返回 x_alarm 表所有数据的同时,根据 devid 关联 x_devicename 表,补充返回设备名称和设备安装地址这两个字段,并且保留原有的分页和条件查询功能。
实现思路
- 数据关联 :通过
devid将x_alarm和x_devicename表关联,查询时补充设备名称、地址字段; - DTO 封装:创建一个包含告警信息 + 设备信息的 DTO 类,用于接收关联查询结果;
- 修改查询逻辑:替换原有的单表分页查询,改为自定义 SQL 关联查询,保留分页和条件过滤;
- 结果封装:将查询结果封装成前端需要的格式(总数 + 分页数据)。
完整实现代码
步骤 1:创建告警扩展 DTO 类(包含设备信息)
import lombok.Data;
import java.util.Date;
/**
* 告警信息扩展DTO(包含设备名称和地址)
*/
@Data
public class AlarmExtDTO {
// 告警表原有字段
private Integer uid;
private String devid;
private String alarmtype;
private Date alarmtime;
private String operation;
private Date operationtime;
private String operusername;
// 关联设备表的字段
private String devname; // 设备名称
private String devaddress; // 设备安装地址
}
步骤 2:修改 Mapper 层(自定义关联分页查询)
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
public interface AlarmMapper {
/**
* 关联查询告警+设备信息(带分页和条件)
*/
@Select("SELECT " +
"a.uid, a.devid, a.alarmtype, a.alarmtime, a.operation, " +
"a.operationtime, a.operusername, " +
"b.devname, b.devaddress " +
"FROM x_alarm a " +
"LEFT JOIN x_devicename b ON a.devid = b.devid " + // 左连接:保证无设备信息的告警也能查询到
"${ew.customSqlSegment}") // 用于拼接MyBatis-Plus的条件
IPage<AlarmExtDTO> selectAlarmWithDevice(Page<AlarmExtDTO> page,
@Param(Constants.WRAPPER) Wrapper<Alarm> wrapper);
}
步骤 3:修改 Service 层(可选,封装业务逻辑)
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 org.springframework.stereotype.Service;
@Service
public class AlarmServiceImpl extends ServiceImpl<AlarmMapper, Alarm> implements AlarmService {
@Override
public Page<AlarmExtDTO> getAlarmWithDevicePage(Page<AlarmExtDTO> page,
String devid, String alarmtype) {
LambdaQueryWrapper<Alarm> wrapper = new LambdaQueryWrapper<>();
// 保留原有条件过滤
wrapper.like(StringUtils.hasLength(devid), Alarm::getDevid, devid);
wrapper.like(StringUtils.hasLength(alarmtype), Alarm::getAlarmtype, alarmtype);
// 执行关联分页查询
return baseMapper.selectAlarmWithDevice(page, wrapper);
}
}
// 对应的Service接口
public interface AlarmService extends IService<Alarm> {
Page<AlarmExtDTO> getAlarmWithDevicePage(Page<AlarmExtDTO> page, String devid, String alarmtype);
}
步骤 4:修改 Controller 层(最终接口)
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import java.util.HashMap;
@RestController
public class AlarmController {
private final AlarmService alarmService;
// 构造器注入
public AlarmController(AlarmService alarmService) {
this.alarmService = alarmService;
}
@GetMapping("/alarm/list")
public Result<Map<String, Object>> getalarmList(
@RequestParam(value = "devid", required = false) String devid,
@RequestParam(value = "alarmtype", required = false) String alarmtype,
@RequestParam(value = "pageNo") Long pageNo,
@RequestParam(value = "pageSize") Long pageSize) {
// 构建分页对象
Page<AlarmExtDTO> page = new Page<>(pageNo, pageSize);
// 调用关联查询方法
Page<AlarmExtDTO> resultPage = alarmService.getAlarmWithDevicePage(page, devid, alarmtype);
// 封装返回结果(保持原有格式)
HashMap<String, Object> data = new HashMap<>();
data.put("total", resultPage.getTotal()); // 总条数
data.put("rows", resultPage.getRecords()); // 分页数据(包含设备名称/地址)
return Result.success(data);
}
}
关键说明
- 表关联方式 :使用
LEFT JOIN(左连接)而非内连接,确保即使x_devicename中没有对应devid的记录,告警数据也能正常返回(设备名称 / 地址为 null); - 条件复用 :通过
${ew.customSqlSegment}复用 MyBatis-Plus 的LambdaQueryWrapper条件,无需手动拼接 where 语句,保留原有的devid、alarmtype模糊查询; - DTO 设计 :新增
AlarmExtDTO专门用于接收关联查询结果,避免修改原有Alarm实体类,符合 "单一职责" 原则; - 分页兼容:完全保留原有的分页参数(pageNo/pageSize)和返回格式(total/rows),前端无需修改。
测试示例
假设数据库中有以下数据:
- x_alarm:devid = "DEV001",alarmtype = "故障告警"
- x_devicename:devid = "DEV001",devname = "温湿度传感器",devaddress = "一号厂房 3 楼"
调用接口:/alarm/list?devid=DEV001&pageNo=1&pageSize=10
总结
- 核心改动是通过 LEFT JOIN 关联两张表,并新增 DTO 接收扩展字段;
- 复用 MyBatis-Plus 的条件构造器和分页插件,保留原有查询条件和分页逻辑;
- 接口返回格式不变,仅在
rows数组中新增devname和devaddress字段,前端可直接使用。
创建位置规范(遵循 Java 项目最佳实践)
在 Spring Boot/Spring MVC 项目中,DTO(数据传输对象)类的创建位置有固定的规范,通常遵循以下目录结构:
plaintext
src/main/java/
└── com/你的项目包名/ # 根包(比如 com.company.project)
├── controller/ # 控制器(已有)
├── service/ # 服务层(已有)
├── mapper/ # Mapper层(已有)
├── entity/ # 数据库实体类(对应x_alarm、x_devicename的实体,已有)
└── dto/ # 新增:专门存放DTO类的目录
└── alarm/ # 可选:按业务模块细分(比如告警模块)
└── AlarmExtDTO.java # 你的告警扩展DTO类
二、IDEA 中具体创建步骤
步骤 1:定位并创建 dto 目录
- 在 IDEA 的「Project」面板中,展开
src/main/java→ 展开你的项目根包(比如com.xxx.project); - 右键点击根包 → 选择
New→Package; - 输入包名
dto(如果想按模块细分,可输入dto.alarm)→ 回车确认。
步骤 2:创建 AlarmExtDTO 类
- 右键点击刚创建的
dto(或dto.alarm)包 → 选择New→Java Class; - 在弹出的输入框中输入类名
AlarmExtDTO→ 回车; - 把之前提供的 DTO 代码复制到这个类文件中,补充对应的包名(IDEA 会自动提示补全)。