1. 개요
Model View Controller
SpringMVC는 Java 기반 MVC 패턴을 구현한 경량 웹 프레임워크입니다. Spring 프레임워크의 주요 모듈 중 하나로, 웹 애플리케이션 개발에 널리 사용됩니다.
2. 작동 원리
서버 초기화 과정
- 서버가 시작되면 ServletContainersInitConfig 클래스가 실행되어 웹 컨테이너를 초기화합니다.
- createServletApplicationContext 메서드를 통해 WebApplicationcontext 객체가 생성되어 ServletContext에 저장됩니다.
- SpringMvcConfig 설정 클래스가 WebApplicationcontext에 로드됩니다.
- @ComponentScan 어노테이션이 지정된 패키지의 빈(Bean)을 스캔합니다.
- UserController가 로드되며, 각 @RequestMapping 값이 실제 메서드에 매핑됩니다.
- getservletMappings 메서드가 모든 요청이 SpringMVC를 통해 처리되도록 설정합니다.
3. Spring과 SpringMVC의 빈 관리 분리
Spring과 SpringMVC는 각각 다른 컨테이너에서 빈을 관리합니다. SpringMVC의 컨트롤러는 Spring의 빈으로 로드되지 않도록 excludeFilters 속성을 사용하여 필터링해야 합니다.
4. Servlet 컨테이너 초기화 설정
AbstractAnnotationConfigDispatcherServletInitializer는 AbstractDispatcherServletInitializer의 하위 클래스로, 설정이 간소화된 추상 메서드를 제공합니다.
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
@Override
protected Class>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
5. 요청과 응답 처리
@RequestMapping 요청 매핑
메서드 또는 클래스위에 사용하며, 컨트롤러의 접근 경로를 지정합니다. value 속성을 통해 주소Prefix를 설정합니다.
GET 요청 처리
1. 일반 파라미터 전달
http://localhost/commonParam?name=hello&age=25
@Controller
public class UserController {
@RequestMapping("/commonParam")
public String commonParam(String name, int age) {
System.out.println("전달된 이름: " + name);
System.out.println("전달된 나이: " + age);
return "{'common param'}";
}
}
2. POJO 객체 파라미터 전달
http://localhost:8080/sample/pojoParam?name=john&age=30
Member 클래스:
public class Member {
private String name;
private int age;
private Address address = new Address();
public Member() {
}
public Member(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "Member{name='" + name + "', age=" + age + ", address=" + address + "}";
}
}
Address 클래스:
public class Address {
private String city;
private String province;
public Address() {
}
public Address(String city, String province) {
this.city = city;
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
@Override
public String toString() {
return "Address{city='" + city + "', province='" + province + "'}";
}
}
@RequestMapping("/pojoParam")
@ResponseBody
public String pojoParam(Member member) {
System.out.println("POJO 파라미터: " + member);
return "pojo param";
}
POJO 클래스형을 파라미터로使用时, 전달되는 파라미터명이 POJO 클래스의 속성명과 일치하면 자동으로 매핑됩니다. 중첩 객체에는 address.city=값 형태 형태로 전달합니다.
3. 배열 및 컬렉션 파라미터
여러 값을 배열로 전달할 경우 파라미터명을 동일하게 반복하여 전송합니다. 컬렉션의 경우 @RequestParam 어노테이션이 필요합니다.
4. JSON 데이터 전달
JSON 형식의 데이터 전달은 별도의 설정이 필요합니다.
POST 요청 처리
POST 요청의 파라미터는 요청 본문(Body)에 포함되므로, Postman 등에서 body 섹션을 선택하여 데이터를 입력합니다.
응답 처리
메서드의 반환값에 따라 응답 형식이 결정됩니다. 문자열 반환 시视图 이름을, @ResponseBody와 함께 사용하면 응답 본문으로 처리됩니다. 객체 반환 시 자동으로 JSON으로 변환됩니다.
6. 주요 어노테이션 및 설정
1. 한글 인코딩 설정
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
return new Filter[]{filter};
}
@ResponseBody
메서드 위에 적용하며, 반환값을 응답 본문으로 설정합니다. 객체 타입 반환 시 자동으로 JSON으로 변환되며, HttpMessageConverter 인터페이스가 이를 처리합니다.
@RequestParam
파라미터 앞에 적용하며, 요청 파라미터명을 메서드 파라미터에 매핑합니다. 컬렉션 타입 파라미터 앞에 사용하여 데이터를 파라미터 형태로 전달받을 수 있습니다.
@RequestParam은 URL 파라미터 및 폼 데이터(x-www-form-urlencoded)를 처리하고, @RequestBody는 JSON 데이터를 처리합니다.
JSON 데이터 수신
의존성 추가:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.18.1</version>
</dependency>
SpringMVC 설정 클래스에 @EnableWebMvc 어노테이션 추가:
@EnableWebMvc
@ComponentScan("com.example.controller")
public class SpringMvcConfig {
}
JSON 컬렉션 수신 예시:
@RequestMapping("/jsonListParam")
@ResponseBody
public String jsonListParam(@RequestBody List<String> favorites) {
System.out.println("JSON 컬렉션 파라미터: " + favorites);
return "jsonListParam functioned";
}
Postman에서 body - raw - JSON을 선택하여 전송합니다.
날짜 데이터 수신
날짜 형식은 2088-08-18, 2088/08/18, 08/18/2088 등 다양합니다. 두 번째 형식이 기본값이며, 다른 형식은 @DateTimeFormat 어노테이션으로 지정합니다.
@RequestMapping("/dateParam")
@ResponseBody
public String dateParam(Date date,
@DateTimeFormat(pattern = "yyyy-MM-dd") Date date1,
@DateTimeFormat(pattern = "yyyy/MM/dd HH:mm:ss") Date date2) {
System.out.println("date 타입: " + date);
System.out.println("date1 타입: " + date1);
System.out.println("date2 타입: " + date2);
return "1234";
}
7. REST 개발 방식
REST(Representational State Transfer)
REST 방식을 자원(Resource) 접근에 활용하는 것을 RESTful이라고 합니다. 장점은 URL 자원 접근 행위를 숨기고 간결하게 작성할 수 있다는 것입니다.
RESTful 메서드 매핑
@RestController
@RequestMapping("/member")
public class MemberControllerForREST {
private Member member = new Member();
@PostMapping
public String save(@RequestBody Member member) {
System.out.println("멤버 저장: " + member);
return "member save functioned";
}
@DeleteMapping("/{id}")
public String delete(@PathVariable int id) {
System.out.println("멤버 삭제: " + id);
return "member delete functioned";
}
@PutMapping
public String update(@RequestBody Member member) {
System.out.println("멤버 수정: " + member);
return "update functioned";
}
@GetMapping("/{id}")
public String getById(@PathVariable int id) {
System.out.println("ID로 조회: " + id);
return "member getById";
}
@GetMapping
public String getAll() {
System.out.println("전체 조회");
return "member getAll functioned";
}
}
정적 파일 MVC 차단 해제
정적 파일이 MVC에 의해 차단되지 않도록 설정:
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**")
.addResourceLocations("/pages/");
}
}
위 설정으로 /pages/ 경로의 파일 요청 시 MVC 매핑을 건너뛰고 직접 파일에 접근합니다.