SpringBoot2 仿B站高性能前端+后端项目
xia讠果☛
lexuecode.com/7338.html
搭建数据库与持久层框架
1. 需求分析与规划
- 业务需求:明确应用程序需要存储哪些数据,以及数据之间的关系。
- 性能需求:评估数据的读写频率、并发量和预期的负载。
- 数据一致性:确定数据一致性和完整性的要求。
- 可扩展性:考虑未来数据增长和系统扩展的需求。
2. 数据库选择
- 关系型数据库:如MySQL、PostgreSQL、Oracle等,适用于结构化数据和复杂关系。
- 非关系型数据库:如MongoDB、Cassandra、Redis等,适用于非结构化数据或需要水平扩展的场景。
3. 数据库设计
- 数据模型:根据业务需求设计数据模型,包括表结构、字段、数据类型和索引。
- 关系设计:对于关系型数据库,设计表之间的关系,如一对一、一对多、多对多。
- 规范化:确保数据模型满足数据库规范化原则,减少数据冗余。
4. 数据库配置与部署
- 安装数据库:根据操作系统和环境安装合适的数据库软件。
- 配置数据库:设置数据库的连接参数、字符集、存储引擎等。
- 安全性:配置用户权限、加密连接等安全措施。
5. 持久层框架选择
- ORM(对象关系映射)框架:如Hibernate、Entity Framework、Django ORM等,将对象模型映射到关系模型。
- 数据访问框架:如MyBatis、JdbcTemplate等,提供数据访问的抽象和简化。
6. 持久层框架集成
- 配置数据源:在应用程序中配置数据库连接池和数据源。
- 实体类映射:定义实体类与数据库表的映射关系。
- SQL映射:编写或配置SQL语句,定义数据的查询、插入、更新和删除操作。
7. 事务管理
- 事务控制:确保数据操作的原子性、一致性、隔离性和持久性。
- 声明式事务:在ORM框架中使用注解或XML配置事务边界。
8. 测试与优化
- 单元测试:编写单元测试来验证数据访问逻辑的正确性。
- 性能测试:进行性能测试,优化SQL语句和索引。
- 监控:监控数据库性能和资源使用情况。
9. 部署与维护
- 备份与恢复:制定数据库备份策略,确保数据安全。
- 版本控制:随着应用的迭代,管理数据库架构的变更。
- 监控与调优:持续监控数据库性能,根据需要进行调优。
SpringBoot2 基于JWT的用户token验证
JWT的结构 JWT由三段信息用.连接构成的字符串。
Header.Payload.Signature 例如:
| eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxIn0.ihOZFzg3ZGIbBMneRy-4RMqors1P3nuO-wRJnQtTzWQ |
|---|
Header头部
承载两部分信息:token类型和采用的加密算法
{
"typ": "JWT",
"alg": "HS256"
}
token类型:JWT 加密算法:HS256
Payload负载
存放有效信息的地方
iss: jwt签发者 sub: jwt所面向的用户 aud: 接收jwt的一方 exp: 过期时间戳(jwt的过期时间,这个过期时间必须要大于签发时间) nbf: 定义在什么时间之前,该jwt都是不可用的 iat: jwt的签发时间 jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
Signature签名
对头部及负载内容进行签证。采用Header中声明的算法,接收三个参数:base64编码的Header、base64编码的Payload和密钥(secret)进行运算。密钥secret是保存在服务端的,服务端会根据这个密钥进行生成token和进行验证。
- 输入用户名和密码,进行登录 2. 服务器对登录用户进行认证(如果认证通过,根据用户的信息和JWT的生成规则生成token) 3. 服务器将该token字符串返回给用户 4. 当用户请求服务器API时,在请求的Header中加入token 5. 服务端进行校验(如果通过,则解析其中内容,根据其权限和业务逻辑给出响应结果。如果不通过,返回401) 6. 返回请求数据
SpringBoot集成JWT实现token验证步骤
1. 引入JWT依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
2. 自定义实体User类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
String Id;
String username;
String password;
}
3. 生成token方法
@Service("TokenService")
public class TokenService {
public String getToken(User user) {
String token="";
// 存入需要保存在token里的信息,这里把用户ID存入token
token= JWT.create().withAudience(user.getId())
.sign(Algorithm.HMAC256(user.getPassword()));
// 使用HMAC256加密算法生成token,密钥是用户的密码
return token;
}
}
4. 拦截器获取并验证token
public class AuthenticationInterceptor implements HandlerInterceptor {
@Autowired
UserService userService;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
// 从 http 请求头中取出 token
String token = httpServletRequest.getHeader("token");
// 如果不是映射到方法直接通过
if(!(object instanceof HandlerMethod)){
return true;
}
HandlerMethod handlerMethod=(HandlerMethod)object;
Method method=handlerMethod.getMethod();
// 检查是否有passtoken注释,有则跳过认证
if (method.isAnnotationPresent(PassToken.class)) {
PassToken passToken = method.getAnnotation(PassToken.class);
if (passToken.required()) {
return true;
}
}
// 检查有没有需要用户权限的注解
if (method.isAnnotationPresent(UserLoginToken.class)) {
UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
if (userLoginToken.required()) {
// 执行认证
if (token == null) {
throw new RuntimeException("无token,请重新登录");
}
// 获取 token 中的 userId
String userId;
try {
userId = JWT.decode(token).getAudience().get(0);
} catch (JWTDecodeException j) {
throw new RuntimeException("401");
}
User user = userService.findUserById(userId);
if (user == null) {
throw new RuntimeException("用户不存在,请重新登录");
}
// 验证 token
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
try {
jwtVerifier.verify(token);
} catch (JWTVerificationException e) {
throw new RuntimeException("401");
}
return true;
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
boolean preHandle()预处理回调方法,实现处理器的预处理,第三个参数为响应的处理器,自定义Controller 返回值为true表示继续流程(如调用下一个拦截器或处理器)或者接着执行postHandle()和afterCompletion() 返回值为false表示流程中断,不会继续调用其他的拦截器或处理器,中断执行
5. 配置拦截器 在配置类上添加了注解@Configuration,标明了该类是一个配置类并且会将该类作为一个SpringBean添加到IOC容器内
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
//addPathPatterns方法用于设置拦截器的过滤路径规则
public void addInterceptors(InterceptorRegistry registry) {
// 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
registry.addInterceptor(authenticationInterceptor())
.addPathPatterns("/**");
}
@Bean
public AuthenticationInterceptor authenticationInterceptor() {
return new AuthenticationInterceptor();
}
}
6. 数据访问接口
@RestController
@RequestMapping("api")
public class UserApi {
@Autowired
UserService userService;
@Autowired
TokenService tokenService;
//登录
@PostMapping("/login")
public Object login( User user){
JSONObject jsonObject=new JSONObject();
User userForBase=userService.findByUsername(user);
if(userForBase==null){
jsonObject.put("message","登录失败,用户不存在");
return jsonObject;
}else {
if (!userForBase.getPassword().equals(user.getPassword())){
jsonObject.put("message","登录失败,密码错误");
return jsonObject;
}else {
String token = tokenService.getToken(userForBase);
jsonObject.put("token", token);
jsonObject.put("user", userForBase);
return jsonObject;
}
}
}
@UserLoginToken
@GetMapping("/getMessage")
//登录注解,说明该接口必须登录获取token后,在请求头中加上token并通过验证才可以访问
public String getMessage(){
return "你已通过验证";
}
}