Development/Spring Boot3 (Kotlin)
[Kotlin][SpringBoot3] Kopring 서버 기본 실습 10 - User에서 username, email 데이터 삭제하고, fromip 정보로 자동 회원가입 및 로그인 처리하는 api 구현
Tradgineer
2023. 9. 14. 17:04
1. 이전 포스팅
https://growingsaja.tistory.com/975
2. 목표
username, email 없이 fromip로 고유한 username을 대체하는 이용자 User 시스템 기능 구현
login 관련 정보 등을 추가해 정보 저장
로그인 시도시, 없는 계정이면 해당 fromIp 기준으로 계정 생성
3. 소스코드 수정
// vim entities/User.kt
package com.example.practicekopring.entities
import org.springframework.data.annotation.Id
import org.springframework.data.mongodb.core.mapping.Document
import java.time.LocalDateTime
@Document(collection = "users")
data class User(
@Id
val id: String? = null,
var lastUpdatedAt_KST: String? = null, // 데이터 최종 편집 일시 추가
var lastUpdatedAt: LocalDateTime? = null,
var createdAt_KST: String? = null, // 데이터 초기 생성 일시 추가
var createdAt: LocalDateTime? = null,
var lastLoginAt_KST: String? = null, // 최근 로그인 일시 추가
var lastLoginAt: LocalDateTime? = null,
var fromIp: String? = null, // 접속 ip : ip가 고유한 user name 역할을 합니다.
val fromDevice_first: String? = null, // 첫 접속 디바이스
var fromDevice_last: String? = null, // 최근 접속 디바이스
val fromChannel_first: String? = null, // 첫 접속 채널
var fromChannel_last: String? = null // 최근 접속 채널
)
data class UpdateUserInfo(
val id: String? = null,
val fromIp: String? = null
)
// vim repositories/UserRepository.kt
package com.example.practicekopring.repositories
import com.example.practicekopring.entities.User
import org.springframework.data.mongodb.repository.MongoRepository
// UserRepository 인터페이스는 User 엔터티와 관련된 데이터베이스 작업을 위한 Repository입니다.
interface UserRepository : MongoRepository<User, String> {
fun findByFromIp(fromIp: String): User?
fun findAllByOrderByFromIpAsc(): List<User>
fun findByFromIpContaining(keyword: String): List<User>
}
// vim services/UserService.kt
package com.example.practicekopring.services
import com.example.practicekopring.entities.User
import com.example.practicekopring.entities.UpdateUserInfo
import com.example.practicekopring.repositories.UserRepository
import org.springframework.data.domain.Page
import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Pageable
import org.springframework.stereotype.Service
import java.time.LocalDateTime
import java.time.ZoneId
@Service
class UserService(private val userRepository: UserRepository) {
// 1. 모든 사용자 조회
fun getAllUsers(): List<User> {
return userRepository.findAll()
}
// 2. 사용자 로그인 또는 생성
fun loginUser(fromIp: String, fromDevice: String, fromChannel: String): User? {
// 현재 일시 가져오기
val currentTime = LocalDateTime.now()
val currenctTime_KST = currentTime.atZone(ZoneId.of("Asia/Seoul")).toString().substring(0, 19).replace("T", " ") // 데이터 최종 편집 일시 설정
val userByFromIp = userRepository.findByFromIp(fromIp)
if (userByFromIp == null) {
// 로그인 실패시 회원가입 진행
val user = User(fromIp = fromIp, fromDevice_first = fromDevice, fromChannel_first = fromChannel, fromDevice_last = fromDevice, fromChannel_last = fromChannel)
user.createdAt = currentTime
user.createdAt_KST = currenctTime_KST
user.lastLoginAt = currentTime
user.lastLoginAt_KST = currenctTime_KST
return userRepository.save(user)
} else {
// 로그인 성공
val id: String? = userByFromIp.id
val existingUser = id?.let { userRepository.findById(it) }
if (existingUser != null) {
if (existingUser.isPresent) {
val userToUpdate = existingUser.get()
userToUpdate.fromIp = fromIp
// 작업 임시 저장
userToUpdate.lastLoginAt = currentTime
userToUpdate.lastLoginAt_KST = currenctTime_KST
userToUpdate.fromDevice_last = fromDevice
userToUpdate.fromChannel_last = fromChannel
return userRepository.save(userToUpdate)
}
} else {
println("[ERROR] Login Fail. Not exist user.")
}
return null
}
}
// 3. 사용자 업데이트
fun updateUser(id: String, fromIp: String): User? {
val existingUser = userRepository.findById(id)
if (existingUser.isPresent) {
val userToUpdate = existingUser.get()
userToUpdate.fromIp = fromIp
// 작업 일시 저장
val currentTime = LocalDateTime.now()
val currentTime_KST = currentTime.atZone(ZoneId.of("Asia/Seoul")).toString().substring(0, 19).replace("T", " ") // 데이터 최종 편집 일시 설정
// 한국 일시 저장
userToUpdate.lastUpdatedAt = currentTime
userToUpdate.lastUpdatedAt_KST = currentTime_KST
return userRepository.save(userToUpdate)
}
return null
}
// 4. 사용자 업데이트 with body
fun updateUserWithBody(user: UpdateUserInfo): User? {
val existingUser = userRepository.findById(user.id ?: "")
val userToUpdate = existingUser.get()
userToUpdate.fromIp = user.fromIp ?: userToUpdate.fromIp
// 작업 일시 저장
val currentTime = LocalDateTime.now()
userToUpdate.lastUpdatedAt = currentTime
// 한국 일시 string 저장
userToUpdate.lastUpdatedAt_KST = currentTime.atZone(ZoneId.of("Asia/Seoul")).toString().substring(0, 19).replace("T", " ") // 데이터 최종 편집 일시 설정 // 데이터 최종 편집 일시 설정
return userRepository.save(userToUpdate)
}
// 5. fromip로 검색
fun searchUsersByFromIp(keyword: String): List<User> {
return userRepository.findByFromIpContaining(keyword)
}
// 6. 사용자 삭제
fun deleteUser(id: String) {
userRepository.deleteById(id)
}
// 7. 사용자 카운트 조회
fun getUserCount(): Long {
return userRepository.count()
}
// 10. 사용자 정렬 조회 (예: 이름 오름차순)
fun getUsersSortedByFromIp(): List<User> {
return userRepository.findAllByOrderByFromIpAsc()
}
// 11. 특정 페이지의 사용자 조회 (페이징)
fun getUsersByPage(page: Int, size: Int): Page<User> {
val pageable: Pageable = PageRequest.of(page, size)
return userRepository.findAll(pageable)
}
}
// vim controllers/UserController.kt
package com.example.practicekopring.controllers
import com.example.practicekopring.entities.User
import com.example.practicekopring.entities.UpdateUserInfo
import com.example.practicekopring.services.UserService
import org.springframework.data.domain.Page
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.bind.annotation.PathVariable
@RestController
@RequestMapping("/api/v1/users")
class UserController(private val userService: UserService) {
// 1. 모든 사용자 조회
@GetMapping("/")
fun getAllUsers(): List<User> {
return userService.getAllUsers()
}
// 2. 사용자 생성
@PostMapping("/loginUser")
fun loginUser(
@RequestParam fromIp: String,
@RequestParam fromDevice: String,
@RequestParam fromChannel: String
): User? {
return userService.loginUser(fromIp, fromDevice, fromChannel)
}
// 3. 사용자 업데이트
@PutMapping("/{id}/update")
fun updateUser(
@PathVariable id: String,
@RequestParam fromIp: String
): User? {
val updatedUser = userService.updateUser(id, fromIp)
return updatedUser
}
// 4. 사용자 업데이트 body 버전
@PostMapping("/update-with-body")
fun updateUserWithBody(
@RequestBody user: UpdateUserInfo
): User? {
val updatedUser = userService.updateUserWithBody(user)
return updatedUser
}
// 5. 사용자 검색
@PostMapping("/search-user-by-fromip")
fun searchUsersByFromIp(
@RequestParam keyword: String
): List<User> {
return userService.searchUsersByFromIp(keyword)
}
// 6. 사용자 삭제
@DeleteMapping("/{id}/delete")
fun deleteUser(
@PathVariable id: String
) {
userService.deleteUser(id)
}
// 7. 사용자 카운트 조회
@GetMapping("/count")
fun getUserCount(): Long {
return userService.getUserCount()
}
// 10. 사용자 정렬 조회 (예: 이름 오름차순)
@GetMapping("/sorted")
fun getUsersSortedByName(): List<User> {
return userService.getUsersSortedByFromIp()
}
// 11. 특정 페이지의 사용자 조회 (페이징)
@GetMapping("/paged")
fun getUsersByPage(
@RequestParam page: Int,
@RequestParam size: Int
): Page<User> {
return userService.getUsersByPage(page, size)
}
}
4. 없는 계정으로 로그인 시도
= 회원가입 처리 진행 정상적으로 되는거 확인
5. 있는 계정으로 로그인 시도
있는 계정이므로, 있는 해당 데이터의 일부를 수정합니다.