Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

승띵이의 개발일지

[Spring Boot] 로그인 1 본문

언어/Spring Boot

[Spring Boot] 로그인 1

승띵이 2022. 11. 14. 10:52
로그인(Login)

 

이번 포스팅에서는 로그인 기능을 구현해 보려고 한다. 

 

아직 세션에 대해 배우지 않았기에 본 포스팅에서는 email과 password를 입력하였을 때 DB에 있는 users 테이블에 있는 email과 password가 동일한지 확인하는 작업정도만 구현해 보려고 한다. 

 

나머지는 세션 배우고 2탄에서...

 

껍데기만 만드는 것 같지만 그래도 고고고

 

 

결과

 

초기 화면

 

이메일을 읿력하지 않을 경우 경고 메세지 등장. 비번도 마찬가지로 됩니당

 

올바른 이메일과 비번을 입력하면 로그인 완료!

 

DB에 존재하지 않는 회원은 로그인이 되지 않는다. 당연하게도

 

 

기능 구현

 

이제부터 html과 css는 특별한 추가사항이 있는 것이 아니면 따로 업로드하지 않겠다. 

 

넘 길고 뭐 다 아는 내용이니깐..

 

 

MemberMapper.xml

 

<select id="selectUserByEmailPassword" resultType="com.smchoi.studymemberbbs.entities.member.UserEntity">
    SELECT `email`             AS `email`,
           `password`          AS `password`,
           `nickname`          AS `nickname`,
           `name`              AS `name`,
           `contact`           AS `contact`,
           `address_postal`    AS `addressPostal`,
           `address_primary`   AS `addressPrimary`,
           `address_secondary` AS `addressSecondary`,
           `registered_on`     AS `registeredOn`
    FROM `study_member`.`users`
    WHERE BINARY `email` = #{email} and `password` = #{password}
    LIMIT 1
</select>

 

MemberMapper.xml 파일에 위와 같이 <select> 코드를 추가해 주었다. 해당 쿼리문은 email과 password로 해당 레코드를 select하는 쿼리문이다.

 

email과 password가 맞다면 다른 속성들을 select한다는 뜻이다.

 

 

IMemberMapper 인터페이스

 

UserEntity selectUserByEmailPassword(@Param(value = "email") String email, 
                                     @Param(value = "password") String password);

 

UserEntitiy 타입으로 selectUserByEmailPassword 메서드를 만들어 매개변수로 email과 password를 받아준다.

 

@Param 어노테이션을 사용하여 매개변수를 받아주면 Mapper.xml 에서 ParameterType을 명시할 필요가 없다.

 

 

MemberService

 

public Enum<? extends IResult> login(UserEntity user) {
    UserEntity userEmailPassword = this.memberMapper.selectUserByEmailPassword(user.getEmail(),
            CryptoUtils.hashSha512(user.getPassword()));

    // 값이 없으면 실패
    if (userEmailPassword != null) {
        return CommonResult.SUCCESS;
    }

    return CommonResult.FAILURE;
}

 

MemberService 에서 Enum 형태로 login 메서드를 만들어 주었다. 

UserEntity userEmailPassword 를 this.memberMapper.selectUserByEmailPassword()를 사용하여 정의해준 뒤 값이 존재한다면 SUCCESS, 존재하지 않는다면 FAILURE를 반환해 주었다.

 

MemberController

 

@RequestMapping(value = "login",
        method = RequestMethod.GET,
        produces = MediaType.TEXT_HTML_VALUE)
@ResponseBody
public ModelAndView getLogin() {
    ModelAndView modelAndView = new ModelAndView("member/login");

    return modelAndView;
}

@RequestMapping(value = "login",
        method = RequestMethod.POST,
        produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public String postLogin(UserEntity user) {
    Enum<?> result = this.memberService.login(user);
    JSONObject responseObject = new JSONObject();
    responseObject.put("result", result.name().toLowerCase());

    return responseObject.toString();
}

 

1. getLogin

@RequestMapping 어노테이션을 사용하여 value, method 등을 설정해주고, ModelAndView()를 사용하여 읽어올 html 파일의 경로를 설정해 주었다. 

 

2. postLogin

해당 메서드에서는 user 매개변수에 대한 memberService에서 반환된 SUCCESS/FAILURE 값을 Enum result에 담아주고JSONObject responeObject 객체를 생성한 뒤 responseObject.put()을 사용하여 result 값을 넣어준 뒤 responseObject를 String 형태롤 반환해주었다. 

 

JSONObject result는 js에서 XHR 구현할 때 사용할 예정이다.

 

javascript

 

const Warning = {
    getElementById: () => form.querySelector('[rel="warningRow"]'),
    show: (text) => {
        const warningRow = Warning.getElementById();
        warningRow.querySelector('.text').innerText = text;
        warningRow.classList.add('visible');

    },
    hide: () => Warning.getElementById().classList.remove('visible')
};

form.onsubmit = (e) => {
    e.preventDefault();

    Warning.hide();
    if (form['email'].value === '') {
        Warning.show('이메일을 입력해주세요');
        form['email'].focus();
        return;
    }
    if (form['password'].value === '') {
        Warning.show('비밀번호를 입력해주세요');
        form['password'].focus();
        return;
    }
    Cover.show("로그인 중입니다.\n\n잠시만 기다려주세요.")
    const xhr = new XMLHttpRequest();
    const formData = new FormData();
    formData.append('email', form['email'].value);
    formData.append('password', form['password'].value);
    xhr.open('POST', './login');
    xhr.onreadystatechange = () => {
        Cover.hide();
        if (xhr.readyState === XMLHttpRequest.DONE) {
            if (xhr.status >= 200 && xhr.status < 300) {
                const responseObject = JSON.parse(xhr.responseText);
                switch (responseObject['result']) {
                    case'success':
                        alert('로그인 완료!');
                        break;
                    case'failure':
                        Warning.show('해당 정보를 가진 회원이 존재하지 않습니다.\n이메일과 비밀번호를 확인해주세요.')
                        break;
                    default:
                        Warning.show('로그인에 실패하였습니다.')
                }
            }
        }
    }
    xhr.send(formData);
}

 

1. <input> email과 password가 공란일시 Warning 함수를 사용하여 경고문구가 나타나게 하였다.

 

2. xhr을 선언하고 formData에  email과 password 값을 담아준다.

 

만일 xhr의 status가 200 이상 300 미만(성공)이라면 상수 responsObject를 선언하고 responseObject의 결과가 success이면 로그인 완료, failure이면 Warning 함수를 사용해 경고문구를 show해준다. default 값은 '로그인에 실패하였습니다' 라는 경고문구가 show되는 것으로 한다.

 

 

마치며

 

오늘 본 포스팅에서는 세션 파트에 들어가기 전에 로그인 껍데기를 만드는 작업을 수행하였다.

 

세션 들어가면 대가리 깨진다고 하던데..

 

골통 분쇄 당하고 로그인하기 2탄 만들어 볼게요

 

 

Comments