framework/spring mvc 웹사이트제작법

[springMVC웹] 12. 암호화처리, 보안처리(권한처리), 예외처리하는 법

jeri 2024. 8. 5. 18:36
반응형

https://o5e2o5.tistory.com/222

  • 기존에 그냥 MVC패턴으로 만든 것을 springMVC를 이용해 다시 만들 것임
  • 기존에 만들었던 기능에 보안 처리 하는 방법, 예외 처리 하는 방법 추가할 것임

01. 테이블, DTO

🖤[테이블] USERINFO
desc userinfo
🖤[DTO] Userinfo.java
package xyz.itwill10.dto;

import lombok.Data;

//desc userinfo
/*
이름       널?       유형
-------- -------- -------------
USERID   NOT NULL VARCHAR2(100)
PASSWORD          VARCHAR2(100)
NAME              VARCHAR2(200)
EMAIL             VARCHAR2(300)
STATUS            NUMBER(1)
*/

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

02. Mapper바인딩

💛[Mapper] UserinfoMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "<https://mybatis.org/dtd/mybatis-3-mapper.dtd>">
<mapper namespace="xyz.itwill10.mapper.UserinfoMapper">

	<insert id="insertUserinfo">
		insert into userinfo values(#{userid},#{password},#{name},#{email},#{status})
	</insert>

	<!-- 전달값이 있을 경우 변경해라! - 동적 SQL -->
	<update id="updateUserinfo">
		update userinfo
		<set>
			<if test="password!=null and password!=''">
				password=#{password},
			</if>
			<if test="name!=null and name!=''">
				name=#{name},
			</if>
			<if test="email!=null and email!=''">
				email=#{email},
			</if>
			<if test="status==1 or status==9">
				status=#{status},
			</if>
		</set>
		where userid=#{userid}
	</update>

	<delete id="deleteUserinfo">
		delete from userinfo where userid=#{userid}
	</delete>

	<select id="selectUserinfo" resultType="Userinfo">
		select * from userinfo where userid=#{userid}
	</select>

	<select id="selectUserinfoList" resultType="Userinfo">
		select * from userinfo order by userid
	</select>

</mapper>
💛[Mapper] UserinfoMapper.java
package xyz.itwill10.mapper;

import java.util.List;

import xyz.itwill10.dto.Userinfo;

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

03. @Repository

🖤[DAO] (부모) UserinfoDAO.java
package xyz.itwill10.dao;

import java.util.List;

import xyz.itwill10.dto.Userinfo;

public interface UserinfoDAO {
	int insertUserinfo(Userinfo userinfo);
	int updateUserinfo(Userinfo userinfo);
	int deleteUserinfo(String userid);
	Userinfo selectUserinfo(String userid);
	List<Userinfo> selectUserinfoList();
}
🖤[DAO] (자식) UserinfoDAOImpl.java
package xyz.itwill10.dao;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;

import lombok.RequiredArgsConstructor;
import xyz.itwill10.dto.Userinfo;
import xyz.itwill10.mapper.UserinfoMapper;

@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 
	}

	@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();
	}

}

04. @Service

🌈 암호화 라이브러리 빌드처리

추가로 알면 좋은 라이브러리

🖤[Service] (부모) UserinfoService.java
package xyz.itwill10.service;

import java.util.List;

import xyz.itwill10.dto.Userinfo;
import xyz.itwill10.exception.ExistUserinfoException;
import xyz.itwill10.exception.LoginAuthFailExecption;
import xyz.itwill10.exception.UserinfoNotFoundException;

public interface UserinfoService {

	void addUserinfo(Userinfo userinfo) throws ExistUserinfoException;

	//해당하는 아이디의 회원정보를 검색했을 때 없을 경우 검색, 삭제, 변경이 안되므로 그거에 대한 예외처리 필요
	void modifyUserinfo(Userinfo userinfo) throws UserinfoNotFoundException;
	void removeUserinfo(String userid) throws UserinfoNotFoundException;
	Userinfo getUserinfo(String userid) throws UserinfoNotFoundException;

	List<Userinfo> getUserinfoList(); //예외를 만들어지 않아도 됨, 차라리 EL에서 empty 연산자 사용하기
    
	Userinfo loginAuth(Userinfo userinfo) throws LoginAuthFailException;
}
🖤[Service] (자식) UserinfoServiceImpl.java
  • 서비스 클래스의 메소드
    • 서비스 클래스의 메소드는 원래 더 복잡함!
    • 왜? 테이블 여러개 사용할 것이므로!!
    • 원래는 복잡하지만 우선은 테이블 하나만 이용해서 간단히 작성함!!
    • 실제 개발할 때와 다르니 주의
package xyz.itwill10.service;

import java.util.List;

import org.mindrot.jbcrypt.BCrypt;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import lombok.RequiredArgsConstructor;
import xyz.itwill10.dao.UserinfoDAO;
import xyz.itwill10.dto.Userinfo;
import xyz.itwill10.exception.ExistUserinfoException;
import xyz.itwill10.exception.LoginAuthFailException;
import xyz.itwill10.exception.UserinfoNotFoundException;

//🌈암호화 처리 기능을 사용하기 위한 방법
//=> Controller 클래스에서 만들어도 되지만, Service 클래스에서 만들어도 됨!

//step1.
//jbcrypt 라이브러리를 프로젝트에 빌드 처리 - 메이븐 : pm.xml
//[spring-security-core] [spring-security-web] [spring-security-config] 3개 빌드처리도 가능하지만,
//그러면 새 xml 파일 만들어야함ㅠㅠ

//step2.
//BCrypt.hashpw(String password, String salt)메소드를 호출하여 비밀번호의 암호화 처리
// => 매개변수로 비밀번호와 첨가물을 전달받아 암호화 처리 - 첨가물에 의해 비밀번호가 다르게 변환
// => salt(첨가물)에 의해 비밀번호가 싹 변경됨! salt를 알지 못하는 이상 암호화 알고리즘을 알아도 비밀번호를 절대 못알아냄
// => BCrypt 클래스 : 단방향 암호화 기능을 제공하는 BlowFish 알고리즘을 기반으로 설계된 암호화 처리 클래스 - 비밀번호를 저장할 목적으로 가장 많이 사용
// => BCrypt.gensalt(int log_bounds) : 첨가물(Salt - String)의 길이를 전달받아 첨가물을 생성하여 반환하는 메소드
// => 매개변수에 값을 전달하지 않을 경우 첨가물의 기본 길이는 [10]으로 자동 설정

//step3.
//BCrypt.checkpw(String plaintext, String hashed)로 암호화된 비밀번호를 비교하여 결과를 반환받아 저장하는 메소드
// => 매개변수로 일반 문자열(plaintext)과 암호화된 문자열(hashed)을 전달받아 비교하여 다른 경우 [false]를 반환하고
//같은 경우 [true]를 반환

//Service 클래스의 메소드는 데이타 처리 시 발생되는 문제에 대한 인위적 예외 발생
// => 발생된 예외는 Controller 클래스의 요청 처리 메소드에서 처리되도록 예외 전달
@Service
@RequiredArgsConstructor
public class UserinfoServiceImpl implements UserinfoService {

	private final UserinfoDAO userinfoDAO; //인젝션처리

	//addUserinfo - ExistUserinfoException 예외 전달
	//insert, delete, update 하는 명령어는 ROLLBACK 처리 필요하므로 반드시 @Transactional 설정하기!!
	@Transactional
	@Override
	public void addUserinfo(Userinfo userinfo) throws ExistUserinfoException {
		//전달받은 회원정보의 아이디가 기존 회원정보의 아이디와 중복된 경우
		if(userinfoDAO.selectUserinfo(userinfo.getUserid())!=null){
			//사용자 정의 예외 클래스로 인위적 예외 발생
			// => "예외를 명확하게 구분"하고 예외 처리 시 필요값을 저장하여 전달하기 위한 사용자 정의 예외클래스 작성
			// => Front Controller도 명확한 예외를 알 수 있음
			throw new ExistUserinfoException("이미 사용 중인 아이디를 입력 하였습니다.", userinfo);
		}

		//삽입 전 전달받은 회원정보의 비밀번호는 암호화 처리하여 필드값 저장
		// => 전달받은 회원정보의 비밀번호를 암호화 처리하여 필드값으로 변경하는 명령은 Controller 클래스의 요청 처리 메소드에서 작성 가능
		String hashedPassword = BCrypt.hashpw(userinfo.getPassword(),BCrypt.gensalt());
		userinfo.setPassword(hashedPassword); //암호화된 비밀번호로 필드값 변경

		userinfoDAO.insertUserinfo(userinfo); //삽입처리
	}

	//modifyUserinfo - UserinfoNotFoundException 예외 전달
	@Transactional
	@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); //변경처리
	}

	//removeUserinfo - UserinfoNotFoundException 예외 전달
	@Transactional
	@Override
	public void removeUserinfo(String userid) throws UserinfoNotFoundException {
		//전달받은 회원정보의 아이디로 기존 회원정보를 검색하여 검색결과가 없는 경우 - 즉, 삭제할 회원정보가 없다!!
		if(userinfoDAO.selectUserinfo(userid)==null) {
			throw new UserinfoNotFoundException("아이디의 회원정보가 존재하지 않습니다.");
		}
		userinfoDAO.deleteUserinfo(userid); //삭제처리
	}

	//getUserinfo - UserinfoNotFoundException 예외 전달
	//=> select를 전달하는 메소드에는 @Transactional 필요없음
  	//=> 왜? COMMIT, ROLLBACK 처리 필요없으므로!!
	@Override
	public Userinfo getUserinfo(String userid) throws UserinfoNotFoundException {
		//전달받은 아이디로 기존 회원정보를 검색하여 검색결과를 반환받아 저장
		Userinfo userinfo=userinfoDAO.selectUserinfo(userid);
		//검색된 회원정보가 없는 경우
		if(userinfo==null) {
			throw new UserinfoNotFoundException("아이디의 회원정보가 존재하지 않습니다.");
		}
		return userinfo;
	}

	//getUserinfoList - 예외 발생 딱히 없음.. 왜? 그냥 출력만 하는 메소드니까..
	@Override
	public List<Userinfo> getUserinfoList() {
		return userinfoDAO.selectUserinfoList();
	}

	//loginAuth - LoginAuthFailException 예외 전달
	//회원정보를 전달받아 인증 처리하기 위한 메소드
	// => 예외가 발생된 경우 [인증 실패]로 메소드 종료
	// => 예외가 발생되지 않은 경우 [인증 성공]으로 검색된 회원정보를 반환
	@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;
	}

}

 

05. @Controller

https://github.com/jaeheela/java-edu/blob/main/spring/src/main/java/xyz/itwill10/controller/UserinfoController.java

 

java-edu/spring/src/main/java/xyz/itwill10/controller/UserinfoController.java at main · jaeheela/java-edu

📝 [JAVA] java, oracle, mybatis, spring. Contribute to jaeheela/java-edu development by creating an account on GitHub.

github.com

🖤[Controller] UserinfoController.java
  • url 주소로 값을 전달하는 법
  • url 주소로 값을 전달받는 법
  • Front Controller 에 의해 호출되는 메소드
    • @RequestMapping : 요청 처리 메소드
    • @ExceptionHandler : 예외 처리 메소드
package xyz.itwill10.controller;

import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import lombok.RequiredArgsConstructor;
import xyz.itwill10.dto.Userinfo;
import xyz.itwill10.exception.ExistUserinfoException;
import xyz.itwill10.exception.LoginAuthFailExecption;
import xyz.itwill10.exception.UserinfoNotFoundException;
import xyz.itwill10.service.UserinfoService;

@Controller
@RequestMapping("/userinfo")
@RequiredArgsConstructor
public class UserinfoController {

	//필드 의존성 주입
	private final UserinfoService userinfoService;

🤍[GET] /userinfo/write 요청 - 권한(AdminAuthInterceptor) + 예외 없음

  • 권한 : 로그인 사용자 중 관리자만 요청 가능함
  • 예외 : 없음
	/*
	//회원등록을 위해 회원정보를 입력받기 위한 뷰이름을 반환하는 요청 처리 메소드
	// => 비로그인 사용자 또는 관리자가 아닌 사용자가 페이지를 요청한 경우 인위적 예외 발생
	// => 예외 처리 메소드에 의해 예외 처리 - 에러 메세지를 출력하는 JSP 문서로 포워드 이동하여 응답
	@RequestMapping(value = "/write", method = RequestMethod.GET)
	public String write(HttpSession session) throws Exception {
		//세션에 저장된 권한 관련 객체를 반환받아 저장
		Userinfo loginUserinfo=(Userinfo)session.getAttribute("loginUserinfo");
		//비로그인 사용자이거나 관리자가 아닌 경우
		if(loginUserinfo==null || loginUserinfo.getStatus()!=9) {
			throw new Exception("비정상적인 요청입니다.");
		}
		return "userinfo/user_write";
	}
	*/
	//회원등록을 위해 회원정보를 입력받기 위한 뷰이름을 반환하는 요청 처리 메소드
	// => 비로그인 사용자 또는 관리자가 아닌 사용자가 페이지 요청할 경우 권한 관련 인터셉터를 이용하여 처리
	// => 권한 관련 인터셉터를 이용할 경우 요청 처리 메소드에서 권한 관련 명령 미작성 가능
	@RequestMapping(value = "/write", method = RequestMethod.GET)
	public String write() {
		return "userinfo/user_write";
	}

🤍[POST] /userinfo/write 요청 - 권한(AdminAuthInterceptor) + 예외(ExistUserinfoException)

  • 권한 : 로그인 사용자 중 관리자만 요청 가능함
  • 예외 : 전달받은 아이디가 이미 존재하는 아이디라는 예외 발생의 가능성
	//=> 요청 처리 메소드에서는 예외 처리를 위해 앞으로 try~catch를 사용하지 않음!! 우리는 이제 예외처리메소드를 이용할 것임(ExceptionHandler)

	/*
	//회원정보를 전달받아 USERINFO 테이블에 삽입하고 로그인 페이지를 요청하기 위한 URL 주소를
	//클라이언트에게 전달하는 요청 처리 메소드
	// => UserinfoService 객체의 메소드 호출 시 예외 발생 가능 - try~catch 구문을 사용하여 예외 처리
	// => try ~ catch 구문을 쓰면 예외를 잡아서 어떻게 처리할 지 알려주지만,
	// => try ~ catch 구문을 쓰지 않고 예외를 전달하면 500 에러를 발생함
	@RequestMapping(value = "/write", method = RequestMethod.POST)
	public String write(@ModelAttribute Userinfo userinfo, Model model) {
		try {
			userinfoService.addUserinfo(userinfo);
		} catch (ExistUserinfoException e) {
			//뷰에서 출력하기 위해 ExistUserinfoException객체에 저장된 에러 메세지를 속성값으로 저장
			model.addAttribute("message", e.getMessage());

			//뷰에서 출력하기 위해 ExistUserinfoException객체에 저장된 회원정보(사용자입력값)을 속성값으로 저장
			model.addAttribute("userinfo", userinfo);

			//아이디 중복으로 예외가 발생된 경우 회원정보를 입력받기 위한 뷰이름을 반환
			return "userinfo/user_write"; //한마디로 현재페이지 새로고침 느낌..?!
		}
		return "redirect:/userinfo/login";
	}
	*/
    
    
	//회원정보를 전달받아 USERINFO 테이블에 삽입하고 로그인 페이지를 요청하기 위한 URL 주소를 클라이언트에게 전달하는 요청 처리 메소드
	// => UserinfoService 객체의 메소드 호출 시 예외 발생 가능 - Front Controller에게 예외 전달
	// => Front Controller는 전달받은 예외로 인해 500 에러코드 발생하여 클라이언트에게 전달
	// => Front Controller는 해당 예외에 대한 ExceptionHandler 기능을 제공하는 메소드가
	//작성된 경우 ExceptionHandler 기능의 메소드를 호출하여 예외 처리 가능
	@RequestMapping(value = "/write", method = RequestMethod.POST)
	public String write(@ModelAttribute Userinfo userinfo) throws ExistUserinfoException {
		userinfoService.addUserinfo(userinfo);
		return "redirect:/userinfo/login";
	}

🤍[GET] /userinfo/login 요청 - 권한 없음 + 예외 없음

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

🤍[POST] /userinfo/login 요청 - 권한 없음 + 예외(LoginAuthFailException)

  • 권한 : 없음
  • 예외 : 전달받은 아이디가 존재하지 않는 아이디라는 예외 발생의 가능성
	//인증정보를 전달받아 로그인 처리 후 환영 메세지를 출력하는 뷰이름을 반환하는 요청 처리 메소드
	@RequestMapping(value = "/login", method = RequestMethod.POST)
	public String login(@ModelAttribute Userinfo userinfo, HttpSession session) throws LoginAuthFailException {
		//인증 실패시 LoginAuthFailException 발생하고 인증 성공시 검색된 회원정보 반환받아 저장
		Userinfo authUserinfo=userinfoService.loginAuth(userinfo);

		//세션에 권한 관련 정보를 속성값으로 저장
		session.setAttribute("loginUserinfo", authUserinfo);

		return "userinfo/user_login";
	}

🤍/userinfo/list 요청 - 권한(LoginAuthInterceptor) + 예외 없음

  • 권한 : 로그인 사용자만 요청 가능함
  • 예외 : 없음
	/*
	//[핵심관심코드] : USERINFO 테이블에 저장된 모든 회원정보를 검색하여 속성값으로 저장하여 회원목록을 출력
	//하는 뷰이름을 반환하는 요청 처리 메소드
    
	//[횡단관심코드 - Interceptor클래스] : 비로그인 사용자가 페이지를 요청한 경우 인위적 예외 발생 - 예외 처리 메소드에 의해 예외 처리
	@RequestMapping("/list")
	public String list(Model model, HttpSession session) throws Exception {
		Userinfo loginUserinfo=(Userinfo)session.getAttribute("loginUserinfo");
		if(loginUserinfo==null) {//비로그인 사용자가 페이지를 요청한 경우
			throw new Exception("비정상적인 요청입니다.");//인위적 예외 발생
		}

		model.addAttribute("userinfoList", userinfoService.getUserinfoList());

		return "userinfo/user_list";
	}
	*/

	//USERINFO 테이블에 저장된 모든 회원정보를 검색하여 속성값으로 저장하여 회원목록을 출력하는 뷰이름을 반환하는 요청 처리 메소드
	// => 비로그인 사용자가 페이지를 요청할 경우 권한 관련 인터셉터를 이용하여 처리
	@RequestMapping("/list")
	public String list(Model model) {
		model.addAttribute("userinfoList", userinfoService.getUserinfoList());
		return "userinfo/user_list";
	}

🤍/userinfo/view 요청 - 권한(LoginAuthInterceptor) + 예외(UserinfoNotFoundException)

  • 권한 : 로그인 사용자만 요청 가능함
  • 예외 : 전달받은 아이디가 존재하지 않는 아이디라는 예외 발생의 가능성
	//아이디를 전달받아 USERINFO 테이블에 저장된 해당 아이디의 회원정보를 검색하여 속성값으로
	//저장하여 회원정보를 출력하는 뷰이름을 반환하는 요청 처리 메소드
	// => 비로그인 사용자가 페이지를 요청할 경우 권한 관련 인터셉터를 이용하여 처리
	@RequestMapping("/view")
	public String view(@RequestParam String userid, Model model) throws UserinfoNotFoundException {
		model.addAttribute("userinfo", userinfoService.getUserinfo(userid));
		return "userinfo/user_view";
	}

 

🤍[GET] /userinfo/modify 요청 - 권한(AdminAuthInterceptor) + 예외(UserinfoNotFoundException)

  • 권한 : 로그인 사용자 중 관리자만 요청 가능함
  • 예외 : 전달받은 아이디가 존재하지 않는 아이디라는 예외 발생의 가능성
	//아이디를 전달받아 USERINFO 테이블에 저장된 해당 아이디의 회원정보를 검색하여 속성값으로
	//저장하여 변경할 회원정보를 입력받기 위한 뷰이름을 반환하는 요청 처리 메소드
	// => 비로그인 사용자 또는 관리자가 아닌 사용자가 페이지 요청할 경우 권한 관련 인터셉터를 이용하여 처리
	@RequestMapping(value = "/modify", method = RequestMethod.GET)
	public String modify(@RequestParam String userid, Model model) throws UserinfoNotFoundException {
		model.addAttribute("userinfo", userinfoService.getUserinfo(userid));
		return "userinfo/user_modify";
	}

 

🤍[POST] /userinfo/modify 요청 - 권한(AdminAuthInterceptor) + 예외(UserinfoNotFoundException)

  • 권한 : 로그인 사용자 중 관리자만 요청 가능함
  • 예외 : 전달받은 아이디가 존재하지 않는 아이디라는 예외 발생의 가능성
	//회원정보를 전달받아 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/user_view?userid="+userinfo.getUserid();
	}

🤍[POST] /userinfo/remove 요청 - 권한() + 예외(UserinfoNotFoundException)

  • 권한 : 로그인 사용자 중 관리자만 요청 가능함
  • 예외 : 전달받은 아이디가 존재하지 않는 아이디라는 예외 발생의 가능성
	//아이디를 전달받아 USERINFO 테이블에 저장된 해당 아이디의 회원정보를 삭제하고 회원목록을
	//출력하는 페이지를 요청하기 위한 URL 주소를 클라이언트에게 전달하는 요청 처리 메소드
	// => 비로그인 사용자 또는 관리자가 아닌 사용자가 페이지 요청할 경우 권한 관련 인터셉터를 이용하여 처리
	@RequestMapping("/remove")
	public String remove(@RequestParam String userid, HttpSession session) throws UserinfoNotFoundException {
		userinfoService.removeUserinfo(userid);

		Userinfo loginUserinfo = (Userinfo)session.getAttribute("loginUserinfo");
		//로그인 사용자가 삭제된 경우
		if(loginUserinfo.getUserid().equals(userid)) {
			return "redirect:userinfo/logout";
		}

		return "redirect:userinfo/list";
	}

🤍 /userinfo/logout 요청 - 권한(LoginAuthInterceptor) + 예외 없음

  • 권한 : 로그인 사용자만 요청 가능함
  • 예외 : 없음
	//로그아웃 처리 후 로그인 페이지를 요청하기 위한 URL 주소를 클라이언트에게 전달하는 요청 처리 메소드
	@RequestMapping("/logout")
	public String login(HttpSession session) {
		//session.removeAttribute("loginUserinfo");
		session.invalidate();

		return "redirect:/userinfo/login";
	}

🤍 예외 처리 메소드 (ExceptionHandler Method)

  • 일반적으로 메세지를 출력하게 예외 처리 메소드 작성함
  • 예외 처리 메소드가 있기 때문에 요청 처리 메소드에서 try ~ catch 구문을 쓸 필요가 없고, 그냥 메소드만 호출해서 사용
  • 만약 요청 처리 메소드에서 예외가 발생한다면?? 예외를 전달하여 Front Controller가 예외를 호출해 알아서 처리할 수 있도록 메소드만 잘 작성해두기
  • 예외처리는 try ~ catch로 절대 하지 않고, ExceptionHandler 이용할 것임
	//예외 처리 메소드
	//=> 주의) 작성 순서도 중요함 ExistUserinfoException -> -> ... -> Exception
	// => Exception 예외는 try~catch 처럼 가장 마지막에 작성해야함 - 왜? 모든 예외를 다 잡으니까!!

	//@ExceptionHandler : Controller 클래스의 메소드에 예외 처리 기능을 제공하도록 설정하는 어노테이션
	// => Controller 클래스의 요청 처리 메소드에서 예외가 발생되어 Front Controller에게 전달된 경우 예외 관련 객체를 제공받아 예외 처리하기 위한 메소드 - ExceptionHandler Method
    
	//value 속성 : 예외 처리하기 위한 클래스(Class 객체)를 속성값으로 설정
	// => 다른 속성이 없는 경우 속성값만 설정 가능
    
	//예외 처리 메소드에서 예외 처리를 위해 필요한 객체를 매개변수로 전달받아 사용 가능하며 뷰이름을 반환해 JSP 문서로 응답 처리 가능 - 리다이렉트 이동 가능
   
	@ExceptionHandler(value = ExistUserinfoException.class) //ExistUserinfoException 클래스에서 처리할게!
	public String userinfoExceptionHandler(ExistUserinfoException exception, Model model) {
		model.addAttribute("message", exception.getMessage());  //저장해서 user_write.jsp로 보낼게
		model.addAttribute("userinfo", exception.getUserinfo());
		return "userinfo/user_write";
	}

	@ExceptionHandler(LoginAuthFailExecption.class)
	public String userinfoExceptionHandler(LoginAuthFailException exception, Model model) {
		model.addAttribute("message", exception.getMessage());
		model.addAttribute("userid",exception.getUserid());
		return "userinfo/user_login";
	}

	@ExceptionHandler(UserinfoNotFoundException.class)
	public String userinfoExceptionHandler(UserinfoNotFoundException exception) {
		return "userinfo/user_error";
	}

	/*
	@ExceptionHandler(value = Exception.class) //Exception 클래스에서 처리할게! (모든 예외를 다 잡을 예정)
	public String userinfoExceptionHandler() {
		return "userinfo/user_error";
	}
	*/

}

06. VIEW

💚[JSP] 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>"%>
<!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>
💚[JSP] user_login.jsp - 로그인 입력페이지
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="<http://java.sun.com/jsp/jstl/core>"%>
<!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 userLogin() {
	if ( f.userid.value == "" ) {
		alert("아이디를 입력하십시요.");
		f.userid.focus();
		return;
	}
	if ( f.password.value == "" ) {
		alert("비밀번호를 입력하십시요.");
		f.password.focus();
		return;
	}

	f.action = "<c:url value="/userinfo/login"/>";
	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>
		  	<!--contents-->
			<table width=590 border=0 cellpadding=0 cellspacing=0>
				<tr>
					<td bgcolor="f4f4f4" height="22">&nbsp;&nbsp;<b>회원관리 - 로그인</b></td>
				</tr>
			</table>
			<br>
		  	<c:choose>
			  	<c:when test="${empty(loginUserinfo) }"><%-- 비로그인 사용자인 경우 --%>
					<!-- login Form  -->
					<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="${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">
							</td>
						</tr>
					</table>
					</form>
					<br>
					<table width=590 border=0 cellpadding=0 cellspacing=0>
						<tr>
							<td align=center>
								<input type="button" value="로그인" onClick="userLogin();"> &nbsp;
							</td>
						</tr>
					</table>
				</c:when>
				<c:otherwise><%-- 로그인 사용자인 경우 --%>
					<table border="0" cellpadding="0" cellspacing="1" width="590" bgcolor="BBBBBB">
						<tr>
							<td align=center bgcolor="E6ECDE" height="22">
								${loginUserinfo.name }님, 환영합니다.
							</td>
						</tr>
					</table>
					<br>
					<table width=590 border=0 cellpadding=0 cellspacing=0>
						<tr>
							<td align=center>
								<button type="button" onclick="location.href='<c:url value="/userinfo/list"/>';">회원목록</button>
								<button type="button" onclick="location.href='<c:url value="/userinfo/logout"/>';">로그아웃</button>
								<c:if test="${loginUserinfo.status == 9 }">
									<button type="button" onclick="location.href='<c:url value="/userinfo/write"/>';">회원등록</button>
								</c:if>
							</td>
						</tr>
					</table>
				</c:otherwise>
			</c:choose>
		</td>
	</tr>
</table>
</body>
</html>
💚[JSP] user_list.jsp - 회원목록 출력페이지
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="<http://java.sun.com/jsp/jstl/core>"%>
<!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">
</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>
	  	<table width=590 border=0 cellpadding=0 cellspacing=0>
		  	<tr>
				<td bgcolor="f4f4f4" height="22">&nbsp;&nbsp;<b>회원관리 - 회원목록</b></td>
		  	</tr>
	  	</table>
	  	<br>

	  	<table border="0" cellpadding="0" cellspacing="1" width="590" bgcolor="BBBBBB">
		  	<tr>
				<td width=190 align=center bgcolor="E6ECDE" height="22">아이디</td>
				<td width=200 align=center bgcolor="E6ECDE">이름</td>
				<td width=200 align=center bgcolor="E6ECDE">이메일</td>
		  	</tr>

		  	<c:forEach var="userinfo" items="${userinfoList }">
			  	<tr>
					<td width=190 align=center bgcolor="ffffff" height="20">
						${userinfo.userid }
					</td>
					<td width=200 align=center bgcolor="ffffff">
						<a href="<c:url value="/userinfo/view"/>?userid=${userinfo.userid }" class="user">
							${userinfo.name }
						</a>
					</td>
					<td width=200 align=center bgcolor="ffffff">
						${userinfo.email }
					</td>
			  	</tr>
		  	</c:forEach>
	  	</table>

		<br>
	  	<table border="0" cellpadding="0" cellspacing="1" width="590">
			<tr>
				<td align="right">
					<c:if test="${loginUserinfo.status == 9 }">
						<input type="button" value="회원등록" onclick="location.href='<c:url value="/userinfo/write"/>';"/>
					</c:if>
					<input type="button" value="로그아웃" onclick="location.href='<c:url value="/userinfo/logout"/>';"/>
				</td>
			</tr>
		</table>
	</td>
</tr>
</table>
</body>
</html>
💚[JSP] user_view.jsp - 회원정보 출력페이지
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="<http://java.sun.com/jsp/jstl/core>"%>
<!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 userRemove(userid) {
	if (confirm("정말로 삭제 하시겠습니까?") ) {
		location.href='<c:url value="/userinfo/remove"/>?userid='+userid;
	}
}
</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>
	  <table width=590 border=0 cellpadding=0 cellspacing=0>
		  <tr>
			<td bgcolor="f4f4f4" height="22">&nbsp;&nbsp;<b>회원관리 - 회원정보</b></td>
		  </tr>
	  </table>
	  <br>

	  <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;">
				${userinfo.userid }
			</td>
		  </tr>
		  <tr>
			<td width=100 align=center bgcolor="E6ECDE" height="22">이름</td>
			<td width=490 bgcolor="ffffff"  style="padding-left:10px;">
				${userinfo.name }
			</td>
		  </tr>
		  <tr>
			<td width=100 align=center bgcolor="E6ECDE" height="22">이메일</td>
			<td width=490 bgcolor="ffffff"  style="padding-left:10px;">
				${userinfo.email }
			</td>
		  </tr>
	  </table>
	  <br>

	  <table width=590 border=0 cellpadding=0 cellspacing=0>
		  <tr>
			<td align=center>
			<c:if test="${loginUserinfo.status == 9 }">
				<input type="button" value="수정" onClick="location.href='<c:url value="/userinfo/modify"/>?userid=${userinfo.userid}';">
				<input type="button" value="삭제" onClick="userRemove('${userinfo.userid}');">
			</c:if>
			<input type="button" value="목록" onClick="location.href='<c:url value="/userinfo/list"/>';">
			</td>
		  </tr>
	  </table>

	  </td>
	</tr>
</table>
</body>
</html>
💚[JSP] user_modify.jsp - 회원정보 수정페이지
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="<http://java.sun.com/jsp/jstl/core>"%>

<!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 userModify() {
	if ( f.name.value == "" ) {
		alert("이름을 입력하십시요.");
		f.name.focus();
		return false;
	}
	f.action = "<c:url value="/userinfo/modify"/>";
	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>
	  <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">
	  <input type="hidden" name="userid" value="${userinfo.userid }">
	  <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;">
				${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">
				<span style="color: red;">** 비밀번호를 변경하지 않을 경우 입력하지 마세요. **</span>
			</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="userModify();">
			<input type="button" value="목록" onClick="location.href='<c:url value="/userinfo/list"/>';">
			</td>
		  </tr>
	  </table>

	  </td>
	</tr>
</table>

</body>
</html>
💚[JSP] user_error.jsp - 에러페이지
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="<http://java.sun.com/jsp/jstl/core>"%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SPRING</title>
<style type="text/css">
body {
	text-align: center;
}
.message {
	color: red;
	font-size: 1.5em;
}
</style>
</head>
<body>
	<h1>에러페이지</h1>
	<hr>
	<p class="message">프로그램 실행에 예기치 못한 오류가 발생 하였거나 비정상적 방법으로
	프로그램을 요청하여 오류가 발생 하였습니다.</p>
	<button type="button" onclick="location.href='<c:url value="/userinfo/login"/>';">로그인 페이지 이동</button>
</body>
</html>
반응형