本文不仅记录租期、标签和配套,还延伸到基本属性、杂费、地区、图片上传与公寓信息管理。内容较长,可先按下列脉络定位,再阅读原始接口和代码笔记。
阅读脉络
基础资料 :租期、标签、配套、房间基本属性和公寓杂费,先确认各自的数据表与查询/维护接口。
地区与图片 :地区接口为公寓地址选择提供数据;上传接口使用 MinIO 保存图片,数据库中记录的是后续展示需要的关联信息。
公寓信息 :保存或更新时处理公寓本体及其图片、标签、配套等关联信息;分页列表与详情页再按不同需要组装结果。
状态与关联查询 :删除、发布状态修改、按区县查询公寓各有不同用途,不要把下架等同于删除。
下面保留原有的接口实现记录。由于文章跨越多个模块,调试时建议先验证基础资料,再验证公寓保存和详情,最后检查删除与发布状态的影响。
房间租期管理 1. 找到对应的数据库
2. 设计接口 接口1:查询全部租期列表 1 2 3 4 5 6 @GetMapping("list") @Operation(summary = "查询全部租期列表") public Result<List<LeaseTerm>> listLeaseTerm () { List<LeaseTerm> list = leaseTermService.list(); return Result.ok(list); }
接口2:保存或更新租期信息 1 2 3 4 5 6 7 8 9 10 @PostMapping("saveOrUpdate") @Operation(summary = "保存或更新租期信息") public Result saveOrUpdate (@RequestBody LeaseTerm leaseTerm) { boolean saveOrUpdate = leaseTermService.saveOrUpdate(leaseTerm); if (saveOrUpdate) { return Result.ok(); } else { return Result.fail(); } }
接口3:根据ID删除租期 1 2 3 4 5 6 7 8 9 10 @DeleteMapping("deleteById") @Operation(summary = "根据ID删除租期") public Result deleteLeaseTermById (@RequestParam Long id) { boolean remove = leaseTermService.removeById(id); if (remove) { return Result.ok(); } else { return Result.fail(); } }
标签管理 1. 找到对应的数据库
2. 设计接口 接口1:(根据类型)查询标签列表 1 2 3 4 5 6 7 8 @Operation(summary = "(根据类型)查询标签列表") @GetMapping("list") public Result<List<LabelInfo>> labelList (@RequestParam(required = false) ItemType type) { LambdaQueryWrapper<LabelInfo> queryWrapper = new LambdaQueryWrapper <>(); queryWrapper.eq(type != null , LabelInfo::getType, type); List<LabelInfo> list = labelInfoService.list(queryWrapper); return Result.ok(list); }
1 2026-07-04T19:30:48.558+08:00 WARN 20000 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'com.atguigu.lease.model.enums.ItemType'; Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.RequestParam com.atguigu.lease.model.enums.ItemType] for value '2']
原因:传递参数值为1或2,而方法需要美剧类型ItemType,1/2转换成枚举类型时出错
解决方法:
方式一:不使用枚举类型,使用String或Integer
方式二:编写转换器,将1/2转换成枚举类型
自定义转换器 解决:
前端传递 type 参数时,通过 SpringMVC 的 WebDataBinder 或 Converter ,将请求参数转换为对应的枚举类型。
数据库查询时,通过 MyBatis 的 TypeHandler ,将枚举对象中的 type 值转换为数据库字段值,从而拼接 SQL 条件进行查询。
代码实现:
定义转换器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Component public class StringToBaseEnumConverterFactory implements ConverterFactory <String, BaseEnum> { @Override public <T extends BaseEnum > Converter<String, T> getConverter (Class<T> targetType) { return new Converter <String, T>() { @Override public T convert (String code) { T[] enumConstants = targetType.getEnumConstants(); for (T enumConstant : enumConstants) { if (enumConstant.getCode().equals(Integer.valueOf(code))) { return enumConstant; } } throw new IllegalArgumentException ("参数非法" ); } }; } }
StringToBaseEnumConverterFactory 可以让所有“实现了 BaseEnum 接口的枚举类”都支持转换。
注册转换器:
1 2 3 4 5 6 7 8 9 10 11 @Configuration public class WebMvcConfiguration implements WebMvcConfigurer { @Autowired private StringToBaseEnumConverterFactory stringToBaseEnumConverterFactory; @Override public void addFormatters (FormatterRegistry registry) { registry.addConverterFactory(stringToBaseEnumConverterFactory); } }
ItemType枚举类
1 2 3 4 5 6 7 8 9 10 public enum ItemType implements BaseEnum { APARTMENT(1, "公寓"), ROOM(2, "房间"); @EnumValue @JsonValue private Integer code; private String name; ... }
@EnumValue注解:告诉 MyBatis-Plus,数据库里存这个枚举的 code 值。
@JsonValue注解:告诉 Spring Boot 返回 JSON 时,这个枚举用 code 表示。
接口2:新增或修改标签信息 1 2 3 4 5 6 7 8 9 10 @Operation(summary = "新增或修改标签信息") @PostMapping("saveOrUpdate") public Result saveOrUpdateLabel (@RequestBody LabelInfo labelInfo) { boolean saveOrUpdate = labelInfoService.saveOrUpdate(labelInfo); if (saveOrUpdate) { return Result.ok(); } else { return Result.fail(); } }
接口3:根据id删除标签信息 1 2 3 4 5 6 7 8 9 10 @Operation(summary = "根据id删除标签信息") @DeleteMapping("deleteById") public Result deleteLabelById (@RequestParam Long id) { boolean removeById = labelInfoService.removeById(id); if (removeById) { return Result.ok(); } else { return Result.fail(); } }
配套管理 1. 找到对应的数据库
2. 设计接口 接口1:[根据类型]查询配套信息列表 1 2 3 4 5 6 7 8 @Operation(summary = "[根据类型]查询配套信息列表") @GetMapping("list") public Result<List<FacilityInfo>> listFacility (@RequestParam(required = false) ItemType type) { LambdaQueryWrapper<FacilityInfo> queryWrapper = new LambdaQueryWrapper <>(); queryWrapper.eq(type != null , FacilityInfo::getType, type); List<FacilityInfo> list = facilityInfoService.list(queryWrapper); return Result.ok(list); }
接口2:新增或修改配套信息 1 2 3 4 5 6 7 8 9 10 @Operation(summary = "新增或修改配套信息") @PostMapping("saveOrUpdate") public Result saveOrUpdate (@RequestBody FacilityInfo facilityInfo) { boolean saveOrUpdate = facilityInfoService.saveOrUpdate(facilityInfo); if (saveOrUpdate) { return Result.ok(); } else { return Result.fail(); } }
接口3:根据id删除配套信息 1 2 3 4 5 6 7 8 9 10 @Operation(summary = "根据id删除配套信息") @DeleteMapping("deleteById") public Result removeFacilityById (@RequestParam Long id) { boolean removeById = facilityInfoService.removeById(id); if (removeById) { return Result.ok(); } else { return Result.fail(); } }
基本属性管理 
1. 找到对应的数据库
基本属性名称表attr_key
基本属性值表attr_value
2. 设计接口 *** 接口1:查询全部属性名称和属性值列表** 1. 拓展实体类
由于返回结果包含多张表数据,创建vo类型用于封装最终结果
1 2 3 4 5 6 @Data public class AttrKeyVo extends AttrKey { @Schema(description = "属性value列表") private List<AttrValue> attrValueList; }
1 2 3 4 5 6 7 @Schema(description = "属性值") @Data public class AttrValueVo extends AttrValue { @Schema(description = "对应的属性key_name") private String attrKeyName; }
2. Controller 1 2 3 4 5 6 @Operation(summary = "查询全部属性名称和属性值列表") @GetMapping("list") public Result<List<AttrKeyVo>> listAttrInfo () { List<AttrKeyVo> list = attrKeyService.listAttrInfo(); return Result.ok(list); }
3. Service 1 2 3 4 public interface AttrKeyService extends IService <AttrKey> { List<AttrKeyVo> listAttrInfo () ; }
4. ServiceImpl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Service public class AttrKeyServiceImpl extends ServiceImpl <AttrKeyMapper, AttrKey> implements AttrKeyService { @Autowired private AttrKeyMapper attrKeyMapper; @Override public List<AttrKeyVo> listAttrInfo () { List<AttrKeyVo> list = attrKeyMapper.listAttrInfo(); return list; } }
Mapper.java 1 2 3 4 5 6 @Mapper public interface AttrKeyMapper extends BaseMapper <AttrKey> { List<AttrKeyVo> listAttrInfo () ; }
Mapper.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <mapper namespace ="com.atguigu.lease.web.admin.mapper.AttrKeyMapper" > <resultMap id ="BaseResultMap" type ="com.atguigu.lease.web.admin.vo.attr.AttrKeyVo" > <id column ="id" property ="id" /> <result column ="key_name" property ="name" /> <collection property ="attrValueList" ofType ="com.atguigu.lease.model.entity.AttrValue" > <id column ="value_id" property ="id" /> <result column ="value_name" property ="name" /> <result column ="key_id" property ="attrKeyId" /> </collection > </resultMap > <select id ="listAttrInfo" resultMap ="BaseResultMap" > SELECT k.id, k.name key_name, v.id value_id, v.name value_name, v.attr_key_id key_id FROM attr_key k LEFT JOIN attr_value v ON k.id = v.attr_key_id </select > </mapper >
拓展
多领域模型介绍
POJO : POJO指的是普通的Java对象,没有任何特殊限制或要求,不依赖于特定的框架或接口。它通常用于表示简单的数据对象,只包含私有字段、对应的getter和setter方法以及一些业务逻辑。
Entity : Entity表示系统中具有独特身份的业务对象。它通常映射到数据库表中的记录,有唯一的标识符(ID)并包含与业务相关的数据和行为。
VO : VO(Value Object)是一种用于表示值的对象,通常是不可变的,只包含数据而没有业务行为。它用于封装一组相关的数据,常用于传递数据结构。
接口2:根据id删除属性值 1 2 3 4 5 6 7 8 9 10 @Operation(summary = "根据id删除属性值") @DeleteMapping("value/deleteById") public Result removeAttrValueById (@RequestParam Long id) { boolean remove = attrValueService.removeById(id); if (remove) { return Result.ok(); } else { return Result.fail(); } }
*** 接口3:根据id删除属性名称** 1 2 3 4 5 6 7 8 9 10 11 12 @Operation(summary = "根据id删除属性名称") @DeleteMapping("key/deleteById") public Result removeAttrKeyById (@RequestParam Long attrKeyId) { attrKeyService.removeById(attrKeyId); LambdaQueryWrapper<AttrValue> wrapper = new LambdaQueryWrapper <>(); wrapper.eq(AttrValue::getAttrKeyId, attrKeyId); attrValueService.remove(wrapper); return Result.ok(); }
接口4:新增或更新属性名称 1 2 3 4 5 6 @Operation(summary = "新增或更新属性名称") @PostMapping("key/saveOrUpdate") public Result saveOrUpdateAttrKey (@RequestBody AttrKey attrKey) { boolean saveOrUpdate = attrKeyService.saveOrUpdate(attrKey); return Result.ok(saveOrUpdate); }
接口5:新增或更新属性值 1 2 3 4 5 6 @Operation(summary = "新增或更新属性值") @PostMapping("value/saveOrUpdate") public Result saveOrUpdateAttrValue (@RequestBody AttrValue attrValue) { boolean saveOrUpdate = attrValueService.saveOrUpdate(attrValue); return Result.ok(saveOrUpdate); }
公寓杂费管理 同基本属性管理
1. 找到对应的数据库
杂费名称表fee_key
杂费值表fee_value
2. 设计接口 接口1:查询全部杂费名称和杂费值列表 1. 拓展实体类 1 2 3 4 5 6 @Data public class FeeKeyVo extends FeeKey { @Schema(description = "杂费value列表") private List<FeeValue> feeValueList; }
1 2 3 4 5 6 7 @Schema(description = "杂费值") @Data public class FeeValueVo extends FeeValue { @Schema(description = "费用所对的fee_key名称") private String feeKeyName; }
2. Controller 1 2 3 4 5 6 @Operation(summary = "查询全部杂费名称和杂费值列表") @GetMapping("list") public Result<List<FeeKeyVo>> feeInfoList () { List<FeeKeyVo> list = feeKeyService.listFeeInfo(); return Result.ok(list); }
3. Service 1 2 3 4 5 public interface FeeKeyService extends IService <FeeKey> { List<FeeKeyVo> listFeeInfo () ; }
4. ServiceImpl 1 2 3 4 5 6 7 8 9 10 11 12 13 @Service public class FeeKeyServiceImpl extends ServiceImpl <FeeKeyMapper, FeeKey> implements FeeKeyService { @Autowired private FeeKeyMapper feeKeyMapper; @Override public List<FeeKeyVo> listFeeInfo () { List<FeeKeyVo> list = feeKeyMapper.listFeeInfo(); return list; } }
5. Mapper.java 1 2 3 4 5 @Mapper public interface FeeKeyMapper extends BaseMapper <FeeKey> { List<FeeKeyVo> listFeeInfo () ; }
6. Mapper.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <mapper namespace ="com.atguigu.lease.web.admin.mapper.FeeKeyMapper" > <resultMap id ="BaseREsultMap" type ="com.atguigu.lease.web.admin.vo.fee.FeeKeyVo" > <id property ="id" column ="id" /> <result property ="name" column ="key_name" /> <collection property ="feeValueList" ofType ="com.atguigu.lease.model.entity.FeeValue" > <id property ="id" column ="value_id" /> <result property ="name" column ="value_name" /> <result property ="unit" column ="value_unit" /> <result property ="feeKeyId" column ="key_id" /> </collection > </resultMap > <select id ="listFeeInfo" resultMap ="BaseREsultMap" > SELECT k.id, k.name key_name, v.id value_id, v.unit value_unit, v.fee_key_id key_id FROM fee_key k left join fee_value v on k.id = v.fee_key_id </select > </mapper >
接口2:根据id删除杂费值 1 2 3 4 5 6 7 8 9 10 @Operation(summary = "根据id删除杂费值") @DeleteMapping("value/deleteById") public Result deleteFeeValueById (@RequestParam Long id) { boolean remove = feeValueService.removeById(id); if (remove) { return Result.ok(); } else { return Result.fail(); } }
接口3:根据id删除杂费名称 1 2 3 4 5 6 7 8 9 10 @Operation(summary = "根据id删除杂费名称") @DeleteMapping("key/deleteById") public Result deleteFeeKeyById (@RequestParam Long feeKeyId) { feeKeyService.removeById(feeKeyId); LambdaQueryWrapper<FeeValue> queryWrapper = new LambdaQueryWrapper <>(); queryWrapper.eq(FeeValue::getFeeKeyId, feeKeyId); feeValueService.remove(queryWrapper); return Result.ok(); }
接口4:保存或更新杂费名称 1 2 3 4 5 6 @Operation(summary = "保存或更新杂费名称") @PostMapping("key/saveOrUpdate") public Result saveOrUpdateFeeKey (@RequestBody FeeKey feeKey) { boolean saveOrUpdate = feeKeyService.saveOrUpdate(feeKey); return Result.ok(saveOrUpdate); }
接口5:保存或更新杂费值 1 2 3 4 5 6 @Operation(summary = "保存或更新杂费值") @PostMapping("value/saveOrUpdate") public Result saveOrUpdateFeeValue (@RequestBody FeeValue feeValue) { boolean saveOrUpdate = feeValueService.saveOrUpdate(feeValue); return Result.ok(saveOrUpdate); }
地区信息管理 1. 概述
实现省市区三级联动
对应数据库:
省信息表province_info
市信息表city_info
区信息表district_info
2. 设计接口 
接口1:查询所有省 1 2 3 4 5 6 @Operation(summary = "查询省份信息列表") @GetMapping("province/list") public Result<List<ProvinceInfo>> listProvince () { List<ProvinceInfo> list = provinceInfoService.list(); return Result.ok(list); }
接口2:查询省下的所有市 1 2 3 4 5 6 7 8 @Operation(summary = "根据省份id查询城市信息列表") @GetMapping("city/listByProvinceId") public Result<List<CityInfo>> listCityInfoByProvinceId (@RequestParam Long id) { LambdaQueryWrapper<CityInfo> wrapper = new LambdaQueryWrapper <>(); wrapper.eq(CityInfo::getProvinceId, id); List<CityInfo> list = cityInfoService.list(wrapper); return Result.ok(list); }
接口3:查询市下的所有区 1 2 3 4 5 6 7 8 @GetMapping("district/listByCityId") @Operation(summary = "根据城市id查询区县信息") public Result<List<DistrictInfo>> listDistrictInfoByCityId (@RequestParam Long id) { LambdaQueryWrapper<DistrictInfo> wrapper = new LambdaQueryWrapper <>(); wrapper.eq(DistrictInfo::getCityId, id); List<DistrictInfo> list = districtInfoService.list(wrapper); return Result.ok(list); }
导入图片 1. 引入依赖 1 2 3 4 <dependency > <groupId > io.minio</groupId > <artifactId > minio</artifactId > </dependency >
2. 添加配置信息 1 2 3 4 5 minio: endpoint: http://127.0.0.1:9000 accesskey: minioadmin secretkey: minioadmin bucketname: atguigu
3. 创建类读取配置文件内容 1 2 3 4 5 6 7 8 9 10 @ConfigurationProperties(prefix = "minio") @Data @Component public class MinioProperyties { private String endpoint; private String accesskey; private String secretkey; private String bucketname; }
4. 创建配置类将Minio交给Spring管理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @SpringBootConfiguration public class MinioConfiguration { @Autowired private MinioProperyties properyties; @Bean public MinioClient minioClient () { return MinioClient.builder() .endpoint("http://127.0.0.1:9000" ) .credentials("minioadmin" , "minioadmin" ) .build(); } }
5. 设计接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Tag(name = "文件管理") @RequestMapping("/admin/file") @RestController public class FileUploadController { @Autowired private FileService fileService; @Operation(summary = "上传文件") @PostMapping("upload") public Result<String> upload (@RequestParam MultipartFile file) { String url = fileService.upload(file); return Result.ok(url); } }
6. Service 7. ServiceImpl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 @Service public class FileServiceImpl implements FileService { @Autowired private MinioClient client; @Autowired private MinioProperyties properties; @Override public String upload (MultipartFile file) { try { boolean bucketExists = client.bucketExists(BucketExistsArgs.builder() .bucket(properties.getBucketname()) .build()); if (!bucketExists) { client.makeBucket(MakeBucketArgs.builder() .bucket(properties.getBucketname()) .build()); client.setBucketPolicy(SetBucketPolicyArgs.builder() .bucket(properties.getBucketname()) .config(createBucketPolicyConfig(properties.getBucketname())) .build()); } String filename = new SimpleDateFormat ("yyyyMMdd" ).format(new Date ()) + "/" + UUID.randomUUID() + "-" + file.getOriginalFilename(); client.putObject(PutObjectArgs.builder(). bucket(properties.getBucketname()). object(filename). stream(file.getInputStream(), file.getSize(), -1 ). contentType(file.getContentType()).build()); return String.join("/" , properties.getEndpoint(), properties.getBucketname(), filename); } catch (Exception e) { e.printStackTrace(); } return null ; } private String createBucketPolicyConfig (String bucketName) { return """ { "Statement" : [ { "Action" : "s3:GetObject", "Effect" : "Allow", "Principal" : "*", "Resource" : "arn:aws:s3:::%s/*" } ], "Version" : "2012-10-17" } """ .formatted(bucketName); } }
文件上传大小 1 2 3 4 spring: servlet: max-file-size: 100MB max-request-size: 150MB
统一异常处理 问题演示
添加GlobalExceptionHandler
1 2 3 4 5 6 7 8 9 10 @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) @ResponseBody public Result error (Exception e) { e.printStackTrace(); return Result.fail(); } }
公寓管理 1. 数据库表
apartment_info:公寓基本信息表
apartment_facility:公寓配置信息数据表
apartment_label:公寓标签数据
apartment_fee_value:公寓杂费管理
graph_info:图片表
2. 设计接口 接口1:保存或更新公寓信息 1. 拓展实体类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Schema(description = "公寓信息") @Data public class ApartmentSubmitVo extends ApartmentInfo { @Schema(description="公寓配套id") private List<Long> facilityInfoIds; @Schema(description="公寓标签id") private List<Long> labelIds; @Schema(description="公寓杂费值id") private List<Long> feeValueIds; @Schema(description="公寓图片id") private List<GraphVo> graphVoList; }
2. Controller 1 2 3 4 5 6 @Operation(summary = "保存或更新公寓信息") @PostMapping("saveOrUpdate") public Result saveOrUpdate (@RequestBody ApartmentSubmitVo apartmentSubmitVo) { apartmentInfoService.saveOrUpdateApartment(apartmentSubmitVo); return Result.ok(); }
Service 1 2 3 4 5 public interface ApartmentInfoService extends IService <ApartmentInfo> { void saveOrUpdateApartment (ApartmentSubmitVo apartmentSubmitVo) ; }
ServiceImpl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 @Service public class ApartmentInfoServiceImpl extends ServiceImpl <ApartmentInfoMapper, ApartmentInfo> implements ApartmentInfoService { @Autowired private ApartmentFacilityService apartmentFacilityService; @Autowired private ApartmentLabelService apartmentLabelService; @Autowired private ApartmentFeeValueService apartmentFeeValueService; @Autowired private GraphInfoService graphInfoService; @Override public void saveOrUpdateApartment (ApartmentSubmitVo apartmentSubmitVo) { boolean isUpdate = apartmentSubmitVo.getId() != null ; this .saveOrUpdate(apartmentSubmitVo); if (isUpdate) { LambdaQueryWrapper<ApartmentFacility> wrapper = new LambdaQueryWrapper <>(); wrapper.eq(ApartmentFacility::getApartmentId, apartmentSubmitVo.getId()); apartmentFacilityService.remove(wrapper); LambdaQueryWrapper<ApartmentLabel> labelWrapper = new LambdaQueryWrapper <>(); labelWrapper.eq(ApartmentLabel::getApartmentId, apartmentSubmitVo.getId()); apartmentLabelService.remove(labelWrapper); LambdaQueryWrapper<ApartmentFeeValue> feeWrapper = new LambdaQueryWrapper <>(); feeWrapper.eq(ApartmentFeeValue::getApartmentId, apartmentSubmitVo.getId()); apartmentFeeValueService.remove(feeWrapper); LambdaQueryWrapper<GraphInfo> graphWrapper = new LambdaQueryWrapper <>(); graphWrapper.eq(GraphInfo::getItemId, apartmentSubmitVo.getId()); graphWrapper.eq(GraphInfo::getItemType, ItemType.APARTMENT); graphInfoService.remove(graphWrapper); } List<Long> facilityInfoIds = apartmentSubmitVo.getFacilityInfoIds(); if (facilityInfoIds != null && !facilityInfoIds.isEmpty()) { ArrayList<ApartmentFacility> afList = new ArrayList <>(); for (Long fid : facilityInfoIds) { ApartmentFacility apartmentFacility = new ApartmentFacility (); apartmentFacility.setFacilityId(fid); apartmentFacility.setApartmentId(apartmentSubmitVo.getId()); afList.add(apartmentFacility); } apartmentFacilityService.saveBatch(afList); } List<Long> labelIds = apartmentSubmitVo.getLabelIds(); if (labelIds != null && !labelIds.isEmpty()) { ArrayList<ApartmentLabel> apartmentLabelList = new ArrayList <>(); for (Long labelId : labelIds) { ApartmentLabel apartmentLabel = new ApartmentLabel (); apartmentLabel.setLabelId(labelId); apartmentLabel.setApartmentId(apartmentSubmitVo.getId()); apartmentLabelList.add(apartmentLabel); } apartmentLabelService.saveBatch(apartmentLabelList); } List<Long> feeValueIds = apartmentSubmitVo.getFeeValueIds(); if (feeValueIds != null && !feeValueIds.isEmpty()) { ArrayList<ApartmentFeeValue> feeValueList = new ArrayList <>(); for (Long feeValueId : feeValueIds) { ApartmentFeeValue apartmentFeeValue = new ApartmentFeeValue (); apartmentFeeValue.setFeeValueId(feeValueId); apartmentFeeValue.setApartmentId(apartmentSubmitVo.getId()); feeValueList.add(apartmentFeeValue); } apartmentFeeValueService.saveBatch(feeValueList); } List<GraphVo> graphVoList = apartmentSubmitVo.getGraphVoList(); if (graphVoList != null && !graphVoList.isEmpty()) { ArrayList<GraphInfo> graphVoArrayList = new ArrayList <>(); for (GraphVo graphVo : graphVoList) { GraphInfo graphInfo = new GraphInfo (); graphInfo.setName(graphVo.getName()); graphInfo.setItemId(apartmentSubmitVo.getId()); graphInfo.setItemType(ItemType.APARTMENT); graphInfo.setUrl(graphVo.getUrl()); graphVoArrayList.add(graphInfo); } graphInfoService.saveBatch(graphVoArrayList); } }
接口2:根据条件分页查询公寓列表 1. 配置分页插件 1 2 3 4 5 6 7 8 9 10 @Configuration @MapperScan("com.atguigu.lease.web.*.mapper") public class MybatisPlusConfiguration { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor () { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor (); interceptor.addInnerInterceptor(new PaginationInnerInterceptor ()); return interceptor; } }
2. Controller 1 2 3 4 5 6 7 8 @Operation(summary = "根据条件分页查询公寓列表") @GetMapping("pageItem") public Result<IPage<ApartmentItemVo>> pageItem (@RequestParam long current, @RequestParam long size, ApartmentQueryVo queryVo) { Page<ApartmentItemVo> page = new Page <>(current, size); IPage<ApartmentItemVo> pageModel = apartmentInfoService.selectApartmentInfoPage(page, queryVo); return Result.ok(pageModel); }
3. Service 1 IPage<ApartmentItemVo> selectApartmentInfoPage (@Param("page") Page<ApartmentItemVo> page, @Param("queryVo") ApartmentQueryVo queryVo) ;
4. ServiceImpl 1 2 3 4 @Override public IPage<ApartmentItemVo> selectApartmentInfoPage (Page<ApartmentItemVo> page, ApartmentQueryVo queryVo) { return apartmentInfoMapper.selectApartmentInfoPage(page, queryVo); }
5. Mapper 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 <mapper namespace ="com.atguigu.lease.web.admin.mapper.ApartmentInfoMapper" > <select id ="selectApartmentInfoPage" resultType ="com.atguigu.lease.web.admin.vo.apartment.ApartmentItemVo" > select ai.id, ai.name, ai.introduction, ai.district_id, ai.district_name, ai.city_id, ai.city_name, ai.province_id, ai.province_name, ai.address_detail, ai.latitude, ai.longitude, ai.phone, ai.is_release, ifnull(tc.cnt,0) total_room_count, ifnull(tc.cnt,0) - ifnull(cc.cnt,0) free_room_count from (select id, name, introduction, district_id, district_name, city_id, city_name, province_id, province_name, address_detail, latitude, longitude, phone, is_release from apartment_info <where > is_deleted=0 <if test ="queryVo.provinceId != null" > and province_id=#{queryVo.provinceId} </if > <if test ="queryVo.cityId != null" > and city_id=#{queryVo.cityId} </if > <if test ="queryVo.districtId != null" > and district_id=#{queryVo.districtId} </if > </where > ) ai left join (select apartment_id, count(*) cnt from room_info where is_deleted = 0 and is_release = 1 group by apartment_id) tc on ai.id = tc.apartment_id left join (select apartment_id, count(*) cnt from lease_agreement where is_deleted = 0 and status in (2, 5) group by apartment_id) cc on ai.id = cc.apartment_id </select > </mapper >
测试时开启参数功能
1 2 springdoc: default-flat-param-object: true
接口3:根据ID获取公寓详细信息 Controller 1 2 3 4 5 6 @Operation(summary = "根据ID获取公寓详细信息") @GetMapping("getDetailById") public Result<ApartmentDetailVo> getDetailById (@RequestParam Long id) { ApartmentDetailVo apartmentDetailVo = apartmentInfoService.getDetailById(id); return Result.ok(apartmentDetailVo); }
Service 1 2 3 4 5 6 7 8 9 public interface ApartmentInfoService extends IService <ApartmentInfo> { void saveOrUpdateApartment (ApartmentSubmitVo apartmentSubmitVo) ; ApartmentDetailVo getDetailById (Long id) ; }
ServiceImpl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 @Autowired private FacilityInfoMapper facilityInfoMapper;@Autowired private LabelInfoMapper labelInfoMapper;@Autowired private FeeValueMapper feeValueMapper;@Autowired private GraphInfoMapper graphInfoMapper;@Override public ApartmentDetailVo getDetailById (Long id) { ApartmentInfo apartmentInfo = this .getById(id); if (apartmentInfo == null ) { return null ; } List<FacilityInfo> facilityInfoList = facilityInfoMapper.findFacilityListByApartmentId(id); List<LabelInfo> labelInfoList = labelInfoMapper.findLabelListByApartmentId(id); List<FeeValueVo> feeValueVoList = feeValueMapper.findFeeValueListByApartmentId(id); List<GraphVo> graphVoList = graphInfoMapper.findGraphListByApartmentId(ItemType.APARTMENT, id); ApartmentDetailVo apartmentDetailVo = new ApartmentDetailVo (); BeanUtils.copyProperties(apartmentInfo, apartmentDetailVo); apartmentDetailVo.setFacilityInfoList(facilityInfoList); apartmentDetailVo.setLabelInfoList(labelInfoList); apartmentDetailVo.setFeeValueVoList(feeValueVoList); apartmentDetailVo.setGraphVoList(graphVoList); return apartmentDetailVo; }
Mapper 省略
接口4:根据ID删除公寓详细信息 Controller 1 2 3 4 5 6 @Operation(summary = "根据id删除公寓信息") @DeleteMapping("removeById") public Result removeById (@RequestParam Long id) { apartmentInfoService.removeApartmentInfo(id); return Result.ok(); }
Service 1 void removeApartmentInfo (Long id) ;
ServiceImpl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 @Override public void removeApartmentInfo (Long id) { LambdaQueryWrapper<RoomInfo> wrapper = new LambdaQueryWrapper <>(); wrapper.eq(RoomInfo::getApartmentId, id); long count = roomInfoService.count(wrapper); if (count > 0 ) { throw new RuntimeException ("存在房间信息" ); } this .removeById(id); LambdaQueryWrapper<ApartmentFacility> wrapper01 = new LambdaQueryWrapper <>(); wrapper01.eq(ApartmentFacility::getApartmentId, id); apartmentFacilityService.remove(wrapper01); LambdaQueryWrapper<ApartmentLabel> wrapper02 = new LambdaQueryWrapper <>(); wrapper02.eq(ApartmentLabel::getApartmentId, id); apartmentLabelService.remove(wrapper02); LambdaQueryWrapper<ApartmentFeeValue> wrapper03 = new LambdaQueryWrapper <>(); wrapper03.eq(ApartmentFeeValue::getApartmentId, id); apartmentFeeValueService.remove(wrapper03); LambdaQueryWrapper<GraphInfo> wrapper04 = new LambdaQueryWrapper <>(); wrapper04.eq(GraphInfo::getItemId, id); graphInfoService.remove(wrapper04); }
接口5:根据ID修改公寓发布状态 Controller 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Operation(summary = "根据id修改公寓发布状态") @PostMapping("updateReleaseStatusById") public Result updateReleaseStatusById (@RequestParam Long id, @RequestParam ReleaseStatus status) { ApartmentInfo apartmentInfo = apartmentInfoService.getById(id); apartmentInfo.setIsRelease(status); apartmentInfoService.updateById(apartmentInfo); LambdaUpdateWrapper<ApartmentInfo> wrapper = new LambdaUpdateWrapper <>(); wrapper.eq(ApartmentInfo::getId, id); wrapper.set(ApartmentInfo::getIsRelease, status); return Result.ok(); }
接口6: 根据区县ID查询公寓信息列表 1 2 3 4 5 6 7 8 @Operation(summary = "根据区县id查询公寓信息列表") @GetMapping("listInfoByDistrictId") public Result<List<ApartmentInfo>> listInfoByDistrictId (@RequestParam Long id) { LambdaQueryWrapper<ApartmentInfo> queryWrapper = new LambdaQueryWrapper <>(); queryWrapper.eq(ApartmentInfo::getDistrictId, id); List<ApartmentInfo> list = apartmentInfoService.list(queryWrapper); return Result.ok(list); }