[SpringBoot] 스프링부트 + JPA를 이용한 CRUD 구현 3. 등록 기능 만들기


🎋 Controller


src/main/java/com/test/spring/boot_crud/web/PostsApiController.java

package com.test.spring.boot_crud.web;

import com.test.spring.boot_crud.service.posts.PostsService;
import com.test.spring.boot_crud.web.dto.PostsSaveRequestDto;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RestController
public class PostsApiController {

    private final PostsService postsService;

    @PostMapping("/api/posts")
    public Long save(@RequestBody PostsSaveRequestDto requestDto) {
        return postsService.save(requestDto);
    }
}


  • @RequiredArgsConstructor : 의존성 주입(Dependency Injection) 활용을 위해 사용 / final 필드나 @NotNull이 붙은 모든 필드에 대해 생성자를 생성해준다.

  • @RestController : @Controller + @ResponseBody / Controller 클래스에 @RestController 어노테이션을 붙이면 하위 메서드 마다 @ResponseBody를 추가하지 않아도 객체를 문자열이나 JSON의 형태로 전송할 수 있다.

  • @RequestBody : HTTP 요청의 Body 내용을 통째로 자바 객체로 변환해 매핑된 메소드의 파라미터로 전달

    • @ResponseBody : 자바 객체를 HTTP 요청의 Body 내용으로 매핑하여 클라이언트로 전송



🎋 Service


src/main/java/com/test/spring/boot_crud/service/PostsService.java

package com.test.spring.boot_crud.service.posts;

import com.test.spring.boot_crud.domain.posts.PostsRepository;
import com.test.spring.boot_crud.web.dto.PostsSaveRequestDto;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@RequiredArgsConstructor
@Service
public class PostsService {

    private final PostsRepository postsRepository;

    @Transactional
    public Long save(PostsSaveRequestDto requestDto) {
        return postsRepository.save(requestDto.toEntity()).getId();
    }
}


  • @Transactional

    • 클래스 또는 메서드에 선언, 빈 생성 시 프록시로 생성하여 호출될 때 트랜잭션 처리를 진행

    • Transaction의 begincommit을 메인 로직 앞뒤로 수행, 예외 발생 시 rollback처리를 자동으로 해주는 기능을 담당

    • Proxy 형태로 동작 > 외부에서 접근이 가능한 메서드만 설정 가능 (private 적용 시 오류 발생)

  • .save() : 파라미터로 들어온 entity가 새로운 엔터티라면 insert, 이미 존재하는 엔터티라면 update



🎋 Dto


src/main/java/com/test/spring/boot_crud/web/dto/PostsSaveRequestDto.java

package com.test.spring.boot_crud.web.dto;

import com.test.spring.boot_crud.domain.posts.Posts;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class PostsSaveRequestDto {

    private String title;
    private String content;
    private String author;

    @Builder
    public PostsSaveRequestDto(String title, String content, String author) {
        this.title = title;
        this.content = content;
        this.author = author;
    }

    public Posts toEntity(){
        return Posts.builder()
                .title(title)
                .content(content)
                .author(author)
                .build();
    }
}



🎋 등록 페이지


src/main/resources/templates/posts-save.mustache



<h1>게시글 등록</h1>

<div class="col-md-8">
    <div class="col-md-6">
        <form>
            <div class="form-group">
                <label for="title">제목</label>
                <input type="text" class="form-control" id="title" placeholder="제목을 입력하세요.">
            </div>
            <div class="form-group">
                <label for="author">작성자</label>
                <input type="text" class="form-control" id="author" placeholder="작성자를 입력하세요.">
            </div>
            <div class="form-group">
                <label for="content">내용</label>
                <input type="text" class="form-control" id="content" placeholder="내용을 입력하세요.">
            </div>
        </form>
        <br>
        <div class="btn-group" role="group" aria-label="btns">
            <a href="/" role="button"><button type="button" class="btn btn-secondary">취소</button></a>
            <button type="button" class="btn btn-warning" id="btn-save">등록</button>
        </div>
    </div>
</div>




🎋 index.js


src/resources/static/js/app/index.js

var main = {

    init : function(){
        var _this = this;
        $('#btn-save').on('click', function(){
            _this.save();
        });
    },

    save : function(){
        var data = {
            title: $('#title').val(),
            author: $('#author').val(),
            content: $('#content').val()
        };
        $.ajax({
            type: 'POST',
            url: '/api/posts',
            dataType: 'json',
            contentType: 'application/json; charset=utf-8',
            data: JSON.stringify(data)
        }).done(function(){
            alert('게시글이 등록되었습니다.');
            window.location.href = '/';
        }).fail(function(error){
            alert(JSON.stringify(error));
        });
    }
};

main.init();


footer.mustache에 index.js를 추가해주자.

<script src=...
...>

<script src="/js/app/index.js"></script>

</body>
</html>



🎋 Controller


src/main/java/com/test/spring/boot_crud/web/IndexController.java

package com.test.spring.boot_crud.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class IndexController {

    @GetMapping("/")
    public String index() {
        return "index";
    }

    @GetMapping("/posts/save")
    public String postsSave(){
        return "posts-save";
    }

}




Categories:

SpringBoot