项目的架构
网关:1路由转发 2.认证鉴权(token)3.统一处理(跨域)
Mysql:关系型数据库
ES:搜索数据库
Redis:页面级缓存,会话状态存储
GitLab:私有托管平台
K8S:自动化部署、扩展和管理容器化应用程序的开源系统
Jenkins:自动化部署
1.环境搭建
创建一个父工程:依赖管理 版本锁定
子工程:具体业务实现
Controller编写规则:
1.映射路径
2.请求方式
3.请求参数
4.响应结果-返回值
2.专辑模块
2.1专辑管理添加
1.统一返回结果
package com.atguigu.tingshu.common.result;
import lombok.Data;
/**
* 全局统一返回结果类
*
*/
@Data
public class Result<T> {
//返回码
private Integer code;
//返回消息
private String message;
//返回数据
private T data;
public Result(){}
// 返回数据
protected static <T> Result<T> build(T data) {
Result<T> result = new Result<T>();
if (data != null)
result.setData(data);
return result;
}
public static <T> Result<T> build(T body, Integer code, String message) {
Result<T> result = build(body);
result.setCode(code);
result.setMessage(message);
return result;
}
public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {
Result<T> result = build(body);
result.setCode(resultCodeEnum.getCode());
result.setMessage(resultCodeEnum.getMessage());
return result;
}
public static<T> Result<T> ok(){
return Result.ok(null);
}
/**
* 操作成功
* @param data baseCategory1List
* @param <T>
* @return
*/
public static<T> Result<T> ok(T data){
Result<T> result = build(data);
return build(data, ResultCodeEnum.SUCCESS);
}
public static<T> Result<T> fail(){
return Result.fail(null);
}
/**
* 操作失败
* @param data
* @param <T>
* @return
*/
public static<T> Result<T> fail(T data){
Result<T> result = build(data);
return build(data, ResultCodeEnum.FAIL);
}
public Result<T> message(String msg){
this.setMessage(msg);
return this;
}
public Result<T> code(Integer code){
this.setCode(code);
return this;
}
}
2. 统一结果状态信息类
package com.atguigu.tingshu.common.result;
import lombok.Getter;
/**
* 统一返回结果状态信息类
*
*/
@Getter
public enum ResultCodeEnum {
SUCCESS(200,"成功"),
FAIL(201, "失败"),
SERVICE_ERROR(2012, "服务异常"),
DATA_ERROR(204, "数据异常"),
ILLEGAL_REQUEST(205, "非法请求"),
REPEAT_SUBMIT(206, "重复提交"),
ARGUMENT_VALID_ERROR(210, "参数校验异常"),
SIGN_ERROR(300, "签名错误"),
SIGN_OVERDUE(301, "签名已过期"),
LOGIN_AUTH(208, "未登陆"),
PERMISSION(209, "没有权限"),
ACCOUNT_ERROR(214, "账号不正确"),
PASSWORD_ERROR(215, "密码不正确"),
PHONE_CODE_ERROR(215, "手机验证码不正确"),
LOGIN_MOBLE_ERROR( 216, "账号不正确"),
ACCOUNT_STOP( 216, "账号已停用"),
NODE_ERROR( 217, "该节点下有子节点,不可以删除"),
VOD_FILE_ID_ERROR( 220, "声音媒体id不正确"),
XXL_JOB_ERROR(210, "调度操作失败"),
ACCOUNT_LESS(220, "账户余额不足"),
ACCOUNT_LOCK_ERROR(221, "账户余额锁定失败"),
ACCOUNT_UNLOCK_ERROR(221, "账户余额解锁失败"),
ACCOUNT_MINUSLOCK_ERROR(221, "账户余额扣减失败"),
ACCOUNT_LOCK_REPEAT(221, "重复锁定"),
ACCOUNT_LOCK_RESULT_NULL(221, "锁定账号结果对象为空"),
ORDER_SUBMIT_REPEAT(221, "超时或重复提交订单"),
NO_BUY_NOT_SEE(230, "未购买不能观看"),
EXIST_NO_EXPIRE_LIVE(230, "当前存在未过期直播"),
REPEAT_BUY_ERROR(231, "已经购买过该专辑"),
;
private Integer code;
private String message;
private ResultCodeEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
}
3.全局异常处理
package com.atguigu.tingshu.common.handler;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 全局异常处理类
*
*/
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody
public Result error(Exception e){
e.printStackTrace();
return Result.fail();
}
/**
* 自定义异常处理方法
* @param e
* @return
*/
@ExceptionHandler(GuiguException.class)
@ResponseBody
public Result error(GuiguException e){
return Result.build(null,e.getCode(), e.getMessage());
}
@ExceptionHandler({IllegalArgumentException.class})
@ResponseBody
public Result llegalArgumentException(Exception e) {
log.error("触发异常拦截: " + e.getMessage(), e);
return Result.build(null, ResultCodeEnum.ARGUMENT_VALID_ERROR);
}
@ExceptionHandler(value = BindException.class)
@ResponseBody
public Result error(BindException exception) {
BindingResult result = exception.getBindingResult();
Map<String, Object> errorMap = new HashMap<>();
List<FieldError> fieldErrors = result.getFieldErrors();
fieldErrors.forEach(error -> {
log.error("field: " + error.getField() + ", msg:" + error.getDefaultMessage());
errorMap.put(error.getField(), error.getDefaultMessage());
});
return Result.build(errorMap, ResultCodeEnum.ARGUMENT_VALID_ERROR);
}
@ExceptionHandler(value = MethodArgumentNotValidException.class)
@ResponseBody
public Result error(MethodArgumentNotValidException exception) {
BindingResult result = exception.getBindingResult();
Map<String, Object> errorMap = new HashMap<>();
List<FieldError> fieldErrors = result.getFieldErrors();
fieldErrors.forEach(error -> {
log.error("field: " + error.getField() + ", msg:" + error.getDefaultMessage());
errorMap.put(error.getField(), error.getDefaultMessage());
});
return Result.build(errorMap, ResultCodeEnum.ARGUMENT_VALID_ERROR);
}
}
4.自定义全局异常
package com.atguigu.tingshu.common.execption;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import lombok.Data;
/**
* 自定义全局异常类
*
*/
@Data
public class GuiguException extends RuntimeException {
private Integer code;
private String message;
/**
* 通过状态码和错误消息创建异常对象
* @param code
* @param message
*/
public GuiguException(Integer code, String message) {
super(message);
this.code = code;
this.message = message;
}
/**
* 接收枚举类型对象
* @param resultCodeEnum
*/
public GuiguException(ResultCodeEnum resultCodeEnum) {
super(resultCodeEnum.getMessage());
this.code = resultCodeEnum.getCode();
this.message = resultCodeEnum.getMessage();
}
@Override
public String toString() {
return "GuliException{" +
"code=" + code +
", message=" + this.getMessage() +
'}';
}
}
2.1.1 专辑分类列表(三级分类)
1.controller
package com.atguigu.tingshu.album.api;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.album.service.BaseCategoryService;
import com.atguigu.tingshu.common.result.Result;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@Tag(name = "分类管理")
@RestController
@RequestMapping(value = "/api/album")
@SuppressWarnings({"all"})
public class BaseCategoryApiController {
@Autowired
private BaseCategoryService baseCategoryService;
/**
* @description:
* @author: yanhongwei
* @date:
* @param: * @param null
* @return:
**/
/// api/album/category/getBaseCategoryList
@GetMapping(value = "/category/getBaseCategoryList")
public Result<List<JSONObject>> getBaseCategoryList() {
// public Result<List<Map<String, Object>>> getBaseCategoryList()
// JSONObject jsonObject = new JSONObject();
List<JSONObject> categoryList = baseCategoryService.getBaseCategoryList();
return Result.ok(categoryList);
}
}
2.impl
package com.atguigu.tingshu.album.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.album.mapper.BaseCategory1Mapper;
import com.atguigu.tingshu.album.mapper.BaseCategory2Mapper;
import com.atguigu.tingshu.album.mapper.BaseCategory3Mapper;
import com.atguigu.tingshu.album.mapper.BaseCategoryViewMapper;
import com.atguigu.tingshu.album.service.BaseCategoryService;
import com.atguigu.tingshu.model.album.BaseCategory1;
import com.atguigu.tingshu.model.album.BaseCategoryView;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.http.client.utils.CloneUtils;
import org.apache.kafka.common.utils.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@SuppressWarnings({"all"})
public class BaseCategoryServiceImpl extends ServiceImpl<BaseCategory1Mapper, BaseCategory1> implements BaseCategoryService {
@Autowired
private BaseCategoryViewMapper baseCategoryViewMapper;
@Override
public List<JSONObject> getBaseCategoryList() {
//创建一级集合,收集数据
List<JSONObject> allList = new ArrayList<>();
//查询所有分类
List<BaseCategoryView> baseCategoryViewsList = baseCategoryViewMapper.selectList(null);
//封装
if (CollectionUtil.isNotEmpty(baseCategoryViewsList)) {
//分组一级分类
Map<Long, List<BaseCategoryView>> collect1Map = baseCategoryViewsList.stream().collect(Collectors.groupingBy(BaseCategoryView::getCategory1Id));
for (Map.Entry<Long, List<BaseCategoryView>> Entry1 : collect1Map.entrySet()) {
//创建一级分类封装对象
JSONObject obj1 = new JSONObject();
//获取1级id 跟name
Long category1Id = Entry1.getKey();
List<BaseCategoryView> category2List = Entry1.getValue();
String category1Name = category2List.get(0).getCategory1Name();
obj1.put("categoryId", category1Id);
obj1.put("categoryName", category1Name);
//创建二级分类收集集合
List<JSONObject> array2 = new ArrayList<>();
//分组二级分类
Map<Long, List<BaseCategoryView>> collect2Map = category2List.stream().collect(Collectors.groupingBy(BaseCategoryView::getCategory2Id));
for (Map.Entry<Long, List<BaseCategoryView>> Entry2 : collect2Map.entrySet()) {
//创建二级分类封装对象
JSONObject obj2 = new JSONObject();
//获取2级分类id name
Long category2Id = Entry2.getKey();
List<BaseCategoryView> category3List = Entry2.getValue();
String category2Name = category3List.get(0).getCategory2Name();
obj2.put("categoryId", category2Id);
obj2.put("categoryName", category2Name);
List<JSONObject> array3 = category3List.stream().map(baseCategoryView -> {
JSONObject obj3 = new JSONObject();
obj3.put("categoryId", baseCategoryView.getCategory3Id());
obj3.put("categoryName", baseCategoryView.getCategory3Name());
return obj3;
}).collect(Collectors.toList());
obj2.put("categoryChild", array3);
//收集二级分类
array2.add(obj2);
}
//封装2级分类
obj1.put("categoryChild", array2);
//收集一级分类对象
allList.add(obj1);
}
System.out.println("collect = ");
}
return allList;
}
}
3.mapper
package com.atguigu.tingshu.album.mapper;
import com.atguigu.tingshu.model.album.BaseCategoryView;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface BaseCategoryViewMapper extends BaseMapper<BaseCategoryView> {
}
4. 视图
创建视图封装一些sql语句,不需要再多表查询了
BaseCategoryView
#创建视图
create view view_category01 as
select c3.id,
c1.id category1_id,
c1.name category1_name,
c2.id category2_id,
c2.name category2_name,
c3.id category3_id,
c3.name category3_name,
c3.is_deleted,
c3.create_time,
c3.update_time
from base_category1 c1
inner join base_category2 c2 on c1.id = c2.category1_id
inner join base_category3 c3 on c2.id = c3.category2_id
//
//
package com.atguigu.tingshu.model.album;
import com.atguigu.tingshu.model.base.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* <p>
* BaseCategoryView
* </p>
*
* @author atguigu
*/
@Data
@Schema(description = "分类视图")
@TableName("base_category_view")
public class BaseCategoryView extends BaseEntity {
private static final long serialVersionUID = 1L;
@Schema(description = "一级分类编号")
@TableField("category1_id")
private Long category1Id;
@Schema(description = "一级分类名称")
@TableField("category1_name")
private String category1Name;
@Schema(description = "二级分类编号")
@TableField("category2_id")
private Long category2Id;
@Schema(description = "二级分类名称")
@TableField("category2_name")
private String category2Name;
@Schema(description = "三级分类编号")
@TableField("category3_id")
private Long category3Id;
@Schema(description = "三级分类名称")
@TableField("category3_name")
private String category3Name;
}

2.1.2 查询一级分类下面的标签
1.controller
@GetMapping(value = "category/findAttribute/{category1Id}")
public Result<List<BaseAttribute>> findAttribute(@PathVariable Long category1Id) {
List<BaseAttribute> attributeList = baseCategoryService.findAttribute(category1Id);
return Result.ok(attributeList);
}
2.impl
package com.atguigu.tingshu.album.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.album.mapper.*;
import com.atguigu.tingshu.album.service.BaseCategoryService;
import com.atguigu.tingshu.model.album.BaseAttribute;