这将是一篇很长的文章,因为它涵盖了我的应用程序的后端和前端,我将详细介绍 Laravel、Postman Json 返回和 Kotlin Jetpack Compose 中的每个代码。我正在创建一个问卷应用程序,用户可以通过单选按钮选择输入答案,然后提交答案。
基本上,用户填写每个单选按钮,它将存储在本地主机 phpMyAdmin 数据库中
我尝试调试几个小时的一个问题是我似乎无法提交答案,并且在 Android Studio Logcat 中,此代码片段中显示 500 Internal Server Error:
AnswerModel(answers=[Answer(question_id=1, answer=3)], user_id=1, fill_date=22-6-24)
Failed to submit answers: HTTP 500 Internal Server Error
基本上,php laravel 代码中有一个答案和提交控制器,它与答案和结果数据库相关,用于存储输入的答案。这是提交控制器:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Answer;
use App\Models\Result;
class SubmitController extends Controller
{
public function store(Request $request){
$request_answer = json_decode($request->input('answers'), true);
$totalScore = 0;
foreach ($request_answer as $key => $value) {
Answer::create([
'user_id' => $request->input('user_id'),
'question_id' => $value['question_id'],
'answer_value' => $value['answer'],
'created_at' => now(),
'updated_at' => now(),
]);
$totalScore += $value['answer'];
}
$result = Result::create([
'user_id' => $request->input('user_id'),
'fill_date'=> $request->input('fill_date'),
'score'=> $totalScore,
'created_at' => now(),
'updated_at' => now(),
]);
return response()->json(['message' => 'Answers submitted successfully', 'result' => ""]);
}
}
接下来是提交api的表单数据。我已经测试过它并且有效。
答案:
[
{
"question_id" : "1",
"answer" : "3",
"user_id": "1"
},
{
"question_id" : "2",
"answer" : "3",
"user_id": "1"
},
{
"question_id" : "3",
"answer" : "3",
"user_id": "1"
}
]
用户 ID:
1
填写日期:
24-7-24
接下来是android代码。有一些与此过程相关的代码片段,包括数据类、存储库、视图模型和视图屏幕。
以下是数据类:
data class AnswerModel(
val answers: List<Answer>,
val user_id: String,
val fill_date: String
)
下一个数据类:
data class Answer(
val question_id: String,
val answer: String
)
最终响应数据类:
data class AnswerResponse(
val message: String,
val result: Result
)
接下来,这是用于此 POST api 的 api 代码:
@Singleton
interface EMedibApi {
//api and post data
@POST("submit")
suspend fun submitAnswers(@HeaderMap headers: Map<String , String>,
@Body request: AnswerModel): AnswerResponse
}
之后,这是视图模型(我在这里使用了submitAnswers函数):
@HiltViewModel
class DsmqViewModel @Inject constructor(private val repository: DsmqRepository) : ViewModel() {
var isLoading: Boolean by mutableStateOf(false)
var questions: QuestionResponse? by mutableStateOf(
QuestionResponse(
data = null
)
)
init {
fetchQuestions()
// fetchResults()
}
private fun fetchQuestions() {
viewModelScope.launch {
isLoading = true
try {
when (val response = repository.getQuestions()) {
is Resource.Success -> {
Log.d("DSMQ DATA", "${response.data}")
questions = response.data!!
}
is Resource.Error -> {
Log.d("DSMQ DATA", "${response.message}")
}
else -> {
Log.d("DSMQ DATA", "$response")
}
}
} catch (e: HttpException) {
Log.e("DsmqViewModel", "Failed to fetch questions: ${e.message}")
} finally {
isLoading = false
}
}
}
fun submitAnswers(answers: List<Answer>, headers: Map<String, String> , userId: String, fillDate: String) {
viewModelScope.launch {
isLoading = true
val answerModel = AnswerModel(
answers = answers,
user_id = userId,
fill_date = fillDate
)
Log.d("DSMQ SUBMIT", answerModel.toString())
try {
when (val response = repository.submitAnswers(answerModel, headers)) {
is Resource.Success -> {
Log.d("DSMQ SUBMIT", "Answers submitted successfully: ${response.data}")
}
is Resource.Error -> {
Log.d("DSMQ SUBMIT", "Failed to submit answers: ${response.message}")
}
else -> {
Log.d("DSMQ SUBMIT", "Unknown response: $response")
}
}
} catch (e: HttpException) {
Log.e("DsmqViewModel", "Failed to submit answers: ${e.response()}")
} finally {
isLoading = false
}
}
}
}
接下来是存储库
//the dsmq repository
class DsmqRepository @Inject constructor(private val api: EMedibApi) {
suspend fun getQuestions(): Resource<QuestionResponse>{
Resource.Loading(data = true)
return try {
val dataQuestion = api.getQuestions()
Resource.Success(data = dataQuestion)
} catch (e: Exception) {
Resource.Error(message = e.message.toString())
} finally {
Resource.Loading(data = false)
}
}
//create function for submittingAnswers
suspend fun submitAnswers(answerModel: AnswerModel, headers: Map<String, String>): Resource<AnswerResponse> {
Resource.Loading(data = true)
return try {
val responseSubmit = api.submitAnswers(headers, answerModel)
Resource.Success(data = responseSubmit)
} catch (e: Exception) {
Resource.Error(message = e.message.toString())
} finally {
Resource.Loading(data = false)
}
}
}
最后,这是与提交答案相关的视图/屏幕/功能。 QuestionItem.kt代码:
@Composable
fun QuestionItem(
question: String,
options: List<Option>,
onAnswerSelected: (Answer) -> Unit
) {
var selectedOptionId by remember { mutableStateOf(-1) }
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = question,
textAlign = TextAlign.Center,
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 8.dp)
)
val optionTexts = options.map { it.option_text ?: "No options provided" }
val textAboveOptions = listOf(
"Sangat berlaku bagi saya",
"Berlaku bagi saya",
"Sedikit berlaku bagi saya",
"Tidak berlaku bagi saya"
)
HorizontalRadioButton(
options = optionTexts,
textAboveOptions = textAboveOptions,
selectedOption = selectedOptionId,
onOptionSelected = { optionId ->
selectedOptionId = optionId
if (options.isNotEmpty()) {
val selectedOption = options.find { it.id == optionId }
selectedOption?.let {
val answer = Answer(
question_id = it.question_id.toString(),
answer = it.option_text
)
onAnswerSelected(answer)
}
}
}
)
}
}
最后全屏(在startQuestionnaire if语句之后使用Answer数据类):
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DsmqScreen(
navController: NavController,
viewModel: DsmqViewModel = hiltViewModel(),
) {
val customSelectedColor = Color(0xFF5799FC)
val lightGreen = Color(0xFF13ECA2)
val redColor = Color(0xFFF20D3F)
//val selectedAnswers = remember { mutableStateListOf<AnswerResponse>() }
val selectedAnswers = remember { mutableStateListOf<Answer>() }
var showDialog by remember { mutableStateOf(false) }
var showSubmitDialog by remember { mutableStateOf(false) }
var startQuestionnaire by remember { mutableStateOf(false) }
var selectedDate by remember { mutableStateOf("") }
var showInfoDialog by remember { mutableStateOf(false) }
Scaffold(
topBar = {
CenterAlignedTopAppBar(
title = {
Text(
text = "Diabetes Self-Management Questionnaire",
style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.Center,
fontWeight = FontWeight.SemiBold,
color = Color.White
)
},
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(containerColor = customSelectedColor)
)
}
) {
it
Column(
modifier = Modifier
.padding(16.dp)
.fillMaxHeight()
.verticalScroll(rememberScrollState())
) {
Spacer(modifier = Modifier.height(62.dp))
Button(
onClick = { showInfoDialog = true },
modifier = Modifier.align(Alignment.CenterHorizontally),
colors = ButtonDefaults.buttonColors(customSelectedColor)
) {
Text(text = "Apa itu Diabetes Self Management Questionnaire?", color = Color.White)
}
if (showInfoDialog) {
InfoAlertDialog(
onDismiss = { showInfoDialog = false }
)
}
EnterDate(selectedDate = selectedDate, onDateSelected = { selectedDate = it })
Spacer(modifier = Modifier.height(2.dp))
Button(
onClick = {
if (selectedDate.isNotEmpty()) {
showDialog = true
}
},
modifier = Modifier.align(Alignment.CenterHorizontally),
colors = ButtonDefaults.buttonColors(customSelectedColor)
) {
Text(text = "Mulai Isi Kuesioner")
}
Spacer(modifier = Modifier.height(20.dp))
StartQuestionnaireDialog(
showDialog = showDialog,
onDismiss = {
showDialog = false
},
onConfirm = {
showDialog = false
startQuestionnaire = true
},
confirmButtonColor = lightGreen,
dismissButtonColor = redColor
)
if (startQuestionnaire) {
Column {
viewModel.questions?.data?.forEach { it ->
QuestionItem(
question = it.question_text,
options = it.options ?: emptyList(),
onAnswerSelected = { answer ->
Log.d("DSMQ", "Answer Selected: $answer")
selectedAnswers.removeIf { it.question_id == answer.question_id }
selectedAnswers.add(answer)
}
)
}
//Spacer(modifier = Modifier.height(16.dp))
Button(
onClick = { showSubmitDialog = true },
modifier = Modifier.align(Alignment.CenterHorizontally),
colors = ButtonDefaults.buttonColors(customSelectedColor)
) {
Text(text = "Selesai Kuesioner", color = Color.White)
}
Spacer(modifier = Modifier.height(76.dp))
}
}
if (showSubmitDialog) {
AlertDialog(
onDismissRequest = { showSubmitDialog = false },
title = { Text(text = "Submit Answers") },
text = { Text(text = "Are you sure you want to submit your answers?") },
confirmButton = {
Button(
onClick = {
val headerMap = mutableMapOf<String, String>()
headerMap["Accept"] = "application/json"
showSubmitDialog = false
val userId = "1"
Log.d("selected Answer", selectedAnswers.toString())
viewModel.submitAnswers(
answers = selectedAnswers.toList(),
userId = userId,
fillDate = selectedDate,
headers = headerMap)
// Handle successful submission, e.g., navigate to result screen
// navController.popBackStack()
},
colors = ButtonDefaults.buttonColors(containerColor = lightGreen)
) {
Text(text = "Yes", color = Color.White)
}
},
dismissButton = {
Button(
onClick = { showSubmitDialog = false },
colors = ButtonDefaults.buttonColors(containerColor = redColor)
) {
Text(text = "No", color = Color.White)
}
}
)
}
//customprofile list tile to questionnaire
CustomTile(
title = "Hasil DSMQ",
subtitle ="Pantau Hasil DSMQ Anda" ,
leadingIcon = Icons.Outlined.Calculate,
onClick = {
//navigasi
}
)
Spacer(modifier = Modifier.height(96.dp))
}
}
}
我一直渴望得到答案,但我不知道为什么它不断给出 500 内部服务器错误。我已经完成了:
php artisan serve
激活本地主机服务器,但它一直给我错误代码 500。我已经测试了所有其他 API,它们似乎可以工作。
更新:我已经修复了它,并且邮递员和 Android API 测试都有效。
显然我只需要更新 laravel 上的 Submitcontroller :
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Answer;
use App\Models\Result;
class SubmitController extends Controller
{
public function store(Request $request){
$request_answer = is_string($request->input('answers')) ? json_decode($request->input('answers'), true) : $request->input('answers');
//$request_answer = json_decode($request->input('answers'), true);
if (is_null($request_answer) || !is_array($request_answer)) {
return response()->json(['message' => 'Invalid answers data'], 400);
}
$totalScore = 0;
foreach ($request_answer as $key => $value) {
Answer::create([
'user_id' => $request->input('user_id'),
'question_id' => $value['question_id'],
'answer_value' => $value['answer'],
'created_at' => now(),
'updated_at' => now(),
]);
$totalScore += $value['answer'];
}
$result = Result::create([
'user_id' => $request->input('user_id'),
'fill_date'=> $request->input('fill_date'),
'score'=> $totalScore,
'created_at' => now(),
'updated_at' => now(),
]);
return response()->json(['message' => 'Answers submitted successfully', 'result' => $result]);
}
}