221109 Spring Boot 로그인, member

wonny·2022년 11월 10일
0

수업 복습

목록 보기
13/14

SpringBootMiniProject

로그인, 로그아웃

login/loginform.jsp

<body>
	<div class="container">
		<div class="row">
			<div class="col-sm-6 col-md-4 col-md-offset-4">
				<h1 class="text-center login-title">로그인</h1>
				<div class="account-wall">
					<img class="profile-img"
						src="https://lh5.googleusercontent.com/-b0-k99FZlyE/AAAAAAAAAAI/AAAAAAAAAAA/eu7opA4byxI/photo.jpg?sz=120"
						alt="">
					<form class="form-signin" action="loginprocess" method="post">
						<input type="text" name="id" class="form-control" placeholder="Id"
							required="required" value="${sessionScope.saveok==null?"":sessionScope.myid}" > 
						<input type="password" name="pass"
							class="form-control" placeholder="Password" required="required">
						<button class="btn btn-lg btn-primary btn-block" type="submit">Sign
							in</button>
						<label class="checkbox pull-left"> <input type="checkbox"
							name="cbsave" value="remember-me" ${sessionScope.saveok==null?"":"checked" }> Remember me
						</label> <a href="#" class="pull-right need-help">Need help? </a> <span
							class="clearfix"></span>
					</form>
				</div>
				<a href="#" class="text-center new-account">Create an account </a>
			</div>
		</div>
	</div>
</body>

LoginController.java

일단 로그인폼으로 이동하게끔 해놓고 나중에 로그인 상태에 따라 알맞게 이동하도록 수정해줘야 함

@GetMapping("/login/main")
public String form(){
	return "/sub2/login/loginform";
}

MemberMapperInter.java

public String getName(String id); //아이디에 해당하는 이름 가져오기
public int getIdPassCheck(Map<String, String> map); //아이디, 비밀번호 일치하는 데이터 찾기, 보내야 하는 parameter가 2개(아이디, 패스워드)니까 map으로 묶어야 한다. 

map에서 key값은 항상 String, value값은 id, pass 모두 String 이니까 String으로 써준다. 만약 String, int인 경우 Object로 주면 된다.

MemberSql.xml

	<select id="getName" parameterType="String" resultType="String">
		select name from bootmember where id=#{id}
	</select>
	<select id="getIdPassCheck" parameterType="HashMap" resultType="int">
		select count(*) from bootmember where id=#{id} and pass=#{pass}
	</select>

MemberServiceInter.java

	public String getName(String id); //아이디에 해당하는 이름 가져오기
	public int getIdPassCheck(String id, String pass); 

service에서는 map을 풀어서 String id, String pass 각각 써준다.

MemberService.java

	@Override
	public String getName(String id) {
		// TODO Auto-generated method stub
		return mapperInter.getName(id);
	}

	@Override
	public int getIdPassCheck(String id, String pass) {
		// TODO Auto-generated method stub
		
		Map<String, String> map = new HashMap<>();
		
		map.put("id", id);
		map.put("pass", pass);
		
		return mapperInter.getIdPassCheck(map);
	}

LoginController.java

//로그인폼 -> loginprocess
	@PostMapping("/login/loginprocess")
	public String loginProc(@RequestParam String id,
			@RequestParam String pass,
			@RequestParam(required = false) String cbsave,
			HttpSession session) {
		
		//id, pass 일치하는게 있는지 없는지
		int check = service.getIdPassCheck(id, pass);
		
		//check==1인 경우(db에 id, pass 일치 데이터가 있다는 얘기)
		if(check==1) {
			session.setMaxInactiveInterval(60*60*8); //8시간 저장
						
			session.setAttribute("myid", id); //가져온 id를 myid로 저장 
			session.setAttribute("loginok", "yes"); //loginok를 yes로 저장
			session.setAttribute("saveok", cbsave); //cbsave 값을 saveok로 저장, 체크 되어 있으면 'on', 체크 없으면 null
			
			return "redirect:main"; //check==1인 경우에만 main으로 보내야 하니까..!(0이면 로그인 fail)
			
		}else {
			
			return "/member/passfail";
		}
		
	}

cbsave는 체크 안되어 있을 때 오류가 날 수도 있기 때문에 required = false를 해준다.

passfail.jsp

아이디나 비밀번호가 틀린 경우 '로그인 실패' 알림창이 뜨고 다시 로그인폼으로 돌아가기

<script type="text/javascript">
	alert("로그인 실패");
	history.back();

</script>

LoginController.java

세션에서 로그인 상태 확인하고, 상태에 따라 알맞게 로그인폼 이동하게 수정한다.
로그인 상태이면 버튼을 로그아웃 폼으로, 로그아웃 상태이면 로그인 폼으로!

@GetMapping("/login/main")
	public String loginform(HttpSession session, Model model) {
		
		//로그인 상태인지 아닌지 -> 상태에 따라 나오는 화면이 달라야 하니까
		String loginok = (String)session.getAttribute("loginok"); //session에서 loginok를 가져와서 loginok라고 하겠다.
		
		//폼의 id 얻어오기
		String myid=(String)session.getAttribute("myid"); //세션에 저장한 id를 myid로 저장해놨었는데 그걸 myid로 가져온다.
		
		//cbsave값 가져오기
		String saveok = (String)session.getAttribute("saveok");
		
		if(loginok==null) {
			return "/sub2/login/loginform";
		}else {
			
			//로그인 중에는 로그인한 계정의 이름을 저장
			String name = service.getName(myid);
			
			//request에 저장하기(model)
			model.addAttribute("name", name);
			
			return "/sub2/login/logoutform";
		}
		
	}
    
    //로그아웃
    @GetMapping("/login/logoutprocess")
	public String logoutProc(HttpSession session) {
		session.removeAttribute("loginok");
		return "redirect:main";
	}

layout/title.jsp

로그인 상태이면 '로그아웃' 버튼이 보이고, 로그아웃 상태이면 '로그인' 버튼이 보이게

<div class="login">
	<c:if test="${sessionScope.loginok==null}">
		<button type="button" class="btn btn-primary" onclick="location.href='${root}/login/main'" style="float: right;">로그인</button>
	</c:if>
	<c:if test="${sessionScope.loginok!=null}">
		<b>${sessionScope.myid }님이 로그인 중입니다.</b>
		<button type="button" class="btn btn-primary" onclick="location.href='${root}/login/logoutprocess'" style="text-align: center;">로그아웃</button>
	</c:if>
	
</div>

로그인 계정 정보만 보이게하기

myinfo.jsp

<table class="table table-bordered" style="width: 700px;">
	<c:forEach var="dto" items="${list }">
		<c:if test="${sessionScope.loginok!=null && sessionScope.myid==dto.id }">
		<tr>
			<td style="width: 200px;" align="center" rowspan="5">
				<img alt="" src="../photo/${dto.photo}" width="180" height="240" border="1">
				<br><br>
				<input type="file" name="newphoto" id="newphoto" style="display: none;" num=${dto.num }>
				<button type="button" class="btn btn-info btnnewphoto">사진 변경</button>
			</td>
			<td style="width: 250px;">이름: ${dto.name }</td>
			<td rowspan="5" align="center" width="200">
				<button type="button" class="btn btn-warning">수정</button>
				<button type="button" class="btn btn-danger" id="deleteme" num=${dto.num }>탈퇴</button>
			</td>
		</tr>
		<tr>
			<td>
				아이디: ${dto.id }
			</td>
		</tr>
		<tr>
			<td>
				이메일: ${dto.email }
			</td>
		</tr>
		<tr>
			<td>
				연락처: ${dto.hp }
			</td>
		</tr>
		<tr>
			<td>
				주소: ${dto.addr }
			</td>
		</tr>
	
		</c:if>
	</c:forEach>
</table>

로그인 계정 프로필 사진 띄우기

로그인한 계정의 이미지를 세션으로 가져오려면 sessionScope에 저장을 해줘야 한다.

MemberMapperInter.java

public MemberDto getDataById(String id); //아이디를 통해서 dto값 가져오기

MemberSql.java

<select id="getDataById" parameterType="String" resultType="member">
		select * from bootmember where id=#{id}
</select>

MemberServiceInter.java

public MemberDto getDataById(String id);

MemberService.java

@Override
	public void deleteMember(String num) {
		// TODO Auto-generated method stub
		mapperInter.deleteMember(num);
	}

LoginController.java

로그인 과정에서 MemberDto를 mdto를 불러오고 service.getDataById(id);로 저장한다. session에 mdto.getPhoto를 "loginphoto"로 저장해준다.

	//로그인폼 -> loginprocess
	@PostMapping("/login/loginprocess")
	public String loginProc(@RequestParam String id,
			@RequestParam String pass,
			@RequestParam(required = false) String cbsave,
			HttpSession session) {
		
		//id, pass 일치하는게 있는지 없는지
		int check = service.getIdPassCheck(id, pass);
		
		//check==1인 경우(db에 id, pass 일치 데이터가 있다는 얘기)
		if(check==1) {
			session.setMaxInactiveInterval(60*60*8); //8시간 저장
			
			//dto 선언
			MemberDto mdto = service.getDataById(id);
			
			session.setAttribute("myid", id); //가져온 id를 myid로 저장 
			session.setAttribute("loginok", "yes"); //loginok를 yes로 저장
			session.setAttribute("saveok", cbsave); //cbsave 값을 saveok로 저장, 체크 되어 있으면 'on', 체크 없으면 null
			session.setAttribute("loginphoto", mdto.getPhoto());
			
			return "redirect:main"; //check==1인 경우에만 main으로 보내야 하니까..!(0이면 로그인 fail)
			
		}else {
			
			return "/member/passfail";
		}
		
	}

info.jsp

<!-- 로그인 안되어 있을 땐 기본 'noimage'사진이 나온다.-->
<c:if test="${sessionScope.loginok==null}">
	<img alt="" src="${root}/image/noimage.png" class="img-circle" style="width: 100px; height: 100px;">
</c:if>
<!-- 로그인 상태일 땐 계정의 photo가 나온다. -->
<c:if test="${sessionScope.loginok!=null}">
	<img alt="" src="${root}/photo/${sessionScope.loginphoto}" class="img-circle" style="width: 100px; height: 100px;">
</c:if>

삭제(체크박스)

MemberMapperInter.java

public void deleteMember(String num); //삭제

MemberSql.xml

<delete id="deleteMember" parameterType="String">
		delete from bootmember where num=#{num}
	</delete>

MemberServiceInter.java

public void deleteMember(String num);

MemberService.java

@Override
	public void deleteMember(String num) {
		// TODO Auto-generated method stub
		mapperInter.deleteMember(num);
	}

memberlist.jsp

<script type="text/javascript">
	$(function(){
		
		//전체 체크박스 체크 여부 따라 아래 체크박스 체크/해제
		$("#allcheck").click(function(){
		
			//allcheck 클릭했을 때 체크값 얻기
			var chk = $(this).is(":checked"); //true/false
			console.log(chk);
			
			//체크값을 글별 체크에 일괄 전달
			$(".del").prop("checked",chk);
		});
		
		
		
	});
</script>
</head>
<body>
<h2 class="alert alert-info">${totalCount }명의 회원이 가입되어 있습니다.</h2>
<hr>
<c:if test="${sessionScope.loginok!=null && sessionScope.myid=='admin' }">
<table class="table table-bordered" style="width: 1000px;">
		<tr>
			<th style="width: 50px;">번호</th>
			<th style="width: 100px;">이름</th>
			<th style="width: 100px;">아이디</th>
			<th style="width: 120px;">연락처</th>
			<th style="width: 150px;">이메일</th>
			<th style="width: 120px;">주소</th>
			<th style="width: 100px;">가입일</th>
			<th style="width: 60px;"><input type="checkbox" id="allcheck"> 삭제</th>
		</tr>
		
		<c:forEach var="dto" items="${list }" varStatus="i">
			<tr>
				<td>${i.count}</td>
				<td><img alt="" src="../photo/${dto.photo }" style="width: 30px; height: 30px;"> ${dto.name }</td>
				<td>${dto.id }</td>
				<td>${dto.hp}</td>
				<td>${dto.email }</td>
				<td>${dto.addr }</td>
				<td><fmt:formatDate value="${dto.gaipday }" pattern="yyyy-MM-dd"/> </td>
				<td><input type="checkbox" class="del" num=${dto.num }></td>
			</tr>
		</c:forEach>
		
</table>
	<button type="button" class="btn btn-danger" style="float: right;" id="btnmemberdel">삭제</button>
</c:if>
</body>

MemberController.java

json 반환할 값이 없기 때문에 void, json 반환할 값이 있는 경우 Map<String, Integer> 이런 식으로 써줘야 한다.


		//delete
		@GetMapping("/member/delete")
		@ResponseBody //생략하고 ajax에서 dataType 생략해줘도 됨
		public void delete(@RequestParam String num) {
			
			service.deleteMember(num);
			
		}
		

memberlist.jsp

<script type="text/javascript">
	$(function(){
    
		//체크한 회원 삭제
		$("#btnmemberdel").click(function(){
			
			//체크한 인원 수 구하기
			var cnt = $(".del:checked").length;
			//alert(cnt);
			
			if(cnt==0){
				alert("삭제할 회원을 선택하세요");
				return;
			}else{
				$(".del:checked").each(function(i,ele){
					var num = $(this).attr("num");
					console.log(num);
					
					$.ajax({
						url:"delete",
						type:"get",
						data:{"num":num},
						dataType:"html",
						success: function(res){
							location.reload();
							
						}
						
					});
				});
			}
		});
   });

수정(ajax 방식으로 - formData 객체)

formData 객체를 활용할 땐 contentType, processData를 false로 줘야 한다.

MemberMapperInter.java

public MemberDto getDataByNum(String num); //num에 해당하는 데이터
	public void updatePhoto(Map<String, String> map); //num에 해당하는 사진 수정하기 - setPhoto, num이 필요하니까 Object object 대신 String 해도 되긴 함
	public void updateMember(MemberDto dto); //num에 해당하는 모든 dto 수정하기

MemberSql.xml

<select id="getDataByNum" parameterType="String" resultType="member">
		select * from bootmember where num=#{num}
	</select>
	<update id="updatePhoto" parameterType="map">
		update bootmember set photo=#{photo} where num=#{num}	
	</update>
	<update id="updateMember" parameterType="member" >
		update bootmember set name=#{name}, hp=#{hp}, addr=#{addr}, email=#{email} where num=#{num}
	</update>

MemberServiceInter.java

map으로 줬던건 풀어서 써준다.

public MemberDto getDataByNum(String num); //num에 해당하는 데이터
	public void updatePhoto(String num, String photo); //num에 해당하는 사진 수정하기 - setPhoto, num이 필요하니까 Object object 대신 String 해도 되긴 함
	public void updateMember(MemberDto dto); //num에 해당하는 모든 dto 수정하기

MemberService.java

@Override
	public MemberDto getDataByNum(String num) {
		// TODO Auto-generated method stub
		return mapperInter.getDataByNum(num);
	}

	@Override
	public void updatePhoto(String num, String photo) {
		// TODO Auto-generated method stub
		
		Map<String, String> map = new HashMap<>();
		
		map.put("num", num);
		map.put("photo", photo);
		
		mapperInter.updatePhoto(map);
	}
	
	@Override
	public void updateMember(MemberDto dto) {
		// TODO Auto-generated method stub
		mapperInter.updateMember(dto);
	}

myinfo.jsp

<td style="width: 200px;" align="center" rowspan="5">
				<img alt="" src="../photo/${dto.photo}" width="180" height="240" border="1">
				<br><br>
				<input type="file" name="newphoto" id="newphoto" style="display: none;" num=${dto.num }>
				<button type="button" class="btn btn-info btnnewphoto">사진 변경</button>
			</td>
<script type="text/javascript">
$(function(){
	//사진 변경 버튼 클릭시 파일 선택창 열기
	$(".btnnewphoto").click(function(){
		$("#newphoto").trigger("click");
	});
	
	//사진 선택하면 이미지 미리보기
	$("#newphoto").change(function(){
		var num = $(this).attr("num");
		console.log(num);
		
		var form = new FormData();
		form.append("photo", $("#newphoto")[0].files[0]);
		form.append("num", num);
		
		console.dir(form); //dir은 객체를 읽어옴
		
		
	});
	

});
</script>

MemberController.java

//formData는 getMapping(x), PostMapping(O)
		@PostMapping("/member/updatephoto")
		@ResponseBody
		public void photoUpload(String num,
				MultipartFile photo,
				HttpSession session) {
			
			//업로드 될 경로
			String path = session.getServletContext().getRealPath("/photo");
			
			//업로드 파일명
			SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
			String filename = "img_"+sdf.format(new Date())+photo.getOriginalFilename();
			
			//실제 업로드
			try {
				photo.transferTo(new File(path+"\\"+filename));
				
				service.updatePhoto(num, filename);
				
			} catch (IllegalStateException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}

myinfo.jsp

//사진 선택하면 이미지 미리보기
	$("#newphoto").change(function(){
		var num = $(this).attr("num");
		console.log(num);
		
		var form = new FormData();
		form.append("photo", $("#newphoto")[0].files[0]);
		form.append("num", num);
		
		console.dir(form); //dir은 객체를 읽어옴
		
		$.ajax({
			url:"updatephoto",
			type:"post",
			data:form,
			dataType:"text",
			processData:false,
			contentType:false,
			success:function(res){
				location.reload();
			}
		});
		
	});

삭제(myinfo에서)

myinfo.jsp

탈퇴 버튼에 num 값을 넣어준다.

<button type="button" class="btn btn-danger" id="deleteme" num=${dto.num }>탈퇴</button>

MemberController.jsp

//myinfo 탈퇴
		@GetMapping("/member/deleteme")
		@ResponseBody
		public void deleteme(String num,
				HttpSession session) {
			
			service.deleteMember(num);
			
			session.removeAttribute("loginok");
			session.removeAttribute("myid");
			session.removeAttribute("loginphoto");
			
		}

myinfo.jsp

//탈퇴 버튼 누르면 탈퇴
	$("#deleteme").click(function(){
		var num = $(this).attr("num");
		console.log(num);
		
		var a = "탈퇴하시겠습니까?";
		confirm(a);
		if(a){
		
		$.ajax({
			url:"deleteme",
			type:"get",
			data:{"num":num},
			dataType:"html",
			success: function(res){
				
				location.href="/login/main";
			}
			
		});
		
			
		}
	});
profile
하다 보면 되겠지요..!

0개의 댓글