[토이 투표] 22.07.05 일지

재호·2022년 7월 5일
0

기표 체크

기존에 투표에 참여한 사람은 재참여가 불가능 하도록 투표 처리 메서드를 수정했다.

	//VoteItemRepository
	@Query(value="select v.* from voteitem v where  board_num=?", nativeQuery = true)
	List<VoteItem> findByBno(Long bno);
    
    
    
    //VoteDetailRepository
    @Query(value = "select v.* from votedetail v where voter=:voter and item_num=:ino", nativeQuery = true)
	Optional<VoteDetail> findByVoterAndIno(@Param("voter") String voter, @Param("ino") Long ino);


	
    //ItemService
	@Override //실제 투표 처리
	public String throwVote(VoteItemDTO itemDTO, String email) {
		List<VoteItem> list = itemRepository.findByBno(itemDTO.getBoard_num());
		//이미 투표했는지 여부 확인
		boolean checkVote = false;
		for(VoteItem item : list) {
			Optional<VoteDetail> optional = detailRepository.findByVoterAndIno(email, item.getIno());
			if(optional.isPresent()) {
				checkVote = true;
				break;
			}
		}
		if(checkVote) { //기투표자
			return "참여한투표";
		}
	
		VoteItem item = itemRepository.findById(itemDTO.getIno()).get();
		
		VoteDetail detail = VoteDetail.builder().voter(email)
											.voteitem(item)
											.build();
		// save를 하면 commit이 되기 때문에 EntityManager의 persist를 이용
		em.persist(detail);
		
		VoteDetail result = null;
		
		Optional<VoteDetail> optional = detailRepository.findById(detail.getDno());
		if(optional.isPresent()) {
			result = optional.get();
		}
		
		// 득표 수 갱신
		Integer itemCount = detailRepository.countByVoteitem(item);
		//commit 전 이므로 더티 체킹을 이용해 업데이트
		item.countVote(itemCount);
		
		if(result != null) return "성공";
		return "실패";
	}

투표를 눌렀을 때 해당 투표 글의 투표 항목들을 모두 불러오는 쿼리를 하나 만들었는데 JPQL을 이용하려면 엔티티를 사용해야 하고 그렇게 되면 select 쿼리가 한번 필요하기 때문에 Native Query를 사용했다. 그렇게 받아온 투표 항목 리스트들을 순회하며 투표자의 이메일과 투표항목의 id를 동시에 만족하는 결과를 찾는 쿼리를 만들었고 이 또한 아까와 같은 이유로 Native Query로 만들었다. 이 쿼리의 결과가 비어있지 않다면 투표를 했다는 의미이므로 투표처리는 종료된다.

회원 관련 기능 구현


메인 화면의 기능들은 대부분 구현한 상황이다. 맨 위 네비게이션 바를 보면 로그인 버튼이 있는데 세션에서 로그인 정보를 읽어와 로그인 여부를 확인하고 로그인로그아웃 글자를 동적으로 바뀌게 했다. 당연히 이동 URL또한 변경된다. 또한 회원가입 버튼도 마찬가지로 로그인이 되어있지 않다면 회원가입 로그인이 되있다면 마이페이지가 보이도록 되어있다.


로그인 화면은 아주 간단하게 만들었다. 로그인 컨트롤러에서 아이디와 비밀번호가 올바른지 확인하고 성공 시 메인화면으로 이동한다. 자동 로그인 버튼에 대한 기능은 우선순위를 낮게 잡아서 마지막으로 미룬 상태이다.


회원가입 시에는 이메일뿐만 아니라 닉네임 또한 중복 체크를 해야한다. 이 웹사이트에서는 투표 글을 작성했을 때 노출되는 회원 정보를 이메일이 아니라 닉네임으로 사용할 것이기 때문이다.


마이 페이지로 이동하면 비밀번호를 제외한 회원 정보가 출력되도록 했다. 아래의 수정 버튼을 누르면 회원 정보를 수정할 수 있는 페이지로 이동한다.


모든 정보를 수정할 수 있고 그에 대해 다시 한번 이메일이나 닉네임에 대한 중복확인을 해야한다.
이메일이나 닉네임에 대한 입력값이 변동되면 사용가능 여부를 저장하는 변수에 대해 false 값을 주고 중복확인을 통해 중복 여부의 확인이 완료되면 다시 true로, 그리고 수정하기 버튼을 누를 당시에 입력값이 기존 이메일이나 닉네임과 같다면 다시 true로 변경시켜 정보 수정이 완료될 수 있도록 했다.

ajax 처리

회원가입이나 수정에서 이메일과 닉네임에 대한 중복확인을 위해 비동기적 데이터 통신을 해야하기 때문에 ajax를 사용해야 한다. 지난 프로젝트에서는 JQuery를 사용해서 ajax를 구현했지만 JQuery가 사장되어가는 추세라서 라이브러리를 쓰지 않고 자바스크립트의 fetch를 이용서 구현했다.
또한 ajax 데이터 통신을 하는 Controller 메서드도 새로 구현했다.

	//이메일 중복 확인
	@ResponseBody
	@PostMapping("/emailcheck")
	public JSONObject emailCheck(@RequestBody MemberDTO dto){
		log.info("이메일 중복 확인 요청");
		//결과: "사용가능" or "사용불가"
		String result = memberService.checkEmail(dto.getEmail());
		Map<String, String> map = new HashMap<>();
		map.put("result", result);
		
		JSONObject jsonObj = new JSONObject(map);
		
		return jsonObj;
	}
	
	//닉네임 중복 확인
	@ResponseBody
	@PostMapping("/nicknamecheck")
	public JSONObject nicknameCheck(@RequestBody MemberDTO dto){
		log.info("닉네임 중복 확인 요청");
		//결과: "사용가능" or "사용불가"
		String result = memberService.checkNickname(dto.getNickname());
		Map<String, String> map = new HashMap<>();
		map.put("result", result);
		
		JSONObject jsonObj = new JSONObject(map);
		
		return jsonObj;
	}
    
    ------------------------------------------------------------
    
		//이메일 중복 확인
		const emailBtn = document.querySelector(".btn-email");
		emailBtn.addEventListener('click', idCheck);

		function idCheck(){
			var email = document.querySelector("#email");
			var val = email.value;

			fetch("/member/emailcheck", {
				method: "POST",
				headers: {
					"Content-Type" : "application/json",
				},
				body: JSON.stringify({email: val})
			})
			.then((response) => response.json())
			.then((data) => {
				console.log(data);
				if(data.result == "사용가능"){
					alert("사용이 가능한 이메일입니다");
					emailUsable = true;
				}else if(data.result == "사용불가"){
					alert("이미 가입된 이메일입니다");
					email.value = "";
					emailUsable = false;
				}
			});
		}

@ResponseBody를 통해 리턴 값이 View가 아닌 일반 데이터가 전송되도록 설정하고, 파라미터 앞에 @RequestBody를 넣어줘서 Json형식으로 들어오는 데이터를 파싱시켜준다. 메서드의 리턴값으로 Json형식을 사용하기 위해 JSONObject를 사용했다.

투표글 목록


최신 투표글부터 나오도록 정렬되어 있고 간단하게 제목과 작성자의 닉네임만 보이도록 했다. 리스트의 우측 상단에 검색 영역이 있고 [제목, 내용, 제목+내용, 작성자] 별 카테고리로 검색을 할 수 있도록 했다. 검색한 후 페이지를 이동할 때 검색 내용이 초기화되지 않도록 URL을 설정했다.

Git

https://github.com/JINJAEHO/vote

profile
Java, Spring, SpringMVC, JPA, MyBatis

0개의 댓글