코딩하는 문과생
[Spring] Spring 프레임워크(2) - Layer와 MVC패턴 본문
[계층화 아키텍처]
효율적인 개발과 유지보수를 위해 계층화하여 개발
각 레이어는 독립된 R&R을 가진다.
-
프레젠테이션(화면) 영역: 사용자와 상호작용을 담당, 사용자의 요청을 분석/응답
-
비즈니스 영역: 기능을 수행, 트랜잭션 수행
-
데이터 영역: 데이터의 저장과 조회를 담당, 주로 데이터베이스와 연동하여 작업
[MVC패턴]
프레젠테이션쪽을 세분화한 패턴
-
View - 화면
-
Controller - View와 Model의 바인딩과 제어를 담당, 사용자의 요청을 처리
-
Model - 화면에 뿌려질 데이터(데이터의 저장과 처리)
[컴포넌트 자동등록]
1. 어노테이션을 사용
@Component
@Controller - 프레젠테이션 영역
@Service - 비즈니스 영역
@Repsitory - 데이터 영역
2. <context:component-scan base-package="패키지 명" />
어노테이션이 있는 클래스를 스캔한다.
Bean이 될 수 있는 모든 컴포넌트들을 자동으로 찾아 Bean Container에 등록
3. @Autowired를 이용해 Component간 의존관계 표현
ex. component layer
- Article.java
package kr.co.acomp.hello.vo;
public class Article {
private int articleId;
private String author;
private String title;
private String content;
public Article() {
}
public Article(int articleId, String author, String title, String content) {
this.articleId = articleId;
this.author = author;
this.title = title;
this.content = content;
}
public int getArticleId() {
return articleId;
}
public void setArticleId(int articleId) {
this.articleId = articleId;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "Article [articleId=" + articleId + ", author=" + author + ", title=" + title + ", content=" + content
+ "]";
}
}
-spring-context.xml 추가
<!-- 해당 패키지 하위에 있는 컴포넌트를 스캔한다. -->
<context:component-scan base-package="kr.co.acomp.hello"/>
- ArticleDAO.java
package kr.co.acomp.hello.dao;
import org.springframework.stereotype.Repository;
import kr.co.acomp.hello.vo.Article;
@Repository
public class ArticleDAO {
public void insertArticle(Article article) {
System.out.println("insert OK...");
}
}
- BbsService.java
package kr.co.acomp.hello.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import kr.co.acomp.hello.dao.ArticleDAO;
import kr.co.acomp.hello.vo.Article;
@Service
public class BbsService {
//Auto DI를 위한 어노테이션
@Autowired
private ArticleDAO articleDAO;
public void registArticle(Article article) {
articleDAO.insertArticle(article);
}
}
-HelloMain.java
package kr.co.acomp.hello;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import kr.co.acomp.hello.service.BbsService;
import kr.co.acomp.hello.vo.Article;
public class HelloMain {
public static void main(String[] args) {
AbstractApplicationContext ctx =
new ClassPathXmlApplicationContext("/spring-context.xml");
BbsService service = ctx.getBean("bbsService", BbsService.class);
service.registArticle(new Article());
//insert OK~
}
}
[MVC패턴 - 모델2 아키텍처]
비즈니스 로직과 프레젠테이션을 분리하기 위함
-
컨트롤러: 요청 처리 및 흐름 제어 담당(프론트 컨트롤러- 모든 요청을 받는다, 애플리케이션 컨트롤러 - @Controller)
-
모델: 비즈니스 로직 및 데이터 처리 담당
-
뷰: 모델이 처리한 결과 데이터의 화면 생성 담당
서버 템플릿 기술: Thymeleaf
프론트 컨트롤러: 클라이언트가 보낸 요청을 맏아 공통 작업을 먼저 수행, 적절한 세부 컨트롤러에게 작업을 위임, 마지막 뷰를 생성
[Spring MVC]
DI, AOP 지원, 웹개발을 위한 MVC프레임워크를 제공
프론트 컨트롤러(DispatcherServlet클래스 - 모든 요청을 받아서 처리, 예외 발생 시 일관된 방식으로 처리) 지원
- 구성요소
-
DispatcherServlet
-
HandlerMapping - DispatcherServlet이 어떤 Controller를 호출해야 되는 지 알려준다.
-
Controller - 요청처리, @Controller를 우리는 개발한다.
-
ModelAndView - 화면과 데이터에 대한 정보를 보유한 객체
-
ViewResolver - 어떤 뷰를 선택할 지 도와준다.
-
View - 화면 정보만 보유한 객체
web.xml에서 DispatcherServlet설정과 filter, encoding작업이 필요하다.

ex. 설정
- pom.xml 추가
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
-web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<!-- 모든 요청에 대해 DispatcherSevlet을 통과해라 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/servlet-context.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
-servlet-context.xml 생성
<?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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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="kr.co.acomp.hello"></context:component-scan>
<mvc:annotation-driven/>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
[Controller]
-
사용자 요청(url) 기준으로 컨트롤러의 특정 메소드를 찾는다.
-
요청 파라미터가 있으면 처리하고
-
비즈니스 처리를 위해서 서비스(Service) 컴포넌트를 주입받는다.
-
실행된 결과를 전달받아 DispatcherServlet에게 반환
- 주요 어노테이션
@Controller
@RequestMapping: 클래스 레벨과 메소드 레벨에서 정의하는 방법이 있다.
@Autowired
- ModelAndView에는 2가지가 저장된다.
1. ViewName 2. 담은 데이터(key:value, 이 값은 jsp파일에서 ${...}형식으로 받아올 수 있다.)
- 리다이렉트와 포워드, /로 시작하면 절대경로, 없다면 현재 경로 기준
-
return "redirect:/bbs/list"
-
return "forward:/bbs/list"
ex. controller
- BbsController.java
package kr.co.acomp.hello.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import kr.co.acomp.hello.service.BbsService;
import kr.co.acomp.hello.vo.Article;
@Controller
@RequestMapping("/bbs")
public class BbsController {
@Autowired
private BbsService bbsService;
@RequestMapping("/write")
public String write() {
bbsService.registArticle(new Article());
return "write_ok";
}
}
-write_ok.jsp
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
<h1>write ok...</h1>
</body>
</html>
- BbsController.java 수정
@Controller
@RequestMapping("/bbs")
public class BbsController {
@Autowired
private BbsService bbsService;
@RequestMapping("/write")
public String write(@RequestParam("author") String author) {
bbsService.registArticle(new Article());
System.out.println(author);
return "write_ok";
}
}


[Http 파라미터 처리]
-@RequestParam
required=false는 요청 값이 없을 때 에러를 보내지 않고 null을 리턴
required=false, defaultValue=""는 null인경우 값을 지정할 수 있다.
-파라미터가 많아지는 경우
: Command객체를 이용해 폼을 전송한다.
ex. public ModelAndView test9(Member member) {...
-
Command객체는 자동으로 View의 Model로 바로 등록
-
타입 자동 변환 기능
-
name이 동일한 input값들을 List로 처리가능
ex. get방식과 post방식
package kr.co.acomp.hello.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import kr.co.acomp.hello.service.BbsService;
import kr.co.acomp.hello.vo.Article;
@Controller
@RequestMapping("/bbs")
public class BbsController {
@Autowired
private BbsService bbsService;
@RequestMapping(value="/write", method=RequestMethod.POST)
//@PostMapping("/write")
public String doWrite() {
bbsService.registArticle(new Article());
System.out.println("post request...");
return "write_ok";
}
@RequestMapping("/write")
//@GetMapping("/write")
public String write() {
bbsService.registArticle(new Article());
System.out.println("get request...");
return "write_ok";
}
}
ex.@Pathvariable
- BbsController.java 추가
@GetMapping("/{articleId}")
public String viewDetail(@PathVariable String articleId) {
System.out.println("글 번호는: " + articleId);
return "write_ok";
}

ex. command객체
- BbsController.java 수정
@PostMapping("/write")
//스프링은 파라미터 내 객체를 Command객체로 판단한다.
public String doWrite(Article article) {
bbsService.registArticle(article);
System.out.println("post request...");
return "write_ok";
}
-ArticleDAO 수정
public void insertArticle(Article article) {
System.out.println(article);
}

ex. ModelAndView로 jsp에 데이터 전달
-BbsController.java수정
@PostMapping("/write")
//스프링은 파라미터 내 객체를 Command객체로 판단한다.
public ModelAndView doWrite(Article article) {
bbsService.registArticle(article);
System.out.println("post request...");
return new ModelAndView("write_ok").addObject("article", article);
}
-write_ok.jsp
<body>
<h1>write ok...</h1>
<ul>
<li>${article.articleId }</li>
<li>${article.author }</li>
<li>${article.title }</li>
<li>${article.content }</li>
</ul>
</body>

'웹 프로그래밍 > Spring' 카테고리의 다른 글
| [Spring] Spring 프레임워크(4) - static 파일처리, 파일 업로드 (0) | 2020.03.08 |
|---|---|
| [Spring] Spring 프레임워크(3) - Rest API (0) | 2020.03.08 |
| [Spring] Spring 프레임워크(1) - 개요, Maven, IoC (0) | 2020.03.08 |
| [Spring] 8. 스프링 기본(7) - Interceptor (0) | 2020.02.07 |
| [Spring] 7. 스프링 기본(6) - 게시판 (CRUD)2 (0) | 2020.02.07 |