3/15 TIL

큰모래·2023년 3월 15일
0
post-custom-banner

스프링부트

실습 1 - 주어진 아이디,비밀번호로 로그인 정보 체크


RsData

  • 상황에 맞는 resultCodemsg를 반환하기 위한 RsData 클래스 생성

@Getter
@AllArgsConstructor
public class RsData {
    private final String resultCode;
    private final String msg;
}

MemberService

  • tryLogin 메서드
    • 쿼리스트링을 통해 받은 usernamepassword에 대한 검사를 진행한다.
    • 상황에 맞는 RSData 객체를 반환

@Service
public class MemberService {

    public RsData tryLogin(String username, String password) {

        if (username.equals("user1") && password.equals("1234")) {
            return new RsData("S-1", username + "님 환영합니다.");
        }

        if (username.equals("user1")) {
            return new RsData("F-1", "비밀번호가 일치하지 않습니다.");
        }

        return new RsData("F-2", username + "(은)는 존재하지 않는 회원입니다.");
    }
}

MemberController

  • memberService에서 반환받은 RsData 객체를 리턴
  • @ResponseBody 에 의해 반환 받은 객체를 웹페이지에 Json 형태로 출력
  • usernamepassword에 대한 검사를 membeService에서 진행해 코드가 간결해짐.

@Controller
public class MemberController {

    private final MemberService memberService;

    public MemberController() {
        memberService = new MemberService();
    }

    @GetMapping("/member/login")
    @ResponseBody
    public RsData showLogin(@RequestParam String username, @RequestParam String password) {
        return memberService.tryLogin(username, password);
    }

}

전체 흐름

  1. /member/login?username=[유저네임]&password=[패스워드] 호출
  2. MemberControllershowLogin 메서드 호출
  3. showLogin 메서드에서 usernamepassword 를 토대로 memberService.tryLogin 메서드 반환
  4. tryLogin 메서드는 usernamepassword 의 유효성 검사를 진행해 RsData 객체를 반환한다.
  5. 반환한 RsData 객체는 @ResponseBody 에 의해 json 형식으로 출력된다.

실습 2 - 회원 10명 추가


Member

  • 멤버 리스트에 담을 멤버 객체를 위한 클래스 생성

@Data
@AllArgsConstructor
public class Member {
    private final long id;
    private final String username;
    private final String password;
}
  • @Data는 다음과 같은 어노테이션을 내포하고 있다.

MemberRepository

  • memberList 를 관리할 MemberRepository 생성
  • findByUsername 메서드를 통해 memberList에서 username 으로 member 찾기
    • 만약, 없다면 null 반환

@Repository
public class MemberRepository {
    private static List<Member> memberList = new ArrayList<>();
    private static long lastId = 0;

    public MemberRepository() {
        memberList.add(new Member(lastId++,"user1", "1234"));
        memberList.add(new Member(lastId++,"abc", "12345"));
        memberList.add(new Member(lastId++,"test", "12346"));
        memberList.add(new Member(lastId++,"love", "12347"));
        memberList.add(new Member(lastId++,"like", "12348"));
        memberList.add(new Member(lastId++,"giving", "12349"));
        memberList.add(new Member(lastId++,"thanks", "123410"));
        memberList.add(new Member(lastId++,"hello", "123411"));
        memberList.add(new Member(lastId++,"good", "123412"));
        memberList.add(new Member(lastId++,"peace", "123413"));
    }

    public Member findByUsername(String username) {
        for (Member member : memberList) {
            if (member.getUsername().equals(username)) {
                return member;
            }
        }
        return null;
    }

}

MemberService

  • memberRepositoryfindByUsername 을 통해 반환받은 member를 검사한다.

@Service
public class MemberService {

    private final MemberRepository memberRepository;

    public MemberService() {
        memberRepository = new MemberRepository();
    }

    public RsData tryLogin(String username, String password) {

        Member member = memberRepository.findByUsername(username);

        if (member == null) {
            return new RsData("F-2", username + "(은)는 존재하지 않는 회원입니다.");
        }

        if (!member.getPassword().equals(password)) {
            return new RsData("F-1", "비밀번호가 일치하지 않습니다.");
        }

        return new RsData("S-1", username + "님 환영합니다.");

    }
}

MemberController

  • 기존의 코드에서 쿼리스트링으로 들어오는 usernamepassword 에 대한 검사 추가

@Controller
public class MemberController {

    private final MemberService memberService;

    @Autowired
    public MemberController() {
        memberService = new MemberService();
    }

    @GetMapping("/member/login")
    @ResponseBody
    public RsData showLogin(@RequestParam String username, @RequestParam String password) {
        if ( username == null || username.trim().length() == 0 ) {
            return new RsData("F-3", "username(을)를 입력해주세요.");
        }

        if ( password == null || password.trim().length() == 0 ) {
            return new RsData("F-4", "password(을)를 입력해주세요.");
        }

        return memberService.tryLogin(username, password);
    }

}

전체 흐름

  1. /member/login?username=[유저네임]&password=[패스워드] 호출
  2. usernamepassword 에 대한 유효성 검사
  3. showLogin 메서드에서 usernamepassword 를 토대로 memberService.tryLogin 메서드 반환
  4. tryLogin 메서드에서는 username 을 토대로 memberRepository.findByUsername 메서드 실행
  5. findByUsername 메서드는 memberList 에서 해당 username 을 가진 member 객체를 찾는다.
  6. 만약 찾았다면 member 객체를 반환하고, 없다면 null 반환
  7. 반환 받은 값으로 memberServicetryLogin 에서 유효성 검사 및 RsData 객체 반환
  8. 컨트롤러에서 최종적으로 RsData 객체를 반환해 json 형식으로 출력한다.

의존성 주입


기존 코드

  • 생성자를 호출할때 마다 객체를 생성한다.
    • 이렇게 하면 의존하는 클래스와 구현체간의 결합도가 높아진다. → 유지보수 측면에서 어려워짐.
		
  // MemberController 
  private final MemberService memberService;    
	public MemberController() {
       memberService = new MemberService();
  }

	// MemberService
	private final MemberRepository memberRepository;
  public MemberService() {
       memberRepository = new MemberRepository();
  }

수정 코드

  • 클래스에 @Component 어노테이션을 붙이면 스프링 컨테이너는 해당 클래스를 통해 빈 객체를 만들어 관리
    • @Controller, @Service, @Repository 모두 @Component를 내포하고 있다.
  • @Autowired 를 통해 생성자 주입을 하면 스프링 컨테이너는 해당 타입의 빈 객체를 찾아 주입해준다.
	  // MemberController
		private final MemberService memberService;
    @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }

		// MemberService
		private final MemberRepository memberRepository;
    @Autowired
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

생성자 주입의 장점

  • 불변성 보장
    • 생성자를 통해 빈 객체를 주입함으로써 이후 빈 객체가 변경되지 않도록 보장한다.
  • 의존성 추적
    • 생성자를 통해 의존성을 주입하면 해당 객체가 의존하는 다른 객체를 찾기 쉽다.
  • 결합도 감소
    • 객체간의 결합도를 감소시켜 유연하고 확장성이 좋은 프로그램을 만들 수 있다.

실습 3,4 - 쿠키를 이용한 로그인 처리 + Rq


Rq

  • 쿠키를 관리하는 Rq 클래스 따로 생성
  • setCookie 메서드는 로그인 성공시 쿠키를 만들어 브라우저에 응답하는 메서드이다.
    • 이때 쿠키의 keyloginMemberId , valuemember 객체의 id 값이다.
  • getLoginMemberId 메서드는 현재 브라우저에서 요청한 쿠키의 value 값(id)을 추출하는 메서드이다.
    • 만약 쿠키가 없다면 null 반환
  • removeCookie 메서드는 로그아웃 시 쿠키 정보를 삭제하는 메서드이다.

@Data
@AllArgsConstructor
public class Rq {

    private HttpServletRequest request;
    private HttpServletResponse response;

    public Rq(HttpServletRequest request) {
        this.request = request;
    }

    public Rq(HttpServletResponse response) {
        this.response = response;
    }

    public void setCookie(Long id) {
        response.addCookie(new Cookie("loginMemberId", id + ""));
    }

    public String getLoginMemberId() {
        if (request.getCookies() != null) {
            for (Cookie cookie : request.getCookies()) {
                if (cookie.getName().equals("loginMemberId")) {
                    return cookie.getValue();
                }

            }
        }
        return null;
    }

    public void removeCookie(String key) {
        if (request.getCookies() != null) {
            for (Cookie cookie : request.getCookies()) {
                if (cookie.getName().equals(key)) {
                    cookie.setMaxAge(0);
                    response.addCookie(cookie);
                }
            }
        }
    }

}

  1. /member/me url 접속 시도

    1. 로그인을 하지 않아 쿠키 정보가 없어 그에 맞는 RsDatajson 형식으로 출력
    		@GetMapping("/member/me")
        @ResponseBody
        public RsData showMe(HttpServletRequest request) {
            Rq rq = new Rq(request);
            String loginMemberId = rq.getLoginMemberId();
    
            if (loginMemberId == null) {
                return RsData.of("F-1", "로그인 후 이용해주세요.");
            }
    
            Member member = memberService.findById(Integer.parseInt(loginMemberId));
    
            return RsData.of("S-1", "당신의 username(은)는 " + member.getUsername() + "입니다.");
        }
  1. /member/login?username=[유저네임]&password=[패스워드] 접속

    1. memberList 에 저장된 usernamepassword 로 로그인 시도
    2. 로그인 성공 시 서버에서 rq.setCookie()를 통해 쿠키를 발행해준다.
    3. 로그인 실패 시 상황에 맞는 RsDatajson 형식으로 출력
    		@GetMapping("/member/login")
        @ResponseBody
        public RsData showLogin(HttpServletResponse response, @RequestParam String username, @RequestParam String password) {
            if (username == null || username.trim().length() == 0) {
                return RsData.of("F-3", "username(을)를 입력해주세요.");
            }
    
            if (password == null || password.trim().length() == 0) {
                return RsData.of("F-4", "password(을)를 입력해주세요.");
            }
    
            Rq rq = new Rq(response);
    
            RsData rsData = memberService.tryLogin(username, password);
            if (rsData.isSuccess()) {
                Member member = (Member) rsData.getData();
                rq.setCookie(member.getId());
            }
    
            return rsData;
        }
  1. /member/me 재접속

    1. 이전 단계에서 로그인에 성공했다면 현재 나의 브라우저에 로그인 정보가 담긴 쿠키가 있을 것이다

    2. 또한, 현재 나의 접속 상태가 RsData를 통해 Json으로 정상 출력된다.

  1. /member/logout
    1. rq.removeCookie() 메서드를 통해 현재 내가 가진 쿠키를 제거함으로써 로그인 정보를 제거한다.
    ```java
    		@GetMapping("/member/logout")
        @ResponseBody
        public RsData showLogout(HttpServletRequest request, HttpServletResponse response) {
            Rq rq = new Rq(request, response);
            rq.removeCookie("loginMemberId");
    
            return RsData.of("S-1", "로그아웃 되었습니다.");
        }
    ```
profile
큰모래
post-custom-banner

0개의 댓글