프로젝트/Staffriends 프로젝트

[Staffriends 프로젝트] (1) 회원 CRUD 구현하기 - 2. 로그인

sungw00 2023. 5. 22. 03:03
728x90

로그인

이전 포스팅에서 회원가입(Create)을 진행하였다면 로그인에서는 회원가입 된 데이터를 읽어서 적절한 요청과 응답을 해주면 된다.

 

1. UserController 작성

package board.controller;

import board.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import board.vo.UserVo;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;

@Controller
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/joinForm") // 회원가입 페이지
    public String join() {
        return "/user/joinForm";
    }

    @PostMapping("/join/idCheck") // 중복 아이디 확인
    @ResponseBody
    public Map<String, Integer> idCheck(@RequestBody String username) throws Exception {
        Map<String, Integer> map = new HashMap<>(); // 중복 아이디 결과를 담아줄 map 선언
        map.put("count", userService.idCheck(username)); // 중복된 아이디의 갯수를 map에 put
        return map; // 갯수 반환
    }

    @PostMapping("/join/insert") // 회원 가입
    @ResponseBody
    public String joinUser(@RequestBody UserVo userVo) throws Exception{
        userService.insertUser(userVo);
        return "success";
    }

    @GetMapping("/loginForm") // 로그인 페이지
    public String login() {
        return "/user/loginForm";
    }

    @PostMapping("/loginProc") // ID와 PW 일치 여부 확인
    @ResponseBody
    public boolean loginProc(@RequestBody UserVo userVo, HttpSession session) throws Exception {
        String username = userService.loginProc(userVo); // 일치하는 회원의 id
        if (username == null) { // 일치하는 회원의 아이디가 조회되지 않으면 세션 값을 설정하지 않고 리턴
            return false;
        }
        userVo = userService.getUserInfo(username); // 회원의 id로 회원 정보를 조회하여 담아줌
        session.setAttribute("signIn", userVo); // 회원의 세션 정보 생성 후 리턴
        return true;
    }

    @GetMapping("/logout") // 로그아웃
    public String logOut(HttpServletRequest request) {
        HttpSession session = request.getSession(); // 전달받은 세션의 정보를 저장
        session.invalidate(); // 세션 무효화
        return "redirect:/";
    }
}
  1. /user/loginForm 으로 요청이 들어올 시 로그인 페이지인 /user/loginForm.jsp를 반환한다.
  2. 로그인을 위해 아이디와 비밀번호를 POST 방식으로 HTTP BODY에 담아 전송받고, userService.loginProc의 인자로 userVo를 전달하여 결과값은 username을 반환받는다.
  3. loginProc에서는 전달받은 아이디와 비밀번호가 일치하는 회원을 DB에서 찾아 그 회원의 아이디를 반환하는데, null이라면 false를 반환하고 null이 아니라면 회원의 아이디로 getUserInfo 메서드를 이용해 회원 정보를 조회하여 userVo에 담아주고 signIn이라는 이름으로 세션을 생성한 후 리턴한다.
  4. user.js의 loginProc 메서드에서는 회원 정보를 반환받은지 여부를 판별하여 로그인을 시킬지 말지를 판단한다.
  5. 그리고 로그아웃은 session.invalidate() 메서드로 해당 세션을 무효화하는 방식으로 구현했다.

2. UserService, UserServiceImpl, UserMapper 작성

UserService.java

package board.service;

import board.vo.UserVo;
import org.springframework.stereotype.Service;

@Service
public interface UserService {
    void insertUser(UserVo userVo) throws Exception;

    String loginProc(UserVo userVo) throws Exception;

    int idCheck(String username) throws Exception;

    UserVo getUserInfo(String username);
}

UserServiceImpl.java

package board.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import board.vo.UserVo;
import board.mapper.UserMapper;

import java.io.*;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.util.Map;

@Repository
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public void insertUser(UserVo userVo) throws Exception { // 비밀번호 암호화 후 회원가입 진행
        messageDigest(userVo, userVo.getPassword());
        userMapper.insertUser(userVo);
    }

    @Override
    public int idCheck(String username) throws Exception { // 중복 아이디 확인
        return userMapper.idCheck(username);
    }

    @Override
    public String loginProc(UserVo userVo) throws Exception { // 비밀번호 암호화 후 로그인 진행
        messageDigest(userVo, userVo.getPassword());
        return userMapper.loginProc(userVo);
    }

    @Override
    public UserVo getUserInfo(String username) { // 회원 정보 조회
        return userMapper.getUserInfo(username);
    }
}

UserMapper.java

package board.mapper;

import org.apache.ibatis.annotations.Mapper;
import board.vo.UserVo;

@Mapper
public interface UserMapper {
    void insertUser(UserVo userVo) throws Exception;

    String loginProc(UserVo userVo) throws Exception;

    int idCheck(String username) throws Exception;

    UserVo getUserInfo(String username);
}

 

3. user.js 작성

function loginProc() { // 로그인 실행 로직
    let username = document.getElementById('username').value.trim();
    let password = document.getElementById('password').value.trim();

    if (username === "") {
        alert("아이디를 입력해주세요.");
        document.getElementById('username').focus();
        return false;
    }
    if (password === "") {
        alert("비밀번호를 입력해주세요.");
        document.getElementById('password').focus();
        return false;
    }

    let data = {
        username:username,
        password:password
    };

    let xhr = new XMLHttpRequest();
    xhr.open("POST", "/user/loginProc");
    xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    xhr.onload = function() {
        if (xhr.status === 200 || xhr.status === 201) {
            let resp = xhr.responseText;
            let result = JSON.parse(resp);
            if (resp.status === 500) {
                alert("에러가 발생했습니다.");
            } else {
                if (username) { // 회원 정보를 반환받은 경우
                    alert("로그인이 완료되었습니다.");
                    location.href = "/";
                } else { // 반환받은 회원 정보가 없는 경우
                    alert("아이디 또는 비밀번호를 확인해주세요.");
                    document.getElementById('username').focus();
                }
            }
        } else {
            console.log(xhr.responseText);
            alert("에러가 발생했습니다. \n에러 코드: " + xhr.status);
        }
    };
    xhr.onerror = function() {
        console.log(xhr.responseText);
        alert("에러가 발생했습니다. \n에러 코드: " + xhr.status);
    };
    xhr.send(JSON.stringify(data));
}

4. loginForm.jsp 작성

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ include file="../layout/header.jsp"%>
<title>로그인</title>
<html>
<body>
<c:set var="REST_API_KEY" value="69eddbebb2b07d6a316fc057c32fdbdf"/>
<%--<c:set var="REDIRECT_URI" value="http://localhost/user/kakao"/>--%>
<c:set var="REDIRECT_URI" value="http://staffriends.duckdns.org/user/kakao"/>
<h2 style="text-align: center; margin-top: 30px; margin-bottom: 70px; font-family: KakaoBold;">로그인</h2>
<section style="padding-bottom: 50px;">
<div class="container center-div">
<form method="post" class="container center-div container-size">
    <div class="form-group" style="margin-bottom: 32px;">
        <h5 style="text-align: left">아이디</h5><input type="text" class="form-control" placeholder="아이디를 입력하세요." name="username" id="username">
    </div>
    <div class="form-group">
        <h5 style="text-align: left">비밀번호</h5><input type="password" class="form-control" placeholder="비밀번호를 입력하세요." name="password" id="password">
    </div>
    <div style="text-align: center; padding-bottom: 20px;"><a href="javascript:findMyIdPopUp()">아이디 찾기</a> | <a href="javascript:findMyPasswordPopUp()">비밀번호 찾기</a></div>
    <input class="btn btn-staffriends btn-lg center-div" type="button" value="로그인" onclick="loginProc()">
    <a href="https://kauth.kakao.com/oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code"><img src="/img/kakao_login_medium_wide.png" class="btn-block" style="margin-top: 5px;height: 50px"></a>
</form>
</div>
</section>
</body>
</html>
<%@ include file="../layout/footer.jsp"%>

5. sql-user.xml 작성

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

<mapper namespace="board.mapper.UserMapper">
<insert id="insertUser" parameterType="board.vo.UserVo">
        <![CDATA[
            INSERT INTO user
                (
                     name,
                     username,
                     password,
                     email,
                     nickname,
                     join_date,
                     oauth
                 )
            VALUES
                (
                     #{name},
                     #{username},
                     #{password},
                     #{email},
                     #{nickname},
                     now(),
                     #{oauth}
                 )
        ]]>
    </insert>

    <select id="idCheck" parameterType="String" resultType="Integer">
        <![CDATA[
            SELECT
                count(*) as username
            FROM
                user
            WHERE
                username = #{username}
        ]]>
    </select>

    <select id="loginProc" parameterType="board.vo.UserVo" resultType="String">
        <![CDATA[
            SELECT
                username
            FROM
                user
            WHERE
                username = #{username} AND password = #{password}
        ]]>
    </select>

    <select id="getUserInfo" parameterType="String" resultType="board.vo.UserVo">
        <![CDATA[
            SELECT
                *
            FROM
                user
            WHERE
                username = #{username}
        ]]>
    </select>
</mapper>

 

프로젝트 전체 코드 Github 주소

https://github.com/sungwoo-jo/Staffriends-Project

 

GitHub - sungwoo-jo/Staffriends-Project: AI 스마트 시각장애인 지팡이

AI 스마트 시각장애인 지팡이. Contribute to sungwoo-jo/Staffriends-Project development by creating an account on GitHub.

github.com

 

728x90