老年人景区订票系统设计与实现:基于SpringBoot+Vue+uniapp
系统概述
本文介绍了一款专为老年群体设计的景区订票系统,采用前后端分离架构,后端基于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,通过数据卷持久化存储。系统支持水平扩展,可根据访问量灵活调整服务实例数量。
系统优化
针对老年用户特点,系统在界面设计上进行了特别优化,包括:
- 采用大字体、高对比度配色方案
- 简化操作流程,减少操作步骤
- 提供语音辅助功能,支持语音导航
- 增加紧急求助按钮,方便老年用户获取帮助
- 优化加载速度,减少等待时间
在性能优化方面,系统实现了缓存机制、异步处理、数据库索引优化等措施,确保系统在高并发情况下仍能保持良好性能。