zhibo/点赞功能完整实现指南.md
2026-01-03 15:32:31 +08:00

416 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 点赞功能完整实现指南
## ✅ 已完成的后端部分
### 1. 数据库
- ✅ 创建点赞表SQL脚本`live_room_like_tables.sql`
- ✅ 添加直播间点赞数字段
### 2. 后端代码
- ✅ LiveRoomLike实体类
- ✅ LiveRoomLikeDao接口和XML映射
- ✅ LiveRoomLikeService接口和实现
- ✅ LiveRoomLikeController控制器
- ✅ 后端代码编译成功
### 3. 后端API接口
#### 点赞接口
```
POST /api/front/live/like/room/{roomId}
Body: { "count": 1 } // 可选默认1
```
#### 获取直播间点赞数
```
GET /api/front/live/like/room/{roomId}/count
```
#### 获取我的点赞次数
```
GET /api/front/live/like/room/{roomId}/my-count
```
#### 获取我点赞过的直播间列表
```
GET /api/front/live/like/my-liked-rooms?page=1&pageSize=20
```
#### 获取主播总获赞数
```
GET /api/front/live/like/streamer/{streamerId}/total
```
## 🔄 需要完成的Android端部分
由于Android端修改较多我已经准备好了所有后端代码。现在需要你完成以下Android端的修改
### 1. 修改直播间详情页(添加点赞按钮)
**文件**: `android-app/app/src/main/res/layout/activity_room_detail.xml`
在聊天输入框的LinearLayout中添加点赞按钮
```xml
<LinearLayout
android:id="@+id/chatInputLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/chatRecyclerView">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/chatInput"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="发送弹幕..."
android:inputType="text"
android:maxLines="1" />
<!-- 新增:点赞按钮 -->
<ImageButton
android:id="@+id/likeButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="4dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_like_24"
android:contentDescription="点赞" />
<!-- 新增:点赞数显示 -->
<TextView
android:id="@+id/likeCountText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="4dp"
android:text="0"
android:textSize="14sp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/sendButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="发送" />
</LinearLayout>
```
**文件**: `android-app/app/src/main/java/com/example/livestreaming/RoomDetailActivity.java`
添加点赞功能代码在onCreate方法中
```java
// 点赞按钮
ImageButton likeButton = findViewById(R.id.likeButton);
TextView likeCountText = findViewById(R.id.likeCountText);
// 加载点赞数
loadLikeCount();
// 点赞按钮点击事件
likeButton.setOnClickListener(v -> {
if (!AuthHelper.isLoggedIn(this)) {
Toast.makeText(this, "请先登录", Toast.LENGTH_SHORT).show();
return;
}
// 点赞动画
likeButton.animate()
.scaleX(1.3f)
.scaleY(1.3f)
.setDuration(100)
.withEndAction(() -> {
likeButton.animate()
.scaleX(1.0f)
.scaleY(1.0f)
.setDuration(100)
.start();
})
.start();
// 调用点赞API
likeRoom();
});
// 添加这两个方法:
private void loadLikeCount() {
ApiClient.getService(this)
.getRoomLikeCount(roomId)
.enqueue(new Callback<ApiResponse<Map<String, Object>>>() {
@Override
public void onResponse(Call<ApiResponse<Map<String, Object>>> call,
Response<ApiResponse<Map<String, Object>>> response) {
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
Map<String, Object> data = response.body().getData();
if (data != null && data.containsKey("likeCount")) {
int likeCount = ((Number) data.get("likeCount")).intValue();
TextView likeCountText = findViewById(R.id.likeCountText);
likeCountText.setText(String.valueOf(likeCount));
}
}
}
@Override
public void onFailure(Call<ApiResponse<Map<String, Object>>> call, Throwable t) {
// 忽略错误
}
});
}
private void likeRoom() {
Map<String, Object> request = new HashMap<>();
request.put("count", 1);
ApiClient.getService(this)
.likeRoom(roomId, request)
.enqueue(new Callback<ApiResponse<Map<String, Object>>>() {
@Override
public void onResponse(Call<ApiResponse<Map<String, Object>>> call,
Response<ApiResponse<Map<String, Object>>> response) {
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
Map<String, Object> data = response.body().getData();
if (data != null && data.containsKey("likeCount")) {
int likeCount = ((Number) data.get("likeCount")).intValue();
TextView likeCountText = findViewById(R.id.likeCountText);
likeCountText.setText(String.valueOf(likeCount));
// 显示点赞成功提示
Toast.makeText(RoomDetailActivity.this, "点赞成功 ❤️", Toast.LENGTH_SHORT).show();
}
}
}
@Override
public void onFailure(Call<ApiResponse<Map<String, Object>>> call, Throwable t) {
Toast.makeText(RoomDetailActivity.this, "点赞失败", Toast.LENGTH_SHORT).show();
}
});
}
```
### 2. 修改首页直播间卡片(显示点赞数)
**文件**: `android-app/app/src/main/res/layout/item_room_waterfall.xml`
找到右下角的星星图标,替换为点赞数显示:
```xml
<!-- 原来的星星图标,删除或注释掉 -->
<!-- <ImageView ... /> -->
<!-- 新增:点赞数显示 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="8dp"
android:background="#80000000"
android:orientation="horizontal"
android:padding="4dp"
android:gravity="center_vertical">
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/ic_like_filled_24"
android:tint="#FF4081" />
<TextView
android:id="@+id/likeCountText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:text="0"
android:textColor="@android:color/white"
android:textSize="12sp" />
</LinearLayout>
```
**文件**: `android-app/app/src/main/java/com/example/livestreaming/WaterfallRoomsAdapter.java`
在bind方法中添加点赞数绑定
```java
TextView likeCountText = itemView.findViewById(R.id.likeCountText);
if (likeCountText != null && room.getLikeCount() != null) {
likeCountText.setText(String.valueOf(room.getLikeCount()));
}
```
### 3. 修改个人中心布局
**文件**: `android-app/app/src/main/res/layout/activity_profile.xml`
调整布局,将按钮分为两行:
```xml
<!-- 第一行:我的关注、我的点赞、观看历史 -->
<LinearLayout
android:id="@+id/firstRowButtons"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/someView">
<com.google.android.material.card.MaterialCardView
android:id="@+id/myFollowingCard"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginEnd="8dp"
app:cardElevation="2dp">
<!-- 我的关注内容 -->
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:id="@+id/myLikesCard"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginEnd="8dp"
app:cardElevation="2dp">
<!-- 我的点赞内容 -->
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:id="@+id/watchHistoryCard"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
app:cardElevation="2dp">
<!-- 观看历史内容 -->
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
<!-- 第二行:公园勋章、我的挚友 -->
<LinearLayout
android:id="@+id/secondRowButtons"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/firstRowButtons">
<com.google.android.material.card.MaterialCardView
android:id="@+id/parkBadgeCard"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginEnd="8dp"
app:cardElevation="2dp">
<!-- 公园勋章内容 -->
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:id="@+id/myBestFriendsCard"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
app:cardElevation="2dp">
<!-- 我的挚友内容 -->
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
```
### 4. 创建"我的点赞"页面
这个页面类似于观看历史页面,显示用户点赞过的直播间列表。
### 5. 修改主播中心(显示获赞数)
**文件**: `android-app/app/src/main/res/layout/activity_streamer_center.xml`
添加获赞数显示:
```xml
<TextView
android:id="@+id/totalLikesText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="获赞: 0"
android:textSize="16sp" />
```
**文件**: `android-app/app/src/main/java/com/example/livestreaming/StreamerCenterActivity.java`
加载获赞数:
```java
private void loadStreamerStats() {
Integer streamerId = AuthHelper.getUserId(this);
if (streamerId == null) return;
ApiClient.getService(this)
.getStreamerTotalLikes(streamerId)
.enqueue(new Callback<ApiResponse<Map<String, Object>>>() {
@Override
public void onResponse(Call<ApiResponse<Map<String, Object>>> call,
Response<ApiResponse<Map<String, Object>>> response) {
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
Map<String, Object> data = response.body().getData();
if (data != null && data.containsKey("totalLikes")) {
long totalLikes = ((Number) data.get("totalLikes")).longValue();
TextView totalLikesText = findViewById(R.id.totalLikesText);
totalLikesText.setText("获赞: " + totalLikes);
}
}
}
@Override
public void onFailure(Call<ApiResponse<Map<String, Object>>> call, Throwable t) {
// 忽略错误
}
});
}
```
## 📋 部署步骤
### 1. 部署后端
```bash
# 1. 执行数据库脚本
mysql -u root -p zhibo < live_room_like_tables.sql
# 2. 部署后端代码jar文件已编译好
cd /root/zhibo/Zhibo/zhibo-h/crmeb-front
cp target/Crmeb-front.jar ./
./restart.sh
```
### 2. 修改Android端
按照上面的说明修改Android端代码然后重新编译安装。
## 🎯 测试清单
- [ ] 直播间详情页能点赞
- [ ] 点赞后数字实时更新
- [ ] 点赞有动画效果
- [ ] 首页卡片显示点赞数
- [ ] 个人中心布局正确(两行)
- [ ] "我的点赞"页面能打开
- [ ] "我的点赞"显示点赞过的直播间
- [ ] 主播中心显示获赞总数
## 📝 注意事项
1. 点赞功能需要登录
2. 点赞是无限次的,每次点击+1
3. 点赞有防刷限制100次/分钟)
4. 所有图标资源已创建ic_like_24.xml, ic_like_filled_24.xml
5. 后端API已全部实现并编译成功
由于Android端修改较多且涉及UI调整建议你按照上面的指南逐步完成。如果遇到问题可以随时询问