Language : Java 8
Type : Gradle
Packaging : Jar
Dependencies : Spring Web, Spring Data JPA, Lombok
- SQL : H2 Database(Test용), MySQL Driver(배포용)
Spring Framework
: Spring 서버를 구현하였기 때문에 Controller, Service, Repository로 구분하여 사용함. 하지만 기능이 단순하여 Service에서의 역할을 Controller에서 대부분 이행시킴
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@NoArgsConstructor // 기본 생성자를 만들어 줌
@Getter // Get 함수를 자동으로 생성
@Entity // 아래 나열되어 있는 목록들이 DB에서 테이블 역할을 할 것을 알려줌
public class Bulletin extends Timestamped { // 게시글의 생성시간과 수정시간을 알려줄 Class를 상속받음
@GeneratedValue(strategy = GenerationType.AUTO) // PK(Primary Key) 값을 자동으로 1씩 증가시켜줌
@Id // 아래 값이 PK라는 것을 알려줌
private Long id;
@Column(nullable = false) // null(데이터 없음) 상태가 불가함
private String title;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String contents;
public Bulletin(BulletinRequestDto requestDto) { // Dto에 대한 설명은 아래에서 하겠음
this.title = requestDto.getTitle();
this.name = requestDto.getName();
this.contents = requestDto.getContents();
}
}
게시글을 작성하게 되면 글의 제목, 작성자명, 작성 내용이 포함되기 때문에 각각을 Entity에 포함시켰으며, 각 Column에 들어갈 Data를 Dto에 담아서 운반하는 방식을 사용함.
import lombok.Getter;
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 // 멤버변수를 Column이 되게 만들어줌
@EntityListeners(AuditingEntityListener.class) // 수정이 있을 시 자동으로 기록
@Getter
public class Timestamped {
@CreatedDate // 최초 생성된 시점
private LocalDateTime createdAt;
@LastModifiedDate // 마지막에 수정된 시점
private LocalDateTime modifiedAt;
}
import lombok.Getter;
@Getter
public class BulletinRequestDto {
private String title;
private String name;
private String contents;
}
Client로부터 요청 받을 때의 경우와 Client에게 응답을 줄 때의 경우를 나눠서 Dto를 생성해야 하지만 현재 프로젝트에서는 요청을 받는 경우의 Dto만 생성함.
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RequiredArgsConstructor // final(상수)로 선언된 멤버 변수를 자동으로 생성
@RestController // @Controller라고만 하면 해당 클래스가 Controller라는 것을 알려주지만
// @Restcontroller를 선언하면 Json 형태로 데이터를 주고받음을 선언
public class BulletinController {
private final BulletinRepository bulletinRepository;
// 게시글 작성 api
@PostMapping("/api/bulletins")
public Bulletin createBulletin(@RequestBody BulletinRequestDto requestDto) {
Bulletin bulletin = new Bulletin(requestDto);
return bulletinRepository.save(bulletin);
// controller에서는 Dto에 담긴 Data를 client로부터 받고 실질적인 기능은
// service로 넘겨줘야 하지만 현재는 모두 controller에서 진행함
}
// 게시글 조회 api
@GetMapping("/api/bulletins")
public List<Bulletin> getBulletins() {
return bulletinRepository.findAllByOrderByModifiedAtDesc();
}
// 게시글 삭제 api
@DeleteMapping("/api/bulletins/{id}")
public Long deleteBulletin(@PathVariable Long id) {
bulletinRepository.deleteById(id);
return id;
}
}
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@RequiredArgsConstructor
@Service // 해당 글래스가 Service임을 선언
public class BulletinService {
private final BulletinRepository bulletinRepository;
}
controller에서 service 역할까지 같이 하고 있기 때문에 이번 프로젝트에서는 비어있음.
다음 프로젝트부터는 service에 비중을 대폭 늘릴 필요가 있음.
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface BulletinRepository extends JpaRepository<Bulletin, Long> {
List<Bulletin> findAllByOrderByModifiedAtDesc();
}
Jpa Repository를 상속해 왔기 때문에 db에 연결하는 것부터 종료하는 작업까지 모두 대신 해줌.
그리고 게시물을 조회할 때 수정한 날짜 순서대로 게시를 해야하기 때문에 query문을 하나 만듦.
$(document).ready(function () {
showBulletin();
})
// 게시글 작성
function addBulletin() {
let title = $('#title').val();
let name = $('#name').val();
let contents = $('#contents').val();
let data = {'title':title, 'name':name, 'contents':contents};
$.ajax({
type: "POST",
url: '/api/bulletins',
contentType: "application/json",
data: JSON.stringify(data),
success: function (response) {
$('#title').val("");
$('#name').val("");
$('#contents').val("");
$('div.nav-write').removeClass('active');
$('div.nav-find').addClass('active');
$('#write-area').hide();
$('#find-area').show();
showBulletin();
}
})
}
// 게시글 조회
function showBulletin() {
$('#bulletin-boxes').empty();
$.ajax({
type: 'GET',
url: '/api/bulletins',
success: function (response) {
for (let i = 0; i < response.length; i++) {
let bulletin = response[i];
let id = bulletin['id'];
let title = bulletin['title'];
let name = bulletin['name'];
let modifiedAt = bulletin['modifiedAt'].split("20")[1].split("T")[0];
let contents = bulletin['contents'];
addHTML(id, title, name, modifiedAt, contents);
}
}
})
}
function addHTML(id, title, name, modifiedAt, contents) {
let tempHtml1 = `<button type="button" class="btn btn-light" data-toggle="modal" data-target="#${id}-exampleModalCenter" style="margin-right: 20px">
<p style="font-weight: bold; font-size: 20px" id="${id}-title">${title}</p>
<p style="font-size: 15px" id="${id}-name">${name}</p>
<p style="font-size: 10px;" id="${id}-modifiedAt">${modifiedAt}</p>
</button>`
let tempHtml2 = `<div class="modal fade" id="${id}-exampleModalCenter" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="${id}-exampleModalLongTitle">${title}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p id="${id}-name">${name}</p>
<p>${modifiedAt}</p>
<p id="${id}-contents">${contents}</p>
<p class="deleteButton" style="color: blue" onclick="deleteBulletin('${id}')">삭제</p>
</div>
</div>
</div>
</div>`
$('#bulletin-boxes').append(tempHtml1);
$('#modal-box').append(tempHtml2);
}
// 게시글 삭제
function deleteBulletin(id) {
$.ajax({
type: "DELETE",
url: `/api/bulletins/${id}`,
success: function (response) {
alert('메시지 삭제에 성공하였습니다.');
window.location.reload()
}
})
}
Spring Framework를 이용하여 간단한 게시글을 만들어 보면서 Spring이 어떻게 작동되는지 원리를 이해하게 되었고, 어떠한 기능에 대한 코드를 작성하려고 할 때 해당 코드를 어디에 입력하면 되는지 이해할 수 있는 프로젝트였다.