본문 바로가기
Web Development/Spring Legacy

[Spring / Legacy] 다중 정렬 기능 구현(feat. Mapper XML 파일에서 List 처리 방법)

by 감자맹고우 2023. 2. 7.
728x90
반응형

Spring Legacy 프로젝트를 구현하면서, 정렬 기능은 흔하게 구현하는 기능이다.

간단하게는 쿼리에서 ORDER BY를 통해 쉽게 처리 가능하다.

그러나 이번에 구현할 기능은, 다중 정렬 기능이다. 별다른 기능은 아니고 여러 개를 동시에 정렬하는 기능이다.

 

이런 정렬 기능을 DB 툴 등에서 쉽게 발견할 수 있다.

 

위 이미지처럼 하나의 컬럼이 오름차순 정렬이 되어 있어도 다른 컬럼의 오름차순 정렬이 동작하는 기능이다.

여기까지만 생각하면, 그냥 리스트에 담아서 처리하거나 null 예외 처리 등으로 바로 쿼리의 ORDER BY에 대입하여 처리하면 될 것이다.

 

그러나 기능을 좀 더 분석해보기로 했다.

그 결과, 가장 마지막으로 선택한 Column을 최우선 순위로 하여 정렬하는 모습을 발견할 수 있었다.

당연하게도 ORDER BY는 가장 앞 순위의 컬럼부터 정렬을 한다.

그렇기 때문에 단순하게 대입만 하는 방식으로 처리한다면, 앞 순위의 컬럼부터 정렬하기 때문에 사용자의 의도와는 다른 정렬이 이루어질 수 있다.

 

위의 이미지로 예를 들면, _pageName의 오름차순이 선택된 상태에서 _pageTitle의 오름차순을 사용자가 선택하면, 선택한 _pageTitle의 오름차순 정렬이 아닌 컬럼 순서 상 앞 순서인 _pageName의 오름차순 정렬을 우선순위로 한 정렬 결과를 보여주게 되는 것이다.

그렇기 때문에 원하는 의도대로 동작하려면, 사용자가 마지막으로 선택한 컬럼을 따로 저장해 처리할 필요가 있다.

이제 구현해보자.

 

 

[ 구현 방법 ]

 

우선, Java에서 2개의 클래스를 만들었다.

 

(1) 정렬 대상 컬럼과 순서(오름차순, 내림차순) 를 담을 클래스

public class Order {
    private String column;
    private String direction;
    
    /* 생성자 */
    //아래에 parameter를 받아 처리하는 생성자를 만들어주었기 때문에,
    //기본생성자를 직접 만들어주었음
    public Order() {}
    //편의상, 기본생성자와 별개로 parameter를 받는 생성자를 만들어주었음
    public Order(String column, String direction) {
        this.column = column;
        this.direction = direction;
    }
    
    public String getColumn() {
        return column;
    }
    public void setColumn(String column) {
        this.column = column;
    }
    public String getDirection() {
        return direction;
    }
    public void setDirection(String direction) {
        this.direction = direction;
    }
}

 

(2) 사용자가 정렬하려고 하는 컬럼 정보 리스트와, 현재 선택한 컬럼 이름을 담을 클래스

import java.util.ArrayList;
import java.util.List;

import com.~~~.Order; //앞의 Order 클래스

public class UserOrder {
    private String lastSelectedColumn;
    private List<Order> orderList;
    
    public String getLastSelectedColumn() {
        return lastSelectedColumn;
    }
    public void setLastSelectedColumn(String lastSelectedColumn) {
        this.lastSelectedColumn = lastSelectedColumn;
        //마지막 선택한 컬럼을 지정 시,
        //정렬할 컬럼 리스트에서, 마지막 선택한 컬럼을 가장 처음으로 배치한 리스트로
        //정렬할 컬럼 리스트를 변경
        List<Order> list = new ArrayList<Order>();
        List<Order> prevList = getOrderList();
        if(prevList != null) {
            for(Order o : prevList) {
                if(this.lastSelectedColumn.equals(o.getColumn())) {
                    Order order = new Order(o.getColumn(), o.getDirection());
                    list.add(order);
                    prevList.remove((Object)o);
                    break;
                }
            }
            for(Order o : prevList)
                list.add(o);
        }
        setOrderList(list);
    }
    public List<Order> getOrderList() {
        return orderList;
    }
    public void setOrderList(List<Order> orderList) {
        this.orderList = orderList;
    }
}

 

반응형

 

그리고, 뷰단에서 사용자가 정렬을 하려는 컬럼들을 서버단에서 각각 Order 클래스 변수로 할당했다.

//예시
new Order("_pageName", "DESC");

 

다음으로는, UserOrder 클래스 변수를 생성하였다.

UserOrder 클래스에는 lastSelectedColumn과 orderList 변수가 있다.

 

이를 할당해주기 위해, 위에서 선언된 각각의 Order 클래스 변수를 List로 담아 orderList로 할당해주었고,

뷰단에서 전달한, 사용자가 마지막으로 선택한 컬럼을 lastSelectedColumn으로 할당해주었다.

이어서, 데이터를 조회하는 메소드에 UserOrder 클래스 변수를 파라미터로 넘겨 조회하도록 하였다.

설명한 코드는 대충 다음과 같다.

 

//Controller
public class TestController{

    private TestService testService;
    
    //생성자 주입
    public TestController(TestService testService) {
        this.testService = testService;
    }

    @GetMapping(value = "/test")
    public String test(ModelMap model, String lastSelectedColumn, String pageNameDir, String pageTitleDir) {
        List<Order> orderList = new ArrayList<Order>();
        addOrderList(orderList, "_pageName", pageNameDir);
        addOrderList(orderList, "_pageTitle", pageTitleDir);
        
        UserOrder userOrder = new UserOrder();
        userOrder.setOrderList(orderList);
        
        if(!StringUtils.isEmpty(lastSelectedColumn))
            userOrder.setLastSelectedColumn(lastSelectedColumn);
            
        //==> lastSelectedColumn이나 orderList를 뷰단으로 넘겨줄 시 별도 처리 필요
        //※ 주의 : orderList를 넘겨줄 시, orderList가 아니라 userOrder.getOrderList()를 넘겨주어야 함
        //-> 이유 : setLastSelectedColumn 시, List.remove 메소드 동작
        
        List<TestVO> testList = testService.getTestList(userOrder);
        model.addAttribute("testList", testList);
    }

    public void addOrderList(List<Order> list, String column, String direction) {
        if(!StringUtils.isEmpty(direction)) {
            Order o = new Order();
            o.setColumn(column);
            o.setDirection(direction);
            list.add(o);
        }
    }
}

 

이제, Mapper.xml 파일에서 자바의 컬렉션인 List를 어떻게 처리할 지 알아보자.

구글링을 통해 해결방법을 쉽게 찾을 수 있지만, 항상 동일하게 처리되진 않으므로 내가 사용한 코드는 대충 다음과 같다.

 

-- Mapper.xml
<select id="getTestList" parameterType="UserOrder" resultType="TestVO">
    SELECT
        *
    FROM
        tb_test
    -- orderList에 Order가 있는지 확인
    <if test="orderList.size > 0">
    ORDER BY
        <foreach collection="orderList" item="item" separator=",">
            -- 컬럼명을 직접 대입할 때는 #{}를 사용하지만,
            -- Collection 의 요소를 대입할 때는 ${}를 사용함에 유의
            ${item.column} ${item.direction}
        </foreach>
    </if>
</select>

 

이렇게 하면 Java의 List를 Mapper XML 파일에서 처리하여, 다중 정렬 기능을 구현할 수 있다!

 

( 코드를 축약하다 보니, 정상 동작하지 않을 수 있습니다. 문제가 발생하면 댓글 남겨주세요~ )

 

 

🤞 도움이 되셨기를 바랍니다. 한 번의 클릭과 댓글은 어딘가의 누군가에게 진실로 큰 힘이 됩니다. 🐱‍🏍

 

728x90
반응형

댓글