
- 기획의도
- 조원소개
- 프로젝트 환경 및 진행 일정
- 설계방식
1) ERD
2) Flow Chart- 주요코드 설명
- 소감
우리는 바쁜세상을 살면서 다른 취미, 기술 등을 배워볼 시간이나 기회가 흔치않다.
그래서 우리팀은 간편하고 쉽게 배울수있고 접근성도 좋은 튜터링 사이트를 만들게 됐다.
자신의 재능을 팔수있고 그 재능을 배워볼수있는 최고의 튜터링 사이트인 저Do(just do) 이다.
참여인원 : 6명



기간 : 22.12/12 ~ 22.12/27



이번 게시판을 만들때 Repository는 JpaRepository를 상속받아 만들었다.
JpaRepository를 상속받기 위해서는 interface로 class를 만들어야 한다.
JpaRepository를 상속받으면 Repository에 crud에 관한 메서드들을 따로 입력하지 않아도 되서 코드가 깔끔해진다.
board(게시물)
package com.yujeans.justdo.board;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.validation.constraints.NotNull;
import com.yujeans.justdo.user.Account;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Entity
@Getter @Setter
@SequenceGenerator(
name = "Board_seq_generator",
sequenceName = "Board_seq",
initialValue = 1,
allocationSize = 1
)
@ToString
public class Board {
@Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "Board_seq_generator")
private Long id;
private String title;
@Lob
private String content;
private String startDate;
@Column(columnDefinition = "integer default 0", nullable = false)
private int views;
@ManyToOne
@JoinColumn
@NotNull
private Account account;
@OneToMany(mappedBy = "board", cascade = {CascadeType.REMOVE})
private List<Reply> replys = new ArrayList<Reply>();
public void addReply(Reply reply) {
reply.setBoard(this);
this.replys.add(reply);
}
}
reply(댓글)
package com.yujeans.justdo.board;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.validation.constraints.NotNull;
import com.yujeans.justdo.user.Account;
import lombok.Getter;
import lombok.Setter;
@Entity
@Getter @Setter
@SequenceGenerator(
name = "Reply_seq_generator",
sequenceName = "Reply_seq",
initialValue = 1,
allocationSize = 1
)
public class Reply {
@Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "Reply_seq_generator")
private Long id;
private String content;
private String startDate;
@ManyToOne
@JoinColumn
@NotNull
private Account account;
@ManyToOne
@JoinColumn
private Board board;
}
board(게시물)
package com.yujeans.justdo.board.dto;
import javax.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class BoardFormDto {
@NotBlank(message = "제목을 입력해 주세요")
private String title;
@NotBlank(message = "내용을 입력해 주세요")
private String content;
}
reply(댓글)
package com.yujeans.justdo.board.dto;
import javax.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class ReplyFormDto {
@NotBlank(message = "댓글을 입력해 주세요")
private String content;
}

//// controller ////
// 글작성
@PostMapping("/board/boardWriteSub")
public String boardWritePro(@Validated @ModelAttribute BoardFormDto boardFormDto
,BindingResult bindingResult, Model model, HttpServletRequest request){
if(bindingResult.hasErrors()) {
System.out.println("========= bindingResult Error =========");
System.out.println(bindingResult.toString());
System.out.println(bindingResult.getAllErrors().get(0));
return "/board/board_write";
}
Board board = new Board();
Account account = credentialService.findUserInfo((String)request.getAttribute("id"));
board.setContent(boardFormDto.getContent());
board.setTitle(boardFormDto.getTitle());
board.setStartDate(LocalDate.now().toString());
board.setAccount(account);
boardService.write(board);
model.addAttribute("boardList", boardService.boardList());
return "redirect:/board/boardList";
}
// 게시글 수정
@PostMapping("/board/boardUpdate/{id}")
public String boardUpdate(@PathVariable("id") Long id, @ModelAttribute BoardFormDto boardFormDto, Model model, HttpServletRequest request){
Optional<Board> result = boardService.findById(id);
Board board = result.get();
board.setId(id);
board.setContent(boardFormDto.getContent());
board.setTitle(boardFormDto.getTitle());
board.setStartDate(LocalDate.now().toString());
boardService.write(board);
model.addAttribute("boardUpdate", boardService.boardList()) ;
return "redirect:/board/boardView/{id}";
}
//// service ////
// 게시글 작성 / 수정
@Transactional
public void write(Board board) {
boardRepository.save(board);
}
//// repository ////
// JpaRepository 사용

//// controller ////
// 상세보기 이동
@GetMapping("/board/boardView/{id}")
public String boardView(@PathVariable("id") Long id, HttpServletRequest request, HttpServletResponse response
,Model model, ReplyFormDto replyFormDto){
System.out.println("상세보기 id : " + id);
System.out.println("보드 뷰 테스트");
boardService.boardView(id, request, response);
Optional<Board> findResult = boardService.findById(id);
Board board = findResult.get();
model.addAttribute("boardView", board);
model.addAttribute("replyList", replyService.findByBoard(board));
Credential credential = credentialService.findByAccountId(board.getAccount().getId());
String isSameId = "false";
if(credential.getUsername().equals(request.getAttribute("id"))) {
isSameId = "true";
}
Optional<Credential> loginCredential = credentialService.findByUsername(request.getAttribute("id").toString());
model.addAttribute("isSameId", isSameId);
model.addAttribute("credentialId", loginCredential.get().getId());
return "/board/board_view";
}
//// service ////
// board Service //
// 상세보기 / 수정 페이징 id값 이동
public Optional<Board> findById(Long id) {
return boardRepository.findById(id);
}
// reply Service //
// 게시글 아이디 찾기
public List<Reply> findByBoard(Board board){
return replyRepository.findByBoard(board);
}
// credential Service //
public Credential findByAccountId(Long id) {
return credentialRepository.findByAccountId(id);
}
//// repository ////
// board Repository //
// JpaRepository 사용
// reply Repository //
List<Reply> findByBoard(Board board);
// credential repository //
@Query("SELECT c FROM Credential c WHERE c.account.id = :id")
public Credential findByAccountId(@Param(value = "id") Long id);
//// controller ////
// 게시글 삭제
@GetMapping("/board/boardDelete/{id}")
public String boardDelete(@PathVariable("id") Long id){
System.out.println("board_id : "+id);
boardService.boardDelete(id);
return "redirect:/board/boardList";
}
//// service ////
// 게시글 삭제
@Transactional
public void boardDelete(Long id){
boardRepository.deleteById(id);
}
//// repository ////
// JpaRepository 사용

//// controller ////
// 게시판 리스트 페이징
@GetMapping("/board/boardList")
public String paging(Model model, @PageableDefault(sort = "id", direction = Direction.DESC, size=7)
Pageable pageable) {
Page<Board> boardList = boardService.getBoardList(pageable);
// 이전 다음 버튼
model.addAttribute("first", pageable.first().getPageNumber());
model.addAttribute("previous", pageable.previousOrFirst().getPageNumber());
model.addAttribute("next", pageable.next().getPageNumber());
model.addAttribute("last", pageable.getPageSize()-1);
// 이전 다음 페이지 유무
model.addAttribute("hasPrev", boardList.hasPrevious());
model.addAttribute("hasNext", boardList.hasNext());
// 토탈페이지 확인
model.addAttribute("total", boardList.getTotalPages()-1);
// 페이징 번호 처리
int nowPage = boardList.getPageable().getPageNumber()+1;
int startPage = Math.max(1, nowPage -2);
int endPage = Math.min(nowPage+2, boardList.getTotalPages());
int pageSize = 5;
int lastPage = boardList.getTotalPages();
int prevOfLastPage = boardList.getTotalPages()-1;
if(nowPage==1 || nowPage==2) {
if(lastPage<=pageSize) {
endPage = lastPage;
}else {
endPage = pageSize;
}
}else if(nowPage==prevOfLastPage || nowPage==lastPage) {
if((lastPage-4)<=0) {
startPage = 1;
}else {
startPage = lastPage-4;
}
}
model.addAttribute("boardList", boardList);
model.addAttribute("nowPage", nowPage);
model.addAttribute("startPage", startPage);
model.addAttribute("endPage", endPage);
return "/board/board_list";
}
//// service ////
// 페이징 처리
@Transactional
public Page<Board> getBoardList(Pageable pageable) {
Page<Board> boardList = boardRepository.findAll(pageable);
return boardList;
}
//// repository ////
// JpaRepository 사용


//// controller ////
// 게시판 검색후 페이징
@GetMapping("/board/boardSearchList")
public String searchPaging(String keyword, Model model, @PageableDefault(sort = "id", direction = Direction.DESC, size=7)
Pageable pageable) {
Page<Board> searchList = boardService.getSearchList(keyword, pageable);
// 이전 다음 버튼
model.addAttribute("first", pageable.first().getPageNumber());
model.addAttribute("previous", pageable.previousOrFirst().getPageNumber());
model.addAttribute("next", pageable.next().getPageNumber());
model.addAttribute("last", pageable.getPageSize()-1);
// 이전 다음 페이지 유무
model.addAttribute("hasPrev", searchList.hasPrevious());
model.addAttribute("hasNext", searchList.hasNext());
// 토탈페이지 확인
model.addAttribute("total", searchList.getTotalPages()-1);
// 페이징 번호 처리
int nowPage = searchList.getPageable().getPageNumber()+1;
int startPage = Math.max(1, nowPage -2);
int endPage = Math.min(nowPage+2, searchList.getTotalPages());
int pageSize = 5;
int lastPage = searchList.getTotalPages();
int prevOfLastPage = searchList.getTotalPages()-1;
if(nowPage==1 || nowPage==2) {
if(lastPage<=pageSize) {
endPage = lastPage;
}else {
endPage = pageSize;
}
}else if(nowPage==prevOfLastPage || nowPage==lastPage) {
if((lastPage-4)<=0) {
startPage = 1;
}else {
startPage = lastPage-4;
}
}
model.addAttribute("searchList", searchList);
model.addAttribute("nowPage", nowPage);
model.addAttribute("startPage", startPage);
model.addAttribute("endPage", endPage);
return "/board/board_search_list";
}
//// service ////
// 페이징 검색
@Transactional
public Page<Board> getSearchList(String keyword, Pageable pageable) {
Page<Board> searchList = boardRepository.findByTitleContaining(keyword, pageable);
return searchList;
}
//// repository ////
// 게시판 검색 키워드
public Page<Board> findByTitleContaining(String keyword, Pageable pageable);

//// controller ////
// 댓글작성
@PostMapping("/board/commentWriteSub/{id}")
public String boardWritePro(@Validated @ModelAttribute ReplyFormDto replyFormDto, Model model
,BindingResult bindingResult, HttpServletRequest request, @PathVariable("id") Long id){
if(bindingResult.hasErrors()) {
System.out.println("========= bindingResult Error =========");
System.out.println(bindingResult.toString());
System.out.println(bindingResult.getAllErrors().get(0));
return "/board/board_view";
}
Reply reply = new Reply();
Account account = credentialService.findUserInfo((String)request.getAttribute("id"));
reply.setContent(replyFormDto.getContent());
reply.setStartDate(LocalDate.now().toString());
reply.setAccount(account);
reply.setBoard(boardService.findById(id).get());
replyService.write(reply);
model.addAttribute("replyList", replyService.replyList());
return "redirect:/board/boardView/"+id;
}
//// service ////
// board Service //
// 상세보기 / 수정 페이징 id값 이동
public Optional<Board> findById(Long id) {
return boardRepository.findById(id);
}
// reply Service //
// 댓글 작성 / 수정
@Transactional
public void write(Reply reply) {
replyRepository.save(reply);
}
// 댓글 리스트
public List<Reply> replyList() {
return replyRepository.findAll();
}
// credential Service //
public Account findUserInfo(String username) {
return credentialRepository.findAccountByUsername(username);
}
//// repository ////
// board Repository //
// JpaRepository 사용
// reply Repository //
// JpaRepository 사용
// credential repository //
@Query("SELECT c.account FROM Credential c "
+ "WHERE c.username = :username")
public Account findAccountByUsername(@Param(value = "username") String username);
//// controller ////
// 댓글 삭제
@Transactional
@GetMapping("/board/commentDelete/{boardId}/{replyId}")
public String boardDelete(@PathVariable("boardId") Long boardId, @PathVariable("replyId") Long replyId, Model model){
System.out.println("댓글삭제 : " + replyId);
replyService.replyDelete(replyId);
return "redirect:/board/boardView/" + boardId;
}
//// service ////
// reply Service //
// 댓글 삭제
@Transactional
public void replyDelete(Long id) {
replyRepository.deleteById(id);
}
//// repository ////
// reply Repository //
// JpaRepository 사용
카카오로그인은 다른 팀원이 구현했는데 이번 프로젝트에서 중요했던부분이라 간단하게 보여주겠습니다.
위 사진에서 카카오로 로그인 버튼을 클릭하면 카카오에서 제공해주는 로그인 폼으로 이동하게 된다.
카카오로그인 폼에서 로그인을 한다.
카카오에서는 프로필 사진까지 제공해주는데 위 헤더에 카톡 프로필사진까지 뜨게 구현해놨다. 이 프로필 사진 뜨는거 하나가 퀄리티 차이가 엄청 큰거 같다.
카카오에서 제공하는 로그아웃폼인데 이 서비스만 로그아웃 버튼을 눌렀을때는 로그아웃은 됬지만 쿠키는 남아있어서
위에서 카카오로 로그인을 누르면 카카오로그인을 다시 안해줘도 로그인이 된다.
그리고 카카오계정과 함께 로그아웃을 누르면 쿠키가 삭제되 완전 로그아웃이된다.
저번 jsp프로젝트 때 보다 더 많은걸 알게 된거 같다.
jsp때 보다 쉬운거 같으면서 어려웠고
이번에는 다른팀원이 카카오로그인을 썼는데 APi 사용방법을 많이 공부해야봐야 될거같다.
그리고 역시 협업시에 git hub가 중요한데 git hub를 더 마스터 해야될거같고 코드를 더 깔끔하게 쓰는 연습을 해야 될거같다.