if (insertRequest == null){
throw new RootException(ApiStatusCode.BAD_REQUEST, "잘못된 정보입니다.");
}
2차. 입력값의 이상유무
BidingResult를 사용하여 최초의 Request값에 대한 검증을 한다.
Request객체의 검증 어노테이션을 활용한다.
@NotNull, @NotBlank, @NotEmpty, @Size, @Min, @Max 등
if (bindingResult.hasErrors()) {
log.info("BindingResult hasErrors");
throw new RootException(ApiStatusCode.BAD_REQUEST, "잘못된 정보입니다.");
}
3차. Service 계층 세부 내용검증
if (insertRequest.getStartDt().compareTo(insertRequest.getEndDt()) >= 1) {
//0이면같음, 음수면 정상
throw new RootException(ApiStatusCode.BAD_REQUEST, "노출 시작 일자가 종료 일자 보다 늦을 수 없습니다.");
}
Spring을 사용하며 @RequestParam, @RequestBody, @ModelAttribute 3가지 어노테이션을 활용하였다.
대충 어떻게 사용하는지는 알지만 한번 정리의 필요성을 느꼈다. 정리 고고
@RequestParam
public String getTest(@RequestParam("name") String name){
System.out.println(name);
}
@RequestParam은 1개의 HTTP 요청 파라미터를 받기위해서 사용한다.
- value
- defaultValue
- required = true(기본설정 true / )false 설정가능
required = false 설정을 하지않고 파라미터를 전송하지않을시 400 에러가 발생한다.
@RequestBody
public String getTest(@RequestBody Test test){
System.out.println(test);
}
Json형태의 HTTP Body내용을 Java 객체로 변환시켜주는 역할을 한다.
Get과 Post 방식 모두 사용은 가능하지만, @RequestBody는 Body안에 Json을 포함해야한다.
하지만 Get은 QueryParameter방식으로 보내기때문에 Get은 Get답게 Post는 Post답게 사용해야한다.
@ModelAttribute
@Getter
@Setter
public class TestDto {
private String name;
private int age;
}
public class TestController {
@RequestGetMapping(value = "/hi")
public void getTest(@ModelAttribute("test") TestDto test){
System.out.println("이름 : " + test.getName());
System.out.println("나이 : " + test.getAge());
}
}
@ModelAttribute는 Form형태 기반의 요청들을 받는다. Get Post 둘다 사용가능하다. Get의 경우는 Query Parameter로 요청데이터를 보내고, Post의 경우 x-www-from-urlencoded형태로 요청데이터를 보낸다.단, DTO에 바인딩시 Setter를 통해 바인딩된다. Setter가 없으면 바인딩되지않음!
@Transactional JPA를 활용한 프로젝트를 개발하였지만, 깊이 있는 이해도는 없었다. 명확하게 설명하지 못한다면,
제대로 알고있는게 아니라 생각한다. 공부내용 정리글이다.
Transactional 정의
데이터베이스에서 트랜잭션은 데이터베이스 관리 시스템 또는 유사한 시스템에서 상호작용의 단위이다.
여기서 단위는 더이상 쪼개질 수 없는 최소의 연산이다.
Transactional 특징
원자성(Atomicity): 트랜잭션의 모든 작업이 완전히 성공하거나 완전히 실패하는 단일 단위로 처리되도록 보장하는 능력이다. 중간 단계까지 실행되고 실패하는 일이 없도록 하는 것이다.
일관성(Consistency): 각 데이터 트랜잭션이 데이터베이스를 일관성 있는 상태에서 일관성 있는 상태로 이동해야 함을 의미한다. 즉, 트랜잭션이 성공적으로 완료하면 언제나 동일한 데이터베이스 상태로 유지하는 것을 의미한다.
격리성(Isolation): 트랜잭션을 수행 시 다른 트랜잭션의 연산 작업이 끼어들지 못하도록 보장하는 것을 의미한다. 이것은 트랜잭션 밖에 있는 어떤 연산도 중간 단계의 데이터를 볼 수 없음을 의미한다. 즉, 데이터베이스는 스트레스 테스트를 통과해야 한다. 과부하로 인해 잘못된 데이터베이스 트랜잭션이 발생하지 않아야 한다.
지속성(Durability): 성공적으로 수행된 트랜잭션은 영원히 반영(기록)되어야 함을 의미한다. 트랜잭션은 로그에 모든 것이 저장된 후에만 commit 상태로 간주 될 수 있다. 데이터베이스내의 데이터는 트랜잭션의 결과로만 변경되어야 하며, 외부 영향에 의해 변경 될 수 없어야 한다.
데이터베이스 트랜잭션 처리에 있어서 중요한 요소이며, 데이터베이스가 제공하는 일관성과 안정성을 보장합니다.
Servlet => Spring => Spring Boot 순서로 공부를하며 DTO와 Entity의 차이점은 간략하게 파악하였다.
하지만 DTO와 VO는 어떠한 차이점이 있을까?
여러 참고 사이트를 비교하며 정리해본다.
DTO(Data Transfer Object)
DTO는 데이터를 전달하기 위한 객체이다. 계층간의 Getter / Setter를 이용하여 데이터를 주고 받는다.
여러 레이어에서 사용할 수 있지만, 주로 View와 Controller사이에서 사용한다.
DTO는 Getter / Setter 메소드를 포함하고, 그 외의 비즈니스 로직은 포함하지 않는다.
EX)
public class MemberDto {
private String name;
private int age;
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;
}
}
Setter가 아닌 생성자를 이용해서 초기화하는 경우 불변 객체로 활용 할 수 있다. 불변 객체로 만들시 데이터를 전달하는 과정에서 데이터가 변조되지 않는다.
public class MemberDto {
private final String name;
private final int age;
public MemberDto(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
VO(Value Object)
VO는 값 자체를 표현하는 객체이다. VO는 객체들의 주소가 달라도 값이 같으면 동일한것으로 여긴다.
EX) 고유번호가 다른 만원 2장이 있다. 이 둘은 고유번호(주소)는 다르지만 값(10,000원)은 동일하다.
VO는 Getter 메소드와 함께 비즈니스 로직도 포함 할 수 있다. 단, Setter 메서드는 포함하지 않고, 값의 비교를 위해
equals()와 hashCode() 메소드를 오버라이딩 해줘야한다.
public class Money {
private final String currency;
private final int value;
public Money(String currency, int value) {
this.currency = currency;
this.value = value;
}
public String getCurrency() {
return currency;
}
public int getValue() {
return value;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Money money = (Money) o;
return value == money.value && Objects.equals(currency, money.currency);
}
@Override
public int hashCode() {
return Objects.hash(currency, value);
}
}
// MoneyTest.java
public class MoneyTest {
@DisplayName("VO 동등비교를 한다.")
@Test
void isSameObjects() {
Money money1 = new Money("원", 10000);
Money money2 = new Money("원", 10000);
assertThat(money1).isEqualTo(money2);
assertThat(money1).hasSameHashCodeAs(money2);
}
}
EX) equals()와 hashCode() 메서드를 오버라이딩 하지 않았을 때
EX) equals()와 hashCode() 메서드를 오버라이딩 하였을 때
Entity
Entity는 실제 DB 테이블과 매핑되는 핵심 클래스이다. 이를 기준으로 테이블이 생성되고 스키마가 변경된다.
따라서, 절대로 Entity를 요청이나 응답값을 전달하는 클래스로 사용해서는 안된다.
그리고 비즈니스 로직을 포함할 수 있다.
public class Member {
private final Long id;
private final String email;
private final String password;
private final Integer age;
public Member() {
}
public Member(Long id, String email, String password, Integer age) {
this.id = id;
this.email = email;
this.password = password;
this.age = age;
}
}