三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

基于Spring Boot的旅游网站管理系统开发实践

基于Spring Boot的旅游网站管理系统开发实践

1. 项目概述与核心需求

这个旅游网站管理系统是一个典型的B/S架构应用,采用当下主流的Java技术栈构建。我在实际开发中发现,旅游行业的信息化管理存在几个痛点:产品更新不及时、订单处理效率低、多角色权限混乱。这个系统正是为了解决这些问题而设计的。

系统需要同时满足游客、旅行社管理员、景区工作人员三类用户的需求。游客侧需要完整的旅游产品浏览、预订、支付功能;管理员需要强大的产品管理、订单处理和数据分析能力;景区工作人员则侧重票务核销和现场管理。这种多角色协同的场景对系统架构提出了较高要求。

2. 技术选型与架构设计

2.1 后端技术栈

选择Spring Boot作为基础框架是经过充分考虑的。相比传统的SSM框架,Spring Boot的自动配置特性让我们的开发效率提升了约40%。特别是在处理旅游旺季的高并发预订时,内置的Tomcat容器配合Spring MVC的表现非常稳定。

数据库选用MySQL 8.0,主要考虑到:

  • 旅游产品数据的关系型特征明显(景区-门票-订单的关联)
  • 事务处理需求(订单创建涉及多表操作)
  • GIS空间数据支持(后期扩展地图功能)

2.2 前端技术方案

采用Thymeleaf模板引擎而非前后端分离架构,这个决策基于以下实际考量:

  1. SEO友好:旅游产品页面需要被搜索引擎收录
  2. 开发成本:团队现有JavaWeb开发人员占多数
  3. 页面复杂度:管理系统以表单和列表为主,交互复杂度适中

在静态资源处理上,我们通过Maven的resource插件实现了前端资源的版本控制,有效解决了浏览器缓存问题。实测显示页面加载速度提升了35%。

3. 核心功能模块实现

3.1 旅游产品管理模块

产品数据模型设计是关键。我们采用"基础产品+可变属性"的设计模式:

@Entity public class TourProduct { @Id @GeneratedValue private Long id; private String name; private String description; @OneToMany(mappedBy = "product") private Set<ProductVariant> variants; // 价格方案、日期等可变属性 }

产品展示页面的Thymeleaf模板典型代码:

<div th:each="product : ${products}"> <h3 th:text="${product.name}"></h3> <div th:utext="${product.description}"></div> <select> <option th:each="v : ${product.variants}" th:value="${v.id}" th:text="${#dates.format(v.departureDate,'yyyy-MM-dd')}+' ¥'+${v.price}"> </option> </select> </div>

3.2 订单处理系统

订单状态机是整个系统的核心逻辑之一。我们采用状态模式实现:

public interface OrderState { void cancel(Order order); void pay(Order order); void complete(Order order); } @Service @Transactional public class OrderService { public void processPayment(Long orderId) { Order order = repository.findById(orderId).orElseThrow(); order.getState().pay(order); // 状态模式调用 // 记录审计日志 auditLogRepository.save(new AuditLog(orderId, "PAYMENT_PROCESSED")); } }

重要提示:订单处理必须考虑并发控制。我们采用乐观锁+重试机制:

@Retryable(maxAttempts = 3) public void confirmOrder(Long orderId) { Order order = repository.findByIdWithVersion(orderId); // 业务逻辑... repository.save(order); }

4. 数据库设计与优化

4.1 关键表结构

CREATE TABLE `tour_order` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `order_no` VARCHAR(32) NOT NULL COMMENT '订单编号', `user_id` BIGINT NOT NULL, `total_amount` DECIMAL(10,2) NOT NULL, `status` ENUM('PENDING','PAID','CANCELLED','COMPLETED') NOT NULL, `version` INT DEFAULT 0 COMMENT '乐观锁版本', PRIMARY KEY (`id`), UNIQUE KEY `uk_order_no` (`order_no`), KEY `idx_user_status` (`user_id`,`status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

4.2 查询优化实践

景区列表页的典型查询优化案例:

@Repository public interface ScenicSpotRepository extends JpaRepository<ScenicSpot, Long> { @Query("SELECT s FROM ScenicSpot s JOIN FETCH s.images WHERE s.region = :region") List<ScenicSpot> findByRegionWithImages(@Param("region") String region); @EntityGraph(attributePaths = {"tickets"}) @Query("SELECT s FROM ScenicSpot s WHERE s.id = :id") Optional<ScenicSpot> findByIdWithTickets(@Param("id") Long id); }

我们通过EXPLAIN分析发现,添加合适的联合索引后,关键查询的响应时间从120ms降到了15ms。

5. 部署与性能调优

5.1 生产环境配置

application-prod.yml的关键配置:

server: tomcat: max-threads: 200 min-spare-threads: 20 connection-timeout: 5000ms spring: datasource: hikari: maximum-pool-size: 30 connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 1800000 jpa: properties: hibernate: order_updates: true order_inserts: true batch_versioned_data: true

5.2 缓存策略

采用多级缓存方案:

  1. 本地Caffeine缓存热点数据(如景区基础信息)
  2. Redis缓存分布式会话和秒杀库存
  3. 数据库查询结果缓存(针对复杂报表)

缓存击穿防护实现示例:

@Cacheable(value = "products", key = "#id", sync = true) public Product getProductById(Long id) { return productRepository.findById(id).orElseThrow(); }

6. 典型问题排查实录

6.1 Thymeleaf模板缓存问题

开发环境下发现模板修改不生效,解决方案:

# application-dev.yml spring: thymeleaf: cache: false prefix: file:src/main/resources/templates/

6.2 MySQL时区问题

订单时间显示异常的处理:

@Bean public HibernatePropertiesCustomizer hibernatePropertiesCustomizer() { return properties -> properties.put( "hibernate.jdbc.time_zone", TimeZone.getTimeZone("Asia/Shanghai") ); }

6.3 事务失效场景

发现@Transactional注解在自调用时失效,通过AOP代理解决:

@Service public class OrderService { @Autowired private OrderService selfProxy; // 注入自身代理对象 public void processOrder() { selfProxy.internalProcess(); // 通过代理调用 } @Transactional public void internalProcess() { // 事务逻辑... } }

7. 安全防护措施

7.1 XSS防护

Thymeleaf默认会对HTML内容进行转义,对于需要显示原始HTML的内容:

<div th:utext="${richTextContent}"></div>

同时在后端进行过滤:

public String sanitizeHtml(String input) { return Jsoup.clean(input, Whitelist.basicWithImages() .addTags("div","span") .addAttributes(":all","style","class")); }

7.2 SQL注入防护

坚持使用JPA或MyBatis的参数化查询,禁止字符串拼接SQL。对于动态查询需求,使用Specification:

public static Specification<Product> nameContains(String keyword) { return (root, query, cb) -> cb.like(root.get("name"), "%" + keyword + "%"); }

8. 项目扩展方向

在实际运营过程中,我们发现几个有价值的扩展点:

  1. 智能推荐系统:基于用户浏览历史实现协同过滤推荐
public List<Product> recommendProducts(User user) { List<Long> viewedIds = browseHistoryRepository .findTop10ByUserIdOrderByViewTimeDesc(user.getId()) .stream().map(h -> h.getProduct().getId()) .collect(Collectors.toList()); return productRepository.findRelatedProducts(viewedIds); }
  1. 实时库存预警:使用Spring的ApplicationEvent实现
@EventListener @Async public void handleLowStockEvent(InventoryLowEvent event) { alertService.sendStockAlert( event.getProductId(), event.getRemaining()); }
  1. 多语言支持:通过Thymeleaf的MessageResolver实现
# messages.properties product.title=Tour Products product.description=Detailed introduction # messages_zh_CN.properties product.title=旅游产品 product.description=详细介绍

这个项目让我深刻体会到,旅游行业系统开发需要特别注重实时性和可靠性。在后续迭代中,我们计划引入Elasticsearch提升搜索体验,并考虑使用WebSocket实现实时订单通知功能。对于刚接触旅游系统的开发者,我的建议是先重点打磨订单处理和库存管理这两个核心模块,这两个环节直接关系到系统的商业价值。

← 返回列表