스프링부트 독학-7장 블로그 화면 구성하기

jaegeunsong97·2023년 9월 1일
0

출처

신서영개발자님의 스프링부트 책

새롭게 알게된 내용 정리

타임리프

  • 템플릿엔진 : 스프링 서버에서 데이터를 받아 우리가 보는 웹페이지, HTML 상에 그 데이터를 넣어 보여주는 도구
    • 데이터를 넘겨받아 HTML에 데이터를 넣어 동적인 웹페이지를 만들어주는 도구
    • 타임리프 : 스프링 대표적인 템플릿 엔진, 컨틀로러에서 모델을 통해 데이터를 설정하면, 모델은 뷰에서 사용할 수 있게 데이터를 전달
<h1 text=${이름}>
<p text=${나이}>
  • 타임리프 표현식
표현식설명
${...}변수의 값 표현식
#{...}속성 파일 값 표현식
@{...}URL 표현식
* {...}선택한 변수의 표현식. th:object에서 선택한 객체에 접근
  • 타임리프 문법
표현식설명예제
th:text텍스트를 표현할 때 사용th:text=${person.name}
th:each컬레션을 반복할 떄 사용th:each="person:${persons}"
th:if조건이 true일 때만 표시th:if="${person.age}>=20"
th:unless조건이 false일 때만 표시th:unless="${person.age}>=20"
th:href이동경로th:href="@{/persons(id=${person.id})}"
th:with변숫값으로 지정th:with="name=${person.name}"
th:object선택한 객체로 지정th:object="${person}"
  • Model : 뷰, 즉HTML 쪽으로 값을 넘겨주는 객체

  • 기억해야할 어노테이션

    • @EnableJpaAuditing : created_at, updated_at 자동 업데이트
    • @LastModifiedDate : 엔티티가 수정될 때 수정 시간 저장
  • JS

    • id를 ?-btn으로 설정한 엘리먼트를 찾아, 해당 엘리먼트에서 클릭 이벤트가 발생하면 fetch()를 통해 해당 주소로 요청을 보내는 역할
// 삭제
const deleteButton = document.getElementById('delete-btn');

if (deleteButton) {
    deleteButton.addEventListener('click', event => {
        let id = document.getElementById('article-id').value;
        fetch(`/api/articles/${id}`, {
            method: 'DELETE'
        })
        .then(() => {
          	alert('삭제가 완료되었습니다.');
          	location.replace('/articles'); // 실행 시 사용자의 웹 브라우저 화면을 현재 주소를 기반해 옮겨주는 역할 
        });
    });
}

// 수정
const modifyButton = document.getElementById('modify-btn');

if (modifyButton) {
    modifyButton.addEventListener('click', event => {
        let params = new URLSearchParams(location.search);
        let id = params.get('id');

        fetch(`/api/articles/${id}`, {
            method: 'PUT',
            headers: {
                "Content-Type": "application/json",
            },
            body: JSON.stringify({
                title: document.getElementById('title').value,
                content: document.getElementById('content').value
            })
        })
        .then(() => {
            alert('수정이 완료되었습니다.');
            location.replace(`/articles/${id}`);
        });
    });
}

// 생성
const createButton = document.getElementById('create-btn');

if (createButton) {
    createButton.addEventListener('click', event => {
        fetch('/api/articles', {
            method: 'POST',
            headers: {
                "Content-Type": "application/json",
            },
            body: JSON.stringify({
                title: document.getElementById('title').value,
                content: document.getElementById('content').value
            })
        })
        .then(() => {
            alert('등록 완료되었습니다.');
            location.replace('/articles');
        });
    });
}
  • 수정과 생성을 함께 개발하는 이유
    • 같은화면에서 이루어지기 때문에
@GetMapping("/new-article")
    public String newArticle(@RequestParam(required = false) Long id, Model model) {
        if (id == null) { // 생성
            model.addAttribute("article", new ArticleViewResponse());
        } else { // 수정
            Article article = blogService.findById(id);
            model.addAttribute("article", new ArticleViewResponse(article));
        }

        return "newArticle";
    }
profile
블로그 이전 : https://medium.com/@jaegeunsong97

0개의 댓글