记录专辑标签查询、添加专辑、列表检索、删除与修改流程,重点整理关联数据的保存及接口分层。

本篇要点

  • 按分类查询专辑属性与标签
  • 保存专辑及关联信息
  • 完成列表、删除和修改接口

内容回顾

1、搭建项目环境

  • 软件环境
  • 项目工程

docker start spzx_rabbitmq

  • 搭建前端环境

2、专辑管理

  • 添加专辑需求
  • 查询所有分类接口(三级分类)
  • 上传文件接口

– 在配置文件里面有数据 yaml 或者 properties

今天内容

1、添加专辑功能

image-20251021090326230

根据一级分类Id获取专辑标签对应数据接口

效果

image-20251021090625691

表关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# base_attribute:标签(属性)名称,有一级分类id

select ba.attribute_name from base_attribute ba
where ba.category1_id=2;

# base_attribute_value: 属性名称下面哪些值,attribute_id关联属性名称

# 获取属性名称和对应值,两张表关联查询
select ba.category1_id,ba.attribute_name,bav.value_name from

base_attribute ba inner join base_attribute_value bav

on ba.id = bav.attribute_id

where ba.category1_id=2

接口实现

  • 实体类
  • 有一个标签名称,一个标签名称里面有多个标签值(使用List类型属性封装)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Data
@Schema(description = "BaseAttribute")
@TableName("base_attribute")
public class BaseAttribute extends BaseEntity {

private static final long serialVersionUID = 1L;

@Schema(description = "一级分类id")
@TableField("category1_id")
private Long category1Id;

@Schema(description = "属性显示名称")
@TableField("attribute_name")
private String attributeName;

//标签里面多个标签值
@TableField(exist = false)
private List<BaseAttributeValue> attributeValueList;

}
BaseCatetoryApiController
1
2
3
4
5
6
7
8
//根据一级分类id查询对应标签数据(标签名称和标签值)
// /api/album/category/findAttribute/2
@GetMapping("findAttribute/{category1Id}")
public Result findAttribute(@PathVariable("category1Id") Long category1Id){
//调用service
List<BaseAttribute> list = baseCategoryService.findAttribute(category1Id);
return Result.ok(list);
}
servcie
1
2
3
4
5
6
//根据一级分类id查询对应标签数据(标签名称和标签值)
@Override
public List<BaseAttribute> findAttribute(Long category1Id) {
//调用mapper
return baseAttributeMapper.selectAttribute(category1Id);
}
mapper
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?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对应-->
<!--id:表示主键 property:表示实体类的属性名
column:表示通过sql 执行以后查询出来的字段名-->
<id column="id" property="id"></id>

<!--List<BaseAttributeValue> attributeValueList-->
<collection property="attributeValueList"
ofType="com.atguigu.tingshu.model.album.BaseAttributeValue"
autoMapping="true">
<id column="attribute_value_id" property="id"></id>
</collection>
</resultMap>

<select id="selectAttribute" resultMap="baseAttributeMap">
select
ba.id,
ba.attribute_name,
ba.category1_id,
bav.id attribute_value_id,
bav.value_name,
bav.attribute_id
from
base_attribute ba
inner join base_attribute_value bav on ba.id = bav.attribute_id
where ba.category1_id = #{category1Id}
order by ba.id
</select>

</mapper>

添加专辑接口

分析

请求路径和提交方式:

image-20251021102308459

请求体,前端传递数据:

image-20251021102406461

添加专辑需要使用表

  • 实现添加专辑,向三张表添加数据
1
2
3
4
5
6
album_info:专辑基本信息

album_stat:每个专辑统计数据,
0401-播放量 0402-订阅量 0403-购买量 0403-评论数

album_attribute_value: 保存每个专辑标签名称和对应值数据

接口实现

AlbumInfoApiController
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Tag(name = "专辑管理")
@RestController
@RequestMapping("api/album/albumInfo")
@SuppressWarnings({"all"})
public class AlbumInfoApiController {

@Autowired
private AlbumInfoService albumInfoService;

//保存专辑
@PostMapping("saveAlbumInfo")
public Result saveAlbumInfo(@RequestBody @Validated AlbumInfoVo albumInfoVo) {
//调用service方法
albumInfoService.saveAlbumInfo(albumInfoVo);
return Result.ok();
}
}
service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
@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
@Override
public void saveAlbumInfo(AlbumInfoVo albumInfoVo) {
//1 添加专辑基本信息 album_info
AlbumInfo albumInfo = new AlbumInfo();
// AlbumInfoVo 值--放到 AlbumInfo
//String albumTitle = albumInfoVo.getAlbumTitle();
//albumInfo.setAlbumTitle(albumTitle);
BeanUtils.copyProperties(albumInfoVo,albumInfo);

//专辑有几个值需要单独设置,前端没有传递过来的
//TODO userId 用户id,后面完善
albumInfo.setUserId(1L);
// 专辑状态,设置通过
albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
//设置收费专辑,免费试听集数,前3集
String payType = albumInfo.getPayType();
if(!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(payType)) {
albumInfo.setTracksForFree(3);
}
//调用方法保存
albumInfoMapper.insert(albumInfo);

//2 添加专辑下面标签名称和标签值数据 album_attribute_value
List<AlbumAttributeValueVo> albumAttributeValueVoList =
albumInfoVo.getAlbumAttributeValueVoList();
//非空判断
if(!CollectionUtils.isEmpty(albumAttributeValueVoList)) {
albumAttributeValueVoList.stream().forEach(albumAttributeValueVo -> {
AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
// AlbumAttributeValueVo -- AlbumAttributeValue
BeanUtils.copyProperties(albumAttributeValueVo,albumAttributeValue);
//专辑id
albumAttributeValue.setAlbumId(albumInfo.getId());

albumAttributeValueMapper.insert(albumAttributeValue);
});
}

//3 添加专辑四个统计数据 播放量,订阅量等 初始值 0 album_stat
//播放量
this.saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_PLAY);
//订阅量
this.saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_SUBSCRIBE);
//购买量
this.saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_BROWSE);
//评论数
this.saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_COMMENT);
}

//保存专辑统计数据的方法
public void saveAlbumStat(Long albumId, String statType) {
AlbumStat albumStat = new AlbumStat();
albumStat.setAlbumId(albumId);
albumStat.setStatType(statType);// 0401 0402 ....0403
albumStat.setStatNum(0);
albumStatMapper.insert(albumStat);
}
}

完善代码-批量添加

image-20251021140453877

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//2 添加专辑下面标签名称和标签值数据 album_attribute_value
List<AlbumAttributeValueVo> albumAttributeValueVoList =
albumInfoVo.getAlbumAttributeValueVoList();

// List<AlbumAttributeValueVo> -- List<AlbumAttributeValue>
List<AlbumAttributeValue> albumAttributeValueList = albumAttributeValueVoList.stream().map(albumAttributeValueVo -> {
AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
BeanUtils.copyProperties(albumAttributeValueVo, albumAttributeValue);
albumAttributeValue.setAlbumId(albumInfo.getId());
return albumAttributeValue;
}).collect(Collectors.toList());

//批量添加
albumAttributeValueService.saveBatch(albumAttributeValueList);

2、查询专辑列表接口

分析

效果

image-20251021142521501

查询表和语句编写

  • 行变列
  • 实现思路:分组 + if + 聚合函数实现
  • 分组之后,select后面出现:分组字段、聚合函数、重复数据
1
2
3
4
5
6
7
8
9
10
11
12
13
# album_info 关联  album_stat
select
ai.id,
ai.album_title,

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,
ai.cover_url
from album_info ai inner join album_stat ast
on ai.id = ast.album_id
group by ai.id

接口实现

AlbumInfoApiController

1
2
3
4
5
6
7
8
9
10
11
12
13
//查询专辑列表
@PostMapping("findUserAlbumPage/{page}/{limit}")
public Result findUserAlbumPage(@PathVariable Long page,
@PathVariable Long limit,
@RequestBody AlbumInfoQuery albumInfoQuery){
albumInfoQuery.setUserId(1L);
//创建page对象,传递当前页和每页记录数
Page<AlbumListVo> pageParam = new Page<>(page, limit);
//调用service方法
IPage<AlbumListVo> pageModel =
albumInfoService.selectAlbumPage(pageParam,albumInfoQuery);
return Result.ok(pageModel);
}

service

1
2
3
4
5
//查询专辑列表
@Override
public IPage<AlbumListVo> selectAlbumPage(Page<AlbumListVo> pageParam, AlbumInfoQuery albumInfoQuery) {
return albumInfoMapper.selectUserAlbumPage(pageParam,albumInfoQuery);
}

mapper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?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
album.id as albumId,
album.album_title,
album.cover_url,
album.include_track_count,
album.is_finished,
max(if(stat.stat_type = '0401', stat_num, 0)) playStatNum,
max(if(stat.stat_type = '0402', stat_num, 0)) subscribeStatNum,
max(if(stat.stat_type = '0403', stat_num, 0)) buyStatNum,
max(if(stat.stat_type = '0404', stat_num, 0)) commentStatNum
from album_info album inner join album_stat stat
on album.id = stat.album_id
<where>
<if test="vo.userId!=null">
album.user_id = #{vo.userId}
</if>
<if test="vo.status!=null and vo.status!=''">
and album.status = #{vo.status}
</if>
<if test="vo.albumTitle!=null and vo.albumTitle !=''">
and album.album_title like concat('%',#{vo.albumTitle},'%')
</if>
and album.is_deleted = 0
</where>
group by album.id
order by album.id
</select>
</mapper>

3、根据id删除专辑接口

分析

  • 请求路径中,根据专辑id进行删除

image-20251021153752942

  • 删除哪些表数据

album_info:基本信息
album_stat:统计数据
album_attribute_value:标签名称和标签值数据

接口实现

controller

1
2
3
4
5
@DeleteMapping("removeAlbumInfo/{albumId}")
public Result removeAlbumInfo(@PathVariable("albumId") String albumId) {
albumInfoService.removeAlbumInfo(albumId);
return Result.ok();
}

service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//删除专辑
@Override
public void removeAlbumInfo(String albumId) {
//1 判断当前专辑下面是否包含声音,如果包含不能删除
// select count(*) from track_info where album_id=?
LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(TrackInfo::getAlbumId,albumId);
Long count = trackInfoMapper.selectCount(queryWrapper);
if(count > 0) {//包含声音,如果包含不能删除
throw new GuiguException(400, "该专辑下存在未删除声音!");
}

//2 如果专辑下面不包含声音,可以删除
//2.1 删除专辑基本信息
albumInfoMapper.deleteById(albumId);

//2.2 删除专辑标签名称和标签值数据
LambdaQueryWrapper<AlbumAttributeValue> queryWrapper1 =
new LambdaQueryWrapper<>();
queryWrapper1.eq(AlbumAttributeValue::getAlbumId,albumId);
albumAttributeValueMapper.delete(queryWrapper1);

//2.3 删除专辑四个统计数据
LambdaQueryWrapper<AlbumStat> queryWrapper2 =
new LambdaQueryWrapper<>();
queryWrapper2.eq(AlbumStat::getAlbumId,albumId);
albumStatMapper.delete(queryWrapper2);
}

4、修改专辑接口

接口1:根据专辑id获取专辑数据

controller

1
2
3
4
5
6
//修改-根据专辑id获取专辑数据
@GetMapping("getAlbumInfo/{albumId}")
public Result<AlbumInfo> getAlbumInfo(@PathVariable Long albumId) {
AlbumInfo albumInfo = albumInfoService.getAlbumInfo(albumId);
return Result.ok(albumInfo);
}

service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//修改-根据专辑id获取专辑数据
@Override
public AlbumInfo getAlbumInfo(Long albumId) {
//1 根据专辑id获取专辑基本信息
AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);

//2 根据专辑id获取标签数据
LambdaQueryWrapper<AlbumAttributeValue> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(AlbumAttributeValue::getAlbumId,albumId);
List<AlbumAttributeValue> albumAttributeValueList = albumAttributeValueMapper.selectList(wrapper);

//3 把获取标签数据list集合封装到专辑对象里面
albumInfo.setAlbumAttributeValueVoList(albumAttributeValueList);

return albumInfo;
}

接口2:修改专辑接口

controller

1
2
3
4
5
6
7
8
9
10
    //修改接口
// Request URL: http://localhost/api/album/albumInfo/updateAlbumInfo/1607
// Request Method: PUT
@PutMapping("updateAlbumInfo/{albumId}")
public Result updateAlbumInfo(@PathVariable Long albumId,
@RequestBody @Validated AlbumInfoVo albumInfoVo) {
// 调用服务层方法
albumInfoService.updateAlbumInfo(albumId,albumInfoVo);
return Result.ok();
}

service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//修改
@Override
public void updateAlbumInfo(Long albumId, AlbumInfoVo albumInfoVo) {
//根据专辑id修改专辑基本信息
AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
BeanUtils.copyProperties(albumInfoVo,albumInfo);
albumInfoMapper.updateById(albumInfo);

//根据专辑id删除标签名称和标签值数据
LambdaQueryWrapper<AlbumAttributeValue> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(AlbumAttributeValue::getAlbumId,albumId);
albumAttributeValueMapper.delete(wrapper);

//添加专辑下面 标签名称和标签值数据
List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
if(!CollectionUtils.isEmpty(albumAttributeValueVoList)) {
albumAttributeValueVoList.stream().forEach(albumAttributeValueVo -> {
AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
BeanUtils.copyProperties(albumAttributeValueVo,albumAttributeValue);
albumAttributeValue.setAlbumId(albumId);
albumAttributeValueMapper.insert(albumAttributeValue);
});
}
}