[블로그 프로젝트] Spring Boot Validation
Spring Boot 에서는 Validation을 통해 데이터의 유효성을 검증할 수 있다. public class SignUpRequestDto { @NotBlank @Email private String email; @NotBlank @Size(min = 8, max = 20) private String password; @NotBlank private String nickname; @NotBlank @Pattern(regexp = "^[0-9]{11,13}$") private String telNumber; @NotBlank private String address; private String addressDetail; @NotNull @AssertTrue private Boolean agreedPe..
2024.03.06
no image
ORM JPA Hibernate Spring Data JPA
이전글 : https://sumjo.tistory.com/6 스프링 부트 Controller, DTO Servlet은 간단히 말하자면 CGI를 개선해서 동적 페이지를 생성해주기 위한 서버 프로그램, 자바 클래스이다. 추후에 다룰 예정이다. 클라이언트에서 요청은 Dispatcher Servlet이 먼저 처리한다. 프론 sumjo.tistory.com ORM(Object-Relational Mapping) 우리가 일반 적으로 알고 있는 애플리케이션 Class와 RDB(Relational DataBase)의 테이블을 매핑(연결)한다는 뜻이며, 기술적으로는 어플리케이션의 객체를 RDB 테이블에 자동으로 영속화 해주는 것이라고 보면된다. 라고 한다. 간단히 말하자면 객체(클래스)와 데이터베이스를 맵핑시켜준다는 뜻..
2024.01.30
no image
Mapping을 인식하지 못할 때(Java VScode Clean)
GetMapping을 해줬지만, postman에서 요청을 보내도 계속 404가 반환됐다. 다른 파일에 테스트 Mapping을 추가해도 마찬가지였다. 오류 찾는 데 상당히 많은 시간을 썼지만, 결론적으로 워크스페이스 오류, 파일을 제대로 인식하지 못했던 것이다. 억울하다. clean cmd + shift + p 혹은 vscode 위 검색창에 > 를 치고 명령어를 입력한다 실행하면 워크스페이스가 정리되고 재실행 된다. 이후 api요청도 성공적으로 반환. 진짜 억울하다.
2024.01.17
no image
[블로그 프로젝트] Response Entity
ResponseEntity 공식문서에 따르면 public class ResponseEntity extends HttpEntity Extension of HttpEntity that adds an HttpStatusCode status code. Used in RestTemplate as well as in @Controller methods. HttpEntity를 상속받아서 HttpStatusCode를 추가하여 HttpRequest에 대한 응답을 포함한 클래스이다. private ResponseEntity(@Nullable T body, @Nullable MultiValueMap headers, Object status) { super(body, headers); Assert.notNull(status,..
2024.01.15
no image
스프링 부트 Controller, DTO
Servlet은 간단히 말하자면 CGI를 개선해서 동적 페이지를 생성해주기 위한 서버 프로그램, 자바 클래스이다. 추후에 다룰 예정이다. 클라이언트에서 요청은 Dispatcher Servlet이 먼저 처리한다. 프론트 컨트롤러 라고도 한다. Dispatcher Servlet은 요청에 매핑된 적절한 Controller를 찾아 요청을 위임한다. 과거엔 Servlet이 web.xml에서 맵핑된 URL을 찾아주어야 했지만, Dispatcher Servlet을 통해 Controller만 적절히 구현해두면 알아서 적절하게 요청을 위임해주게 되었다. // Servlet alias HelloServlet test.servlet.HelloServlet // URL에 필요한 Servlet을 맵핑 시켜준다 // /hello..
2024.01.12
no image
[블로그 프로젝트] 스프링 프로젝트 생성
Spring initializr를 vs code 에서 명령어로 실행가능 하다. 이후에 group id, artifact name 등을 설정해주면 된다. 패키지 dependencies를 설정해준다. 내가 고른 패키지의 간단한 설명 Spring Web(Spring MVC) - web 프로젝트에 필요한 기능 제공, mvc패턴과 request mapping 등 Validation - 어노테이션을 통해 유효성을 검증할 수 있다. (requestBody 등) Spring Security -보안 관련 메소드 제공 Spring Data JPA - Repository 인터페이스를 를 통해 데이터 베이스 CRUD작업 (JPA기반을 더 편하게) MySQL Driver - 이름 그대로 Mysql 데이터베이스 드라이버 Lomb..
2024.01.12

Spring Boot 에서는 Validation을 통해 데이터의 유효성을 검증할 수 있다.

 

public class SignUpRequestDto {

	@NotBlank @Email
	private String email;

	@NotBlank @Size(min = 8, max = 20)
	private String password;

	@NotBlank
	private String nickname;

	@NotBlank @Pattern(regexp = "^[0-9]{11,13}$")
	private String telNumber;

	@NotBlank
	private String address;

	private String addressDetail;

	@NotNull @AssertTrue
	private Boolean agreedPersonal;
}

 

회원가입 요청에 대한 DTO 객체이다.

멤버 변수에 annotaion을 적용하여 유효성 검증을 지정할 수 있다.

  1. @NotBlank: 해당 필드가 null이 아니며, 공백을 제외한 길이가 0보다 커야 함을 나타냅니다. 주로 String 타입에 사용됩니다.
  2. @Email: 해당 필드가 이메일 주소 형식에 맞아야 함을 나타냅니다.
  3. @Size(min = x, max = y): 해당 필드의 크기가 지정된 범위 내에 있어야 함을 나타냅니다. min과 max를 통해 최소값과 최대값을 지정할 수 있습니다.
  4. @Pattern(regexp = "패턴"): 해당 필드가 주어진 정규 표현식에 일치해야 함을 나타냅니다. 여기서는 전화번호가 특정 패턴을 따르도록 강제하고 있습니다.
  5. @NotNull: 해당 필드가 null이 아니어야 함을 나타냅니다. 모든 객체 타입에 사용할 수 있습니다.
  6. @AssertTrue: 해당 필드의 값이 true이어야 함을 나타냅니다. 주로 boolean 타입에 사용되며, 약관 동의 여부 확인 등에 사용될 수 있습니다.
  1. @Min(value): 숫자 필드가 지정된 최소값 이상이어야 함을 나타냅니다.
  2. @Max(value): 숫자 필드가 지정된 최대값 이하이어야 함을 나타냅니다.
  3. @Digits(integer, fraction): 숫자 필드가 가질 수 있는 정수 부분과 소수 부분의 자릿수를 지정합니다.
  4. @DecimalMin(value): 숫자 필드가 지정된 값 이상이어야 함을 나타내며, 소수를 허용합니다.
  5. @DecimalMax(value): 숫자 필드가 지정된 값 이하이어야 함을 나타내며, 소수를 허용합니다.
  6. @Future@FutureOrPresent: 해당 필드의 날짜/시간이 현재보다 미래여야 함을 나타냅니다. @FutureOrPresent는 현재 시간도 유효함을 의미합니다.
  7. @Past@PastOrPresent: 해당 필드의 날짜/시간이 현재보다 과거여야 함을 나타냅니다. @PastOrPresent는 현재 시간도 유효함을 의미합니다.
  8. @Positive@PositiveOrZero: 숫자 필드가 각각 양수이거나 0을 포함한 양수여야 함을 나타냅니다.
  9. @Negative@NegativeOrZero: 숫자 필드가 각각 음수이거나 0을 포함한 음수여야 함을 나타냅니다.
  10. @NotEmpty: 컬렉션, 맵, 배열, 문자열 등이 비어있지 않아야 함을 나타냅니다.

 

RequestBody로 받은 DTO를 서버 사이드에서 @Valid 어노테이션을 통해 유효성을 검증한다

public class AuthController {
	
	private final AuthService authService;
	
	@PostMapping("/sign-up")
	public ResponseEntity<? super SignUpResponseDto> signUp(
		@RequestBody @Valid SignUpRequestDto requestBody
		) {
			ResponseEntity<? super SignUpResponseDto> response = authService.signUp(requestBody);
			return response;
	}	


	@PostMapping("/sign-in")
	public ResponseEntity<? super SignInResponseDto> signIn(
		@RequestBody @Valid SignInRequestDto requestBody
	){
		ResponseEntity<? super SignInResponseDto> response = authService.signIn(requestBody);
		return response;
	}
}

 

 

validation fail은 RestController Advice를 통해 예외 처리를 했다.

 

RestControllerAdvice

여런 컨트롤러에 대해서 전역적인 Exeption Handling을 제공한다.

ControllerAdvie + ResponseBody를 합쳐놓은 형태로, 에러 핸들링 ResponseBody로 핸들링에 대해서 객체로 리턴해줄 수 있다.

@RestControllerAdvice
public class BadRequestExceptionHandler {
	
	@ExceptionHandler({MethodArgumentNotValidException.class, HttpMessageNotReadableException.class})
	public ResponseEntity<ResponseDto> validationExceptionHandler(Exception exception) {
		return ResponseDto.validationFailed();
	}
}

 

이전글 : https://sumjo.tistory.com/6

 

스프링 부트 Controller, DTO

Servlet은 간단히 말하자면 CGI를 개선해서 동적 페이지를 생성해주기 위한 서버 프로그램, 자바 클래스이다. 추후에 다룰 예정이다. 클라이언트에서 요청은 Dispatcher Servlet이 먼저 처리한다. 프론

sumjo.tistory.com

 

ORM(Object-Relational Mapping)

우리가 일반 적으로 알고 있는 애플리케이션 Class와 RDB(Relational DataBase)의 테이블을 매핑(연결)한다는 뜻이며, 기술적으로는 어플리케이션의 객체를 RDB 테이블에 자동으로 영속화 해주는 것이라고 보면된다.

라고 한다.

간단히 말하자면 객체(클래스)와 데이터베이스를 맵핑시켜준다는 뜻이다. 예시를 들어보겠다.

데이터베이스를 맵핑시켜주기 위해서는 데이터 베이스 칼럼과 대응되는 Entity 객체가 필요하다.

@Entity(name="user")
@Table(name="user")
public class UserEntity {
        @Id
        private String email;
        private String password;
        private String nickname;
        private String telNumber;
        private String address;
        private String addressDetail;
        private String profileImage;
        private boolean agreedPersonal;
    }

user table과 대응되는 Entity 객체의 일부이다.

데이터베이스의 칼럼을 다 가지고 있는 객체이다. 즉 한 테이블에 대응되는 객체인 셈이다.

변수명을 바탕으로 대응시키는데, telNumber -> tel_number로 변환돼서 대응이 되기 때문에 데이터베이스 칼럼명을 옳바르게 작성해야 한다.

 

JPA

기본적으로 ORM 표준 명세이다.

JPA는 라이브러리가 아니고 관계형 데이터베이스의 사용 방식을 정의한 인터페이스 모음이다.

때문에 실제로 구현한 구현체가 필요하고 Spring에서 Hibernate가 JPA구현체의 표준처럼 사용된다.

 

Hibernate

JPA가 인터페이스, Hibernate가 인터페이스를 구현한 Class 의 관계라고 볼 수 있겠다.

위에 말했듯이 JPA구현체의 표준처럼 사용되고 있다.

 

Spring Data Jpa

공식 문서에 따르면 JPA 기반 API를 더 사용하기 쉽게 만들어주는 기술이라고 나와있다.

즉 Spring Data JPA 또한 인터페이스 이고, JPA 사용을 더 쉽게 한번 더 감싸 준 것이다. Repository를 제공하여 데이터베이스 접근을 편하게 만들어준다.

예시를 보자.

 

 

 

데이터베이스 접근 순서도이다.

Spring Data JPA 에서 제공하는 Repository를 통해 CRUD메소드를 호출하면

메소드를 구현한 Hibernate가 데이터베이스와 통신한다.

JDBC는 DB CONNECTION과 같은 기본적인 API를 제공하는 인터페이스다.

 

 

 

GetMapping을 해줬지만, postman에서 요청을 보내도 계속 404가 반환됐다.

다른 파일에 테스트 Mapping을 추가해도 마찬가지였다.

오류 찾는 데 상당히 많은 시간을 썼지만, 결론적으로 워크스페이스 오류, 파일을 제대로 인식하지 못했던 것이다. 

억울하다.

 

clean

cmd + shift + p 혹은

vscode 위 검색창에 > 를 치고 명령어를 입력한다

 

실행하면 워크스페이스가 정리되고 재실행 된다.

이후 api요청도 성공적으로 반환.

진짜 억울하다.

 

ResponseEntity

공식문서에 따르면


public class ResponseEntity<T> extends HttpEntity<T>

Extension of HttpEntity that adds an HttpStatusCode status code. Used in RestTemplate as well as in @Controller methods.


 

HttpEntity를 상속받아서 HttpStatusCode를 추가하여 HttpRequest에 대한 응답을 포함한 클래스이다.

private ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, Object status) {
		super(body, headers);
		Assert.notNull(status, "HttpStatus must not be null");
		this.status = status;
}

 

생성자를 보면 body와 headers는 부모 클래스인 HttpEntity의 생성자를 호출하고 있고

ResponseEntity에서 추가된 HttpStatusCode는 멤버 변수를 초기화 해주는 것을 볼 수 있다.

 

Response를 위해 정의한 ResponseDto코드

@Getter
@AllArgsConstructor
public class ResponseDto {
	
	private String code;
	private String message;

	public static ResponseEntity<ResponseDto> databaseError() {
		ResponseDto responseBody = new ResponseDto(ResponseCode.DATABASE_ERROR, ResponseMessage.DATABASE_ERROR);
		return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(responseBody);
	}


	public static ResponseEntity<ResponseDto> validationFailed() {
			ResponseDto responseBody = new ResponseDto(ResponseCode.VALIDATION_FAILED, ResponseMessage.VALIDATION_FAILED);
		return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(responseBody);
	}
}

 

code와 message를 멤버 변수로 가지고 있다.

각자 에러코드와 에러 메세지를 담당한다.

response에 대한 기본 구조(뼈대)라고 볼 수 있다. api요청에 대한 반환값은 모두 ResponseDto를 상속받아서 구현 할것이다.

SignUpResponseDto(예시)

@Getter
public class SignUpResponseDto extends ResponseDto{
	
	private SignUpResponseDto(){
		super(ResponseCode.SUCCESS, ResponseMessage.SUCCESS);
	}

	public static ResponseEntity<SignUpResponseDto> success(){
		SignUpResponseDto result = new SignUpResponseDto();
		return ResponseEntity.status(HttpStatus.OK).body(result);
	}

	public static ResponseEntity<ResponseDto> duplicateEmail(){
		ResponseDto result = new ResponseDto(ResponseCode.DUPLICATE_EMAIL, ResponseMessage.DUPLICATE_EMAIL);
		return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result);
	}

	public static ResponseEntity<ResponseDto> duplicateNickname(){
		ResponseDto result = new ResponseDto(ResponseCode.DUPLICATE_NICKNAME, ResponseMessage.DUPLICATE_NICKNAME);
		return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result);
	}

	public static ResponseEntity<ResponseDto> duplicateTelNumber(){
		ResponseDto result = new ResponseDto(ResponseCode.DUPLICATE_TEL_NUMBER, ResponseMessage.DUPLICATE_TEL_NUMBER);
		return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result);
	}
}

회원가입 요청에 대한 응답 클래스이다.

생성자는 부모 클래스 ResponseEntity의 생성자를 호출해 code와 message를 success로 초기화 한다.

성공시에는 그대로 SignUpResponseDto를 body에 담아 보낸다.

에러가 나면 에러 케이스에 맞게 ResponseDto를 초기화해주고 ResponseDto 그대로 body로 보내준다.

 

postman으로 이미 데이터베이스에 존재하는 이메일을 요청으로 보냈을 때

code와 message에 에러가 반환되는 것을 볼 수 있다.

Servlet은 간단히 말하자면 CGI를 개선해서 동적 페이지를 생성해주기 위한 서버 프로그램, 자바 클래스이다. 추후에 다룰 예정이다.

클라이언트에서 요청은 Dispatcher Servlet이 먼저 처리한다. 프론트 컨트롤러 라고도 한다.

Dispatcher Servlet은 요청에 매핑된 적절한 Controller를 찾아 요청을 위임한다. 과거엔 Servlet이 web.xml에서 맵핑된 URL을 찾아주어야 했지만, Dispatcher Servlet을 통해 Controller만 적절히 구현해두면 알아서 적절하게 요청을 위임해주게 되었다.

 

  // Servlet alias
  <servlet>
  	<servlet-name>HelloServlet</servlet-name>
  	<servlet-class>test.servlet.HelloServlet</servlet-class>
  </servlet>
  
  // URL에 필요한 Servlet을 맵핑 시켜준다
  // /hello 경로로 요청이 오면 HelloServlet으로 요청 위임
  <servlet-mapping>
  	<servlet-name>HelloServlet</servlet-name>
  	<url-pattern>/hello</url-pattern>
  </servlet-mapping>

/hello 경로로 요청이 오면 HelloServlet을 통해 페이지를 제공하는 web.xml의 예시이다.

 

각 레이어 간 데이터 이동은 DTO(Data Transfer Object)를 이용한다.

DTO는 데이터 전송을 위해 getter, setter메소드만 가지고 비즈니스 로직을 가지지 않는 간단한 객체이다.

@Getter
@NoArgsConstructor
@AllArgsConstructor
public class CommentListItem {
	private String nickname;
	private String profileImage;
	private String writeDatetime;
	private String content;
}

댓글에 관한 DTO

 

Controller는 위에서 말했듯이 요청에 대한 처리를 위임받아 적절한 처리를 한 후에 Response, 혹은 패턴에 따라 View에 넘겨주는 비즈니스 로직을 처리하는 객체이다.

@RestController
@RequestMapping("api/v1/auth")
@RequiredArgsConstructor
public class AuthController {
	
	private final AuthService authService;
	
	@PostMapping("/sign-up")
	public ResponseEntity<? super SignUpResponseDto> signUp(
		@RequestBody @Valid SignUpRequestDto requestBody
		) {
			ResponseEntity<? super SignUpResponseDto> response = authService.signUp(requestBody);
			return response;
	}	


	@PostMapping("/sign-in")
	public ResponseEntity<? super SignInResponseDto> signIn(
		@RequestBody @Valid SignInRequestDto requestBody
	){
		ResponseEntity<? super SignInResponseDto> response = authService.signIn(requestBody);
		return response;
	}
	
	
}

회원가입과 로그인에 관한 Controller 예시이다. 

Mapping 어노테이션을 통해 요청, 경로에 대한 맵핑을 하고 그에 따른 처리 코드를 작성한다.

위에서 xml 파일에서 URL 맵핑을 설정하는 과정과 비슷하다고 볼 수 있다.

예시를 살펴보자면

1. 로그인, 또는 회원가입에 필요한 데이터를 DTO 인자로 받는다. (requestBody)

2. service객체의 메소드를 호출해 데이터베이스 작업

3. ResponseEntity로 감싸서 response 반환

위의 그림(client, controller, service, repository) 에서 client <-> controller 까지의 과정이라고 볼 수 있다.

 

다음 글에서 controller 이후 계층에 관해서 작성해보겠다.

Spring initializr를 vs code 에서 명령어로 실행가능 하다.

  이후에 group id, artifact name 등을 설정해주면 된다.

 

패키지 dependencies를 설정해준다.

내가 고른 패키지의 간단한 설명

Spring Web(Spring MVC) -  web 프로젝트에 필요한 기능 제공, mvc패턴과 request mapping 등

Validation - 어노테이션을 통해 유효성을 검증할 수 있다. (requestBody 등)

Spring Security -보안 관련 메소드 제공

Spring Data JPA - Repository 인터페이스를 를 통해 데이터 베이스 CRUD작업 (JPA기반을 더 편하게)

MySQL Driver - 이름 그대로 Mysql 데이터베이스 드라이버

Lombok - 어노테이션을 통해 getter setter등을 편리하게 세팅