@RequestBody는 클라이언트가 전송하는 Http 요청의 Body내용을 Java Object로 변환시켜주는 역할을 한다. 그렇기 때문에 Body가 존재하지 않는 Get 방식의 메소드에 @RequestBody를 활용하는 것은 적합하지 않으므로, 에러가 발생하게 된다. 즉, @RequestBody는 반드시 Post 요청과 함께 사용되어야 한다. @RequestBody는 Json이나 XML과 같은 형태의 데이터를 Jackson 등의 MessageConverter를 활용하여 Java Object로 변환한다. 이러한 성질은 Parameter로 받은 데이터들을 자바 객체로 1대1로 매킹시켜주는 @ModelAttribute와 차이가 있다. 즉, @RequestBody는 POST방식으로 Json의 형태로 넘겨온 데이터를 객체로 바인딩하기 위해 사용할 수 있다
@ModelAttribute는 클라이언트가 전송하는 여러 파라미터들을 1대1로 객체에 바인딩하여 다시 View로 넘겨서 출력하기 위해 사용되는 오브젝트이다. @ModelAttribute에는 매핑시키는 파라미터의 타입이 객체의 타입과 일치하는지를 포함한 다양한 검증(Validiation) 작업이 추가적으로 진행된다. 예를 들어 게시물의 번호를 저장하는 int형 index 변수에 "1번" 이라는 String형을 넣으려고 한다면, BindException이 발생하게 된다. @RequestBody의 경우에는 Json이나 XML을 Jackson과 같은 MessageConverter를 사용하여 변환시키는 반면에, @ModelAttribute는 여러 개의 파라미터를 바로 자바빈 객체로 매핑시킨다는 차이가 있다. 그렇기 때문에 @ModelAttribute는 JSP에서 Form 태그를 통해 전달받은 파라미터들을 객체로 바인딩 시키는 경우에 사용할 수 있다.
@ModelAttribute와 @RequestBody를 보다 극단적으로 설명하자면, @ModelAttribute는 바인딩시키는 어떤 데이터를 set해주는 Setter함수가 없다면 매핑이 되지 않는다. 하지만 @RequestBody는 요청받은 데이터를 변환시키는 것이기 때문에, Setter함수가 없어도 값이 매핑이 된다.
@RequestParam은 요청 파라미터를 메소드에서 1:1로 받기 위해서 사용한다. @RequestParam은 필수 여부가 true이기 때문에 기본적으로 반드시 해당 파라미터가 전송되어야 한다. 해당 파라미터가 전송되지 않으면 400 Error를 유발하게 된다. 그렇기 때문에 반드시 필요한 변수가 아니라면 required의 값을 false로 설정해둘 수 있으며 해당 Parameter를 사용하지 않고 요청을 보낼 경우에 default로 받을 값을 defaultValue 옵션을 통해 설정할 수도 있다.
import com.ku.mha.journal.app.board.model.BoardVO;
import com.ku.mha.journal.app.board.service.BoardService;
import com.ku.mha.journal.app.issue.model.IssueVO;
import com.ku.mha.journal.app.issue.service.IssueService;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.List;
@Controller
@RequestMapping(value = "/board")
@Log4j2
public class BoardController {
@Resource(name = "boardService")
private BoardService boardService;
@PostMapping(value = "/requestBody")
public ResponseEntity requestBody(@RequestBody BoardVO boardVO){
// @RequestBody는 Json으로 받은 요청을 MessageConverter를 통해 Java 객체로 변환시킨다.
log.info(boardVO.getContents());
return ResponseEntity.ok(boardService.add(boardVO));
}
@PostMapping(value = "/modelAttribute")
public String modelAttribute(Model model, @ModelAttribute BoardVO boardVO){
// @ModelAttribute는 Form태그를 통해 전송받은 파라미터들을 Java 객체로 매핑시킨다.
// 만약 boardVO에 contents에 대한 Setter함수가 없다면 매핑을 시키지 못하고, 항상 null을 갖게 된다.
log.info(boardVO.getContents());
model.addAttribute("boardVO", boardService.add(boardVO));
return "/views/board/detail";
}
@GetMapping(value = "/list")
public ResponseEntity requestParam(@RequestParam(value = "searchKeyWord1", required = false) String searchKeyWord1, @RequestParam(value = "writer", defaultValue = "MangKyu") String searchKeyWord2){
List<BoardVO> boardList;
// searchKeyWord1는 required가 false이기 때문에 없을 수도 있다.
if(searchKeyWord1 != null){
boardList = boardService.findAllBoardBySearchKeyWord(searchKeyWord1);
} else {
boardList = boardService.findAllBoard();
}
// 반면에, searchKeyWord2는 required가 true이기 때문에 반드시 요청 파라미터로 존재해야 한다.
log.info(searchKeyWord2);
return ResponseEntity.ok(boardList);
}
}
Transaction은 2개 이상의 쿼리를 하나의 커넥션으로 묶어 DB에 전송하고, 이 과정에서 에러가 발생할 경우 자동으로 모든 과정을 원래대로 되돌려 놓습니다. 이러한 과정을 구현하기 위해 Transaction은 하나 이상의 쿼리를 처리할 때 동일한 Connection 객체를 공유하도록 합니다.
일반적으로 Spring에서는 Service Layer에서 @Transactional 을 추가하여 Transaction 처리를 합니다. 아래의 예시는 상점과 관련된 Service 부분이고, 데이터의 조회만 일어나는 select 메소드에서는 @Transactional 을 활용하고 있지 않지만, 값을 추가하거나 변경 또는 삭제하는 insert, update, delete 메소드에는 @Transactional을 추가하여 트랜잭션을 설정할 수 있다.
@Controller
: Presentatiton Layer
: 요청과 응답을 처리해주는 클래스
@Service
: Service Layer
: 비즈니스 로직을 담당하는 클래스
@Repository
: Persistence Layer
: DB에 액세스하는 클래스에 사용
@RestController
: @Controller + @ResponseBody
: 메서드의 반환 결과를 JSON 형태로 반환
@RequestMapping
: 요청 URL을 어떤 메서드가 처리할 것인지 매핑
@Bean
: 개발자가 직접 제어 불가능한 외부 라이브러리를 Bean으로 등록하기 위해 사용
@Component
: 개발자가 직접 작성한 클래스를 Bean으로 등록하기 위해 사용
@Autowired
: 생성자나 setter 메서드없이 의존성을 주입해 자동으로 객체 생성
@Configuration
: 해당클래스가 환경설정 관련 파일
: 해당 클래스에 정의된 @Bean이 적용된 메서드는 @Autowired를 통해 부를 수 있음
@ConfigurationProperties
: 프로퍼티 파일을 읽어와서 해당 값을 사용할 수 있게 만듬
@Transactional
: 해당 클래스 또는 메서드에 트랜잭션 적용
: DB에 액세스하는 여러 연산들을 하나의 트랜잭션으로 처리해 오류가 발생하면 자동으로 롤백
: 보통 Service
@ExceptionHandler
: 컨트롤러단에서 발생하는 예외를 잡아서 처리해주는 메서드에 사용(컨트롤러 메서드에 사용하는 어노테이션)
: 어노테이션 인자로 전달된 에외를 처리
@ControllerAdvice
: @Controller나 @RestController에서 발생한 예외를 한 곳에서 처리할 수 있도록 도와주는 어노테이션
: 컨트롤러를 보조하는 클래스에 사용하는 어노테이션
: 컨트롤러에서 쓰이는 공통기능들을 모듈화하여 전역으로 사용
: 전역에서 발생하는 예외들을 잡아 처리해주는 클래스
@SpringBootApplication
: @Configuration, @EnableAutoConfiguration, @ComponentScan 어노테이션이 뭉침
@Builder
: 모델 객체를 생성할 때 Builder를 자동으로 추가
: @Builder를 사용한 경우 build()시 설정하지 않으면 0/null/false가 됨
-> @Builder.Default : 디폴트값 지정(각 멤버변수)