본문 바로가기

학원/복기

[Spring] 예외 클래스 / ExceptionHandler / jbcrypt 라이브러리

SpirngMVC 구현 

 

 

USERINFO 테이블을 이용할 것임

 


DTO 선언

Userinfo 

@Data
public class Userinfo {
	private String userid;
	private String password;
	private String name;
	private String email;
	private int status;
}

 

Mapper 생성

 

UserinfoMapper.xml

 

UserinfoMapper.java

public interface UserinfoMapper {
	int insertUserinfo(Userinfo userinfo);
	int updateUserinfo(Userinfo userinfo);
	int deleteUserinfo(String userid);
	Userinfo selectUserinfo(String userid);
	List<Userinfo> selectUserinfoList();
}

 

DAO 선언

 

UserinfoDAOImpl

//상속받을 인터페이스
public interface UserinfoDAO {
	int insertUserinfo(Userinfo userinfo);
	int updateUserinfo(Userinfo userinfo);
	int deleteUserinfo(String userid);
	Userinfo selectUserinfo(String userid);
	List<Userinfo> selectUserinfoList();
}

@Repository
@RequiredArgsConstructor
public class UserinfoDAOImpl implements UserinfoDAO {
	private final SqlSession sqlSession;

	@Override
	public int insertUserinfo(Userinfo userinfo) {
		return sqlSession.getMapper(UserinfoMapper.class).insertUserinfo(userinfo);
	}

	@Override
	public int updateUserinfo(Userinfo userinfo) {
		return sqlSession.getMapper(UserinfoMapper.class).updateUserinfo(userinfo);
	}

	@Override
	public int deleteUserinfo(String userid) {
		return sqlSession.getMapper(UserinfoMapper.class).deleteUserinfo(userid);
	}

	@Override
	public Userinfo selectUserinfo(String userid) {
		return sqlSession.getMapper(UserinfoMapper.class).selectUserinfo(userid);
	}

	@Override
	public List<Userinfo> selectUserinfoList() {
		return sqlSession.getMapper(UserinfoMapper.class).selectUserinfoList();
	}
}

 

인위적 예외 처리 위한 예외 클래스를  선언해보자 

 

xyz.itwill10.exception 패키지 생성

 

 

ExistsUserinfoException

//회원정보를 등록할 때 사용자로부터 입력받은 회원정보의 아이디가 기존 회원정보의 아이디와 중복될 경우 
//발생될 예외를 처리하기 위한 예외 클래스

@Getter
public class ExistsUserinfoException extends Exception {
	private static final long serialVersionUID = 1L;
	//예외처리에 필요한 값을 저장하기 위한 필드 선언
	private Userinfo userinfo; //사용자로부터 입력받은 회원정보를 저장

	public ExistsUserinfoException() {
		// TODO Auto-generated constructor stub
	}
	
	//매개변수로 예외 메세지와 예외처리에 필요한 값을 전달받아 필드에 저장 
	public ExistsUserinfoException(String message, Userinfo userinfo) {
		super(message);//부모 클래스 Exception의 생성자 호출 - 객체 생성시 메세지 전달 가능
		this.userinfo=userinfo;//클래스 내의 멤버 변수에 값 할당
	}
}

 

UserinfoNotFoundException

//회원정보에 대한 변경, 삭제, 검색할 때 사용자로부터 전달받은 아이디의 회원정보가 없는 경우 
//발생될 예외를 처리하기 위한 예외 클래스 
public class UserinfoNotFoundException extends Exception {
	private static final long serialVersionUID = 1L;

	public UserinfoNotFoundException() {
		// TODO Auto-generated constructor stub
	}
	
	public UserinfoNotFoundException(String message) {
		super(message);//부모 클래스 Exception의 생성자 호출 - 객체 생성시 메세지 전달 가
	}
}

 

LoginAuthFailException

//로그인할때 사용자로부터 입력받은 아이디와 비밀번호에 대한 인증이 실패한 경우
//발생될 예외를 처리하기 위한 예외 클래스 
public class LoginAuthFailException extends Exception {
	private static final long serialVersionUID = 1L;
	
	//예외처리에 필요한 값을 저장하기 위한 필드
	// -> 사용자로부터 입력받은 아이디를 저장하기 위한 필드
	@Getter
	private String userid;
	
	public LoginAuthFailException() {
		// TODO Auto-generated constructor stub
	}
	
	public LoginAuthFailException(String message, String userid) {
		super(message);
		this.userid=userid;
	}
}

 

 

사용자로부터 전달된 값이 이상하면 처리를 못하기 때문에 인위적 예외를 발생시키기 위해 예외 클래스를 만들어 떠넘길 수 있도록 만들 수 있다. 

데이터를 처리하기 위해 발생하는 모든 문제를 인위적인 예외를 발생하는 것으로 대체하고, Front Controller가 알아서 처리하도록 만들어 주는 것이다. (이를 위해선 Exception Handler를 만들어야 한다.)

새로운 Exception클래스를 만드는이유는 클래스이름때문인데, 클래스를 보고 어떤 종류의 에러인지 직관적으로 알 수 있기 때문이다. 

예외를 명확하게 구분하고 예외처리시 필요한 값을 제공받기 위해 직접 생성한 예외 클래스를 사용하여 인위적 예외를 발생시킨다. 

 

 

Service 선언

 

UserinfoService

//서비스 클래스가 상속받을 인터페이스
public interface UserinfoService {
	void addUserinfo(Userinfo userinfo) throws ExistsUserinfoException;
	void modifyUserinfo(Userinfo userinfo) throws UserinfoNotFoundException;
	void removeUserinfo(String userid) throws UserinfoNotFoundException;
	void getUserinfo(String userid) throws UserinfoNotFoundException;
	List<Userinfo> getUserinfoList();
	Userinfo loginAuth(Userinfo userinfo) throws LoginAuthFailException;
}

 

 

사용자로부터 입력받아 전달된 문자열(비밀번호)을 암호화 처리하는 방법에 대해 알아보자

 

spring security를 이용하는 방법과 간단히 암호화만 하는 방법이 있는데 우선 후자로 해볼 것이다.

 

1. jbcrypt 라이브러리(자바에서 사용하는 암호화 라이브러리)를 프로젝트에 빌드 처리한다. - 메이븐을 이용 : pom.xml 

 

https://mvnrepository.com/artifact/org.mindrot/jbcrypt/0.4

 

 

pom.xml

 

 

2. BCrypt.hashpw(String password, String salt) 메소드를 호출하여 문자열을 암호화 처리할 수 있다.

  • 매개변수로 암호화 처리할 문자열과 첨가물을 전달받아 암호화 처리한다. 
  • 첨가물에 의해 비밀번호가 다르게 암호화 처리 된다.
  • BCrypt 클래스는 단방향 암호화 기능의 BlowFish 알고리즘을 기반으로 설계된 암호화 처리 클래스이다.
  • BCrypt.gensalt(int log_bounds) : 매개변수로 첨가물(Salt - String)의 길이를 전달받아 첨가물을 생성하여 반환하는 메소드 - 매개변수에 길이를 전달하지 않으면 자동으로 [10]으로 설정된다. (첨가물의 길이가 짧을수록 속도가 빠르다)

 

3. BCrypt.checkpw(String plaintext, String hashed) 메소드로 암호화된 비밀번호를 비교하여 실행결과를 반환받아 처리한다.

  • 매개변수로 일반 문자열과 암호화된 문자열을 비교하여 다른 경우 [false]를 반환하고 같은 경우 true를 반환하는 메소드이다. 

 

UserinfoServiceImpl

//서비스 클래스
@Service
@RequiredArgsConstructor
public class UserinfoServiceImpl implements UserinfoService {
	private final UserinfoDAO userinfoDAO;

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void addUserinfo(Userinfo userinfo) throws ExistsUserinfoException {
		//매개변수로 전달받은 회원정보의 아이디가 기존 회원정보의 아이디와 중복될 경우
		if(userinfoDAO.selectUserinfo(userinfo.getUserid()) != null) {
			//예외를 명확하기 구분하고 예외처리시 필요한 값을 제공하기 위해 직접 생성한 예외 
			//클래스를 사용하여 인위적인 예외 발생
			throw new ExistsUserinfoException("이미 사용중인 아이디를 입력 하였습니다.", userinfo);
		}
		
		//매개변수로 전달받은 회원정보의 비밀번호를 암호화 처리하여 필드값으로 다시 저장
		String hashedPassword=BCrypt.hashpw(userinfo.getPassword(), BCrypt.gensalt());
		userinfo.setPassword(hashedPassword);
		
		userinfoDAO.insertUserinfo(userinfo);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void modifyUserinfo(Userinfo userinfo) throws UserinfoNotFoundException {
		//매개변수로 전달받은 회원정보의 아이디로 기존 회원정보를 검색하여 검색결과가 없는 경우
		if(userinfoDAO.selectUserinfo(userinfo.getUserid()) == null) {
			throw new UserinfoNotFoundException("아이디의 회원정보가 존재하지 않습니다.");
		}
		
		//매개변수로 전달받은 회원정보의 비밀번호가 존재할 경우 비밀번호를 암호화 처리하여 필드값으로 저장
		if(userinfo.getPassword() != null && !userinfo.getPassword().equals("")) {
			String hashedPassword=BCrypt.hashpw(userinfo.getPassword(), BCrypt.gensalt());
			userinfo.setPassword(hashedPassword);			
		}
		
		userinfoDAO.updateUserinfo(userinfo);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void removeUserinfo(String userid) throws UserinfoNotFoundException {
		//매개변수로 전달받은 아이디로 기존 회원정보를 검색하여 검색결과가 없는 경우
		if(userinfoDAO.selectUserinfo(userid) == null) {
			throw new UserinfoNotFoundException("아이디의 회원정보가 존재하지 않습니다.");
		}	
		
		userinfoDAO.deleteUserinfo(userid);
	}

	@Override
	public Userinfo getUserinfo(String userid) throws UserinfoNotFoundException {
		//매개변수로 전달받은 아이디로 기존 회원정보를 검색하여 검색결과를 반환받아 저장
		Userinfo userinfo=userinfoDAO.selectUserinfo(userid);
		
		//검색된 회원정보가 없는 경우
		if(userinfo == null) {
			throw new UserinfoNotFoundException("아이디의 회원정보가 존재하지 않습니다.");
		}
		
		return userinfo;
	}

	@Override
	public List<Userinfo> getUserinfoList() {
		return userinfoDAO.selectUserinfoList();
	}

	//매개변수로 회원정보(아이디와 비밀번호)를 전달받아 인증 처리하기 위한 메소드
	// => 인증 실패시 예외 발생하고 인증 성공시 예외 미발생
	// => 인증 성공시 로그인된 회원정보를 검색하여 반환 - 세션에 권한 관련 정보로 저장
	@Override
	public Userinfo loginAuth(Userinfo userinfo) throws LoginAuthFailException {
		//매개변수로 전달받은 회원정보의 아이디로 기존 회원정보를 검색하여 검색결과를 반환받아 저장
		Userinfo authUserinfo=userinfoDAO.selectUserinfo(userinfo.getUserid());

		//검색된 회원정보가 없는 경우 - 아이디 인증 실패
		if(authUserinfo == null) {
			throw new LoginAuthFailException("아이디의 회원정보가 존재하지 않습니다.", userinfo.getUserid());
		}
		
		//매개변수로 전달받은 회원정보의 비밀번호와 검색된 회원정보의 비밀번호를 비교하여
		//같지 않은 경우 - 비밀번호 인증 실패
		if(!BCrypt.checkpw(userinfo.getPassword(), authUserinfo.getPassword())) {
			throw new LoginAuthFailException("아이디가 없거나 비밀번호가 맞지 않습니다.", userinfo.getUserid());
		}
		
		//매개변수로 전달받은 회원정보의 아이디로 검색된 회원정보 반환 
		return authUserinfo;
	}
}

 

 

Controller 클래스 선언 

 

UserinfoController

@Controller
@RequestMapping("/userinfo")
@RequiredArgsConstructor
public class UserinfoController {
	private final UserinfoService userinfoService;
	
	@RequestMapping(value = "/write", method = RequestMethod.GET)
	public String write(HttpSession session) {
		Userinfo loginUserinfo=(Userinfo)session.getAttribute("loginUserinfo");
		
		return "userinfo/user_write";
	}
	
	//회원정보를 전달받아 USERINFO 테이블에 삽입하고 로그인 페이지를 요청할 수 있는 URL 주소를
	//클라이언트에게 전달하여 응답 처리하는 요청 처리 메소드
	// => UserinfoService 객체로 메소드 호출시 예외 발생 - 예외 처리 메소드를 이용하여 예외 처리
	@RequestMapping(value = "/write", method = RequestMethod.POST)
	public String write(@ModelAttribute Userinfo userinfo) throws ExistsUserinfoException {
		userinfoService.addUserinfo(userinfo);
		return "redirect:/userinfo/login";
	}
}

 

user_write.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>    
<%-- 사용자로부터 회원정보를 입력받기 위한 JSP 문서 --%>
<%-- => [회원등록] 태그를 클릭한 경우 [/userinfo/write] 페이지 요청 - 입력값(회원정보) 전달 --%>
<%-- => [로그인] 태그를 클릭한 경우 [/userinfo/login] 문서 요청 --%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>SPRING</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel=stylesheet href="<c:url value="/css/user.css"/>" type="text/css">
<script language="JavaScript">
function userCreate() {
	if ( f.userid.value == "" ) {
		alert("아이디를 입력하십시요.");
		f.userid.focus();
		return;
	} 
	if ( f.password.value == "" ) {
		alert("비밀번호를 입력하십시요.");
		f.password.focus();
		return;
	}
	if ( f.name.value == "" ) {
		alert("이름을 입력하십시요.");
		f.name.focus();
		return;
	}
	
	f.action = "<c:url value="/userinfo/write"/>";
	f.submit();
}
</script>
</head>
<body bgcolor=#FFFFFF text=#000000 leftmargin=0 topmargin=0 marginwidth=0 marginheight=0>
<br>
<table width=780 border=0 cellpadding=0 cellspacing=0>
	<tr>
	  <td width="20"></td>
	  <td style="color: red;">${message }</td>			
	</tr>

	<tr>
	  <td width="20"></td>
	  <td>
	  <table width=590 border=0 cellpadding=0 cellspacing=0>
		  <tr>
			<td bgcolor="f4f4f4" height="22">&nbsp;&nbsp;<b>회원관리 - 회원등록</b></td>
		  </tr>
	  </table>  
	  <br>
	  
	  <form name="f" method="post">
	  <table border="0" cellpadding="0" cellspacing="1" width="590" bgcolor="BBBBBB">
		  <tr>
			<td width=100 align=center bgcolor="E6ECDE" height="22">아이디</td>
			<td width=490 bgcolor="ffffff" style="padding-left:10px;">
				<input type="text" style="width:150" name="userid" value="${userinfo.userid }">
			</td>
		  </tr>
		  <tr>
			<td width=100 align=center bgcolor="E6ECDE" height="22">비밀번호</td>
			<td width=490 bgcolor="ffffff" style="padding-left:10px;">
				<input type="password" style="width:150" name="password" value="${userinfo.password }">
			</td>
		  </tr>
		  <tr>
			<td width=100 align=center bgcolor="E6ECDE" height="22">이름</td>
			<td width=490 bgcolor="ffffff" style="padding-left:10px;">
				<input type="text" style="width:240" name="name" value="${userinfo.name }">
			</td>
		  </tr>
		  <tr>
			<td width=100 align=center bgcolor="E6ECDE" height="22">이메일</td>
			<td width=490 bgcolor="ffffff" style="padding-left:10px;">
				<input type="text" style="width:240" name="email" value="${userinfo.email }">
			</td>
		  </tr>
		  <tr>
			<td width=100 align=center bgcolor="E6ECDE" height="22">회원등급</td>
			<td width=490 bgcolor="ffffff" style="padding-left:10px;">
				<select name="status">
					<option value="1" <c:if test="${userinfo.status == 1 }">selected</c:if>>일반회원</option>
					<option value="9" <c:if test="${userinfo.status == 9 }">selected</c:if>>관리자</option>
				</select>
			</td>
		  </tr>		  
	  </table>
	  </form>
	  <br>
	  <table width=590 border=0 cellpadding=0 cellspacing=0>
		  <tr>
			<td align=center>
				<input type="button" value="회원등록" onClick="userCreate();">
				<input type="button" value="로그인" onClick="location.href='<c:url value="/userinfo/login"/>';">
			</td>
		  </tr>
	  </table>
	  </td>
	</tr>
</table>  
</body>
</html>

 

 

관리자와 일반회원을 각각 등록해주었다. 비밀번호는 암호화 처리 되어 저장된 것을 확인할 수 있다.

 

 

예외클래스를 추가로 선언해주자

 

 BadRequestException

//비정상적으로 페이지를 요청한 경우 발생될 예외를 처리하기 위한 예외 클래스
public class BadRequestException extends Exception {
	private static final long serialVersionUID = 1L;

	public BadRequestException() {
		// TODO Auto-generated constructor stub
	}
	
	public BadRequestException(String message) {
		super(message);
	}
}

 

회원정보를 입력받기 위한 뷰이름을 반환하는 요청 처리 메소드 write()를 비로그인 사용자 또는 관리자가 아닌 사용자가 페이지를 요청할 경우 BadRequestException 클래스를 통해 인위적 예외를 발생시키도록 작성해보자.

 

UserinfoController

//회원정보를 입력받기 위한 뷰이름을 반환하는 요청 처리 메소드
// => 비로그인 사용자 또는 관리자가 아닌 사용자가 페이지를 요청할 경우 인위적 예외 발생
@RequestMapping(value = "/write", method = RequestMethod.GET)
public String write(HttpSession session) throws BadRequestException {
	Userinfo loginUserinfo=(Userinfo)session.getAttribute("loginUserinfo");
	if(loginUserinfo == null || loginUserinfo.getStatus() !=9) {
		throw new BadRequestException("비정상적인 요청입니다.");
	}
	return "userinfo/user_write";
}

 

클라이언트가 비정상적인 요청을 한 경우 인위적 예외가 발생한다.

 

 

회원정보를 전달받아 USERINFO 테이블에 삽입하고 로그인 페이지를 요청할 있는 URL 주소를 클라이언트에게 전달하여 응답 처리하는 요청 처리 메소드를 선언해보자. - UserinfoService 객체로 메소드 호출시 예외가 발생한다.

 

UserinfoController

1.try~catch 구문을 사용하여 예외 처리

@RequestMapping(value = "/write", method = RequestMethod.POST)
public String write(@ModelAttribute Userinfo userinfo, Model model) {
	try {
		//매개변수로 전달받은 회원정보의 아이디가 중복될 경우 ExistsUserinfoException 발생
		userinfoService.addUserinfo(userinfo);
	} catch (ExistsUserinfoException e) {
		//ExistsUserinfoException 객체에 저장된 예외 메세지를 반환받아 속성값으로 저장
		model.addAttribute("message", e.getMessage());
			
		//ExistsUserinfoException 객체에 저장된 회원정보(Userinfo 객체)를 반환받아 속성값으로 저장
		//model.addAttribute("userinfo", e.getUserinfo());
			
		//아이디가 중복되어 예외가 발생된 경우 회원정보를 입력받기 위한 뷰이름 반환
		return "userinfo/user_write";
	}
	return "redirect:/userinfo/login";
}
	
	
2.ExistsUserinfoException 클래스에 떠넘겨서 예외처리 

@RequestMapping(value = "/write", method = RequestMethod.POST)
public String write(@ModelAttribute Userinfo userinfo) throws ExistsUserinfoException {
	userinfoService.addUserinfo(userinfo);
	return "redirect:/userinfo/login";
}

 

로그인정보를 전달받아 로그인 처리하고 환영메세지를 출력하는 뷰이름을 반환하는 요청 메소드를 작성해보자. 

 

//로그인정보를 입력받기 위한 뷰이름을 반환하는 요청 처리 메소드
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String login() {
	return "userinfo/user_login";
}

1.try~catch 구문을 사용하여 예외 처리 - 인증 성공후 로그인 회원정보를 세션의 속성값으로 저장 - 권한

@RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(@ModelAttribute Userinfo userinfo, Model model, HttpSession session) {
	try {
		//매개변수로 전달받은 회원정보로 인증 실패된 경우 LoginAuthFailException 발생
		Userinfo authUserinfo=userinfoService.loginAuth(userinfo);
				
		//LoginAuthFailException 미발생 - 인증 성공
		session.setAttribute("loginUserinfo", authUserinfo);
	} catch (LoginAuthFailException e) {
		model.addAttribute("message", e.getMessage());
		model.addAttribute("userid", e.getUserid());
		return "userinfo/user_login";
	}
			
	return "userinfo/user_login";
}


2.LoginAuthFailException에 떠넘겨서 예외처리

@RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(@ModelAttribute Userinfo userinfo, HttpSession session) throws LoginAuthFailException {
	Userinfo authUserinfo=userinfoService.loginAuth(userinfo);
	session.setAttribute("loginUserinfo", authUserinfo);
	return "userinfo/user_login";
}

 

기타 메소드들 

...
	//로그아웃 처리하고 로그인 페이지를 요청할 수 있는 URL 주소를 클라이언트에게 전달하여 
	//응답 처리하는 요청 처리 메소드
	@RequestMapping("/logout")
	public String logout(HttpSession session) {
		//session.removeAttribute("loginUserinfo");
		session.invalidate();
		
		return "redirect:/userinfo/login";
	}

	//USEINFO 테이블에 저장된 모든 회원정보를 검색하여 속성값으로 저장하여 회원목록을 출력하는
	//뷰이름을 반환하는 요청 처리 메소드
	// => 비로그인 사용자가 페이지를 요청할 경우 인위적 예외 발생
	@RequestMapping("/list")
	public String list(Model model, HttpSession session) throws BadRequestException {
		Userinfo loginUserinfo=(Userinfo)session.getAttribute("loginUserinfo");
		if(loginUserinfo == null) {
			throw new BadRequestException("비정상적인 요청입니다.");
		}
		
		model.addAttribute("userinfoList", userinfoService.getUserinfoList());
		return "userinfo/user_list";
	}
	
	//아이디를 전달받아 USEINFO 테이블에 저장된 회원정보를 검색하여 속성값으로 저장하여 
	//회원정보를 출력하는 뷰이름을 반환하는 요청 처리 메소드
	// => 비로그인 사용자가 페이지를 요청할 경우 인위적 예외 발생
	@RequestMapping("/view")
	public String view(@RequestParam String userid, Model model, HttpSession session) throws BadRequestException, UserinfoNotFoundException {
		Userinfo loginUserinfo=(Userinfo)session.getAttribute("loginUserinfo");
		if(loginUserinfo == null) {
			throw new BadRequestException("비정상적인 요청입니다.");
		}
		
		model.addAttribute("userinfo", userinfoService.getUserinfo(userid));
		return "userinfo/user_view";
	}

	//아이디를 전달받아 USEINFO 테이블에 저장된 회원정보를 검색하여 속성값으로 저장하여 
	//회원정보를 변경하는 뷰이름을 반환하는 요청 처리 메소드
	// => 비로그인 사용자 또는 관리자가 아닌 사용자가 페이지를 요청할 경우 인위적 예외 발생
	@RequestMapping(value = "/modify", method = RequestMethod.GET)
	public String modify(@RequestParam String userid, Model model, HttpSession session) throws BadRequestException, UserinfoNotFoundException {
		Userinfo loginUserinfo=(Userinfo)session.getAttribute("loginUserinfo");
		if(loginUserinfo == null || loginUserinfo.getStatus() != 9) {
			throw new BadRequestException("비정상적인 요청입니다.");
		}
		
		model.addAttribute("userinfo", userinfoService.getUserinfo(userid));
		return "userinfo/user_modify";
	}
	
	//회원정보를 전달받아 USERINFO 테이블에 저장된 회원정보를 변경하고 회원정보를 출력하는 
	//페이지를 요청할 수 있는 URL 주소를 클라이언트에게 전달하여 응답 처리하는 요청 처리 메소드
	// => 회원정보를 출력하는 페이지 요청시 아이디 전달
	@RequestMapping(value = "/modify", method = RequestMethod.POST)
	public String modify(@ModelAttribute Userinfo userinfo, HttpSession session) throws UserinfoNotFoundException {
		userinfoService.modifyUserinfo(userinfo);
		
		Userinfo loginUserinfo=(Userinfo)session.getAttribute("loginUserinfo");
		//로그인 사용자와 변경 처리된 사용자가 동일한 경우
		if(loginUserinfo.getUserid().equals(userinfo.getUserid())) {
			//세션에 권한 관련 정보(회원정보)로 저장된 속성값 변경
			session.setAttribute("loginUserinfo", userinfoService.getUserinfo(userinfo.getUserid()));
		}
		
		return "redirect:/userinfo/view?userid="+userinfo.getUserid();
	}

	//아이디를 전달받아 USEINFO 테이블에 저장된 회원정보를 삭제하고 회원목록 출력페이지를
	//요청할 수 있는 URL 주소를 클라이언트에게 전달하여 응답 처리하는 요청 처리 메소드
	// => 비로그인 사용자 또는 관리자가 아닌 사용자가 페이지를 요청할 경우 인위적 예외 발생
	@RequestMapping("/remove")
	public String remove(@RequestParam String userid, HttpSession session) throws BadRequestException, UserinfoNotFoundException {
		Userinfo loginUserinfo=(Userinfo)session.getAttribute("loginUserinfo");
		if(loginUserinfo == null || loginUserinfo.getStatus() != 9) {
			throw new BadRequestException("비정상적인 요청입니다.");
		}
		
		userinfoService.removeUserinfo(userid);
		
		if(loginUserinfo.getUserid().equals(userid)) {
			return "redirect:/userinfo/logout";
		}
		
		return "redirect:/userinfo/list";
	}
...

 


ExceptionHandler 

 

컨트롤러 내의 요청 처리 메소드 외에 예외 처리 메소드(Exception Handle Method)를 이용하여 예외처리를 할 수 있다.

 

@ExceptionHandler

  • 메소드에 예외처리 기능을 제공하기 위한 어노테이션이다.
  • Controller 클래스의 요청 처리 메소드에서 예외가 발생되어 Front Controller에게 전달된 경우 예외 객체를 제공받아 예외처리하기 위한 메소드이다. (예외 처리 메소드)
    • 예외 처리 메소드는 매개변수를 이용하여 예외 처리에 필요한 객체를 제공받아 사용 가능하며 클라이언트에게 응답하기 위한 뷰이름을 반환한다. - 리다이렉트 이동 가능 
  • value 속성에 예외처리하기 위한 클래스(Class 객체)를 속성값으로 설정하면 된다.

 

예외 처리만 담당하는 컨트롤러(ExceptionController)를 따로 선언해 사용하는 것을 권장한다. 

(모든 Controller 클래스의 요청 처리 메소드에서 발생되는 예외를 전달받아 처리할 수 있기 때문)

 

 

예외처리만 담당하는 컨트롤러 만들기

 

@ControllerAdvice 

  • 예외 처리 메소드만 작성된 Controller 클래스를 Spring Bean으로 등록하기 위한 어노테이션이다.
  • 모든 Controller 클래스의 요청 처리 메소드에서 발생되어 전달된 예외를 제공받아 처리할 수 있다. 따라서 예외 처리 메소드들은 예외처리만 담당하는 컨트롤러를 따로 만들어서 작성해주는 것이 좋다. 

 

ExceptionController 

@ControllerAdvice
public class ExceptionController {
	@ExceptionHandler(value = BadRequestException.class)	
	public String badRequestExceptionHander() {
		return "userinfo/user_error";
	}
	
	@ExceptionHandler(value = ExistsUserinfoException.class)	
	public String existsUserinfoExceptionHander(ExistsUserinfoException exception, Model model) {
		model.addAttribute("message", exception.getMessage());
		model.addAttribute("userinfo", exception.getUserinfo());
		return "userinfo/user_write";
	}
	
	@ExceptionHandler(value = LoginAuthFailException.class)
	public String loginAuthFailExceptionHandler(LoginAuthFailException exception, Model model) {
		model.addAttribute("message", exception.getMessage());
		model.addAttribute("userid", exception.getUserid());
		return "userinfo/user_login";
	}
	
	@ExceptionHandler(value = UserinfoNotFoundException.class)
	public String userinfoNotFoundExceptionHandler() {
		return "userinfo/user_error";
	}
	
	/*
	모든 예외를 다 잡아주는 예외 처리 메소드
	@ExceptionHandler(value = Exception.class)	
	public String exceptionHander() {
		return "userinfo/user_error";
	}
	*/
}