인생 디벨로퍼

[Ajax] 좋아요 만들기! 본문

JAVA Spring

[Ajax] 좋아요 만들기!

뫄뫙뫄 2023. 6. 18. 04:43
728x90
반응형

뷰 구현

jQuery 라이브러리 추가

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

하트 모양 이모티콘 추가

<i id="heart" class="fa-regular fa-heart fa-lg" value="no" style="margin-left: 3%;"></i>

클릭 모션 script 

    <script>
                        $("#heart").click(() => {
                            let value = $("#heart").val();
                            if (value == "ok") {
                                $("#heart").removeClass("fa-solid");
                                $("#heart").val("no");
                            } else {
                                $("#heart").addClass("fa-solid");
                                $("#heart").val("ok");
                            }
                        });
                    </script>

 

클릭시 하트가 채워진다


테이블 생성

create table love_tb(
    id int auto_increment primary key,
    board_id int not null,
    user_id int not null,
    created_at timestamp not null
);

모델링 

package shop.mtcoding.newblog.model;

import java.sql.Timestamp;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class Love {
    private Integer id;
    private Integer boardId;
    private Integer userId;
    private Timestamp createdAt;
}

 

package shop.mtcoding.newblog.model;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface LoveRepository {

    public Love findByBoardIdAndUserIdLove(int boardId, int userId);

    public List<Love> findAll();

    public Love findById(int id);

    public int insert(Love love);

    public int updateById(Love love);

    public int deleteById(int id);

}

board_id, user_id 로 조회 쿼리

select * from love_tb where board_id=1 and user_id=1;

참고 해, 매퍼 만들기

 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="shop.mtcoding.newblog.model.LoveRepository">

    <select id="findByBoardIdAndUserIdLove" resultType="shop.mtcoding.newblog.model.Love">
        select * from board_tb
    </select>

    <select id="findAll" resultType="shop.mtcoding.newblog.model.Love">
        select * from board_tb
    </select>

    <select id="findById" resultType="shop.mtcoding.newblog.model.Love">
        select * from board_tb where id = #{id}
    </select>    
    
    <insert id="insert">
        insert into love_tb (board_id, user_id, created_at) values(#{boardId}, #{userId}, now())
    </insert>    

    <delete id="deleteById" >
        delete from love_tb where id = #{id} 
    </delete>    


</mapper>

1. 좋아요 상태 보기

Controller

 @GetMapping("/board/{id}")
    public String detail(@PathVariable int id, Model model) {

        User principal = (User) session.getAttribute("principal");
        if (principal != null) {
            Love love = loveRepository.findByBoardIdAndUserIdLove(id, principal.getId());
            model.addAttribute("love", love);
        }

        BoardDetailRespDto board = boardService.글상세보기(id);
        model.addAttribute("board", board);

        List<ReplyDetailRespDto> replyDtoList = replyService.getReplyList(board.getId());
        model.addAttribute("replyDtoList", replyDtoList);

        return "board/detail";
    }

jsp 수정

 <div class="mb-2">
                        글 번호 : <span id="id"><i>${board.id}</i></span> 작성자 : <span><i>${board.username}</i></span>
                        <c:choose>
                            <c:when test="${love==null}">
                                 <i id="heart" class="fa-regular fa-heart fa-lg" style="margin-left: 3%;"></i>
                            </c:when>
                            
                            <c:otherwise>
                                <i id="heart" class="fa-solid fa-heart fa-lg" style="margin-left: 3%;"></i>
                            </c:otherwise>
                        </c:choose>

board id 와, principal id 가 있을경우 꽉찬 하트로 나타내기


2. 좋아요 on

Controller

@PostMapping("/love")
    public @ResponseBody ResponseEntity<?> loveSave(@RequestBody LoveReqDto loveReqDto) {
        User principal = (User) session.getAttribute("principal");
        if (principal == null) {
            throw new CustomApiException("인증이 필요합니다.", HttpStatus.BAD_REQUEST);
        }
        if (loveReqDto.getBoardId() == null) {
            throw new CustomApiException("boardId를 전달해 주세요");
        }
        int loveId = loveService.좋아요(loveReqDto.getBoardId(), principal.getId());
        return new ResponseEntity<>(new ResponseDto<>(1, "좋아요 성공", loveId), HttpStatus.OK);
    }

json 으로 받아오기.

attr() 메서드는 선택자로 요소를 선택한 후, 해당 요소의 지정된 속성 값을 반환

insert 되며 생성된 'love id' 데이터 반환

Service

  @Transactional
    public int 좋아요(int boardId, int principalId) {

        Board boardOP = boardRepository.findById(boardId);
        if (boardOP == null) {
            throw new CustomApiException("게시글이 존재하지 않습니다", HttpStatus.BAD_REQUEST);
        }

        Love love = new Love();
        love.setBoardId(boardId);
        love.setUserId(principalId);
        loveRepository.insert(love);

        return love.getId();

    }

love 객체를 생성해서 board id 와 principal id 를 주입.

.xml

   <insert id="insert" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
        insert into love_tb (board_id, user_id, created_at) values(#{boardId}, #{userId}, now())
    </insert>
  • useGeneratedKeys="true": 이 속성은 자동 생성된 키를 사용할지 여부. 즉, 데이터베이스에서 자동으로 생성되는 키를 사용하도록 설정함.
  • keyColumn="id": 이 속성은 자동 생성된 키가 저장될 컬럼의 이름.
  • keyProperty="id": 이 속성은 자동 생성된 키가 매핑될 객체의 프로퍼티(property) 이름.

id 는 데이터 베이스에서 자동으로 생성 되도록 설정.

jsp

       <div class="mb-2">
                        글 번호 : <span id="id"><i>${board.id}</i></span> 작성자 : <span><i>${board.username}</i></span>
                        <c:choose>
                            <c:when test="${love==null}">
                                 <i id="heart" class="fa-regular fa-heart fa-lg" value="${love.id}" onClick="loveUpdate()" style="margin-left: 3%;"></i>
                            </c:when>
                            
                            <c:otherwise>
                                <i id="heart" class="fa-solid fa-heart fa-lg" value="${love.id}" onClick="loveUpdate()" style="margin-left: 3%;"></i>
                            </c:otherwise>
                        </c:choose>
                        
                    </div>
                    
<script>
    function loveUpdate() {
        let boardId = $("#boardId").val();
        let id = $("#heart").attr("value");
        console.log(id);
        if (id=="") {

            let data = {boardId:boardId}
            
            $.ajax({
                type: "post",
                url: "/love",
                data: JSON.stringify(data),
                contentType: "application/json; charset=utf-8",
                dataType: "json"
            }).done((res) => { // 20X 일때
                $("#heart").attr("value",res.data);
                $("#heart").addClass("fa-solid");
                $("#heart").removeClass("fa-regular");
             
            }).fail((err) => {
                alert(err.responseJSON.msg);
                console.log("실패");
            });

        }

.attr 메소드로 value 값을 res.date 로 변경해줌

.addClass 메소드로 class 에 문장 추가.

.removeClass 메소드로 class 에 문장 삭제.


3. 좋아요 취소 

Controller

@DeleteMapping("/love/{id}")
    public @ResponseBody ResponseEntity<?> loveDelete(@PathVariable int id) {
        User principal = (User) session.getAttribute("principal");
        if (principal == null) {
            throw new CustomApiException("인증이 필요합니다.", HttpStatus.BAD_REQUEST);
        }
        loveService.좋아요취소(id, principal.getId());
        return new ResponseEntity<>(new ResponseDto<>(1, "좋아요 취소 성공", null), HttpStatus.OK);
    }

Service

    @Transactional
    public void 좋아요취소(int id, int principalId) {
        Love lovePS = loveRepository.findById(id);

        if (lovePS == null) {
            throw new CustomApiException("좋아요 내역이 존재하지 않습니다", HttpStatus.BAD_REQUEST);
        }

        if (lovePS.getUserId() != principalId) {
            throw new CustomApiException("좋아요 취소 권한이 없습니다.", HttpStatus.BAD_REQUEST);
        }
        try {
            loveRepository.deleteById(id);
        } catch (Exception e) {
            throw new CustomApiException("서버에 일시적인 문제가 생겼습니다.", HttpStatus.INTERNAL_SERVER_ERROR);
        }

    }

jsp

 else {
                        
           $.ajax({
                type: "delete",
                url: "/love/" + id,
                dataType: "json"
            }).done((res) => { // 20X 일때
                $("#heart").attr("value",res.data);
                $("#heart").removeClass("fa-solid");
                $("#heart").addClass("fa-regular");
            }).fail((err) => { // 40X, 50X 일때
                alert(err.responseJSON.msg);
                });
        }

    }
</script>

 

728x90
반응형

'JAVA Spring' 카테고리의 다른 글

Cookie 아이디 저장하기  (0) 2023.06.18
[Ajax] 비밀번호 확인  (0) 2023.06.18
[Ajax] 썸네일 수정 contentType 설정  (0) 2023.06.17
SHA-256 해시 함수 코드  (0) 2023.05.12
spring 정리  (0) 2023.05.09