Java/Spring

[Spring] 13. Spring MVC

담크 2021. 7. 8. 23:58

이번에는 SpringMVC에 대해 설명해보도록 하겠습니다.

먼저 SpringMVC을 간단하게 설명하자면

 

SpringMVC란?

- 스프링 프레임워크에서 지원하는 SpringMVC는 모델-뷰-컨트롤러(MVC)구현을 포함하여 도메인 모델 코드와 웹 폼을 깔끔하게 분리할 수 있도록 한다.

- 스프링 프레임워크의 다른 기능과 통합할 수 있게 하며, MVC 기반의 웹 프로그램 개발을 효율적으로 할 수 있도록 지원한다.

 

SpringMVC 특징

- Spring Framework의 다른 모듈과의 연계가 용이하다.

- 컨트롤러, command 객체, 모델 객체, Validator 등 각각의 역할에 대한 명확한 분리가 되어있다.

- Form 객체 없이 사용자 지정 가능한 데이터 바인딩과 유효성 체크를 지원한다.

- 어떠한 View 기술과도 연계가 용이하다.

- Tag lib을 통한 Message 출력, 테마 적용 등과 입력 폼을 보다 쉽게 구현할 수 있다.

 

SpringMVC 장점

- SpringMVC 프레임워크는 스프링 기반으로 사용할 수 있다.

- 스프링이 제공하는 트랜잭션 처리가 DI 나 AOP 적용 등을 쉽게 사용할 수 있도록 돕는다.

- 스트럭츠와 같은 프레임워크와 스프링 프레임워크를 연동하기 위해 추가적인 설정을 하지 않아도 된다.

 

 

SpringMVC부터는 앞과 다르게 단순히 기술 설명이 아닌 흐름으로 나타내기 때문에 코드를 한 번에 작성해두는 게 아닌 그때그때 맞춰서 작성하겠습니다.

 

우선 이클립스에서 오른쪽 상단의 Perspective를 JAVAEE로 변경해주세요

Project Explorer에서 마우스 오른쪽 - new - Dynamic Web Project를 선택합니다.

저는 같은이름의 프로젝트가 이미 있어서 저렇게 나오는데 이름은 원하시는걸로 하시면 됩니다.

Next를 누르고

위 사진과 같이 작성해줍니다. (체크박스는 꼭 체크하셔서 web.xml파일을 만들어주세요!!)

그다음 프로젝트를 maven으로 만들어주세요

(프로젝트 우클릭-configure-convert to maven project를 눌러주시면 만들 수 있습니다.)

 

프로젝트 생성이 완료되었다면 pom.xml이라는 파일이 보일 텐데 

spring-web / spring-webmvc 이렇게 2개를 </build> 태그 아래에 <dependencies>를 추가해 붙여주세요

추가하는 방법은

https://darmk.tistory.com/entry/Spring-Eclipse%EC%97%90-Spring-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0?category=945098 

 

[Spring] Eclipse에 Spring 설치하기

이제 스프링을 실습하기 위한 환경을 구축할 건데요. 저는 Eclipse IDE 환경에서 실습할 예정이며 이클립스 설정에 대한 부분은 추후 올리겠습니다. 가장 먼저 Eclipse 위에 메뉴바에 help 눌러보시면

darmk.tistory.com

 

여기를 참고하시면 됩니다.

그다음은 WebContent/WEB-INF를 들어가 보시면 아까 만든 web.xml파일이 있을 거예요

여기서 welcomfile list를 다 지우고 listener를 써줄 건데

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>Spring07_HelloMVC</display-name>
	
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/applicationContext.xml</param-value>
	</context-param>
    
	<servlet>
		<servlet-name>hello</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	</servlet>
	<!-- /*.do 아님!! -->
	<servlet-mapping>
		<servlet-name>hello</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
</web-app>

이렇게 작성해주시면 됩니다.

그리고 web.xml과 같은 경로에 hello-servlet.xml과 applicationContext.xml을 만들어줄 건데요

만들 때는 new-other에서 Spring Bean Configuration File로 만들어줍니다.

hello-servlet을 만들 땐 Next를 눌러서 Context, mvc에 두 개다 체크표시를 해주세요

그리고 아래와 같이 코드를 작성해줍니다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

	<context:component-scan base-package="com.hello.mvc" />
	<mvc:annotation-driven />
</beans>

<context:component-scan base-package="com.hello.mvc" />는 com.hello.mvc 밑에 있는 거 다 읽어온다 라는 의미로 알고 계시면 됩니다.

이제 src폴더 밑에

이렇게 3개의 패키지와 클래스를 만들어주세요

그다음 controller, biz, dao각각에 @Controller, @Service, @Repository 어노테이션을 작성해줍니다.

그러면 어노테이션이 자동으로 Controller는 controller, Biz는 service, Dao는 repository로 등록시켜줍니다.

(이 부분은 예전 같았으면 servlet으로 따로 만들어줬어야 했는데 @annotation으로 설정해준 겁니다. ㅎㅎ)

 

그 다음 내용을 작성해봅시다.

HelloController.java

package com.hello.mvc.controller;

import org.springframework.stereotype.Controller;

@Controller
public class HelloController {
	
	@Autowired
	private HelloBiz biz;
	
	@RequestMapping("/hello.do")
	public String getHello(Model model) {
		
		model.addAttribute("message", biz.getHello());
		return "/WEB-INF/views/hello.jsp";
	}
	
	@RequestMapping("/bye.do")
	public ModelAndView getBye(@RequestParam("name") String nickname) {
		ModelAndView mav = new ModelAndView();
		
		mav.setViewName("/WEB-INF/views/bye.jsp");
		mav.addObject("message", "bye, " + nickname);
		
		return mav;
	}
}

이 getHello부분과 getBye는 사용되는 의미가 같다고 보시면 됩니다.

지금보다 더 옛날엔 getHello( )부분을 getBye( )와 같이 썼다고 합니다.

 

HelloBiz.java

package com.hello.mvc.biz;

import org.springframework.stereotype.Service;

@Service
public class HelloBiz {
	@Autowired
	private HelloDao dao;
	
	public String getHello() {
		return "Hello, " + dao.getHello();
	}

}

HelloDao.java

package com.hello.mvc.dao;

import org.springframework.stereotype.Repository;

@Repository
public class HelloDao {

	public String getHello() {
		return "Spring";
	}

}

자 이제 controller에서 "/WEB-INF/views/hello.jsp"를 리턴해줬으니 해당경로에 파일을 만들도록 하겠습니다.

WEB-INF폴더 안에는 views폴더도 없으므로 views폴더를 먼저 만들고 그 안에 hello.jsp, bye.jsp를 만들어줍시다.

hello.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	<h1>${message }</h1>
	
</body>
</html>

bye.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	<h1>${message }</h1>
</body>
</html>

그리고 처음 실행을 위한 index.html도 만들어 줍니다.(경로는 WebContent 밑에다가 만들어주세요!!)

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	<a href="hello.do">hello</a>
	<br/>
	<a href="bye.do?name=spring">bye</a>
</body>
</html>

이제 코드를 실행해보면

가장 처음 로드된 화면
hello 링크를 눌렀을 때

 

bye 링크를 눌렀을 때

 

결국 이 코드들은 spring에서 mvc패턴으로 web을 하려고 한다. 라고 생각하시면 됩니다.

이제 위의 코드를 정리한 내용을 살펴보면

 

1. 처음에 index에서 hello.do를 눌렀을 때 listener가 그 요청이 어디로 가야 할지, 어떤 서블릿으로 올려줘야 되는지 그런 것들을 연결해주는 역할을 한다.

 

2. Dispatcher servlet이 요청이 들어오면 어떤 서블릿한테 넘겨줘야하는지(어떤 컨트롤러를 연결해줘야 하는지) 파악하고 넘겨준다.

init param이 없으면 servlet-name에 써있는 이름과 똑같은 (이름-servlet.xml)파일을 자동으로 읽어준다. (여기서는 그래서 hello-servlet.xml을 읽어줍니다.)

 

3. com.hello.mvc 아래에 있는 모든 패키지의 annotation을 읽어서 객체를 생성하고 값을 읽어온다.

(mvc:annotation-driven 태그가 없어도 mvc설정이 가능하지만 이 태그는 mvc와 관련된 것들을 따로 관리해준다고 합니다.)

 

4. applicationContext에서 project전체에 사용되는 공용 객체들을 저장한다.

context-param은 context(즉 project) 전체에 적용되어 사용되는 변수의 값(모든 서블릿에서 사용하는 애)인데 web.xml에서 context-param을 해줬기 때문에 가능합니다.

 

5. Dispatcher servlet은 Handlermapping을 통해서 Controller한테 요청을 전달해준다.

 

6. Controller -> Service -> Repository -> DB -> Repository -> Service -> Controller 로 값을 보내고 응답받는다.

 

7. Controller에서 MAV(Model And View)라는 객체에 model값과 view값을 같이 보낸다.

 

8. Dispatcher servlet이 그걸 받아서 viewResolver를 통해 해당 view를 가져와서 응답한다. (가지고 올때 Model에 담겨있는 값을 준다.)

 

9. hello.jsp에 {message}부분에 값이 들어가고 출력된다.

 

이 흐름도를 그림으로 본다면

 

 

**추가

혹시 hello.jsp나 bye.jsp만들 때 <%@ 부분에 에러가 발생하면

https://darmk.tistory.com/entry/The-superclass-javaxsaervlethttpHttpServlet-was-not-found-on-the-Java-Build-Path-%EC%97%90%EB%9F%AC

여기를 참고해주세요

 

 

 

** 몇가지 annotation에 대한 간단한 정리 

 

@RequsetMapping

- url을 class 또는 method와 mapping을 시켜주는 역할

 

@RequestParam

- key=value 형태로 넘어오는 파라미터를 mapping된 method의 파라미터로 지정

 

@ModelAttribute

- form tag를 통해 넘어온 model을 mapping된 method의 파라미터로 지정

 

@SessionAttribute

- session에서 model의 정보를 유지하고 싶을 경우 사용