JAVA 웹개발 과정 국비 77일차 정리

77일차

※ 배우는 과정이므로 정확하지 않을 수 있습니다.
잘못된 점은 알려주시면 수정하도록 하겠습니다!


즐거웠던 세미 프로젝트가 끝났다.
후기는 내일 정리해서 올리도록 하고.. 오늘부터는 대망의 Spring 진도가 나갔다. 쉽지않았다.

1. Spring Framework

1) Spring Framework

전자정부프레임워크(Spring + 기타 프레임워크들..)가 규정되어있어서 Spring 프레임워크를 기본적으로 알아야만 한다.
스프링의 장점은 1. 편리함 2. 유지보수에 유리 이다.

2) 환경설정

① Workspace 새로 만들기

기존 실습 코드들이 들어있던 workspace와는 다르게 C:\ 또는 D:\ 와 같이 경로 바로 밑으로 떨어지는 곳에 workspace를 만들어준다.
이유는 경로상에 한글이 있으면 오류가 뜨기 때문에 (치명적인 것은 아니지만) 귀찮으니까 한글이 경로에 없게 만들어주자.

② STS 설치

마켓플레이스 들어가서 스프링을 이클립스에서 쉽게 사용할 수 있게 만들어주는 STS(Spring Tool Suits) 라고 하는 것을 받아준다.
add-on 말고 Spring Tools 3을 받아야한다. 4는 Boot라고 보면 된다.
모두 체크하고 설치.

③ 새 프로젝트 생성

이클립스를 재시작하고 Open Perspective에서 Spring을 클릭한 뒤, Spring Legacy Project를 클릭, Spring MVC Project를 클릭하여 새로운 프로젝트를 생성한다.
간혹 이 레거시 프로젝트 생성이 안보일 때가 있는데, OpenJDK의 위치가 잘못되면 그럴 수 있다고 한다.
추가 요소를 다운받는다는 것을 확인하고 넘어가면, Package명을 어떻게 할건지 우선적으로 나오는데 보통 기업명.프로젝트명.요소의범주로 이루어진 3단구조를 이용한다.
처음 만드는 것은 컨트롤러일 수밖에 없기 때문에 예를 들면 kh.spring.controller라고 적는다.

④ Maven으로 라이브러리 버전 바꿔주기

현재 버전들은 너무 낮은 버전이거나, 이슈가 있는 버전이므로 최신 버전으로 바꿔준다.

  1. pom.xml로 들어간다
  2. 자바 버전 바꿔주기
    • <java-version>1.6<java-version> 의 1.6을 11로 바꿔준다.
  3. 스프링 버전 바꿔주기
    • org.springframework-version>3.1.1.RELEASE</org.springframework-version> 에서 3.1.1.RELEASE를 5.3.9로 바꿔준다.
    • 알맞은 버전은 Maven repository에서 찾아보기.
  4. log4j 버전 바꾸기
    • log4j 이슈 때문에 일단 최신 버전인 2.17.0으로 맞춰 버전을 변경해주었다.
    • 다른 조치는 아직까지 없는듯..?
  5. 설정에서 버전 바꿔주기
    • 버전만 다운로드 된 거지 프로젝트에서 사용하겠다는 설정은 별도로 해줘야함
    • 프로젝트 우클릭> Properties > Project Facets > 자바 11, Dynamic Web Module 3.1로 바꿔주기.
  6. ojdbc 추가하기
    • DB와 연동시켜야 하므로, ojdbc를 Maven Repository에서 검색하여 추가해준다.
    • ojdbc8의 dependency 코드를 추가해주자.
    • 가끔 링크가 깨져서 에러가 나는 경우가 있으므로, 잘 찾아서 쓰도록 하자.

⑤ 인코딩 설정

Preferences에서 CSS, HTML, JSP, Content Types, Workspace 설정을 모두 UTF-8로 바꿔준다.
MAC은 패스!

⑥ Server 추가

왼쪽 하단에 No servers are available... 눌러서 Tomcat 추가를 해준다.
우리는 8.5버전을 쓰므로 아파치를 누르고 8.5를 맞춰 클릭
톰캣이 저장되어있는 경로를 설정해준다.

⑦ 포트번호, path 변경

안해줘도 상관은 없지만 편리함을 위해 포트번호를 80번, path=”“로 변경.

3) 조수 두명!

스프링 프로젝트에서는 MavenSpring 이 두 조수가 개발을 지원해준다.

  • Maven
    • 라이브러리 관리
    • 배포 관리
  • Spring
    • 인스턴스 라이프사이클 관리
    • 디자인패턴 관리
    • 횡단관심사 관리
    • 스케쥴링 관리
    • 트랜젝션 관리 등등..

① Maven

기본적으로 프로젝트의 라이브러리를 관리한다.
pom.xml을 통해 라이브러리를 관리할 수 있다.
위의 2) 환경설정의 ④번이 좋은 예시이다.

② Spring

스프링 MVC 패턴의 순서와 각 개념을 이해해야 스프링이 어떤 일을 하는지 이해하기 쉽다.

ⓐ Spring MVC 구성요소
구성요소 하는 일
Dispatcher Servlet 진정한 의미의 프론트 컨트롤러. 모든 흐름을 통제한다.
Handler Mapping 어떤 클라이언트 요청이 들어오냐에 따라 컨트롤러를 분배
ViewResolver URL을 조립하는 역할
Controller DAO를 불러서 일을 처리
ModelAndView DAO한테 받은 응답을 request에 넣음(Model) + 가야하는 jsp이름(View)
View 결과 데이터를 화면에 뿌려준다
ⓑ Spring MVC 작동 순서
  1. 클라이언트가 요청을 전송한다.
  2. Dispatcher Servlet이 클라이언트의 Request를 분석한다(요청 URI를 확인).
  3. Dispatcher Servlet : 이 클라이언트의 요청을 처리해줄 수 있는 컨트롤러가 누구지?
  4. Dispatcher Servlet : Handler Mapping아 누구한테 가야하는지 알려줘~
  5. Handler Mapping : A컨트롤러로 가면 돼~
  6. Dispatcher는 Handler Mapping이 알려준 컨트롤러에게 request를 넘긴다.
  7. A컨트롤러는 받은 request를 DAO에게 넘긴다.
  8. DAO는 DB와 통신하여 값을 받아온다.
  9. DAO는 그 응답을 컨트롤러에게 보낸다.
  10. 컨트롤러는 ModelAndView 객체를 Dispatcher에 돌려보낸다.
  11. Dispatcher는 ModelAndView를 ViewResolver에게 보냄
  12. ViewResolver는 URL을 조립해서 다시 Dispatcher에게 보냄.
  13. Dispatcher는 URL을 받아서 View에게 전달한다.

4) Spring 프로젝트 폴더의 구조

spring

  • src/main/java
    • DAO, DTO, Controller 등을 실제로 만들어 사용할 폴더
  • src/main/resources
    • mybatis 프레임워크의 자원이나 다른 자원들을 넣는 폴더.
    • HTML, CSS, IMAGE 등을 넣는 폴더가 아니다!
    • 자바와 관련된 자원들을 넣을 때 쓴다.
    • xml 문서 등을 넣을 때 사용한다.
  • src/test/java와 src/test/resources
    • jUnit(단위테스트 라이브러리)를 사용할 때 쓴다.
    • 우리 과정은 TDD(Test Driven Development)가 아니기 때문에 패스..
  • JRE System Library
    • 자바가 스프링에 제공해주는 라이브러리
  • Maven Dependencies
    • 프로젝트에 들어간 라이브러리는 모두 여기에 모인다.
  • target
    • 배포 전 필요한 것들이 이곳으로 다 복사가 된다. 그 후 target 폴더 안에 있는 내용들이 realPath로 복사가 된다.
    • 만들고 실행하는 과정에 자동으로 제어되기 때문에 이 폴더를 만질일은 없다.
  • src/main/webapp/resources
    • HTML, CSS, JS 등이 모이는 곳.
  • src/main/webapp/WEB-INF/views
    • jsp 파일들이 모이는 곳
    • jsp파일을 클릭하고 실행하는 것이 막힌다.
    • WEB-INF 폴더가 외부에서 접근을 차단하기 때문.
  • src/main/webapp/WEB-INF/spring
    • 폴더 안 servlet-context.xml 과 root-context.xml은 스프링이 읽어들일 설정파일이다.
  • src/main/webapp/WEB-INF/classes
    • spring 폴더나 views 폴더는 마음대로 지워도 되지만 이 폴더는 지우면 안됨!
    • 내가 만든 클래스들이 컴파일되어 들어오는 곳
    • 건드리지 않는 것이 좋다.

5) 프로젝트 실행 과정

위의 Spring MVC 작동 순서와는 다른, 프로젝트를 실행했을 때 어떤 순서로 동작하는지를 정리한다.

  1. Tomcat 실행
  2. web.xml 분석(톰캣꺼 말고 프로젝트꺼. views 폴더 안에 있는)
  3. web.xml 분석 중에 Spring Container 생성
  4. Spring Container 가동되며 servlet-context.xml & root-context.xml 분석
  5. servlet-context.xml 분석 중에 InternalResourceViewResolver 인스턴스 생성
  6. Component-scan이 실행되면서 특정 @Annotation이 붙은 클래스들을 인스턴스로 생성

6) localhost만 쳤는데 home.jsp로 어떻게 이동하는가?

HomeController 안에 아래와 같이 home 메소드가 있다고 치자, 여기서 브라우저에 localhost만 입력해도 home.jsp(이미 만들어놓은 기본 jsp)로 이동할 수 있다. 어떻게 이동이 되는 것일까?

@Controller
public class HomeController {
	
	@RequestMapping("/")
	public String home() {
		return "home";
	}	
}
  1. 서버가 켜짐
  2. 톰캣이 실행됨
  3. 스프링 컨테이너 생성됨
  4. InternalResourceViewResolver 인스턴스 생성됨
  5. 동시에 HomeController 생성됨(component-scan이 돌면서 @controller를 찾아 인스턴스를 생성)
  6. annotation-driven이 Handler Mapping에게 @controller가 붙은 애들의 존재를 알려준다.(이런 애도 있으니까 같이 조회해~)
  7. @controller가 붙은 클래스 안에 @RequestMapping 안에 있는 URL을 Handler Mapping에 등록 (/ -> HomeController)
  8. 클라이언트가 localhost를 주소창에 입력( / 요청)
  9. Dispatcher가 /를 Handler Mapping한테 물어봄
  10. 7번에 저장된 정보로 HomeController로 보내짐
  11. HomeController 안에 home 메소드 실행

① views/web.xml

web.xml 안의 코드를 살펴보자.

ⓐ Dispatcher 인스턴스 생성 코드
<!-- Processes application requests -->
<servlet>
	<servlet-name>appServlet</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>
ⓑ Spring 컨테이너 생성 코드

bean 태그는 스프링 컨테이너에게 인스턴스를 만들라는 명령을 내려준다.

<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
ⓒ Spring 컨테이너가 생성되며 아래 두 xml문서를 읽어들인다.
  1. /WEB-INF/spring/appServlet/servlet-context.xml (Dispatcher 인스턴스 생성 코드 안에 있는)
  2. /WEB-INF/spring/root-context.xml (pom.xml 안에 있는)
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>

② root-context.xml

아직 아무런 내용도 존재하지 않음.
스프링 컨테이너가 생성되며 읽어들여도 아무 일도 발생하지 않는다.

③ servlet-context.xml

ⓐ ViewResolver 인스턴스 생성
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<beans:property name="prefix" value="/WEB-INF/views/" />
	<beans:property name="suffix" value=".jsp" />
</beans:bean>
ⓑ @Annotation이 붙은 클래스들을 인스턴스로 생성
<context:component-scan base-package="kh.spring.controller" />
ⓒ Handler Mapping 에게 알림

@controller라는 어노테이션이 붙은 애들의 존재를 Handler Mapping에게 알려준다.
나중에 얘네들도 조회될 수 있게끔.
즉, @RequestMapping 어노테이션에 있는 url을 Handler Mapping이 알고 있게한다.

<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />

7) ViewResolver

URL을 조립하는 역할이라고 정리는 했는데.. 어떻게 조립한다는 것일까?

@Controller
public class HomeController {
	
	@RequestMapping("/")
	public String home() {
		return "home";
	}	
}

스프링의 @RequestMapping 이 붙은 메소드는 리턴할 수 있는 값의 종류가 3가지이다.

  1. void
  2. String
  3. ModelAndView

여기서 / 요청을 받아서 String값 home을 리턴하게 되면, Dispatcher는 ViewResolver에 이 값을 전달한다.
아래는 servlet-context.xml 안의 ViewResolver 생성 코드이다.

<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<beans:property name="prefix" value="/WEB-INF/views/" />
	<beans:property name="suffix" value=".jsp" />
</beans:bean>

prefix는 접두사, suffix는 접미사라는 뜻으로, home 값의 각각 앞 뒤에 이 value 값들을 붙여주면 /WEB-INF/views/home.jsp 가 된다.
즉, 위의 경로로 갈 수 있게 경로를 조립한다는 뜻이다.
ViewResolver는 위처럼 jsp로만 조립하는 것이 아니라 html, 파일첨부 등 다양하게 쓸 수 있다. 아직은 이해를 돕기 위해 jsp만 두고 실습을 하는 것 같다.

3. MVC2 와 Spring MVC의 차이

기존 세미 프로젝트를 하면서 느꼈던 불편함이 스프링으로 넘어오면서 해소가 되는 것 같다.
아직 스프링을 배운지 1일차이지만, 갈수록 더 느껴질 것 같아 따로 정리를 미리 해본다.

1) JSP로 다이렉트 접근

MVC2에서는 JSP 경로를 주소창에 다이렉트로 적어주면 접근이 가능했다. 대신 컨트롤러를 거치지 않았기 때문에 빈 페이지나 에러 페이지를 볼 수 있었다.
하지만 스프링은 직접적인 주소를 적어서 들어가는 것을 막아놓았기 때문에 이런 상황이 발생되지 않게 한다.
따라서 스프링에서는 redirect는 더이상 쓸 수 없고, forward만 사용이 가능하다.

2) new를 할 수 없다.

MVC2에서는 모든 인스턴스 생성을 개발자가 할 수 있었지만, 스프링에서는 new를 제한하여 더이상 개발자가 new를 할 수 없게 만든다.
대신 스프링 컨테이너가 대신 인스턴스를 생성하여 가지고 있다가 개발자가 필요할 때 꺼내쓰도록 해준다.
스프링에서 인스턴스 생성은 xml 파일에 bean 태그를 통해 이루어진다.(싱글톤으로 만들어진다.)
물론 전부 그런 것은 아니다.

3) 서버에서 값 받기

MVC2에서는 request.getParameter를 이용하여 name값을 받아왔다.
스프링에서도 메소드에 HttpServletRequest reqeust를 인자값으로 받아서 getParameter를 쓸 수 있지만, 그것보다 더 쉬운 방법이 있다.

@RequestMapping("inputProc")
public String inputProc(HttpServletRequest request) {
	String name = request.getParameter("name");
	String contact = request.getParameter("contact");
	return "home";
}

바로 매개변수에 자료형을 일치시키고, name 값을 일치시키면 동일하게 데이터를 받아온다는 것이다.

@RequestMapping("inputProc")
public String inputProc(String name, String contact) {
	return "home";
}

또 다른 방법은 DTO를 생성하여 DTO 자체를 받는 것이다.
주의할 점은 name 속성과, DTO의 멤버필드 이름이 동일해야 한다.
seq값은 넘어오지 않기 때문에, 아래 상황에서는 0이 입력되고, String이라면 null이 입력된다.

public class ContactDTO {
	private int seq;
	private String name;
	private String contact;
}
@RequestMapping("inputProc")
public String inputProc(ContactDTO dto) {
	System.out.println(dto.getName() +":"+ dto.getContact());
	return "home";
}

매개변수는 한개 이상 받을 수 있기 때문에, 여러 값을 한꺼번에 받는 것도 물론 가능하다.

@RequestMapping("inputProc")
public String inputProc(ContactDTO dto, HttpSession session) {
	System.out.println(dto.getName() +":"+ dto.getContact());
	String id = (String)session.getAttribute("loginId");
	return "home";
}

댓글남기기