互联酒旅总结

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


一、项目介绍

这是一个酒店订购服务的一个项目,后端主要有酒店模块,搜索模块,个人中心。

前端主要技术:

后端主要技术:

 组织结构:

 系统架构:

开发环境:

二、数据库的设计

1.注意事项

遵循阿里规范,注意字段类型

三、搜索模块

1.枚举

代码如下:

@RestController
@Api(tags = "后台枚举CRUD", value = "EnumController")
@RequestMapping("/admin/hotel/search")
public class EnumController {

    @Resource
    private IEnumService enumService;
    /**
     * 获取全部枚举
     *
     * @return 全部枚举
     */
    @ApiOperation(value = "获取全部枚举")
    @GetMapping(value = "/enum-list")
    public CommonResult<List<EnumType>> allEnum() {
        List<EnumType> enumTypeList = enumService.getDictItem();
        return CommonResult.success(enumTypeList);
    }

    /**
     * 新增枚举
     *
     * @param enumType 枚举类型
     * @return 返回添加结果
     */
    @ApiOperation(value = "添加枚举")
    @PostMapping(value = "/enum-add")
    public CommonResult<Boolean> saveEnum(@RequestBody EnumType enumType) {
        enumService.saveEnum(enumType);
        return CommonResult.success(true, "添加成功");
    }

    /**
     * 修改枚举
     *
     * @param enumType 枚举类型
     * @return 返回修改结果
     */
    @ApiOperation(value = "修改枚举")
    @PostMapping(value = "/enum-update")
    public CommonResult<Boolean> updateEnum(@RequestBody EnumType enumType) {
        enumService.updateEnum(enumType);
        return CommonResult.success(true, "修改成功");
    }

    /**
     * 删除枚举
     *
     * @param id 枚举id
     * @return 返回删除结果
     */
    @ApiOperation(value = "删除枚举")
    @GetMapping(value = "/enum-delete")
    public CommonResult<Boolean> deleteEnum(@RequestParam Long id) {
        enumService.deleteEnum(id);
        return CommonResult.success(true, "删除成功");
    }

}
@Service
public class EnumServiceImpl extends ServiceImpl<EnumMapper, EnumType> implements IEnumService {


    /**
     * 查询所有枚举
     *
     * @return 枚举
     */
    @Override
    public List<EnumType> getDictItem() {
        List<EnumType> allEnm = this.list();
        List<EnumType> parentList = allEnm.stream().filter(v -> v.getParentId().equals(0L)).collect(Collectors.toList());
        parentList.forEach(parentEnum -> {
            List<EnumType> children = allEnm.stream().filter(v -> v.getParentId().equals(parentEnum.getId())).collect(Collectors.toList());
            parentEnum.setChildren(children);
        });
        return parentList;
    }

    /**
     * 添加枚举
     *
     * @param enumType 枚举对象
     */
    @Override
    public void saveEnum(EnumType enumType) {
        boolean flag = this.save(enumType);
        if (!flag) {
            Asserts.fail("新增失败");
        }
    }

    /**
     * 修改枚举
     *
     * @param enumType 枚举对象
     */
    @Override
    public void updateEnum(EnumType enumType) {
        boolean flag = this.updateById(enumType);
        if (!flag) {
            Asserts.fail("更新失败");
        }
    }

    /**
     * @param id 枚举id
     */
    @Override
    public void deleteEnum(Long id) {
        boolean flag = this.removeById(id);
        if (!flag) {
            Asserts.fail("删除失败");
        }
    }
}
public interface IEnumService extends IService<EnumType> {


    /**
     * 查询所有枚举
     *
     * @return 枚举
     */
    List<EnumType> getDictItem();


    /**
     * 添加枚举
     *
     * @param enumType
     */
    void saveEnum(EnumType enumType);

    /**
     * 更新枚举
     *
     * @param enumType
     */
    void updateEnum(EnumType enumType);

    /**
     * 删除枚举
     *
     * @param id
     */
    void deleteEnum(Long id);


}

2.Elasticsearch

代码如下:

@Api(tags = "搜索酒店", value = "EsHotelController")
@Validated
@RestController
@RequestMapping("/hotel/search")
public class EsHotelController {

    @Resource
    private EsHotelService esHotelService;
    @Resource
    private IEnumService enumService;

    @ApiOperation(value = "综合搜索、筛选、排序")
    @PostMapping(value = "/list")
    public CommonResult<CommonPage<EsHotel>> search(HotelDTO hotelDTO) {
        Page<EsHotel> esHotelPage = esHotelService.search(hotelDTO);
        CommonPage<EsHotel> hotelCommonPage = CommonPage.restPage(esHotelPage);
        return CommonResult.success(hotelCommonPage);
    }


    /**
     * @return 返回查询结果
     */
    @ApiOperation(value = "获取全部枚举列表")
    @GetMapping(value = "/enum-list")
    public CommonResult<List<EnumType>> allEnum() {
        List<EnumType> enumTypeList = enumService.getDictItem();
        return CommonResult.success(enumTypeList);
    }


}
@Service
@Slf4j
public class EsHotelServiceImpl implements EsHotelService {


    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    /**
     * @return 酒店列表
     */
    @Override
    public Page<EsHotel> search(HotelDTO hotelDTO) {
        //创建分页
        Pageable pageable = PageRequest.of(hotelDTO.getPageNum(), hotelDTO.getPageSize());
        //创建查询条件
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        //分页
        nativeSearchQueryBuilder.withPageable(pageable);

        //过滤
        filter(hotelDTO, nativeSearchQueryBuilder);

        //搜索
        searchKeyword(hotelDTO, nativeSearchQueryBuilder);

        //排序
        sort(hotelDTO, nativeSearchQueryBuilder);

        NativeSearchQuery searchQuery = nativeSearchQueryBuilder.build();
        //打印查询DSL语句
        log.info("DSL:{}", searchQuery.getQuery());
        SearchHits<EsHotel> searchHits = elasticsearchRestTemplate.search(searchQuery, EsHotel.class);
        //查询无结果返回空集合
        if (searchHits.getTotalHits() <= 0) {
            return new PageImpl<>(new ArrayList<>(), pageable, 0);
        }
        //转换成酒店集合
        List<EsHotel> searchProductList = searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList());
        return new PageImpl<>(searchProductList, pageable, searchHits.getTotalHits());

    }

    private void filter(HotelDTO hotelDTO, NativeSearchQueryBuilder nativeSearchQueryBuilder) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //查询附近地标
        if (ObjectUtil.isNotNull(hotelDTO.getLandmarkNearby())) {
            boolQueryBuilder.must(QueryBuilders.matchQuery(SearchCode.LANDMARK_NEARBY, hotelDTO.getLandmarkNearby()));
        }
        //查询酒店星级
        if (ObjectUtil.isNotNull(hotelDTO.getHotelStars())) {
            boolQueryBuilder.must(QueryBuilders.termsQuery(SearchCode.GRADE, (Object[]) hotelDTO.getHotelStars()));
        }
        //查询方圆几千米酒店
        if (ObjectUtil.isNotNull(hotelDTO.getLongitude()) && ObjectUtil.isNotNull(hotelDTO.getLatitude()) && ObjectUtil.isNotNull(hotelDTO.getRange())) {
            boolQueryBuilder.must(QueryBuilders.geoDistanceQuery(SearchCode.LOCATION).point(hotelDTO.getLatitude(), hotelDTO.getLongitude())
                    .distance(hotelDTO.getRange(), DistanceUnit.KILOMETERS).geoDistance(GeoDistance.ARC));
        }
        //查询价格区间
        if (ObjectUtil.isNotNull(hotelDTO.getMinPrice()) && ObjectUtil.isNotNull(hotelDTO.getMaxPrice())) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery(SearchCode.FLOOR_SPECIAL_PRICE).gte(hotelDTO.getMinPrice()).lte(hotelDTO.getMaxPrice()));
        }
        nativeSearchQueryBuilder.withFilter(boolQueryBuilder);
    }

    private void searchKeyword(HotelDTO hotelDTO, NativeSearchQueryBuilder nativeSearchQueryBuilder) {
        if (CharSequenceUtil.isEmpty(hotelDTO.getQueryText())) {
            //关键字为空则全查
            nativeSearchQueryBuilder.withQuery(QueryBuilders.matchAllQuery());
        } else {
            //设置权重
            List<FunctionScoreQueryBuilder.FilterFunctionBuilder> filterFunctionBuilders = new ArrayList<>();
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery(SearchCode.ADDRESS_DETAIL, hotelDTO.getQueryText()),
                    ScoreFunctionBuilders.weightFactorFunction(10)));
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery(SearchCode.CITY_NAME, hotelDTO.getQueryText()),
                    ScoreFunctionBuilders.weightFactorFunction(8)));
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery(SearchCode.REGION, hotelDTO.getQueryText()),
                    ScoreFunctionBuilders.weightFactorFunction(6)));
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery(SearchCode.BRAND, hotelDTO.getQueryText()),
                    ScoreFunctionBuilders.weightFactorFunction(4)));
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery(SearchCode.NAME, hotelDTO.getQueryText()),
                    ScoreFunctionBuilders.weightFactorFunction(2)));
            FunctionScoreQueryBuilder.FilterFunctionBuilder[] builders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[filterFunctionBuilders.size()];
            filterFunctionBuilders.toArray(builders);
            FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(builders)
                    .scoreMode(FunctionScoreQuery.ScoreMode.SUM)
                    .setMinScore(2);
            nativeSearchQueryBuilder.withQuery(functionScoreQueryBuilder);
        }
    }

    private void sort(HotelDTO hotelDTO, NativeSearchQueryBuilder nativeSearchQueryBuilder) {
        //设置排序默认值
        if (ObjectUtil.isNull(hotelDTO.getSort())) {
            hotelDTO.setSort(0);
        }
        switch (hotelDTO.getSort()) {
            //直线距离排序
            case SearchCode.DISTANCE_ASC:
                //经纬度为null无法排序
                if (ObjectUtil.isNotNull(hotelDTO.getLongitude()) && ObjectUtil.isNotNull(hotelDTO.getLatitude())) {
                    nativeSearchQueryBuilder.withSort(SortBuilders.geoDistanceSort(SearchCode.LOCATION, hotelDTO.getLatitude(), hotelDTO.getLongitude())
                            .unit(DistanceUnit.KILOMETERS).order(SortOrder.ASC));
                }
                break;
            //销量高低排序
            case SearchCode.SALE_COUNT_DESC:
                nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(SearchCode.SALE_COUNT).order(SortOrder.DESC));
                break;
            //价格低高排序
            case SearchCode.PRICE_ASC:
                nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(SearchCode.FLOOR_SPECIAL_PRICE).order(SortOrder.ASC));
                break;
            //价格高低排序
            case SearchCode.PRICE_DESC:
                nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(SearchCode.FLOOR_SPECIAL_PRICE).order(SortOrder.DESC));
                break;
            //评分高低排序
            case SearchCode.SCORE_DESC:
                nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(SearchCode.EVALUATE_SCORE).order(SortOrder.DESC));
                break;
            //点评数高低排序
            case SearchCode.COMMENT_DESC:
                nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(SearchCode.EVALUATE_COUNT).order(SortOrder.DESC));
                break;
            //综合排序
            default:
                nativeSearchQueryBuilder.withSort(SortBuilders.scoreSort().order(SortOrder.DESC));
                break;
        }
    }
}
public interface EsHotelService {


    /**
     * 搜索酒店
     *
     * @param hotelDTO 酒店传参
     * @return 酒店列表
     */
    Page<EsHotel> search(HotelDTO hotelDTO);


}

四、API 文档规范

  1. 请求方式 GET/POST
  2. 请求路径按照任务分配表上的写
  3. GET 请求的参数在 Query 里面填写,POST 在 Body 里写。
  4. 不要使用 RESTFul 的路径传参
  5. 参数名采用驼峰命名
  6. 数据库中存在的字段的参数,命名要保持一致
  7. 如果参数中用多个 id 参数,必须区分命名,且要与数据库一致
  8. 传参的实例值尽量真实一点
  9. 类型要选择正确,类型的选项很多自己看看。
  10. 响应数据示例的格式必须的实际的格式
  11. 响应数据的类型和描述和请求参数的要求一致
  12. 金额数据:后端使用整数存,前端部分要转化为小数

五、接口设计

酒店搜索接口

获取枚举列表接口

添加枚举

修改枚举

删除枚举

查询枚举 

 

总结

经历了一个多月吧,项目也接近尾声。通过这次项目,让我们这些新手熟悉到开发的流程。总而言之,这次的项目学到了很多对工作有益的事。我也顺利的找到了实习,加油吧!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值