반응형

이전에는 강의를 들으며 진행했지만 순전히 나의 힘으로 진행해 보기 위해 애를 썼다. 물론 강의를 조금 훑긴 했지만.

 

먼저 나는 웹이나 앱이나 여러 방면에서 내 서버가 쓰이기 위해 REST API를 바로 만들어 준다고 생각했다.

 

폴더를 api, dto, entity, repository, service 다섯 항목으로 구성했으며 내용은 다음과 같다.


먼저 Entity를 구현하여 로그인 기능에 사용될 변수들을 생성한다.

@AllArgsConstructor
@ToString
@NoArgsConstructor
@Entity
@Getter
public class Signin {
//    @Id
//    private String uuid; //uuid를 사용하려 했으나, ID값이 pk가 되어 사용 안함.

    @Id
    private String userid;
    @Column
    private String userpw;
//
//    public Signin(String userid, String userpw){ //AllArgsConstructor이 자동 생성
//   }

}

엔티티에 사용된 어노테이션들을 설명하겠다.

1) ArgsConstructor -

  • @NoArgsConstructor : 디폴트 생성자만 만들어준다.
  • @AllArgsConstructor : 모든 필드의 생성자를 만들어준다.
  • @RequiredArgsConstructor : 필수 생성자만 만들어준다.

이에 따라서 맨 아랫줄의 Signin은 @AllArgsConstructor로 인해 만들 이유가 없어진 것이다. 마찬가지로 오류 또한 발생했었다.

 

2)@ToString - 클래스 출력시 가지고 있는 엔티티 반환.

3)@Getter - 알아서 접근자 메소드를 생성한다. 후술 하겠으나, 덕을 좀 봤다.

4)@Entity - JPA가 관리할 엔티티임을 선언.

 

5) DB관련 어노테이션

@Id - pk임을 선언 [주의]❗️어노테이션 불러올 때, javax.persistence를 불러올 것. 오류가 발생했었다.

@Column 컬럼 매핑!

 

로그인 기능을 구현하기 위해서, 필요한 것이 아이디와 비밀번호 이외에 필요한 부분은 크게 없다. 물론 더 성장했을 경우 jwt토큰이나, 스프링부트 시큐리티를 활용하여 보안기능이 강력한 로그인을 제작할 수 있겠지만, 아직 내 수준은 초보에 머물러있기에 무작정 달려가보자.

 

각설하고 아이디와 비밀번호만 필요할 것 같아 관련 엔티티를 생성해 준 코드이다.


다음은 Repository이다. 엔티티가 DB를 생성했다면, 리파지토리는 DB에 접근하기 위해 메소드를 활용하게 하는 인터페이스이다!

public interface SigninRepository extends CrudRepository<Signin, Long> {
    Optional<Signin> findByuserid(String userid);

}

먼저 생각해낸 로직은 그렇다. 유저가 아이디와 비밀번호를 입력하면, 나는 입력한 유저아이디를 먼저 DB와 비교한다. 비교한 아이디가 DB에 존재하면 그제서야 비밀번호를 서로 확인하여 유저가 정상적으로 로그인 할 수 있음을 확인해준다.

 

따라서, findByuserid라는 메소드를 구현했다. userid를 받아서 Signin 엔티티에 먼저 담는것이다.


엔티티와 리파지토리를 구현했다면 서로를 연결하기 위한 dto가 필요하다.

@AllArgsConstructor
@ToString
public class SigninForm {
    private String userid;
    private String userpw;
    public Signin toEntity(){return new Signin(userid, userpw);}
}

dto를 엔티티로 바꿔주는 메소드 toEntity를 구현했다. 본 메소드를 사용하면 userid와 userpw를 받게 될것이다.


api 폴더 내부의 SigninApiController이다.

@RestController //REST API 컨트롤러임을 확인
@Slf4j // 로그 사용
public class SigninApiController {
    @Autowired // 자동 적용.
    private SigninService signinservice;

    @PostMapping("/signin") //signin이라는 주소 사용, post 사용.
    public ResponseEntity<Signin> signin(@RequestBody SigninForm dto){
        Signin signed = signinservice.login(dto); //signed는 로그인이라는 서비스 메소드로 확인
        return (signed != null) ? 
                ResponseEntity.status(HttpStatus.OK).body(signed) :
                ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
    }


}

@RestController로 RESTAPI임을 선언한다. 왜 RESTAPI를 사용하는가? 라고 묻는다면 대답해드리는게 인지상정!

간단히 말하자면, 세상에는 다양한 종류의 디바이스들이 있다. OS, IOS, WEB 기타등등 여러 디바이스에서 내가 만든 서버를 활용하기 위해서 활용되는 방식이다. "어떤 디바이스든 정해진 규격을 만들어 그 규격의 값을 제공받는다"가 주된 목표 되겠다. 디바이스가 다르다고 하더라도 값만 올바른 형식으로 받으면 되는 것 아닌가? 그래서 사람들은 RESTAPI라는 개념을 만들었고, 우리는 JSON이라는 형식을 주고받게 되었다.

 

말이 길어졌는데, 아무튼 나는 웹이나 앱 어디서든 쓰이기 위해 RESTAPI로 선언했다.

 

api로직은 그렇다. dto로 사용자 입력을 받고 서비스에서 엔티티로 변환한뒤 아이디 비교 비밀번호 비교를 실시하고, 다시 api로 돌아와 회원이면 HttpStatus.OK(200)과 사용자의 아이디 비밀번호를 그대로 제공해주고, 없을 경우 HttpStatus.BAD_REQUEST(400)을 제공하며 null값을 보낸다.


마지막 서비스이다.

@Slf4j
@Service
public class SigninService {

    @Autowired
    private SigninRepository signinRepository;

    public Signin login(SigninForm dto) {
        Signin user = dto.toEntity();
        log.info("id = {}, pw = {}", user.getUserid(),user.getUserpw());
		//입력된 아이디와 비밀번호 무엇인지!
        Optional<Signin> byuserid = signinRepository.findByuserid(user.getUserid());

        if (byuserid.isPresent()){
            Signin register = byuserid.get();
            if (register.getUserpw().equals(user.getUserpw())){ //등록되어 있는 비밀번호 .equals 유저가 입력한 비밀번호 비교
                // 비밀번호 일치
                return user;
            }
            else {
                // 비밀번호 불일치
                return null;
            }
        }
        else {
            //조회 결과 없음
            return null;
        }
    }
}

서비스에서는 주 기능을 구현해준다고 생각하면 된다.

로직 설명 들어가겠다. dto로 받은 유저의 정보를 엔티티화 하여 user로 받는다.

아까 엔티티에서 @getter 어노테이션을 선언하여 getUserid()라는 메소드가 자동생성되었다. 아주 꿀기능이라고 볼 수 있다.

그에 따라 user의 아이디와 비밀번호를 본 메소드로 찾아낼 수 있다.

 

byuserid라는 변수를 선언해준다. 리파지토리에 선언했었던 findByuserid 메소드를 활요해준다. dto로 받은 아이디를 DB에서 찾고 그것을 반환해주는 코드가 되겠다.

 

옵셔널로 바인딩 했기에 byuserid에 정보가 있을수도 없을 수도 있다. 왜 추상적인 값 옵셔널로 줬는가? byuserid에 정보가 있다면 DB에 ID가 있는것이고, 없으면 없는거지! 그러니 확인하기도 쉽다는 것이다. isPresent()를 사용하여 값이 있나 없나 확인한다.

 

register이라는 변수를 byuserid.get()으로 구현한다. register은 byuserid 엔티티의 모든 정보를 담는다.

 

.equals() 메소드를 활용한다! String값을 비교할때는 == 연산자가 아닌 equals메소드를 활용하자. 자 여기서 주의할점 register과 user의 차이점을 알겠는가? register은 DB에 등록되어있는 정보이고, user은 사용자로부터 입력받은 정보가 되겠다!! 따라서 getUserpw()메소드를 사용하여 비밀번호를 서로 비교해주자.


구현은 이로써 끝이 났다. DATA.sql을 resources 밑에 넣어 데이터를 여러가지 집어넣었고, Talend API Tester을 사용하여 정상작동하는지 확인했다.

Talend API에 해당값을 넣었더니 Response가 200으로 나왔다.

정상작동 하네용 ㅋㅋ 성공!!


로그인 기능 구현 중 다양한 오류 발생.

기깔나는 대화..

1) 카멜 케이스와 스네이크 케이스

UserID 는 오류가 난다. UserId로 설정해줘야한다. 왜? 카멜 케이스라서. 진짜 유의하기 바란다.

userId로 바꿨다. DB에서는 USER_ID로 설정되었다 왜? 자동적으로 대문자는 띄어쓰기로 생각하기 때문이라고 추측했다.

따라서 userid로 바꿔주었더니 그제서야 USERID로 들어갔다. 내가 만든 엔티티가 다 소문자인 이유이다.

끼.. 끼잉... 나는 이런 거 안배웠단 말야!!!

 

2) null값으로 데이터를 잡았었다.

이전코드는 진짜 난리가 났었다. null값으로 데이터를 잡아서 곤혹을 치뤘다..

 

아무튼 감만세 파이팅!

반응형

'BackEnd > Spring boot' 카테고리의 다른 글

스프링부트 - 간단한 로그인 수정 #1-1  (6) 2023.01.12

+ Recent posts