416 lines
13 KiB
Markdown
416 lines
13 KiB
Markdown
|
|
# 点赞功能完整实现指南
|
|||
|
|
|
|||
|
|
## ✅ 已完成的后端部分
|
|||
|
|
|
|||
|
|
### 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调整,建议你按照上面的指南逐步完成。如果遇到问题,可以随时询问!
|