본문 바로가기
Spring

스프링 정리 - MVC

by moca7 2024. 11. 13.

 

 

 

 

ㅁ 아이콘

- 파일에 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();

    }

 

}

 

 

 

 

ㅁ 생성자를 통한 객체 주입 예시

 


<?xml version="1.0" encoding="UTF-8"?>
   

    <bean class="com.br.spring.di.Phone" id="phone1">
        <property name="name" value="아이폰 16 pro" />
        <property name="brand" value="Apple" />
        <property name="price" value="1700000" />
        <property name="releaseDate" value="2024-09-28" />
    </bean>

    <bean class="com.br.spring.di.Phone" id="phone2">
        <constructor-arg value="갤럭시 s24" />
        <constructor-arg value="Samsung" />
        <constructor-arg value="1600000" />
        <constructor-arg value="2024-02-01" />
    </bean>
 
</beans>
 

 

- 위는 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