course 2021/Spring

Spring02 - 12/03

코딩하는토끼 2021. 12. 16. 21:30

> 다시 한번 정리하고 넘어가자

- 프로젝트 우클릭 - Maven - Update Project

- 패키지 우클릭 - New - Spring Bean Configuration File 

- 클래스 우클릭 Run As Java Application 으로 실행하기


lecture.p06core

MyDao

package lecture.p06core;

public class MyDao {

}

 

MyServlet

package lecture.p06core;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class MyServlet {
	
	private MyDao myDao;
	
//	public MyServlet(MyDao myDao) {
//		this.myDao = myDao;
//	}
}

@setter 작성하여 setMyDao 메소드를 통해 주입할 수도 있지만,

아래 주석처리한 것처럼 생성자를 이용해서 주입할 수도 있다!

이를 직접 작성하지 않고 annotation 을 작성할거임 - @AllArgsConstructor

(@getter 는 읽기를 위해 작성)

 

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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="myServlet" class="lecture.p06core.MyServlet">
		<constructor-arg ref="myDao"></constructor-arg>
	</bean>
	<bean id="myDao" class="lecture.p06core.MyDao"></bean>

</beans>

이번에는 property 태그가 아닌 constructor-arg 태그 작성 (생성자를 이용해 주입하는 태그)

 

App

package lecture.p06core;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import lombok.extern.log4j.Log4j;

@Log4j
public class App {
	public static void main(String[] args) {
		
		String config = "lecture/p06core/context.xml";
		
		ApplicationContext context = new ClassPathXmlApplicationContext(config);
		
		MyServlet myServlet = context.getBean(MyServlet.class);
		MyDao myDao = context.getBean(MyDao.class);
		
		log.warn(myServlet);
		log.warn(myDao);
		
		log.warn(myServlet.getMyDao());
		
	}
}

 

결과


lecture.p07core

context.xml

패키지 우클릭 - New - Spring Bean Configuration File 에서 name 작성 후 바로 finish 하지말고 next

위와 같은 옵션에서 beans, context 체크하여 생성★하기

<?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"
	xsi:schemaLocation="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">

<bean id="myServlet" class="lecture.p07core.MyServlet"></bean>
<bean id="myDao" class="lecture.p07core.MyDao"></bean>

</beans>

 

* MyServlet, MyDao 는 생성만 하고 아무것도 작성하지 않음

 

App

package lecture.p07core;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import lombok.extern.log4j.Log4j;

@Log4j
public class App {
	public static void main(String[] args) {
		
		String config = "lecture/p07core/context.xml";
		
		ApplicationContext context = new ClassPathXmlApplicationContext(config);
		
		MyServlet myServlet = context.getBean(MyServlet.class);
		MyDao myDao = context.getBean(MyDao.class);
		
		log.warn(myServlet);
		log.warn(myDao);
	}
}


> 다른 방법

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"
	xsi:schemaLocation="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="lecture.p07core"></context:component-scan>

</beans>

<context:component-scan base-package="lecture.p07core"></context:component-scan>

와 같이 context:component-scan 태그 작성하고

 

MyServlet

package lecture.p07core;

import org.springframework.stereotype.Component;

@Component
public class MyServlet {

}

 

MyDao

package lecture.p07core;

import org.springframework.stereotype.Component;

@Component
public class MyDao {

}

 

위와 같이 MyServlet, MyDao 에 annotation 으로 @Component 작성 (bean 을 생성할 수 있도록 함)


lecture.p08coreExercise

연습

Student 

package lecture.p08coreExercise;

import org.springframework.stereotype.Component;

@Component
public class Student {

}

 

Teacher

package lecture.p08coreExercise;

import org.springframework.stereotype.Component;

@Component
public class Teacher {

}

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"
	xsi:schemaLocation="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="lecture.p08coreExercise"></context:component-scan>

</beans>

App

package lecture.p08coreExercise;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import lombok.extern.log4j.Log4j;

@Log4j
public class App {
	public static void main(String[] args) {

		String config = "lecture/p08coreExercise/context.xml";

		ApplicationContext context = new ClassPathXmlApplicationContext(config);

		Student student = context.getBean(Student.class); // not exception
		Teacher teacher = context.getBean(Teacher.class); // not exception

		log.warn(student);
		log.warn(teacher);
		
		log.warn("--- bean 이름으로 얻기 ----");
		
		log.warn(context.getBean("student"));
		log.warn(context.getBean("teacher"));
	}
}

bean 이름으로 얻기 아래에 context.getBean 까지는 알겠는데 그냥 냅다 "student" "teacher" 넣는다고?

- bean 이름은 클래스 이름 (소문자로 바꾼) 으로 생성된다. 그래서 student, teacher 이 bean 이름인 것.


lecture.p09core

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"
	xsi:schemaLocation="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="lecture.p09core"></context:component-scan>
</beans>

MyDao

package lecture.p09core;

import org.springframework.stereotype.Component;

@Component
public class MyDao {

}

MyServlet

package lecture.p09core;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyServlet {

	private MyDao myDao;

	public MyDao getMyDao() {
		return myDao;
	}

	@Autowired
	public void setMyDao(MyDao myDao) {
		this.myDao = myDao;
	}
}

set/get 메소드 직접 작성했는데, 그냥 @Getter, @Setter 작성해도됨

@Autowired : 주입되도록 하는 역할 (set 메소드 위에 작성됨)

Dao → Servlet

 

App

package lecture.p09core;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
	public static void main(String[] args) {

		String config = "lecture/p09core/context.xml";

		ApplicationContext context = new ClassPathXmlApplicationContext(config);

		MyServlet myServlet = context.getBean(MyServlet.class);
		MyDao myDao = context.getBean(MyDao.class);

		System.out.println(myServlet);
		System.out.println(myDao);
		
		System.out.println(myServlet.getMyDao());
	}
}


lecture.p10coreExercise

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"
	xsi:schemaLocation="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="lecture.p10coreExercise"></context:component-scan>
</beans>

Memory

package lecture.p10coreExercise;

import org.springframework.stereotype.Component;

@Component
public class Memory {

}

Computer

package lecture.p10coreExercise;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import lombok.Getter;
import lombok.Setter;

@Component
@Getter
@Setter(onMethod_ = @Autowired)
public class Computer {

	private Memory memory;

//	@Autowired
//	public void setMemory(Memory memory) {
//		this.memory = memory;
//	}
//
//	public Memory getMemory() {
//		return memory;
//	}
}

@Setter(onMethod_=@Autowired) 작성

App

package lecture.p10coreExercise;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
	public static void main(String[] args) {
		
		String config = "lecture/p10coreExercise/context.xml";
		
		ApplicationContext context = new ClassPathXmlApplicationContext(config);
		
		System.out.println(context.getBean("computer")); // not null, not exception
		System.out.println(context.getBean("memory")); // not null, not exception
		
		System.out.println(context.getBean(Computer.class).getMemory()); // not null, not exception
		
	}
}


lecture.p11core

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"
	xsi:schemaLocation="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="lecture.p11core"></context:component-scan>
</beans>

MyDao

package lecture.p11core;

import org.springframework.stereotype.Component;

@Component
public class MyDao {

}

MyServlet

package lecture.p11core;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import lombok.Getter;

@Component
@Getter
public class MyServlet {
	private MyDao myDao;

	@Autowired // 생성자가 하나만 존재할 경우 @Autowired가 없어도 DI 됨.
	public MyServlet(MyDao myDao) {
		this.myDao = myDao;
	}
}

생성자를 이용하는 방법

App

package lecture.p11core;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
	public static void main(String[] args) {
		String path = "lecture/p11core/context.xml";
		
		ApplicationContext context = new ClassPathXmlApplicationContext(path);
		
		MyServlet s = context.getBean(MyServlet.class);
		MyDao d = context.getBean(MyDao.class);
		
		System.out.println(s);
		System.out.println(d);
		
		System.out.println(s.getMyDao());
		
	}
}

lecture.p12core

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"
	xsi:schemaLocation="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="lecture.p12core"></context:component-scan>
</beans>

MyDao

package lecture.p12core;

import org.springframework.stereotype.Component;

@Component
public class MyDao {

}

MyServlet

package lecture.p12core;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import lombok.Getter;

@Component
@Getter
public class MyServlet {

	@Autowired
	private MyDao myDao;
}

App

package lecture.p12core;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
	public static void main(String[] args) {
		
		String path = "lecture/p12core/context.xml";
		ApplicationContext context = new ClassPathXmlApplicationContext(path);
		
		MyServlet s = context.getBean(MyServlet.class);
		MyDao d = context.getBean(MyDao.class);
		
		System.out.println(s);
		System.out.println(d);
		
		System.out.println(s.getMyDao());
	}
}

> 정리

* 주입: DI (dependence injection)

1. <bean class=""></baen> 작성하여 bean 생성 (p04)

2. <bean class=""> <property name="" ref=""></property> </bean>

<bean id="" class=""></bean> 작성하여 주입 (p04, p05)

3. <bean id="" class=""><constructor-arg ref=""></constructor-arg></bean>
<bean id="" class=""></bean> 작성하고,

annotation @AllArgsConstructor 작성하여 

생성자를 이용한 주입 (p06)

4. xml 파일 생성 시 옵션에서 beans, context 체크, 

<context:component-scan base-package=""></context:component-scan> 작성하고,

annotation @Component 작성하여 bean 생성 (p07, p08)

5. 4번 + 주입하기 위해 set 메소드에 @Autowired 작성해줌 (p09, p10)

6. 4번 + 생성자를 이용해 주입하기위해 생성자에 @Autowired 작성해줌 (p11)


Tomcat 에서 Spring bean 을 만들고 DI 를 하기 위해서 Listener 를 사용! 

(Listener 는 tomcat 이 시작하자마자 실행됨)

이러한 역할을 하는 listener 가 이미 spring 에 있다

WEB-INF > web.xml 파일 

listener 태그가 존재

WEB-INF > spring > root-context.xml

어떤 bean 을 만들고 어떤 DI 를 하는지에 대한 설명을 root-context.xml 파일에 작성

 

Spring 에서 제공하는 servlet 도 있다 - DispatcherServlet

root-context.xml 은 listener 에, servlet-context.xml 은 servlet 에 사용됨

WEB-INF > spring > appServlet > servlet-context.xml

이 DispatcherServlet 을 언제 작동시킬지 경로를 작성 (이전에는 annotation 으로 작성했었음)

.xml 파일에서는 mapping 태그로 작성한다

/ 경로로 요청이 오면 appServlet 으로 전달 - 그러면 위의 DispatcherServlet 이 요청을 받음

 

이제 우리는 서블릿을 작성하지 않고, DispatcherServlet 이 모든 요청을 받아 처리하게 됨

DispatcherServlet 은 servlet-context.xml 설정파일을 읽어서 spring bean 을 만들고 DI 도 하게 됨

applicationContext 가 만들어진다 (리스너에서도, 서블릿에서도 만들어져 총 2개의 applicationContext) 

(DispatcherServlet 에 요청이 오지 않아도 load-on-startup 태그에 의해 초기화 이루어짐)

ROOT 가 WEB 보다 상위, WEB 에서는 ROOT 참조 가능하지만 반대는 불가능

ROOT 내 bean 들에는 dao, service 같은 것들이 있다


> 참고

https://spring.io/projects/spring-framework

Learn 탭에서 최신버전의 Reference Doc. 과 API Doc. 참고

- Reference Doc. https://docs.spring.io/spring-framework/docs/current/reference/html/

주로 Core, Web Servlet 참고

특히 Web Servlet 의 1.1 DispatcherServlet, 1.3 Annotated Controllers


servlet-context.xml

WEB-INF > views 안에 .jsp 파일을 만들거고,

org.zerock.controller 패키지 안에 component 를 만들것임


p01controller

Controller01

그냥 class 로 생성하면된다

Spring MVC 에서 사용하는 @Controller annotation

https://docs.spring.io/spring-framework/docs/current/javadoc-api/ 참고

아무튼 @Component 대신 @Controller 씀

→ @Controller 가 붙은 클래스의 bean ! 이라고 이해하기

@RequestMapping 과 함께 쓰임

@RequestMapping("/cont01") : 경로 /cont01

package org.zerock.controller.p01controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/cont01")
public class Controller01 {
	
	// "/cont01"
	@RequestMapping("")
	public void method00() {
		System.out.println("메소드00 일함");
	}
	
	// "/cont01/met01"
	@RequestMapping("/met01")
	public void method01() {
		System.out.println("메소드01 일함");
	}
	
	// "/cont01/met02" 요청이 왔을 때 일하는 메소드(method02)를 작성하세요. return : void
	@RequestMapping("/met02")
	public void method02() {
		System.out.println("메소드02 일함");
	}
	
	
	// "/cont01/met03", "/cont01/met04" 로 요청이 왔을 때 일하는 메소드
	@RequestMapping({"/met03", "/met04"})
	public void method03() {
		System.out.println("메소드 03 일함");
	}
	
	// "/cont01/met05", "/cont01/met06" 로 요청이 왔을 때 일하는 메소드 method05 작성
	@RequestMapping({"/met05", "/met06"})
	public void method05() {
		System.out.println("메소드 05 일함");
	}
}

annotation, 경로 주의깊게 보기

경로를 비워두거나 여러 경로를 하나에 작성할 수도 있다

("") : /cont01

("/") : /cont01/

({"/met03", "met04"}) : /cont01/met03 혹은 /cont01/met04

 

결과 ↓

프로젝트 run on server 로 실행 - 주소창에 경로 입력 /cont01/met01

이런 창이 뜨지만 무시하고 콘솔창 확인


Controller02

package org.zerock.controller.p01controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/cont02")
public class Controller02 {

	// url : "/cont02/met01" , method : get
	@RequestMapping(value = "/met01", method = RequestMethod.GET)
	public void method01() {
		System.out.println("메소드 01 일함");
	}

	// url : "/cont02/met01" , method : post
	@RequestMapping(value = "/met01", method = RequestMethod.POST)
	public void method02() {
		System.out.println("메소드 02 일함");
	}

//	@RequestMapping(value = "/met03", method = RequestMethod.GET)
	@GetMapping("/met03")
	public void method03() {
		System.out.println("메소드 03 일함");
	}

	// url : "/cont02/met03", method : post 일하는 메소드 method04를 작성
//	@RequestMapping(value = "/met03", method = RequestMethod.POST)
	@PostMapping("/met03")
	public void method04() {
		System.out.println("메소드 04 일함");
	}
	
	
	@RequestMapping(value="/met05", method = {RequestMethod.GET, RequestMethod.POST})
	public void mthod05() {
		System.out.println("메소드 05 일함");
	}

}

RequestMethod

https://docs.spring.io/spring-framework/docs/current/javadoc-api/ 참고

@RequestMapping(value = "/met01", method = RequestMethod.GET)

@RequestMapping(value = "/met01", method = RequestMethod.POST)

@GetMapping("/met03")

@PostMapping("/met03")

 

Get 방식의 요청은 Controller01 에서와 같이 해도 되지만 Post 방식은 터미널로 보내야 함 ↓

get 방식: curl -s 주소 > o.txt

post 방식: curl -s -X POST 주소 > o.txt

(주소는 프로젝트 실행하고 경로 입력한 것)

콘솔 창 결과 ↓

 

방식 get, post 두가지 설정 가능

method = {RequestMethod.GET, RequestMethod.POST}


Controller03

package org.zerock.controller.p01controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/cont03")
public class Controller03 {

	@RequestMapping("/met01")
	public void method01(HttpServletRequest request) {
		System.out.println("메소드 01 일함");

		// 2. request 분석/ 가공
		String name = request.getParameter("name");
		String ageStr = request.getParameter("age");
		int age = Integer.parseInt(ageStr);

		// 3.
		System.out.println(name);
		System.out.println(age);
	}

	@RequestMapping("/met02")
	public void method02(String name, Integer age) {
		System.out.println("메소드 02 일함");
		System.out.println(name);
		System.out.println(age);
	}

	// /cont03/met03 : request 파라미터, address(String)와 id(Integer)를 받도록 메소드 작성
	@RequestMapping("/met03")
	public void method03(String address, Integer id) {
		System.out.println(address);
		System.out.println(id);
	}

	@RequestMapping("/met04")
	public void method04(@RequestParam("name") String contactName) {
		System.out.println(contactName);
	}

	// url:/cont03/met05?country=korea&height=200
	@RequestMapping("/met05")
	public void method05(@RequestParam("country") String c,
			@RequestParam("height") Integer h) {
		System.out.println(c);
		System.out.println(h);
	}
}

method01

(HttpServletRequest request) 입력할 수 있다

request.getParameter 로 name, age 받아서 출력

name, age - 쿼리 스트링으로 입력

method02 

method01 에서 했던 일을 단순히 메소드의 매개변수로 작성함으로써 가능하게 함

int 여도 자동 형변환 되어 받아짐

null 값을 받기 위해서는 참조타입으로 (integer 로) 작성

name, age 정상적으로 전달받아 출력됨

method03

address, id 받아서 출력

method04

이름이 다를 경우?

@RequestParam("") 이라는 어노테이션으로 명시해주면 된다

method04(@RequestParam("name") String contactName)

name 으로 받아서 contactName 에 저장됨

method05

연습


> 정리

1. 클래스에 @Controller, @RequestMapping 작성, 메소드에 @RequestMapping 작성

@RequestMapping() 안에는 경로(value), 전달방식(method) 작성

- method 에는 대표적으로 get, post 가 있으며 post 방식의 요청은 터미널로 전달한다

2. request.getParameter 로 전달받던 값들을 메소드의 매개변수로 간단히 받을 수 있음

- 만약 이름이 다르다면 @RequestParam() 작성

* 프로젝트 run on server 로 실행하여 주소창에 경로 입력하면 콘솔에서 결과를 확인할 수 있다

전달할 값 또한 주소창에 쿼리 스트링으로 입력하면 된다