checkIn 프로젝트(SpringBoot)

Spring Boot + JPA + Mysql 게시판 (1) 게시글 등록_수정본

hazy1993 2023. 1. 8. 01:11

나는 게시글 등록하는 부분을 하기로했다.

 

프로젝트 규모 초기 설정을 너무 크게잡아서 모두가 하기 어렵고

 

불편한 사항이 있을가봐 규모를 축소하고 소규모로 하기로 했다.

 

게시글등록에 관해 작성.

 

1.컨트롤러

package com.teamproject.checkin.board;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import java.util.List;

@Controller
@RequiredArgsConstructor
public class BoardController {

    //@Autowired  RequiredArgsConstructor
    //final이 붙거나 @NotNull 이 붙은 필드의 생성자를 자동 생성해주는 롬복 어노테이션
    final BoardService boardService;

    //기본부트스트랩
    @GetMapping("/freeBoard")
    public String FRboardList(Model model){
   
        return "/board/freeBoard";
    }

    @GetMapping("/FRWrite")
    public String FRWrite(Model model){
        return "/board/FRWrite";
    }

    @PostMapping("/boardReg")
    public String boardReg(BoardDto boardDto){
        boardService.boardReg(boardDto);
        return "redirect:/freeBoard";
    }
    @GetMapping("/FRDetail")
    public String FRDetail(Model model){
        return "/board/FRDetail";
    }

    @GetMapping("/FREdit")
    public String FREdit(Model model){
        return "/board/FREdit";
    }

}

FRboardList  : 게시글리스트 (Get)
FRWrite : 게시글 작성화면 (Get)
boardReg : 게시글 입력기능(Post)
FRDetail : 상세조회
FREdit : 수정

 

2.Board (Entity)

package com.teamproject.checkin.board;

import com.teamproject.checkin.commEntity.TimeEntity;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
//@IdClass(BoarderPK.class)
public class Board extends TimeEntity {

/*    @Id //@Pk
    private String corpCode;

    @Id
    private String partCode;*/
  //  @Id
    private String boardType;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)//자동으로 PK 값 입력이 됨 테스트 필요
    private Long boardNo;

    private String boardTitle;
    private String boardContent;
   // public Board() { }

    public Board(Long boardNo, String boardType, String boardTitle, String boardContent){
        this.boardNo = boardNo;
        this.boardType = boardType;
        this.boardTitle = boardTitle;
        this.boardContent = boardContent;
    }
    public static Board of (Long boardNo, String boardType, String boardTitle, String boardContent)
    {
        return new Board(boardNo, boardType, boardTitle,boardContent);
    }

}

!!Board of 중요!! JPA를 사용하기 위해 Entity를 리턴해주는 것으로 추측된다.

하단에 내용 설명하도록 하겠습니다.

 

그리고 등록, 수정에 관한 정보를 입력하기 위해 

public class Board extends TimeEntity 

상속처리를 해줬다.

 

 

2_2 TimeEntity 추가

공통으로 사용 할 수 있도록 따로 배두었다.

이름은 commEntity로 해두었는데 util이 나을지는 팀원과 상의를 해보려고한다.

 

package com.teamproject.checkin.commEntity;


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.Column;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;


//사용하기 위해 @EnableJpaAuditing 애노테이션 붙이기
@Getter
@MappedSuperclass // 테이블로 매핑하지 않고, 자식 Entity에게 매핑정보를 상속하기 위한 애노테이션
@EntityListeners(AuditingEntityListener.class) //JAP에게 해당 Entity는 Auditing 사용한다는 것을 알리는 애노테이션
public class TimeEntity {

    @CreatedDate
    @Column(updatable = false)
    private LocalDateTime insDate;

    @LastModifiedDate
    private LocalDateTime updDate;

}

Auditing 사용을 위해 메인 컨트롤러에도 추가를 해준다

@RestController
@SpringBootApplication
@EnableJpaAuditing
public class CheckInApplication {

    @RequestMapping("/")
    public String home(){
        return "hello SpringBoot!";
    }

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

}

@EnableJpaAuditing 추가

 

 

 

 

3.BoardRepository

public interface BoardRepository extends JpaRepository<Board, Long> {

}

Repository는 데이터 조작을 담당한다. interface로 생성하며, JpaRepository를 extends한다. JpaRepository의 값은 매핑할 entity와 id의 타입이다.(PK로 추측)

 

4.BoardService

package com.teamproject.checkin.board;


import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class BoardService {

    private final BoardRepository boardRepository;
 
    public Board boardReg(BoardDto dto){
        return boardRepository.save(dto.toEntity());
    }
}

Service는 위에서 말했듯 실제로 비즈니스 로직을 시행해주는 역할을 한다.

컨트롤러에서 받은 데이터를 저장히기 위해 BoardService의 boardReg를 실행, boardReg를 구현해줘야한다.

boardReg는 Repository를 통해 실제로 데이터를 저장하게 된다. (repository의 save는 JpaRepository -> PagingAndSortingRepository -> CrudRepository 의 인터페이스이다.)

 

CrudRepository 인터페이스 일부

<S extends T> S save(S entity);

매개변수로 entity를 받는것으로 볼 수 있다.

 

6.DTO

package com.teamproject.checkin.board;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.time.LocalDateTime;

@Getter
@Setter
@NoArgsConstructor
public class BoardDto {

    private Long boardNo;
    private String boardType;
    private String boardTitle;
    private String boardContent;
    private LocalDateTime insDate;
    private LocalDateTime updDate;



    public BoardDto(Long boardNo, String boardType, String boardTitle, String boardContent,LocalDateTime insDate,LocalDateTime updDate) {
        this.boardNo = boardNo;
        this.boardType = boardType;
        this.boardTitle = boardTitle;
        this.boardContent = boardContent;
        this.insDate = insDate;
        this.updDate = updDate;

    }

    public Board toEntity(){
        return  Board.of(boardNo, boardType, boardTitle,boardContent);
    }

    // entity를 dto로 변환
    public static BoardDto fromEntity(Board entity){
        return new BoardDto(
                entity.getBoardNo(),
                entity.getBoardType(),
                entity.getBoardTitle(),
                entity.getBoardContent(),
                entity.getInsDate(),
                entity.getUpdDate()
        );
    }
}

 마지막으로 DTO.

기본 생성자 생성 및  toEntity매서드를 만들어준다.

Board를 Entity로 변환해 주는 기능을 한다. save() 매서드를 사용하기 위함이다.

 

Hibernate: 
    insert 
    into
        board
        (ins_date, upd_date, board_content, board_title, board_type) 
    values
        (?, ?, ?, ?, ?)

 

글 입력시 쿼리가 잘 날아가는것을 볼 수 있다.

 

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
   xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
   layout:decorate="~{layout/layout002}">
<th:block layout:fragment="content002">
<style>
.tbx {
      resize: none;
}
</style>
   <div class="app-content content">
      <div class="content-wrapper">
         <div class="content-wrapper-before"></div>
         <div class="content-header row">
            <div class="content-header-left col-md-4 col-12 mb-2">
               <h3 class="content-header-title">자유게시판</h3> <!-- Title 입력 -->
            </div>
            <div class="content-header-right col-md-8 col-12">
               <div class="breadcrumbs-top float-md-right">
                  <div class="breadcrumb-wrapper mr-1">
                     <ol class="breadcrumb">
                        <li class="breadcrumb-item"><a href="/home">Home</a></li> <!-- Home LINK -->
                        <li class="breadcrumb-item active">자유게시판 > 글쓰기</li> <!-- Title 입력 -->
                     </ol>
                  </div>
               </div>
            </div>
         </div>
         <div class="content-body">
            <section id="chartjs-bar-charts">
               <div class="row">
                  <div class="col-12">
                     <div class="card">
                        <div class="card-header">
                           <h4 class="card-title">자유게시판 게시글작성</h4> <!-- 부제목 입력 -->
                        </div>
                        <div class="card-content collapse show">
                                <div class="row">
                              <div class="col-12">
                                 <div class="card">
                                    <div class="card-header">
                                       <h1 class="card-title"><a href="javascript:history.back()"><span class="pink"><i class="la la-mail-reply"></i>뒤로</span></a></h1>
                                       <a class="heading-elements-toggle"><i class="la la-ellipsis-v font-medium-3"></i></a>
                                       <div class="heading-elements">
                                          <ul class="list-inline mb-0">
                                             <li><a data-action="collapse"><i class="ft-minus"></i></a></li>
                                          </ul>
                                       </div>
                                    </div>
                                    <div class="card-content collapse show">
                                       <div class="card-body">
                                       <form class="form" th:action="@{/boardReg}"  method="post">
                                          <div class="form-body">
                                             <input type="hidden" name="boardType" value="B" readonly>
                                       <!--      <input type="hidden" id="date" name="date">-->
                                             <div class="form-group" style="text-align: right;">
                                                <button type="button" class="btn btn-primary mr-1 btn-sm"><i class="la la-paperclip"></i></button>
                                                <button type="button" class="btn btn-danger mr-1 btn-sm"><i class="la la-file-image-o"></i></button>
                                             </div>
                                             <div class="form-group">
                                                <input type="text" id="writer" class="form-control" placeholder="작성자" name="writer" readonly="readonly" value="작성자">
                                             </div>
                                             <div class="form-group">
                                                <input type="text" id="boardTitle" class="form-control" placeholder="제목을 입력하세요..." name="boardTitle">
                                             </div>
                                             <div class="form-group">
                                                <textarea id="boardContent" name="boardContent" rows="20" class="form-control tbx" placeholder="내용을 입력하세요..." ></textarea>
                                             </div>
                                          </div>
                                          <div class="form-actions center">
                                             <button type="submit" class="btn btn-outline-primary">새글등록</button>
                                          </div>
                                       </form>
                                    </div>
                                    </div>
                                 </div>
                              </div>
                           </div>
                        </div>
                     </div>
                  </div>
               </div>
            </section>
         </div>
      </div>
   </div>
</th:block>
<script>



</script>
</html>

 

현 게시판은 공부중에 작성하는 것으로 많이 미흡한 부분이 있을 수 있습니다.

 

추가내용에 대해서는 추후 추가로 작성하거나 수정하도록하겠습니다.

 

피드백을 주신다면 감사히 받겠습니다

 

(현재 시간이나 작성자 , 게시판타입 등등은 안받거나 하드코딩 입니다)

 

테이블에 등록자 컬럼도 없네요.. 추후 추가를..ㄷㄷ..ㅠㅠ