美食网站基于SpringBoot+Vue+UniApp的开发实现
技术架构概述
本项目采用SpringBoot作为后端框架,Vue用于前端交互,UniApp实现跨平台支持,结合MyBatis-Plus完成数据持久化操作。
后端框架:SpringBoot
SpringBoot内置了嵌入式服务器(如Tomcat、Jetty等),通过自动配置功能简化了依赖管理。开发者无需手动配置每个组件,即可快速搭建高效的应用程序。此外,Spring Boot还集成了Spring Data、Spring Security和Spring Cloud等插件,增强了系统的扩展性和安全性。
前端框架:Vue
Vue的核心特性包括响应式数据绑定、虚拟DOM和组件化开发。这些特性使得开发者可以专注于业务逻辑处理,而无需关心UI的手动更新。当数据发生变化时,Vue会自动触发视图更新,从而提升了开发效率和代码可维护性。
持久层框架:MyBatis-Plus
MyBatis-Plus是MyBatis的增强工具,提供了丰富的API和注解支持,极大减少了手写SQL的工作量。它支持多种数据库(如MySQL、Oracle等),并具备分页查询、动态条件构造、乐观锁控制等功能,帮助开发者更高效地完成数据访问层的开发。
系统测试方案
为确保系统的稳定性和功能性,我们从多个角度对系统进行了全面测试。
登录功能测试
以下是针对登录模块设计的测试用例:
| 输入数据 | 预期结果 | 实际结果 | 结果分析 |
|---|---|---|---|
| 用户名:admin 密码:123456 验证码:正确 | 成功登录 | 成功登录 | 符合预期 |
| 用户名:admin 密码:错误密码 验证码:正确 | 提示密码错误 | 提示密码错误 | 符合预期 |
| 用户名:admin 密码:123456 验证码:错误 | 提示验证码错误 | 提示验证码错误 | 符合预期 |
| 用户名:空 密码:123456 验证码:正确 | 提示用户名不能为空 | 提示用户名不能为空 | 符合预期 |
| 用户名:admin 密码:空 验证码:正确 | 提示密码不能为空 | 提示密码不能为空 | 符合预期 |
用户管理功能测试
以下是针对用户管理模块设计的测试用例:
| 输入数据 | 预期结果 | 实际结果 | 结果分析 |
|---|---|---|---|
| 填写完整用户信息 | 添加成功,用户显示在列表中 | 添加成功,用户显示在列表中 | 符合预期 |
| 修改现有用户信息 | 修改成功,用户信息更新 | 修改成功,用户信息更新 | 符合预期 |
| 删除用户 | 系统询问是否确认删除,删除后用户不在列表中 | 系统询问是否确认删除,删除后用户不在列表中 | 符合预期 |
| 不填写用户名尝试添加 | 提示用户名不能为空 | 提示用户名不能为空 | 符合预期 |
| 添加已存在的用户名 | 提示用户名重复 | 提示用户名重复 | 符合预期 |
代码示例
登录接口实现
@RestController
@RequestMapping("/auth")
public class AuthController {
@PostMapping("/login")
public Result login(@RequestParam String username,
@RequestParam String password,
@RequestParam String captcha,
HttpServletRequest request) {
User user = userService.findByUsername(username);
if (user == null || !passwordEncoder.matches(password, user.getPassword())) {
return Result.fail("用户名或密码错误");
}
String token = jwtService.generateToken(user.getId(), user.getRole());
return Result.success().addData("token", token);
}
}
Token生成逻辑
@Service
public class JwtService {
public String generateToken(Long userId, String role) {
Calendar expiration = Calendar.getInstance();
expiration.add(Calendar.HOUR_OF_DAY, 1);
Map claims = new HashMap<>();
claims.put("userId", userId);
claims.put("role", role);
return Jwts.builder()
.setClaims(claims)
.setExpiration(expiration.getTime())
.signWith(SignatureAlgorithm.HS256, "secretKey")
.compact();
}
}
权限拦截器
@Component
public class AuthInterceptor implements HandlerInterceptor {
private static final String AUTH_HEADER = "Authorization";
@Autowired
private JwtService jwtService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod method = (HandlerMethod) handler;
if (method.getMethodAnnotation(IgnoreAuth.class) != null) {
return true;
}
String authHeader = request.getHeader(AUTH_HEADER);
if (StringUtils.isBlank(authHeader) || !authHeader.startsWith("Bearer ")) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
return false;
}
String token = authHeader.substring(7);
try {
Claims claims = jwtService.parseToken(token);
request.setAttribute("userId", claims.get("userId"));
request.setAttribute("role", claims.get("role"));
return true;
} catch (Exception e) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
return false;
}
}
}
数据库结构
-- 用户Token表结构
DROP TABLE IF EXISTS `user_token`;
CREATE TABLE `user_token` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` bigint NOT NULL COMMENT '用户ID',
`username` varchar(50) NOT NULL COMMENT '用户名',
`role` varchar(50) DEFAULT NULL COMMENT '角色',
`token` varchar(200) NOT NULL COMMENT 'Token值',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`expires_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '过期时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户Token表';
-- 示例数据
INSERT INTO `user_token` VALUES (1, 1, 'admin', '管理员', 'abc123def456ghi789', '2023-03-01 10:00:00', '2023-03-02 10:00:00');