[Spring]3주차
💡 학습내용
1. 스프링을 이용해 API 만들기
API 설계하기
Spring 서버에는
Controller, Service, Repository 3계층 존재
Repository => Service => Controller
타임라인 API
POST => /api/memos => Retrun Memo
GET => /api/memos => Retrun List<Memo>
PUT => /api/memos/{id} => Retrun Long
DELETE => /api/memos/{id} => Retrun Long
Repository 만들기
com > sparta > week03 > domain
Memo.java
package com.sparta.week03.domain;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@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();
}
}
Timestamped.java
@MappedSuperclass
Entity 가 자동으로 컬럼으로 인식합니다.
@EntityListeners(AuditingEntityListener.class)
생성/변경 시간을 자동으로 업데이트. 변화가 일어나면 자동으로 업데이트 해주겠다.
package com.sparta.week03.domain;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class Timestamped {
@CreatedDate
private LocalDateTime createdAt; // 생성시간
@LastModifiedDate
private LocalDateTime modifiedAt; // 수정시간
}
MemoRepository.java
Query Lookup Strategies
List<Memo> findAllByOrderByModifiedAtDesc();
findAll 을 쓰지만, 그냥 findAll 을 하는게 아니라, 즉 전부 다 찾을 건데, 생성 시간을 최신순으로 정렬을 해줘 라고 요청하는 것!
package com.sparta.week03.domain;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
// JpaRepository<Memo, Long> : Memo 라는 클래스고, Long 은 id 타입
public interface MemoRepository extends JpaRepository<Memo, Long> {
List<Memo> findAllByOrderByModifiedAtDesc(); // findAll By OrderBy Modified At Desc 순서대로 정렬을 해줘!
// 수정된 날짜 기준으로 정렬 하라는 뜻! 최신 순으로 정렬을 해줘라는 뜻
}
MemoRequestDto.java
package com.sparta.week03.domain;
import lombok.Getter;
@Getter
public class MemoRequestDto {
private String username;
private String contents;
}
Service 만들기
Update
기능
com > sparta > week03 > service
위치에 만들기
MemoService.java
...
@RequiredArgsConstructor // final 로 선언된 변수가 있으면, 그 변수를 생성할 때 반드시 넣어 주겠다는 뜻!
@Service
public class MemoService {
private final MemoRepository memoRepository; // final 꼭 필요하다고 말해줘야함
@Transactional // update 할 때 이게 DB에 직접 반영 되야한다는 것을 알려줌.
public Long update(Long id, MemoRequestDto requestDto) { // id와 변경시킬 때 필요한 정보
Memo memo = memoRepository.findById(id).orElseThrow(
() -> new IllegalArgumentException("아이디가 존재하지 않습니다.")
);
memo.update(requestDto);
return memo.getId();
}
}
Memo 클래스에 update 매서드 추가하기
...
public void update(MemoRequestDto requestDto) {
this.username = requestDto.getUsername();
this.contents = requestDto.getContents();
}
...
Controller 만들기
MemoController.java
@RequiredArgsConstructor // new memoRepository, new memoService 이렇게 안하고, 요청이 들어올 때 이런 거는 스프링이 알아서 해준다.
@RestController
public class MemoController {
private final MemoRepository memoRepository;
private final MemoService memoService;
@PostMapping("/api/memos")
public Memo createMemo(@RequestBody MemoRequestDto requestDto) {
Memo memo = new Memo(requestDto);
return memoRepository.save(memo);
}
@GetMapping("/api/memos")
public List<Memo> readMemos() {
return memoRepository.findAllByOrderByModifiedAtDesc();
}
@GetMapping("/api/memos/{id}")
public Memo readMemos(@PathVariable Long id) {
return memoRepository.findById(id).orElseThrow(
() -> new IllegalArgumentException("해당 id 없음")
);
}
@PutMapping("/api/memos/{id}")
public Long updateMemo(@PathVariable Long id, @RequestBody MemoRequestDto requestDto) {
return memoService.update(id, requestDto);
}
@DeleteMapping("/api/memos/{id}")
public Long deleteMemo(@PathVariable Long id) {
memoRepository.deleteById(id);
return id;
}
}
jQuery
// 없에기
$('#cards-box').empty();
// 생성하기
$('#cards-box').append(`<div class="card">
<img class="card-img-top"
src="https://www.eurail.com/content/dam/images/eurail/Italy%20OCP%20Promo%20Block.adaptive.767.1535627244182.jpg"
alt="Card image cap">
<div class="card-body">
<a href="#" class="card-title">여기 기사 제목이 들어가죠</a>
<p class="card-text">기사의 요약 내용이 들어갑니다. 동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라만세 무궁화 삼천리 화려강산...</p>
<p class="card-text comment">여기에 코멘트가 들어갑니다.</p>
</div>
</div>`);
클라이언트 설계하기
writePost
💎 writePost 함수
function writePost() {
// 1. 작성한 메모를 불러옵니다.
let contents = $('#contents').val();
// 2. 작성한 메모가 올바른지 isValidContents 함수를 통해 확인합니다.
if (isValidContents(contents) === false) return;
// 3. genRandomName 함수를 통해 익명의 username 을 만듭니다.
let username = genRandomName(10);
// 4. 전달할 data JSON 으로 만듭니다.
let data = {
'username': username,
'contents': contents
};
// 5. POST /api/memos 에 data 를 전달합니다.
$.ajax({
type: "POST",
url: "/api/memos",
contentType: "application/json", // JSON 형식으로 전달함을 알리기
data: JSON.stringify(data),
success: function (response) {
alert('메시지가 성공적으로 작성되었습니다.');
window.location.reload();
}
});
}
contentType: "application/json"
받는 쪽에다가 JSON이다, 번역해라 라고 말해주는 것
data: JSON.stringify(data)
원래 String 형태밖에 못주고 받으니까 JSON 형식을 String 형태로 바꾸기
success: function (response) {...}
성공적으로 응답이 왔을 때, 응답을 response 라는 것 안에다가 넣어주겠다.
window.location.reload()
화면 새로고침
getMessages
created_at, modified_at 데이터가 오지 않았던 이유는 Getter 가 없었기 때문.
- Spring 한테 Auditing 기능을 사용하고 있다고 알려줘야함.
Timestamped
사용할 때 Getter
꼭 사용하기
Timestamped.java
package com.sparta.week03.domain;
...
@Getter
@MappedSuperclass // Entity 가 자동으로 컬럼으로 인식합니다.
@EntityListeners(AuditingEntityListener.class) // 생성/변경 시간을 자동으로 업데이트합니다. 변화가 일어나면 자동으로 업데이트 해주겠다.
public abstract class Timestamped {
@CreatedDate
private LocalDateTime createdAt; // 생성시간
@LastModifiedDate
private LocalDateTime modifiedAt; // 수정시간
}
Week03Application.java
package com.sparta.week03;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@EnableJpaAuditing // 꼭 넣어주기!
@SpringBootApplication
public class Week03Application {
public static void main(String[] args) {
SpringApplication.run(Week03Application.class, args);
}
}
💎 getMessages 함수
$(document).ready(function () {
// HTML 문서를 로드할 때마다 실행합니다.
getMessages();
})
// 메모를 불러와서 보여줍니다.
function getMessages() {
// 1. 기존 메모 내용을 지웁니다.
$('#cards-box').empty();
// 2. 메모 목록을 불러와서 HTML로 붙입니다.
$.ajax({
type: 'GET',
url: '/api/memos',
success: function (response) {
for (let i = 0; i < response.length; i++) {
let memo = response[i];
let id = memo.id;
let username = memo.username;
let contents = memo.contents;
let modifiedAt = memo.modifiedAt;
addHTML(id, username, contents, modifiedAt)
}
}
})
}
// 메모 하나를 HTML로 만들어서 body 태그 내 원하는 곳에 붙입니다.
function addHTML(id, username, contents, modifiedAt) {
// 1. HTML 태그를 만듭니다.
let tempHtml = `<div class="card">
<!-- date/username 영역 -->
<div class="metadata">
<div class="date">
${modifiedAt}
</div>
<div id="${id}-username" class="username">
${username}
</div>
</div>
<!-- contents 조회/수정 영역-->
<div class="contents">
<div id="${id}-contents" class="text">
${contents}
</div>
<div id="${id}-editarea" class="edit">
<textarea id="${id}-textarea" class="te-edit" name="" id="" cols="30" rows="5"></textarea>
</div>
</div>
<!-- 버튼 영역-->
<div class="footer">
<img id="${id}-edit" class="icon-start-edit" src="images/edit.png" alt="" onclick="editPost('${id}')">
<img id="${id}-delete" class="icon-delete" src="images/delete.png" alt="" onclick="deleteOne('${id}')">
<img id="${id}-submit" class="icon-end-edit" src="images/done.png" alt="" onclick="submitEdit('${id}')">
</div>
</div>`;
// 2. #cards-box 에 HTML을 붙인다.
$('#cards-box').append(tempHtml);
}
submitEdit
💎 submitEdit 함수
// 메모를 수정합니다.
function submitEdit(id) {
// 1. 작성 대상 메모의 username과 contents 를 확인합니다.
let username = $(`#${id}-username`).text().trim();
let contents = $(`#${id}-textarea`).val().trim();
// 2. 작성한 메모가 올바른지 isValidContents 함수를 통해 확인합니다.
if (isValidContents(contents) == false) {
return;
}
// 3. 전달할 data JSON으로 만듭니다.
let data = {'username': username, 'contents': contents};
// 4. PUT /api/memos/{id} 에 data를 전달합니다.
$.ajax({
type: "PUT",
url: `/api/memos/${id}`,
contentType: "application/json",
data: JSON.stringify(data),
success: function (response) {
alert('메시지 변경에 성공하였습니다.');
window.location.reload();
}
});
}
deleteOne
💎 deleteOne 함수
function deleteOne(id) {
$.ajax({
type: "DELETE",
url: `/api/memos/${id}`,
success: function (response) {
alert('메시지 삭제에 성공하였습니다.');
window.location.reload();
}
})
}
Author And Source
이 문제에 관하여([Spring]3주차), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@soso0/spring-03저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)