ㅁ 아이콘
- 파일에 X가 붙어있으면 xml 파일을 의미한다.
- 파일에 M이 붙어있으면 Maven을 의미한다. (pom.xml 파일)
- 파일에 커피콩 모양과 s가 같이 있으면 spring bean configuraiton file이다.
- 폴더에 패키지가 포함되어 있으면 소스파일이 보관되는 폴더다.
- 폴더에 s가 붙어있으면 스프링과 관련된 문서가 포함되어 있다는 뜻이다.
ㅁ 수시로 project-clean, maven-update project, 프로젝트 새로고침.
ㅁ 스프링 특징
- IOC와 DI가 스프링의 가장 기본적이면서 중요한 특징이다.
- 개발자가 직접 객체를 생성해서 쓰지 않고 스프링에게 받아서 쓴다.
(1) IOC
- 제어의 역전.
- 컨트롤의 제어권이 개발자가 아닌 프레임워크에 있다.
- 개발자가 프로그램을 제어하지 않고 Framework가 프로그램을 제어하는 것을 의미한다.
- 객체의 생성부터 모든 생명주기의 관리까지 프레임워크가 주도한다.
(2) DI
- 의존성 주입.
- 설정 파일이나 어노테이션을 통해 객체간의 의존 관계를 설정해서 개발자가 직접 의존하는 객체를 생성할 필요가 없다.
- 클래스가 사용할 객체(의존성)를 직접 생성하는 대신, 스프링이 그 객체를 대신 생성하고 주입해주는 구조를 의미합니다.
- 스프링 컨테이너는 애플리케이션이 필요로 하는 모든 객체(빈)를 미리 생성하고, 이 객체들을 관리합니다.
개발자가 직접 new 키워드로 객체를 생성하지 않고, 필요할 때 스프링 컨테이너에서 가져오는 방식이 DI의 핵심입니다.
- DI는 IoC를 구현하는 한 가지 방법이다.
(3) POJO
- 일반 Java 객체(POJO)로 애플리케이션을 구성해 가볍고 유연하게 객체 생성과 의존성 관리를 처리한다.
- 스프링은 개인이 만든 DTO(VO) 클래스를 자유롭게 사용할 수 있다.
이는 Spring이 POJO(Plain Old Java Object) 기반으로 설계되어, 특별한 상속이나 인터페이스 구현 없이 일반적인 Java 객체를 사용할 수 있기 때문입니다.
(4) Spring AOP
- 자바의 가장 큰 특징이 OOP(객체지향 프로그래밍)였다.
그런데 OOP의 문제점이 많다. 그걸 개선한 게 AOP다.
공통적으로 매번 써야하는 코드들을 따로 분리해서 관리할 수 있다.
- 트랜잭션, 로깅, 보안 등 여러 모듈, 여러 계층에서 공통으로 필요로 하는 기능의 경우 해당 기능들을 분리하여 관리한다.
(5) Spring JDBC
- Mybatis나 Hibernate 등의 데이터베이스를 처리하는 영속성 프레임워크와 연결할 수 있는 인터페이스를 제공한다.
- Spring JDBC는 데이터베이스 접근을 간편하게 하기 위해 전통적인 JDBC의 복잡한 예외 처리와 리소스 관리를 자동화하여, 개발자가 데이터 쿼리에 집중할 수 있도록 돕는 기능입니다.
(6) Spring MVC
- 디자인 패턴 중 하나로 하나의 애플리케이션을 구현할 때 구성요소들을 Model, View, Controller로 역할을 구분하는 패턴.
- MVC 디자인 패턴을 통해 웹 어플리케이션의 Model, View, Controller 사이의 의존 관계를 DI 컨테이너에서 관리하여 개발자가 아닌 서버가 객체들을 관리하는 웹 애플리케이션을 구축할 수 있다.
ㅁ IOC 컨테이너
- 개발에 필요한 객체들을 스프링이 관리하게끔 하기 위해서는
해당 객체들을 먼저 빈(Bean)으로 등록해야 된다.
- 개발에 필요한 객체들을 빈(Bean)이라고 한다.
IOC 컨테이너는 등록된 빈(= 객체)들을 가지고 있는 컨테이너다.
- "스프링 컨테이너"나 "빈 컨테이너"라고도 한다.
- 스프링 컨테이너는 Spring에서 애플리케이션의 객체(Bean)를 생성하고 관리하는 시스템을 뜻한다.
ㅁ IOC 컨테이너에 Bean을 등록하는 방법
- 내가 만든 클래스가 아닌 어디선가 제공되는 클래스를 빈으로 등록하고 싶다면 xml 방식이나 java 방식으로 해야 한다.
내가 만든 클래스를 빈으로 등록할 때는 주로 어노테이션 방식으로 할 예정이다.
(1) xml 방식
- Spring Bean Configuration File(xml)에 <bean> 태그로 등록하는 방법.
(2) java 방식
- @Configuration 클래스에서 @Bean을 이용해서 등록하는 방법.
(3) MVC용 어노테이션 방식
- 클래스 위에 @Controller, @Service, @Dao, @Component를 붙이면 빈 등록이 끝난다.
ㅁ IoC + DI의 장점
- 개발에 사용할 서비스 클래스를 빈으로 등록(xml 방식, 자바 방식, MVC용 어노테이션)하고,
DI관련 어노테이션(@Autowired 등)을 통해 해당 객체를 주입받아 사용한다.
(1) 메모리를 보다 효율적으로 사용할 수 있다.
- 직접 new로 생성할 경우 매번 메모리 영역에 새로 생성된다.
자주 사용될 객체, 동시에 다수가 사용할 객체라면 그만큼 객체가 생성되었다가 소멸됨을 반복하며 메모리를 빈번하게 사용한다.
- 스프링의 IoC와 DI 개념이 적용되면 스프링 컨테이너가 해당 객체를 딱 한번만 생성해서 가지고 있다가,
필요할 때마다 해당 객체를 자동으로 주입해준다. (싱글톤 개념이 들어가 있음)
(2) 클래스간의 결합도를 해소할 수 있음 (결합도를 낮출 수 있음)
- 결합도가 높을 때 발생되는 문제 -> 특정 클래스 수정시 해당 클래스를 사용하고 있는 다른 클래스도 수정해야됨.
ex) MemberServiceImpl 클래스의 이름이 바뀌는 경우 new로 직접 생성한 경우에는 직접 new로 생성했던 구문을 전부 바꿔야 한다.
- 스프링의 IoC와 DI 개념이 적용되면 결합도가 낮아져서 소스코드의 수정을 최소화 할 수 있다.
ex) MemberServiceImpl 클래스 이름만 바꾸면 된다.
ㅁ Spring Bean Configuration File
- Bean(개발에 사용할 객체)을 등록할 수 있는 xml 파일.
- xml 파일에 등록된 Bean은 IOC 컨테이너에 보관된다. 그러면 이제부터 스프링이 이 객체를 관리한다.
- appCtx.xml과 root-context.xml 모두 Spring 설정 파일로 지정되었다면, 서버 시작 시 Spring IoC 컨테이너가 해당 파일들을 로드하여 Bean을 등록한다.
- 둘 다 Bean을 등록하는 목적은 같지만 root-context.xml은 전역 Bean 설정으로 널리 사용되는 반면,
appCtx.xml과 같은 이름은 모듈별 또는 특정 기능별로 Bean을 구분하여 등록할 때 사용한다.
- 스프링 설정 파일(Spring Bean Configuration File)은 Spring 서버가 시작될 때 자동으로 읽힌다.
ㅁ web.xml
- 서버 스타트시 제일 먼저 web.xml 파일이 읽혀진다.
- web.xml 파일에 root-context.xml 파일이 적혀있어서 root-context.xml 파일도 실행된다.
root-context.xml이 스프링 컨테이너를 생성할 때 읽어들이는 파일의 경로다.
- 그래서 root-context.xml에 작성된 빈들이 스프링 컨테이너(IOC 컨테이너)에 등록된다.
- web.xml 파일의 그 아래에 <servlet>과 <servlet-mapping> 태그가 있다. 서블릿이 하나 있다.
어떤 url로 요청하든 스프링에서 제공하는 DispatcherServlet이 작동되도록 mapping되어 있다.
- 이때 servlet-context.xml(서블릿과 관련된 환경설정 파일) 파일을 읽어들이면서 DispatcherServlet 객체가 생성된다.
- 요청과 관련된 설정 및 빈 등록은 servlet-context.xml에 작성한다.
이 파일이 Spring Bean Configuration File이다.
ㅁ servlet-context.xml
(1) <annotation-driven>
- 스프링 MVC에서 어노테이션을 이용한 핸들러 매핑과 어노테이션 기반 컨트롤러 기능을 활성화하는 역할이다.
(2) <context:component-scan>
- base-package로 작성된 패키지를 가지고 있는 모든 클래스들을 스캔(= 빈 스캐닝)하면서 @Component 타입의 어노테이션이 붙어있는 클래스들을 자동으로 빈으로 등록한다.
- 일반 클래스를 빈으로 등록시키고 싶으면 @Component를 붙이면 된다.
- @Component 타입의 어노테이션으로 @Controller, @Service, @Repository가 있다.
MVC 역할별로 세분화되어 있다. 각각 컨트롤러, 서비스, dao 단에 붙이는 어노테이션이다.
- @Component와 같은 어노테이션을 인식하고 빈으로 자동 등록할 수 있도록하는 설정이 servlet-context.xml의 <annotation-driven> 태그다.
(3) <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
- InternalResourceViewResolver 클래스가 빈으로 등록되어 있다.
ViewResolver 클래스에 의해 응답페이지가 보여진다.
- 앞과 뒤에 prefix와 suffix가 붙는다.
prefix(접두어)의 값으로 "/WEB-INF/views/"
suffix(접미어)의 값으로 ".jsp"
- request.getRequestDispatcher("/WEB-INF/views/~.jsp").forward(request, response);
(4) <resources mapping="/resources/**" location="/resources/" />
- 정적인 자원(이미지, 오디오, 비디오, css, js 등)들을 관리하는 디렉토리(폴더)의 경로를 설정하는 태그.
- resources는 원래 있는 폴더고 servlet-context.xml에 등록되어 있다.
임의로 정적 자원 폴더를 만들었다면 servlet-context.xml에 등록을 해야 한다.
ㅁ Container에 등록된 Bean을 가져오는 방법
(1) 가장 근본적인 방법은 빈들이 담겨있는 Spring 컨테이너 객체로부터 getBean 메소드로 가져오는 방법이다.
Spring Bean Configuration File(xml) 파일이나 @Configuration이 붙은 클래스파일을 AbstractApplicationContext형 변수에 담고 getBean 메소드로 꺼내서 쓴다.
(2) 새로운 방법은 DI 관련 어노테이션을 이용하는 방법이다.
- @Inject : 등록된 Bean들 중 타입(class)이 일치하는 Bean 객체를 주입해주는 어노테이션
- @Resource : 등록된 Bean들 중 이름(id)이 일치하는 Bean 객체를 주입해주는 어노테이션
이름으로 찾으려면 @Qualifier("이름")를 직접 명시해야 한다.
- @Autowired : 등록된 Bean들 중 타입(class)이 일치하는 Bean 객체를 주입해주는 어노테이션
@Autowired는 @Qualifier이 내장되어있어서 타입이 여러개일 경우 이름으로 자동으로 찾아진다.
- 실무에서는 거진 @Autowired를 사용한다.
ㅁ @Autowired 사용방법
(1) 필드로 생성된 객체 주입
- 필드마다 매번 필드 위에 @Autowired 작성
(2) 메소드로 생성된 객체 주입
- 생성자의 매개변수에 스프링 컨테이너가 관리하는 Bean을 전달받아 주입.
- @Autowired 생략불가능
- 통상 setter 메소드의 형태로 작성. 이렇게 작성하지 않아도 @Autowired 붙어있으면 주입된다.
(3) 생성자로 생성된 객체 주입
- 생성자의 매개변수에 스프링 컨테이너가 관리하는 Bean을 전달받아 주입.
- 필드를 초기화하는 매개변수 생성자 작성 후 해당 생성자 상단에 @Autowired 어노테이션 기술
- @Autowired 어노테이션 생략가능.
- 실무에서 자주 쓰는 방법은 생성자를 이용하는 방법이다.
필드, 메소드는 각각 10개면 어노테이션을 10번 다 써야 한다. @Autowired 생략도 가능하고.
ㅁ 필드를 통한 객체 주입 예시
@Controller
public class PhoneController2 {
@Autowired
private PhoneService pService; // 이러면 현재 서비스로 등록되어 있는 객체가 여기에 주입된다.
@RequestMapping("/list.ph")
public void selectList() {
pService.selectList();
}
}
ㅁ 생성자를 통한 객체 주입 예시
- 위는 root-context.xml이다.
@Controller
public class PhoneController1 {
private Phone a;
private Phone b;
// @Autowired 생략 가능
public PhoneController1(Phone phone1, Phone phone2) { // 매개변수에 생성된 객체 주입
this.a = phone1;
this.b = phone2;
}
@RequestMapping("/test2") // "localhost:8888/spring/test2" 라는 url 요청시 실행되는 메소드
public void diTest2() {
System.out.println(a);
System.out.println(b);
}
}
==========================================================================
[Spring MVC]
ㅁ 스프링 전에는 컨트롤러를 서블릿 클래스로 직접 구현했다.
- Spring에서는 직접 서블릿을 만들지 않고, 모든 URL 요청을 처리하는 하나의 서블릿(DispatcherServlet)을 사용한다.
- 서블릿의 개념이 아예 없는 것은 아니다. 스프링에선 모든 url 요청에 대한 서블릿을 하나 둔다.
Spring에서는 DispatcherServlet이 모든 요청을 받아서 각 컨트롤러에 분배하는 역할을 한다.
ㅁ 스프링 사용 후
- 요청 처리를 담당하는 역할의 Controller 클래스 상단에 @Controller 작성
- 해당 클래스 내에 url 요청별로 실행시킬 메소드를 작성 후 @RequestMapping으로 url 매핑값 작성
ㅁ 어노테이션
(1) @Autowired, @Inject, @Resource
- 필드, 메소드, 생성자 위에 붙어서 객체를 주입한다. (DI)
(2) @RequestMapping(value="" [method=])
- 클래스 위와 메소드 위에 붙는다.
- 클래스 위에 @RequestMapping("/book") 이렇게 작성하는 경우
해당 컨트롤러는 앞으로 /book으로 시작하는 모든 url 요청을 처리하는 클래스로 선언.
- 메소드 위에 붙는 경우.
- value 속성에 URL Mapping값을 작성한다. 여러개 작성할 수 있다. value만 쓸 때는 속성명을 생략할 수 있다.
- method 속성에 요청 방식을 작성한다. 생략시 get, post 둘 다 허용함.
- 메소드 마다 괄호 안의 경로가 달라야 한다. 같으면 오류가 발생한다.
- @RequestMapping(value="/book/list.do") 맨 앞의 슬래시는 생략 가능하다.
@RequestMapping(value="book/list.do")
@RequestMapping("book/list.do")
- Spring MVC의 뷰 리졸버는 경로에 있는 슬래시("/")를 자동으로 정리해주기 때문에, //처럼 슬래시가 중복되어도 문제가 발생하지 않는다.
- 메소드명은 아무 역할이 없다.
- 반환 타입은 String이면 응답할 jsp의 경로를 문자열로 반환값을 작성한다.
void면 반환값을 작성하지 않는다. 이때 응답할 jsp 경로는 url 매핑값과 동일하게 인식된다.
url mapping값에서 .do는 떼고 그 앞으로만 찾는다. (.을 포함한 뒤쪽 구문은 뗀다)
- 반환값은 DispatcherServlet의 ViewResolver에 전달된다.
이때 반환값 앞(prefix)에 "/WEB-INF/views"가 붙고, 뒤(suffix)에 ".jsp"가 붙으면서 응답뷰 경로가 완성된다.
- 기본적으로 포워딩으로 인식돼서 포워딩처리까지 자동으로 진행된다.
앞이랑 뒤에 붙을 걸 고려해서 그 사이에 들어갈 문자열만 반환하면 포워딩으로 인식돼서 포워딩이 진행된다.
- 만약 포워딩이 아니라 redirect를 하고 싶다면 반환 문자열 앞에 "redirect:"를 붙여주면 된다.
ex) return "redirect:/book/detail.do?no=1";
- 포워드 때와 달리 redirect: 다음에 슬래시로 시작해야만 한다.
/는 애플리케이션의 루트(context root)를 기준으로 경로를 설정하겠다는 뜻입니다.
"redirect:/book/detail.do?no=1"는 http://localhost:8080/spring/book/detail.do?no=1로 리다이렉트합니다.
- 매개변수는 마음대로 써도 된다. 쓸 수 있는 매개변수가 엄청 많다.
보통 요청과 응답을 위한 각종 변수들을 선언한다. (request, response, session 등)
- 커맨드 객체는 요청시 클라이언트가 전달한 파라미터 데이터를 주입 받기 위해 사용되는 객체다.
- Model model : 응답페이지에서 필요한 데이터(attribute)를 담는 객체 (request scpoe다) (포워딩하는거)
- ModelAndView mv : Model(데이터) + View(뷰 정보)를 같이 담을 수 있는 객체
- RedirectAttributes arr : redirect할 때 필요한 정보(flash attribute)가 있다면 담는 객체 (redirect하는거)
(3) @GetMapping, @PostMapping
- Spring Boot에서는 HTTP 메서드에 따라 더 명확한 @GetMapping, @PostMapping 같은 어노테이션이 제공되기 때문에 이러한 어노테이션을 사용하는 것이 권장된다.
(4) @Controller
- 컨트롤러 패키지는 항상 클래스 상단에 @Controller를 써서 빈으로 등록한다.
- 컨트롤러 용도의 클래스 상단에 @Controller라는 어노테이션을 붙인다.
@Controller는 클라이언트의 요청을 처리할 클래스를 Bean으로 등록하기 위해 작성하는 어노테이션이다.
- 메소드 위에 @RequestMapping 어노테이션만 있으면 되는게 아니고 컨트롤러 클래스를 빈으로 등록시키는 @Controller 어노테이션이 필요하다.
(5) @Component
- 일반 클래스를 빈으로 등록시키고 싶으면 @Component를 붙이면 된다.
- @Component 타입의 어노테이션으로 @Controller, @Service, @Repository가 있다.
MVC 역할별로 세분화되어 있다. 각각 컨트롤러, 서비스(ServiceImpl), dao 단에 붙이는 어노테이션이다.
(6) @RequestParam
- 컨트롤러의 메소드에서 매개변수 앞에 작성한다.
- request.getParameter()를 자동으로 실행하는 어노테이션이다.
(7) Lombok 어노테이션
- @NoArgsConstructor : 매개변수 없는 생성자 생성
- @AllArgsConstructor : 모든 필드들로 매개변수 생성자 생성
- @Getter : getter 메소드 생성
- @Setter : setter 메소드 생성
- @ToString : toString 메소드 생성
- Getter, Setter는 lombok 걸로 import한다.
- @RequriedArgsConstructor : final 필드로 매개변수 생성자를 만들어 준다. (주입한다)
- 앞으로 사용할 DI 방식은 (final + @RequiredArgsConstructor)다.
일반 필드들이 추가될 수도 있기 때문에 모든 필드들에 주입이 되어서는 안된다.
(8) @ResponseBody
- Spring에서는 기본적으로 return result;로 문자열 리턴하면 포워딩하려 한다. 그래서 404 에러가 발생할 수 있다.
- return 하는 문자열이 응답 뷰가 아니라 응답 데이터라는 것을 알려줘야 한다.
- 메소드 상단에 @ResponseBody 어노테이션을 붙이면 반환값이 응답 뷰가 아니라 응답 데이터다.
- 응답 뷰가 아닌 응답 데이터를 반환하는 경우, 돌려보내는 데이터에 대한 타입을 써줘야 한다.
단순한 숫자나 영문이면 타입을 쓰지 않아도 상관없지만 한글 데이터는 깨질 수 있어서 무조건 써야 한다.
- @GetMapping, @PostMapping의 produces 속성에 응답 데이터에 대한 MIME 타입을 쓸 수 있다.
@GetMapping(value="/detail1.do", produces="text/html; charset=utf-8")
@GetMapping(value="/detail3.do", produces="application/json") // 스프링이면 jackson 필요, 부트면 내장.
- 비동기식으로 데이터 응답시 필요한 어노테이션.
- 해당 어노테이션이 붙은 메소드에서의 반환 값은 응답 뷰가 아닌 어떤 data(text, json, xml 등)라는 걸 의미한다.
(8) @RestController
- 현재 모든 메소드들이 응답 뷰가 아닌 응답 데이터를 돌려주는 메소드다.
모든 메소드에 @ResponseBody가 붙어있다.
- 페이지 이동(포워딩, 리다이렉트) 없이 컨트롤러가 응답 데이터를 돌려줄 목적으로만 제작되어 있으면
클래스 위에 @Controller 대신 @RestController 어노테이션을 작성할 수 있다.
- 이러면 각 메소드들 위에 @ResponseBody 어노테이션을 쓰지 않아도 된다.
안의 메소드들이 전부 @ResponseBody가 붙은 채로 동작한다.
그냥 응답해도 응답 뷰가 아니라 응답 데이터를 리턴하는 컨트롤러로 인식된다.
ㅁ url 경로
- href="${contextPath}/list.bk" => href="${contextPath}/book/list.do"
- href="${contextPath}/detail.mem?no=1" => href="${contextPath}/member/detail.do?no=1"
- href="${contextPath}/detail2.mem?no=1" => href="${contextPath}/member/detail2.do?no=1"
- 서비스를 앞에 한 단계 더 둬서 구분해도 된다.
ㅁ 스프링에서 WEB-INF에 있는 페이지는 무조건 서블릿을 거쳐서 가야 한다.
- Spring MVC에서는 WEB-INF 폴더에 있는 페이지(예: JSP 파일 등)는 외부에서 직접 접근할 수 없고, 반드시 컨트롤러(서블릿)를 통해서만 접근이 가능합니다.
- 이는 보안상의 이유로 WEB-INF에 위치한 파일이 URL로 직접 노출되지 않게 하려는 목적이며,
Spring MVC에서는 Controller에서 요청을 처리하고 적절한 View로 포워딩하는 방식으로 이 구조를 사용합니다.
ㅁ
- a태그는 get 방식이다. redirect도 거의 get 방식이다.
====================================================================================
[요청시 parameter 처리]
ㅁ 요청시 파라미터를 처리하는 방법 3가지
- 1번째 기능은 스프링 이전의 전통적인 방법이다. 2번째 기능부터 스프링 프레임워크의 기능이라고 생각하면 된다.
(1) HttpServletRequest 방법
- 컨트롤러의 메소드에서 매개변수로 HttpServletRequest request를 두고 request.getParameter("key")으로 뽑는다.
- request.setCharacterEncoding("utf-8");는 요청의 문자 인코딩을 UTF-8로 설정하는 코드로,
Spring에서는 이를 매번 작성하지 않고 스프링에서 제공하는 인코딩 필터를 web.xml에 등록하여 모든 요청에 대해 자동으로 UTF-8 인코딩이 적용되도록 할 수 있다.
Spring Boot는 자동으로 UTF-8 인코딩을 설정하므로, 별도의 설정이 필요하지 않습니다.
(2) @RequestParam 방법
- request.getParameter("key")를 자동으로 실행하는 어노테이션이다.
- @RequestParam 어노테이션 하나하나가 곧 request.getPrameter()다.
- 컨트롤러의 메소드에서 매개변수 앞에 작성한다.
public String memberEnroll2(@RequestParam(value="name") String name) { }
public String memberEnroll2(@RequestParam("name") String name) { }
- value 속성 하나만 사용시 value=는 생략 가능하다.
public String memberEnroll2(String name) { }
- 매개변수 name 처럼 요청시 전달되는 key값과 매개변수의 이름이 같으면 @RequestParam 어노테이션을 생략할 수 있다.
- 내가 형변환하지 않아도 자동으로 parsing되서 담긴다.
- 그래서 String형이 아닌 int형 매개변수는 오류가 발생할 수 있다.
int형에는 숫자만 담긴다. null이나 빈문자열이 오면 형변환이 불가능해서 오류가 발생한다.
@RequestParam 어노테이션이 있든 없든 내부적으로 파싱돼서 매개변수에 담기기 때문에 빈문자열이 올 경우 400 에러가 발생한다.
- defaultValue 속성으로 기본값을 지정하면 오류가 나지 않는다.
public String memberEnroll2(@RequestParam(value="age", defaultValue="10") int age) { }
- 마이바티스를 사용하면 데이터를 하나만 넘길 수 있다. DTO에 담거나 Map에 담아서 넘긴다.
(3) 커맨드 객체 방법
- 요청 파라미터들을 각 필드에 담고자하는 객체에, 즉 전달값들을 특정 dto 객체에 바로 담는 경우 사용한다.
- 메소드의 매개변수로 전달값들을 담고자하는 객체를 작성하고,
요청 파라미터의 key값을 담고자하는 객체의 필드명으로 작성한다.
- 이제부턴 key값(name 속성값)도 중요하다.
어떤 필드에 담고 싶은지에 맞춰서 key값을 작성한다.
스프링이 내부적으로 setter메소드를 수행한다.
@PostMapping("/enroll3.do")
public String memberEnroll3(MemberDto mem){ }
- /member/enroll3.do?name=홍길동&age=20&addr=서울 이라는 url 요청시
매개변수로 있는 DTO 객체를 기본생성자로 생성하고,
파라미터의 key값을 가지고 setter 메소드를 찾아서 실행한다.
(내부적으로 실행되는 내용)
MemberDto mem = new MemberDto();
mem.setName("홍길동");
mem.setAge(Integer.parseInt("20"));
mem.setAddr("서울");
- 그래서 dto 객체에 기본생성자와 setter 메소드가 존재해야 한다.
- 그냥 매개변수에 dto 객체만 주면 끝이다.
- 그런데 input 태그에 required 속성이 없어서 특정값을 입력하지 않을 수도 있다.
나이를 입력하지 않으면 빈 문자열을 숫자로 parsing하려해서 오류가 발생한다.
- dto 객체의 age 필드가 int형이어서 문제가 된다. String형이었으면 그냥 빈 문자열이 담기고 끝이다.
값이 누락되면 이런 오류가 빈번하게 발생해서 dto의 필드들을 다 String형으로 두는 경우가 많다.
db에서 number타입이어도 크게 상관 없다.
=========================================================================
[Lombok]
ㅁ Lombok
- 뒤늦게 필드를 수정할 때 그 필드만 수정하면 끝이 아니고 매개변수 생성자, getter, setter 등 그 필드가 쓰인 모든 곳을 수정해야 한다.
- 뒤늦게 필드를 추가할 때도 생성자, getter, setter를 전부 추가해야 한다.
- Lombok이라는 라이브러리를 사용하면 생성자, getter, setter 등을 일일이 작성하지 않아도 된다.
Lombok을 사용하지 않는 회사면 일일이 작성해야 한다.
- Lombok은 스프링의 기능이 아니다.
ㅁ Lombok
- 해당 클래스에 작성되어있는 필드를 가지고 내부적으로 생성자, getter/setter, toString 등을 만들어주는 어노테이션을 제공하는 라이브러리다. (스프링과는 전혀 상관 없다)
- 클래스에 필드만 작성하고 클래스 상단에 필요로하는 생성자 또는 메소드 어노테이션을 기술하면 된다.
- 필드가 나중에 변경(타입, 이름, 추가 등)될 경우 매번 일일이 생성자 또는 메소드를 수정할 필요가 없다.
ㅁ Lombok 어노테이션
- @NoArgsConstructor : 매개변수 없는 생성자 생성
- @AllArgsConstructor : 매개변수 생성자 생성
- @Getter : getter 메소드 생성
- @Setter : setter 메소드 생성
- @ToString : toString 메소드 생성
- Getter, Setter는 lombok 걸로 import한다.
- @RequriedArgsConstructor : final 필드로 매개변수 생성자를 만들어 준다. (주입한다)
- 앞으로 사용할 DI 방식은 (final + @RequiredArgsConstructor)다.
일반 필드들이 추가될 수도 있기 때문에 모든 필드들에 주입이 되어서는 안된다.
ㅁ
- 이제부터는 DTO 객체에 필드만 작성한다.
그러면 필드를 바탕으로 자동으로 생성자, getter, setter를 만들어 준다.
필드를 수정하면 알아서 생성자, getter, setter도 전부 바뀐다.
- 롬복을 쓸거면 필드는 소문자 최소 2개 이상으로 시작하는 이름으로 지어야 한다.
=========================================================================
[응답페이지 이동시 응답데이터 담기]
ㅁ 스프링 MVC에서 응답 데이터와 뷰 정보를 전달하는 객체
- 스프링 MVC에서 Model, ModelAndView, RedirectAttributes는 직접 생성할 필요 없이 매개변수로 선언하면 스프링이 자동으로 주입해 준다. 컨트롤러 메서드에서 필요한 객체를 매개변수로 선언하기만 하면 됩니다.
(1) Model model : 응답페이지에서 필요한 데이터(attribute)를 담는 객체 (request scpoe다) (포워딩하는거)
(2) ModelAndView mv : Model(데이터) + View(뷰 정보)를 같이 담을 수 있는 객체
(3) RedirectAttributes arr : redirect할 때 필요한 정보(flash attribute)가 있다면 담는 객체 (redirect하는거)
ㅁ Model 객체, ModelAndView 객체 중 원하는 방식으로 하면 된다.
- 매개변수에 ModelAndView 객체를 추가한다.
메소드의 반환형도 ModelAndView 객체로 작성한다. (Model은 반환형 String)
(1) Model 객체 이용하기
- requestScope 영역에 데이터를 맵형식(key-value)로 담을 수 있는 객체
- 단 setAttribute가 아닌 addAttribute 메소드를 사용한다.
@GetMapping("/list.do")
public String noticeList(Model model) {
List<NoticeDto> list = noticeService.selectNoticeList(); // 응답페이지에 필요한 데이터
model.addAttribute("list", list);
return "notice/list"; // /WEB-INF/views/notice/list.jsp로 포워딩
}
<c:forEach var="n" items="${ list }">
<tr>
<td>${ n.no }</td>
<td>${ n.title }</td>
<td>${ n.content }</td>
</tr>
</c:forEach>
(2) ModelAndView 객체 이용하기
- Model과 View가 합쳐져 있는 객체.
- Model은 데이터를 담는 객체, View는 응답 뷰에 대한 정보를 담는 객체
- ModelAndView 객체에 데이터와 응답 뷰에 대한 정보를 담고 해당 객체를 반환한다
@GetMapping("/detail.do")
public ModelAndView noticeDetail(int no, ModelAndView mv) { // key값과 매개변수명이 같으면 @RequestParam 생략가능
// NoticeDto n = noticeService.selectNoticeByNo(no); 응답 페이지에 필요한 데이터
// return "notice/detail"; 응답뷰
mv.addObject("notice", noticeService.selectNoticeByNo(no)); // 응답 페이지에 필요한 데이터
mv.setViewName("notice/detail"); // 응답뷰
// mv.addObject("notice", noticeService.selectNoticeByNo(no)).setViewName("notice/detail");
// addObject 메소드가 해당 ModelAndView 객체를 반환하기 때문에 한줄로 메소드 체이닝 가능하다.
return mv;
}
<c:choose>
<c:when test="${ empty notice }"> 조회된 공지사항이 없습니다. </c:when>
<c:otherwise>
번호 : ${ notice.no } <br>
제목 : ${ notice.title } <br>
내용 : ${ notice.content }
</c:otherwise>
</c:choose>
(3) RedirectAttributes 객체 이용하기
- redirect시 포워딩 되는 페이지에 필요한 데이터를 담는 방법
- model 객체는 따지고보면 request scope다. 그래서 바로 포워딩되는 jsp에서만 사용 가능하다.
- redirect로 다른 controller가 실행되는 순간 현재 만들어진 Model 객체는 소멸된다.
- reidrect 하는데 model.addAttribute("alertMsg", "성공적으로 수정되었습니다.");로 담아봤자 Model 객체가 소멸된다.
- RedirectAttributes 객체를 생성해서 데이터를 담으면 건너 건너 포워딩된 페이지(jsp)까지 RedirectAttributes 객체가 유지된다.
이때 addFlashAttribute 메소드로 담으면 된다.
@PostMapping("/update.do")
public String noticeUpdate(NoticeDto n, RedirectAttributes ra) { // 1) 요청시 전달값 처리 - 커맨드 객체
// 2) 요청처리를 위한 서비스 호출
int result = noticeService.updateNotice(n);
// 3) 응답
if(result > 0) {
// return "notice/detail"; 이건 포워딩이다.
//model.addAttribute("alertMsg", "성공적으로 수정되었습니다.");
ra.addFlashAttribute("alertMsg", "성공적으로 수정되었습니다.");
return "redirect:/notice/detail.do?no=" + n.getNo(); // context path 안줘도 됨. 여기에도 글번호 넘겨야 함.
}else {
// return "main"; 이렇게 하면 메인페이지가 뜨긴 하는데 url이 메인 페이지가 아니라 /update.do다.
// MvcController 가보면 이미 메인페이지로 이동하는 메소드가 정의되어 있음.
return "redirect:/";
}
}
=========================================================================
[Spring MVC 정리]
- https://moca7.tistory.com/277
'Spring' 카테고리의 다른 글
스프링 정리3 - AJAX (1) | 2024.11.15 |
---|---|
스프링 정리2 - 로깅 (1) | 2024.11.14 |
디비 (1) | 2024.11.06 |
[스프링부트] 10. 트랜잭션 처리 (0) | 2024.11.06 |
[스프링부트] 9. 웹소켓 (2) | 2024.11.06 |