컨트롤러 및 핸들러 매핑 관련 애노테이션

 

@RequestParam

 - Controller 메소드의 파라미터와 웹 요청 파라미터를 매핑하기 위한 애노테이션이다.

 - @RequestParam이 붙은 메소드의 인수는 필수 요청 파라미터이다.

 요청 파라미터에 @RequestParam으로 설정한 파라미터가 존재하지 않으면 400에러가 발생한다.

 required 옵션 속성값을 false로 설정하면 해당 이름의 요청 파라미터가 존재하지 않은 경우, 메소드의 인수는 null을 갖는다. 

- defaultValue 속성에 기본값을 설정하면 해당 이름의 요청 파라미터가 존재하지 않은 경우, 메소드의 인수는 defaultValue속성에서 설정한 기본값을 갖는다. 

 

@ModelAttribute

1) 개요

 - Controller 메소드의 파라미터나 리턴 값을 Model 객체와 바인딩 하기 위한 애노테이션

 - @ModelAttribute는 실제적으로 ModelMap.addAttribute(이름, 값)와 같은 기능을 한다.

 - 사용 방법

 (1)요청 메소드의 매개변수에 사용

  요청 파라미터는 @ModelAttribute가 적용된 메소드의 파라미터(모델 객체)에 매핑되어 넘어온다.

 @ModelAttribute가 적용된 메소드의 파라미터는 포워딩 되는 View 페이지에서 사용 가능하다.

 (2)메소드 레벨(method level)로 사용

 View에서 사용할 데이터를 설정하는 용도로 사용

 @ModelAttribute가 설정된 메소드는 @RequestMapping이 적용된 메소드보다 먼저 호출

 @ModelAttribute 메소드 실행 결과로 리턴되는 객체는 자동으로 Model에 저장

 @ModelAttribute 메소드 실행 결과로 리턴된 객체를 View 페이지에서 사용 가능

 

2) 옵션

 - value : 바인드 하려는 Model 속성 이름 String

 

@RequestHeader

- HTTP 요청 헤더 값을 컨트롤러 메소드의 매개변수로 전달한다.

- @RequestHeader 로 설정한 헤더는 기본적으로 필수 헤더로 존재하지 않으면 400에러가 발생한다.

- required 속성을 이용해 필수여부를 설정할 수 있다.

- dafaultValue 속성을 이용해 헤더가 존재하지 않은 경우 기본 값으로 설정 가능하다.

 

@CookieValue

- HTTP 쿠키 값을 HttpServletRequest등을 통해 읽을 필요없이 컨트롤러 메소드의 인수로 전달 받을 수 있다.

- @CookieValue로 설정한 쿠키는 필수로 해당 쿠키가 존재하지 않으면 400 에러가 발생한다.

- required 속성을 이용해 필수여부를 설정할 수 있다.

- defaultValue 속성을 이용해 쿠키가 존재하지 않은 경우 기본 값으로 설정 가능하다.

 

@SessionAttributes

- Model 객체를 세션에 저장하고 사용하기 위한 애노테이션

- 클래스 레벨(type level)에서 선언할 수 있다.

- 지속적으로 사용자의 입력 값을 유지시키거나 여러 단계에 걸쳐 submit 되면서 완성되는 폼을 구성하는 경우에 사용 가능하다.

- 사용방법

 @SessionAttributes 는 컨트롤러에서 사용되며 애노테이션에서 설정한 모델객체를 세션에 저장하는 역할을 한다. 이후부터 해당 모델객체가 사용되면 세션에서 불러와서 사용하며, 뷰에서 이름으로 접근이 가능하다.

 @SessionAttribues를 컨트롤러 클래스에 붙이고 모델 이름을 인자로 넣어준다. 컨트롤러의 메소드가 만드는 모델 정보 중에 이름이 같은 것이 있으면 세션에도 저장하고 컨트롤러 메소드의 @ModelAttrbute 인자를 HTTP요청이 아니라 먼저 세션에서 검색하여 사용한다.

 @SessionAttributes로 세션에서 사용완료된 객체는 사용 후에 SessionStatus.setComplete() 메소드로 세션에 저장한 정보를 제거해야 한다.

 

@PathVariable

1) 개요

- @PathVariable은 메소드 매개 변수가 URI 템플릿 변수에 바인딩되어야 함을 나타내는 애노테이션이다. 요청 URI 매핑의 템플릿 변수를 처리하고 이를 메소드 매개 변수로 사용할 수 있다.

- @RequestMapping 애노테이션이 있는 핸들러 메소드에 지원된다.

- 메소드 매개 변수가 Map<String, String>이면 Map이 모든 경로 변수 이름 및 값으로 채워진다.

 

2) 옵션

- name : 바인드 할 경로 변수 이름으로 스프링 4.3.3부터 사용 가능 String

- required : 필수 여부 설정으로 기본값은 true이며 스프링 4.3.3부터 사용가능. boolean

- value : name의 별칭 String

 

3) REST(Representational State Transfer)

 (1) 개요

 - 자원을 이름(자원의 표현)으로 구분하여 해당 자원의 상태(정보)를 주고 받는 모든 것을 의미

 - 월드 와이드 웹(www)과 같은 분산 하이퍼 미디어 시스템을 위한 소프트웨어 개발 아키텍처의 한 형식. REST는 기본적으로 웹의 기존 기술과 HTTP 프로토콜을 그대로 활용하기 때문에 웹의 장점을 최대한 활용할 수 있는 아키텍처 스타일로 네트워크 상에서 Client와  Server 사이의 통신 방식 중 하나

 - HTTP URI(Uniform Resource Identifier)를 통해 자원(Resource)을 명시하고, HTTP Method(POST, GET, PUT, DELETE)를 통해 해당 자원에 대한 CRUD Operation을 적용하는 것을 의미

 - REST는 자원 기반의 구조(ROA, Resource Oriented Architecture) 설계의 중심에 Resource가 있고 HTTP Method를 통해 Resource를 처리하도록 설계된 아키텍쳐를 의미

 - 웹사이트의 이미지, 텍스트, DB 내용 등의 모든 자원에 고유한 ID 인 HTTP URI를 부여

 - CRUD Operation : Create : 생성 (POST) READ : 조회 (GET) Update : 수정 (PUT) Delete : 삭제(Delete) HEAD : header 정보 조회(HEAD)

 

 (2) REST API

 - API(Application Programming Interface) 데이터와 기능의 집합을 제공하여 컴퓨터 프로그램간 상호작용을 촉진하며, 서로 정보를 교환가능 하도록 하는 것

 - REST API의 정의

 REST 기반으로 서비스 API를 구현한 것

 OpenAPI, 마이크로 서비스(하나의 큰 애플리케이션을 여러 개의 작은 애플리케이션으로 쪼개어 변경과 조합이 가능하도록 만든 아키텍처) 등을 제공하는 업체 대부분은 REST API를 제공한다.

 - REST API 설계 기본 규칙

 -- URI는 정보의 자원을 표현해야 한다.

 -- 자원에 대한 행위는 HTTP Method(GET, PUT, POST, DELETE 등)로 표현한다.

 --- URI에 HTTP Method가 들어가면 안된다.

 --- URI에 행위에 대한 동사 표현이 들어가면 안된다. (CRUD 기능을 나타내는 것은 URI에 사용하지 않는다.)

 

(3) RESTful 서비스

- RESTful은 일반적으로 REST라는 아키텍처를 구현하는 웹 서비스를 나타내기 위해 사용되는 용어이다. "REST API"를 제공하는 웹 서비스를 "RESTful"하다고 할 수 있다.

- RESTful 서비스는 URI를 사용하여 리소스 이름을 지정한다.

- Spring은 @RequestMapping을 사용하여 요청에 대한 URI 템플릿을 정의하여 RESTful 서비스를 한다. @PathVariable은 템플릿 변수의 값을 추출하고 해당 값을 메소드 매개변수에 할당하는 데 사용한다.

MVC 웹 애플리케이션

컨트롤러 및 핸들러 맵핑

@Controller

- Controller의 역할을 수행한다고 명시.

- Controller는 필요한 비즈니스 로직을 호출하여 처리 결과(Model)와 처리 결과를 출력할 View 정보를 DispatcherServlet에 반환한다.

- Bean으로 등록된다.

- @Component의 구체화된 애노테이션으로 클래스에 붙인다.

- 빈 이름을 지정하지 않으면 클래스 이름의 첫 문자를 소문자로 바꾼 것이 빈의 이름(id)으로 빈을 등록한다.

- 형식 @Controller, @Controller("beanName")

 

@RequestMapping

- 요청에 대해 어떤 Controller, 어떤 메소드가 처리할지를 매핑하기 위한 애노테이션

 url을 class또는 method와 mapping 시켜주는 역할을 한다.

- 선언위치 : 클래스 또는 메소드

 1) class level(type level) 매핑 : 컨트롤러의 모든 메소드에서 처리하는 경우

 2) method level 매핑 : 요펑 url에 대한 해당 메소드에서 처리하는 경우

- GET, POST, PUT, DELETE 등으로 표현되는 모든 HTTP Request method 를 매핑 할 수 있다.

- @RequestMapping 시 따로 HTTP Method를 설정하지 않으면 모든 Method를 허용한다.

- @RequestMapping 애노테이션은 Ant 스타일의 패턴을 지원한다.

 1) ? : 1개의 문자와 매칭

 2) * : 0개 이상의 문자와 매칭

 3) ** : 0개 이상의 디렉터리와 매칭

 4) {spring:[a-z]+} : "spring"이라는 path variable로 정규문법 [a-z]+와 일치

- 상위 클래스에 @RequestMapping이 정의되어 있고 하위 클래스에서는 @RequestMapping을 재정의하지 않은 경우 @RequestMapping는 그대로 상속된다

- 상위 클래스의 클래스에 정의된 @RequestMapping과 하위 클래스의 메소드에 정의된 @RequestMapping의 조합이 가능하다.

- 스프링 4.3부터는 5가지 애노테이션을 추가하여 HTTP 요청 메소드별로 세분화 하였다.

 추가된 HTTP 요청 메소드별 매핑 애노테이션

@GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping

@GetMapping("/hello") 은 @RequestMapping(value="/hello", method=RequestMethod.GET)의 축약형이다.

@PostMaoong("/hello") 은@RequestMapping(value="/hello", method=RequestMethod.POST)의 축약형이다.

 

컨트롤러 메소드의 리턴 타입

1) ModelAndView 객체

- 처리결과를 담은 Model 객체와 View정보를 ModelAndView객체에 담아 반환

- ModelAndView 클래스는 컨트롤러의 처리 결과를 보여줄 뷰와 뷰에 전달할 값을 저장하는 용도로 사용

 

2) String

 - 뷰의 이름을 반환한다.

 

3) Model, ModelMap

 - 처리 결과를 Model 객체에 담아 반환한다.

- Model은 인터페이스이며, ModelMap은 클래스로 사용방법은 유사하다.

- ModelMap 하위 클래스인 ExtendedModelMap은 Model구현 클래스이다.

- 뷰의 이름은 RequestToViewNameTranslator를 통해매핑된 URL로 결정된다.

 URL 이 "/hello/main"인 경우 뷰의 잉름은 "hello/main"이 된다.

- Model 객체 생성 예

 Model model = ExtendedModelMap();

 

4) void

- 메소드의 인수로 HttpServletResponse파라미터가 존재하지 않는 경우 뷰의 이름은 RequestToViewNameTranslator를 통해 매핑된 URL로 결정된다. URL이 "/hello/main"인 경우 뷰의 이름은 "hello/main"이 된다.

- HttpServletResponse등을 사용해서 직접 응답을 처리하는 경우 사용할 수 있다.

 

5) Map

- 처리 결과를 Map 객체에 담아 반환한다.

- 뷰의 이름은 RequestToViewNameTranslator를 통해 매핑된 URL로 결정된다. URL이 "/hello/main"인 경우 뷰의 이름은 "hello/main"이 된다.

 

6) View

- View 객체를 직접 반환. 해당 View객체를 이용하여 뷰를 생성

- AbstractView 클래스 등을 상속받은 커스텀 뷰를 반환할 수 있다.

- 파일 다운로드, PDF 나Excel로 변환하여 다운로드를 구현할 경우에 사용할 수 있다.

 

포워딩과 리다이렉트

 

1) 포워딩(forwarding)

- "forward:"로 시작하는 View이름을 설정하며, forward는 디폴트로 생략 가능하다.

- 컨트롤러 메소드의 리턴 타입이 String인 경우 "bbs/list" 뷰 이름으로 포워딩

return "bbs/list";

- 컨트롤러 메소드의 리턴 타입이 ModelAndView인 경우 "bbs/list" 뷰 이름으로 포워딩

return new ModelAndView("bbs/list");

 

2) 리다이렉트(Redirect)

- RedirectView

 HttpServletResponse의 sendRedirect(location)를 호출해주는 기능을 가진 뷰

 실제 뷰가 생성되는 것이 아니라 URL만 만들어져 다른 페이지로 리다이렉트 된다.

 모델 정보가 있다면 URL 뒤에 파라미터로 추가된다.

- 리다이렉트 방법

 redirect: 로 시작하는 View이름을 설정

1) 컨트롤러 메소드의 리턴 타입이 String인 경우 "/main"으로 리다이렉트

return "redirect:/main";

2) 컨트롤러 메소드의 리턴 타입이 ModelAndView인 경우 "/main"으로 리다이렉트

return new ModelAndView("rediect:/main");

 

RedirectView 오브젝트를 직접 만들어 반환

return new ModelAndView(new RedirectView("/main") );

 

컨트롤러 핸들러 메소드의 매개변수

1) Servlet API

- HttpServletRequest, HttpServletResponse, HttpSession

 

2) java.util.Locale

- DispatcherServlet의 지역정보 리졸버(Locale Resolver)가 결정한 Locale객체

 

3) java.io.InputStream / java.io.Reader

- request(요쳥 정보) body 영역을 직접 읽어 들이기 위한 InputStream 또는 Reader 객체

 

4) java.io.OutputStream / java.io.Writer

- response 정보를 직접 보내기 위한 OutputStream 또는 Writer 객체

 

5) Map, Model, ModelMap

- 뷰에 전달할 모델 데이터 설정

 

6) 커맨트 객체

- HTTP 요청 파라미터를 저장할 객체

 

7) RedirectAttrivutes

- 리다이렉트 되는 페이지에 데이터를 전달한다.

- 주요 메소드

 (1) addAttribute(String attributeName, Object attributeValue)

 - 리다이렉트 되는 URL에 쿼리 스트링으로 데이터를 전달해준다.

 - 쿼리 스트링으로 전달되므로 String으로 변환이 가능한 원시타입만 가능하다.

 - F5를 눌러 새로고침을 해도 값이 유지된다.

 

 (2) addFlashAttribute(String attributeName, Object attributeValue)

 - 리다이렉트 되는 페이지에 데이터를 전달하며, 주소 뒤에 표시되지 않는다.

 - 세션을 이용하여 값을 전달 후에 삭제된다. 즉, 일회성으로 F5를 눌러 새로고침을 하면 값이 사라진다.

 

8) SessionStatus

 - @SessionAttributes 애노테이션을 사용하여 session에 저장된 데이터를 정리하는데 활용하는 인터페이스

 - SessionStatus의 setComplete() 메소드를 호출하면 현재 컨트롤러에서 @SessionAttributes에 의해 세션에 저장된 모델 데이터를 모두 삭제한다.

 

9) Errors, BindingResult

 - Errors는 유효성 검증 결과를 저장할 때 사용

 - Errors의 하위 인터페이스로 폼 값을 커맨드 객체에 바인딩한 결과를 저장하고 에러코드로 메세지를 가져온다.

Spring Web MVC 란 ?

- Spring Web MVC는 Servlet API를 기반으로 구축 된 웹 프레임 워크

- Model 2 MVC 패턴을 지원

- Spring Web MVC는 유연하고 느슨하게 결합된 웹 애플리케이션을 개발하는 데 사용할 수 있는 Model-View-Controller아키텍쳐 및 준비된 구성요소를 제공한다.

- MVC 패턴은 애플리케이션의 다양한 측면(입력 로직, 비즈니스 로직 및 UI로직)을 분리하는 동시에 이러한 요소간에 느슨한 결합을 제공한다.

 1) Model은 애플리케이션 데이터를 캡슐화하며 일반적으로 POJO로 구성

 2) View는 모델 데이터를 렌더링하는 역할을 하며 일반적으로 클라이언트의 브라우저가 해석 할 수 있는 HTML output을 생성

 3) Controller는 사용자 요청을 처리하고 적절한 모델을 구축하고 렌더링을 위해 뷰를 전달

- Spring Web MVC는 모든 HTTP 요청 및 응답을 처리하는 DispatcherServlet을 기반으로 설계되었다.

- 스프링 프레임워크 5 버전부터 리액티브 스택 기반으로 웹 애플리케이션을 개발할 때 사용할 수 있는 스프링 Webflux를 제공

 

Spring MVC Architecture

- Model, View, Controller를 분리한 디자인 패턴

- Model

 1) 애플리케이션의 상태(data)를 나타낸다

 2) 일반적으로 POJO로 구성

 3) Java Beans

- View

 1) 디스플레이 데이터 또는 프리젠테이션

 2) Model data의 렌더링을 담당하며, HTML output을 생성

 3) JSP, 타임리프(Thymeleaf), 그루비(Groovy), 프리마커(Freemarket) 등 여러 Template Engine이 있다.

- Controller

 1) View와 Model 사이의 인터페이스 역할

 2) Model, View에 대한 사용자 입력 및 요청을 수신하여 그에 따라 적절한 결과를 Model에 담아 View에 전달.

 즉, Model Object와 이 Model을 화면에 출력할 View Name을 반환

 

String MVC 처리과정

1) DispatcherServlet이 클라이언트의 요청을 받는다.

2) DispatcherServlet은 적절한 컨트롤러를 선택하는 작업을 HandlerMapping에 전달한다. HandlerMapping은 들어오는 요청 URL에 매핑된 컨트롤러를 선택하고, 선택된 Handler 및 Controller를 DispatcherServlet에 반환한다.

3) DispatcherServlet은 Controller의 비즈니스 로직 실행 작업을 HandlerAdapter에 전달한다.

4) GandlerAdapter는 Controller의 비즈니스 로직 프로세스를 호출한다.

5) 컨트롤러는 비즈니스 로직을 실행하고 처리 결과를 Model에 설정하고 뷰의 논리적 이름을 HandlerAdapter에 반환한다.

6) DispatcherServlet은 View 이름에 해당하는 View를 해결하는 작업을 ViewResolver에 전달한다. ViewResolver는 View 이름에 매핑된 View로 전달한다.

8) View는 모델 데이터를 렌더링하고 응답을 반환한다.

 

Spring MVC 주요 컨포넌트

1) DispatcherSerlvet

- Spring Framework가 제공하는 Servlet 클래스

- 사용자의 요청을 받는다.

- DispatcherServlet이 받은 요청은 HandlerMapping으로 넘어간다.

- Front Controller Pattern

 모든 리소서(Resource)요청을 처리해주는 하나의 컨트롤러(Controller)를 두는 패턴

 DispatcherServlet이 Front Controller의 역할을 수행한다.

 

2) HandlerMapping

- 사용자의 요청을 처리한 Controller를 찾는다.

- 요청 uri에 해당하는 Controller 정보를 저장하는 table을 가진다. 클래스에 @RequestMapping("/uri") annotation을 명시하면 해당 URL에 대한 요청이 들어왔을 때 table에 저장된 정보에 따라 해당 클래스 또는 메소드에 Mapping한다.

 

3) Controller

- 요청에 맵팽된 Controller에게 위임됨(@Controller)

- @RequestMapping을 통하여ㅠ 요청을 처리할 메소드를 호출

- 필요한 비즈니스 로직을 처리

- View에 전달할 결과 데이터(Model)와 이동할 화면(View) 정보를 스프링 MVC가 제공하는 ModelAndView 인스턴스에 담아 DispatcherServlet에 반환

- DispatcherServlet는 ViewResolver에게 뷰 논리정보(View Name)를 전달

 

4) ModelAndView

- Controller에서 처리 결과를 View에 전달할 결과 데이터(Model)와 이동할 화면(View)정보를 담는 클래스

- Controller메소드에서 리턴 타입이 String 인 경우에도 핸들러에서 ModelAndView인스턴스에 View정보를 넣는다.

 

5) ViewResolver

- ViewResolver는 View Name을 이용해 알맞는 view객체를 찾는다.

 1) Controller가 반환한 View Name에 prefix와 suffix를 적용하여 View Object를 반환한다.

 2) View Name : 'home', prefix : '/WEB-INF/views/', suffix : '.jsp'인 경우 => '/WEB-INF/views/home.jsp' 라는 위치의 View(JSP)에 Controller에게 받은 Model을 전달한다.

- View에 Model을 redering 하여 View 인스턴스를 다시 DispatcherServlet에 반환한다.

- DispatcherServlet은 최종 결과를 클라이언트에 응답

 

6) View

- 결과 데이터인 Model 객체를 출력한다.

 

Annotation 기반 Bean 설정

 

- Annotation의 사용으로 설정파일을 간결화하고 객체 또는 메소드의 맵핑을 명확하게 할 수 있다.

- Java code로 설정을 하기 때문에 type safe하며, Spring이 빠르게 container를 설정하게 한다.

- Annotation이 클래스 (또는 메소드) 상단에 추가되면서 설정이 구성되기 때문에 클래스 파일만 보아도 어떤 스프링 설정이 적용된 클래스인지 한눈에 알 수 있다.

- 설정이 변경될 경우 Application code 클래스 파일까지 수정해 주어야 한다.

- 애노테이션을 이용한 의존성 주입 Field Injection, Setter Injection, Constructor Injection

 

애노테이션을 이용한 이용한 의존성 주입(Dependency Injection)

1) Field Injection

- 필드를 통한 의존성 주입

- 사용 예

public class Sample {
	@Autowired
    private Example example;
}

 

2) Setter Injection(수정한 주입)

- setter 메소드를 통한 의존성 주입

- 사용 예

public class Sample {
	private Example example;
    @Autowired
    public void setExample(Example example) {
    this.example = example;
    }
}

 

3) Constructor Injection(생성자 주입)

- 생성자를 통한 의존성 주입

- 권장 방식

- 사용 예

public class Sample {
	private Example example;
    @Autowired
    public Sample(Example example) {
    	this.example = example;
    }
}

 

<context:annotation-config/>

- 애노테이션(Annotation)은 기본적으로 활성화되지 않기 때문에 xml에 명시적인 활성화 작업이 필요하다.

- Application Context 안에 이미 등록된 bean들의 Annotation을 활성화 하기 위해 사용 한다.

즉, 스프링 컨텍스트에 의해 생성되어 저장된 bean들에 대해서 @Autowired와 @Qualifier 등의 Annotation 을 인식할 수 있다.

- <context:component-scan> 은 Bean을 등록하고 @Autowired와 @Qualifier 등의 Annotation을 활성화 할 수 있지만 <context:annotation-config/>는 Bean을 등록하지는 못한다.

- <context:annotation-config/> 로 활성화 할 수 있는 Annotation

@Autowired, @Qualifier, @Resource, @PostConstruct, @PreDestroy 등

 

의존성 주입 애노테이션

1) @Autowired

- @Autowired는 주입하려고 하는 객체의 타입이 일치하는 객체를 자동으로 주입한다.

- @Autowired는 필드, 생성자, Setter 메소드, 일반 메소드에 붙일 수 있다.

- 필드에 붙이면 Setter를 통해 주입되며, Setter가 없으면 컴파일 과정에서 자동으로 추가된다.

- @Autowired를 필드, Setter 메소드에 붙여서 사용할 경우 반드시 기존 생성자가 정의되어 있어야 한다.

 

2) @Qualifier

- 동일한 타입한 타입의 빈 객체가 여러 개 정의되어 있는 경우 특정 빈을 주입할 수 있도록 설정한다.

@Qualifier는 <bean> 태그 하위에 <qualifier> 태그를 설정하여 특정 빈을 삽입할 수 있게 설정한다.

- @Autowired 애노테이션이 적용된 주입 대상에 @Qualifier 애노테이션을 설정한다.

@Qualifier는 단독으로 사용할 수 없으며 @Autowired애노테이션과 함께 사용한다.

- 형식

 @Autowired

 @Qualifier("beanName")

 

3) @Resource

- @Resource는 주입하려고 하는 객체의 이름<id>이 일치하는 객체를 자동으로 주입한다.

- @Resource는 Java제공 애노테이션이며 필드, 입력 파라미터가 하나인 Setter 메소드에 붙일 수 있다. 생성자에는 붙일 수 없다.

- 필드에 직접 정의하는 경우 Setter를 정의하지 않아도 된다.

- @Autowired와 마찬가지 반드시 기본 생성자가 정의되어 있어야 한다.

- 형식

 name 속성을 지정하지 않은 경우 : 필드명과 동일한 이름의 빈을 주입한다.

@Resource

 name 속성을 지정한 경우 : name 속성의 빈 이름과 동일한 빈을 주입한다.

@Resource(name="beanName")

 

4) @Inject

- @Inject는 @Autowired와 유사하며, 주입하려고 하는 객체의 타입이 일치한 객체를 자동으로 주입한다.

- @Inject는 Java 제공 애노테이션이며 필드, 생성자, Setter에 붙일 수 있다.

- @Inject를 사용하기 위해서는 javax.inject의존성을 추가한다.

 

5) @Named

- @Autowired의 @Qualifier와 같이 사용할 수 있는 것이 @Inject에서는 @Named 이다.

- @Named에 빈 이름(id)를 지정한다.

- 형식

 @Named("beanName")

 

기타 의존성주입 관련 애노테이션

1) @Required

 - setter에 붙여 반드시 주입 해야하는 프로퍼티로 설정하는 애노테이션

- Spring 5.1 버전부터 Deprecated 되었다. 반드시 주입해야 할 프로퍼티는 생성자 주입을 이용한다.

- 스프링 5.1이상을 사용하거나 자바 파일 bean을 등록했을 경우 무시된다.

 

2) @Value

- 기본 자료형과 문자열의 값을 필드에 주입하기 위해 사용되며, 필드나 생성자와 메소드는 매개 변수 수준에서 적용할 수 있다.

- 생성자 주입 시 자동으로 주입되지 않는 기본 자료형과 문자열의 값을 설정한다.

- 사용 예 : 생성자

public class Sample {
	private int num;
    @Autowired
    public Sample(@Value("10") int num) {
    	this.num = num;
    }
}

 

<context:component-scan/>태그

1) 개요

- Component Scan을 지원하는 태그

- Bean이 될 수 있는 모든 Componenet를 자동으로 찾아 Bean Container에 등록한다.

- 설정 과정을 XML로 선언하는 방식보다 이해하기 쉽고 직관적이다. 

 @Component, @Repository, @Service, @Controller를 선언하고자 하는 Java 코드에 용도에 맞게 직관적으로 선언을 하기 때문에 알아보기 쉽고, 코드를 이해하기도 편하다.

- <context:component-scan>을 이용하게 되면 <context:annotation-config>의 사용이 불필요하다. 즉, @Autowired, @Qualifier, @Resource 같은 애노테이션도 활성화되므로 사용이 불필요하다.

 

컨테이너(Container) 란?

- 컨테이너는 어플리케이션을 관련 라이브러리 및 종속항목과 함께 패키지로 묶어 소프트웨어 서비스 구동을 위한 격리 환경을 제공한다.

- 컨테이너는 보통 인스턴스의 생명주기 관리와 추가적인 기능을 제공한다.

  Servlet 컨테이너는 Servlet의 생성, 생성 후 초기화, 서비스 실행, 소멸에 관한 모든 권한을 가지고 있다.

  개발자가 직접 Servlet을 생성하고 서비스하지는 않는다.

- 스프링 컨테이너는 스프링 프레임워크의 핵심부에 위치하며, 종속객체 주입을 이용하여 애플리케이션을 구성하는 컴포넌트들을 관리한다. 

 

IoC(Inversion Of Control, 제어의 역전)란?

- IoC는 객체의 생성, 생명주기의 관리까지 모든 객체에 대한 제어권이 바뀌었다는 것을 의미한다.

즉, 인스턴스 생성에서 소멸까지의 생명주기 관리를 개발자가 아닌 컨테리너가 담당한다는 것을 의미한다.

- 컴포넌트 의존관계 결정(Component Dependency Resolution), 설정(configuration) 및 생명주기(lifecycle)를 해결하기 위한 디자인 패턴(Design Pattern)이다.

- IoC는 객체 간의 결합도를 줄이고 유연한 코드를 작성하게 하여 가독성 및 코드의 중복, 유지보수를 편하게 할 수 있다.

 

IoC 구현 방법

- DL (Dependency Lookup, 의존성 검색)

저장소에 저장되어 있는 Bean에 접근하기 위해 컨테이너가 제공하는 API를 이용하여 Bean을 Lookup

EJB, Spring 등에서 지원

- DI (Dependency Injection, 의존성 주입)

각 클래스간의 의존관계를 빈 설정(Bean Definition) 정보를 바탕으로 컨테이너가 자동으로 연결한다.

Constructor Injection, Method(Setter) Injection, Field Injection 등

- Spring, PicoContainer 에서 지원

 

Dependency Injection(의존성 주입)

- 객체 자체가 아니라 Framework에 의해 객체의 의존성이 주입되는 설계 패턴

각 클래스간의 의존관계를 빈 설정(Bean Definition) 정보를 바탕으로 컨테이너가 자동으로 연결

- Framework에 의해 동적으로 주입되므로 모듈 간의 결합도가 낮아지고 유연성이 높아진다.

- Dependency Injection은 Spring Framework에서 지원하는 IoC의 형태

- 의존성 주입 방법

Constructor Injection : 생성자를 이용한 의존성 주입

Method(Setter) Injection : Setter나 일반 메소드를 이용한 의존성 주입

Field Injection : 필드를 통한 의존성 주입

 

 

Dependency Injection(의존성 주입) 장점

- Dependency Reduction : 객체 상호 간 의존성 관계를 줄여준다.

- Reusable Structure : 코드의 재사용과 조합이 용이하다.

- Readability : 코드들이 분리되어 가독성이 높다.

- Loose Coupling & Easy to change : 구조는 변화에 민감하지 않을 수 있다.

- 기타 테스트가 용이하고 다양한 패턴을 적용하는 데 유연하다.

 

<?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:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="
	    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
		
	<!-- bean 태그 : 스프링 컨테이너에 빈을 정의(객체 생성) -->
	<!-- 기본 생성자를 이용하여 빈을 정의 -->
	<bean id="userService" class="com.user1.UserServiceImpl"/>
	
	<!-- 생성자로 기본 자료형의 값을 인수로 전달 -->
<!-- 
	<bean id="userService2" class="com.user1.UserServiceImpl2">
		<constructor-arg value="이자바"/>
		<constructor-arg value="010-1111-1111"/> 
		<constructor-arg value="17"/>
	</bean>
-->	
	<bean id="userService2" class="com.user1.UserServiceImpl2">
		<constructor-arg index="0" value="이자바"/>
		<constructor-arg index="2" value="17"/>
		<constructor-arg index="1" value="010-1111-1111"/>
	</bean>

	<!-- 생성자를 이용한 의존성 주입 -->
	<bean id="user" class="com.user1.User">
		<constructor-arg ref="userService2"/>
	</bean>
	
</beans>
<!-- c 네임스페이스를 이용하여 생성자에 값 설정(문자열 또는 기본 자료형) -->
	<bean id="userService2" class="com.user2.UserServiceImpl2"
		c:name="너자바" c:tel="010-2222-2222" c:age="23"/>
	
	<!-- c 네임스페이스를 이용하여 생성자로 의존성 주입 -->
	<!-- init-method : 메소드 설정 - 객체가 생성될 때 단 한 번 호출(초기화 작업이 필요한 경우) -->
	<!-- destroy=method : 메소드 설정 - 객체가 소멸되기 직전 한 번 호출 -->
	<bean id="user" class="com.user2.User"
		c:userService-ref="userService2"
		init-method="init"
		destroy-method="destroy"/>
	<bean id="userService" class="com.user3.UserServiceImpl"/>
	
	<!-- setter를 이용한 프로퍼티 설정(문자열 또는 기본자료형) -->
	<bean id="userService2" class="com.user3.UserServiceImpl2">
		<property name="name" value="다자바"/>
		<property name="tel" value="010-5555-5555"/>
		<property name="age" value="21"/>
	</bean>
	
	<!-- setter를 이용한 의존성 주입 -->
	<!-- 반드시 setter가 존재해야함 -->
	<!-- setter는 name 속성값을 기준으로 첫글자를 대문자로하여 앞에 set을 붙인 메소드명 -->
	<!-- name="userService" => setUserService 라는 메소드명이 존재해야 함 -->
	<bean id="user" class="com.user3.User">
		<property name="userService" ref="userService2"/>
	</bean>
<bean id="userService" class="com.user4.UserServiceImpl"/>
	
	<!-- p 네임스페이스를 이용한 프로퍼티 설정(문자열 또는 기본자료형) -->
	<bean id="userService2" class="com.user4.UserServiceImpl2"
		p:name="홍자바" p:tel="010-1234-5678" p:age="20"/>
	
	<!-- setter를 이용한 의존성 주입 (p 네임스페이스) -->
	<!-- 반드시 setter가 존재해야함 -->
	<bean id="user" class="com.user4.User"
		p:userService-ref="userService2"/>
	<bean id="userService" class="com.user5.UserServiceImpl">
		<property name="name" value="컬렉션"/>
		<property name="address">
			<map>
				<entry key="서블릿" value="서울"/> <!-- <entry key-ref="객체명-1" value-ref="객체명-2"/> -->
				<entry>
					<key><value>스프링</value></key>
					<value>경기</value> <!-- <ref bean="객체명"/> -->
				</entry>
			</map>
		</property>
		<property name="hobby">
			<list>
				<value>게임</value> <!-- <ref bean="객체명"/> -->
				<value>영화</value>
				<value>음악</value>
			</list>
		</property>
		<property name="tels">
			<props>
				<prop key="후후후">010-1111-1111</prop>
				<prop key="호호호">010-2222-2222</prop>
				<prop key="하하하">010-3333-3333</prop>
			</props>
		</property>
	</bean>
	
	<bean id="user" class="com.user5.User">
		<property name="userService" ref="userService"/>
	</bean>
<!-- properties 파일  읽기 -->
	<context:property-placeholder 
		location="classpath:com/user6/user.properties"/>
	
	<bean id="userService" class="com.user6.UserServiceImpl">
		<property name="name" value="${join.name}"/>
		<property name="tel" value="${join.tel}"/>
		<property name="age" value="${join.age}"/>
	</bean>
	
	<bean id="user" class="com.user6.User">
		<property name="userService" ref="userService"/>
	</bean>
<!-- scope : 기본 - singleton : 하나의 객체만 생성 -->
	<bean id="movie" class="com.scope1.Movie"/>
	
	<!-- prototype : 객체를 호출할 때 마다 새로운 객체 생성 -->
	<bean id="music" class="com.scope1.Music" scope="prototype"/>

<bean id="movie" class="com.scope2.Movie" scope="prototype"/>
	<bean id="music" class="com.scope2.Music" scope="prototype">
		<aop:scoped-proxy/> <!-- 메소드를 호출할 때 마다 객체가 생성 -->
	</bean>
	
	<bean id="user" class="com.scope2.User">
		<property name="movie" ref="movie"/>
		<property name="music" ref="music"/>
	</bean>

<!-- scope : 기본 - singleton : 하나의 객체만 생성 -->
<!-- scope="prototype" - 빈을 호출 할 때마다 새로운 객체를 생성 -->	

<!-- 피자 -->
<bean id="pizza" class="com.look.Pizza" scope="prototype"/>

<!-- 베지 피자 -->
<bean id="veggiePizza" class="com.look.Pizza" scope="prototype">
	<property name="isVeg" value="true"/>
</bean>

<!-- 
	룩업 메소드 인젝션 : 컨테이너가 관리하는 빈의 메소드를 재정의하여
					컨테이너 안의 다른 빈을 검색하는 기능 
 -->
<bean id="pizzaShop" class="com.look.PizzaShop">
	<lookup-method name="makePizza" bean="pizza"/>
	<lookup-method name="makeVeggiePizza" bean="veggiePizza"/>
</bean>

 

프레임워크(Framework) 란?

소프트웨어의 구체적인 부분에 해당하는 설계와 구현을 재사용이 가능하게끔 일련의 협업화된 형태로 클래스들을 제공하는 것

즉, 복잡한 문제를 해결하거나 서술하는데 사용되는 기본 개념 구조(뼈대) 이다.

프레임워크는 라이브러리와 달리 애플리케이션의 틀과 구저를 결정할 뿐 아니라, 그 위에 개발된 개발자의 코드를 제어한다.

프레임 워크는 구체적이며 확장 가능한 기반 코드를 가지고 있으며, 설계자가 의도하는 여러 디자인 패턴의 집합으로 구성되어 있다.

 

라이브러리(Library)란 ?

자주 사용되는 로직을 재사용하기 편리하도록 잘 정리한 일련의 코드들의 집합

소프트웨어 개발 시 사용되는 프로그램의 구성요소로, 공통으로 상요될 수 있는 특정한 기능(들)을 모듈화한 것

대상 환경(플랫폼)에서 바로 실행될 수 있는 형태로 제공

라이브러리 자체로는 사용자가 직접 일반적인조작으로실행할 수 없으며, 해당 라이브러리의 기능을 직접 호출하는 프로그램을 실행하거나, 사용자가 해당 라이브러리의 기능을 실행하는 API를 사용하는 프로그램을 직접 개발하여 실행

프로그래밍 언어에서 라이브러리를 사용할 수 있도록 소스코드 수준에서 인터페이스를 노출시킨 것이 API이다.

 

스프링 프레임워크란?

자바엔터프라이즈 개발을 위한 오픈 소스 애플리케이션 프레임워크

자바 객체를 담고 있는 경량의 컨테이너로서 자바 객체의 생성, 소멸과 같은 라이프 사이클을 관리

DI(Dependency injextion), AOP(Aspect Oriented Programming), MVC(Model View Controller), 트랜잭션, 보안 등의 기능을 지원

Spring Framework는 IoC(Inversion of Control, 제어의 역전) 기반이다. 컨트롤의 제어권이 사용자가 아니라 프레임워크에 있어 필요에ㅜ 따라 스프링에서 사용자의 코드를 호출한다.

제어의 역전(IoC : Inversion of Control) ?

- 일반적인 프로그램은 객체의 생성 및 소면, 의존성 주입, 메소드 호출 등을 개발자가 제어하는 구조이다. 하지만, 기존 개발자가 모든 작업을 제어하던 것을 특별한 객체에 모든 것을 위임하여 객체의 생성부터 소멸까지의 생명주기, 의존성 주입 등 모든 객체에 대한 제어권이 넘어간 것을  IoC(제어의 역전)라 한다. 

 

특징

- 컨테이너 역할 : Spring 컨테이너는 객체의 LifeCycle을 관리하며, 컨테이너로부터 필요한 객체를 가져와 사용할 수 있다.

- 의존성 주입(DI : dependency Injection) : Spring은 설정파일이나 어노테이션을 통해서 객체 간의 의존관계를 설정한다.

- 관점지향 프로그래밍(AOP : Aspect-Oriented Programming) : 트랜잭션이나 로깅, 보안과 같이 여러 모듈에서 공통적으로 사용하는 기능의 경우 해당 기능을 분리하여 관리

- 트랜잭션 처리를 위한 일관된 방법 제공 : JDBC, JTA(JavaTransaction API) 등 어떤 트랜잭션을 사용하던 설정을 통해 정보를 관리하므로 트랜잭션 구현에 상관없이 동일한 코드 사용가능

- 영속성과 관련된 다양한 API를 지원 : JDBC 및 MyBatis, Hibernate, JPA(Java Persistence API) 등 데이터베이스 처리를 위한 ORM(Object Relational Mapping) 프레임워크와의 연동을 지원

- POJO(Plain Old Vaca Object) 지원 : 컨테이너에 저장되는 Java 객체는 특정한 인터페이스를 구현하거나, 특정 클래스를 상속받지 않아도 된다.

 

POJO(Plain Old Java Object)

- POJO란 객체지향적인 원리에 충실하면서, 특정 환경과 규약에 종속되지 않아 필요에 따라 재사용될 수 있는 방식으로 설계된 오브젝트라 할 수 있다.

- 조건

(1) 특정 규약에 종속되지 않는다.

- 지정된 클래스를 extends 하지 않는다.

- 정의된 인터페이스를 implement 하지 않는다.

- 정의된 Annotation을 포함하지 않는다.

- 특정 규약에 종속되지 않아 객체지향 설계가 용이하다.

(2) 특정 환경에 종속되지 않는다.

- 예를 들어 웹 환경에 종속되는 HttpServletRequest나 HttpSession과 관련된 API를 직접 이용하면 안된다.

- 다른 환경에서 사용하기 어려우며, 웹 서버 없이 독립적으로 테스트가 어렵다.

- 비지니스 로직과 기술적인 내용을 담은 웹 정보 코드가 섞여 이해하기 어려워진다.

(3) 단일 책임 원칙을 지키는 클래스

책임과 역할이 각기 다른 코드를 하나의 클래스에 넣는 경우 진정한 POJO라 할 수 없다.

 

 

Spring Framework의 구조

- Spring Core

Spring Core는 Spring Container을 의미하며 Spring Framework의 핵심이다.

- Spring Context

 context정보들을 제공하는 설정 파일로, JNDI, EJB, Validation, Scheduling, Internalization 등의 서비스

- Spring AOP(Aspect-Oriented Programming, 관점 지향 프로그래밍)

 공통의 관심 사항을 적용해서 발생하는 의존 관계의 복잡성과 코드 중복을 해소해 주는 프로그래밍 기법

- Spring DAO(Data Access Object)

 JDBC 추상화계층을 제공하여 코드나 예외처리부분을 간편화 시켜 일관된 방법

- Spring ORM(Object Relational Mapping)

Hibernate, JPA(Java Persistence API), JDO(java Data Objects), MyBatis 등을 지원

- Spring Web

 일반적인 Web Application 개발에 필요한 기본적인 기능을 지원

- Spring MVC(Model-View-Controller)

Model2 구조로 Application을 만들 수 있도록 지원

개발 환경
  - J2SE
    JDK 8 Update 291
  - DBMS
    Oracle 18c
  - WAS(Web Container)
    Apache Tomcat 8.5
  - Servlet/JSP Spec
    Servlet 3.1 / JSP 2.3
  - 소프트웨어 형상관리(Software Configuration Management)
    GIT
  - 기타
    javascript, AJAX, JSON, jQuery, CSS3, HTML5 

 

JSP/Servlet으로 이번에는 UI도 만들어서 웹 프로그래밍을 팀플로 진행해보았다 :) 기능을 만들 때 생각처럼 되지 않는 것들도 있었지만 어쨌든 팀원들과 함께 프로젝트를 완성해서 뜻깊은 경험이었다.!

 

커스텀 태그(Custom Tag, 사용자 정의 태그) 이해

 

커스텀 태그(Custom Tag, 사용자 정의 태그)란?

- JSP 언어의 확장인 커스텀 태그는 동적 기능을 캡슐화하는 메커니즘을 제공한다.

- 커스텀 태그는 사용자 정의 JSP 요소로 특정 작업을 수행하기 위하여 사용자에 의해 만들어진 태그이다.

- JSTL도 커스텀 태그의 일정으로 JSP 페이지 개발 및 유지 관리를 단순화한다.

 

커스텀 태그 장점

- 재 사용성 향상 : 한번 작성한 커스텀 태그는 어떤 JSP 컨테이너에서든지 사용 가능하다.

- 쉽고 단순한 JSP 제작 : 자바 코드에 익숙하지 않은 개발자들도 커스텀 태그를 통해서 쉽게 JSP 페이지를 작성할 수 있게 된다.

- 코드의 가독성 향상 : 스크립트 코드를 줄일 수 있기 때문에 JSP 코드의 가독성을 높일 수 있다.

 

커스텀 태그 종류

- JSP 1.2 기반의 커스텀 태그

- JSP 2.0 또는 그 이상 버전의 SimpleTag를 사용한 커스텀 태그

- JSP 2.0 또는 그 이상 버전의 태그 파일을 사용한 커스텀 태그

 

커스텀 태그 관련 인터페이스

javax.servlet.jsp.tagext_JspTag 인터페이스 

- 선언된 메소드는 없으며, Tag 및 SimpleTag 인터페이스의 상위 인터페이스이다.

 

javax.servlet.jsp.tagext.Tag 인터페이스

- JSP 1.2에서 제공하는 커스텀 태그를 구현할 경우에 사용한다.

- 단순한 태그 처리 시 사용하는 커스텀 태그이다.

- JspTag 인터페이스를 상속받았다.

 

javax.servlet.jsp.tagext.IterationTag 인터페이스

- JSP 1.2에서 제공하는 커스텀 태그

- 반복적인 작업을 처리하는 커스텀 태그이다.

- JspTag, Tag 인터페이스를 상속받앙ㅆ다.

 

javax.servlet.jsp.tagext.BodyTag 인터페이스

- JSP 1.2에서 제공하는 커스텀 태그를 구현할 경우에 사용한다.

- 태그의 body 내용이 있을 때 사용하는 커스텀 태그이다.

- InterationTag, JspTag, Tag 인터페이스를 상속 받았다.

 

JSP 1.2 기반 커스텀 태그 관련 인터페이스 및 클래스

javax.servlet.jsp.tagext.JspTag 인터페이스

- 선언된 메소드는 없으며, Tag 및 SimpleTag 인터페이스의 상위 인터페이스이다.

 

javax.servlet.jsp.tagext.Tag 인터페이스

- JSP 1.2에서 제공하는 커스텀 태그를 구현할 경우에 사용한다.

- 단순한 태그 처리 시 사용하는 커스텀 태그이다.

- JspTag 인터페이스를 상속받았다.

 

javax.servlet.jsp.tagext.IterationTag 인터페이스

- JSP 1.2에서 제공하는 커스텀 태그를 구현할 경우에 사용한다.

- 반복적인 작업을 처리하는 커스텀 태그이다.

- JspTag, Tag 인터페이스를 상속받았다.

 

javax.servlet.tagext.BodyTag 인터페이스

- JSP 1.2에서 제공하는 커스텀 태그를 구현할 경우에 사용한다.

- 태그의 body 내용이 있을 때 사용하는 커스텀 태그이다.

- IterationTag, JspTag, Tag 인터페이스를 상속받았다.

 

javax.servlet.jsp.tagext.TagSupport 클래스

- 커스텀 태그를 구현하기 위한 클래스의 최상위 클래스이다.

- IterationTag, JspTag, Tag 인터페이스를 구현한 클래스이다.

 

javax.servlet.jsp.tagext.BodyTagSupport 클래스

- 몸체(body)가 있는 커스텀 태그를 구현하기 위한 클래스의 상위 클래스이다.

- TagSupport 클래스의 하위 클래스이다.

- BodyTag, IterationTag, JspTag, Tag 인터페이스를 구현한 클래스이다.

 

JSP 2.0 기반 커스텀 태그 관련 인터페이스 및 클래스

 

javax.servlet.jsp.tagext.SimpleTag 인터페이스

- JSP 2.0 에서 제공하는 커스텀 태그 구현 시 사용한다.

- Tag, IterationTag 를 하나로 묶어서 좀 더 쉽게 구현이 가능한 커스텀 태그이다.

- JspTag 인터페이스를 상속 받았다.

 

javax.servlet.jsp.tagext.SimpleTagSupport 클래스

- SimpleTag를 구현하는 태그 핸들러를 정의하기 위한 상위 클래스이다.

- SimpleTag 인터페이스를 구현한 클래스이다.

 

javax.servlet.jsp.tagext.DynamicAttributes 

- 커스텀 태그가 동적 속성을 처리하기 위해서는 이 인터페이스를 구현해야 한다.

 

 

 

+ Recent posts