Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] 2주차 과제 제출 #4

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.sopt.week_2_remind.controller;

import lombok.RequiredArgsConstructor;
import org.sopt.week_2_remind.service.MemberCreateDto;
import org.sopt.week_2_remind.service.MemberFindDto;
import org.sopt.week_2_remind.service.MemberService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.net.URI;
import java.util.List;

@Transactional
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/member") //어디로 요청이 들어올거냐?를 보는 것.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rest api에서 리소스는 복수형을 쓰는 것을 더 선호한다고 알고 있습니다!

public class MemberController {
private final MemberService memberService;

@PostMapping
public ResponseEntity postMember(@RequestBody MemberCreateDto memberCreate){
return ResponseEntity.created(URI.create(memberService.createMember(memberCreate))).build();
//createMember가 MemberService의 함수이다.
}

@GetMapping("/{memberId}")
public ResponseEntity<MemberFindDto> findMemberById(@PathVariable Long memberId){
return ResponseEntity.ok(memberService.findMemberById(memberId));
//findMemberById가 MemberService의 함수이다.
}

@DeleteMapping("/{memberId}")
public ResponseEntity deleteMember(@PathVariable Long memberId){
memberService.deleteMemberById(memberId); //deleteMemberById가 MemberService의 함수이다.
return ResponseEntity.noContent().build();
/*
클라이언트에게 반환할 데이터가 없으므로, HTTP 상태 코드 204(No Content)를 함께 응답한다.
이는 요청이 성공적으로 처리되었지만 응답으로 반환할 데이터가 없음을 나타낸다.
*/
}

//기존 세미나 코드에서 이 부분 추가
@GetMapping("/memberList")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

위에서 언급드린 것과 같이
GET /api/v1/members라고 하면
전체 멤버 조회api에서
GET /api/v1/member/memberList라고 할 필요가 없을 것 같습니다.
이미 members라는 복수형에 멤버들을 갖고오겠다는 의미가 포함된 것이니까용
rest에 대해 한번 알아보시는 것을 추천드립니다!!

public ResponseEntity<List<MemberFindDto>> findAllMembers() {
try {
List<MemberFindDto> members = memberService.findAllMembers();
return ResponseEntity.ok(members);
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
}
}
Comment on lines +47 to +54

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 부분에서는 굳이 예외를 잡을 필요가 없을 것 같습니당
멤버리스트를 검색을 했는데 결과가 없어서 빈리스트를 반환하는 것은 자연스러운 일이니까요

Comment on lines +46 to +54
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

재연님이 이미 언급해주셨지만, 저 또한 이 부분은 굳이 예외 처리를 할 필요는 없을 것 같다는 의견에 동의합니다.


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.sopt.week_2_remind.controller;

import org.sopt.week_2_remind.controller.dto.ApiResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/*
* 이 컨트롤러는 /test 경로로 들어오는 GET 요청에는 "test API" 문자열을 반환하고,
* /test/json 경로로 들어오는 GET 요청에는 JSON 형식의 응답을 반환
*/

@RestController
@RequestMapping("/test")
public class TestController {

@GetMapping
public String test(){
return "test API";
}

@GetMapping("/json")
public ApiResponse testJson(){
return ApiResponse.create("test API with JSON");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.sopt.week_2_remind.controller.dto;

import lombok.AllArgsConstructor;
import lombok.Getter;

/*
JSON 통신을 해야 하므로, 이 클래스를 활용하여 JSON 객체를 만드는 것이다.
리스폰스 객체의 필드에 접근해야하기 때문에 @Getter 어노테이션이 없으면 통신이 되지 않음.
*/
@AllArgsConstructor //생성자 자동으로 생성해줌
@Getter
public class ApiResponse {
private String content;

public static ApiResponse create(String content){
return new ApiResponse(content);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.sopt.week_2_remind.domain;

import jakarta.persistence.*;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.net.PasswordAuthentication;

@Entity
@Getter
@NoArgsConstructor
public class Member {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

private String name;

@Enumerated(EnumType.STRING)
private Part part;
private int age;

//@Builder 애노테이션 붙임으로써 그냥 빌더패턴과 같아짐
@Builder
private Member(String name, Part part, int age){
this.name=name;
this.part=part;
this.age=age;
}

//이거와 같아진 것! 편한거 골라서 쓰면 된다.
public static Member create(String name, Part part, int age){
return Member.builder()
.name(name)
.part(part)
.age(age)
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.sopt.week_2_remind.domain;

public enum Part {
IOS,
SERVER,
ANDROID,
PLAN,
WEB,
DESIGN;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.sopt.week_2_remind.repository;

import org.sopt.week_2_remind.domain.Member;
import org.springframework.data.jpa.repository.JpaRepository;

public interface MemberRepository extends JpaRepository<Member,Long> {
/*
JPA에서 기본적으로 delete, get 이런거 제공해줌..
DB에서 자체적으로 생성해주는 ID로 찾고, 지우고 이런거 하는듯
*/
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.sopt.week_2_remind.service;

import org.sopt.week_2_remind.domain.Part;

/*
- 자동으로 접근자 메서드(getter)가 생성된다.
- 레코드는 equals(), hashCode(), toString() 메서드가 자동으로 생성
- 레코드는 불변(immutable)하며, 한 번 생성되면 내부 상태를 변경할 수 없습니다.
- 필드를 final로 선언하여 보장
*/
public record MemberCreateDto(String name, Part part, int age) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.sopt.week_2_remind.service;

import org.sopt.week_2_remind.domain.Member;
import org.sopt.week_2_remind.domain.Part;

public record MemberFindDto(String name, Part part, int age) {
/*
이 메서드는 Member 객체를 인자로 받아서
해당 객체의 정보를 사용하여 MemberFindDto 인스턴스를 생성합
*/
public static MemberFindDto of(Member member){
return new MemberFindDto(member.getName(), member.getPart(), member.getAge());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.sopt.week_2_remind.service;

import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import org.sopt.week_2_remind.domain.Member;
import org.sopt.week_2_remind.repository.MemberRepository;
import org.springframework.core.SpringVersion;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class MemberService { //Service 에는 비즈니스 로직을 구현한다.

private final MemberRepository memberRepository;

@Transactional
public String createMember(MemberCreateDto memberCreate){ //포스트맨에서 POST로 멤버 생성 가능
Member member = memberRepository.save(Member.create(memberCreate.name(), memberCreate.part(), memberCreate.age()));
return member.getId().toString();
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@transactional(readonly=true)붙이시는 것을 추천드립니다!

public MemberFindDto findMemberById(Long memberId){ //ID를 기준으로 Member 찾기
Member member = memberRepository.findById(memberId).orElseThrow(
() -> new EntityNotFoundException("ID에 해당하는 사용자가 존재하지 않습니다."));
return MemberFindDto.of(member);
}

@Transactional
public void deleteMemberById(Long memberId){ //ID를 기준으로 Member 를 삭제
Member member = memberRepository.findById(memberId).orElseThrow(
()->new EntityNotFoundException("ID에 해당하는 사용자가 존재하지 않습니다."));
memberRepository.delete(member);
}

//기존 세미나 코드에서 이 부분 추가

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 마찬가지로 readonly=true해주세용

public List<MemberFindDto> findAllMembers() {
try {
return memberRepository.findAll().stream()
.map(MemberFindDto::of)
.collect(Collectors.toList());
} catch (Exception e) {
e.printStackTrace();
return null;
}
Comment on lines +40 to +49

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

위에서 언급드린 것과 마찬가지로 굳이 예외를 잡을 이유 없을 것 같습니다~

}
}