Spring을 처음 사용해볼 때 @Controller@RestController의 차이점도 정확히 모르고 둘이 헷갈려 사용을 제대로 못해 제가 원하는 View를 보여주지 못했던 기억이 있습니다.

 

오늘은 Spring MVC에서 자주 쓰게 되는 @Controller@RestController의 차이점을 알아보겠습니다.

 

 

@Controller@RestController의 차이

 

Spring에서 컨트롤러를 지정해주기 위한 어노테이션은 @Controller@RestController가 있습니다.

전통적인 Spring MVC의 컨트롤러인 @ControllerRestuful 웹서비스의 컨트롤러인 @RestController의 주요한 차이점은 HTTP Response Body가 생성되는 방식입니다.

 

좀 더 쉽게 말하자면 @Controller의 주용도는 View를 리턴하는 것이고, @RestControllerJSON/XML 타입의 HTTP 응답을 직접 리턴합니다.

 

2가지의 어노테이션을 아래에서 간단히 설명해드리겠습니다.

 

1. @Controller(Spring MVC Controller)

Controller에서 View 반환하는 경우

 

전통적인 Spring MVC의 컨트롤러인 @Controller는 주로 View를 반환하기 위해 사용합니다. 아래와 같은 과정을 통해 Spring MVC ContainerClient의 요청으로부터 View를 반환합니다.

 

1.ClientURI 형식으로 웹 서비스에 요청을 보낸다.

2.Mapping되는 Handler와 그 Type을 찾는 DispatcherServlet이 요청을 인터셉트한다.

3.Controller가 요청을 처리한 후에 응답을 DispatcherServlet으로 반환하고, DispatcherServletView를 사용자에게 반환한다.

 

Client -> Request -> Dispatcher Servlet -> Handler Mapping -> Controller -> View -> Dispatcher Servlet -> Response -> Client

 

 

Data를 반환할 때

 

Spring MVC ControllerView 만 반환하지 않습니다. Data를 반환해야 하는 경우가 있는데 이럴 때에는ResponseBody 어노테이션을 활용하여 Json형태로 데이터를 반환할 수 있습니다.

 

1.ClientURI 형식으로 웹 서비스에 요청을 보낸다.

2.Mapping되는 Handler와 그 Type을 찾는 DispatcherServlet이 요청을 인터셉트한다.

3.@ResponseBody를 사용하여 Client에게 Json 형태로 데이터를 반환한다.

 

Client -> Request -> Dispatcher Servlet -> Handler Mapping -> Controller (ResponseBody)-> Response -> Client

 

 

2. @RestController(Spring Restful Controller)

 

@RestControllerSpring MVC Controller@ResponseBody가 추가된 것입니다. 클래스 상단에 @RestController 어노테이션을 선언하면 Method마다 @ResponseBody를 붙여 주지 않아도 됩니다.

RestController의 주용도는 Json/Xml 형태로 객체 데이터를 반환하는 것입니다.

 

 

1.ClientURI 형식으로 웹 서비스에 요청을 보낸다.

2.Mapping되는 Handler와 그 Type을 찾는 DispatcherServlet이 요청을 인터셉트한다.

3.RestController는 해당 요청을 처리하고 데이터를 반환한다.

 

Client -> HTTP Request -> Dispatcher Servlet -> Handler Mapping -> RestController (자동 ResponseBody 추가)-> HTTP Response -> Client

 

 

참고한 자료

https://mangkyu.tistory.com/49

https://www.genuitec.com/spring-frameworkrestcontroller-vs-controller/

https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html

 

다들 스프링부트 프로젝트를 처음 시작할때 @SpringBootApplication를 한번씩 보셨을 것입니다.

오늘은 @SpringBootApplication에 대해서 간단히 알아보겠습니다.

@SpringBootApplication 이란?

@SpringBootAplication 어노테이션은 auto-configuration을 담당합니다.

다시 이야기 하자면 @SpringBootAplication 어노테이션으로 인해 스프링 부트의 자동 설정, 스프링 Bean 읽기와 생성이 모두 자동으로 설정됩니다.

 

@SpringBootAplication 어노테이션이 있는 위치부터 설정을 읽어가기 때문에 이 어노테이션을 포함한 클래스는 항상 프로젝트의 최상단에 위치해야만 합니다.

 

 

@SpringBootAplication의 내부 구조

@SpringBootAplication의 내부 구조를 간단히 살펴 보면 아래와 같습니다.

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
...

@SpringBootApplication을 이용하면 위 코드를 보면 알 수 있듯이 세가지의 어노테이션을 포함하고 있습니다.

- @EnableAutoConfiguration

- @ComponentScan

- @SpringBootConfiguration

 

이 세가지의 어노테이션이 @SpringBootAplication의 특징인데 아래에서 간단히 설명하겠습니다.

 

@EnableAutoConfiguration 설정 자동 등록하기

@EnableAutoConfigurationSpring boot의 핵심으로써, 미리 정의되어 있는 Bean들을 가져와서 등록해줍니다.

미리 정의되어 있는 Bean들은 spring-boot-autoconfigure > META-INF > spring.factories에 위치하여 있습니다.

 

@ComponentScan 빈 등록하기

스프링에서 관리하는 POJO(Bean)’이라고 합니다.

 

@ComponentScan은 현재 패키지 이하에서 아래와 같은 어노테이션이 붙어 있는 클래스들을 찾아서 빈으로 등록하는 역할을 합니다.

@Component
@Configuration
@Repository
@Service
@Controller
@RestController

 

@SpringBootConfiguration - @Configuration의 용도

 

@Configurationspring 에 빈 팩토리를 위한 오브젝트를 설정을 담당하는 클래스라고 인식 할 수 있도록 알려주는 어노테이션입니다.

 

@SpringBootConfiguration@Configuration의 대안이라고 할 수 있습니다.

@Configuration와 거의 같은 일을 하지만 가장 큰 차이점이라고 하면 @SpringBootConfiguration을 사용하면 구성을 자동으로 찾을 수 있다는 것 입니다. 이것은 단위 또는 통합 테스트에 특히 유용 할 수 있습니다.

 

 

참고자료

스프링 부트와 AWS로 혼자 구현하는 웹 서비스 -이동욱 지음
https://seongmun-hong.github.io/springboot/Spring-boot-EnableAutoConfiguration
https://www.baeldung.com/springbootconfiguration-annotation

 

IoC의 개념


IoCInversion of Control의 약자 말그대로 제어의 역전이다.

제어의 역전이라을 간단히 말하자면 프로그램의 제어 흐름 구조가 뒤바뀌는 것이라고 설명할 수 있다.

 

 

 

일반적인 제어 흐름(IOC X)


일반적으로 프로그램의 흐름은 main() 메소드와 같이 프로그램이 시작되는 지접에서 다음에 사용할 오브젝트를 결정하고, 결정한 오브젝트를 생성하고, 만들어진 오브젝트에 있는 메소드를 호출하고, 그 오브젝트 안에서 다음에 사용할 것을 결정하고 호출하는 식의 작업이 반복된다.

모든 오브젝트들이 능동적으로 자신이 사용할 클래스를 결정하고, 언제 어떻게 그 오브젝트를 만들지를 스스로 관장한다. 즉 모든 종류의 작업을 사용하는 쪽에서 제어를 하는 구조라고 말할 수 있다.

 

/* 
일반적인 제어권: 자기가 사용할 의존성은 자기가 만들어서 사용
*/


public class PetOwner{
    private AnimalType animal;

    public PetOwner() {
        this.animal = new Dog();
    }
}

 

위의 코드는 PetOwner 클래스에서 Dog이라는 사용할 클래스를 직접 정한다.

 

 

 

제어가 역전된 흐름


제어의 역전이란 위와 같은 제어 흐름의 개념을 거꾸로 뒤집는 것이라고 말할 수 있다.

제어의 역전에서는 오브젝트가 자신이 사용할 오브젝트를 스스로 선택하지 않고 생성하지 않는다.

또한 모든 제어 권한을 자신이 아닌 다른 대상에게 위임하기 때문에 자신도 어떻게 만들어지고 어디서 사용되는지를 알 수 없다. 

 

/*
Inversion Of Control
다른 누군가가 의존성을 밖에서 준다.(제어권의 역전)
의존성을 주입해주는 일:Dependency Injection(일종의 IOC)
*/

public class PetOwner {
  public AnimalType animal;
  public PetOwner(AninalType animal) {
      this.animal = animal;
  }
  
}

 

위의 코드는 PetOwner의 AnimalType을 자신이 정하는 것이 아니라 외부에서 정하게 된다.

 

 

초기 구조

 

그레이들을 사용하여 스프링 부트 프로젝트를 생성하면 아래와 같은 구조를 가지게 됩니다.

 

 

여기서 논리적 구조란 이클립스와 같은 개발 툴에서 보여지는 프로젝트의 구조를 의미합니다

물리적 구조는 운영체제에서의 실제적인 폴더 구조를 의미합니다.


 

 

프로젝트의 주요 파일 및 구조

프로젝트의 주요 파일 및 구조 의미
src/main/java 자바 소스 디렉터리
SampleApplication 애플리케이션을 시작할 수 있는 main 메서드가 존재하는 구성 메인 클래스
templates 스프링 부트에서 사용 가능한 여러 가지 뷰 템플릿(ex Thymeleaf, FreeMarker) 파일 위치
static 스타일 시트, 자바스크립트, 이미지 등의 정적 리소스 디렉터리
application.properties 애플리케이션 및 스프링의 설정 등에서 사용할 여러 가지 프로퍼티 정의
Project and External Dependencies 그레이들에 명시한 프로젝트의 필수 라이브러리 모음
src JSP 등 리소스 디렉터리
bulid.gradle 그레이들 빌드 명세, 프로젝트에 필요한 라이브러리 관리, 빌드 및 배포 설정

 

 

DAO 란?

- Data Access Object의 약어로서 DB를 사용해 데이터를 조회하거나 조작하는 기능을 전담하도록 만든 오브젝트를 말한다.

 

 

DAO의 클래스 예제

public class UserDao {

 public void add(User user) throws ClassNotFoundException, SQLException{
  Class.forName("com.mysql.jdbc.Driver");
  Connection c= DriverManager.getConnection(
  				"jdbc:mysql://localhost/springbook", "spring", "book");
  
  PreparedStatement ps = c.prepareStatement(
  						"insert into users(id,name,password) value(?,?,?)");
  
  ps.setString(1,  user.getName());
  ps.setInt(2,  user.getValue());
  ps.setString(3,  user.getPassword());
  
  ps.executeUpdate();
  
  ps.close();
  c.close();
 }
}

 

 

+ Recent posts