当前位置: 首页 > news >正文

【尚庭公寓SpringBoot + Vue 项目实战】公寓管理(十一)

【尚庭公寓SpringBoot + Vue 项目实战】公寓管理(十一)


文章目录

      • 【尚庭公寓SpringBoot + Vue 项目实战】公寓管理(十一)
        • 1、业务介绍
        • 2、逻辑模型介绍
        • 3、接口开发
          • 3.1、保存或更新公寓信息
          • 3.2、根据条件分页查询详细信息
          • 3.3、根据ID获取公寓详细信息
          • 3.4、 根据ID删除公寓信息
          • 3.5、根据ID修改公寓发布状态
          • 3.6、根据区县ID查询公寓信息列表

1、业务介绍

公寓管理共有六个接口,分别是

  1. 保存或更新公寓信息
  2. 根据条件分页查询详细信息
  3. 根据ID获取公寓详情信息
  4. 根据ID删除公寓信息
  5. 根据ID修改公寓发布状态
  6. 根据区县ID查询公寓信息列表

image-20240615225107206

2、逻辑模型介绍

image-20240615225155083

3、接口开发
3.1、保存或更新公寓信息

查看接口

image-20240615230105118

image-20240615230119810

进行开发

查看web-admin模块中的com.atguigu.lease.web.admin.vo.apartment.ApartmentSubmitVo类,内容如下:

@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;}

编写Controller层逻辑

@Operation(summary = "保存或更新公寓信息")
@PostMapping("saveOrUpdate")
public Result saveOrUpdate(@RequestBody ApartmentSubmitVo apartmentSubmitVo) {service.saveOrUpdateApartment(apartmentSubmitVo);return Result.ok();
}

编写Service层逻辑

  • ApartmentInfoService中增加如下内容

    void saveOrUpdateApartment(ApartmentSubmitVo apartmentSubmitVo);
    
  • ApartmentInfoServiceImpl中增加如下内容

    /*** @author liubo* @description 针对表【apartment_info(公寓信息表)】的数据库操作Service实现* @createDate 2023-07-24 15:48:00*/
    @Service
    public class ApartmentInfoServiceImpl extends ServiceImpl<ApartmentInfoMapper, ApartmentInfo>implements ApartmentInfoService {@Autowiredprivate GraphInfoService graphInfoService;@Autowiredprivate ApartmentFacilityService apartmentFacilityService;@Autowiredprivate ApartmentLabelService apartmentLabelService;@Autowiredprivate ApartmentFeeValueService apartmentFeeValueService;/*** 保存或更新公寓信息** @param apartmentSubmitVo*/@Override@Transactionalpublic void apartmentSaveOrUpdate(ApartmentSubmitVo apartmentSubmitVo) {//判断是新增方法还是修改方法boolean isUpdate = apartmentSubmitVo.getId() != null;super.saveOrUpdate(apartmentSubmitVo);if (isUpdate){//进行删除,先删除后再添加//删除图片LambdaQueryWrapper<GraphInfo> graphInfoQueryWrapper = new LambdaQueryWrapper<>();graphInfoQueryWrapper.eq(GraphInfo::getItemType, ItemType.APARTMENT);graphInfoQueryWrapper.eq(GraphInfo::getItemId,apartmentSubmitVo.getId());graphInfoService.remove(graphInfoQueryWrapper);//删除配套列表LambdaQueryWrapper<ApartmentFacility> apartmentFacilityQueryWrapper = new LambdaQueryWrapper<>();apartmentFacilityQueryWrapper.eq(ApartmentFacility::getApartmentId,apartmentSubmitVo.getId());apartmentFacilityService.remove(apartmentFacilityQueryWrapper);//删除标签LambdaQueryWrapper<ApartmentLabel> apartmentLabelQueryWrapper = new LambdaQueryWrapper<>();apartmentLabelQueryWrapper.eq(ApartmentLabel::getApartmentId,apartmentSubmitVo.getId());apartmentLabelService.remove(apartmentLabelQueryWrapper);//删除杂费LambdaQueryWrapper<ApartmentFeeValue> apartmentFeeValueQueryWrapper = new LambdaQueryWrapper<>();apartmentFeeValueQueryWrapper.eq(ApartmentFeeValue::getApartmentId,apartmentSubmitVo.getId());apartmentFeeValueService.remove(apartmentFeeValueQueryWrapper);}//插入图片List<GraphVo> graphVoList = apartmentSubmitVo.getGraphVoList();if (!CollectionUtils.isEmpty(graphVoList)){List<GraphInfo> graphInfoList = new ArrayList<>();//循环添加for (GraphVo graphVo : graphVoList) {GraphInfo graphInfo = GraphInfo.builder().name(graphVo.getName()).url(graphVo.getUrl()).itemId(apartmentSubmitVo.getId()).itemType(ItemType.APARTMENT).build();graphInfoList.add(graphInfo);}graphInfoService.saveBatch(graphInfoList);}}
    }
    
3.2、根据条件分页查询详细信息

查看接口

image-20240615230601651

进行开发

查看请求和响应的数据结构

  • 请求数据结构

    • currentsize为分页相关参数,分别表示当前所处页面每个页面的记录数

    • ApartmentQueryVo为公寓的查询条件,详细结构如下:

@Schema(description = "公寓信息")
@Data
public class ApartmentDetailVo extends ApartmentInfo {@Schema(description = "图片列表")private List<GraphVo> graphVoList;@Schema(description = "标签列表")private List<LabelInfo> labelInfoList;@Schema(description = "配套列表")private List<FacilityInfo> facilityInfoList;@Schema(description = "杂费列表")private List<FeeValueVo> feeValueVoList;
}

响应数据结构

单个公寓信息记录可查看com.atguigu.lease.web.admin.vo.apartment.ApartmentItemVo,内容如下:

@Data
@Schema(description = "后台管理系统公寓列表实体")
public class ApartmentItemVo extends ApartmentInfo {@Schema(description = "房间总数")private Long totalRoomCount;@Schema(description = "空闲房间数")private Long freeRoomCount;}

配置Mybatis-Plus分页插件

common模块中的com.atguigu.lease.common.mybatisplus.MybatisPlusConfiguration中增加如下内容:

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;
}

接口实现

  • 编写Controller层逻辑

    ApartmentController中增加如下内容:

@Operation(summary = "根据条件分页查询公寓列表")
@GetMapping("pageItem")
public Result<IPage<ApartmentItemVo>> pageItem(@RequestParam long current, @RequestParam long size, ApartmentQueryVo queryVo) {IPage<ApartmentItemVo> page = new Page<>(current, size);IPage<ApartmentItemVo> list = service.pageApartmentItemByQuery(page, queryVo);return Result.ok(list);
}

编写Service层逻辑

  • ApartmentInfoService中增加如下内容
IPage<ApartmentItemVo> pageApartmentItemByQuery(IPage<ApartmentItemVo> page, ApartmentQueryVo queryVo);

ApartmentInfoServiceImpl中增加如下内容

@Autowired
private ApartmentInfoMapper apartmentInfoMapper;/*** 分页查询* @param page* @param queryVo* @return*/
@Override
public IPage<ApartmentItemVo> pageItem(IPage<ApartmentItemVo> page, ApartmentQueryVo queryVo) {return apartmentInfoMapper.pageItem(page,queryVo);
}

编写Mapper层逻辑

ApartmentInfoMapper中增加如下内容

IPage<ApartmentItemVo> pageApartmentItemByQuery(IPage<ApartmentItemVo> page, ApartmentQueryVo queryVo);

ApartmentInfoMapper.xml中增加如下内容

<select id="pageItem" 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_countfrom (select id,name,introduction,district_id,district_name,city_id,city_name,province_id,province_name,address_detail,latitude,longitude,phone,is_releasefrom 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>) aileft join(select apartment_id,count(*) cntfrom room_infowhere is_deleted = 0and is_release = 1group by apartment_id) tcon ai.id = tc.apartment_idleft join(select apartment_id,count(*) cntfrom lease_agreementwhere is_deleted = 0and status in (2, 5)group by apartment_id) ccon ai.id = cc.apartment_id</select>

注意:

默认情况下Knife4j为该接口生成的接口文档如下图所示,其中的queryVo参数不方便调试

可在application.yml文件中增加如下配置,将queryVo做打平处理

image-20240615231518354

springdoc:default-flat-param-object: true

spring.default-flat-param-object参数设置为true后,效果如下。

image-20240615231529102

3.3、根据ID获取公寓详细信息

查看接口

image-20240615232418668

image-20240615232446248

查看响应数据结构

查看web-admin下的com.atguigu.lease.web.admin.vo.apartment.ApartmentDetailVo,内容如下

@Schema(description = "公寓信息")
@Data
public class ApartmentDetailVo extends ApartmentInfo {@Schema(description = "图片列表")private List<GraphVo> graphVoList;@Schema(description = "标签列表")private List<LabelInfo> labelInfoList;@Schema(description = "配套列表")private List<FacilityInfo> facilityInfoList;@Schema(description = "杂费列表")private List<FeeValueVo> feeValueVoList;
}

编写Controller层逻辑

ApartmentController中增加如下内容

@Operation(summary = "根据ID获取公寓详细信息")
@GetMapping("getDetailById")
public Result<ApartmentDetailVo> getDetailById(@RequestParam Long id) {ApartmentDetailVo apartmentDetailVo = apartmentInfoService.getDetailById(id);return Result.ok(apartmentDetailVo);
}

编写Service层逻辑

ApartmentInfoService中增加如下内容

ApartmentDetailVo getApartmentDetailById(Long id);

ApartmentInfoServiceImpl中增加如下内容

@Autowired
private GraphInfoMapper graphInfoMapper;@Autowired
private LabelInfoMapper labelInfoMapper;@Autowired
private FacilityInfoMapper facilityInfoMapper;@Autowired
private FeeValueMapper feeValueMapper;/*** 根据id获取公寓详细信息** @param id* @return*/
@Override
public ApartmentDetailVo getDetailById(Long id) {//1、根据id或获取公寓信息ApartmentInfo apartmentInfo = this.getById(id);if (apartmentInfo == null){return null;}//2、获取图片列表List<GraphVo> graphVoList = graphInfoMapper.getByIdGraphList(id,ItemType.APARTMENT);//3、获取标签列表List<LabelInfo> labelInfoList = labelInfoMapper.selectListByApartmentId(id);//4、查询配套列表List<FacilityInfo> facilityInfoList =  facilityInfoMapper.selectListByApartmentId(id);//5、查询杂费信息列表List<FeeValueVo> feeValueVoList = feeValueMapper.selectListByApartmentId(id);ApartmentDetailVo apartmentDetailVo = new ApartmentDetailVo();//复制属性BeanUtils.copyProperties(apartmentInfo,apartmentDetailVo);//增加属性apartmentDetailVo.setGraphVoList(graphVoList);apartmentDetailVo.setLabelInfoList(labelInfoList);apartmentDetailVo.setFacilityInfoList(facilityInfoList);apartmentDetailVo.setFeeValueVoList(feeValueVoList);return apartmentDetailVo;
}

编写Mapper层逻辑

编写公寓图片查询逻辑,在GraphInfoMapper中增加如下内容

/**
* @author liubo
* @description 针对表【graph_info(图片信息表)】的数据库操作Mapper
* @createDate 2023-07-24 15:48:00
* @Entity com.atguigu.lease.model.GraphInfo
*/
public interface GraphInfoMapper extends BaseMapper<GraphInfo> {@Select("select name,url from graph_info where is_deleted=0 and item_id = #{id} and item_id = #{itemType}")List<GraphVo> getByIdGraphList(Long id,ItemType itemType);
}

编写公寓标签查询逻辑

LabelInfoMapper中增加如下内容

/**
* @author liubo
* @description 针对表【label_info(标签信息表)】的数据库操作Mapper
* @createDate 2023-07-24 15:48:00
* @Entity com.atguigu.lease.model.LabelInfo
*/
public interface LabelInfoMapper extends BaseMapper<LabelInfo> {/*** 获取标签列表* @param id* @return*/@Select("select id, type, name from label_info where label_info.is_deleted = 0 and id in " +"(select apartment_label.label_id from apartment_label where apartment_label.is_deleted = 0 and  apartment_id = #{id})")List<LabelInfo> selectListByApartmentId(Long id);
}

编写公寓配套查询逻辑

FacilityInfoMapper中增加如下内容

/**
* @author liubo
* @description 针对表【facility_info(配套信息表)】的数据库操作Mapper
* @createDate 2023-07-24 15:48:00
* @Entity com.atguigu.lease.model.FacilityInfo
*/
public interface FacilityInfoMapper extends BaseMapper<FacilityInfo> {/*** 根据id查询配套信息* @param id* @return*/@Select("select id,type,name,icon from facility_info where " +"is_deleted=0 and  id in " +"(select facility_id from apartment_facility where is_deleted = 0 and apartment_id = #{id})")List<FacilityInfo> selectListByApartmentId(Long id);
}List<FacilityInfo> selectListByApartmentId(Long id);

编写公寓杂费查询逻辑

FeeValueMapper中增加如下内容

/**
* @author liubo
* @description 针对表【fee_value(杂项费用值表)】的数据库操作Mapper
* @createDate 2023-07-24 15:48:00
* @Entity com.atguigu.lease.model.FeeValue
*/
public interface FeeValueMapper extends BaseMapper<FeeValue> {List<FeeValueVo> selectListByApartmentId(Long id);
}

FeeValueMapper.xml中增加如下内容

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.lease.web.admin.mapper.FeeValueMapper"><select id="selectListByApartmentId" resultType="com.atguigu.lease.web.admin.vo.fee.FeeValueVo">selectfv.id,fv.name,fv.unit,fv.fee_key_id,fk.name as fee_key_namefrom fee_value fvjoin fee_key fk on fv.fee_key_id = fk.idwhere fv.is_deleted = 0 and fk.is_deleted = 0and fv.id in(select fee_value_id from apartment_fee_value where is_deleted = 0 and apartment_id = #{id})</select>
</mapper>
3.4、 根据ID删除公寓信息

查看接口

image-20240615232524882

编写Controller层逻辑

ApartmentController中增加如下内容

@Operation(summary = "根据id删除公寓信息")
@DeleteMapping("removeById")
public Result removeById(@RequestParam Long id) {apartmentInfoService.removeApartmentById(id);return Result.ok();
}

编写Service层逻辑

ApartmentInfoService中增加如下内容

/*** 根据id删除公寓信息* @param id*/
void removeApartmentById(Long id);

ApartmentInfoServiceImpl中增加如下内容

@Autowired
private RoomInfoMapper roomInfoMapper;/*** 根据id删除公寓信息** @param id*/
@Override
@Transactional
public void removeApartmentById(Long id) {//查询公寓内是否有房间LambdaQueryWrapper<RoomInfo> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(RoomInfo::getApartmentId,id);Long count = roomInfoMapper.selectCount(queryWrapper);if (count > 0){throw new LeaseException(ResultCodeEnum.ADMIN_APARMIN_APARTMENT_DELETE_ERROR);}//删除公寓super.removeById(id);//删除图片LambdaQueryWrapper<GraphInfo> graphInfoQueryWrapper = new LambdaQueryWrapper<>();graphInfoQueryWrapper.eq(GraphInfo::getItemType, ItemType.APARTMENT);graphInfoQueryWrapper.eq(GraphInfo::getItemId,id);graphInfoService.remove(graphInfoQueryWrapper);//删除配套列表LambdaQueryWrapper<ApartmentFacility> apartmentFacilityQueryWrapper = new LambdaQueryWrapper<>();apartmentFacilityQueryWrapper.eq(ApartmentFacility::getApartmentId,id);apartmentFacilityService.remove(apartmentFacilityQueryWrapper);//删除标签LambdaQueryWrapper<ApartmentLabel> apartmentLabelQueryWrapper = new LambdaQueryWrapper<>();apartmentLabelQueryWrapper.eq(ApartmentLabel::getApartmentId,id);apartmentLabelService.remove(apartmentLabelQueryWrapper);//删除杂费LambdaQueryWrapper<ApartmentFeeValue> apartmentFeeValueQueryWrapper = new LambdaQueryWrapper<>();apartmentFeeValueQueryWrapper.eq(ApartmentFeeValue::getApartmentId,id);apartmentFeeValueService.remove(apartmentFeeValueQueryWrapper);}

知识点

由于公寓下会包含房间信息,因此在删除公寓时最好先判断一下该公寓下是否存在房间信息,若存在,则提醒用户先删除房间信息后再删除公寓信息,判断逻辑如下

LambdaQueryWrapper<RoomInfo> roomQueryWrapper = new LambdaQueryWrapper<>();
roomQueryWrapper.eq(RoomInfo::getApartmentId, id);
Long count = roomInfoMapper.selectCount(roomQueryWrapper);
if (count > 0) {//直接为前端返回如下响应:先删除房间信息再删除公寓信息
}

想要直接为前端返回响应,可利用前边配置的全局异常处理功能(此处直接抛出异常,全局异常处理器捕获到异常后,便会直接为前端返回响应结果)。

为灵活设置响应信息,可自定义异常类,如下

common模块创建com.atguigu.lease.common.exception.LeaseException类,内容如下:

@Data
public class LeaseException extends RuntimeException {//异常状态码private Integer code;/*** 通过状态码和错误消息创建异常对象* @param message* @param code*/public LeaseException(String message, Integer code) {super(message);this.code = code;}/*** 根据响应结果枚举对象创建异常对象* @param resultCodeEnum*/public LeaseException(ResultCodeEnum resultCodeEnum) {super(resultCodeEnum.getMessage());this.code = resultCodeEnum.getCode();}@Overridepublic String toString() {return "LeaseException{" +"code=" + code +", message=" + this.getMessage() +'}';}
}

common模块com.atguigu.lease.common.exception.GlobalExceptionHandler类中,增加自定义异常类的处理逻辑

@ExceptionHandler(LeaseException.class)
@ResponseBody
public Result error(LeaseException e){e.printStackTrace();return Result.fail(e.getCode(), e.getMessage());
}

为Result新增一个构造方法,如下

public static <T> Result<T> fail(Integer code, String message) {Result<T> result = build(null);result.setCode(code);result.setMessage(message);return result;
}
3.5、根据ID修改公寓发布状态

查看接口

image-20240615232925369

进行开发

ApartmentController中增加如下内容:

@Operation(summary = "根据id修改公寓发布状态")
@PostMapping("updateReleaseStatusById")
public Result updateReleaseStatusById(@RequestParam Long id, @RequestParam ReleaseStatus status) {LambdaQueryWrapper<ApartmentInfo> apartmentInfoQueryWrapper = new LambdaQueryWrapper<>();apartmentInfoQueryWrapper.eq(ApartmentInfo::getId,id);apartmentInfoQueryWrapper.eq(ApartmentInfo::getIsRelease,status);apartmentInfoService.update(apartmentInfoQueryWrapper);return Result.ok();
}
3.6、根据区县ID查询公寓信息列表

查看接口

image-20240615233103039

进行开发

ApartmentController中增加如下内容:

@Operation(summary = "根据区县id查询公寓信息列表")
@GetMapping("listInfoByDistrictId")
public Result<List<ApartmentInfo>> listInfoByDistrictId(@RequestParam Long id) {LambdaQueryWrapper<ApartmentInfo> apartmentInfoQueryWrapper = new LambdaQueryWrapper<>();apartmentInfoQueryWrapper.eq(ApartmentInfo::getDistrictId,id);List<ApartmentInfo> list = apartmentInfoService.list(apartmentInfoQueryWrapper);return Result.ok(list);
}

相关文章:

  • NumPy 切片和索引
  • Linux时间子系统1:gettimeofday和clock_gettime实现分析
  • 【Python】 Stacking: 强大的集成学习方法
  • React 中的事件处理
  • 如何确保数据跨域交换安全、合规、可追溯性?
  • java中Array(数组)、List(列表)、Set(集合)、Map(映射)、Queue(队列)详解
  • 【面试题】MySQL常见面试题总结
  • 深度学习第二章
  • Perplexity AI — 探索网络,发掘知识,沟通思想
  • 基于鲸鱼优化的DSN弱栅栏覆盖算法matlab仿真
  • MySQL之优化服务器设置(五)
  • 几何公差的设计和选用
  • k8s-kubernetes常用命令,服务部署,可视化控制台安装及token的生成
  • 【Android面试八股文】在Android中,出现ClassNotFound的有可能的原因是什么?
  • 富格林:细心发现虚假确保安全
  • DataBase in Android
  • HTML-表单
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • Python代码面试必读 - Data Structures and Algorithms in Python
  • SpiderData 2019年2月13日 DApp数据排行榜
  • vue自定义指令实现v-tap插件
  • 安装python包到指定虚拟环境
  • 仿天猫超市收藏抛物线动画工具库
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 技术胖1-4季视频复习— (看视频笔记)
  • 理解在java “”i=i++;”所发生的事情
  • 一、python与pycharm的安装
  • 原生JS动态加载JS、CSS文件及代码脚本
  • 你对linux中grep命令知道多少?
  • 树莓派用上kodexplorer也能玩成私有网盘
  • ​决定德拉瓦州地区版图的关键历史事件
  • ​批处理文件中的errorlevel用法
  • ​软考-高级-信息系统项目管理师教程 第四版【第23章-组织通用管理-思维导图】​
  • # 安徽锐锋科技IDMS系统简介
  • (2)STL算法之元素计数
  • (iPhone/iPad开发)在UIWebView中自定义菜单栏
  • (javascript)再说document.body.scrollTop的使用问题
  • (二)斐波那契Fabonacci函数
  • (删)Java线程同步实现一:synchronzied和wait()/notify()
  • (转)ORM
  • .Net - 类的介绍
  • .NET 编写一个可以异步等待循环中任何一个部分的 Awaiter
  • .net 调用php,php 调用.net com组件 --
  • .NET 快速重构概要1
  • .net 提取注释生成API文档 帮助文档
  • .NET 应用架构指导 V2 学习笔记(一) 软件架构的关键原则
  • .NET/C# 在 64 位进程中读取 32 位进程重定向后的注册表
  • .NetCore 如何动态路由
  • .net专家(高海东的专栏)
  • [android学习笔记]学习jni编程
  • [AutoSar]BSW_Memory_Stack_004 创建一个简单NV block并调试
  • [BT]BUUCTF刷题第8天(3.26)
  • [C#]C# OpenVINO部署yolov8图像分类模型
  • [C#小技巧]如何捕捉上升沿和下降沿
  • [CSS] - 修正IE6不支持position:fixed的bug