Spring

12.12.(월) Spring Framework(13): 회원관리 기능(7)

콜라든포비 2022. 12. 15. 20:57

로그인

회원가입을 했으니 로그인을 해보자.

로그인 form 페이지

URL매핑

상단 메뉴바에 미리 만들어놓은 로그인버튼에 하이퍼링크를 설정해주고 jsp파일을 만들자.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="<%= request.getContextPath() %>/js_css/style.css" type="text/css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
</head>
<body>
	<div class="topMenu">
		<ul>
			<li><a href="/myapp/">홈</a></li>
			<li><a href="/myapp/member/login">로그인</a></li>
			<li><a href="/myapp/member/signup">회원가입</a></li>
			<li><a href="#">로그아웃/회원정보수정</a></li>
			<li><a href="#">게시판</a></li>
			<li><a href="#">자료실</a></li>
		</ul>
	</div>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<div class="container">
	<h1>로그인</h1>
	<form method="post" action="/myapp/member/loginOk">
		<ul>
			<li>아이디 : <input type="text" name="username" id="username" maxlength="15" placeholder="아이디를 입력하세요."></li>
			<li>비밀번호 : <input type="password" name="password" id="password" placeholder="비밀번호를 입력하세요."></li>
			<li><input type="submit" value="로그인"></li>
		</ul>
	</form>
</div>

컨트롤러 매핑

그리고 메뉴바에서 로그인 페이지로 이동하는 매핑을 컨트롤러에 해준다.

package com.poby.myapp.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
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 org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.poby.myapp.service.MemberService;
import com.poby.myapp.vo.MemberVO;
import com.poby.myapp.vo.ZipcodeVO;

@Controller
public class MemberController {
	// 클래스를 찾아 객체를 생성해주는 어노테이션
	@Autowired
	MemberService service;
	
	// 회원가입 페이지 이동
	@RequestMapping("/member/signup")
	public String signup() {
		return "member/signup";
	}
	
	// 아이디 중복확인 팝업
	@RequestMapping("/member/idCheck")
	public String idCheck(String username, Model model) {
		// DB에 username이 이미 존재하는지 확인
		int result = service.idCheck(username);
		
		model.addAttribute("username", username);	// 검색 조건
		model.addAttribute("result", result);		// 검색 결과
		
		return "member/idCheck";
	}
	
	// 우편번호 검색 팝업
	@GetMapping("/member/searchZipcode")
	public ModelAndView searchZipcode(String street) {
		ModelAndView mav = new ModelAndView();
		
		List<ZipcodeVO> list = null;
		if(street!=null && street!="") {
			// 도로명 주소가 있을때만 DB검색 실시
			list = service.searchZipcode(street);
		}
		
		mav.addObject("list", list);	// 검색값이 있으면 제대로 리턴, 없으면 null
		
		mav.setViewName("member/searchZipcode");
		return mav;
	}
	
	// 회원가입
//	@RequestMapping(value="/member/signupOk", method=RequestMethod.POST)
	@PostMapping("/member/signupOk")
	public ModelAndView signupOk(MemberVO vo) {
		ModelAndView mav = new ModelAndView();
		System.out.println(vo.toString());
		
		int result = service.signupOk(vo);
		
		if(result>0) {
			mav.setViewName("redirect:/");	// 뷰페이지 이름을 jsp파일명 대신 다른 컨트롤러의 매핑 주소로 보낸다
		}else {
			mav.setViewName("member/signupResult");
		}
		return mav;
	}
	
	// 로그인 페이지로 이동
	@RequestMapping("/member/login")
	public String login() {
		return "member/login";
	}
}

로그인 정보 DB조회

URL매핑

URL매핑은 앞서 form태그의 action에서 해줬다.

컨트롤러 매핑

로그인 정보를 DB에서 조회시킬 loginOk을 컨트롤러에 매핑하자.

package com.poby.myapp.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
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 org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.poby.myapp.service.MemberService;
import com.poby.myapp.vo.MemberVO;
import com.poby.myapp.vo.ZipcodeVO;

@Controller
public class MemberController {
	// 클래스를 찾아 객체를 생성해주는 어노테이션
	@Autowired
	MemberService service;
	
	// 회원가입 페이지 이동
	@RequestMapping("/member/signup")
	public String signup() {
		return "member/signup";
	}
	
	// 아이디 중복확인 팝업
	@RequestMapping("/member/idCheck")
	public String idCheck(String username, Model model) {
		// DB에 username이 이미 존재하는지 확인
		int result = service.idCheck(username);
		
		model.addAttribute("username", username);	// 검색 조건
		model.addAttribute("result", result);		// 검색 결과
		
		return "member/idCheck";
	}
	
	// 우편번호 검색 팝업
	@GetMapping("/member/searchZipcode")
	public ModelAndView searchZipcode(String street) {
		ModelAndView mav = new ModelAndView();
		
		List<ZipcodeVO> list = null;
		if(street!=null && street!="") {
			// 도로명 주소가 있을때만 DB검색 실시
			list = service.searchZipcode(street);
		}
		
		mav.addObject("list", list);	// 검색값이 있으면 제대로 리턴, 없으면 null
		
		mav.setViewName("member/searchZipcode");
		return mav;
	}
	
	// 회원가입
//	@RequestMapping(value="/member/signupOk", method=RequestMethod.POST)
	@PostMapping("/member/signupOk")
	public ModelAndView signupOk(MemberVO vo) {
		ModelAndView mav = new ModelAndView();
		System.out.println(vo.toString());
		
		int result = service.signupOk(vo);
		
		if(result>0) {
			mav.setViewName("redirect:/");	// 뷰페이지 이름을 jsp파일명 대신 다른 컨트롤러의 매핑 주소로 보낸다
		}else {
			mav.setViewName("member/signupResult");
		}
		return mav;
	}
	
	// 로그인 페이지로 이동
	@RequestMapping("/member/login")
	public String login() {
		return "member/login";
	}
	
	// 로그인
	@PostMapping("/member/loginOk")
	public ModelAndView loginOk(MemberVO vo) {
		ModelAndView mav = new ModelAndView();
		
		// 아이디와 비밀번호가 일치하면 username, name 선택
		
		
		return mav;
	}
}

DAO, Service, ServiceImpl 객체 생성

이제 DAO, Service, ServiceImpl에 메소드를 추가하자.

package com.poby.myapp.dao;

import java.util.List;

import com.poby.myapp.vo.MemberVO;
import com.poby.myapp.vo.ZipcodeVO;

public interface MemberDAO {
	// 아이디 중복확인
	public int idCheck(String username);
	
	// 우편번호 검색
	public List<ZipcodeVO> searchZipcode(String street);
	
	// 회원 등록
	public int signupOk(MemberVO vo);
	
	// 로그인
	public MemberVO loginOk(MemberVO vo);
}
package com.poby.myapp.service;

import java.util.List;

import com.poby.myapp.vo.MemberVO;
import com.poby.myapp.vo.ZipcodeVO;

public interface MemberService {
	public int idCheck(String username);
	public List<ZipcodeVO> searchZipcode(String street);
	public int signupOk(MemberVO vo);
	public MemberVO loginOk(MemberVO vo);
}
package com.poby.myapp.service;

import java.util.List;

import javax.inject.Inject;

import org.springframework.stereotype.Service;

import com.poby.myapp.dao.MemberDAO;
import com.poby.myapp.vo.MemberVO;
import com.poby.myapp.vo.ZipcodeVO;

@Service
public class MemberServiceImpl implements MemberService {
	@Inject
	MemberDAO dao;

	@Override
	public int idCheck(String username) {
		return dao.idCheck(username);
	}

	@Override
	public List<ZipcodeVO> searchZipcode(String street) {
		return dao.searchZipcode(street);
	}

	@Override
	public int signupOk(MemberVO vo) {
		return dao.signupOk(vo);
	}

	@Override
	public MemberVO loginOk(MemberVO vo) {
		return dao.loginOk(vo);
	}
}

쿼리문 작성

쿼리문을 memberMapper.xml에 작성하자.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.poby.myapp.dao.MemberDAO">
	<select id="idCheck" resultType="int">
		SELECT count(username) cnt FROM member_tbl WHERE username=#{param1}
	</select>
	<select id="searchZipcode" resultType="com.poby.myapp.vo.ZipcodeVO">
		SELECT zipcode, city, street, bldg1, bldg2, bldgname, dong, num1, num2 
		FROM zipcode_tbl WHERE street LIKE '%${param1}%'
	</select>
	<insert id="signupOk">
		INSERT INTO member_tbl(username, password, name, tel, email, zipcode, addr, detailaddr) 
		VALUES (#{username}, #{password}, #{name}, #{tel}, #{email}, #{zipcode}, #{addr}, #{detailaddr})
	</insert>
	<select id="loginOk" resultType="com.poby.myapp.vo.MemberVO">
		SELECT username, name FROM member_tbl WHERE username=#{username} AND password=${password}
	</select>
</mapper>

컨트롤러 완성

로그인 정보를 확인하고 아이디와 이름을 select해왔으니, 이 데이터를 컨트롤러를 통해서 뷰페이지로 넘겨주자.

package com.poby.myapp.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
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 org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.poby.myapp.service.MemberService;
import com.poby.myapp.vo.MemberVO;
import com.poby.myapp.vo.ZipcodeVO;

@Controller
public class MemberController {
	// 클래스를 찾아 객체를 생성해주는 어노테이션
	@Autowired
	MemberService service;
	
	// 회원가입 페이지 이동
	@RequestMapping("/member/signup")
	public String signup() {
		return "member/signup";
	}
	
	// 아이디 중복확인 팝업
	@RequestMapping("/member/idCheck")
	public String idCheck(String username, Model model) {
		// DB에 username이 이미 존재하는지 확인
		int result = service.idCheck(username);
		
		model.addAttribute("username", username);	// 검색 조건
		model.addAttribute("result", result);		// 검색 결과
		
		return "member/idCheck";
	}
	
	// 우편번호 검색 팝업
	@GetMapping("/member/searchZipcode")
	public ModelAndView searchZipcode(String street) {
		ModelAndView mav = new ModelAndView();
		
		List<ZipcodeVO> list = null;
		if(street!=null && street!="") {
			// 도로명 주소가 있을때만 DB검색 실시
			list = service.searchZipcode(street);
		}
		
		mav.addObject("list", list);	// 검색값이 있으면 제대로 리턴, 없으면 null
		
		mav.setViewName("member/searchZipcode");
		return mav;
	}
	
	// 회원가입
//	@RequestMapping(value="/member/signupOk", method=RequestMethod.POST)
	@PostMapping("/member/signupOk")
	public ModelAndView signupOk(MemberVO vo) {
		ModelAndView mav = new ModelAndView();
		System.out.println(vo.toString());
		
		int result = service.signupOk(vo);
		
		if(result>0) {
			mav.setViewName("redirect:/");	// 뷰페이지 이름을 jsp파일명 대신 다른 컨트롤러의 매핑 주소로 보낸다
		}else {
			mav.setViewName("member/signupResult");
		}
		return mav;
	}
	
	// 로그인 페이지로 이동
	@RequestMapping("/member/login")
	public String login() {
		return "member/login";
	}
	
	// 로그인
	@PostMapping("/member/loginOk")
	public ModelAndView loginOk(MemberVO vo) {
		ModelAndView mav = new ModelAndView();
		
		// 아이디와 비밀번호가 일치하면 username, name 선택
		MemberVO VO = service.loginOk(vo);
		
		if(VO==null) {
			// 로그인 실패 시 로그인 페이지로 이동
			mav.setViewName("redirect:login");
		}else {
			// 로그인 성공 시 홈페이지로 이동
			mav.setViewName("redirect:/");
		}
		
		return mav;
	}
}

로그인 성공 시 홈페이지로 이동할때 세션에다가 아이디와 이름을 기록할 것이다.

HttpRequest를 통해서 해도 되지만, 매개변수에 곧 바로 HttpSession을 넣어서 기록할 수도 있다.

// 로그인
@PostMapping("/member/loginOk")
public ModelAndView loginOk(MemberVO vo, HttpSession session) {
	ModelAndView mav = new ModelAndView();
	
	// 아이디와 비밀번호가 일치하면 username, name 선택
	MemberVO VO = service.loginOk(vo);
	
	if(VO==null) {
		// 로그인 실패 시 로그인 페이지로 이동
		mav.setViewName("member/login");
	}else {
		// 로그인 성공 시 홈페이지로 이동
		mav.setViewName("redirect:/");
		// 세션에 로그인 정보 저장
		session.setAttribute("username", VO.getUsername());
		session.setAttribute("name", VO.getName());
		session.setAttribute("logStatus", "Y");
	}
	
	return mav;
}

뷰페이지 수정

상단 메뉴바를 세션에 저장된 로그인 정보에 따라 다르게 표시하도록 수정하자.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="<%= request.getContextPath() %>/js_css/style.css" type="text/css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
</head>
<body>
	<div class="topMenu">
		<ul>
			<li><a href="/myapp/">홈</a></li>
			<c:if test="${ logStatus!='Y' }">
				<li><a href="/myapp/member/login">로그인</a></li>
				<li><a href="/myapp/member/signup">회원가입</a></li>
			</c:if>
			<c:if test="${ logStatus=='Y' }">
				<li><a href="#">로그아웃</a></li>
				<li><a href="#">회원정보수정</a></li>
			</c:if>
			<li><a href="#">게시판</a></li>
			<li><a href="#">자료실</a></li>
		</ul>
	</div>

※ 세션값이 홈페이지에서 적용 안 되는 경우

홈페이지에 들어오면 세션값이 자꾸 안 뜨게되는 이슈가 있었다.

스프링 프로젝트 생성 시 기본 제공되는 home.jsp를 고쳐서 사용하고 있었는데, 알고보니 여기에 있는 이 한 줄 때문에 홈페이지에서만 세션이 없다고 뜨는 것이었다.

<%@ page session="false" %>

home.jsp에서 이걸 지워주니 로그인 후 홈페이지에 들어가니 로그아웃 메뉴가 나타났다.