부자 되기 위한 블로그, 머니킹

안녕하세요. 요즘 spring으로 이력서 제작 웹사이트를 개발중에 있는데요. 그 중에서 jpa를 이용한 drag event 를 활용할 필요가 있었습니다. 해당 부분을 개발하는데 많은 고민을 해야 했던것 같습니다. 아무래도 첫 프로젝트다 보니 그렇겠죠? 이번 포스팅에서는 제가 어떻게 jpa를 활용하여 drag 이벤트를 구현했는지 알아보려고 합니다.

 

Front 부분

    <link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet" type="text/css" />

    <script type="text/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.js" ></script>
    
    
<div class="container" ng-app="container" ng-controller="container-controller">
    <ul id="sortable">
        <li class="ui-state-default">
            <span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
            <span class="inner">mine 1</span>
        </li>
        <li class="ui-state-default">
            <span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
            <span class="inner">mine 2</span>
        </li>
        <li class="ui-state-default">
            <span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
            <span class="inner">mine 3</span>
        </li>
        <li class="ui-state-default">
            <span class="ui-icon ui-icon-arrowthick-2-n-s"></span><
            span class="inner">mine 4</span>
        </li>
        <li class="ui-state-default">
            <span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
            <span class="inner">mine 5</span>
        </li>
    </ul>

</div>

 

먼저 Jquery-ui 를 cdn으로 가져와야 합니다. 당연히 그 이전에 Jquery에 대한 부분도 가져와야 하고요. (해당 jquery를 가져오는 부분은 위쪽에 생략되어 있습니다.)

 

 

$("#sortable").sortable({
        placeholder:"itemBoxHighlight",
        /* 이동할 위치 css 적용 */
        start:function(event,ui){
        },
        stop:function(event,ui){
            reorder();
        }
    });

    function reorder() {
        $("#sortable li").each(function(i, box) {
            $(box).val(i + 1);
        });
    }

이후 sortable 함수를 사용하여 drag 이벤트를 지정해두었는데요. start는 드래그 이벤트 시작시 실행되는 함수이고 stop은 drag 이벤트 종료시 호출되는 함수입니다. jpa를 이용해 조작하려면 stop 부분에 ajax 부를 추가하여 데이터 순서를 업데이트 해주어야 합니다.

 

웹페이지를 띄워 테스트해보면 순서가 잘 드래그 되며 드래그 종료시 순서가 바뀌는 모습을 볼 수 있습니다.

 

$("#block-list").sortable({
    placeholder:"itemBoxHighlight",
    /* 이동할 위치 css 적용 */
    start:function(event,ui){
    },
    stop:function(event,ui){
        console.log(event.target)

        let blockIds = $.map($("#block-list .block-section"), function (select) {
            console.log($(select).data("block-id"));
            return $(select).data("block-id")
        });

        console.log(blockIds)

        const sendUrl = "/profile/update/block/seq";
        const sendData = JSON.stringify({blockIds:blockIds});

        const {resultData,resultStatus} = postCRUD(sendUrl, sendData);

        if(resultStatus == "success"){
            toastr.options.positionClass = "toast-bottom-right";
            toastr.success("성공적으로 순서가 바뀌었습니다");
        }

        reorder();
    }
});

function reorder() {
    $("#block-list li").each(function(i, box) {
        $(box).val(i + 1);
    });
}

 

저같은 경우에는 block-list라는 부분에서 sortable을 활용하였고 해당 data부에 있는 block-id를 총합한 후에 서버쪽으로  보내주었습니다. 여기서 핵심은 class 집합을 array로 받을떄 배치된 순서대로 들어오는 특성을 이용해서 따로 Index 값을 받지 않고 바로 data value만 array 로 가공하여 서버로 보내주었습니다.

 

spring backend 부분

@PostMapping(value = "/update/block/seq", produces = "application/json")
public ResponseEntity updateBlockSeq(
        @RequestBody Map<String, List<String>> sendData
) {
    log.info("updateBlockSeq");

    List<String> blockIds = sendData.get("blockIds");

    profileService.updateBlockSeq(blockIds);

    Map<String, Object> result = new HashMap<>();

    return new ResponseEntity<>(result, HttpStatus.OK);
}

블록아이디를 컨트롤러에서 받아준 후에 service 부에서 blcok 데이터 부를 Update 해주기로 하였습니다.

 

   public void updateBlockSeq(List<String> blockIds) {
        for (int i = 1; i <= blockIds.size(); i++) {
            System.out.println("i = " + i);
            ProfileBlock profileBlock = profileBlockRepository.findById(Long.valueOf(blockIds.get(i-1)));

            profileBlock.setSequence(i);
        }
    }

들어온 blockId는 배치된 list 순서대로 들어왔기 때문에 For문을 돌려서 해당 id를 값으로 가지고 있는 profileBlock을 찾은 후에 for문의 i를 인덱스로 sequence column을 업데이트 해주었습니다.

 

    public List<ProfileBlockComponentContent> findAllByProfileComponent(ProfileBlockComponent profileBlockComponent) {
        JPAQuery<ProfileBlockComponentContent> query = new JPAQuery<>(em);
        QProfileBlockComponentContent profileBlockComponentContent = QProfileBlockComponentContent.profileBlockComponentContent;
        return query.from(profileBlockComponentContent)
                .where(profileBlockComponentContent.profileBlockComponent.eq(profileBlockComponent))
                .orderBy(profileBlockComponentContent.sequence.asc())
                .fetch();
    }

 

그리고 나중에 페이지 로드시 찾는 블록 부분에 orderBy 부분을 추가하여 sequence 순서대로 List를 받게 설정하였습니다. 그러면 thymeleaf에서는 순서대로 반복문을 돌려 요소를 배치하기 떄문에 저장한 순서 그대로를 보여주죠