본문 바로가기
미니프로젝트

1. 익명의 메모장 - 서버구축 (스프링부트)

by DDveloper 2021. 3. 21.

클라이언트와 서버와 DB로 구성된 웹서비스의 기본 구성

  • API - 은행 창구의 개념 / 원하는 요청에 따른 응답 (생성, 조회, 수정, 삭제)
  • Controller - (가장 바깥 부분) 요청/응답을 처리함 (조회, 생성, 수정, 삭제)(get, post, put, delete)
  • Service - (중간 부분) 중요한 작동이 많이 일어남 / update를 위해 필요 (수정)
  • Model - DB에서 테이블 역할
  • Lombok - 코드 절약 기능 (메소드/생성자 등을 자동생성)
  • JPA - 자바명령어를 SQL어로 번역해주는 기능 (SQL을 쓰지 않고 CRUD 할 수 있도록 해주는 번역기)
  • Repository - 데이터 접근 시 사용하는 하나의 도구 (SQL역할) (Interface로 만들어야 함, Class x)
  • Interface - 클래스에서 멤버가 빠진 메소드 모음집, JPA사용시 사용
  • DTO - read, update 할 때 클래스를 다른사람이 변경할 수도 있음. 완충재 역할로 사용

서버의 3계층

  • Controller - Service - Repository

프로젝트 만들 때

  • Repository 먼저 만듬, 그러기 위해 뭐가 필요한지 알아야 함! 그래서 API설계 먼저 진행
  • API설계 ex) 메모 생성, 조회, 변경, 삭제 기능에 따른 각각 Method, URL, Return 정리

API설계(CRUD) URL은 복수형으로..

 


서버 구축 ↓


Application.java

@EnableJpaAuditing
@SpringBootApplication
public class Week03Application {

    public static void main(String[] args) {
        SpringApplication.run(Week03Application.class, args);
    }

}
  • @EnableJpaAuditing : JPA 사용할건데 변동이 있으면 알아서 반영해줘!! (서버에 꼭 넣어야 함)

Packge : domain or (models)

Memo.java

@NoArgsConstructor // 기본생성자를 만듭니다.
@Getter
@Entity // 테이블과 연계됨을 스프링에게 알려줍니다.
public class Memo extends Timestamped { // 생성,수정 시간을 자동으로 만들어줍니다.
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Id
    private Long id;

    @Column(nullable = false)
    private String username;

    @Column(nullable = false)
    private String contents;

    public Memo(String username, String contents) {
        this.username = username;
        this.contents = contents;
    }

    public Memo(MemoRequestDto requestDto) {
        this.username = requestDto.getUsername();
        this.contents = requestDto.getContents();
    }
}

어노테이션 : @NoArgsConstructor(기본생성자 만듬), @Getter(get), @Entity(DB테이블 역할) // Timestamped를 상속 받음 

컬럼 3가지 : Id, username, contents

 

 

 

Timestamped.java

@MappedSuperclass // Entity가 자동으로 컬럼으로 인식합니다.
@EntityListeners(AuditingEntityListener.class) // 생성/변경 시간을 자동으로 업데이트합니다.
public class Timestamped {

    @CreatedDate
    private LocalDateTime createdAt;

    @LastModifiedDate
    private LocalDateTime modifiedAt;
}
  • DB에 생성시간, 수정시간 반영을 위한 Java 
  • Timestamped 클래스를 상속한 곳이 자동으로 생성 시간과 수정 시간을 컬럼으로 잡도록 도와줌

 

MemoRepository.java

public interface MemoRepository extends JpaRepository<Memo, Long> {
	List<Memo> findAllByOrderByModifiedAtDesc();
}
  • 클래스가 아닌 인터페이스(클래스에서 멤버 변수가 없는 메소드만 있는 녀석)! 
  • JpaRepository를 가져다 쓸 것이다.. (findall, save, delete ...) 대상은 <클래스, 구분하는 자료형(여기서는 id가 Long)>
  • findAll....Desc(); -> ModifiedAt(수정시간)을 기준으로 최신순(내림차순) 정렬해줘!
  • ModifiedAt은 어디서 나온거냐? - Memo클래스는 Timestamped클래스를 상속하고 있는데 그안에 ModifiedAt 필드를 갖고있음 그래서 memo클래스에서 modifiedAt을 가질 수 있고 그대로 이름을 따온 것(MemoRepository.java에)

 

MemoRequestDto.java

@Getter
public class MemoRequestDto {
    private String username;
    private String contents;
}
  • 필요한 정보를 물고 다니는 녀석..  / private 가져오기 위해 @Getter
  • ex) 수정요청이 왔다면? 작성자와 변경할 내용이 뭔지 알아야 함

 

여기까지가 서버에서 Repository, JPA, Model, Dto 부분 완성한 것!!!


Packge : service

MemoService.java

@RequiredArgsConstructor
@Service
public class MemoService {

    private final MemoRepository memoRepository;

    @Transactional
    public Long update(Long id, MemoRequestDto requestDto) {
        Memo memo = memoRepository.findById(id).orElseThrow(
                () -> new IllegalArgumentException("아이디가 존재하지 않습니다.")
        );
        memo.update(requestDto);
        return memo.getId();
    }
}
  • Service는 업데이트 기능(API기능에서 변경부분)위해 필요함 / 패키지 따로 생성(service)
  1. update메소드를 만들어 줌 - public 반환타입 메소드이름(재료(파라미터)) /// (어떤 것을 업데이트 해야하는지 id로 알아내고, 변경시킬 내용에 대한 정보) - 재료에 들어감
  2. 필요한 정보를 찾는다. -> 뭔가를 찾으려면 find 사용 -> Repository가 있어야 함 -> 멤버 변수로 memoRepository 선언 / final은 반드시 필요해! 라는 것이고 그로 인해 어노테이션 @RequiredArgsConstructor 추가  
    @RequiredArgsConstructor : final로 선언된 녀석이 있으면 생성할 때 무조건 같이 넣어줘!
  3. memoRepository를 가져와서 id를 기준으로 find -> 뒤에 id가 없을경우를 추가해줘야 함 
  4. 찾는게 완성되면 그 앞에 Memo memo로 반환을 설정 (memoRepository는 메모를 찾는 녀석이니까..)
  5. memo클래스를 바탕으로 update를 해줌 memo.update(requestDto)
  6. 어떤 것이 업데이트 됐는지 반환 memo.getId();
  7. memo클래스에 update 하는 기능 추가하기 (아래참고)
  8. update 메소드 위에 @Transactional : 이게 DB에 진짜 반영이 꼭 돼야 해!!

 

 

 

Memo.java (하단에 추가한 부분)

public void update(MemoRequestDto requestDto) {
    this.username = requestDto.getUsername();
    this.contents = requestDto.getContents();
}
  • Memo클래스에 메소드 생성

public void(반환타입은 없어도 되서) 메소드이름(Service에서 전달받기로 한 값){

      this.~~~내용으로 인해

      우리가 변경할 값을 실어나르는 Dto에 있는 값이 id로 찾은 Memo클래스 안에 적용 된다.

}

 

여기까지가 서버에서 Service 부분 완성한 것!!!


Packge : controller

API기능을 참고해서 Controller 생성

MemoController.java

@RequiredArgsConstructor
@RestController
public class MemoController {

    private final MemoRepository memoRepository;
    private final MemoService memoService;
}
  • update(변경)을 위해서는 Service가, 나머지(생성, 조회, 삭제)를 위해서는 Repository가 필요하니 멤버변수 선언
  • @어노테이션 두가지로 인해 요청이 들어오면 new ~~이런식으로 안만들고 바로 스프링에서 생성해줘서 사용가능
@PostMapping("/api/memos")
public Memo createMemo(@RequestBody MemoRequestDto requestDto) {
    Memo memo = new Memo(requestDto);
    return memoRepository.save(memo);
}
  • create 메소드   @Post 방식(url주소)  --- > post방식으로 들어오면 밑에 메소드를 실행
    public memo(리턴타입) 메소드명(@~~ 메모의 데이터){
       -- 메모를 저장하려면 메모클래스 생성 -- new Memo(requestDto) requestDto에 있는 데이터가 들어감
       -- 저장하기 위해 repository.save(memo(내가방금 생성한 메모)) 을 반환  }
    @RequestBody : 요청이 들어올 때 Body안에 내용?을 넣어줘!
@GetMapping("/api/memos")
public List<Memo> getMemos() {
    return memoRepository.findAllByOrderByModifiedAtDesc();
}
  • read 메소드    @Get 방식(url주소)
    public List<memo>(리턴타입) 메소드명(재료){      (재료 딱히 필요없고 돌려주기만 하면 됌)
    repository에 설정해놓은 수정시간 기준 최신순으로 정렬로 find 한 것을 반환 }
@DeleteMapping("/api/memos/{id}")
public Long deleteMemo(@PathVariable Long id) {
    memoRepository.deleteById(id);
    return id;
}
  • delete메소드 @Delete방식(url주소+ /{id}(어떤녀석을 삭제해야 되는지))
    public Long(id의 반환자료형) 메소드명(재료)){
    repository에서 id구분으로 삭제 후 삭제 한 id 반환 }
    id가 뭔지 모르기 때문에 @PathVariable(경로에 있는 변수) Long id 를 파라미터로 넣어줘야함
@PutMapping("/api/memos/{id}")
public Long updateMemo(@PathVariable Long id, @RequestBody MemoRequestDto requestDto) {
    memoService.update(id, requestDto);
    return id;
}
  • update메소드 @Put방식(url주소+ /{id}(어떤녀석을 삭제해야 되는지)
    publict Long(id) 메소드명(@~Long id, @~ 변경해야 될 데이터)- >(주소가 어디인지 받아올 데이터, 변경할 데이터)
    service에서 update를 하니까 서비스.업데이트(어떤녀석이고, 변경되는 데이터는 이것이다)
    id 반환;
    @PathVariable : 경로에 있는 변수 /@RequestBody : 요청이 들어올 때 Body안에 내용?을 넣어줘! -- 추가!

여기까지가 서버에서 Controller 부분 완성한 것!!!


댓글