ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Mybatis Interceptor 자동 Paging처리 사용방법
    개발/Spring Boot 2021. 4. 24. 13:53

    Github 소스코드보기

    Notion으로 보는것을 추천

     

    Mybatis Interceptor 자동 Paging처리 만들기(1) 바로가기

    Mybatis Interceptor 자동 Paging처리 만들기(2) 바로가기

     

    ♣️미리보기


    • H2 Database Table Data
    • HTTP GET 통신
    • return 값
    {
        "list": [
            {
                "num": 1,
                "id": "test1",
                "pw": "test1",
                "name": "테스트1"
            },
            {
                "num": 2,
                "id": "test2",
                "pw": "test2",
                "name": "테스트2"
            }
        ],
        "pageInfo": {
            "page": 1,
            "size": 2,
            "totalCount": 3
        }
    }

     

    ♦ Controller 매개변수 PageInfo 상속

     

    @RestController
    @RequestMapping(path = "/users")
    public class UserController {
    
      @Autowired
      private UserService userService;
    
      @GetMapping
      public PagableResponse<User> selectUserList(@ModelAttribute @Valid UserSearch userSearch) {
        return userService.selectUserList(userRequest);
      }
    }

    @ModelAttribute 어노테이션에 의해, 조회조건 데이터를 UserSearch에 Binding

     

    @Data
    @EqualsAndHashCode(callSuper = false)
    public class UserSearch extends PageInfo {
      private String id;
      private String name;
    }

    PageInfo상속받는다.

    import javax.validation.constraints.Min;
    import org.apache.ibatis.session.RowBounds;
    import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
    import lombok.Data;
    import lombok.EqualsAndHashCode;
    
    @Data
    @EqualsAndHashCode(callSuper = false)
    @JsonIgnoreProperties({"offset", "limit"})
    public class PageInfo extends RowBounds {
      
      protected Integer page = 1;
    
      @Min(1)
      protected Integer size = 10;
    
      protected Long totalCount = -1L; // set이 되지않았다는 의미로 -1
    }

    조회시 page, size값을 사용, totalCount는 이후 return 시 사용된다.

     

    ♦ Mapper 매개변수PageInfo를 상속받은 객체를 전달, Return Class는 반드시 PagableResponse<T>

     

    @Mapper
    public interface UserMapper {
      @Select(value = """
              <script>
                SELECT * FROM USER
                WHERE 1 = 1
                <if test='id != null and !id.equals("")'>
                  AND ID LIKE '%${id}%'
                </if>
              </script>
          """)
      public PagableResponse<User> selectUserList(UserSearch userRequest);
    }
    1. Controller에서 넘어온 UserSearch 객체를 그대로 매개변수로 전달
    1. Return할 Class를 반드시 PagableResponse<T> 로 지정
    @Data
    @JsonFormat(shape = Shape.OBJECT)
    public class PagableResponse<T> implements List<T> {
    
      private List<T> list;
      
      private PageInfo pageInfo;
    
      public PagableResponse() {
        list = new ArrayList<>();
        pageInfo = new PageInfo();
      }
      
      /*
       * 아래는 List Method Override 
       */
      @Override
      public int size() {
        return list.size();
      }
    	.
    	.
    	.
    }

     

    ♦ 기능 테스트

    User 테이블 Data

    @Autowired
    private UserMapper userMapper;
    
    @Test
    @DisplayName("page, size 지정")
    void selectUserListTestWithPageAndSize() {
      log.debug("■■■ selectUserListTestWithPageAndSize Start ■■■■");
      UserSearch userSearch = new UserSearch();
      userSearch.setPage(1);
      userSearch.setSize(2);
      
      PagableResponse<User> returnObject = userMapper.selectUserList(userSearch);
      log.debug(returnObject.getList().toString());
      log.debug(returnObject.getPageInfo().toString());
      log.debug("■■■ selectUserListTestWithPageAndSize End ■■■■");
    }

    page, size 지정 결과

    c.e.d.api.user.service.UserServiceTests  : ■■■ selectUserListTestWithPageAndSize Start ■■■■
    c.e.d.c.m.interceptor.QueryInterceptor   : ■■ QueryInterceptor intercept: Request Parameter가 PageInfo.class를 상속■■
    c.e.d.a.u.m.U.selectUserList-Long        : ==>  Preparing: SELECT COUNT(*) FROM ( SELECT * FROM USER WHERE 1 = 1 ) COUNT_TABLE
    c.e.d.a.u.m.U.selectUserList-Long        : ==> Parameters: 
    c.e.d.a.u.m.U.selectUserList-Long        : <==      Total: 1
    c.e.d.a.u.m.UserMapper.selectUserList    : ==>  Preparing: SELECT * FROM USER WHERE 1 = 1 LIMIT 0, 2
    c.e.d.a.u.m.UserMapper.selectUserList    : ==> Parameters: 
    c.e.d.a.u.m.UserMapper.selectUserList    : <==      Total: 2
    1. SELECT COUNT(*) FROM ( ~~~ ) COUNT_TABLE 을 붙여서 totalCount를 먼저 구함
    • CountQuery를 Wrapper 형식으로 감싸지않고 SELECT ? FROM 을 정규식으로 COUNT(*)을 삽입하면 성능 향상에 좋을듯

    2. Mapper에 작성된 Select문에 LIMIT 을 붙여서 size 갯수만큼 가져옴

    
    c.e.d.api.user.service.UserServiceTests  : list: [User(num=1, id=test1, pw=test1, name=테스트1), User(num=2, id=test2, pw=test2, name=테스트2)]
    c.e.d.api.user.service.UserServiceTests  : pageInfo: PageInfo(page=1, size=2, totalCount=3)
    c.e.d.api.user.service.UserServiceTests  : ■■■ selectUserListTestWithPageAndSize End ■■■■
    1. list는 size만큼 2개 확인
    1. pageInfo도 정상적으로 page, size, totalCount 채워서 반환 확인

     

    @Autowired
    private UserMapper userMapper;
    
    @Test
    @DisplayName("page, size 미지정")
    void selectUserListTestWithoutPageAndSize() {
      log.debug("■■■ selectUserListTestWithoutPageAndSize Start ■■■■");
      UserSearch userSearch = new UserSearch();
      
      PagableResponse<User> returnObject = userMapper.selectUserList(userSearch);
      log.debug(returnObject.getList().toString());
      log.debug(returnObject.getPageInfo().toString());
      log.debug("■■■ selectUserListTestWithoutPageAndSize End ■■■■");
    }

    page, size 미지정 결과

    c.e.d.c.m.interceptor.QueryInterceptor   : ■■ QueryInterceptor intercept: Request Parameter가 PageInfo.class를 상속■■
    c.e.d.a.u.m.U.selectUserList-Long        : ==>  Preparing: SELECT COUNT(*) FROM ( SELECT * FROM USER WHERE 1 = 1 ) COUNT_TABLE
    c.e.d.a.u.m.U.selectUserList-Long        : ==> Parameters: 
    c.e.d.a.u.m.U.selectUserList-Long        : <==      Total: 1
    c.e.d.a.u.m.UserMapper.selectUserList    : ==>  Preparing: SELECT * FROM USER WHERE 1 = 1
    c.e.d.a.u.m.UserMapper.selectUserList    : ==> Parameters: 
    c.e.d.a.u.m.UserMapper.selectUserList    : <==      Total: 3
    1. SELECT COUNT(*) FROM ( ~~~ ) COUNT_TABLE 을 붙여서 totalCount를 먼저 구함
    1. page or size 가 없어서 LIMIT 을 하지않고 SELECT
    
    c.e.d.api.user.service.UserServiceTests  : list: [User(num=1, id=test1, pw=test1, name=테스트1), User(num=2, id=test2, pw=test2, name=테스트2), User(num=3, id=test3, pw=test3, name=테스트3)]
    c.e.d.api.user.service.UserServiceTests  : pageInfo: PageInfo(page=null, size=null, totalCount=3)
    c.e.d.api.user.service.UserServiceTests  : ■■■ selectUserListTestWithoutPageAndSize End ■■■■
    1. list는 size를 지정하지 않았기에 전체인 3개 확인
    1. pageInfo도 정상적으로 page, size는 그대로 null, totalCount 채워서 반환 확인

     

    댓글

Designed by Tistory.