본문 바로가기

카테고리 없음

24.02.08 챌린지 도전

댓글 작성 API에 게시글에 대한 좋아요를 넣어야 한다.

package com.example.demo.model

import jakarta.persistence.*

@Entity
@Table(name = "PostLike")
class Like(
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long? = null,

    @ManyToOne
    val member: Member,

    @ManyToOne
    val post: Post
)

 

이렇게 like엔티티를 생성했는데, like는 데이터베이스 테이블의 이름으로 쓸수 없다고 하길래  @Table(name = "PostLike")를 넣어서 이름을 바꿨다.

interface LikeService {
    fun addLike(memberId: Long, postId: Long)
}
data class CommentCreateDto(
    val postId: Long,
    val nickname: String,
    val content: String,
    val isLike: Boolean   // 좋아요를 눌렀는지 여부를 표시하는 필드
)

이렇게 각각 작성하고

package com.example.demo.service
import com.example.demo.model.Like
import com.example.demo.repository.LikeRepository
import com.example.demo.repository.MemberRepository
import com.example.demo.repository.PostRepository
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
class LikeServiceImpl(
    private val postRepository: PostRepository,
    private val memberRepository: MemberRepository,
    private val likeRepository: LikeRepository
) : LikeService {

    @Transactional
    override fun addLike(memberId: Long, postId: Long) {
        val member = memberRepository.findById(memberId).orElseThrow {
            IllegalArgumentException("해당하는 회원이 없습니다.")
        }
        val post = postRepository.findById(postId).orElseThrow {
            IllegalArgumentException("해당하는 게시글이 없습니다.")
        }

        if (likeRepository.existsByMemberAndPost(member, post)) {
            throw IllegalArgumentException("이미 좋아요를 누른 게시글입니다.")
        }

        val like = Like(member = member, post = post)
        likeRepository.save(like)
    }

}
package com.example.demo.service

import com.example.demo.dto.CommentCreateDto
import com.example.demo.dto.CommentDto
import com.example.demo.dto.CommentUpdateDto
import com.example.demo.model.Comment
import com.example.demo.repository.CommentRepository
import com.example.demo.repository.LikeRepository
import com.example.demo.repository.PostRepository
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import com.example.demo.model.Like
import com.example.demo.repository.MemberRepository


@Service
class CommentServiceImpl(
    private val commentRepository: CommentRepository,
    private val postRepository: PostRepository,
    private val likeRepository: LikeRepository,
    private val memberRepository: MemberRepository
) : CommentService {

    @Transactional
    override fun createComment(userId: Long, dto: CommentCreateDto): CommentDto {
        val post = postRepository.findById(dto.postId)
            .orElseThrow { IllegalArgumentException("Post not found") }

        val comment = Comment(
            post = post,
            userId = userId,
            nickname = dto.nickname,
            content = dto.content
        )
        commentRepository.save(comment)

        // 좋아요를 처리하는 로직
        if (dto.isLike) {
            val member = memberRepository.findById(userId).orElseThrow { IllegalArgumentException("Member not found") }
            val post = postRepository.findById(dto.postId).orElseThrow { IllegalArgumentException("Post not found") }
            val like = Like(member = member, post = post)
            likeRepository.save(like)
        }

        return CommentDto.from(comment)
    }

    @Transactional
    override fun updateComment(id: Long, userId: Long, dto: CommentUpdateDto): CommentDto {
        val comment = commentRepository.findByIdAndUserId(id, userId)
            .orElseThrow { IllegalArgumentException("Comment not found or not owned by user") }

        comment.content = dto.content

        return CommentDto.from(comment)
    }

    @Transactional(readOnly = true)
    override fun getComment(id: Long): CommentDto {
        val comment = commentRepository.findById(id)
            .orElseThrow { IllegalArgumentException("Comment not found") }

        return CommentDto.from(comment)
    }

    @Transactional
    override fun deleteComment(id: Long, userId: Long) {
        val comment = commentRepository.findByIdAndUserId(id, userId)
            .orElseThrow { IllegalArgumentException("Comment not found or not owned by user") }

        commentRepository.deleteById(id)
    }
}

 

지대로 작동하긴 하는데, 문제는 좋아요가 댓글 작성에 통합되어 있어서 그런지 댓글 하나를 작성하고 나면 에러메시지를 띄운다는것이다. 그 이유는 이미 좋아요가 된 게시글입니다! 라는 이유였다.

 

if (likeRepository.existsByMemberAndPost(member, post)) {
            throw IllegalArgumentException("이미 좋아요를 누른 게시글입니다.")
        }를 없애서 해결!!

 

다음에 해야할건,

- [ ]  회원 가입 버튼을 누르기 전, 같은 닉네임이 존재하는지 "확인" 버튼을 눌러 먼저 유효성 검증부터 할 수 있도록 해보기
- [ ]  (챌린지 과제) 데이터베이스에 비밀번호를 평문으로 저장하는 것이 아닌, 단방향 암호화 알고리즘을 이용하여 암호화 해서 저장하도록 하기

package com.example.demo.security

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder

@Configuration
class PasswordEncoderConfig {

    @Bean
    fun passwordEncoder(): PasswordEncoder {
        return BCryptPasswordEncoder()
    }
}

 

package com.example.demo.service

import com.example.demo.dto.LoginRequest
import com.example.demo.dto.LoginResponse
import com.example.demo.dto.SignUpRequest
import com.example.demo.jwt.JwtPlugin
import com.example.demo.model.Member
import com.example.demo.repository.MemberRepository
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.stereotype.Service

@Service
class MemberServiceImpl(
    private val memberRepository: MemberRepository,
    private val jwtPlugin: JwtPlugin,
    private val passwordEncoder: PasswordEncoder// 이것과
): MemberService {
    override fun signUp(signUpRequest: SignUpRequest): Member {
        if (signUpRequest.nickName == signUpRequest.password) {
            throw IllegalArgumentException("비밀번호는 닉네임과 같을 수 없습니다.")
        }

        if (signUpRequest.password != signUpRequest.passwordConfirm) {
            throw IllegalArgumentException("비밀번호와 비밀번호 확인이 일치하지 않습니다.")
        }

        if (memberRepository.existsByNickName(signUpRequest.nickName)) {
            throw IllegalArgumentException("이미 존재하는 닉네임입니다.")
        }
        val encodedPassword = passwordEncoder.encode(signUpRequest.password)//이거


        val newMember = Member(nickName = signUpRequest.nickName, password = signUpRequest.password)
        return memberRepository.save(newMember)
    }

    override fun login(loginRequest: LoginRequest): LoginResponse {
        val member = memberRepository.findByNickName(loginRequest.nickName)
            ?: throw IllegalArgumentException("닉네임 또는 패스워드를 확인해주세요.")

        if (member.password != loginRequest.password) {
            throw IllegalArgumentException("닉네임 또는 패스워드를 확인해주세요.")
        }

        return LoginResponse(
            accessToken = jwtPlugin.generateAccessToken(
                subject = member.id.toString(),  // 사용자의 ID를 subject로 사용
                nickName = member.nickName  // 사용자의 닉네임을 nickName으로 사용
            )
        )
    }
    override fun existsByNickName(nickname: String): Boolean {
        return memberRepository.existsByNickName(nickname)//이것도 추가
    }
}

 

interface MemberService {
    fun signUp(signUpRequest: SignUpRequest): Member
    fun login(loginRequest: LoginRequest): LoginResponse
    fun existsByNickName(nickname: String): Boolean // 확인을 위해 추가

}

 

package com.example.demo.controller

import com.example.demo.dto.LoginRequest
import com.example.demo.dto.SignUpRequest
import com.example.demo.model.Member
import com.example.demo.service.MemberService
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/api/members")
class MemberController(private val memberService: MemberService) {

    @PostMapping("/signup")
    fun signUp(@RequestBody signUpRequest: SignUpRequest): ResponseEntity<Member> {
        val member = memberService.signUp(signUpRequest)
        return ResponseEntity.ok(member)
    }

    @PostMapping("/login")
    fun login(@RequestBody loginRequest: LoginRequest): ResponseEntity<Any> {
        return try {
            val loginResponse = memberService.login(loginRequest)
            ResponseEntity.ok().body(loginResponse)
        } catch (e: IllegalArgumentException) {
            ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.message)
        }
    }

    @GetMapping("/check-nickname")
    fun checkNickname(@RequestParam nickname: String): ResponseEntity<String> {
        return if (memberService.existsByNickName(nickname)) {
            ResponseEntity.badRequest().body("닉네임이 중복됩니다.")
        } else {
            ResponseEntity.ok().body("사용 가능한 닉네임입니다.")
        }
    }// 회원 가입 버튼을 누르기 전, 같은 닉네임이 존재하는지 "확인" 버튼을 눌러 먼저 유효성 
    검증부터 할 수 있도록 해보기가 이것
}

이러면 될거다!