-
[Spring] MVC 기본 어노테이션과 Lombok 정리하기Server/Spring MVC 2021. 10. 7. 21:59728x90반응형
Spring 기본적인 어노테이션 정리하기
이번 글에서는
Spring Boot에서 MVC를 사용할 때 자주 사용하는 어노테이션과 Lombok 어노테이션
에 대해서 간단하게 알아보겠습니다.위의 사진은 먼저 Spring Boot로 프로젝트를 만들었을 때 프로젝트 구조에 대한 정리입니다. 보통 view 와 관련된 파일들을
resources
디렉토리 아래에 작업을 하는데요. 대표적으로 jsp가 존재합니다. Spring Boot에서 jsp를 사용하는 법 은 여기를 확인하시면 됩니다. 대략 프로젝트 구조에 대해서 정리가 되었다 가정하고 바로어노테이션들의 특징
에 대해서 알아보겠습니다.@RequestMapping
RequestMapping
은 URI를 Controller의 메소드와 맵핑을 할 때 사용하는 스프링 프레임워크 어노테이션입니다.import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping(value = "spring") public class TestController { @RequestMapping(value = "study", method = RequestMethod.GET) public String test() { return "test"; } }
- 위의 코드 예시라면
http://localhost:8080/spring/study
로 접속하면 위의 메소드가 실행됩니다. - 클래스 위의 RequestMapping은 위와 같이 GET, POST를 지정해서도 사용하지만, 공통경로를 지정하기 위해서 많이 사용합니다.
@GetMapping, @PostMapping, @DeleteMapping, @PutMapping, @PatchMapping
import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController @Slf4j public class TestController { @GetMapping("test") public String test() { return "test"; } }
위에서
RequestMapping
이 공통 경로를 지정하는데 많이 사용된다고 했는데요. 그 이유는 번거롭게 따로 GET, POST 설정을 안해도 되도록GetMapping
와 같은 어노테이션이 등장했기 때문입니다. 즉, GET, POST, PUT, PATCH, DELETE 메소드 역할에 맞게 사용하여 URL 매핑하면 됩니다.여기까지는 아주 무난하고 쉽쥬? Spring Boot와 Spring MVC의 힘으로 아주 편하게 사용할 수 있습니다.
@RequestParam
import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @Slf4j public class TestController { @GetMapping("test") public String test(@RequestParam("name1") String name1, @RequestParam("name2") String name2) { log.info(name1); // lee log.info(name2); // choi return "test"; } }
Request 형식
http://localhost:8080/test?name1=lee&name2=choi
다음 알아볼 어노테이션은
RequestParam
인데요. 여러가지 용도로 사용될 수 있겠지만 대표적으로 위와 같이GET 메소드의 query string을 꺼내올 때
@RequestParam을 사용합니다.RequestPart
RequestPart
는multipart/form-data
형태로 요청이 올 때 사용하는 어노테이션입니다. 즉, 대표적으로 사진 업로드 하는 API에서 많이 사용되는데요.import com.example.ggyunispring.service.S3Service import org.springframework.web.bind.annotation.* import org.springframework.web.multipart.MultipartFile @RequestMapping("/test") @RestController class TestController( private val s3Service: S3Service ) { @PostMapping("/upload") fun uploadTest(@RequestPart("image") multipartFile: MultipartFile) { s3Service.upload(multipartFile) } }
이번에는
Kotlin
으로 MultipartFile 을 받아오는 것을 간단하게 작성해보았습니다.참고로 포스트맨에서
MultipartFile
로 요청하는 방법은 위와 같습니다.RequestParm과 RequestPart 차이는 무엇일까?
RequestParam
과RequstPart
의 차이가 무엇인지 얘기가 종종 나오곤 하는데요. 왜냐면 위의 사진 업로드 예제 코드를 보았을 때RequestPart
가 아닌RequestParam
을 사용해도 코드는 정상적으로 작동을 하기 때문인데요. 그래서 둘의 차이에 대해서 좀 더 알아보았습니다.Note that @RequestParam annotation can also be used to associate the part of a "multipart/form-data" request with a method argument supporting the same method argument types. The main difference is that when the method argument is not a String or raw MultipartFile / Part, @RequestParam relies on type conversion via a registered Converter or PropertyEditor while RequestPart relies on HttpMessageConverters taking into consideration the 'Content-Type' header of the request part. RequestParam is likely to be used with name-value form fields while RequestPart is likely to be used with parts containing more complex content e.g. JSON, XML).
Spring 공식 문서 를 보면 두 어노테이션의 차이를 위와 같이 설명하고 있습니다. 요약하자면
RequestParam
은multipart/form-data
을 받는데 사용할 수 있고 등록된 Converter 또는 PropertyEditor를 통한 형식 변환에 의존한다고 합니다. 반면에RequestPart
는 요청 부분의'Content-Type' 헤더를 고려하는 HttpMessage Converters에 의존
한다는 것입니다.이거만 보면 무슨말이지? 싶기도 한데요. 좀 더 보면
RequestParam
은 name-value form 형태에 좀 더 적합한 거 같고,RequestPart
는 JSON, XML 처럼 복잡한 내용을 포함할 때 사용하는게 더 좋다고 합니다. (제가 사용한 예제 코드는RequestParam
이 더 적절한 거 같습니다!)@RequestBody
import com.example.demo.dto.User; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @Slf4j @RestController public class TestController { @PostMapping("test") public String test(@RequestBody UserRequestDTO userRequestDTO) { log.info(userRequestDTO.getName()); // 이름 log.info(userRequestDTO.getPart()); // 파트 return "test"; } }
Request Body
{ "name" : "이름", "part" : "파트" }
다음으로 알아볼 어노테이션은
RequestBody
입니다. 아주 많이 사용하고 중요한 어노테이션인데요. UserRequestDTO 클래스에 name, part 필드가 존재합니다. @RequestBody는 HTTP Header에application-json
으로 요청이 온다면 내부적으로MessageConverter
중의 json을 객체에 매핑해주는MappingJacksonHttpMessageConverter
가 실행됩니다. (MessageConverter는 여러가지가 있으니 일단은 json에 대해서만 알아두어도 된다 생각하지만 더 궁금하다면 더 찾아보면 될 거 같습니다!)RequestHeader
@RestController @Slf4j public class TestController { @GetMapping("test") public void test(@RequestHeader("token") final String token) { log.info(token); } }
RequestHeader
어노테이션은 HTTP Header 정보를 꺼내는 어노테이션입니다. 예를들어 JWT를 사용한다면 API 인가 요청시 Request Header에 Token을 담아서 요청하는데 이 때 토큰을 HTTP Header에서 꺼내야 할 때 사용할 수 있습니다.PathVariable
import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController @Slf4j public class TestController { @GetMapping("test/{id}") public String test(@PathVariable(value = "id") Long id) { log.info(String.valueOf(id)); return "test"; } }
Request 형식
http://localhost:8080/test/1
PathVariable
도 정말 많이 사용되는 어노테이션인데요. 이 어노테이션은params 값을 가져오는데 사용하는
어노테이션입니다. {id}의 이름과 파라미터 이름이 같다면 value 는 사용하지 않아도 된다. (ex:@PathVariable Long id
)Lombok 정리하기
Java의 코드를 보면 일반적으로 아래와 같이 변수는
private
를 선언하고getter/setter
를 사용하게 됩니다.public class Login { private String id; private String password; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
위와 코드를 보면 Getter/Setter를 직접 작성하고 있습니다. 그런데 만약에 필드가 20개 30개라면 클래스의 길이가 엄청 길어질 것입니다.
또한 필드가 수정되면 메소드를 다시 수정해야 한다는 단점이 존재합니다.이러한 단점을 해결하기 위해서 나온 것이
Lombok
입니다. Lombok은 자바 라이브러리이고,@Data, @Getter, @Setter, @Builder
등등의 다양한 어노테이션을 제공합니다.Gradle (build.gradle)
compileOnly 'org.projectlombok:lombok:1.18.10' annotationProcessor 'org.projectlombok:lombok:1.18.10'
Maven (pom.xml)
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
자신이 사용하는 프로젝트에 맞게 의존성을 추가하겠습니다.
Intellij plugin 설치하기
그리고 intellij에서 lombok을 사용하기 위해 plugin을 설치해주어야 합니다.
Windows : file > Setting > Plugins > 'lombok' 입력 > INSTALL
MacOS : Intellij IDEA > preferences > Plugins > 'lombok' 입력 > INSTALL
lombok 설치가 완료되었으면 Restart Intellij IDEA 버튼이 나오고, intellij를 restart 하겠습니다.
Settings > Build > Compiler > Annotation Processors
로 이동 후, Enable annotation processing을 체크하겠습니다.
이제 lombok에서 제공하는 몇가지 어노테이션에 대해 정리해보겠습니다.
1. @Data
import lombok.Data; @Data public class User { private int userIdx; private String name; private String part; }
위와 같이 User 클래스에
@Data
라는 어노테이션을 추가해주면 아래와 같이 메소드들이 생기는 것을 알 수 있습니다. 따라서 어노테이션 하나만으로 아래의 메소드를 사용할 수 있습니다. 하지만 일반적으로@Data
어노테이션은 현재 사용하지 않는 많은 메소드를 만들기 때문에 사용을 지양하는 것이 좋습니다.2. @NoArgsConstructor
@NoArgsConstructor public class User { private int userIdx; private String name; private String part; public User(int userIdx, String name, String part) { this.userIdx = userIdx; this.name = name; this.part = part; } }
자바에서는 매개변수가 있는 생성자가 존재하면 기본 생성자는 자동으로 만들어주지 않게 되는데요. 이럴 때 직접 기본 생성자를 만드는 것이 아니라
@NoArgsConstructor
어노테이션을 사용하여 기본 생성자를 만들 수 있습니다.3. @AllArgsConstructor
@Data @AllArgsConstructor public class User { private int userIdx; private String name; private String part; }
위의 코드처럼 직접 모든 필드가 들어간 생성자를 만들어 줄 필요 없이
@AllArgsConstructor
를 사용하면 모든 필드가 들어간 생성자를 만들어줍니다.4.
@RequiredArgsConstructor
import lombok.RequiredArgsConstructor; import lombok.NonNull; @RequiredArgsConstructor public class User { private final int userIdx; @NotNull private String name; private String part; }
@RequiredArgsConstructor
는 아주 많이 사용되는 어노테이션인데요. final이 붙은 필드와 @NotNull가 존재하는 필드로 생성자를 만들어주는 역할을 합니다. 위의 예시라면 userIdx, name을 매게변수로 하는 생성자를 만들어 줄 것입니다.5. @Slf4j
로그를 출력하기 위해서 알고리즘 풀 때는 System.out.println()을 사용했겠지만 실제 개발 환경에서는 사용하면 안되는 메소드인데요. Spring에서는
@Slf4j
나 다른 logger를 사용하여 로그를 출력할 수 있습니다.import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController @Slf4j public class TestController { @GetMapping("/test") public String test() { log.info("로그입니다"); return "test"; } }
위와 같이 log.info()를 사용하여 로그를 출력한다. (log.error(), log.debug() 다양하게 사용할 수 있습니다.)
6. @Builder란?
Builder 패턴에 대해서 모른다면 여기 를 참고해도 좋을 거 같습니다. 빌더 패턴은
Effective Java 아이템 2
에도 나오는 내용입니다. 자바에서 유용하게 많이 사용될 수 있는 패턴인데요. 이거를 직접 구현한다면 꽤나 복잡한 코드를 작성해야 하지만 어노테이션 하나로 편리하게 사용할 수 있습니다.사용법의 예시는 위와 같이 사용할 수 있는데요. 클래스 전체에 사용할 수도 있고, 생성자를 만들어서 그 생성자에서만 사용할 수도 있습니다.
그 외적으로
Getter
,Setter
등등 있지만 이름에서도 쉽게 어떤 것인지 알 수 있기에 단순한 것들을 생략하겠습니다!반응형'Server > Spring MVC' 카테고리의 다른 글
[Spring] MVC 동작 방식 디버깅을 통해 알아보기 (0) 2021.10.23 [Spring] MVC HttpSession, Interceptor, Cookie 정리하기 (0) 2021.10.20 [Spring] @Valid를 이용해 @RequestBody DTO 검증하기 (1) 2021.10.12 [Spring] 스프링 웹 계층이란? (6) 2020.08.26 [Spring] @MVC와 DispatcherServlet에 대해서 (0) 2020.07.25 - 위의 코드 예시라면