Python+Django+uni-app开发的简易旅行旅游小程序:集景点、美食、特产、酒店于一体的全功能实现

68 阅读5分钟

一、个人简介

  • 💖💖作者:计算机编程果茶熊
  • 💙💙个人简介:曾长期从事计算机专业培训教学,担任过编程老师,同时本人也热爱上课教学,擅长Java、微信小程序、Python、Golang、安卓Android等多个IT方向。会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。平常喜欢分享一些自己开发中遇到的问题的解决办法,也喜欢交流技术,大家有技术代码这一块的问题可以问我!
  • 💛💛想说的话:感谢大家的关注与支持!
  • 💜💜
  • 网站实战项目
  • 安卓/小程序实战项目
  • 💕💕文末获取源码联系计算机编程果茶熊

二、系统介绍

  • 后端开发语言:Java+Python(两个版本都支持)
  • 后端框架:Spring Boot(Spring+SpringMVC+Mybatis)+Django(两个版本都支持)
  • 前端:uni-app+微信小程序+安卓
  • 数据库:MySQL
  • 系统架构:B/S
  • 《简易旅行旅游小程序》是一个基于B/S架构的综合性旅游服务平台,采用Java/Python双版本支持的后端开发方案,分别基于Spring Boot(Spring+SpringMVC+Mybatis)和Django框架实现核心业务逻辑。前端采用uni-app结合微信小程序和安卓平台开发,实现了多端统一部署,数据存储依托MySQL数据库。系统功能全面覆盖旅游服务各环节,包括用户管理、景点分类与信息管理、门票订单管理、美食分类与信息管理、特产分类与信息管理、酒店房型与信息管理、酒店预订管理、游记类型管理、旅游攻略管理、红色故事管理等核心模块,同时提供完善的系统管理、订单管理和个人中心功能。该系统为用户提供了从旅游信息浏览、攻略查询到景点门票购买、酒店预订、特产选购的一站式服务体验,满足了现代旅游者对便捷、全面旅游服务的需求,通过小程序形式实现了随时随地的旅游资源获取与预订管理。

三、简易旅行旅游小程序-视频解说

Python+Django+uni-app开发的简易旅行旅游小程序:集景点、美食、特产、酒店于一体的全功能实现

四、简易旅行旅游小程序-功能展示

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

五、简易旅行旅游小程序-代码展示


// 核心功能1:景点信息管理服务
@Service
public class ScenicSpotServiceImpl implements ScenicSpotService {
    
    @Autowired
    private ScenicSpotMapper scenicSpotMapper;
    
    @Autowired
    private CategoryMapper categoryMapper;
    
    @Override
    @Transactional
    public ResponseResult addScenicSpot(ScenicSpotDTO spotDTO) {
        // 数据校验
        if (StringUtils.isBlank(spotDTO.getName()) || spotDTO.getCategoryId() == null) {
            return ResponseResult.error("景点名称和分类不能为空");
        }
        
        // 检查分类是否存在
        Category category = categoryMapper.selectById(spotDTO.getCategoryId());
        if (category == null) {
            return ResponseResult.error("所选分类不存在");
        }
        
        // 检查景点名称是否重复
        ScenicSpot existSpot = scenicSpotMapper.selectByName(spotDTO.getName());
        if (existSpot != null) {
            return ResponseResult.error("景点名称已存在");
        }
        
        // 处理景点图片
        String mainImage = spotDTO.getMainImage();
        if (StringUtils.isNotBlank(mainImage) && mainImage.startsWith("temp/")) {
            String newPath = "scenic/" + UUID.randomUUID().toString() + mainImage.substring(mainImage.lastIndexOf("."));
            FileUtil.moveFile(mainImage, newPath);
            spotDTO.setMainImage(newPath);
        }
        
        // 构建景点实体并保存
        ScenicSpot scenicSpot = new ScenicSpot();
        BeanUtils.copyProperties(spotDTO, scenicSpot);
        scenicSpot.setCreateTime(new Date());
        scenicSpot.setUpdateTime(new Date());
        scenicSpot.setVisitCount(0);
        scenicSpot.setStatus(1);
        
        // 保存景点信息
        scenicSpotMapper.insert(scenicSpot);
        
        // 处理景点详情图片
        if (spotDTO.getDetailImages() != null && !spotDTO.getDetailImages().isEmpty()) {
            List<ScenicSpotImage> images = new ArrayList<>();
            for (String imgPath : spotDTO.getDetailImages()) {
                ScenicSpotImage image = new ScenicSpotImage();
                image.setScenicId(scenicSpot.getId());
                image.setImageUrl(imgPath);
                images.add(image);
            }
            scenicSpotMapper.batchInsertImages(images);
        }
        
        return ResponseResult.success("景点添加成功", scenicSpot.getId());
    }
}

// 核心功能2:酒店预订管理
@Service
public class HotelBookingServiceImpl implements HotelBookingService {

    @Autowired
    private HotelBookingMapper bookingMapper;
    
    @Autowired
    private HotelRoomMapper roomMapper;
    
    @Autowired
    private UserMapper userMapper;
    
    @Override
    @Transactional
    public ResponseResult createBooking(BookingDTO bookingDTO) {
        // 参数校验
        if (bookingDTO.getUserId() == null || bookingDTO.getRoomId() == null || 
            bookingDTO.getCheckInDate() == null || bookingDTO.getCheckOutDate() == null) {
            return ResponseResult.error("预订信息不完整");
        }
        
        // 检查日期是否合法
        Date checkIn = bookingDTO.getCheckInDate();
        Date checkOut = bookingDTO.getCheckOutDate();
        Date today = new Date();
        
        if (checkIn.before(today)) {
            return ResponseResult.error("入住日期不能早于今天");
        }
        
        if (checkOut.before(checkIn)) {
            return ResponseResult.error("离店日期不能早于入住日期");
        }
        
        // 计算入住天数
        long diffInMillies = Math.abs(checkOut.getTime() - checkIn.getTime());
        long days = TimeUnit.DAYS.convert(diffInMillies, TimeUnit.MILLISECONDS);
        if (days == 0) days = 1; // 至少住一天
        
        // 检查房间是否存在
        HotelRoom room = roomMapper.selectById(bookingDTO.getRoomId());
        if (room == null) {
            return ResponseResult.error("所选房间不存在");
        }
        
        // 检查房间是否可预订(是否有足够库存)
        if (room.getAvailableCount() <= 0) {
            return ResponseResult.error("所选房间已满");
        }
        
        // 检查该时间段内是否已有预订
        List<HotelBooking> existingBookings = bookingMapper.findConflictBookings(
            bookingDTO.getRoomId(), bookingDTO.getCheckInDate(), bookingDTO.getCheckOutDate());
        
        int bookedCount = existingBookings.stream()
                .filter(b -> b.getStatus() != BookingStatus.CANCELLED.getCode())
                .collect(Collectors.toList()).size();
        
        if (bookedCount >= room.getAvailableCount()) {
            return ResponseResult.error("所选日期该房型已满");
        }
        
        // 创建预订记录
        HotelBooking booking = new HotelBooking();
        BeanUtils.copyProperties(bookingDTO, booking);
        
        // 计算总价
        BigDecimal totalPrice = room.getPrice().multiply(new BigDecimal(days));
        booking.setTotalPrice(totalPrice);
        
        // 生成订单号
        String orderNo = "HB" + System.currentTimeMillis() + bookingDTO.getUserId();
        booking.setOrderNo(orderNo);
        booking.setStatus(BookingStatus.PENDING.getCode());
        booking.setCreateTime(new Date());
        
        // 保存预订信息
        bookingMapper.insert(booking);
        
        // 更新房间可用数量
        room.setAvailableCount(room.getAvailableCount() - 1);
        roomMapper.updateById(room);
        
        return ResponseResult.success("酒店预订成功", booking);
    }
}

// 核心功能3:旅游攻略管理
@Service
public class TravelGuideServiceImpl implements TravelGuideService {

    @Autowired
    private TravelGuideMapper guideMapper;
    
    @Autowired
    private GuideTypeMapper typeMapper;
    
    @Autowired
    private UserMapper userMapper;
    
    @Override
    @Transactional
    public ResponseResult publishGuide(TravelGuideDTO guideDTO) {
        // 数据校验
        if (StringUtils.isBlank(guideDTO.getTitle()) || StringUtils.isBlank(guideDTO.getContent()) || 
            guideDTO.getTypeId() == null || guideDTO.getUserId() == null) {
            return ResponseResult.error("攻略信息不完整");
        }
        
        // 检查用户是否存在
        User user = userMapper.selectById(guideDTO.getUserId());
        if (user == null) {
            return ResponseResult.error("用户不存在");
        }
        
        // 检查攻略类型是否存在
        GuideType type = typeMapper.selectById(guideDTO.getTypeId());
        if (type == null) {
            return ResponseResult.error("攻略类型不存在");
        }
        
        // 敏感词过滤
        String filteredTitle = sensitiveFilter(guideDTO.getTitle());
        String filteredContent = sensitiveFilter(guideDTO.getContent());
        
        if (!filteredTitle.equals(guideDTO.getTitle()) || !filteredContent.equals(guideDTO.getContent())) {
            return ResponseResult.error("内容包含敏感词,请修改后重新提交");
        }
        
        // 提取攻略内容中的图片
        List<String> images = extractImages(guideDTO.getContent());
        
        // 处理封面图片
        String coverImage = guideDTO.getCoverImage();
        if (StringUtils.isNotBlank(coverImage) && coverImage.startsWith("temp/")) {
            String newPath = "guide/" + UUID.randomUUID().toString() + coverImage.substring(coverImage.lastIndexOf("."));
            FileUtil.moveFile(coverImage, newPath);
            guideDTO.setCoverImage(newPath);
        } else if (StringUtils.isBlank(coverImage) && !images.isEmpty()) {
            // 如果没有封面图,使用内容中的第一张图作为封面
            guideDTO.setCoverImage(images.get(0));
        }
        
        // 生成摘要
        String summary = generateSummary(guideDTO.getContent());
        
        // 构建攻略实体并保存
        TravelGuide guide = new TravelGuide();
        BeanUtils.copyProperties(guideDTO, guide);
        guide.setSummary(summary);
        guide.setPublishTime(new Date());
        guide.setUpdateTime(new Date());
        guide.setViewCount(0);
        guide.setLikeCount(0);
        guide.setCommentCount(0);
        guide.setStatus(1);
        
        // 保存攻略信息
        guideMapper.insert(guide);
        
        // 保存攻略与景点的关联
        if (guideDTO.getRelatedScenicIds() != null && !guideDTO.getRelatedScenicIds().isEmpty()) {
            List<GuideScenic> relations = new ArrayList<>();
            for (Long scenicId : guideDTO.getRelatedScenicIds()) {
                GuideScenic relation = new GuideScenic();
                relation.setGuideId(guide.getId());
                relation.setScenicId(scenicId);
                relations.add(relation);
            }
            guideMapper.batchInsertScenic(relations);
        }
        
        // 更新用户发布攻略数量
        user.setGuideCount(user.getGuideCount() + 1);
        userMapper.updateById(user);
        
        return ResponseResult.success("攻略发布成功", guide.getId());
    }
    
    // 敏感词过滤方法
    private String sensitiveFilter(String content) {
        // 实际项目中应使用DFA算法或其他高效的敏感词过滤算法
        // 这里简化处理
        List<String> sensitiveWords = Arrays.asList("敏感词1", "敏感词2", "敏感词3");
        String filtered = content;
        for (String word : sensitiveWords) {
            filtered = filtered.replaceAll(word, "***");
        }
        return filtered;
    }
    
    // 从HTML内容中提取图片URL
    private List<String> extractImages(String htmlContent) {
        List<String> images = new ArrayList<>();
        Pattern pattern = Pattern.compile("<img[^>]*src=\"([^\"]+)\"[^>]*>");
        Matcher matcher = pattern.matcher(htmlContent);
        while (matcher.find()) {
            images.add(matcher.group(1));
        }
        return images;
    }
    
    // 生成内容摘要
    private String generateSummary(String content) {
        // 移除HTML标签
        String plainText = content.replaceAll("<[^>]+>", "");
        // 截取前100个字符作为摘要
        if (plainText.length() > 100) {
            return plainText.substring(0, 100) + "...";
        }
        return plainText;
    }
}

六、简易旅行旅游小程序-文档展示

在这里插入图片描述

七、END

致谢

💕💕文末获取源码联系计算机编程果茶熊