반응형

이제 거의 다왔습니다.. 

 

실제로 개발의 기반이되는 (이론 따위 필요없고 개발 하고 싶으면 이것만 보면된다.)

 

근데 개발만 할껀아니잖아요.. 앞에 이론도 좀 봐야함...

 

 

아무튼!

 

우리의 Spring의 흐름은 간단하게 얘기하면

1. Dispatcher-Servlet

2. Controller

3. Service(impl)

4. DAO(impl)

5. Mybatis

6. 다시 Controller로 돌아와 -> JSP 호출(동적페이지)

 

이런식으로 흐른다고 보면된다. 실제로 개발을 할 때에 해당 프로세스는 숙지하고 있어야하며 다 알아야한다.

안그러면 힘들다... 그래서 하나하나 살펴보려고 한다.

 

1, 2번 Dispatcher-servlet 이 받은 요청 처리해주기.

(Dispatcher-Servlet-Controller)

자. 첫단추를 끼워야한다.

 

@RequestMapping , @Controller 이라는 어노테이션만 알면 끝난다. 위치와 소스는 다음과 같다. 

위치는 보통 com/kitao/kr 까지만 생성되있을 껀데, 본인은 구분을 쉽게하기 위해 co, coa 까지 생성해 주었다.

controller의 위치

package com.kitao.kr.co.coa.controller;

import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.kitao.kr.co.coe.service.BoardService;
import com.kitao.kr.co.coe.vo.BoardVO;

/**
 * Handles requests for the application home page.
 */

@Controller
public class HomeController {
	@Value("#{properties['ACTION_NAME']}")
	public String ACTION_NAME;
	
	@Resource(name="boardService")
	private BoardService boardService;
		
	@RequestMapping(value = "/")
	public ModelAndView home(ModelMap model, HttpServletResponse response, HttpServletRequest request) throws Exception {
		request.setCharacterEncoding("UTF-8");
		List <BoardVO> boardVO = boardService.selectBoardList();

		ModelAndView mv = new ModelAndView("co/coa/home");
		mv.addObject("serverTime", "이거 넣을껀데?");
		mv.addObject("boardVO", boardVO);
		
		return mv;
	}
}

 

소스는 이렇게 하나하나 차례로 살펴보자...

@Controller는 여기가 컨트롤러단이다! 라는걸 의미한다.

또한, @RequestMapping(value = "/") 의 의미는 가장 쉽게 말해서 Home에 접근하면 여기를 와라 라는 것이다.

즉, https://wwwhttp://localhost:9122/kr/ 이게 호출되면 해당 Controller를 탈 것이다.

 

여기서 부터 시작인 셈이다. 다음 class home을 봐보자.

return 형이 ModelAndView인건 아직 신경쓰지말자 다음에 얘기할 때가 오겠지..

 

아무튼 다시 돌아오면,

그리고 그 다음 단계인 Service 비스.. 무리한 애가 보인다. 전에 배웠던, 의존성 역전의 법칙을 사용하여(@Resoure) 먼저 의존성을 주입하고, Service단이 실행되는 것으로 보인다. 아마 Service 단에서 실행된 애가 boardVO형의 리스트에 넣어지는 것으로 보인다. 그러면 Service 단을 먼저 살펴보자.

 

service의 의치

저기에서 service는 coe쪽에 있지만, 뭐 상관없다. 어디에 위치해 있든, @Service 이노테이션을 통해 얘가 service단이다! 라는걸 선언해주면 된다. 그럼 안에 소스를 봐보자. 아 보기전에. VO를 봐보겠다.

 

BoardVO.java

package com.kitao.kr.co.coe.vo;

import java.util.Date;

public class BoardVO {
	private String boardId;
	private String boardContents;
	private String boardTitle;
	private Date boardRegDtm;
	
	public String getBoardId() {
		return boardId;
	}
	public void setBoardId(String boardId) {
		this.boardId = boardId;
	}
	public String getBoardContents() {
		return boardContents;
	}
	public void setBoardContents(String boardContents) {
		this.boardContents = boardContents;
	}
	public String getBoardTitle() {
		return boardTitle;
	}
	public void setBoardTitle(String boardTitle) {
		this.boardTitle = boardTitle;
	}
	public Date getBoardRegDtm() {
		return boardRegDtm;
	}
	public void setBoardRegDtm(Date boardRegDtm) {
		this.boardRegDtm = boardRegDtm;
	}
	
	
}

보면 그냥.. 맴버변수에 메소드변수가 들어가있는 것이다. 이게 끝이다. 다음 Service단을 보겠다.

 

BoardService.java

package com.kitao.kr.co.coe.service;

import java.util.List;

import org.springframework.stereotype.Repository;

import com.kitao.kr.co.coe.vo.BoardVO;

public interface BoardService {
	List<BoardVO> selectBoardList() throws Exception;
}

 

아니 이건 뭐 설명할 필요도 없다. 그냥 Service의 부모가 되는 빈 인터페이스가 선언 되어 있다.

그다음 BoardServiceImpl이 중요하다.

 

3번 Service(impl)

 

BoardServiceImpl.java

package com.kitao.kr.co.coe.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.kitao.kr.co.coe.dao.COEBoardDAO;
import com.kitao.kr.co.coe.memory.test;
import com.kitao.kr.co.coe.vo.BoardVO;

@Service("boardService")
public class BoardServiceImpl implements BoardService {
    @Autowired    
	private COEBoardDAO boardDAO;
    
	@Override
	public List<BoardVO> selectBoardList() throws Exception {
	    // 비즈니스 로직 수행
		return boardDAO.boardSearch();
	} 
}

자 여기 다있다.. @Servce("boardService") 라는 애는 얘가 서비스이다! 라는걸알려준다. 따라서, Controller에서

호출된 서비스는 여기로 올 수 있었던 것이다. 실제로 구현도 여기서 다 이루어져 있다.

엄~청 간단한 impl단이지만, 실제로 비즈니스 로직을 수행하는 곳이기도 하다.

 

이제 쿼리를 실행하는 Mybatis를 실행하는 DAO를 보겠다.

 

 

4번, 5번 DAO(impl)과 Mybatis

 

COEBoardDAO.java

DAO 위치

package com.kitao.kr.co.coe.dao;

import java.util.List;

import javax.inject.Inject;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.kitao.kr.co.coe.vo.BoardVO;

@Repository
public class COEBoardDAO {
	@Inject 
	private SqlSession session; 
	private static String namespace = "com.kitao.kr.boardListSearch";

	public List<BoardVO> boardSearch() throws Exception {
		return session.selectList(namespace+".selectBoardSearch");
	}
}

 

자 이제. Mybatis를 실행하기 위해 여기 까지 왔다.. 쿼리를 실행하면 된다.

본인은 DAO, DAOImp로 나누지 않고 DAO에 선언과 구현을 동시에 하였다. 본인이 편한걸로 하면된다.

여기서 선언과 동시에 return으로 쿼리를 반환하는 것을 볼 수 있다.

본인의 쿼리문은 com.kitao.kr.boardListSearch에 있다는 것을 어느정도 유추할 수 있다.

다음단계 쿼리문 작성하는 곳을 가보자.

 

 

ds.COEBoardList_sql.xml

xml 위치

자 낚시 조심하다 위치는 java가 아니라 resources/mappers에 있다. 여기에 생성해 주어야한다. 또한 파일명은 상관없다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kitao.kr.boardListSearch">
	<select id='selectBoardSearch' resultType="com.kitao.kr.co.coe.vo.BoardVO"> 
		SELECT 
			BOARD_ID,
			BOARD_TITLE,
			BOARD_CONTENTS,
			BOARD_REG_DTM
		  FROM
		  	BOARD_MST
	</select> 
</mapper>

자 소스는 다음과 같다. 오.. 뭔가 쿼리문이 보이지 않는가....여........

아~까 session.selectList("com.kitao.kr.boardListSearch"); 이게 여기를 찾아 온다고 생각하면된다..

근데 어떻게 찾아오냐고 물으신다면... 조~기 위에 보이는 mapper로 인해서 여기로 찾아 올 수 있게 된다.

그래서 여기서 실행된 쿼리문에 의해서 Controller에 존재하는 BoardVO에 담기는 것이다!!!! ...

신기하지 않은가?...

 

근데 하나의문이 있는게 쿼리문에서 실행 된 결과는 다음과 같다.

본인이 임의로 넣은 데이터

이런식인데 컬럼명은 BOARD_ID 인데.. BoardVO의 한 변수를 보면 boardId로 선언 되어 있을 것이다..

조금 규칙이 보이지 않는가? 우리는 여기서 '카멜케이스'라는걸 사용해야한다. (모르면 찾아보세요...ㅎ)

이 카멜케이스라는 것을 설정해주면 자바스프링에서는 자동으로 매칭 해 줄 수 있다.

예를들어..

boardVO.boardPw <-> BOARD_PW

boardVO.boardTitle<-> BOARD_TITLE

boardVO.boardContents<-> BOARD_CONTENTS

이런식으로 자동으로 매칭된다는 것이다. 설정은 다음과 같이 할 수 있다.

 

mybatis-config.xml

mybatis-config.xml 위치

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<settings>
		<setting name="mapUnderscoreToCamelCase" value="true"/>
		<setting name="callSettersOnNulls" value="true"/>
		<setting name="jdbcTypeForNull" value="NULL"/>
	</settings>
</configuration>

전에 mybatis사용하려고 만든 mybatis-config.xml에 설정을 하고 소스는 상단과 같다.

여기서 카멜케이스를 사용하여 자동 매핑하는 세팅은 setting에 mapUnderscoreToCamelCase라는 친구이다.

callSettersOnNulls, jdbcTypeForNull 얘는 몬지모르겠다. 구글링했는데 뭐 같이 딸려온애 같은데.

 

나중에 배울꺼지만 callSettersOnNulls 얘는 Mybatis ResultMap을 동적으로 받기위해 HashMap으로 받을 시

value 값이 Null 일때 칼럼이 누락되는 현상을 방지하기 위에 존재한다.

 

jdbcTypeForNull 이 아이는.. Oracle을 사용할 때, Null을 넣을 수 있는 컬럼값에 Null을 넣게 되면 부적합반 열 유형이라는 에러를 뱉게 되는데, 이걸 방지하기 위해 선언한 것이라고 생각하면 된다.

 

 

6. 다시 Controller로 돌아와 -> JSP 호출(동적페이지)

자 이제 그럼 다시 Controller단을 봐보자.

package com.kitao.kr.co.coa.controller;

import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.kitao.kr.co.coe.service.BoardService;
import com.kitao.kr.co.coe.vo.BoardVO;

/**
 * Handles requests for the application home page.
 */

@Controller
public class HomeController {
	@Value("#{properties['ACTION_NAME']}")
	public String ACTION_NAME;
	
	@Resource(name="boardService")
	private BoardService boardService;
		
	@RequestMapping(value = "/")
	public ModelAndView home(ModelMap model, HttpServletResponse response, HttpServletRequest request) throws Exception {
		request.setCharacterEncoding("UTF-8");
		List <BoardVO> boardVO = boardService.selectBoardList();

		ModelAndView mv = new ModelAndView("co/coa/home");
		mv.addObject("serverTime", "이거 넣을껀데?");
		mv.addObject("boardVO", boardVO);
		
		return mv;
	}
}

 

자 여기를 보면, List <BoardVO> boardVO에 자동으로 매핑되어(카멜케이스 이용) 쿼리문 결과를 넣어준다. 그 다음,

ModelAndview mv = new ModelAndView("co/coa/home"); <- 이건 마지막단계인 jsp가 어디있는지 넣고

jsp로 갈 때 같이 넘기고 싶은 변수를 설정해서(mv.addObject 사용) jsp에 넘겨준다.

 

그러면 JSP가 실행 되는 것이다. jsp 위치와 소스를 봐보자.

 

home.jsp

home.jsp

home.jsp는 기본적으로 src/main/webapp/WEB-INF/views에 있다.

여기서 WEB-INF/views 위치 설정은 servlet-context.xml에서 설정할 수 있다. (전에 봤었다..)

 

소스는 다음과 같다.

<%@ page language="java" contentType="text/html; charset=EUC-KR" pageEncoding="EUC-KR"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
	<title>Home</title>
</head>
<body>
	<h1>${serverTime}</h1>
	<c:forEach var="cw" items="${boardVO}">
		<p>번호 : ${cw.boardId}</p>
		<p>번호 : ${cw.boardTitle}</p>
		<p>번호 : ${cw.boardContents}</p>
		<p>번호 : ${cw.boardRegDtm}</p>
		<br><br><br>
	</c:forEach>
</body>
</html>

 

 

이렇게 jsp의 동적페이지 생성으로 끝난다. 그러면 결과를 보자.

결과물

자... 감격스럽다... 이렇게 사용자가 이 화면을 보는 것이다. 비전공자는 모를것이다. 페이지가 이렇게 많은 단계를 거치고 걸쳐서 사용자를 위해 제공 되는지.. 원래 아는 만큼 보이는 것이다.

 

 

이로써 1~6단계 Controller에서 시작해서 Mybatis-JSP 까지 가는 과정이 끝나게 된다.

사실, 프로세스적으로도 중요하지만, 가장 중요한건 HTML, CSS, JS, JAVA, 쿼리문 작성 능력도 중요하다.

프로세스를 다 알고있는 가정하에, 해당 언어로 누가 더 좋은 로직을 짜느냐, 효율성 있는 로직을 짜느냐, 보안이슈를

다 틀어 막느냐, 유지보수를 가정하고 코드를 짜느냐, 스파게티(?) 코드를 덜짜느냐의 문제로 나아가는 것이다.

 

 

 

도움이 되셨다면 아래 공감 버튼 눌러주세요.(로그인 필요없어요!)

반응형

+ Recent posts