RESTFul-API SampleCoding (Java,SpringBoot,Maven,myBatis) #4

   이전 포스팅까지 실제 DB에 저장된 내용을 화면에 출력하는 부분까지 진행했다.   이번 포스팅에서는 사용자 이름을 입력받아서 사용자 이름과 일치하는 데이터를 출력하는 조건검색에 대해서 진행하도록 하겠다.

이전글 : https://clien78.tistory.com/233

 

RESTFul-API SampleCoding (Java,SpringBoot,Maven,myBatis) #3

이번 포스팅에서는 앞서 만든 Project에 Model(DAO)를 추가하고 실제 DB에 저장된 데이터를 화면에 출력한다.   기본적으로 DB Table의 구조와 동일한 Model Class를 생성하고 해당 객체를 List 형태로 조회

blog.iamwhatiam.co.kr

 

   이전글에서 작성했던 'staff201.jsp' 실제로는 'staff203.jsp'이 되어야 한다.  Naming Rule 로 정했던 201은 조회를 하기 위한 검색화면이고 202는 조회를 처리하기 위한 화면, 203은 조회 결과이다.  그렇게 따진다면 이전글에서 만든 화면은 조회 결과가 되기 때문에 203이 되는게 맞다.   일단 'staff201.jsp'의 내용을 'staff203.jsp'으로 똑같이 만들거나 복사하자.

[ staff201.jsp를 복사해서 staff203.jsp 생성 ]

   'staff201.jsp' file은 검색 조건을 입력하고 검색을 요청하는 버튼이 포함된 화면이 되어야 한다.   'staff201.jsp' file의 내용을 아래와 같이 코딩한다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@ taglib prefix="c"   uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fn"  uri="http://java.sun.com/jsp/jstl/functions"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>staff201</title>
        <!-- jQuery 라이브러리 추가 -->
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
        <script type="text/javascript">
            /* 페이징 */
            function goPage(pageNo) {
                $("#pageNo").val(pageNo);
                $("form[name=frm]").attr("target", "_self");
                $("form[name=frm]").attr("method", "post");
                $("form[name=frm]").attr("action", "./staff202.do");
                $("form[name=frm]").submit();
            }
        </script>
    </head>
    <body>
        <form name="frm">
            <label for="username">Name</label>
            <input type="text" id="username" name="username" style="font-size: 11px;" value="${parameter.username}">
            <input type="hidden" id="pageNo" name="pageNo">
            <input type="button" id="Search" value="Search" onclick="goPage('1')">
        </form>
    </body>
</html>

staff201.jsp
0.00MB

 

그리고 'staff203.jsp' file은 아래와 같이 코딩한다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Staff Table Select (staff203)</title>
    </head>

    <body>
        <table style="border: 1px solid #000; border-collapse: collapse; width: 100%;">
            <colgroup>
                <col style="width: auto; text-align: center;">
                <col style="width: auto; text-align: center;">
                <col style="width: auto; text-align: center;">
                <col style="width: auto; text-align: center;">
                <col style="width: auto; text-align: center;">
                <col style="width: auto; text-align: center;">
                <col style="width: auto; text-align: center;">
                <col style="width: auto; text-align: center;">
                <col style="width: auto; text-align: center;">
                <col style="width: auto; text-align: center;">
            </colgroup>

            <thead>
                <tr style="border: 1px solid #000;">
                   <th style="border: 1px solid #000;">Staff ID</th> 
                   <th style="border: 1px solid #000;">First Name</th> 
                   <th style="border: 1px solid #000;">Last Name</th> 
                   <th style="border: 1px solid #000;">Address ID</th> 
                   <th style="border: 1px solid #000;">Email</th> 
                   <th style="border: 1px solid #000;">Store ID</th> 
                   <th style="border: 1px solid #000;">Active</th> 
                   <th style="border: 1px solid #000;">User Name</th> 
                   <th style="border: 1px solid #000;">Password</th> 
                   <th style="border: 1px solid #000;">Last Update</th> 
                </tr>
            </thead>

            <tbody>
                <c:if test="${fn:length(staffInfoList) > 0}">
                    <c:forEach items="${staffInfoList}" var="obj" varStatus="f">
                        <tr style="border: 1px solid #000;">
                            <td style="border: 1px solid #000;">${obj.staffId}</td>
                            <td style="border: 1px solid #000;">${obj.firstName}</td>
                            <td style="border: 1px solid #000;">${obj.lastName}</td>
                            <td style="border: 1px solid #000;">${obj.addressId}</td>
                            <td style="border: 1px solid #000;">${obj.email}</td>
                            <td style="border: 1px solid #000;">${obj.storeId}</td>
                            <td style="border: 1px solid #000;">${obj.active}</td>
                            <td style="border: 1px solid #000;">${obj.username}</td>
                            <td style="border: 1px solid #000;">${obj.password}</td>
                            <td style="border: 1px solid #000;">${obj.lastUpdate}</td>
                        </tr>
                    </c:forEach>
                </c:if>
                <c:if test="${fn:length(staffInfoList) == 0}">
                    <tr>
                        <td colspan="10" style="border: 1px solid #000; text-align: center;">No data available</td>
                    </tr>
                </c:if>
            </tbody>
        </table>
    </body>
</html>

staff203.jsp
0.00MB

 

이전 포스팅에서 작성했던 'StaffController.java' 의 내용을 아래와 같이 수정한다.

package kr.co.iamwhatiam.dvdrental.Web.Staff.Controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

import kr.co.iamwhatiam.dvdrental.Common.Model.Staff;
import kr.co.iamwhatiam.dvdrental.Web.Staff.Service.StaffService;


@Controller
public class StaffController {

	private static final Logger logger = LoggerFactory.getLogger(StaffController.class);

	@Autowired
	private StaffService staffService;





	// get Staff Info List
	@RequestMapping("/Staff/staff201.do")
	public String getStaffSearchOption(@ModelAttribute("staffInfo") Staff staffInfo, Model model, HttpServletRequest request, HttpServletResponse response) throws Exception {

		Map<String, String> parameter = new HashMap<String, String>();

		logger.info("[StaffController.getStaffSearchOption] Start >> staffInfo >> " + staffInfo.toString());

		model.addAttribute("parameter", parameter);

		return "/Staff/staff201";

	}


	// get Staff Info List
	@RequestMapping("/Staff/staff202.do")
	public String getStaffInfoList(@ModelAttribute("staffInfo") Staff staffInfo, Model model, HttpServletRequest request, HttpServletResponse response) throws Exception {

		Map<String, String> parameter = new HashMap<String, String>();

		logger.info("[StaffController.getStaffInfoList] Start >> staffInfo >> " + staffInfo.toString());

		// Staff Info 검색 조건으로 Staff의 first_name 및 last_name 을 OR 검색조건으로 사용할 것이다.
		if (StringUtils.isEmpty(staffInfo.getUsername())) {
			staffInfo.setFirstName("");
		} else {
			staffInfo.setFirstName(staffInfo.getUsername());
		}

		if (StringUtils.isEmpty(staffInfo.getUsername())) {
			staffInfo.setLastName("");
		} else {
			staffInfo.setLastName(staffInfo.getUsername());
		}

		parameter.put("firstName", staffInfo.getFirstName());
		parameter.put("lastName" , staffInfo.getLastName());
		model.addAttribute("parameter", parameter);

		List<Staff> staffInfoList = staffService.getStaffInfoList(parameter);
		model.addAttribute("staffInfoList", staffInfoList);

		return "/Staff/staff203";

	}

}

StaffController.java
0.00MB

 

   이제 변경된 내용을 정리해보자.
   최초 검색을 위해서 화면에 보여지는 Page는 'staff201' 이다.   실제 Web Browser에서 호출되는 주소는 'http://localhost:8080/Staff/staff201.do' 이 된다.   위의 StaffController.java Source를 보면 특별한 동작을 하지 않고 바로 return 해서 'staff201.jsp'를 호출해준다.   그렇게 호출된 화면이 아래의 화면이다.

[ http://localhost:8080/Staff/staff201.do ]

   사용자 이름으로 검색하기 위해서 Input Box에서 문자열로 입력을 받고 Search Button 으로 Submit 한다.   Submit 을 할 때 호출되는 주소가 'staff202.do' 이다.   즉, 201은 조회 조건을 입력받기 위함이고 202는 조회를 처리하기 위한 부분이다.   조회 처리 과정에서 화면은 불필요하기 때문에 'staff202.jsp'는 존재하지 않는다.   다만 Controller 에서 해당 주소로의 요청에 대한 처리 과정만 있을 뿐이다.   화면에서 입력받은 검색 조건을 202 Method 에서 처리를 하고 DB를 조회한다.   그 결과를 203 화면으로 전달하는 것이다.

   그러면 'Mike'라는 이름으로 조회를 했을 때 처리되는 과정을 살펴보자.

[ 검색어로 'Mike'를 입력하고 Search Button 을 누른다. ]

 

[ 'Mike'라는 이름을 가진 Data가 조회되어 출력되었다. ]

INFO  24-07-17 21:14:35[http-nio-8080-exec-2] [StaffController:55] - [StaffController.getStaffInfoList] Start >> staffInfo >> Staff[active=false,addressId=0,email=<null>,firstName=<null>,lastName=<null>,lastUpdate=<null>,password=<null>,picture=<null>,staffId=0,storeId=0,username=Mike]
INFO  24-07-17 21:14:35[http-nio-8080-exec-2] [StaffServiceImpl:24] - [StaffServiceImpl.getStaffInfoList] Start >> parameter >> {firstName=Mike, lastName=Mike}
DEBUG 24-07-17 21:14:35[http-nio-8080-exec-2] [getStaffInfoList:135] - ==>  Preparing: SELECT staff_id ,first_name ,last_name ,address_id ,email ,store_id ,active ,username ,password ,last_update ,picture FROM public.staff WHERE 1=1 AND ( first_name LIKE '%' || ? || '%' OR last_name LIKE '%' || ? || '%') AND ( first_name LIKE '%' || ? || '%' OR last_name LIKE '%' || ? || '%') ORDER BY staff_id
DEBUG 24-07-17 21:14:35[http-nio-8080-exec-2] [getStaffInfoList:135] - ==> Parameters: Mike(String), Mike(String), Mike(String), Mike(String)
TRACE 24-07-17 21:14:35[http-nio-8080-exec-2] [getStaffInfoList:141] - <==    Columns: staff_id, first_name, last_name, address_id, email, store_id, active, username, password, last_update, picture
TRACE 24-07-17 21:14:35[http-nio-8080-exec-2] [getStaffInfoList:141] - <==        Row: 1, Mike, Hillyer, 3, Mike.Hillyer@sakilastaff.com, 1, t, Mike, 8cb2237d0679ca88db6464eac60da96345513964, 2006-05-16 16:13:11.79328, <<BLOB>>
DEBUG 24-07-17 21:14:35[http-nio-8080-exec-2] [getStaffInfoList:135] - <==      Total: 1

   Console에 찍힌 Log를 보면 정상적으로 Database에서 조회 Query를 실행한 것을 확인 할 수 있다.

   이번 포스팅의 내용이 길지는 않지만 전체적인 흐름을 이해하기 위한 부분이기 때문에 확실하게 이해하고 넘어가야 한다.   조회를 하기 위한 조건을 입력받고 그 조건을 담은 Parameter가 Controller가 호출 되면서 전달되고 Service, Service Implement, Mapper 를 거쳐 Database에 조회 Query를 실행하고 그 결과를 호출했던 역순으로 받아서 결과 화면(203)으로 전달되는 일련의 과정을 이해해야 한다.

   이 글에서 설명하지 않은 Log를 남기는 부분과 application.properties 를 Local, Dev, Prd 로 구분하는 부분을 Source에 추가하였다.   실제 현업 Project에서는 대부분 Local에서 개발하고 개발 장비에서 테스트 하고 이관정비를 거쳐서 상용장비로 반영하는 과정을 거치는게 일반적이다.   그래서 환경설정도 각 장비별로 별도로 해야하고 DB도 장비별로 구분되어서 접속되어야 하기 때문에 환경설정을 분리하는 것은 Human Error를 줄이는 최소한의 방책이다.   아래에 전체 Source를 압축해서 첨부해 놓았으니 본인이 작성한 Source와 달라진 부분을 비교해가며 차이를 확인하기 바란다.   그리고 추가적으로 'pom.xml'에 추가된 dependency가 몇몇 있으니 참고하기 바란다.

DVDRental_4.zip
0.12MB

 

   다음 포스팅에서는 Staff Table의 Record를 Update 하는 과정을 설명하다록 하겠다.