[코드로 배우는 스프링 웹 프로젝트 개정판] 3장 정리

스프링 MVC를 이용한 웹 프로젝트에서는 페이지 설정, 테스트 환경 설정, 기본적인 등록, 수정, 삭제, 조회, 목록 구현, 목록 화면의 페이징 처리, 검색 처리 및 페이지 이동 등의 단계가 필요하다. 페이징 처리를 위해서는 페이지 번호와 한 페이지당 보여줄 데이터의 수가 필요하며, MyBatis는 동적 태그 기능을 통해 SQL을 파라미터 조건에 맞게 조정할 수 있다. 또한, 검색 기능은 단일 항목 검색과 다중 항목 검색으로 분류할 수 있으며, 화면에서 검색은 페이지 번호 유지, 검색 조건과 키워드 유지, 한글 처리 등을 고려해야 한다.
DriedPollack's avatar
Mar 18, 2024
[코드로 배우는 스프링 웹 프로젝트 개정판] 3장 정리

🌼스프링 MVC 프로젝트의 기본 구성

💡핵심 포인트

  • 일반적으로 웹 프로젝트는 3-tier 방식으로 구성한다.
    • Presentation Tier는 화면에 보여주는 기술을 사용하는 영역이다. Servlet/JSP나 스프링 MVC가 담당하는 영역이 된다.
    • Business Tier는 순수한 비즈니스 로직을 담고 있는 영역이다. 이 영역의 설계는 실제로 고객의 요구 사항과 정확히 일치해야 한다.
    • Persistence Tier는 데이터를 어떤 방식으로 보관하고, 사용하는가에 대한 설계가 들어가는 계층이다. 일반적으로는 데이터베이스를 이용하지만, 경우에 따라서 네트워크 호출이나 원격 호출 등의 기술이 접목된다.
  • 스프링 MVC의 경우 Presentation Tier는 스프링 MVC가, Spring Core는 의존성 주입을 이용한 객체 간의 연관구조를, MyBatis는 SQL에 대한 처리를 담당한다.

각 영역의 Naming Convention

  • 프로젝트를 진행할 때에는 다음과 같은 네이밍 규칙을 가지고 작성한다.
    • xxxController: 스프링 MVC에서 동작하는 Controller 클래스를 설계할 때 사용한다.
    • xxxService, xxxServiceImpl: 비즈니스 영역을 담당하는 인터페이스는 ‘xxxService’를, 인터페이스를 구현한 클래스는 ‘xxxServiceImpl’라는 이름을 사용한다.
    • xxxDAO, xxxRepository: DAO나 Repository라는 이름으로 영역을 따로 구성하는 것이 보편적이다. 다만 MyBatis의 Mapper 인터페이스를 활용할 수도 있다.
    • VO, DTO: 데이터를 담고 있는 객체를 의미한다. VO는 Read Only의 목적으로, DTO는 데이터 수집의 용도가 더 강하다.
  • 패키지의 구성은 프로젝트의 크기나 구성원들의 성향으로 결정한다.
    • 예를 들어 규모가 작은 프로젝트는 Controller 영역을 별도의 패키지로 설계하고, Service 영역 등을 하나의 작은 패키지로 설계할 수 있다.
    • 반면에, 프로젝트의 규모가 커져서 많은 Service 클래스와 Controller들이 혼재할 수 있다면 비즈니스 단위 별로 패키지를 작성하고, 다시 내부에서 Controller 패키지, Service 패키지 등으로 다시 나누는 방식을 이용한다.

예제 프로젝트 구성

  • pom.xml에서 스프링의 버전과 Java 버전 등을 수정한다.
    • 스프링 관련해서 추가적인 라이브러리로는 spring-tx, spring-jdbc, spring-test가 필요하다.
    • MyBatis를 사용한다면 HikariCP, MyBatis, mybatis-spring, Log4jdbc 라이브러리도 추가한다.
    • 테스트와 Lombok을 위해서 jUnit 버전을 변경하고, Lombok을 추가한다.
    • servlet 3.1을 제대로 사용하기 위해서는 서블릿 3.0 버전 이상으로 수정해야 한다.
  • root-context.xml에는 mybatis-spring 네임스페이스를 추가하고, HikariCP와 MyBatis의 설정을 추가한다.
 

🌼영속/비즈니스 계층의 CRUD 구현

💡핵심 포인트

  • 영속 계층의 작업은 항상 다음과 같은 순서로 진행한다.
    • 테이블의 칼럼 구조를 반영하는 VO(Value Object) 클래스의 생성
    • MyBatis의 Mapper 인터페이스의 작성 / XML 처리
    • 작성한 Mapper 인터페이스의 테스트

영속 계층의 구현 준비

  • VO 클래스를 생성하는 작업은 테이블 설계를 기준으로 작성한다.
    • Lombok을 이용해서 생성자와 getter/setter, toString() 등을 만들어내려면 @Data 어노테이션을 적용한다.
  • 간단한 SQL이라면 어노테이션을 이용해서 처리하는 것이 무난하지만, SQL이 점점 복잡해지거나 상황에 따라 다른 SQL문이 처리되는 경우에는 그다지 유용하지 못할 수 있다.
    • SQL을 작성할 때는 반드시 ;이 없어야 한다.
  • XML을 작성하기 위해 폴더를 생성할 경우 한 번에 생성하는 것이 아닌 하나씩 생성해야 한다.
    • XML을 작성할 때는 반드시 <mapper>의 namespace 속성값을 Mapper 인터페이스와 동일한 이름을 줘야 한다.
    • <select> 태그의 id 속성값은 메서드의 이름과 일치하게 작성해야 한다.

영속 영역의 CRUD 구현

  • 웹 프로젝트 구조에서 구현을 가장 먼저 할 수 있는 영역은 영속 영역이다.
    • MyBatis는 내부적으로 JDBC의 PreparedStatement를 활용하고, 필요한 파라미터를 처리하는 ‘?’dp eogks clghksdms ‘#{속성}’을 이용해서 처리한다.
  • 자동으로 PK값이 정해지는 경우에는 다음과 같은 두 가지 방식으로 처리할 수 있다.
    • insert만 처리되고 생성된 PK 값을 알 필요가 없는 경우
    • insert문이 실행되고 생성된 PK 값을 알아야 하는 경우
      • @SelectKey는 주로 PK값을 미리 SQL을 통해서 처리해 두고 특정한 이름으로 결과를 보관하는 방식이다.
      • @SelectKey를 이용하는 방식은 SQL을 한 번 더 실행하는 부담이 있기는 하지만 자동으로 추가되는 PK값을 확인해야 하는 상황에서는 유용하게 사용된다.
  • MyBatis는 Mapper 인터페이스의 리턴 타입에 맞게 select의 결과를 처리하기 때문에 모든 파라미터와 리턴 타입의 처리는 get파라미터명(), set칼럼명()의 규칙으로 호출된다.
    • 다만 #{속성}이 1개만 존재하는 경우에는 별도의 get파라미터명()을 사용하지 않고 처리된다.
  • 특정 데이터의 삭제 역시 PK 값을 이용해서 처린한다.
  • Update의 경우 delete와 마찬가지로 몇 개의 데이터가 수정되었는가를 처리할 수 있게 int 타입으로 메서드를 설계할 수 있다.
    •  

🌼비즈니스 계층

💡핵심 포인트

  • 비즈니스 계층은 고객의 요구사항을 반영하는 계층으로 프레젠테이션 계층과 영속 계층의 중간 다리 역할을 한다.
    • 일반적으로 비즈니스 영역에 있는 객체들은 Service라는 용어를 많이 사용한다.

비즈니스 계층의 설정

  • 설계를 할 때 각 계층 간의 연결은 인터페이스를 이용해서 느슨한 연결을 한다.
    • 메서드를 설계할 때 이름은 현실적인 로직의 이름을 붙이는 것이 관례이다.
    • @Service 어노테이션은 계층 구조상 주로 비즈니스 영역을 담당하는 객체임을 표시하기 위해 사용한다. 작성된 어노테이션은 패키지를 읽어 들이는 동안 처리된다.
    • 인터페이스가 정상적으로 동작하기 위해서는 객체가 필요하다. 이는 @Autowired와 같이 직접 설정해 줄 수 있고, Setter를 이용해서 처리할 수도 있다.
    • @AllArgsConstructor는 모든 파라미터를 이용하는 생성자를 만들기 때문에 필요한 파라미터를 자동으로 주입할 수 있다.
    • root-context.xml에서 네이스페이스를 추가하면 해당 이름으로 시작하는 태그들을 활용할 수 있다.
 

🌼프레젠테이션(웹) 계층의 CRUD 구현

💡핵심 포인트

Controller의 작성

  • 스프링 MVC의 Controller는 하나의 클래스 내에서 여러 메서드를 작성하고, @RequestMapping 등을 이용해서 URL을 분기하는 구조로 작성할 수 있기 때문에 하나의 클래스에서 필요한 만큼 메서드의 분기를 이용하는 구조로 작성한다.`

BoardController의 작성

  • 컨트롤러는 @Controller 어노테이션을 추가해서 스프링의 빈으로 인식할 수 있게 하고, @RequestMapping을 통해서 해당 주소로 시작하는 모든 처리를 지정할 수 있다.
  • BoardController는 BoardService에 대해 의존적이므로 @AllArgsConstructor를 이용해서 생성자를 만들고 자동으로 주입하도록 한다.
  • 테스트 클래스의 선언부에는 @WebAppConfiguration 어노테이션을 적용한다. Servlet의 ServletContext를 이용하기 위해서인데, 스프링에서는 WebAppContext 라는 존재를 이용한다.
    • @Before 어노테이션이 적용된 메서드는 모든 테스트 전에 매번 실행되는 메서드가 된다.
  • MockMvc는 가짜로 URL과 파라미터 등을 브라우저에서 사용하는 것 처럼 만들어서 Controller를 실행해 볼 수 있다.
    • MockMvcRequestBuilders라는 존재를 이용해서 GET 방식의 호출을 할 수 있다.
    • MockMvcRequestBuilderpost()를 이용하면 POST 방식으로 데이터를 전달 할 수 있고, param() 을 이용해서 전달해야 하는 파라미터들을 지정할 수 있다.
  • 리턴 시에는 redirect: 접두어를 사용할 경우 스프링 MVC가 내부적으로 response.sendRedirect()를 처리해 준다.
  • 조회의 경우 GET 방식으로 처리하므로 @GetMapping을 이용한다.
    • @RequestParam을 이용해서 값을 지정하면 좀 더 명시적으로 처리할 수 있다.
  • 수정 작업의 경우 등록과 유사하게 POST 방식으로 동작하므로 @PostMapping을 이용해서 처리한다.
  • 삭제 처리도 반드시 POST 방식으로 처리한다.
 

🌼화면 처리

💡핵심 포인트

  • 화면을 개발하기 전에는 반드시 화면의 전체 레이아웃이나 디자인이 반영된 상태에서 개발해야 한다.
  • 웹 디자이너가 없다면 BootStrap을 이용한 무료 디자인들을 찾아볼 수 있다.

목록 페이지 작업과 includes

  • 스프링 MVC의 설정에서 화면 설정은 ViewResolver 라는 객체를 통해서 이루어진다.
    • 이는 ‘/WEB-INF/views’ 폴더를 이용하는데, 해당 경로는 브라우저에서 직접 접근할 수 없는 경로이므로 반드시 Controller를 이용하는 모델 2 방식에서는 기본적으로 사용해야 한다.
  • Eclipse 상에서 실행될 때는 ‘/’ 경로로 설정되지 않고, ‘/controller’ 경로를 가지게 되므로 Tomcat의 설정에서 ‘/’로 조정해야 한다.
  • CSS와 JS 파일들의 경로를 수정하는 작업은 브라우저의 개발자 도구를 통해서 확인하며 진핸한다. 개발자 도구를 통해서 현재 브라우저의 Network 부분을 확인하고, 페이지를 새로고침하면 잘못된 URL의 정보를 확인할 수 있다.
  • JSP를 작성할 때마다 많은 양의 HTML 코드를 이용하는 것을 피하기 위해 JSP의 include 지시자를 활용해서 페이지 제작 시에 필요한 내용만을 작성할 수 있게 header.jsp나 footer.jsp 등을 작업한다.
  • JSP 페이지를 작성하다 보면 JavaScript로 브라우저 내에서의 조작이 필요한 경우가 많다. jQuery를 haeder.jsp에 선언해 두면 작성하는 JSP에서 자유롭게 사용할 수 있다.

등록 입력 페이지와 등록 처리

  • 새로운 게시글을 등록했을 때 만일 한글 입력에 문제가 있다는 것을 발견했다면, 브라우저에서 한글이 깨져서 전송되는지를 확인하고, 문제가 없다면 스프링 MVC 쪽에서 한글을 처리하는 필터를 등록해야 한다.
    • 브라우저에서 전송되는 데이터는 개발자 도구를 이용해서 확인할 수 있다. 개발자 도구에서 ‘Network’탭을 열어둔 상태에서 데이터를 보내면 해당 내용을 볼 수 있다.
    • 만약 컨트롤러에 값이 전달될 때 이미 한글이 깨진 상태라면 web.xmlorg.sprinfframework.web.filter.CharacterEncodingFilter 클래스와 UTF-8 파라미터를 가진 필터를 추가해서 문제를 해결할 수 있다.
  • 최근에는 브라우저에서 경고창을 띄우는 방식보다 모달창을 보여주는 방식을 많이 이용한다.
    • 모달창은 활성화된 <div> 를 선택하지 않고서는 다시 원래의 화면을 볼 수 없도록 막기 때문에 메시지를 보여주는데 효과적인 방식이다.
    • 모달창을 보여주는 작업은 jQuery를 이용해서 처리할 수 있다.

조회 페이지와 이동

  • 최근 웹페이지들은 사용자들의 트래픽을 고려해 목록 페이지에서 새 창을 띄워서 조회 페이지로 이동하는 방식을 선호한다.
  • 사용자가 뒤로 가기를 선택하는 경우 의도하지 않은 방향으로 웹 페이지가 동작할 수 있다.
    • 이는 브라우저에서 뒤로 가기나 앞으로 가기를 하면 서버를 다시 호출하는 게 아니라 과거에 자신이 가진 모든 데이터를 활용하기 때문이다.
    • 이 문제를 해결하려면 windows의 history 객체가 가지는 스택 구조를 잘 활용해야 한다.

게시물의 수정/삭제 처리

  • 수정과 삭제는 별개의 페이지에서 하는 것이 일반적이다.
    • 수정 혹은 삭제 작업은 POST 방식으로 처리된다.
    • POST 방식으로 처리하는 부분을 위해서는 <form> 태그로 내용들을 감싸게 한다.
  • <input> 태그에 type=’hidden’ 속성을 부여하면 <form> 태그의 내용은 보이지 않고 버튼만 보이게 처리할 수 있다.
    • 사용자가 버튼을 클릭하면 해당 id를 가진 <form> 태그를 전송해야 하므로 .attr( attributeName, value ).submit() 을 통해 처리를 해야 한다.
 

🌼오라클 데이터베이스 페이징 처리

💡핵심 포인트

  • 수 많은 데이터를 한 페이지에서 보여주면 처리 성능에 영향을 미친다. 또한 브라우저에서도 역시 데이터의 양이나 처리 속도에 문제를 일으키게 된다.
  • 일반적으로 페이징 처리는 크게 번호를 이용하거나 계속 보기의 형태로 구현된다. 번호를 이용한 페이징 처리는 과거 웹 초기부터 이어오던 방식이고, 계속 보기는 Ajax와 앱이 등장한 이후에 무한 스크롤이나 더 보기와 같은 형태로 구현된다.

order by의 문제

  • 데이터의 양이 많을수록 정렬이라는 작업은 많은 리소스를 소모한다.
  • 데이터베이스를 이용할 때 웹이나 애플리케이션에서 가장 신경 쓰는 부분은 다음과 같다.
    • 빠르게 처리되는 것
    • 필요한 양만큼만 데이터를 가져오는 것
  • 빠르게 동작하는 SQL을 위해서는 먼저 order by를 이용하는 작업을 가능하면 하지 말아야 한다.

order by 보다는 인덱스

  • 가장 일반적인 해결책은 인덱스를 이용해서 정렬을 생략하는 방법이다. 인덱스라는 존재가 이미 정렬된 구조이므로 이를 이용해서 별도의 정렬을 하지 않는 방법이다.
    • select /*+ INDEX_DESC(tbl_board pk_board) */ * from tbl_board where bno > 0;
    • 해당 쿼리문은 SORT를 하지 않았고, tbl_board를 바로 접근하는 것이 아니라 pk_board를 이용해서 접근했고, range scan descending, by index rowid로 접근했다.

인덱스를 사용하는 정렬

  • 인덱스에서 가장 중요한 개념 중 하나는 정렬이 되어 있다는 점 이다. 정렬이 이미 되어있는 상태이므로 데이터를 찾아내서 이들을 SORT 하는 과정을 생략할 수 있다.
  • 실무에서도 데이터의 양이 많고 정렬이 필요한 상황이라면 우선적으로 생각하는 것이 인덱스를 작성하는 것이다.
  • 오라클은 select 문을 전달할 때 힌트라는 것을 사용할 수 있다. 힌트는 데이터베이스에 지금 내가 전달한 select 문을 이렇게 실행해 줬으면 좋겠다고 전해주는 것이다.
    • 힌트 구문에서 에러가 나도 SQL 실행에 지장을 주지 않기 때문에 실행 계획을 통해서 개발자가 원하는 대로 SQL이 실행되는지 확인하는 습관을 가져야 한다.

ROWNUM과 인라인뷰

  • 오라클 데이터베이스는 페이지 처리를 위해서 ROWNUM이라는 키워드를 사용해서 데이터에 순번을 붙여 사용한다.
  • 모든 SELECT 문에는 ROWNUM이라는 변수를 이용해서 해당 데이터가 몇 번째로 나오는지 알아낼 수 있다.
  • 한 페이지당 20개의 데이터를 출력한다고 가정하면 ROWNUM 조건을 WHERE 구문에 추가해서 작성할 수 있다.
    • select /*+ INDEX_DESC(tbl_board pk_board) */ rownum rn, bno, title, content from tbl_board where rownum <= 20;
    • 이 경우 ROWNUM 조건이 1이 포함하도록 되어있기 때문에 결과가 나오는 것을 볼 수 있다.
  • 인라인 뷰는 SELECT문 안쪽 FROM에 다시 SELECT문을 작성하는 것이다.
    • 즉 논리적으로는 어떤 결과를 구하는 SELECT 문이 있고, 그 결과를 다시 대상으로 삼아서 SELECT를 하는 것이다.
 

🌼MyBatis와 스프링에서 페이징 처리

💡핵심 포인트

  • 페이징 처리를 위해서 필요한 파라미터는 페이지 번호, 한 페이지당 몇 개의 데이터를 보여줄 것인가를 정하는 두 가지이다.
  • 두 파라미터를 별도로 전달하는 방식도 가능하지만 이 데이터들을 하나의 객체로 묶어서 전달하는 방식이 좀 더 확장성이 좋다.

MyBatis 처리와 테스트

  • 인터페이스와 어노테이션을 이용할 때 페이징 처리의와 같이 경우에 따라 SQL 구문 처리가 필요한 상황에서는 복잡하게 작성된다.
  • XML을 이용할 경우에 < , > 는 태그로 인식되는데, 이를 막기 위해선 [CDATA[ ]] 를 사용한다.
 

🌼페이징 화면 처리

💡핵심 포인트

  • 페이지를 보여주는 작업은 다음과 같은 과정을 통해 진행된다.
    • 브라우저 주소창에서 페이지 번호를 전달해서 결과를 확인하는 단계
    • JSP에서 페이지 번호를 출력하는 단계
    • 각 페이지 번호에 클릭 이벤트 처리
    • 전체 데이터 개수를 반영해서 페이지 번호 조절

페이징 처리할 때 필요한 정보들

  • 화면에 페이징 처리를 하기 위해서는 다음과 같은 정보들이 필요하다.
    • 현재 페이지 번호
    • 이전과 다음으로 이동 가능한 링크의 표시 여부
    • 화면에서 보여지는 페이지의 시작 번호와 끝 번호
  • 페이지를 계산할 때 끝 번호를 먼저 계산하는 것이 수월하다.
    • this.endPage = (int)(Math.ceil(페이지번호 / 10.0)) * 10;
  • 만약 화면에 10개씩 글을 보여준다면 시작 번호는 무조건 끝 번호에서 9를 뺸 값이 된다.
    • this.startPage = this.endPage - 9;
  • 끝 번호는 전체 데이터 수에 의해 영향을 받는다. 전체 데이터 수가 80개라고 가정하면 끝 번호는 10이 아닌 8이 되어야 한다.
    • 만일 끝 번호와 한 페이지당 출력되는 데이터 수의 곱이 전체 데이터 수보다 크다면 끝 번호는 다시 total을 이용해서 다시 계산되어야 한다.
    • realEnd = (int) (Math.ceil((total * 1.0) / amount) ); if(realEnd < this.endPage) { this.endPage = realEnd; }
  • 이전은 시작 번호가 1보다 큰 경우라면 존재한다.
    • this.prev = this.startPage > 1;
  • 다음으로 가는 링크는 realEnd가 끝 번호보다 큰 경우에만 존재하게 된다.
    • this.next = this.endPage < realEnd;
 

🌼검색 처리

💡핵심 포인트

  • 검색 조건은 일반적으로 <select> 태그를 이용해서 작성하거나 <checkbox>를 이용하는 경우가 많다.

검색 기능과 SQL

  • 게시물의 검색 기능은 다음과 같이 분류가 가능하다.
    • 제목/내용/작성자와 같이 단일 항목 검색
    • select * from ( select /*+index_desc(tbl_board pk_board) */ rownum rn, bno, title, content, writerm regdate, updatedate from tbl_board where title like '%Test%' and rownum <=20 ) where rn > 10;
    • 제목 or 내용, 제목 or 작성자, 내용 or 작성자, 제목 or 내용 or 작성자와 같은 다중 항목 검색
    • select * from ( select /*+index_desc(tbl_board pk_board) */ rownum rn, bno, title, content, writerm regdate, updatedate from tbl_board where (title like '%Test%' or content like '%Test%') and rownum <=20 ) where rn > 10;

MyBatis의 동적 SQL

  • 검색 조건이 변하면 SQL의 내용 역시 변하기 때문에 고정된 문자열을 작성하는 방식으로는 제대로 처리할 수 없다.
  • MyBatis는 동적 태그 기능을 통해서 SQL을 파라미터들의 조건에 맞게 조정할 수 있다.
    • <if>는 test 라는 속성과 함께 특정한 조건이 true가 되었을 때 포함된 SQL을 사용하고자 할 때 사용한다.
    • <if test="type == 'T'.toString()"> (title like '%'||#{keyword}||'%') </if> <if test="type == 'C'.toString()"> (content like '%'||#{keyword}||'%') </if> <if test="type == 'W'.toString()"> (writer like '%'||#{keyword}||'%') </if>
    • <choose>는 여러 상황들 중 하나의 상황에서만 동작한다.
    • <choose> <when test="type == 'T'.toString()"> (title like '%'||#{keyword}||'%') </when> <when test="type == 'C'.toString()"> (content like '%'||#{keyword}||'%') </when> <when test="type == 'W'.toString()"> (writer like '%'||#{keyword}||'%') </when> <otherwise> (title like '%'||#{keyword}||'%' or content like '%'||#{keyword}||'%' or writer like '%'||#{keyword}||'%') </otherwise> </choose>
    • <trim>, <where>, <set>은 단독으로 사용되지 않고 <if>, <choose>와 같은 태그들을 내포하여 SQL들을 연결해 주고, 앞 뒤에 필요한 구문들 (and, orm where등)을 추가하거나 생략하는 역할을 한다.
      • <where>의 경우 태그 안쪽에서 SQL이 생성될 때는 where 구문이 붙고, 그렇지 않은 경우에는 생성되지 않는다.
      • select * from tbl_board <where> <if test='bno != null"> bno = #{bno} </if> </where>
      • <trim>은 하위에서 만들어지는 SQL문을 조사하여 앞 쪽에 추가적인 SQL을 넣을 수 있다.
      • select * from tbl_board <where> <if test='bno != null"> bno = #{bno} </if> <trim prifix = "and" > rownum = 1 </trim> </where>
    • <foreach>는 List, 배열, 맵 등을 이용해서 루프를 처리할 수 있다. 주로 in 조건에서 많이 사용하지만, 경우에 따라서 복잡한 where 조건을 만들 때에도 사용한다.
    • Map<String, String> map = new HashMap<>(); map.put("T", "TTTT"); map.put("C", "CCCC"); select * from tbl_board <trim prefix="where (" suffix=")" prefixOverrides="or"> <foreach item="val" index="key" collection="map"> <trim prefix="or"> <if test="key == 'C'.toString()"> content = #{val} </if> <if test="key == 'T'.toString()"> title = #{val} </if> <if test="key == 'W'.toString()"> writer = #{val} </if> </trim> </foreach> </trim>

검색 조건을 위한 Criteria의 변화

  • MyBatis는 <sql>이라는 태그를 이용해서 SQL의 일부를 별도로 보관하고, 필요한 경우에 include시키는 형태로 사용할 수 있다.
    • <sql> 태그는 id라는 속성을 이용해서 필요한 경우에 동일한 SQL의 일부를 재사용할 수 있게 한다.

화면에서 검색 조건 처리

  • 화면에서 검색은 다음과 같은 사항들의 주의하면서 개발해야 한다.
    • 페이지 번호가 파라미터로 유지되었던 것처럼 검색 조건과 키워드 역시 항상 화며 이동 시 같이 전송되어야 한다.
    • 화면에서 검색 버튼을 클릭하면 새로 검색을 한다는 의미이므로 1페이지로 이동한다.
    • 한글의 경우 GET 방식으로 이동하는 경우 문제가 생길 수 있다.
  • 웹페이지에서 RedirectAttributes 파라미터를 매번 유지하는 일이 번거롭고 힘들다면 UriConponentsBuilder 라는 클래스를 이용해서 여러 개의 파라미터들을 연결해서 URL의 형태로 만들 수 있다.
 

🏁결론

해당 내용을 정리하면서 스프링 MVC를 이용하는 웹 프로젝트 전체 구조에 대한 이해, 개발의 각 단계에 필요한 설정 및 테스트 환경, 기본적인 등록, 수정, 삭제, 조회, 리스트 구현, 목록 화면의 페이징 처리, 검색 처리와 페이지 이동에 대한 개념을 이해할 수 있었다.
Share article

More articles

See more posts

👨🏻‍💻DriedPollack's Blog