⭐저Do(just do) (Spring Team Project)⭐

p_chan.log·2023년 1월 2일

project

목록 보기
3/3

📜목차

  1. 기획의도
  2. 조원소개
  3. 프로젝트 환경 및 진행 일정
  4. 설계방식
    1) ERD
    2) Flow Chart
  5. 주요코드 설명
  6. 소감

👉 기획의도

우리는 바쁜세상을 살면서 다른 취미, 기술 등을 배워볼 시간이나 기회가 흔치않다.
그래서 우리팀은 간편하고 쉽게 배울수있고 접근성도 좋은 튜터링 사이트를 만들게 됐다.
자신의 재능을 팔수있고 그 재능을 배워볼수있는 최고의 튜터링 사이트인 저Do(just do) 이다.

📜조원소개

참여인원 : 6명

내가 맡은 작업

🎇 프로젝트 환경 및 진행 일정

🔨개발환경

📆개발일정

기간 : 22.12/12 ~ 22.12/27

📈 설계방식

👇 ERD

👇 FlowChart

✍️ 주요코드 설명

🙆‍♂️ 내가 맡은 작업 : 📝 게시판

이번 게시판을 만들때 Repository는 JpaRepository를 상속받아 만들었다.
JpaRepository를 상속받기 위해서는 interface로 class를 만들어야 한다.
JpaRepository를 상속받으면 Repository에 crud에 관한 메서드들을 따로 입력하지 않아도 되서 코드가 깔끔해진다.

@Entity

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;

}

dto

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를 더 마스터 해야될거같고 코드를 더 깔끔하게 쓰는 연습을 해야 될거같다.

profile
개발자 박찬의 노트

0개의 댓글