如何从PostgreSQL获取每条消息的正确时间并对应展示?
解决每条消息从PostgreSQL获取并展示正确时间的问题
问题分析
当前所有消息显示同一时间,仅发送时展示实际时间,核心原因:
- 前端创建
MessageModel时使用本地生成时间,历史消息未从数据库拉取真实timestamp字段 - 接口设计存在错误(GET请求误用
@Field注解) - 未实现从数据库加载带正确时间的历史消息逻辑
解决方案步骤
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
相关产品推荐
相关产品推荐

