강의

멘토링

커뮤니티

요절복통 블로그 API 만들기 기본

데이터 검증-1

팁: 3번이상 반복작업 = 잘못하고 있나?

if(result.hasErrors()){
List<FieldError> fieldErrors = result.getFieldErrors();
FieldError firstFieldError = fieldErrors.get(0);
String fieldName = firstFieldError.getField(); // title
String errorMessage = firstFieldError.getDefaultMessage(); //..에러메시지

Map<String, String> error = new HashMap<>();
error.put(fieldName, errorMessage);
return error;
}
.andExpect(jsonPath("$.title").value("타이틀을 입력해주세요."))

https://ykh6242.tistory.com/entry/MockMvc%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-REST-API%EC%9D%98-Json-Response-%EA%B2%80%EC%A6%9D

데이터 검증-2

@ControllerAdvice

https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc

Binding Result 삭제

일단 400 => 이후에는 뭐 다른걸로

오류 정하는법

/**
* {
* "code" : "400",
* "message": "잘못된 요청입니다.",
* "validation":{
* "title": "값을 입력해주세요"
* }
* }
*/
public class ErrorResponse {

private final String code;
private final String message;
}

요런 느낌으로 개선해 보자

private Map<String, String> validation = new HashMap<>();
public void addValidation(String fieldName, String errorMessage) {
ValidationTuple tuple = new ValidationTuple(fieldName, errorMessage);
this.validation.put(fieldName, errorMessage);
}

@RequiredArgsConstructor
private class ValidationTuple{
private final String fieldName;
private final String errorMessage;
}

문제가 있다.

변경의 여지가 너무 많다.

작성글 저장 1 - 게시글 저장 구현

필드 인젝션은 test 케이스 말고는 거의 안쓴다.

원인 = WebMvcTest

간단한 테스트에는 괜찮다.그러나 이제는 적합하지 않다.

 영향이 가지 않도록 짜는것이 중요하다.

작성글 저장 2 - 클래스 분리

ObjectMapper objectMapper = new ObjectMapper();
String s = objectMapper.writeValueAsString(request);

순서 바꾸면 망한다.

@Builder
public PostCreate(String title, String content) {
this.title = title;
this.content = content;
}
public PostCreate changeTitle(String title){
return PostCreate.builder()
.title(title)
.content(this.content)
.build();
}

게시글 조회 2 - 응답 클래스 분리

요구사항 추가.

이런 처리는 클라에서 한다.

특정 기능이 추가 됬을때 10글자 정책과 충돌 할수 있다.

이런 조건 케이스에 대한 테스트를 진행하는게 좋지만 그건 알아서하세요.

여기서 하는게 맞냐

인원이 없으면 레이어를 줄여라.

게시글 조회 3 - 게시글 여러개 조회

oprimizer 설정

https://stackoverflow.com/questions/51934322/how-to-get-the-length-of-a-json-array-using-jsonpath

Matchers.is(T value) org.hamcrest

2개다 해주는게 좋은데 생략

게시글 조회 4 - 페이징 처리

https://kim-jong-hyun.tistory.com/31

https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/Pageable.html

한번 읽어봐라.

public List<PostResponse> getList(Pageable pageable){

size 잘 안씀

게시글 조회 5 - 페이징 처리 (QueryDSL)

implementation "com.querydsl:querydsl-core"
implementation "com.querydsl:querydsl-jpa"

annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa" // querydsl JPAAnnotationProcessor 사용 지정
annotationProcessor "jakarta.persistence:jakarta.persistence-api" // java.lang.NoClassDefFoundError(javax.annotation.Entity) 발생 대응
annotationProcessor "jakarta.annotation:jakarta.annotation-api" // java.lang.NoClassDefFoundError (javax.annotation.Generated) 발생 대응

변경사항 :

화면과 내 테스트 케이스 변수가 다름.

반포자이 -> foo, bar

게시글 수정

파라미터가 많아 질수 잇다.

문제점이 있다.

if(postEdit.getTitle() != null){
editorBuilder.title(postEdit.getTitle());
}
if(postEdit.getContent() != null){
editorBuilder.content(postEdit.getContent());
}
PostEditor postEditor = editorBuilder.build();
@Builder
public PostEditor(String title, String content) {
this.title = title != null ? title : this.title;
this.content = content != null ? content : this.content;
}

오류&해결 : jakson 생성자 오류남. 그래서 객체 수정

@Setter
@Getter
@ToString
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class PostEdit {

@NotBlank(message = "타이틀을 입력하세요.")
private String title;

@NotBlank(message="콘텐츠를 입력해주세요.")
private String content;

@Builder
public PostEdit(String title, String content) {
this.title = title;
this.content = content;
}
}

org.springframework.http.converter.HttpMessageConversionException
nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of  'PostEdit' 
(no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

예외처리1

상수로 만들어서 양쪽에 적용되게 했었다.

예외처리2

@JsonInclude(value=JsonInclude.Include.NON_EMPTY)

선호하지 않는 이유 : 

비어있음으로 유추 가능하다.

수십 가지로 늘어남

향후를 대비하면 int로 해두는게 좋다.

스프링에서 제공해주는 것은 저렇게 따로 만든다.

비즈니스용은 하나의 메소드에서 따로

이렇게 꺼내오고 검증하는거 하지마

if 문이 많아 질수 있다.

오류발생: 

@DisplayName("/posts 요청시 title값은 필수다.")

해결 : 

ErrorResponse response = ErrorResponse.builder()
.code("400")
.message("잘못된 요청입니다.")
.validation(new HashMap<>())
.build();

문서화

Spring REST Docs1 - 기본설정

글이 없어서 그런가

Spring REST Docs2 - 요청, 응답필드


asciidoctor.doFirst{
delete file("src/main/resources/static/docs")
}

Spring REST Docs3 - 커스터마이징

단축키 : ctrl + G 같은 글자 선택

단축키 : 하단창 command + 4

그냥 빌드만 누르자

Git

Github SSH 설정, 프로젝트 올리기

단축키 : ctrl + L 화면 클리어

메모리에 복사 : 

cat ~/.ssh/id_rsa.pub | pbcopy

두개 선택하면 commit 이 된채로 시작해서 깃과 프로젝트가 싱크가 안맞는다.

Git 자주쓰는 명령어 예제

단축키: 문장 단위 지우기 control + w