一、个人简介
- 💖💖作者:计算机编程果茶熊
- 💙💙个人简介:曾长期从事计算机专业培训教学,担任过编程老师,同时本人也热爱上课教学,擅长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
💕💕文末获取源码联系计算机编程果茶熊