【尚庭公寓|项目日记】第三天

摘要:

        主要记录了web-admin模块下与公寓有关的几个较难,且知识点较多的几个接口的实现,对这些接口的知识点进行了简单的介绍,巩固有关的知识体系。

 

一,公寓信息管理所有接口

1,保存或更新公寓信息

        众嗦粥滋,mybatisplus提供了非常多的通用mapper,其中就有saveOrUpdate()用于保存或更新。但是就业务场景来说要保存的数据往往不止操作一张表,例如这个接口保存的是ApartmentSubmitVo(继承了ApartmentInfo类)而不是单纯的ApartmentInfo类,所以我们必须自定义方法来实现保存或更新公寓信息。

(1)实现类中调用saveOrUpdate()保存ApartmentSubmitVo中的ApartmentInfo数据到表

boolean isUpdate = apartmentSubmitVo.getId() != null;
super.saveOrUpdate(apartmentSubmitVo);

(2)这里采用的更新策略是删除原有的信息,重新插入新的信息,是否更新的判断是isUpdate

LambdaQueryWrapper<GraphInfo> graphQueryWrapper = new LambdaQueryWrapper<>();
//设置查询条件,itemType为APARTMENT,itemId为apartmentSubmitVo.getId()
graphQueryWrapper.eq(GraphInfo::getItemType, ItemType.APARTMENT);
graphQueryWrapper.eq(GraphInfo::getItemId, apartmentSubmitVo.getId());
//调用graphInfoService的remove方法,删除符合条件的记录
graphInfoService.remove(graphQueryWrapper);


List<GraphVo> graphVoList = apartmentSubmitVo.getGraphVoList();
if (!CollectionUtils.isEmpty(graphVoList)) {
      ArrayList<GraphInfo> graphInfoList = new ArrayList<>();
      //遍历图片VO集合
      for (GraphVo graphVo : graphVoList) {
      //创建一个新的GraphInfo对象
      GraphInfo graphInfo = new GraphInfo();
      graphInfo.setItemType(ItemType.APARTMENT);
      graphInfo.setItemId(apartmentSubmitVo.getId());
      graphInfo.setName(graphVo.getName());
      graphInfo.setUrl(graphVo.getUrl());
      graphInfoList.add(graphInfo);
      }
graphInfoService.saveBatch(graphInfoList);
}

(3)实现时多思考:为什么更新判断在通用保存前?得到数据集合时是不是空?

2, 根据条件分页查询公寓列表

分页查询三步走:构造page对象,自定义查询方法,返回数据

Page<ApartmentItemVo> page = new Page<>(current,size);
//调用service.pageItem方法,查询分页数据,传入构造的page和查询条件queryVo
IPage<ApartmentItemVo> result  = service.pageItem(page, queryVo);
return Result.ok(result);

如果查询涉及到多表,一般采用手写sql来完成查询,观察查询返回类的字段:公寓基本信息(条件查询) + 房间总数 + 空闲房间数(房间总数-已签约房间数)

(1)根据条件查询公寓基本信息作为子表ai

(2)根据公寓id在room_info表中查询出对应的房间总数cnt

(3)根据公寓id在lease_agreement表中查询出已签约房间数cnt

(4)主表公寓信息来自子表ai,左连接上ifnull(tc.cnt,0)和ifnull(tc.cnt,0) - ifnull(cc.cnt,0)

这里采用ifnull是为了避免出现,如果房间总数为null,不仅会使得返回数据为null还会因为运算导致其他字段为null。

        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

3,根据ID获取公寓详细信息

同样,观察要求返回的类ApartmentDetailVo(继承ApartmentInfo),也是需要获取多张表的数据,所以自定义实现方法在Java代码中编写逻辑:

public ApartmentDetailVo queryApartmentDetail(Long id) {
        //1,查询公寓信息
        ApartmentInfo apartmentInfo = apartmentInfoMapper.selectById(id);
        //2,查询图片列表
        List<GraphVo> GraphVoList = graphInfoMapper.selectListByItemTypeAndId(id, ItemType.APARTMENT);
        //3,查询标签列表
        List<LabelInfo> labelInfoList = labelInfoMapper.selectAllLabelsById(id);
        //4,查询配套列表
        List<FacilityInfo> facilityInfoList = facilityInfoMapper.selectFacilityById(id);
        //5,查询杂费列表
        List<FeeValueVo> feeValueVoList = feeValueMapper.seelctListById(id);
        ApartmentDetailVo apartmentDetailVo = new ApartmentDetailVo();
        BeanUtils.copyProperties(apartmentInfo, apartmentDetailVo);
        apartmentDetailVo.setGraphVoList(GraphVoList);
        apartmentDetailVo.setLabelInfoList(labelInfoList);
        apartmentDetailVo.setFacilityInfoList(facilityInfoList);
        apartmentDetailVo.setFeeValueVoList(feeValueVoList);
        return apartmentDetailVo;
}

 4,根据公寓id删除公寓所有信息

这里需要我们思考,如果公寓下有房间存在,我们该怎么处理?所以在删除之前还需要判断该公寓下的房间是否大于0,如果大于0就抛出异常,同时中止删除操作

LambdaQueryWrapper<RoomInfo> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(RoomInfo::getApartmentId, id);
Long count = roomInfoMapper.selectCount(wrapper);
if(count > 0){
   throw new LeaseException(ResultCodeEnum.ADMIN_APARTMENT_DELETE_ERROR);
}

5,自定义异常和全局异常处理

(1)通常在实际开发场景中,都会通过全局异常处理器来处理各类异常,同时可以自定义你自己需要的异常,且在自定义异常中我们一般会接收一个状态枚举(包含code状态码和message错误信息)

@Data
//自定义异常类LeaseException
public class LeaseException extends RuntimeException {
    private Integer code;
    //ResultCodeEnum返回结果状态枚举
    public LeaseException(ResultCodeEnum resultCodeEnum) {
        super(resultCodeEnum.getMessage());
        this.code=resultCodeEnum.getCode();
    }
}

 (2)定义全局处理LeaseException异常的方法

小tips:这里两个处理器,一个默认处理所有异常,一个是leaseException,那么出现异常会怎么执行呢?答案是匹配度高的优先执行

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result handler(Exception e){
        e.printStackTrace();
        return Result.fail();
    }

    //定义全局处理LeaseException异常的方法
    @ExceptionHandler(LeaseException.class)
    //对响应体中的异常进行处理
    @ResponseBody
    public Result handler(LeaseException e){
        e.printStackTrace();
        //返回前端异常信息
        return Result.fail(e.getCode(),e.getMessage());
    }
}

 

二,房间属性管理

1,查询全部属性名称和属性值列表接口

(1)观察返回值为List<AttrKeyVo>包含AttrKeyVo(继承AttrKey)的List集合,一个key可以对应多个value,所以AttrKeyVo中包含List<AttrValue> 。

(2)因为需要集合映射,这里引入一个新的知识点<resultMap><collection>标签,简单来说<resultMap>就是为了处理多张表的同名字段映射到一个类中混淆的情况,<collection>则是对类中集合的单独处理,可以开启autoMapping=true开启自动映射而无需手动映射

    <resultMap id="AttrKeyVoMap" type="com.atguigu.lease.web.admin.vo.attr.AttrKeyVo">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <collection property="attrValueList" ofType="com.atguigu.lease.model.entity.AttrValue">
            <id property="id" column="attr_value_id"/>
            <result property="name" column="attr_value_name"/>
            <result property="attrKeyId" column="attr_key_id"/>
        </collection>
    </resultMap>

    <select id="listAttrInfo" resultMap="AttrKeyVoMap" >
        select k.id,
               k.name,
               v.id   as attr_value_id,
               v.name as attr_value_name,
               v.attr_key_id
        from attr_key k
                 left join attr_value v
                           on k.id = v.attr_key_id and v.is_deleted = 0
        where k.is_deleted = 0
    </select>

 

三,配套设施管理

1,[根据类型]查询配套信息列表接口

接口通过@RequestParam(required = false)标明ItemType为非必需的值,所以在查询条件wrapper构造上引入条件判断type!=null,表示不为空才执行该条件,否则不执行这个条件

@GetMapping("list")
public Result<List<FacilityInfo>> listFacility(@RequestParam(required = false) ItemType type) {
    LambdaQueryWrapper<FacilityInfo> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(type!=null,FacilityInfo::getType, type);
    List<FacilityInfo> list = facilityInfoService.list(wrapper);
    return Result.ok(list);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值