고래씌

[Spring] 2-1. 로그인, 로그아웃 페이지 본문

Server/Spring

[Spring] 2-1. 로그인, 로그아웃 페이지

고래씌 2024. 1. 22. 12:52

1. 로그인 페이지

=> member 폴더

 

 

▶ Member.java

package com.kh.spring.member.model.vo;

import java.sql.Date;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class Member {
	
	private int userNo;
	private String userId;
	private String userPwd;
	private String userName;
	private String birthday;
	private String gender;
	private String phone;
	private String address;
	private Date enrollDate;
	private Date modifyDate;
	private String status;
	
	
}

 

 

▶ MemberController.java

@Controller  => spring의 빈스캐너가 자동으로 빈객체로 만들어준다. (servlet-context.xml안에 있는 태그)

 

☞ 기존객체 생성 방식

private MemberService mService = new MemberServiceImpl();

 Spring의 DI(Dependecy Injection) → 객체를 개발자가 생성하는게 아니라, 스프링이 생성한 객체를
주입받아서 사용하는 방식.
new 연산자를 쓰지말고, 선언만 한후 @Autowird어노테이션을 붙여서 주입을 받음

 

 

☞ 필드방식 의존성 주입

@Autowired
private MemberService mService;

 

장점 : 이해하기 편하다. 사용하기 편하다.
단점 : 1) 순환 의존성 문제가 발생할 수 있다.
          2) 무분별한 주입시 의존관계 확인이 어렵다.

 

 

☞ 생성자 주입방식   => 생성자 주입방식을 권장!
생성자에 참조할 클래스를 인자(매개변수)로 받아서 필드에 매핑시킨다.
장점 : 현재클래스에서 내가 주입시킬 객체들을 모아서 관리할 수 있기 때문에 한눈에 알아보기 편함. 예약어로 final필드를 쓸 수 있다.

public MemberController() {

}

// 의존성을 매개변수 있는 생성자로 주입함. 위에 Autowired 썼던 것은 주석처리!
@Autowired
public MemberController(MemberService mService) {
     this.mService = mService;
}

/*
 * setter방식 의존성 주입 : setter메서드로 빈을 주입받는 방식
 */
public void setMemberService(MemberService mService) {
     this.mService = mService;
}

 

 

 

▶ MemberServiceImpl.java

@Service   어너테이션 추가

 

 

 

▶ MemberServiceImpl.java

@Repository 어너테이션 추가

 


1-1) 스프링에서 paramter를 받는 방법들

1) HttpServletRequest를 이용해서 전달받기

해당 메소드의 매개변수로 HttpServletRequest를 작성해놓으면 스프링 컨테이너가 해당 메소드를 호출할 때 자동으로 request객체를 생성해서 매개변수에 주입해준다.

@RequestMapping(value="login.me", method=RequestMethod.POST)   // 요청해서 mapping할 수 있는 어노테이션. 사용자가 login.me라는 값이 들어왔을때 감지됨
public String loginMember(HttpServletRequest reqeust) {
     // userId, userPwd
    System.out.println("userId : " + reqeust.getParameter("userId"));
    System.out.println("userPwd : " + reqeust.getParameter("userPwd"));
return "main";
}

 

 

2) @ReqeustParam어노테이션을 이용하는 방법

servlet의 request.getParameter("키")로 뽑은 역할을 대신 수행해주는 어노테이션
ReqeustParam속성의 value로 jsp에서 작성했던 name값을 입력해주면 알아서 매개변수로 값을 담아옴.
넘어온 값이 비어있다면 기본값도 지정가능하다.

@RequestMapping(value="login.me", method=RequestMethod.POST)   // 요청해서 mapping할 수 있는 어노테이션. 사용자가 login.me라는 값이 들어왔을때 감지됨
public String loginMember(
     @RequestParam(value="userId", defaultValue="mmm") String userId,
     @RequestParam(value="userPwd") String userPwd) {   // value에는 input태그의 name속성값을 넣으면됨.

     // userId, userPwd
     System.out.println(userId + "||||||||||" + userPwd);
     return "main";
}

 

 

3) @ReqeustParam를 생략하는 방법

단, 기본값을 사용불가.

@RequestMapping(value="login.me", method=RequestMethod.POST)   // 요청해서 mapping할 수 있는 어노테이션. 사용자가 login.me라는 값이 들어왔을때 감지됨
public String loginMember(
    String userId,
    String userPwd) {

// userId, userPwd
System.out.println(userId + "||||||||||" + userPwd);
    return "main";
}

 

 

4) 커맨드 객체 방식

- 해당 메소드의 매개변수로 요청시 전달하고자하는 VO클래스타입의 변수를 세팅하고, 요청시 전달값의 name속성을 VO클래스의 필드명과 일치시켜서 작성(userId, userPwd)

- 스프링컨테이너에서 해당객체를 "기본 생성자"를 호출해서 객체를 생성한 후, 내부적으로 전달받은 key값에 해당하는 setter메서드를 찾아서 전달한 값을 생성된객체의 필드에 담아준다. 따라서 반드시 name속성값과, 필드명이 일치해야한다.

@RequestMapping(value="login.me", method=RequestMethod.POST)   // 요청해서 mapping할 수 있는 어노테이션. 사용자가 login.me라는 값이 들어왔을때 감지됨
public String loginMember(Member m) {

    // userId, userPwd
    System.out.println(m.getUserNo());
    System.out.println(m.getUserId() + "||||||||||" + m.getUserPwd());
return "main";
}

 

 

 

 

우리는 5번 방식으로 할 예정 !!! ★ ★ ★ ★ ★ ★ ★ ★ ★

5) 로그인 요청 처리 완료 후, "응답 데이터"를 담고 응답페이지로 url재요청할 예정

■ 1) Model객체를 이용하는 방법

포워딩할 응답뷰페이지로 전달하고자 하는 데이터를 맵형식으로 담아주기
→ request, session 스코프 두개를 가지고 있음

- 기본 scope : reqeust
   session scope : 클래스 위쪽에 @SessionAttribute을 추가 한후 작성하면된다.

 

 

■ 2) ModelAndView객체 이용

- ModelAndView에서 Model은 데이터를 담을 수 있는 맵형태의 객체(위 Model과 동일)
View는 이동하고자흔 페이지에 대한 정보를 담고있는 객체. 두개를 합쳐서 ModelAndView가 된다.

 

- Model은 내부에 데미터를 추가하고자 할 때 addAttribute()함수를 이용
ModelAndView는 데이터를 추가할 때 addObject()를 사용. view를 지정할때는 setViewName()를 사용

 

	@RequestMapping(value="login.me", method=RequestMethod.POST)   // 요청해서 mapping할 수 있는 어노테이션. 사용자가 login.me라는 값이 들어왔을때 감지됨
	public ModelAndView loginMember(Member m, HttpSession session, Model model, ModelAndView mv) {

		// model.addAttribute("errorMsg", "오류발생");
		
		mv.addObject("errorMsg", "오류발생");
		mv.setViewName("common/errorPage");  // 접두어로 다 붙기때문에 /WEB-INF/views와 .jsp는 생략가능. /WEB-INF/views/common/errorPage.jsp
		
		
		return mv;

	}

 

 

 

☞ common > erroerPage.jsp(에러페이지 만들기)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<jsp:include page="header.jsp"></jsp:include>
	<br>
	<div align="center">
		<img src="https://cdn0.iconfinder.com/data/icons/small-n-flat/24/678069-sign-error-64.png">
		<br><br>
		<h1 style="font-weight:bold;">${errorMsg }</h1>
	</div>
	
	<jsp:include page="footer.jsp"></jsp:include>

</body>
</html>

 

 

 

 로그인 기능 만들기

 

 

▶ MemberController.java

	@PostMapping("login.me")
	public ModelAndView loginMember(@ModelAttribute Member m, HttpSession session, Model model, ModelAndView mv) {
		
		// 암호화 전 로그인 요처리
		
		Member loginUser = mService.loginMember(m);
		String url = "";
				
		if(loginUser == null) { // 로그인 실패시
			mv.addObject("errorMsg", "오류발생");
			mv.setViewName("common/errorPage");
		}else {  // 성공시
			model.addAttribute("loginUser", loginUser);
//			session.setAttribute("loginUser", loginUser);
			mv.setViewName("redirect:/");
		}
		
		return mv;
	}

 

- 클래스 맨위에 @SessionAttributes({"loginUser"}) 추가

☞ 현재 Model안에 추가된 값의 key값과 일치하는 값이 있으면 해당값을 session scope로 이관

 

=> 이렇게 추가하면 model.addAttribute에 담긴 값이 session scope로 이관되어서 로그인을 하게되면 새로고침을 해도 로그아웃을 클릭하지 않는한, 로그인이 유지된다. 단, 로그아웃이 되지않는 문제가 발생하게 되는데 로그아웃이 되게하려면 logout.me에서 status.setComplete();를 해주어야 안에 있는 session이 비어지면서 로그아웃이 가능하게 된다.

 

 

▶ MemberService.java

package com.kh.spring.member.model.service;

import com.kh.spring.member.model.vo.Member;

public interface MemberService {

	Member loginMember(Member m);

}

 

 

▶ MemberServiceImpl.java

=> SqlSession객체를 bean으로 등록한 후에는 스프링컨테이너가 자원 사용후 자동으로 반납을 해주기 때문에 close()할 필요가 없음

package com.kh.spring.member.model.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.kh.spring.member.model.dao.MemberDao;
import com.kh.spring.member.model.vo.Member;

@Service
public class MemberServiceImpl implements MemberService {
	
//	순환 문제 발생함
//	@Autowired
//	private MemberController mController;
	
	@Autowired
	private MemberDao memberDao;
	
	@Override
	public Member loginMember(Member m) {
		/*
		 * SqlSession객체를 bean으로 등록한 후에는 스프링컨테이너가 자원 사용후 자동으로 반납을 해주기 때문에
		 * close()할 필요가 없음
		 */
		return memberDao.loginUser(m);
	}
	
}

 

 

▶ MemberDao.java

package com.kh.spring.member.model.dao;

import com.kh.spring.member.model.vo.Member;

public interface MemberDao {

	Member loginUser(Member m);
	
}

 

 

▶ MemberDaoImpl.java

package com.kh.spring.member.model.dao;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.kh.spring.member.model.vo.Member;

@Repository
public class MemberDaoImpl implements MemberDao{
	
	@Autowired
	private SqlSessionTemplate sqlSession;
	
	@Override
	public Member loginUser(Member m) {
		return sqlSession.selectOne("memberMapper.loginUser", m);
	}
	
}

 

 

=> DB에 저장된 admin, 1234로 로그인한 결과 정상적으로 로그인 되는 것을 확인

 

 

3. 로그아웃

▶ MemberController.java

	@GetMapping("/logout.me")
	public String logoutMember(HttpSession session, SessionStatus status) {
		session.invalidate();
		status.setComplete();  // @SessionAttribute와 model로 session scope에 이관된 데이터는 SessionStatus를 이용해서 바꿔줘야한다.
		// 로그인한 유저가 비어지게됨
		
		return "redirect:/";  // 메인 url로 이동
	}