当前位置:首页 > 技术 > 正文内容

老年人景区订票系统设计与实现:基于SpringBoot+Vue+uniapp

访客 技术 2026年6月30日 1

系统概述

本文介绍了一款专为老年群体设计的景区订票系统,采用前后端分离架构,后端基于SpringBoot框架,前端使用Vue.js框架,并集成uniapp实现跨平台应用。该系统旨在为老年人提供便捷、易用的景区门票预订服务,充分考虑了老年用户的使用习惯和需求特点。

技术架构

后端技术:SpringBoot

SpringBoot作为后端核心框架,提供了内嵌的Tomcat服务器,简化了部署流程。其自动配置功能能够根据项目依赖关系自动完成应用程序配置,显著降低了开发复杂度。框架提供了丰富的开箱即用功能,包括Spring Data、Spring Security等,加速了开发进程,同时便于后续功能扩展和技术集成。

前端技术:Vue.js

Vue.js采用虚拟DOM技术,通过响应式数据绑定和组件化开发模式,实现了高效的DOM操作和界面更新。当数据发生变化时,UI会自动更新,使开发者能够专注于业务逻辑而非繁琐的界面更新工作,体现了Vue框架简洁、灵活、高效的特点。

数据持久化:MyBatisPlus

MyBatisPlus作为MyBatis的增强工具,简化了数据访问层的开发工作。它支持多种数据库,提供了丰富的API和注解,减少了手写SQL的工作量。同时,代码生成器可自动生成实体类、Mapper接口及XML映射文件,支持分页查询、动态查询等高级功能,大幅提升了开发效率。

系统功能设计

系统主要包含用户管理、景点信息展示、门票预订、订单管理、支付处理等功能模块。针对老年用户特点,系统特别优化了界面交互设计,采用大字体、高对比度配色,简化操作流程,提供语音辅助功能等,确保老年用户能够轻松使用。

系统测试与验证

测试目标

系统测试旨在从多角度发现潜在问题,确保系统功能完善、逻辑顺畅。测试过程严格遵循需求规格说明书,验证系统是否符合设计要求,并站在用户角度考虑各种使用场景,确保系统在实际应用中稳定可靠。

功能测试

系统采用黑盒测试方法,对各功能模块进行全面测试。重点测试了用户登录、景点浏览、门票预订、订单管理等核心功能,验证了边界条件处理、必填项验证、权限控制等关键点。测试结果表明,系统各项功能运行正常,符合设计预期。

测试结论

经过全面测试,系统在功能和性能方面均满足设计要求,流程正确,逻辑清晰。系统界面友好,操作简便,特别适合老年用户使用。测试过程中发现的问题已得到妥善解决,系统可投入实际使用。

核心代码实现

用户认证模块

@IgnoreAuth
@PostMapping("/login")
public R authenticate(String username, String password, String captcha, HttpServletRequest request) {
   UserEntity user = userService.queryOne(new QueryWrapper<UserEntity>().eq("username", username));
   if(user == null || !user.getPassword().equals(password)) {
      return R.error("用户名或密码错误");
   }
   String token = tokenService.createToken(user.getId(), username, "users", user.getRole());
   return R.ok().put("token", token);
}

@Override
public String createToken(Long userId, String username, String tableName, String role) {
   TokenEntity tokenEntity = this.getOne(new QueryWrapper<TokenEntity>()
        .eq("userid", userId)
        .eq("role", role));
   String token = RandomUtil.randomString(32);
   Calendar cal = Calendar.getInstance();   
   cal.setTime(new Date());   
   cal.add(Calendar.HOUR_OF_DAY, 1);
   
   if(tokenEntity != null) {
      tokenEntity.setToken(token);
      tokenEntity.setExpiryTime(cal.getTime());
      this.updateById(tokenEntity);
   } else {
      this.save(new TokenEntity(userId, username, tableName, role, token, cal.getTime()));
   }
   return token;
}

权限拦截器


@Component
public class AuthInterceptor implements HandlerInterceptor {

    public static final String AUTH_TOKEN_KEY = "Authorization";

    @Autowired
    private TokenService tokenService;
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 
        throws Exception {
        
        // 配置跨域支持
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Headers", 
            "x-requested-with,request-source,Authorization, Origin,imgType, Content-Type, cache-control");
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        
        // 处理OPTIONS预检请求
        if(request.getMethod().equals(HttpMethod.OPTIONS.name())) {
            response.setStatus(HttpStatus.OK.value());
            return false;
        }
        
        SkipAuth annotation;
        if(handler instanceof HandlerMethod) {
            annotation = ((HandlerMethod) handler).getMethodAnnotation(SkipAuth.class);
        } else {
            return true;
        }

        // 获取请求头中的token
        String token = request.getHeader(AUTH_TOKEN_KEY);
        
        // 不需要验证权限的方法直接放行
        if(annotation != null) {
            return true;
        }
        
        TokenEntity tokenEntity = null;
        if(StringUtils.isNotBlank(token)) {
            tokenEntity = tokenService.getTokenByTokenString(token);
        }
        
        if(tokenEntity != null) {
            request.getSession().setAttribute("userId", tokenEntity.getUserId());
            request.getSession().setAttribute("role", tokenEntity.getRole());
            request.getSession().setAttribute("tableName", tokenEntity.getTableName());
            request.getSession().setAttribute("username", tokenEntity.getUsername());
            return true;
        }
        
        // 返回未登录提示
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        response.getWriter().print(JSON.toJSONString(R.error(401, "请先登录")));
        return false;
    }
}

数据库设计

用户认证表


-- 用户认证表
DROP TABLE IF EXISTS `user_token`;
CREATE TABLE `user_token` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `user_id` bigint(20) NOT NULL COMMENT '用户ID',
  `username` varchar(100) NOT NULL COMMENT '用户名',
  `table_name` varchar(100) DEFAULT NULL COMMENT '关联表名',
  `role` varchar(100) DEFAULT NULL COMMENT '用户角色',
  `token` varchar(200) NOT NULL COMMENT '认证令牌',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `expiry_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '过期时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8 COMMENT='用户认证令牌表';

-- 示例数据
INSERT INTO `user_token` VALUES 
('1', '1', 'admin', 'users', '管理员', 'h1pqzsb9bldh93m92j9m2sljy9bt1wdh', '2023-02-27 19:37:01', '2023-03-17 18:23:02'),
('2', '2', 'elderly_user', 'elderly_users', '老年用户', 'zdm7j8h1wnfe27pkxyiuzvxxy27ykl2a', '2023-03-15 12:58:08', '2023-03-15 14:03:48');

景点信息表


-- 景点信息表
DROP TABLE IF EXISTS `scenic_spot`;
CREATE TABLE `scenic_spot` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '景点ID',
  `name` varchar(100) NOT NULL COMMENT '景点名称',
  `description` text COMMENT '景点描述',
  `location` varchar(200) NOT NULL COMMENT '景点位置',
  `ticket_price` decimal(10,2) NOT NULL COMMENT '门票价格',
  `discount_price` decimal(10,2) DEFAULT NULL COMMENT '优惠价格',
  `image_url` varchar(255) DEFAULT NULL COMMENT '景点图片',
  `status` tinyint(1) DEFAULT '1' COMMENT '状态:1-开放,0-关闭',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='景点信息表';

系统部署

系统采用Docker容器化部署,前后端分离架构。后端服务打包为jar包运行,前端项目构建后部署至Nginx服务器。数据库使用MySQL,通过数据卷持久化存储。系统支持水平扩展,可根据访问量灵活调整服务实例数量。

系统优化

针对老年用户特点,系统在界面设计上进行了特别优化,包括:

  • 采用大字体、高对比度配色方案
  • 简化操作流程,减少操作步骤
  • 提供语音辅助功能,支持语音导航
  • 增加紧急求助按钮,方便老年用户获取帮助
  • 优化加载速度,减少等待时间

在性能优化方面,系统实现了缓存机制、异步处理、数据库索引优化等措施,确保系统在高并发情况下仍能保持良好性能。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。