로그인 요청(Request) URL를 처리하는 컨트롤러(Controller) 클래스를 생성하고 기존의 서비스(Service) 클래스인 "TestLoginService.java"를 수정하여 DAO(Data Access Object) 클래스를 의존성 주입(DI)하여 처리되도록 하겠습니다.
기존 "TestDispatcherServlet.java"의 "service"메소드에서 처리되는 "login.do"과 "loginprocess.do"를 로그인 컨트롤러(Controller)를 만들어 분리하겠습니다.
7. "test2" 프로젝트의 "Java Resources"에서 "src/main/java"의 "com.hom.project.test2.controller"에서 오른쪽 버튼을 클릭하여 컨텍스트 메뉴 [New > Class]를 클릭하고 "TestLoginController.java"를 생성합니다.
"TestLoginController.java"클래스 위에 "@TestAnnController"어노테이션(Annotation)를 추가합니다.
@TestAnnController
public class TestLoginController {
기존 "TestDispatcherServlet.java"의 "service"메소드에서 처리되는 "login.do"입니다.
} else if ("/login.do".equals(requestURI)) {
requestDispatcher = request.getRequestDispatcher("/WEB-INF/jsp/login.jsp");
}
"TestLoginController.java"클래스에 "login"메소드를 추가하고 "@TestAnnRequestMapping"어노테이션을 추가합니다.
/**
* 로그인 페이지로 이동합니다.
* @param request HTTP 요청 객체
* @param response HTTP 응답 객체
* @return ModelAndView 객체
*/
@TestAnnRequestMapping(value = "/login.do", method = RequestMethod.POST)
public ModelAndView login(HttpServletRequest request, HttpServletResponse response) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/WEB-INF/jsp/login.jsp");
return modelAndView;
}
기존 "TestDispatcherServlet.java"의 "service"메소드에서 처리되는 "login.do"부분은 주석처리하거나 삭제합니다.
8. "test2" 프로젝트의 "Java Resources"에서 "src/main/java"의 "com.home.project.test2.service"를 선택한 후 오른쪽 버튼을 클릭하여 컨텍스트 메뉴 [New > Interface]를 클릭하여 "ITestLoginService.java"를 생성합니다.
public interface ITestLoginService {
}
로그인 처리를 위해 사용자 조회 메소드를 추가합니다.
/**
* 로그인를 처리합니다.
* @param request HTTP 요청 객체
* @return 로그인 처리 여부
*/
public abstract Boolean doLogin(HttpServletRequest request);
9. "TestLoginService.java"에 "ITestLoginService.java" 인터페이스가 구현(implements)되도록 수정하고 클래스 위에 "@TestAnnService"어노테이션(Annotation)를 추가합니다.
@TestAnnService
public class TestLoginService implements ITestLoginService {
"ITestLoginDao"인터페이스를 클래스 맴버 필드에 추가하고 외부 주입을 위해 "@TestAnnAutowired"어노테이션을 추가합니다.
@TestAnnAutowired
private ITestLoginDao testLoginDao;
"TestLoginService.java"에 기존 "process"메소드를 수정하여 "ITestLoginService.java"의 "doLogin"메소드를 구현합니다.
기존 "process"메소드입니다.
public void process(HttpServletRequest request) throws UnsupportedEncodingException {
String id = request.getParameter("id");
String password = request.getParameter("pwd");
System.out.println("id : " + id + ", password : " + password);
System.out.println("Locale : " + request.getLocale());
System.out.println("Default Locale : " + Locale.getDefault());
ResourceBundle resourceBundle = ResourceBundle.getBundle("com.home.project.test2.message.login", Locale.getDefault());
HttpSession httpSession = request.getSession(false);
httpSession.removeAttribute("auth");
if ("testid".equals(id) && "testpwd".equals(password)) {
UserVO user = new UserVO();
user.setId(id);
user.setName("사용자");
TestSessionManager testSessionManager = TestSessionManager.getInstance();
HttpSession userSession = testSessionManager.getSession(id);
if (null == userSession) {
httpSession.setAttribute("auth", user);
testSessionManager.addSession(id, httpSession);
request.setAttribute("errorMessage", "");
} else {
/**
* 중복 로그인 방지
* 1. 기존 접속자를 로그아웃 시키고 현재 접속자를 로그인 시킵니다.
* 2. 기존 접속자의 로그인을 유지하고 현재 접속자를 차단합니다.
*/
int processType = 2;
if (1 == processType) {
// 기존 접속자
testSessionManager.removeSession(id);
// 현재 접속자
httpSession.setAttribute("auth", user);
testSessionManager.addSession(id, httpSession);
request.setAttribute("errorMessage", "");
} else if (2 == processType) {
// 현재 접속자
request.setAttribute("errorMessage", new String(resourceBundle.getString("login.block").getBytes("ISO-8859-1"), "UTF-8"));
}
}
} else {
request.setAttribute("errorMessage", new String(resourceBundle.getString("login.mismatch").getBytes("ISO-8859-1"), "UTF-8"));
}
}
"process"메소드에 있는 "UnsupportedEncodingException"를 제거하기 위해 메시지 처리 메소드를 추가합니다.
/**
* 리소스번들에서 메시지를 가져옵니다.
* @param messageKey 리소스번들 메시지 키
* @param locale 웹 브라우저 로케일
* @return 메시지
*/
private String getMessage(String messageKey, Locale locale) {
String message = "";
ResourceBundle resourceBundle = ResourceBundle.getBundle("com.home.project.test2.message.login", locale);
try {
message = new String(resourceBundle.getString(messageKey).getBytes("ISO-8859-1"), "UTF-8");
} catch (UnsupportedEncodingException e) {
//e.printStackTrace();
}
return message;
}
"doLogin"메소드를 오버라이드하여 사용자 조회를 위해 "UserVO"를 생성하고 사용자 조회 결과로 아이디와 패스워드를 검사하게 수정합니다.
@Override
public Boolean doLogin(HttpServletRequest request) {
UserVO userVO = new UserVO();
String userId = request.getParameter("id");
if (userId != null && !userId.trim().isEmpty()) {
userVO.setId(userId);
}
String userPassword = request.getParameter("pwd");
if (userPassword != null && !userPassword.trim().isEmpty()) {
userVO.setPassword(userPassword);
}
System.out.println("id : " + userId + ", password : " + userPassword);
if (userId == null || userId.trim().isEmpty() || userPassword == null || userPassword.trim().isEmpty()) {
request.setAttribute("errorMessage", getMessage("login.mismatch", request.getLocale()));
return false;
}
Boolean result = false;
HttpSession httpSession = request.getSession(false);
httpSession.removeAttribute("auth");
UserVO selectUserVO = null;
selectUserVO = testLoginDao.selectMember(userVO);
if (selectUserVO != null) {
if (selectUserVO.getId().equals(userVO.getId()) && selectUserVO.getPassword().equals(userVO.getPassword())) {
TestSessionManager testSessionManager = TestSessionManager.getInstance();
HttpSession userSession = testSessionManager.getSession(selectUserVO.getId());
if (null == userSession) {
selectUserVO.setPassword("");
selectUserVO.setPasswordSalt("");
httpSession.setAttribute("auth", selectUserVO);
testSessionManager.addSession(selectUserVO.getId(), httpSession);
request.setAttribute("errorMessage", "");
result = true;
} else {
/**
* 중복 로그인 방지
* 1. 기존 접속자를 로그아웃 시키고 현재 접속자를 로그인 시킵니다.
* 2. 기존 접속자의 로그인을 유지하고 현재 접속자를 차단합니다.
*/
int processType = 2;
if (1 == processType) {
// 기존 접속자
testSessionManager.removeSession(selectUserVO.getId());
// 현재 접속자
selectUserVO.setPassword("");
selectUserVO.setPasswordSalt("");
httpSession.setAttribute("auth", selectUserVO);
testSessionManager.addSession(selectUserVO.getId(), httpSession);
request.setAttribute("errorMessage", "");
result = true;
} else if (2 == processType) {
// 현재 접속자
request.setAttribute("errorMessage", getMessage("login.block", request.getLocale()));
}
}
} else {
request.setAttribute("errorMessage", getMessage("login.mismatch", request.getLocale()));
}
} else {
request.setAttribute("errorMessage", getMessage("login.mismatch", request.getLocale()));
}
return result;
}
자세한 설명은 자바 시큐리티 필터 만들기(https://carrotweb.tistory.com/37)와 자바 싱글톤 세션 매니저 만들기(중복 로그인)(https://carrotweb.tistory.com/43)를 참고하시기 바랍니다.
기존 "process"메소드를 주석처리하거나 삭제합니다.
10. 기존 "TestDispatcherServlet.java"의 "service"메소드에서 처리되는 "loginprocess.do"입니다.
} else if ("/loginprocess.do".equals(requestURI)) {
String returnUrl = request.getParameter("returnUrl");
request.setAttribute("returnUrl", returnUrl);
TestLoginService testLoginService = new TestLoginService();
testLoginService.process(request);
boolean auth = false;
HttpSession httpSession = request.getSession(false);
if (null != httpSession) {
if (null != httpSession.getAttribute("auth")) {
auth = true;
}
}
if (auth) {
System.out.println("returnUrl : " + returnUrl);
response.sendRedirect(returnUrl);
} else {
requestDispatcher = request.getRequestDispatcher("/login.do");
}
}
"TestLoginController.java"클래스에 "ITestLoginService"클래스 맴버 필드를 추가하고 "@TestAnnAutowired"어노테이션을 추가합니다.
/**
* 로그인 처리 인터페이스 객체
*/
@TestAnnAutowired
private ITestLoginService testLoginService;
"TestLoginController.java"클래스에 "loginProcess"메소드를 추가하고 "@TestAnnRequestMapping"어노테이션을 추가합니다.
/**
* 로그인 처리 페이지로 이동합니다.
* @param request HTTP 요청 객체
* @param response HTTP 응답 객체
* @return ModelAndView 객체
*/
@TestAnnRequestMapping(value = "/loginprocess.do", method = RequestMethod.POST)
public ModelAndView loginProcess(HttpServletRequest request, HttpServletResponse response) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/login.do");
String returnUrl = request.getParameter("returnUrl");
request.setAttribute("returnUrl", returnUrl);
if (testLoginService.doLogin(request)) {
System.out.println("returnUrl : " + returnUrl);
modelAndView.setViewName("redirect:" + returnUrl);
} else {
modelAndView.setViewName("/login.do");
}
return modelAndView;
}
기존 "TestDispatcherServlet.java"의 "service"메소드에서 처리되는 "loginprocess.do"부분은 주석처리하거나 삭제합니다.
이어서 "TestServletContextListener.java"에서 다오(DAO) 클래스에서 사용할 수 있게 의존성 주입(Dependency Injection - DI)를 하겠습니다.