SpringBoot 仿B站后端项目实战
1. 搭建环境
1)项目架构
业务(功能)架构
用户服务: 注册登录 /大会员权限/ 查找视频
在线视频流播放+实时弹幕
管理后台 视频上传/数据统计/系统消息推送
技术架构
SpringBoot + MySql + Mybatis + Maven
部署架构
前端 : 服务转发 + 负载均衡
后端: 业务处理 + 功能实现
缓存 + 队列
2)开发环境搭建
Windows系统
IDEA软件
JDK1.8 / Maven
创建多环境、多模块项目
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/27484f1fcf243cca6043c05fcec0954d.png#pic_center)
配置JDK\Maven
IDEA 中 配置JDK
设置本地Maven setting文件
重写IDEA默认配置
配置模块间的依赖
添加SpringBoot依赖 pom依赖
启动入口
搭建数据库MySql和持久层框架MyBatis
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
3)热部署
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>2.6.4</version>
</dependency>
2.用户模块开发
Restful风格 *幂等性
POST (不具有幂等性)
1. 文章组发送消息
2. 注册用户
3. 提交表单
GET
DELETE
PUT 用于请求中的负载创建或者替换资源 具有幂等性(一次调用或多次调用等价,不会有副作用)
package com.mao.bilibili.api;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@RestController
public class RestfulApi {
private final Map<Integer,Map<String,Object>> datamap;
public RestfulApi(){
datamap = new HashMap<>();
for (int i = 1; i < 3; i++) {
HashMap<String, Object> data = new HashMap<>();
data.put("id",i);
data.put("name","name"+i);
datamap.put(i,data);
}
}
@GetMapping("/objects/{id}")
public Map<String,Object> getData(@PathVariable("id") Integer id){
return datamap.get(id);
}
@DeleteMapping("/objects/{id}")
public String deleteData(@PathVariable("id") Integer id){
datamap.remove(id);
return "delete success";
}
@PostMapping("/objects")
public String postData(@RequestBody Map<String,Object> data){
Integer[] ts = datamap.keySet().toArray(new Integer[0]);
Arrays.sort(ts);
int id = ts[ts.length - 1] + 1;
datamap.put(id,data);
return "post success";
}
@PutMapping("/objects")
public String putData(@RequestBody Map<String,Object> data){
Integer id = Integer.valueOf(String.valueOf(data.get("id")));
Map<String, Object> containedData = datamap.get(id);
if (containedData == null){
Integer[] ts = datamap.keySet().toArray(new Integer[0]);
Arrays.sort(ts);
int nextId = ts[ts.length - 1] + 1;
datamap.put(nextId,data);
}else {
datamap.put(id,data);
}
return "put success";
}
}
一些规范
通用功能与配置
Utils
Json数据返回类
package com.mao.bilibili.domain;
import lombok.Data;
/**
* @author 小毛同学
* @version 1.0
* @data 2022/3/15 17:06
*/
@Data
public class JsonResponse<T> {
private String code;
private String msg;
private T data;
public JsonResponse(String code,String msg){
this.code =code;
this.msg = msg;
}
public JsonResponse(T data){
this.data = data;
this.code = "0";
this.msg = "success";
}
// 成功返回前端无数据
public static JsonResponse<String> success(){
return new JsonResponse<String>(null);
}
// 返回前端有数据
public static JsonResponse<String> success(String data){
return new JsonResponse<>(data);
}
// 失败
public static JsonResponse<String> fail(){
return new JsonResponse<String>("1","fail");
}
// 返回特定状态码
public static JsonResponse<String> fail(String code,String msg){
return new JsonResponse<>(code, msg);
}
}
Json信息转换配置
@Configuration
public class JsonHttpMessageConverterConfig {
@Bean
@Primary
public HttpMessageConverters fastJsonHttpMessageConverters() {
FastJsonHttpMessageConverter messageConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
fastJsonConfig.setSerializerFeatures(
SerializerFeature.PrettyFormat,
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.WriteNullBooleanAsFalse,
SerializerFeature.DisableCircularReferenceDetect,
SerializerFeature.WriteMapNullValue,
SerializerFeature.MapSortField
);
messageConverter.setFastJsonConfig(fastJsonConfig);
return new HttpMessageConverters(messageConverter);
}
}
全局异常处理
@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CommonGlobalExceptionHandler {
@ExceptionHandler(value = Exception.class)
@ResponseBody
public JsonResponse<String> commonExceptionHandler(HttpServletRequest request,Exception e){
String errorMsg = e.getMessage();
if (e instanceof ConditionException){
String errorCode = ((ConditionException) e).getCode();
return new JsonResponse<>(errorCode,errorMsg);
}else {
return new JsonResponse<>("500",errorMsg);
}
}
}
public class ConditionException extends RuntimeException{
private static final long serialVersionUID = 1L;
private String code;
public ConditionException(String code,String name){
super(name);
this.code = code;
}
public ConditionException(String name){
super(name);
this.code = "500";
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
```java
{
super(name);
this.code = code;
}
public ConditionException(String name){
super(name);
this.code = "500";
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}