일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- 타입 변환 string
- 문자 숫자로 변환
- mappedby
- @Transactional
- 배열 크기순
- 숫자를 문자로
- 토큰 자동입력
- 문자열 숫자로
- ? 연산자
- 문자열 추가
- list 최대 최소
- JPQL
- 문자열 요소
- 문자열 소문자
- 문자열 분리 공백
- Spring Security
- N+1
- 배열
- 문자열 숫자
- 배열 리턴
- aop
- pageable
- 문자열 대문자
- 매개변수 배열
- 배열 길이
- 배열 요소추가
- JPA
- Postman
- 배열 정렬
- 문자열 알파벳
- Today
- Total
D.DevLog
백엔드 개발 | 기업용 테스크 관리 시스템 (TaskFlow) | Troubleshooting (1) 본문
기업용 테스크 관리 시스템 (TaskFlow) 백엔드 개발
중 내가 한 일
0) 협업 환경에 맞춰 세팅
1) 댓글 CRUD
2) 병합시, 토큰값에서 userId 가져오는 걸로 수정
3) api 프론트에 맞춰서 수정, 응답형식 통일
4) 예외처리 통일
5) test code 작성
6) Docker로 프론트랑 연결
0) 협업 환경 세팅
팀 규칙 : 새로운 기능 추가시 이슈 브랜치 생성해서 거기서 작업 후 pull request 올려서 팀원들의 코드리뷰와 승인 후 develop 브랜치로 병합하는 방식, commit 할때도 컨벤션에 맞춰서 커밋진행
어려웠던 부분 ) 어떤식으로 동작하는 형태인지 잘 이해가 안됐음
해결 ) 작업을 하면서 계속 물어보면서 이해를 했음
=> 내가 개발하는 이슈는 로컬의 내 이슈브랜치에서 작업 후 develop 브랜치로 병합, 그 후 다른 기능 개발시에는 이 작업을 반복하면 되는데 새로운 이슈 브랜치에서 작업하는 방법은 develop 브랜치를 pull 해 온 다음, 그 내용을 가지고 새로운 브랜치가서 작업.
ex) 댓글 CRUD 기능 구현은 feature/6 브랜치
git fetch origin : 원격 저장소 최신 상태 확인
git branch -r : 원격에 존재하는 브랜치 목록 출력
git checkout -b feature/6 origin/feature/6 : 로컬 feature/6 브랜치로 이동하고 여기에 원격 origin/feature/6 내용을 받아옴
기능 구현 완료
git push origin feature/6 : 원격 저장소(origin)에 로컬 feature/6을 업로드
pull request, 팀원들 코드 리뷰 -> develop 에 머지
원격 develop 에 업로드된 코드들을 다 받아온 후 다음 기능 구현 시
git fetch origin : 원격 저장소 최신상태 확인 후
git checkout -b feature/10 : 현재 로컬 브랜치(feature/6) 코드를 전부 새로운 브랜치(feature/10)을 만들어 거기로 복사
장점 )
브랜치를 분리해서 작업 -> 충돌이 적게 발생
팀원 모두의 승인 없이 머지가 되지 않음 -> 내가 개발할 때 찾아내지 못한 오류 발견 가능, 모르는 부분을 질문하니까 그 부분을 설명하면서 코드 작성자도 개념을 명확히 잡을 수 있음 (코드의 품질 및 정확도 향상)
▼ 적용한 과정
git commit 컨벤션

각자의 작업 후 develop branch 로 merge

코드 리뷰 및 승인 (모든 팀원의 승인 필요) -> develop branch 로 merge

1) 댓글 CRUD - 코드 병합 진행전 + api 수정 전 작업 내용
< api 설계 >
초기 설계) 도메인 중심의 설계
ex. 댓글 생성 : api/comments
개선한 설계) 프론트 중심의 설계
ex. 댓글 생성 : api/tasks/{task_id}/comments
바꾼 이유) 화면에서 요청하는 api 와 맞아야 정확히 호출 가능, 프론트와 연동하는 과정에서 구현할 수 없는 기능 발생 (검색 기능)
상황 ) 로그인 후 인증된 사용자만이 댓글 생성 가능, 아직 로그인 기능 구현 전인데 거기서 파생된 기능을 구현해야 함
의문 ) User 정보를 어디서 가져와?
해결 ) token 을 통해. 이 토큰이 들어온다고 가정하고 controller 에서 가져온다고 생각하고 test 진행,
@Authentication, @AuthenticationPrincipal 로 토큰에서 정보 받아올 수 있음
의문 ) 공통 응답 형식이 있고, 이렇게 api 마다 다른 데이터를 포함한다면 응답이 뭐가 되야 하는지
해결 ) dto 를 두개 만들면 돼. 그리고 제네릭 사용해서 그 데이터를 넣으면 됨
의문 ) 유저 파트 구현전에 작성자를 어떻게 받아오는지
해결 ) 그냥 String 으로 받거나 직접 입력
상황 ) 로그인 파트 코드 리뷰
의문 ) 빌더 패턴이란? 어디에 쓰는 건지? ( 해결 못함 !!! )
해결 ) @Builder 사용해 명시적으로 객체 생성하는 과정
생성자 위, 클래스 위 둘다 가능하지만 가급적 생성자위에 붙여서 명시적으로 표시해줘
@Entity
@Getter
public class Comment{
@Id
@GeneratedValue(strategy = AccessLevel.PROTECTED)
private Long id;
private String content;
// 방법 1. 정적 팩터리 메서드 사용, 생성자 사용
public static of(Long id, String content){
return(new Comment(id, content));
}
// 방법 2. 빌더 패턴 사용
@Builder
public Comment(Long id, String content){
return Comment.builder()
.id(id)
.content(content)
.build();
}
}
클래스에 @Builder 붙일 경우, 외부에서 수정하지 못하게 하기 위해
@Builder(access=AccessLevel.PRIVATE) 이렇게 한정지어주기도 해
< 댓글 조회 파트 - 작업별 댓글 조회 >
의문 ) 컨트롤러에서 task 별 댓글 조회 후 그 값을 CommentResponseDataDto 에 넣어, 이 형식으로 List 를 만들어서 넘기려고 하는데 어떻게 해야하는지?
해결 ) 우선 그 부분은 컨트롤러가 하는게 아니라 서비스에 들어가야 함. 서비스에서 로직 구현.
from 메서드 만들어 Comment 넣으면 원하는 형태로 응답하도록 만들어줘
.stream() : List<Comment> 넣으면 Stream<Comment> 으로 하나씩 요소 처리해줌
.map : stream 각 요소를 다른 형태로 변환할 때
::from : 메서드로 = CommentResponseDataDto.from(Comment)
.collect(Collectors.toList()); : Collectors 을 List 로 바꿔줘
// Controller 부분
List<CommentResponseDataDto> commentResponseDataDtoList = commentService.findAllCommentByTaskId(taskId);
// Service
public List<CommentResponseDataDto> findAllCommentByTaskId(Long taskId){
List<Comment> commentList = commentRepository.findAllByTaskIdOrderByCreatedAtDesc(taskId);
return commentList.stream()
.map(CommentResponseDataDto::from)
.collect(Collectors.toList());
}
// CommentResponseDataDto 부분
public static CommentResponseDataDto from(Comment comment){
return new CommentResponseDataDto(
comment.getUser().getName(),
comment.getContents(),
comment.getCreatedAt(),
comment.getUpdatedAt()
);
}
Q ) 최신순 정렬 하는 법
A ) JPA 활용, orderby~desc
< 댓글 조회 파트 - 내용에 대한 Like 검색 >
Q ) JPA 에서 Like 검색 하는 법
A ) Like 검색 이란 ? SQL 에서 문자열 부분 일치 검색하는거. 패턴 (% 모든 문자, _ 한글자)
ex. select * from table where name like '%커피%' : '커피' 라는 단어가 들어간 것 찾아
JPA 사용시,
방법1.
선언 Repository // List<User> findByContentsLike("%test%")
호출 Service // userRepository.findByContensLike("%test%"). Contents 필드에서 문자열에 test 가 포함된 것 다 찾아
방법2.
선언 Repository // List<User> findByContentsContains("test")
호출 Service // userRepository.findByContentsLike("test")
Q ) api 설계 시에 작업에 달린 댓글과 내용에 관한 검색을 하나로 해야하는지 / 두개 따로 해야하는지?
A ) 두개로 해도 되는데 구현된 화면에서 확인을 해야 함. 어떤식으로 작동하는지 => 구현된 화면은 tasks/{task_id}/comments 이렇게 계층구조로 이루어져 있는걸 확인 후, 일치시킴
Q ) soft delete 로 삭제로직을 구현(삭제시, isDeleted = True)했는데, 조회시에 삭제된 댓글을 제외하는 로직은 어디에 구현하는가?
A ) Service 로직에서 필터링
return commentListById.stream()
.filter(comment -> !comment.getIsDeleted()) // 삭제 안된 것만 통과
.map(CommentResponseDataDto::from)
.collect(Collectors.toList());
Q ) 저기 필터 내부에 comment 라는 객체를 생성하지 않았는데 이렇게 써도 되는지?
A ) filter 의 매개변수는 각 Comment 하나,
왜? stream 요소는 List 안의 항목인데 그 항목이 Comment
< 로그인 기능 구현 후, 코드 리팩토링 >
상황 ) token 을 어떻게 받아올 수 있는지 ?
해결 ) @AuthenticationPrinciple 이용해서 토큰속 정보 추출 가능 (매개변수를 이런식으로 넣으면 돼)
@AuthenticationPrincipal Long userId
상황 ) jwt 구현 후, 병합해서 실행하려고 하는데 오류로 실행이 안됨
해결 ) secret key 오류. 환경변수로 넣어놨는데 길게 안넣어서!
++ ) 오류 찾는 법 : 메세지 위/밑에서 뒷 부분을 읽어야 함. (유의미한 메세지를 찾아야 오류 발견 가능)
상황 ) 회원가입 중 오류
원인 ) 로그인을 구현한 팀원이 security를 사용하지 않는데 나는 security 를 사용해서 의존성에 추가해놓은 것이 문제가 되었음
해결 ) 의존성을 제거하고 @AuthenticationPrinciple 로 가져오던 토큰을 HttpServletRequest 으로 가져와
private final JwtUtil jwtUtil; // 선언
HttpServletRequest httpServletRequest //로 받아와서
Long userId = jwtUtil.extractId(httpServletRequest)
상황 ) 댓글을 생성하는 부분. api 설계 - api/comments
오류 ) task_id cannot be null
생각 ) user 값은 토큰에서 가져오고 task_id 값은 어디서 가져와?
taskRepository 에서 user_id 로 찾아서 task_id 값 가져와야 함. 그런데 한 사용자가 task 를 여러개 작성했다면 어떻게 특정할까?
이렇게 하면 안되고 api 를 수정해야 함 api/tasks/{task_id}/comments 이런식으로
오류 원인 + 해결 ) 도메인 기반 api 를 설계했는데 프론트와 연동을 진행하다보니 도메인 뿐만 아니라 프론트에서 어떻게 구현되어 있는지도 고려해서 구현해야 함. 계층관계가 있는 경우, 이를 나타내줘야 함
< git 관련 >
Q ) 커밋을 취소하고 싶어서 drop commit 눌렀더니 수정내용도 전부 삭제 되었음. 되돌리는 방법은?
A ) git reflog : 기록 찾기
git reset --hard [로그명] : 복구할 시점의 로그명을 입력하면 거기로 복구됨
상황 ) github develop 브랜치의 코드를 로컬 develop 브랜치로 받아와서 내 작업은 feature/6 에서 하려고 함. 코드가 안보임
문제 ) 어떤식으로 브랜치를 관리해서 협업해야 하는지?
해결 ) git develop -> 로컬 feature/6 으로 받아와
git fetch origin : 원격의 최신 상태가 반영되었는지 확인
git rebase origin/develop : 커밋위에 내 작업이 쌓이는 형식
⭐️ 요구 사항 분석 과정 ⭐️
'Project' 카테고리의 다른 글
백엔드 개발 | 기업용 테스크 관리 시스템 (TaskFlow) | 팀 프로젝트 발표 및 배운 내용 (0) | 2025.06.24 |
---|---|
백엔드 개발 | 기업용 테스크 관리 시스템 (TaskFlow) | Troubleshooting (2) (1) | 2025.06.23 |
효율적인 코드 작성 (Spring boot) | N+1 문제 해결, test code 작성하는 법 (0) | 2025.06.13 |
뉴스피드(SNS) 만들기 (Spring boot) | 진행 중 생긴 질문들, 새로 알게된 것들 (4) | 2025.06.12 |
일정 관리앱 (Spring Boot) | 해설 및 예시 코드 확인 후 배운점 _ 서식 수정 필요 (1) | 2025.06.09 |