티스토리 뷰

실습4 - 1에서는 JSP로 메인, 로그인 화면을 구현했습니다.

 

이번장에서는 로그인과 로그아웃 기능을 만들어 보겠습니다.

 

실습4 - 1에서 생각해볼 내용

- POST방식에서 데이터의 전송 흐름

- $(document).ready(function() ~) 이란?

- jstl이란?

Goal

 - 로그인 기능 구현

 - 로그아웃 기능 구현

 

[로그인 흐름]

사용자는 아이디와, 비밀번호를 입력하여 로그인을 요청합니다. 

백엔드에서의 역할은 사용자로부터 입력받은 정보를 확인하여 데이터베이스의 정보화 조회한 뒤 로그인 처리를 한 후 결과를 반환하는 것 입니다.

1. UserController 

 - 컨트롤러에서는 사용자로부터 입력받은 정보를 받아 유효성을 판단한 뒤 service에 작업을 요청합니다. 

*Controller란?

: 컨트롤러는 클라이언트가 보낸 데이터를 적절히 가공하여 모델에 보내고 모델이 업무 수행을 완료하면, 그 결과를 가지고 화면을 생성하도록 뷰에 전달합니다. SpringBoot에서는 @Controller 어노테이션을 사용하여 Controller class라는 것을 명시합니다.

 

 - User와 관련된 기능을 처리하는 Controller는 UserController로 네이밍하겠습니다.

 

1) UserController 전체 코드

package com.coronabook.springboot.controller;

import java.util.Map;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.coronabook.springboot.model.User;
import com.coronabook.springboot.service.UserService;

@Controller
@RequestMapping("/user")
public class UserContorller {

	@Autowired
	private UserService userService;

	@GetMapping(value = "/login")
	public String login() {
		return "user/login";
	}

	@PostMapping("/login")
	public String login(@RequestParam Map<String, String> map, Model model, HttpSession session) {
		try {
			if (map.get("userid") == null || map.get("userpwd") == null) {
				model.addAttribute("msg", "아이디 또는 비밀번호를 입력해주세요");
				return "error/error";
			}
			User user = userService.login(map);
			if (user != null) {
				session.setAttribute("user", user);
			} else {
				model.addAttribute("msg", "아이디 또는 비밀번호가 올바르지 않습니다.");
				return "error/error";
			}
		} catch (Exception e) {
			e.printStackTrace();
			model.addAttribute("msg", "로그인 중 문제가 발생했습니다.");
			return "error/error";
		}
		return "index";
	} // end of PostMapping("login")
}

[UserController 코드 설명]

@Controller
@RequestMapping("/user")
public class UserContorller {

 - @Controller, @RequestMapping("/user")

:  @Controller은 @Component에서 Controller를 특정지을 수 있도록 한 어노테이션 입니다. 어노테이션이 붙은 class는 implement될 때 classpath scanning에 의해 자동으로 스캔됩니다. @Controller는 주로 @RequestMapping 어노테이션과 자주 사용됩니다. @RequestMapping 어노테이션은 요청을 처리하는 (request handling) 메서드의 위에 작성합니다. 클래스의 위에 작성하면, 해당 클래스의 접근에 URL 매핑을 해줍니다.

 

: 따라서 UserController에 접근할 때는 context-path/user URL로 접근하고, login 메서드에 접근할 때는 context-path/user/login 형식으로 접근합니다.

@Autowired
private UserService userService;

 - @Autowired (참고 : Autowired를 사용하기 위해 이해해야 하는 Spring component 구조)

: @Autowired 어노테이션은 해당 어노테이션을 선언한 코드에 Autowire을 해줍니다. Autowire된 객체는 사용자가 직접 new로 생성하는 것이 아닌 Spring이 객체를 생성해서 주입해줍니다. 이러한 객체의 주입을 의존성주입 (DI)라고 합니다.

 - Service

: Spring MVC 패턴에서 Model은 일반적으로 Service와 DAO로 구성되어 있습니다. 사용자의 데이터를 가공하여 Model로 보내는 Controller는 우선적으로 Service를 호출하여 Service에 데이터 처리를 요청합니다. 

@GetMapping(value = "/login")
public String login() {
return "user/login";
}

  - Get방식으로 user/login URL에 들어온 사용자의 요청을 받으면 login화면을 보여주는 코드입니다. String으로 반환된 "user/loing"에서는 viewResolver를 통해 .jsp파일의 위치로 변환되어 해당 페이지를 띄워줄 수 있게 됩니다.

	@PostMapping("/login")
	public String login(@RequestParam Map<String, String> map, Model model, HttpSession session) {
		try {
			if (map.get("userid") == null || map.get("userpwd") == null) {
				model.addAttribute("msg", "아이디 또는 비밀번호를 입력해주세요");
				return "error/error";
			}
			User user = userService.login(map);
			if (user != null) {
				session.setAttribute("user", user);
			} else {
				model.addAttribute("msg", "아이디 또는 비밀번호가 올바르지 않습니다.");
				return "error/error";
			}
		} catch (Exception e) {
			e.printStackTrace();
			model.addAttribute("msg", "로그인 중 문제가 발생했습니다.");
			return "error/error";
		}
		return "index";
	} // end of PostMapping("login")

 - Post 방식으로 user/login URL에 요청을 하면 페이지 이동이 아닌 사용자 로그인을 처리합니다. 

 - 요청받은 데이터인 userid와 userpwd를 확인하여 error페이지로 에러메세지를 보낼지, 로그인을 처리하는 service 메서드를 호출할지 if문을 통해 확인합니다.

 - session.setAttribute : model단에서 받어온 userid, userpwd에 해당하는 user가 있을 경우 session에 해당 정보 유저를 저장하여 index페이지로 이동합니다. index 페이지에서는 sessionScope에 저장된 user데이터에 따라 로그인정보가 인식됩니다.

2. UserService

 *Service란?

 : Service는 트랜잭션의 한 단위입니다. 트랜잭션이란 하나의 논리적 기능을 수행하기 위한 작업의 단위로서 로그인기능을 예로 들었을 때, login을 하기 위해 userid와 userpwd를 DB에서 확인하기 위해 수행하는 하나의 작업을 의미합니다. Service의 작업은 하나이지만 이 작업을 수행하기 위해서는 DAO가 여러번 불릴 수 있습니다. 따라서 Service에서 논리적으로 처리하는 하나의 작업에는 많은 수의 DAO호출이 있을 수 있기 때문에 Service와 DAO를 나누는 것이 적절합니다.

 - User와 관련된 Service이기 때문에 UserService로 네이밍하겠습니다.

 

1) UserService 전체 코드

 1-1) UserService.java

package com.coronabook.springboot.service;

import java.util.Map;

import com.coronabook.springboot.model.User;

public interface UserService {
	
	public User login(Map<String, String > map) throws Exception;
	
}

 

[UserService.java 코드설명]

 - Service는 재사용성과 확장성을 위해 인터페이스와 구현부분으로 분리하겠습니다.

 - login 처리를 수행할 수 있는 메서드를 정의합니다. ServiceImpl이 해당 메서드를 구현합니다.

 

 1-2) UserServiceImpl.java

package com.coronabook.springboot.service;

import java.util.Map;

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

import com.coronabook.springboot.mapper.UserMapper;
import com.coronabook.springboot.model.User;

@Service("userService")
public class UserServiceImpl implements UserService {
	
	@Autowired
	private UserMapper userMapper;
	
	public User login(Map<String, String> map) throws Exception {
		return userMapper.login(map);
	}
	

}

[UserServiceImpl.java 코드설명]

@Service("userService")

 - Spring이 해당 클래스가 Service임을 알 수 있도록 @Service 어노테이션을 명시합니다. 어노테이션을 명시하면서 이름을 부여할 수 있습니다.

@Autowired
private UserMapper userMapper;

public User login(Map<String, String> map) throws Exception {
	return userMapper.login(map);
}

 - Service는 작업단위를 수행하기 위해 데이터베이스와 연결하여 로직을 처리하는 Mapper클래스를 필요로합니다. UserMapper를 사용하기 위해 @Autowired를 통해 객체를 주입할 수 있도록 합니다.

 - login 메서드는 userMapper의 login메서드를 호출합니다. Mapper의 login메서드는 데이터베이스와 직접 소통하여 login 처리를 할 것입니다.

3. UserMapper

 - Mapper 인터페이스는 Mapper XML파일에 있는 SQL을 호출하기 위한 인터페이스 입니다.

 - @Mapper 어노테이션은 해당 interface가 Mapper 인터페이스임을 알려줍니다.

 * Mapper 인터페이스는 Implementation을 필요로 하지 않습니다. 좀 더 자세히 알아보려면 참고하세요 ( DAO vs Mapper Interface )

package com.coronabook.springboot.mapper;

import java.util.Map;

import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import com.coronabook.springboot.model.User;

@Mapper
@Repository
public interface UserMapper {
	
	public User login(Map<String, String> map);
}

 - @Repository 

: @Repository은 해당 클래스가 repository임을 알려줍니다. class scanning을 통해 @Repository를 Spring beans로 등록됩니다. 스프링에서 Repository는 해당 클래스가 storage, retrieval, search, update 그리고 delete의 기능을 제공하는 클래스를 의미합니다.

4. mapper/user.xml

 - Mapper XML파일은 resources안에 mapper라는 파일을 두어 따로 관리하겠습니다. 

* Mapper XML

: Mapper XML파일은 select, insert, update 그리고 delete와 같인 SQL문들을 설정하는 코드들을 포함하는 Mybatis의 파일입니다. XML에 선언된 코드들은 Mapped Statements 또는 Mapped SQL Statements라고 불립니다.  

( mapper XML file prevents the burden of writing SQL statements repeatedly in the application. In comparison to JDBC, almost 95% of the code is reduced using Mapper XML file in MyBatis. )

 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
	
<mapper namespace="com.coronabook.springboot.mapper.UserMapper">

	<select id="login" parameterType="map" resultType="User">
		select username, userid, email
		from user
		where userid = #{userid} and userpwd = #{userpwd}
	</select>
	
</mapper>
<mapper namespace="com.coronabook.springboot.mapper.UserMapper">

<mapper namespace=~> </mapper> : Mapper XML안의 모든 Mapped SQL statements는 <mapper>라는 이름의 element안에 작성되어 있습니다. <mapper> element는 namespace라는 속성값을 같습니다. namespace와 Mapped Statements의 id를 확인하여 UserMapper에 작성한 메서드와 해당 SQL문을 매핑해줍니다. 따라서 메서드에서 전달된 데이터를 사용할 수 있고 SQL의 결과를 다시 메서드로 반환할 수 있게 됩니다.

<select id="login" parameterType="map" resultType="User">
    select username, userid, email
    from user
    where userid = #{userid} and userpwd = #{userpwd}
</select>

 - 모든 statements는 unique한 id를 갖습니다. 이 id는 UserMapper.java에 정의된 login 메서드와 매핑됩니다. 

5. 실행화면

 * 현재 회원가입 기능이 구현 되어있지 않습니다. 다음 sql문을 복사하고 실행하여 user 테이블에 생성하고 해당 사용자 정보로 로그인을 테스트 해보세요

 - test사용자 insert sql

insert into user (userid, username, userpwd, email, phonenumber, address, joindate)
values ("11", "11", "11", "11@11.com", "11", "11", now());

 

 - 자 이제 로그인 기능이 완료되었습니다. 서버를 실행하고 매핑된 URL(http://localhost:8000/coronabook/)로 방문했을 때 다음과 같은 화면이 나오고 로그인이 정상적으로 이루어지면 완성입니다!

 

이번 장에서는 로그인 기능을 구현하고 Spring MVC 패턴에서 각 컴포넌트의 기능에 대해 알아보았습니다.

글이 길어진 관계로 다음장에서 로그아웃을 구현하겠습니다.

댓글