You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从PostgreSQL获取每条消息的正确时间并对应展示?

解决每条消息从PostgreSQL获取并展示正确时间的问题

问题分析

当前所有消息显示同一时间,仅发送时展示实际时间,核心原因:

  1. 前端创建MessageModel时使用本地生成时间,历史消息未从数据库拉取真实timestamp字段
  2. 接口设计存在错误(GET请求误用@Field注解)
  3. 未实现从数据库加载带正确时间的历史消息逻辑

解决方案步骤

1. 修复后端接口设计

修正接口错误,新增历史消息获取接口:

interface UserService {
    @FormUrlEncoded
    @POST("send_message")
    suspend fun sendMessage(
        @Field("receiver_email") receiverEmail: String,
        @Field("sender_email") senderEmail: String,
        @Field("message") message: String
    ): Response<MessageModel> // 修改返回类型,让后端返回带timestamp的消息

    // 新增获取历史消息接口
    @GET("messages")
    suspend fun getHistoryMessages(
        @Query("sender_email") senderEmail: String,
        @Query("receiver_email") receiverEmail: String
    ): Response<List<MessageModel>>
}

2. 调整UserApi与Repository实现

更新UserApi,添加历史消息获取方法,发送消息返回后端生成的完整消息:

class UserApi(private val userService: UserService) {
    suspend fun sendMessage(messageModel: MessageModel): MessageModel {
        val response = userService.sendMessage(
            receiverEmail = messageModel.receiver_email ?: "",
            senderEmail = messageModel.sender_email ?: "",
            message = messageModel.message ?: ""
        )
        if (response.isSuccessful) {
            return response.body() ?: throw Exception("Empty response body")
        } else {
            throw Exception("Send message failed: ${response.message()}")
        }
    }

    suspend fun getHistoryMessages(senderEmail: String, receiverEmail: String): List<MessageModel> {
        val response = userService.getHistoryMessages(senderEmail, receiverEmail)
        return if (response.isSuccessful) {
            response.body() ?: emptyList()
        } else {
            emptyList()
        }
    }
}

同步更新Repository:

class UserRepository(private val userApi: UserApi) {
    suspend fun sendMessage(message: MessageModel): MessageModel {
        return userApi.sendMessage(message)
    }

    suspend fun getHistoryMessages(senderEmail: String, receiverEmail: String): List<MessageModel> {
        return userApi.getHistoryMessages(senderEmail, receiverEmail)
    }
}

3. 改造ViewModel,管理消息状态

添加消息列表状态流,实现发送消息更新列表、加载历史消息的逻辑:

class ChatViewModel(private val repo: UserRepository) : ViewModel() {
    private val _messages = MutableStateFlow<List<MessageModel>>(emptyList())
    val messages: StateFlow<List<MessageModel>> = _messages

    fun sendMessage(message: MessageModel) {
        viewModelScope.launch {
            try {
                val sentMessage = repo.sendMessage(message)
                // 添加后端返回的带正确时间的消息到列表
                _messages.update { it + sentMessage }
                Log.d("chat_feature", "Message sent successfully")
            } catch (e: Exception) {
                Log.d("chat_feature", "Send error: ${e.message}")
                e.printStackTrace()
            }
        }
    }

    fun loadHistoryMessages(senderEmail: String, receiverEmail: String) {
        viewModelScope.launch {
            val historyMessages = repo.getHistoryMessages(senderEmail, receiverEmail)
            _messages.value = historyMessages
        }
    }
}

4. 调整Composable代码,展示正确时间

移除前端本地生成时间的逻辑,直接使用数据库返回的timestamp,页面初始化时加载历史消息:

@Composable
fun ChatScreen(
    viewModel: ChatViewModel,
    currentActiveUser: User?,
    selectedUser: User?
) {
    var inputText by remember { mutableStateOf("") }

    // 切换聊天对象时加载历史消息
    LaunchedEffect(selectedUser, currentActiveUser) {
        if (selectedUser != null && currentActiveUser != null) {
            viewModel.loadHistoryMessages(
                senderEmail = currentActiveUser.email ?: "",
                receiverEmail = selectedUser.email ?: ""
            )
        }
    }

    Column(modifier = Modifier.fillMaxSize()) {
        // 消息列表
        LazyColumn(
            modifier = Modifier.weight(1f),
            reverseLayout = false
        ) {
            items(viewModel.messages.value) { message ->
                val isCurrentUser = message.sender_email == currentActiveUser?.email
                Column(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(horizontal = 8.dp, vertical = 4.dp),
                    horizontalAlignment = if (isCurrentUser) Alignment.End else Alignment.Start
                ) {
                    // 消息气泡
                    Text(
                        text = message.message ?: "",
                        modifier = Modifier
                            .background(if (isCurrentUser) Color.LightGray else Color.Gray)
                            .padding(12.dp)
                            .clip(RoundedCornerShape(16.dp))
                    )
                    // 展示数据库返回的时间
                    Text(
                        text = message.timestamp ?: "",
                        color = Color.Black,
                        fontSize = 10.sp,
                        fontWeight = FontWeight.SemiBold,
                        modifier = Modifier.padding(top = 4.dp, end = 5.dp)
                    )
                }
            }
        }

        // 输入框与发送按钮
        Row(modifier = Modifier.padding(8.dp)) {
            TextField(
                value = inputText,
                onValueChange = { inputText = it },
                modifier = Modifier.weight(1f),
                placeholder = { Text("输入消息...") }
            )
            Button(
                onClick = {
                    if (inputText.isNotEmpty() && selectedUser != null && currentActiveUser != null) {
                        val messageModel = MessageModel(
                            receiver_email = selectedUser.email ?: "",
                            sender_email = currentActiveUser.email ?: "",
                            message = inputText,
                            receiver_id = selectedUser.id ?: 0,
                            sender_id = currentActiveUser.id ?: 0
                            // 不再传本地时间,由后端生成
                        )
                        viewModel.sendMessage(messageModel)
                        inputText = ""
                    }
                },
                modifier = Modifier.padding(start = 8.dp)
            ) {
                Text("发送")
            }
        }
    }
}

关键注意点

  • 后端时间生成:推荐由后端在插入消息时自动生成timestamp并存入数据库,避免客户端时间不一致问题
  • 消息更新逻辑:发送消息后通过后端返回的消息更新本地列表,确保时间准确
  • 历史消息加载:页面初始化或切换聊天对象时,从数据库拉取完整消息列表,每条消息携带自身时间戳

内容的提问来源于stack exchange,提问作者Josef M

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 06:04:59