-
Notifications
You must be signed in to change notification settings - Fork 10
8주차 미션 / 안드로이드 1조 박경민 #29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: koongmai
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| package com.example.kuit6_android_api | ||
|
|
||
| import android.app.Application | ||
| import com.example.kuit6_android_api.data.di.AppContainer | ||
|
|
||
| class App : Application() { | ||
| lateinit var container: AppContainer | ||
|
|
||
| override fun onCreate() { | ||
| super.onCreate() | ||
| container = AppContainer(this) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,14 +1,19 @@ | ||
| package com.example.kuit6_android_api.data.api | ||
|
|
||
| import android.R.attr.value | ||
| import com.example.kuit6_android_api.data.model.request.LoginRequest | ||
| import com.example.kuit6_android_api.data.model.request.PostCreateRequest | ||
| import com.example.kuit6_android_api.data.model.response.BaseResponse | ||
| import com.example.kuit6_android_api.data.model.response.LoginResponse | ||
| import com.example.kuit6_android_api.data.model.response.PostResponse | ||
| import okhttp3.MultipartBody | ||
| import retrofit2.http.Body | ||
| import retrofit2.http.DELETE | ||
| import retrofit2.http.GET | ||
| import retrofit2.http.Multipart | ||
| import retrofit2.http.POST | ||
| import retrofit2.http.PUT | ||
| import retrofit2.http.Part | ||
| import retrofit2.http.Path | ||
| import retrofit2.http.Query | ||
|
|
||
|
|
@@ -37,4 +42,23 @@ interface ApiService { | |
| suspend fun deletePost( | ||
| @Path(value = "id") id: Long, | ||
| ) : BaseResponse<Unit> | ||
|
|
||
|
|
||
| @POST("/api/upload") | ||
| suspend fun uploadImage( | ||
| @Part file: MultipartBody.Part | ||
| ): BaseResponse<Map<String, String>> | ||
|
Comment on lines
+47
to
+50
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @multipart 어노테이션이 누락되었습니다.
+@Multipart
@POST("/api/upload")
suspend fun uploadImage(
@Part file: MultipartBody.Part
): BaseResponse<Map<String, String>>🤖 Prompt for AI Agents |
||
|
|
||
| @POST("/api/auth/signup") | ||
| suspend fun signup( | ||
| @Body request: LoginRequest | ||
| ): BaseResponse<LoginResponse> | ||
|
|
||
| @POST("/api/auth/login") | ||
| suspend fun login( | ||
| @Body request: LoginRequest | ||
| ): BaseResponse<LoginResponse> | ||
|
|
||
| @GET("/api/auth/validate") | ||
| suspend fun validateToken(): BaseResponse<Boolean> | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| package com.example.kuit6_android_api.data.api | ||
|
|
||
| import android.content.Context | ||
| import com.example.kuit6_android_api.data.repository.TokenRepository | ||
| import kotlinx.coroutines.runBlocking | ||
| import okhttp3.Interceptor | ||
| import okhttp3.Response | ||
|
|
||
| class AuthInterceptor( | ||
| private val context: Context, | ||
| private val tokenRepository: TokenRepository | ||
| ): Interceptor { | ||
|
|
||
| override fun intercept(chain: Interceptor.Chain): Response { | ||
| val originalRequest = chain.request() | ||
|
|
||
| // DataStore에서 토큰 불러오기 (runBlocking 사용) | ||
| val token = runBlocking { | ||
| tokenRepository.getToken(context) | ||
| } | ||
|
|
||
| // 토큰이 있으면 Authorization 헤더에 추가 | ||
| val newRequest = if (!token.isNullOrEmpty()) { | ||
| originalRequest.newBuilder() | ||
| .addHeader("Authorization", "Bearer $token") | ||
| .build() | ||
| } else { | ||
| originalRequest | ||
| } | ||
|
|
||
| return chain.proceed(newRequest) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| package com.example.kuit6_android_api.data.di | ||
|
|
||
| import android.content.Context | ||
| import com.example.kuit6_android_api.data.api.ApiService | ||
| import com.example.kuit6_android_api.data.api.RetrofitClient | ||
| import com.example.kuit6_android_api.data.repository.LoginRepository | ||
| import com.example.kuit6_android_api.data.repository.LoginRepositoryImpl | ||
| import com.example.kuit6_android_api.data.repository.PostRepository | ||
| import com.example.kuit6_android_api.data.repository.PostRepositoryImpl | ||
| import com.example.kuit6_android_api.data.repository.TokenRepository | ||
| import com.example.kuit6_android_api.data.repository.TokenRepositoryImpl | ||
|
|
||
| class AppContainer(private val context: Context) { | ||
|
|
||
| val tokenRepository: TokenRepository by lazy{ | ||
| TokenRepositoryImpl() | ||
| } | ||
|
|
||
| private val retrofitClient: RetrofitClient by lazy { | ||
| RetrofitClient(context, tokenRepository) | ||
| } | ||
|
|
||
| private val apiService: ApiService by lazy { | ||
| retrofitClient.apiService | ||
| } | ||
|
|
||
| val postRepository: PostRepository by lazy{ | ||
| PostRepositoryImpl(apiService) | ||
| } | ||
|
|
||
| val loginRepository: LoginRepository by lazy{ | ||
| LoginRepositoryImpl(apiService) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package com.example.kuit6_android_api.data.model.request | ||
|
|
||
| import kotlinx.serialization.Serializable | ||
|
|
||
| @Serializable | ||
| data class LoginRequest( | ||
| val username:String, | ||
| val password: String | ||
| ) | ||
|
|
||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package com.example.kuit6_android_api.data.model.response | ||
|
|
||
| import kotlinx.serialization.Serializable | ||
|
|
||
| @Serializable | ||
| data class LoginResponse( | ||
| val token: String, | ||
| val userId: Long, | ||
| val username: String | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| package com.example.kuit6_android_api.data.repository | ||
|
|
||
| import com.example.kuit6_android_api.data.model.response.LoginResponse | ||
|
|
||
| interface LoginRepository { | ||
| suspend fun signup(id:String, password: String): Result<LoginResponse> | ||
| suspend fun login(id:String, password: String): Result<LoginResponse> | ||
| suspend fun validateToken(): Result<Boolean> | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| package com.example.kuit6_android_api.data.repository | ||
|
|
||
| import android.util.Log | ||
| import com.example.kuit6_android_api.data.api.ApiService | ||
| import com.example.kuit6_android_api.data.model.request.LoginRequest | ||
| import com.example.kuit6_android_api.data.model.response.LoginResponse | ||
|
|
||
| class LoginRepositoryImpl( | ||
| private val apiService: ApiService | ||
| ): LoginRepository { | ||
| override suspend fun signup(id: String, password: String): Result<LoginResponse> { | ||
| return runCatching { | ||
| val response = apiService.signup(LoginRequest(username = id, password = password)) | ||
|
|
||
| if (response.success && response.data != null) { | ||
| response.data | ||
| } else { | ||
| throw Exception(response.message ?: "회원가입 실패") | ||
| } | ||
| }.onFailure { error -> | ||
| Log.e("LoginRepository", error.message.toString()) | ||
| } | ||
| } | ||
|
|
||
| override suspend fun login(id: String, password: String): Result<LoginResponse> { | ||
| return runCatching { | ||
| val response = apiService.login(LoginRequest(username = id, password = password)) | ||
|
|
||
| if (response.success && response.data != null) { | ||
| response.data | ||
| } else { | ||
| throw Exception(response.message ?: "로그인 실패") | ||
| } | ||
| }.onFailure { error -> | ||
| Log.e("LoginRepository", error.message.toString()) | ||
| } | ||
| } | ||
|
|
||
| override suspend fun validateToken(): Result<Boolean> { | ||
| return runCatching { | ||
| val response = apiService.validateToken() | ||
|
|
||
| if (response.success && response.data != null) { | ||
| response.data | ||
| } else { | ||
| throw Exception(response.message ?: "토큰 검증 실패") | ||
| } | ||
| }.onFailure { error -> | ||
| Log.e("LoginRepository", error.message.toString()) | ||
| } | ||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| package com.example.kuit6_android_api.data.repository | ||
|
|
||
| import com.example.kuit6_android_api.data.model.request.PostCreateRequest | ||
| import com.example.kuit6_android_api.data.model.response.PostResponse | ||
| import okhttp3.MultipartBody | ||
|
|
||
| interface PostRepository{ | ||
| suspend fun getPosts(): Result<List<PostResponse>> | ||
| suspend fun createPost( | ||
| author: String, | ||
| request: PostCreateRequest | ||
| ): Result<PostResponse> | ||
| suspend fun getPostDetail( | ||
| id: Long | ||
| ): Result<PostResponse> | ||
| suspend fun editPost( | ||
| id: Long, | ||
| request: PostCreateRequest | ||
| ): Result<PostResponse> | ||
| suspend fun deletePost( | ||
| id: Long | ||
| ): Result<Unit> | ||
| suspend fun uploadImage( | ||
| file: MultipartBody.Part | ||
| ): Result<Map<String, String>> | ||
|
|
||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
DataStore alpha 버전 사용을 확인하세요.
androidx.datastore.preferences라이브러리의 alpha 버전(1.3.0-alpha01)을 사용하고 있습니다. 프로덕션 환경에서는 안정적인(stable) 버전 사용을 권장합니다.다음 스크립트를 실행하여 최신 안정 버전을 확인하세요:
🏁 Script executed:
Length of output: 0
검증을 위해 추가 정보를 수집하겠습니다.
이제 실제 build.gradle.kts 파일과 버전 카탈로그를 확인하겠습니다.
Now awaiting script results to verify the actual version being used.
🏁 Script executed:
Length of output: 213
Length of output: 167
Length of output: 4394
이제 최신 안정 버전을 확인하겠습니다.
💡 Result:
Sources:
[1] Android Developers — DataStore release notes.
[2] Maven / mvnrepository listing for datastore-preferences.
androidx.datastore.preferencesalpha 버전을 안정 버전으로 업그레이드하세요.프로젝트에서 최신 안정 버전인 1.1.7(2025년 5월 20일 릴리스)로 업그레이드할 것을 권장합니다. gradle/libs.versions.toml의
datastorePreferences버전을 다음과 같이 변경하세요:변경 후 프로덕션 환경에 배포하기 전에 충분한 테스트를 수행해주세요.
🤖 Prompt for AI Agents