새소식

IT 기술 면접

[기술면접] 신입이 준비하는 Spring 기술 면접

  • -

1. Framework란?

  • 특정 형태의 소프트웨어 문제를 해결하기 위해 상호 협력하는 클래스 프레임과 인터페이스 프레임의 집합.
  • 특정한 틀을 만들어 놓고 거기에 살을 붙여 놓음으로써 프로그램을 만들어 작업시간을 줄여주는 것이다.
  • 프레임워크는 특정 개념들의 추상화를 제공하는 여러 클래스나 컴포넌트로 구성된다.

▼ 위의 컴포넌트를 알고 싶다면 클릭!!

더보기

# 컴포넌트란?
컴포넌트는 프로그래밍의 한 부분을 의미하며 재사용이 가능한 최소 단위를 말한다. 그래서 객체지향 언어를 사용할 때 자주 사용되며 재사용이 가능하기 때문에 컴포넌트 단위로 분류하거나 이동 가능하다는 특징이 있다.

이는 모듈(Module)과 혼동될 수 있는데 모듈은 특정 기능을 온전히 수행할 수 있도록 만들어 졌다면 그 모듈 내에서도 재사용이 가능한 단위가 컴포넌트라 할 수 있다.


웹사이트를 구축할 경우 모든 것을 새로 만드는 웹 사이트를 상상조차 할 수 없는게 현실이다. 대부분이 라이브러리, 플러그인, 모듈 그리고 컴포넌트로 재사용이 되는 부분들이 대단히 많다 하겠으며 이를 얼마큼 효과적으로 가장 적합한 어떤 것을 찾고 적용하는 역량이 더 중요해졌다 말할 수 있다.

  • 프레임워크는 이렇게 추상적인 개념들이 문제를 해결하기 위해 같이 작업하는 방법을 정의한다.
  • 프레임워크는 좀 더 높은 수준에서 패턴을 조작한다.

[프레임워크가 중요한 이유]
객체지향 개발을 하게 되면서 개발자의 취향에 따라 다양한 프로그램이 나오게 되었다.

프로그램 개발에 투입되는 개발자도 점점 늘어남에 따라 전체 시스템의 통합성, 일관성이 부족하게 되었기 때문이다.
그래서 개발자의 자유를 제한하기 위해 프레임워크를 도입했다.

 

2. 프레임워크의 장/단점

  • 장점: 개발 시간을 줄일 수 있고 오류로부터 자유로울 수 있다.
  • 단점: 프레임워크에 너무 의존하면 개발 능력이 떨어져서 프레임워크 없이 개발하는 것이 불가능해진다.
    (사용을 하다 보면 편하지만 구조적인 것을 모르고 너무 프레임워크만 의존하면 퇴보할것 같다... )

 

3. Spring Framework(스프링 프레임워크)

  • 자바(JAVA) 플랫폼을 위한 오픈소스 애플리케이션 프레임워크(Framework)이다
  • 자바 엔터프라이즈 개발을 편하게 해주는 오픈소스 경량급 애플리케이션 프레임워크이다
    ( 스프링을 사용하면서 무겁구나 라고 느껐는데, 경량급? 프레임워크라니..ㅎ)
  • 자바 개발을 위한 프레임워크로 종속 객체를 생성해주고, 조립해주는 도구
  • 자바로 된 프레임워크로 자바 SE로 된 자바 객체(POJO)를 자바EE에 의존적이지 않게 연결해주는 역할

▼ 위의 POJO를 알고 싶다면 클릭!!

더보기

# POJO 

평범한 자바 객체라는 뜻인데 어떤 객체를 평범하다고 지칭하는지 그리고
POJO를 사용해서 개발하는게 왜 중요한지 설명하겠다.

먼저 평범하다고 말하는 객체는 다음과 같은 특징을 가진다.

  • 클래스 상속을 강제하지 않는다. 
  • 인터페이스 구현을 강제하지 않는다. 
  • 애노테이션 사용을 강제하지 않는다.

POJO가 아닌 대표적인 객체

public HelloServlet extends HttpServlet {... } 

자바 서블릿 코드를 작성할 때는 이렇게 반드시 HttpServlet을 상속받아야 한다. 

서블릿 프로그래밍을 한다는 이유로 객체지향 프로그래밍의 핵심적인 기능 중 하나인 상속을 빼앗긴 것이나 마찬가지이다. 코드를 작성하고 있는 개발자가 직접 상속을 사용할 수 있는 기회가 없어졌으니.. 

그리고 extends HttpServlet이 추가되면서 이 코드를 이해하기 어려워 진다. 

HttpServlet에서 어떤 기능을 제공하는지 어떤 코드를 어떻게 재사용해야 할지 판단하기도 어렵다. 

POJO는 그러한 제약이 없는 일반적인 객체를 말한다. 
상속이나 인터페이스 구현을 사용하지 않은 객체를 말하는 것이 아니라, 그런 것을 라이브러리나 프레임워크로부터 강제받지 않는 객체라는 것이다. 

public HelloController { .... } 

이런 클래스라면 개발자의 선택에 따라 자신이 만든 다른 Controller클래스를 상속받게 하거나 인터페이스를 구현하게 할 수 있다. 또한 이해하기 쉬운 코드이기도 하다. 무엇보다도 이런 객체가 테스트를 작성하기 편하다. 테스트를 작성하기 쉬운 코드가 곧 좋은 코드이다. 

 

4. 스프링의 특징

  • 경량 컨테이너로서 자바 객체를 직접 관리 => 각각의 객체 생성, 소멸과 같은 라이프 사이클을 관리하며 스프링으로부터 필요한 객체를 얻어올 수 있다.
  • 스프링은 POJO(Plain Old Java Object) 방식의 프레임워크. => 일반적인 J2EE 프레임워크에 비해 구현을 위해 특정한 인터페이스를 구현하거나 상속을 받을 필요가 없어 기존에 존재하는 라이브러리 등을 지원하기에 용이하고 객체가 가볍다.
  • 스프링은 제어의 역행(IoC : Inversion of Control)을 지원 => 컨트롤의 제어권이 사용자가 아니라 프레임워크에 있어서 필요에 따라 스프링에서 사용자의 코드를 호출한다.
  • 스프링은 의존성 주입(DI : Dependency Injection)을 지원 => 각각의 계층이나 서비스들 간에 의존성이 존재할 경우 프레임워크가 서로 연결시켜준다.
  • 스프링은 관점 지향 프로그래밍(AOP : Aspect-Oriented Programming)을 지원 => 따라서 트랜잭션이나 로깅, 보안과 같이 여러 모듈에서 공통적으로 사용하는 기능의 경우 해당 기능을 분리하여 관리할 수 있다.
  • 스프링은 영속성과 관련된 다양한 서비스를 지원 => MyBatis나 Hibernate 등 이미 완성도가 높은 데이터베이스 처리 라이브러리와 연결할 수 있는 인터페이스를 제공한다.
  • 스프링은 확장성이 높음 => 스프링 프레임워크에 통합하기 위해 간단하게 기존 라이브러리를 감싸는 정도로 스프링에서 사용이 가능하기 때문에 수많은 라이브러리가 이미 스프링에서 지원되고 있고 스프링에서 사용되는 라이브러리를 별도로 분리하기도 용이하다.

IOC, DI, AOP는 아래에서 더 설명하겠다

5. Spring MVC 구조의 처리과정

  1. DispatcherServlet : 어플리케이션으로 들어오는 모든 Request를 받는 관문이다. Request를 실제로 처리할 Controller에게 전달하고 그 결과값을 받아서 View에게 전달하여 적절한 응답을 생성할 수 있도록 흐름을 제어한다.

▼DispatcherServlet 장점 클릭!!

더보기

Spring MVC는 DispatcherServlet이 등장함에 따라 web.xml의 역할을 상당히 축소시켜주었습니다. 기존에는 모든 서블릿에 대해 URL 매핑을 활용하기 위해서 web.xml에 모두 등록해주어야 했지만, dispatcher-servlet이 해당 어플리케이션으로 들어오는 모든 요청을 핸들링해주면서 작업을 상당히 편리하게 할 수 있게 되었습니다. 그리고 이 서블릿을 이용한다면 @MVC 역시 사용할 수 있게 되어 좋습니다. 결과적으로 Dispatcher Servlet의 기능 처리를 그려보면 아래의 그림과 같습니다.

  1. HandlerMapping : Request URL 각각 어떤 Controller가 실제로 처리할 것인지 찾아주는 역할
  2. Controller : Request를 직접 처리한 후 그 결과를 다시 DispatcherServlet에게 돌려준다.
  3. ModelAndView : Controller가 처리한 결과와 그 결과를 보여줄 View에 관한 정보를 담고있는 객체이다.
  4. ViewResolver : View관련 정보를 갖고 실제 View를 찾아주는 역할을 한다.
  5. View : Controller가 처리한 결과값을 보여줄 View를 생성한다.

 

 

6. 제어의 역행(Ioc: Inversion of control)

  • 어떠한 일을  하도록 만들어진 프레임워크에 제어의 권한을 넘김으로써 클라이언트 코드가 신경 써야 할 것을 줄이는 전략이다. 이것을 제어가 역전되었다 라고 한다. 

 

7. DI 란?

  • DI는 Dependency Injection(의존성 주입)의 약자로, 객체들 간의 의존성을 줄이기 위해 사용되는 Spring의 IOC 컨테이너의 구체적인 구현 방식.
  • 프레임워크에 정의 되어 있는 인터페이스 interface, 추상 타입 abstract을 나의 코드에서 구현, 상속한 후 프레임워크에 넘겨주는 것이다. 프레임워크는 인터페이스와 추상을 알고 있으므로  내가 하고자 하는 일련의 작업을 처리할 수 있다. 이는 객체를 프레임워크에 주입하는 것이고, 이를 의존을 주입 dependency injection 한다고 한다. 

 

8. AOP란?

  • Spring의 핵심 개념중 하나인 DI가 애플리케이션 모듈들 간의 결합도를 낮춰준다면, AOP는 애플리케이션 전체에 걸쳐 사용되는 기능을 재사용하도록 지원하는 것이다.

AOP (Aspect-Oriented Programming) 란 단어를 번역하면 관점(관심) 지향 프로그래밍으로 된다.
이 관점(관심)이란 단어가 잘 와 닿지 않아 AOP를 이해하는 데 있어 더 어려움이 있을 거라 생각한다.
쉽게 얘기하면 프로젝트 구조를 바라 보는 관점을 바꿔보자는 이야기이다.

우리가 일반적으로 보는 관점은 핵심기능 관점이다.

각각의 Service는 핵심기능에서 바라보았을 때는 Board, User, oo 등 공통된 요소가 없다.
이런 관점에서는 각각의 Service는 각자 코드를 구현하고 있습니다. 하지만, 이 관점을 돌려서 부가기능 이란 관점에서 바라보면 상황이 달라집니다.

부가기능의 관점에서 바라보면 각각의 Service는 수행 시간 측정을 나타내는 before라는 메소드와 after라는 메소드가 공통되는 것을 알 수 있다.

기존에 OOP에서 바라보던 관점을 다르게 하여 부가기능적인 측면에서 보았을 때 공통된 요소를 추출하자는 것이다.
이때 가로(횡단) 영역의 공통된 부분을 잘라냈다고 하여, AOP를 크로스 컷팅(Cross-Cutting)이라고 불리기도 한다.
요약하자면 아래와 같다.

  • OOP : 비즈니스 로직의 모듈화
    • 모듈화의 핵심 단위는 비지니스 로직
  • AOP : 인프라 혹은 부가기능의 모듈화
    • 대표적 예 : 로깅, 트랜잭션, 보안 등
    • 각각의 모듈들의 주목적 외에 필요한 부가적인 기능들

AOP라고 해서 전에 없던 새로운 개념이 등장한 것이 아니다. 결국은 공통된 기능을 재사용하는 기법이다.
OOP에선 공통된 기능을 재사용하는 방법으로 상속이나 위임을 사용한다.
하지만 전체 어플리케이션에서 여기저기에서 사용되는 부가기능들을 상속이나 위임으로 처리하기에는 깔끔하게 모듈화가 어렵다.

그래서 이 문제를 해결하기 위해 AOP가 등장하게 된다.
AOP의 장점은 2가지이다.

  • 어플리케이션 전체에 흩어진 공통 기능이 하나의 장소에서 관리된다는 점
  • 다른 서비스 모듈들이 본인의 목적에만 충실하고 그 외 사항들은 신경 쓰지 않아도 된다는 점

 

9. Service Logic / Business Logic

MVC 패턴에서 비즈니스 로직을 사용하는 구조의 예

//서비스 로직

public class GuguService {

  public String getGuguStr(String input) {

       if( isInputNum(input) ) {

	int num = Integer.valueOf(input);

	Gugudan g = new Gugudan();

	String result = g.createGugu( num );
	return result;
       }
       return null;
   }

  private boolean isInputNum(String input) { }

}
//비즈니스 로직

public class Gugudan {

 public String createGugu(int num) { }

}

위에서 표와 코드를 보면 Service 로직과 Business 로직으로 나뉘는데

Service Logic
정보의 1차적인 처리, 데이터 유효성 검사, 예외처리, 트랜잭션 처리 등 여러 장소에서 공통적으로 요구되는 로직
뒤에 이어지는 Business Logic에 전달하기 위한 데이터를 가공하는 부분
한 개의 클래스에 많은 메소드가 포함되고 각각의 메소드는 서로 직접적인 연관성이 없는 것이 일반적이다
정보처리를 위한 범용 로직
정보를 1차적으로 검사 및 가공하여 뒤에 이어지는 Business Logic를 호출한다
예) BoardService, MemberSerice, CartService



Business Logic
정보의 최종 처리, 핵심적인 로직
한 개의 비즈니스 로직은 한개의 클래스에 정의되는 것이 보통이므로 클래스의 규모가 작은 것이 보통이다
데이터베이스 접속이 필요하면 Data Access Layer를 호출한다



10. VO vs DTO

  • VO : 사용 되는 값이 객체로 표현되며,값 변경이 없는 경우를 말한다.
  • DTO : 데이터의 전송을 위한 객체이며, 비지니스 로직까지 담아서 사용하기 한다.

 

11. Spring  Annotation이란?

  • @를 이용한 주석, 자바 코드에 주석을 달아 특별한 의미를 부여한 것이다.
  • 컴파일러가 특정 오류를 억제하도록 지시하는 것과 같이 프로그램 코드의 일부가 아닌 프로그램에 관한 데이터를 제공, 코드에 정보를 추가하는 정형화된 방법이다.

 

12. Annotation의 용도

  • @Override 어노테이션처럼 컴파일러를 위한 정보를 제공하기 위한 용도이다.
  • 스프링 프레임워크의 @Controller 어노테이션처럼 런타임에 리플렉션을 이용해서 특수 기능을 추가하기 위한 용도
  • 컴파일 과정에 어노테이션 정보로부터 코드를 생성하기 위한 용도

▼리플렉션이란? 클릭!!

더보기

# 자바 리플렉션
다른 언어에는 존재하지 않는 특별한 기능, 컴파일 시간이 아닌 실행시간에 동적으로 특정 클래스의 정보를 객체를 통해 분석 및 추출해내는 프로그래밍 기법




13. Annotation의 종류

@Bean vs @Component

둘 다 목적이 명확하지 않은 Bean을 생성할 때 사용하는 어노테이션이다.
그런데 왜 2개로 나누어져 있나 궁금증이 든다. 차이점을 알아보자.

@Bean
public ObjectMapper objectMapper(){ return new ObjectMapper(); }

@Bean
public RestTemplate restTemplate(){ return new RestTemplate(); }

@Bean
public ServletRegistrationBean servletRegistrationBean(){ 
	ServletRegistrationBean registrationBean = new ServletRegistrationBean( new WebServlet());
	registrationBean.addUrlMappings("/console/*");
	return registrationBean;	
 }

(@Bean)

 

@Component
public class TemplateEngine{}

(@Component)

위 코드를 보면 알 수 있는데 @Bean의 경우 개발자가 컨트롤이 불가능한 외부 라이브러리들을 Bean으로 등록하고 싶은 경우에 사용된다. 

(예를 들면 ObjectMapper의 경우 ObjectMapper Class에 @Component를 선언할 수는 없으니 ObjectMapper의 인스턴스를 생성하는 메서드를 만들고 해당 메서드에 @Bean을 선언하여 Bean으로 등록한다.)

반대로 개발자가 직접 컨트롤이 가능한 Class들의 경우엔 @Component를 사용한다.

그럼 개발자가 생성한 Class에 @Bean은 선언이 가능할까? 아뇨!! 불가능하다..!!

@Bean과 @Component는 각자 선언할 수 있는 타입이 정해져 있어 해당 용도 외에는 컴파일 에러를 발생시킨다.

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RYNTIME)
@Documented
 public @interface Bean{
	String[] name() default {};

	Autowire autowire() default Autowire.NO;

}

(@Target이 METHOD로 지정되어 있지만, TYPE은 없다)

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RYNTIME)
@Documented
 public @interface Component{
	String value() default "";

}

(@Target이 TYPE로 지정되어 Class위에서만 선언될 수 있음을 알 수 있다.)



@Controller vs @WebServlet

javax.servlet.annotation

@Target(value=TYPE)
@Retention(value=RUNTIME)
@Documented
public @interface WebServlet

(@WebServlet)

  • 서블릿을 선언할 때 사용되는 Annotation
  • 이 Annotation이 표시된 클래스는 Servlet Container에 의해 처리된다.
  • 속성 값을 통해 해당 Servlet과 매핑될 URL 패턴을 지정한다.



org.springframework.stereotype

@Target(value=TYPE)
@Retention(value=RUNTIME)
@Documented
@Component
public @interface Controller

(@WebServlet)

  • 이 Annotation이 표시된 클래스는 “Controller” 임을 나타낸다.
  • @Controller는 @Component의 구체화된 역할을 한다.
    classpath scanning을 통해 구현 클래스를 자동으로 감지할 수 있도록 해준다.
  • 일반적으로 RequestMapping 어노테이션을 기반으로 한 handler method와 함께 사용한다

@WebServlet과 @Controller Annotation의 차이
WebServlet과 Spring MVC Controller는 같은 일을 하는 데 사용된다.

@Autowired, @Service, @Repository

위의 어노테이션을 알아보기 전에 MVC의 구조를 다시 한번 살펴보겠다.

파란색 테두리는 주로 jsp, html, ModelAndView 작업이 핵심이다. 데이터를 가지고
Access 하고 원하는 쿼리를 가지고 데이터를 조회하는 작업은 빨간색 테두리에서 이루어진다.
해당 과정에서의 핵심은 얼마나 데이터를 효율적으로 조회할 것인가, 그리고 웹 프로그램
특성 상 멀티유저 경우에서 어떻게 자원을 효율적으로 분배할 것인가이다. 기본적으로 데이터
베이스 부분에서는 Mybatis가 DBCP를 이용해서 싱글톤을 적용해 자원을 효율적으로 사용
하도록 만들어준다. 그럼 위 그림에서 (6) 에 해당하는 과정은 효율성 검증이 마무리
되었다. 이제 문제는 (2),(3) 과정이다. 아래의 그림을 보고 좀 더 자세히 분석해보겠다.

 

우선적으로 웹 서버의 구조에서 각 클라이언트당 스레드의 개념으로 접근하게 된다.
즉, 위의 그림은 3명의 유저가 동시에 서버에 접속을 해서 자원을 사용한다고 하였을 때를 가정한것인데 일반적인 구조에서는 각 스레드 당 객체들이 생성되게 된다. 따라서 스레드의 개수만큼 객체가 생성되게 되고 그 객체의 메모리가 서버의 힙 메모리 공간에 저장되게 된다.

반면 스프링에서 권장하고 있는 사항은 일반적인 구조처럼 각 스레드당 new를 해서 객체를 만드는 것이 아닌 beans 파일 즉 xml에 한번만 정의해놓고 각 스레드가 해당 자원을 공유하면서 결론적으론 서버의 힙 공간에는 초기 셋팅 시 딱 하나만 생성되게 만든다. 스프링 프레임워크는 기본적으로 이러한 구조 즉 SingleTone 패턴을 권장한다.
각 스레드당 객체를 관리하는 것보다 객체를 하나만 보유하고 잇으면서 그걸 공유하는 방법이 효율적이다.
따라서 스프링에서는 이러한 것을 지원하기 위해서 어노테이션으로 @Autowired를 지원한다.

 

# View단 구성(JSP)

테이블 형태로 구성된 뷰를 만들어 보았다.

<div id="friendlist">
		<table border="1">
		<tr>
			<td>구분</td>
			<td>이름</td>
			<td>나이</td>
			<td>주소</td>
			<td>이미지</td>
			<td>제거</td>
		</tr>
		
		<!-- HTML에서 사용하는 배열 forEach  -->
		<c:forEach items="${listuser }" var="user">
			<c:set var="i" value="${i+1 }"/>
				<tr>
					<td><c:out value="${i }"/></td>
					<td><c:out value="${user.userName }"/></td>
					<td><c:out value="${user.userAge }"/></td>
					<td><c:out value="${user.userAddress }"/></td>
					<td><img src="./images/${user.userImage }" width="100" height="100"></td>
					<td><button data-pid="${user.userName }">제거</button></td>
				</tr>
		</c:forEach>
		</table>
	</div>

주로 <table>태그와 JSTL이 사용되었다 
JSTL이란 html에서 일반 프로그램 제어로직을 추가하여 데이터 조작을 가능하게 하는 기술이다.
c:forEach를 이용하여 listuser 로 넘어온 값을 가지고 for문 돌리듯이 수행되어 뷰에 데이터를 보여준다.

JSTL 말고도 EL 표기법을 사용했는데 기존의 JSP에서의 <%= %> 을 ${} 로 표현한 것이다.

위의 jstl과 el태그를 사용하기 위해선 CDN을 추가해주어야 한다. 

<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>    
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>  

 

# Service단 구성(@Service)

이제 서비스 영역을 구성해 보겠다.

dao,service 는 인터페이스와 클래스 파일이 한 세트로 구성된다.
따라서 먼저 필요한 서비스들의 목록을 나열할 수 있는 인터페이스를 만든다.

1. UserListService.java

public interface UserListService {
	public List<UserListResponseDTO> getUserListService();
}

인터페이스는 내부에 메소드 본체를 가질 수 없다. 필요한 메소드 헤더만 정의하고 이를
구현하는 클래스에서 본체를 구현할 수 있다. 이러한 인터페이스로 구성 시 장점은 확장성과 유연성이 좋아진다.
하나의 소켓같은 개념이라 다른 서비스로 쉽게 교체하거나 유지보수가 쉬워진다. 
이제 이러한 인터페이스를 구현할 클래스를 만들어 보자.

2. UserListServiceimpl

@Service("userListService")
public class UserListServiceimpl implements UserListService {
	@Autowired
	UserListDAOImpl userListDAO;
	
	@Override
	public List<UserListResponseDTO> getUserListService(){
		System.out.println("service call");
		
		return userListDAO.getUserListdao();
	}
	
}

클래스 이름에 대한 특별한 규칙은 없지만 대부분 '구현했다' 라는 의미로 impl이라고 많이 명명한다.
implements로 기존에 만들어 두었던 인터페이스를 구현한다. 오버라이드를 이용해서 메소드 본체를
작성한다. 해당 클래스가 Service라는 것을 알리기 위해서 어노테이션으로 @Service라 해준다.
우리가 구현할 로직은 서비스에서 해당 서비스에 맞는 데이터를 불러오기 위해 DAO를 호출하는 것이다.
따라서 리턴으로 DAO에서 불러온 LIST값을 반환한다.
아마 수 많은 에러가 나올것이다. DAO,DTO 클래스를 만들어 주지 않았기 때문이다.

3. UserListResponseDTO.java

public class UserListResponseDTO implements Serializable {
	private String userName;
	private String userAge;
	private String userAddress;
	private String userImage;
	
	public UserListResponseDTO() {}
	
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getUserAge() {
		return userAge;
	}
	public void setUserAge(String userAge) {
		this.userAge = userAge;
	}
	public String getUserAddress() {
		return userAddress;
	}
	public void setUserAddress(String userAddress) {
		this.userAddress = userAddress;
	}
	public String getUserImage() {
		return userImage;
	}
	public void setUserImage(String userImage) {
		this.userImage = userImage;
	}
	@Override
	public String toString() {
		return "UserListResponseDTO [userName=" + userName + ", userAge=" + userAge + ", userAddress=" + userAddress
				+ ", userImage=" + userImage + "]";
	}

위의 DTO는 해당 서비스에서 필요한 구조이다. 즉, 데이터를 주고받을 포맷인것이다.
실제 jsp단에서 EL 표기법으로 해당 변수명과 동일하게 호출하고 있다. DTO또한 명명 규칙이 정해져있지는 않지만
편의상 Request, Response 를 붙여주는 것이 직관적이다. 

그리고 Serializable로 설정해주는 것이 좋은데 이유는 데이터 전송 시 조각단위로 보내는 것이 아닌 하나의 객체로 보낼 수 있게 해주므로 더 효율적이게 된다.

4. Service단을 beans에 등록

beans 파일을 스프링 환경에서 중요한 설정파일이라고 한다. servlet-context.xml에 등록하자.

	<!-- service 등록 -->
	<beans:bean id="userListService" class="kr.co.blogtest.service.UserListServiceimpl"/>

xml파일로 설정 시 초기화 시 한번만 로드되고 계속 공유할 수 있게된다. 반드시 service와 dao는 
beans에 등록을 해주어야지 싱글톤과 @Autowired가 가능하게 된다. 올바르게 class가 적용되었는지 확인할려면 ctrl
키를 누르고 class에다가 가져다 놓으며 해당 파일로 이동할 수 있다. 만약 링크기능이 없다면 잘못 작성된 것으로 경로를 점검해  본다.

 

5. 컨트롤러단에서 서비스 호출

컨트롤러단에서 서비스를 호출하기 위해서 우선 서비스 정보를 가지고 있는 클래스를 선언한다. 
클래스는 impl파일들을 의미하게 되고 new로 객체생성없이 하기 위해서 @Autowire를 써준다.
Autowired같이 자동적으로 객체를 만들어 주고 사용할 수 있게 해주는 것을 스프링에서는 의존성 주입
(Injection)이라고 한다.

@Controller
public class MainController {
	@Autowired
	UserListServiceimpl userListService;
	
	@RequestMapping(value="/",method=RequestMethod.GET)
	public ModelAndView home(ModelAndView mav) {
		//Service call
		List<UserListResponseDTO> userlist = userListService.getUserListService();
		
		for(int i=0; i<userlist.size();i++) {
			System.out.println("name: "+userlist.get(i).getUserName());
		}
		
		mav.addObject("listuser", userlist);
		mav.setViewName("view");
		return mav;
	}
}

UserListServiceimpl을 자동 와이어링 하면 위와 같이 객체 생성없이 getUserListService()를
호출할 수 있다. 현재는 뷰에도 아무런 데이터가 나오지 않고 for문 출력 또한 null 값이 나오게 된다.
이제 데이터가 나올 수 있도록 DAO를 구성해보겠다.

 

# DAO단 구성(@Repository)

먼저구조는 위의 서비스단과 동일하게 인터페이스와 클래스 쌍으로 구성되어있다

DAO와 Service는 구현 상 큰 차이는 없지만 DAO에는 추후 연동할 데이터베이스에 세션
및 Mybatis 코드가 적용된다는 점이 차이가 있다.

1. UserListDAO.java

public interface UserListDAO {
	public List<UserListResponseDTO> getUserListdao();
}

서비스단과 마찬가지로 필요한 메소드들은 헤더만 정의한다.

2. UserListDAOimpl.java

@Repository("userListDAO")
public class UserListDAOimpl implements UserListDAO {
	
	@Override
	public List<UserListResponseDTO> getUserListdao(){
		System.out.println("dao call");
		
		//리스트를 만든다
		List<UserListResponseDTO> userlist =new ArrayList<UserListResponseDTO>();
		
		//총 3명의 학생을 만든다
		UserListResponseDTO list= new UserListResponseDTO();
		list.setUserName("홍길동");
		list.setUserAge("26");
		list.setUserAddress("경기도 수원시");
		list.setUserImage("peopleimage.png");
		
		userlist.add(list);
		
		UserListResponseDTO list2= new UserListResponseDTO();
		list2.setUserName("임꺽정");
		list2.setUserAge("30");
		list2.setUserAddress("경기도 안양시");
		list2.setUserImage("peopleimage.png");
		
		userlist.add(list2);
		
		UserListResponseDTO list3= new UserListResponseDTO();
		list3.setUserName("김철수");
		list3.setUserAge("28");
		list3.setUserAddress("경기도 오산시");
		list3.setUserImage("peopleimage.png");
		
		userlist.add(list3);
	return userlist;
	}
}

우선 해당 클래스가 DAO라는 것을 알리기 위해서 @Repository라고 적어준다.
implements로 인터페이스를 구현해주고 필요한 메소드를 오버라이드 하여 정의한다.
지금은 데이터베이스가 없어 하나씩 List를 만들어서 직접 대입하였다.
해당 리스트를 반환함으로서 다시 서비스를 거쳐 컨트롤러까지 데이터가 전달되게 된다.

3. DAO단을 beans에 등록

서비스단과 마찬가지로 servlet-context.xml에 등록을 해준다.

<!-- DAO 등록 -->
<beans:bean id="userListDAO" class="kr.co.blogtest.dao.UserListDAOimpl"/>

이제 DAO단도 Service단에서 Autowired를 할 수 있다.

4. Service단에서 DAO호출

@Service("userListService")
public class UserListServiceimpl implements UserListService {
	@Autowired
	UserListDAOimpl userListDAO;
	
	@Override
	public List<UserListResponseDTO> getUserListService(){
		System.out.println("service call");
		
		return userListDAO.getUserListdao();
	}
	
}

객체 생성 없이 getUserListdao()를 이용할 수 있다.

이제 서비스단과 DAO단을 모두 구성하였다. 출력을 하면 콘솔에서는 아래와 같이 정상적으로 서비스와
DAO, 그리고 데이터가 올바르게 출력되는걸 볼 수 있다.

이제 이러한 리스트 데이터를 뷰단에 출력을 한 결과는 아래와 같다.

 

@RequestMapping

@Controller
@RequestMapping("/home") // 1) Class Level
public class HomeController {
    /* an HTTP GET for /home */ 
    @RequestMapping(method = RequestMethod.GET) // 2) Handler Level
    public String getAllEmployees(Model model) {
        ...
    }
    /* an HTTP POST for /home/employees */ 
    @RequestMapping(value = "/employees", method = RequestMethod.POST) 
    public String addEmployee(Employee employee) {
        ...
    }
}
  • @RequestMapping에 대한 모든 매핑 정보는 Spring에서 제공하는 HandlerMapping Class가 가지고 있다.
  • 1) Class Level Mapping
    모든 메서드에 적용되는 경우
    “/home”로 들어오는 모든 요청에 대한 처리를 해당 클래스에서 한다는 것을 의미한다.
  • 2) Handler Level Mapping
    요청 url에 대해 해당 메서드에서 처리해야 되는 경우
    “/home/employees” POST 요청에 대한 처리를 addEmployee()에서 한다는 것을 의미한다.
  • value: 해당 url로 요청이 들어오면 이 메서드가 수행된다.
  • method: 요청 method를 명시한다. 없으면 모든 http method 형식에 대해 수행된다.

@RestController

  • @Controller + @ResponseBody
  • @ResponseBody를 모든 메소드에서 적용한다.
    메소드의 반환 결과(문자열)를 JSON 형태로 반환한다.
  • @Controller 와 @RestController 의 차이
    -@Controller
    API와 view를 동시에 사용하는 경우에 사용
    대신 API 서비스로 사용하는 경우는 @ResponseBody를 사용하여 객체를 반환한다.
    view(화면) return이 주목적

    -@RestController
    view가 필요없는 API만 지원하는 서비스에서 사용 (Spring 4.0.1부터 제공)
    @RequestMapping 메서드가 기본적으로 @ResponseBody 의미를 가정한다.
    data(json, xml 등) return이 주목적
    즉, @RestController = @Controller + @ResponseBody

@Required

  • etter method에 사용한다.
  • 영향을 받는 bean property 구성 시 XML 설정 파일에 반드시 property를 채워야 한다. (엄격한 체크)
    그렇지 않으면 BeanInitializationException 예외를 발생
  • 예시
<!-- Definition for student bean -->
<bean id = "student" class = "com.tutorialspoint.Student">
    <property name = "name" value = "Zara" />
    <property name = "age"  value = "11"/>
</bean>

 

@Autowired

  • org.springframework.beans.factory.annotation.Autowired
  • Type에 따라 알아서 Bean을 주입한다.
  • 필드, 생성자, 입력 파라미터가 여러 개인 메소드(@Qualifier는 메소드의 파라미터)에 적용 가능
  • Type을 먼저 확인한 후 못 찾으면 Name에 따라 주입한다.
    Name으로 강제하는 방법: @Qualifier을 같이 명시
  • 예시

  • TIP) Bean을 주입받는 방식 (3가지)
    @Autowired
    setter
    생성자 (@AllArgsConstructor 사용) -> 권장방식

@Qualifier

  • 같은 타입의 빈이 두 개 이상이 존재하는 경우에 스프링이 어떤 빈을 주입해야 할지 알 수 없어서 스프링 컨테이너를 초기화하는 과정에서 예외를 발생시킨다.
  • 이 경우 @Qualifier을 @Autowired와 함께 사용하여 정확히 어떤 bean을 사용할지 지정하여 특정 의존 객체를 주입할 수 있도록 한다.
  • 예시

  • xml 설정에서 bean의 한정자 값(qualifier value)을 설정한다.
    @Autowired 어노테이션이 적용된 주입 대상에 @Qualifier 어노테이션을 설정한다.

@Resource

  • javax.annotation.Resource
  • 표준 자바(JSR-250 표준) Annotation으로, Spring Framework 2.5.* 부터 지원 가능한 Annotation이다.
  • Annotation 사용으로 인해 특정 Framework에 종속적인 어플리케이션을 구성하지 않기 위해서는 @Resource를 사용할 것을 권장한다.
    @Resource를 사용하기 위해서는 class path 내에 jsr250-api.jar 파일을 추가해야 한다.
  • 필드, 입력 파라미터가 한 개인 bean property setter method에 적용 가능

[Data Validation]

@Vaild

  • import javax.validation.Valid;
  • @Size(max=10, min=2, message=”errMsg”)
  • @Email(message=”errMsg”)
  • @NotEmpty(message=”errMsg”)

 

[Configuration]

@EnableWebSecurity
@SpringBootApplication
@EnableWebMvc
@RestControllerAdvice
@ExceptionHandler
@ResponseStatus

[Parameter를 받는 방법]

@RequestParam

  • HTTP GET 요청에 대해 매칭되는 request parameter 값이 자동으로 들어간다.
    url 뒤에 붙는 parameter 값을 가져올 때 사용한다.
    Ex) ` http://localhost:8080/home?index=1&page=2`
@GetMapping("/home")
public String show(@RequestParam("page") int pageNum {
}
  • 위의 경우 GET /home?index=1&page=2와 같이 uri가 전달될 때 page parameter를 받아온다.
  • @RequestParam 어노테이션의 괄호 안의 문자열이 전달 인자 이름(실제 값을 표시)이다.
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.