java听书项目

项目的架构

网关: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;
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 BaseAttributeMapper baseAttributeMapper;

  
    @Override
    public List<BaseAttribute> findAttribute(Long category1Id) {

        return baseAttributeMapper.findAttribute(category1Id);
    }
}
 3.Mapper
package com.atguigu.tingshu.album.mapper;

import com.atguigu.tingshu.model.album.BaseAttribute;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface BaseAttributeMapper extends BaseMapper<BaseAttribute> {


    List<BaseAttribute> findAttribute(Long category1Id);
}
4.xml 
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >


<mapper namespace="com.atguigu.tingshu.album.mapper.BaseAttributeMapper">


    <resultMap id="baseAttributeMap" type="com.atguigu.tingshu.model.album.BaseAttribute" autoMapping="true">
        <id column="id" property="id"/>
        <collection property="attributeValueList" ofType="com.atguigu.tingshu.model.album.BaseAttributeValue" autoMapping="true">
            <id column="base_attribute_value_id" property="id"/>
        </collection>
    </resultMap>
    <select id="findAttribute" resultMap="baseAttributeMap">
        select
            ba.id,
            ba.category1_id,
            ba.attribute_name,
            bav.id base_attribute_value_id,
            bav.attribute_id,
            bav.value_name
        from base_attribute ba left join base_attribute_value bav on bav.attribute_id = ba.id
        where ba.category1_id = #{category1Id} and ba.is_deleted = 0
    </select>
</mapper>

2.1.3 上传图片

 1.controller
package com.atguigu.tingshu.album.api;

import com.atguigu.tingshu.album.service.FileUploadService;
import com.atguigu.tingshu.common.result.Result;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

@Tag(name = "上传管理接口")
@RestController
@RequestMapping("api/album")
public class FileUploadApiController {
    @Autowired
    private FileUploadService fileUploadService;


    /**
     * 将文件上传到分布式存储服务MinIO中
     *
     * @param file
     * @return
     */
    @Operation(summary = "将文件上传到分布式存储服务MinIO中")
    @PostMapping("/fileUpload")
    public Result<String> fileUpload(MultipartFile file) {
        String fileUrl = fileUploadService.imageUpload(file);
        return Result.ok(fileUrl);
    }
}
2.impl
package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import com.atguigu.tingshu.album.config.MinioConstantProperties;
import com.atguigu.tingshu.album.service.FileUploadService;
import com.atguigu.tingshu.common.execption.GuiguException;
import io.minio.*;
import io.minio.errors.MinioException;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;

/**
 * @version: java version 1.8
 * @Author: Mr Orange
 * @description:
 * @date: 2025-02-16 16:17
 */
@Service
public class FileUploadServiceImpl implements FileUploadService {
    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioConstantProperties minioConstantProperties;

    @Override
    @SneakyThrows
    public String imageUpload(MultipartFile file) {
        //校验是否为图片类型

        //1.业务校验验证文件是否为图片,借助ImageIO读取图片。继续判断图片文件后缀名是否符合要求,图片长宽
        BufferedImage read = ImageIO.read(file.getInputStream());
        if (read == null) {
            throw new GuiguException(400, "图片格式非法!");
        }
        // 判断桶是否存在
        boolean found =
                minioClient.bucketExists(BucketExistsArgs.builder().bucket(minioConstantProperties.getBucketName()).build());
        if (!found) {
            // Make a new bucket called 'asiatrip'.
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(minioConstantProperties.getBucketName()).build());
        } else {
            System.out.println("Bucket " + minioConstantProperties.getBucketName() + " already exists.");
        }
        //随机生成文件名称
        String folderName = "/" + DateUtil.today() + "/";
        //文件名
        String fileName = IdUtil.randomUUID();
        //获取后缀名
        String extName = FileUtil.extName(file.getOriginalFilename());  //
        //文件上传的路径
        String objectName = folderName + fileName + "." + extName;

        //2.文件上传
        minioClient.putObject(
                PutObjectArgs.builder().bucket(minioConstantProperties.getBucketName()).object(objectName).stream(
                                file.getInputStream(), file.getSize(), -1)
                        .contentType(file.getContentType())
                        .build());
        return minioConstantProperties.getEndpointUrl()+"/"+minioConstantProperties.getBucketName()+objectName;
    }
}
3.Nacos配置文件

 

 4.MinioClientConfig 配置类
package com.atguigu.tingshu.album.config;

import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @version: java version 1.8
 * @Author: Mr Orange
 * @description:
 * @date: 2025-02-16 16:22
 */
@Configuration
public class MinioClientConfig {
    @Autowired
    private MinioConstantProperties minioConstantProperties;

    @Bean
    public MinioClient minioClient() {
        return MinioClient.builder().
        endpoint(minioConstantProperties.getEndpointUrl()).
        credentials(minioConstantProperties.getAccessKey(), minioConstantProperties.getSecreKey()).
                build();
    }
}
5.MinioConstantProperties 
package com.atguigu.tingshu.album.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration
@ConfigurationProperties(prefix="minio") //读取节点
@Data
public class MinioConstantProperties {

    private String endpointUrl;
    private String accessKey;
    private String secreKey;
    private String bucketName;
}

2.1.4 添加专辑

 1.controller
package com.atguigu.tingshu.album.api;

import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Tag(name = "专辑管理")
@RestController
@RequestMapping("api/album")
@SuppressWarnings({"all"})
public class AlbumInfoApiController {

    @Autowired
    private AlbumInfoService albumInfoService;

//	/api/album/albumInfo/saveAlbumInfo

	@PostMapping("albumInfo/saveAlbumInfo")
    public Result saveAlbumInfo(@RequestBody AlbumInfoVo albumInfoVo){
        //获取用户id
        Long userId = AuthContextHolder.getUserId();
        albumInfoService.saveAlbumInfo(albumInfoVo,userId);
        return Result.ok();
    }
}

2.impl

将前端传递的参数分别添加到对应的3表当中

package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.atguigu.tingshu.album.mapper.AlbumAttributeValueMapper;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private AlbumAttributeValueMapper albumAttributeValueMapper;

    @Autowired
    private AlbumStatMapper albumStatMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveAlbumInfo(AlbumInfoVo albumInfoVo,Long userId) {
        //拷贝数据创建保存对象
        AlbumInfo albumInfo = BeanUtil.copyProperties(albumInfoVo, AlbumInfo.class);
        //设置用户ID
        albumInfo.setUserId(userId);
        //设置免费试听集数
        albumInfo.setTracksForFree(5);
        //设置状态 是否审核通过
        albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);

        //保存专辑信息
        albumInfoMapper.insert(albumInfo);

        //保存专辑属性
        List<AlbumAttributeValue> albumAttributeValueVoList = albumInfo.getAlbumAttributeValueVoList();

        //判断
        if(CollectionUtil.isEmpty(albumAttributeValueVoList)){
            throw new GuiguException(400,"专辑信息不完整");
        }
        for (AlbumAttributeValue albumAttributeValue : albumAttributeValueVoList) {
            albumAttributeValue.setAlbumId(albumInfo.getId());
            albumAttributeValueMapper.insert(albumAttributeValue);
        }


        //保存专辑统计信息
        this.saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_PLAY,0);
        this.saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_SUBSCRIBE,0);
        this.saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_BUY,0);
        this.saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_COMMENT,0);
    }

    private void saveAlbumStat(Long id, String albumStatPlay, int i) {
        AlbumStat albumStat = new AlbumStat();
        albumStat.setAlbumId(id);
        albumStat.setStatType(albumStatPlay);
        albumStat.setStatNum(i);
        albumStatMapper.insert(albumStat);
    }
}

 

2.2查看专辑列表

将专辑表跟统计表联合查询得到

select
    ai.id albumId,
    ai.album_title,
    ai.cover_url,
    ai.include_track_count,
    ai.is_finished,
    ai.status,
    ast.stat_type,
    ast.stat_num
from album_info ai
         inner join album_stat as ast
                    on ai.id = ast.album_id
where ai.user_id = ?
  and ai.status = ?
  and ai.album_title like ?
  and ai.is_deleted = 0
order by ai.id desc

不是前端需要的数据行转列

select
    ai.id albumId,
    ai.album_title,
    ai.cover_url,
    ai.include_track_count,
    ai.is_finished,
    ai.status,
#     ast.stat_type,
#     ast.stat_num,
    max(if(ast.stat_type='0401',ast.stat_num,0)) playStatNum,
    max(if(ast.stat_type='0402',ast.stat_num,0)) subscribeStatNum,
    max(if(ast.stat_type='0403',ast.stat_num,0)) buyStatNum,
    max(if(ast.stat_type='0404',ast.stat_num,0)) albumCommentStaNum
from album_info ai
         inner join album_stat as ast
                    on ai.id = ast.album_id
where ai.user_id = ?
  and ai.status = ?
  and ai.album_title like ?
  and ai.is_deleted = 0
group by ai.id
order by ai.id desc;

 2.2.1controller
public class AlbumInfoApiController {

    @Autowired
    private AlbumInfoService albumInfoService;


    //    /api/album/albumInfo/findUserAlbumPage/{page}/{limit}
    @PostMapping("albumInfo/findUserAlbumPage/{page}/{limit}")
    public Result<Page<AlbumListVo>> findUserAlbumPage(@PathVariable Long page,
                                                       @PathVariable Long limit,
                                                       @RequestBody AlbumInfoQuery albumInfoQuery) {
        //封装Page对象
        Page<AlbumListVo> albumListVoPage = new Page<>(page, limit);
        //获取用户Id
        Long userId = AuthContextHolder.getUserId();
        //封装查询对象条件
        albumInfoQuery.setUserId(userId);
        //调用service查询
        albumListVoPage = albumInfoService.findUserAlbumPage(albumListVoPage, albumInfoQuery);
        return Result.ok(albumListVoPage);
    }
2.impl
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    /*
     * @description: 根据用户ID查询专辑列表
     * @author: yanhongwei
     * @date:
     * @param:  * @param null
     * @return:
     **/
    @Override
    public Page<AlbumListVo> findUserAlbumPage(Page<AlbumListVo> albumListVoPage, AlbumInfoQuery albumInfoQuery) {

        return albumInfoMapper.selectUserAlbumPage(albumListVoPage,albumInfoQuery);
    }}
3.Mapper
package com.atguigu.tingshu.album.mapper;

import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface AlbumInfoMapper extends BaseMapper<AlbumInfo> {

    Page<AlbumListVo> selectUserAlbumPage(@Param("albumListVoPage") Page<AlbumListVo> albumListVoPage, @Param("vo") AlbumInfoQuery albumInfoQuery);
}
 4.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >


<mapper namespace="com.atguigu.tingshu.album.mapper.AlbumInfoMapper">


    <select id="selectUserAlbumPage" resultType="com.atguigu.tingshu.vo.album.AlbumListVo">
        select
        ai.id albumId,
        ai.album_title,
        ai.cover_url,
        ai.include_track_count,
        ai.is_finished,
        ai.status,
        max(if(ast.stat_type='0401',ast.stat_num,0)) playStatNum,
        max(if(ast.stat_type='0402',ast.stat_num,0)) subscribeStatNum,
        max(if(ast.stat_type='0403',ast.stat_num,0)) buyStatNum,
        max(if(ast.stat_type='0404',ast.stat_num,0)) commentStatNum
        from album_info ai
        inner join album_stat as ast
        on ai.id = ast.album_id
        <where>
            ai.user_id = #{vo.userId}
            <if test="vo.status!= null and vo.status!='' ">
                and ai.status = #{vo.status}
            </if>
            <if test="vo.albumTitle!= null and vo.albumTitle!='' ">
                and ai.album_title like concat('%',#{vo.albumTitle},'%')
            </if>
            and ai.is_deleted = 0
        </where>
        group by ai.id
        order by ai.id desc
    </select>
</mapper>

实体类AlbumInfoQuery 前端的请求body

package com.atguigu.tingshu.query.album;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

@Data
@Schema(description = "专辑信息")
public class AlbumInfoQuery {

	@Schema(description = "标题")
	private String albumTitle;

	@Schema(description = "状态")
	private String status;

	@Schema(description = "用户id")
	private Long userId;
}

 后端返回的类

package com.atguigu.tingshu.vo.album;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

@Data
@Schema(description = "用户专辑列表信息")
public class AlbumListVo {

	@Schema(description = "专辑id")
	private Long albumId;

	@Schema(description = "标题")
	private String albumTitle;

	@Schema(description = "专辑封面原图,尺寸不固定,最大尺寸为960*960(像素)")
	private String coverUrl;

	@Schema(description = "专辑包含声音总数")
	private Integer includeTrackCount;

	@Schema(description = "专辑是否完结:0-否;1-完结;")
	private String isFinished;

	@Schema(description = "状态")
	private String status;

	@Schema(description = "播放量")
	private Integer playStatNum;

	@Schema(description = "订阅量")
	private Integer subscribeStatNum;

	@Schema(description = "购买量")
	private Integer buyStatNum;

	@Schema(description = "评论数")
	private Integer commentStatNum;

}

2.3删除专辑

1.controller
public class AlbumInfoApiController {

    @Autowired
    private AlbumInfoService albumInfoService;

    /*
     * @description:删除专辑
     * @author: yanhongwei
     * @date:
     * @param:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值