Day 88

ChangWoo·2023년 1월 6일
0

중앙 HTA

목록 보기
32/51
post-thumbnail

스프링 컨테이너와 의존성 주입

첫 번째 스프링 컨테이너 (XmlWebApplicationContext)

컨트롤러 객체

  • 사용자의 요청을 처리
  • 사용자에게 데이터를 제공
  • 서비스 객체를 의존한다.
    web-context.xml
<context:component-scan base-package="com.sample.web />
- com.sample.web 패키지 및 그 하위 패키지에서 @Controller, @ControllerAdvice, @RestController, @RestControllerAdvice, @Repository, @Service, @Configuration, @Component 등의 어노테이션이 부착된 클래스를 전부 스캔해서 객체 생성

두 번째 스프링 컨테이너 (XmlWebApplicationContext)

서비스 객체

  • 업무로직 수행
  • 매퍼객체를 의존한다.
    service-context.xml
<context:component-scan base-package="com.sample.service />
- com.sample.service 패키지 및 그 하위 패키지에서 @Controller, @ControllerAdvice, @RestController, @RestControllerAdvice, @Repository, @Service, @Configuration, @Component 등의 어노테이션이 부착된 클래스를 전부 스캔해서 객체 생성

매퍼객체

  • 데이터 베이스 엑세스 수행
  • SqlSessionFactory를 의존한다.
    database-context.xml
<bean id="dataSource" class="DriverManagerDataSource">
<bean id="sqlSessionFactory" class="SqlSessionFactoryBean">
<mybatis-spring:scan base-package="com.sample.mapper />
- com.sample.mapper 패키지의 모든 매퍼 인터페이스를 스캔해서 인터페이스를 구현한 매퍼 인스턴스(인스턴스 구현객체)를 생성하고 스프링의 빈으로 등록시킨다.

DriverManagerDataSource

  • 데이터베이스와 연결된 Connection을 관리 제공

SqlSessionFactory

  • SqlSession 제공
  • DriverManagerDataSource을 의존한다.

MapperScannerConfigurer

  • 매퍼 인터페이스를 구현한 매퍼 객체를 생성하고 스프링 컨테이너에 등록
  • SqlSessionFactory를 의존한다.
  • 컨트롤러 / 서비스 / 매퍼는 스프링 컨테이너가 "스캔" 이라는 작업을 통해서 설정정보를 읽어와서 의존성 정보를 주입해서 조립까지 해준다.
  • 의존성 주입 = @Autowired와 같은 어노테이션을 통해 의존성 정보를 주입한다.(=주소값을 가지고 온다.)
  • 자신의 스프링 컨테이너에 필요한 객체가 없다면, 부모 스프링 컨테이너에 가서 찾아 가지고 온다.
  • 별개의 컨테이너이기 때문에 다 싱글턴 객체다.

MVC

  • /register 요청이 오면 TomCat은 요청객체 / 응답객체를 생성한다.

  • DispathcerServlet

    • 첫 번째 요청
      • 요청객체와 응답객체가 전달된다.
      • Service 메소드가 생성된다.
      • HandlerMapping에게 URL을 보내 어떤 컨트롤러를 사용해야 할지 물어본다.
    • 두번째 요청
      • HandlerAdapter에게 컨트롤러 실행을 위임한다.
    • 세번째 요청
      • ViewResolver에게 "redirect:success"를 전달한다.
    • 네번째 요청
      • RedirectView에게 뷰의 render를 실행한다.
  • HandlerMapping

    • 요청 URL(/register)과 매핑되는 컨트롤러를 검색한다.
    • 컨트롤러를 DispatcherServlet에게 반환해준다.
  • HandlerAdapter

    • ModelAndView를 DispatcherServlet에게 반환한다.

    • 전처리 작업을 수행한다.

    • 전처리 작업 : 요청핸들러 메소드의 매개변수 분석

      • UserRegisterForm 객체를 생성한다.
      • UserRegisterForm 객체의 멤버변수(프로퍼티)를 분석한다.
      • 요청파라미터에서 멤버변수명과 동일한 이름의 값을 조회한다.
      • 조회된 요청파라미터값을 UserRegisterForm 객체의 변수에 저장한다.
      • 요청핸들러 메소드를 실행할 때 요청파라미터값이 저장된 UserRegisterForm 객체를 매개변수로 전달한다.
    • 후처리 작업을 수행한다.

    • 후처리 작업 : ModelAndView 객체를 생성하고 반환한다.

      • 요청핸들러 메소드의 반환값, 매개변수를 분석해서 ModelAndView객체를 생성한다.
      • ModelAndView 객체의 model, view, viewName에 값을 설정하고, DispatcherServlet에 반환한다.
  • ViewResolver

    • 뷰이름을 분석해서 적절한 적절한 뷰 객체를 반환한다.
    • DisptcherServlet에게 View객체를 반환한다.
  • RedirectView

    • 재요청 URL "success"를 재요청 URL 응답으로 보낸다.

회원가입 기능

success.jsp
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
<title>애플리케이션</title>
</head>
<body>
<c:set var="menu" value="register" />
<%@ include file="common/navbar.jsp" %>
<div class="container">
	<div class="row mb-3">
		<div class="col-12">
			<div class="border p-3 bg-light">
				<h1 class="mb-4">회원가입 완료</h1>
				<p>회원가입이 완료되었습니다.</p>
			</div>
		</div>
	</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
</body>
</html>
HomeController
@GetMapping("/success")
	public String success() {
		return "success";
	}

실행결과

로그인 기능

Homecontroller

	/*
	 * 값이 적기 때문에 하나씩 적어준다. (id와 패스워드)
	 * 요청핸들러 메소드의 매개변수가 기본자료형 혹은 String형인 경우,
	 * 		- 매개변수의 이름과 동일한 이름으로 요청파라미터값을 조회해서 매개변수로 전달한다.(input박스 이름과 똑같아야 한다!)
	 * 		- 매개변수의 타입이 기본자료형 타입인 경우, 해당 타입으로 형변환해서 전달한다.(int로 설정시 글자가 와도 숫자로 변경해준다.)
	 * 		- 매개변수의 타입이 기본자료형(정수, 실수, 문자, 불린)일 때, 
	 * 		  요청파라미터값이 존재하지 않으면 오류가 발생한다.
	 * 		  요청파라미터값을 해당 타입으로 변환할 수 없을 때 오류가 발생한다.
	 * @RequestParam
	 * 		요청파라미터값을 요청핸들러의 매개변수와 매핑시키는 어노테이션이다.
	 * 		주요 속성
	 * 			name			: 요청파라미터의 이름을 지정한다.
	 * 			required		: 기본값은 true다. false로 지정하면 name에 지정한 요청파라미터값이 없어도 오류가 발생하지 않는다.
	 * 			defaultValue	: name에 지정한 요청파라미터값이 존재하지 않을 때 매개변수로 대입되는 기본값을 설정한다.
	 * 							  defaultValue의 값은 문자열로 설정되지만 매개변수로 대입될 대는 해당 타입으로 형변환된다.
	 * 		예시
	 * 		page / rows / sort가 와야해! 그런데 없으면 1 / 10 / date가 될거야! (무조건 있어야 하는 값은 사용하지 않고 있어도 되고 없어도 되는 값에만 사용!)
	 * 			public String list(@RequestParam(name = "page", required = false, defaultValue = "1") int page,
	 * 								@RequestParam(name = "rows", required = false, defaultValue = "10") int rows,
	 * 								@RequestParam(name = "sort", "required = false, defaultValue = "date") String sort,
	 * 								String opt,
	 * 								String keyword)
	 * 
	 * 요청핸들러 메소드의 매개변수로 가능한 객체 및 어노테인션
	 * 		HttpServletRequest		요청객체
	 * 		HttpServletResponse		응답객체
	 * 		HttpSession				세션객체
	 * 		WebRequest				Spring이 제공하는 객체다. / 요청객체가 가지고 있는 정보 대부분을 제공하는 객체다.
	 * 		TimeZone				시간정보
	 * 		Locale					지역정보(국가, 언어)
	 * 		InputStream				클라이언트와 연결된 읽기 전용 스트림
	 * 		OutputStrean			클라이언트와 연결된 쓰기 전용 스트림
	 * 		Reader					클라이언트와 연결된 텍스트 읽기 전용 스트림
	 * 		Writer					클라이언트와 연결된 텍스트 쓰기 전용 스트림
	 * 		@RequestParam			요청파라미터와 매개변수를 매핑시키는 어노테이션
	 * 		@PathVariable			요청 URL 경로에 포함된 파라미터값과 매개변수를 매핑시키는 어노테이션
	 * 		@ModelAttribute			요청파라미터와 해당값을 저장하는 객체를 매핑시키는 어노테이션
	 * 		@RequestBody			요청메세지의 바디부 정보와 매개변수를 매핑시키는 어노테이션
	 * 		@Valid					요청파라미터값의 유효성 여부를 검증시키는 어노테이션
	 * 		Model					뷰에 전달할 정보를 저장하는 객체
	 * 		Errors					요청파라미터값의 유효성 검증 결과를 저장하는 객체
	 * 		BindingResult			요청파라미터값의 유효성 검증 결과를 저장하는 객체
	 * 		SessionStatus			세션에 저장된 정보를 삭제하는 객체
	 * 		기본자료형					요청파라미터값을 전달받는다.
	 * 		String					요청파라미터값을 전달받는다.
	 * 		사용자정의 객체				요청파라미터값을 전달받는다.
	 */
	@PostMapping("/login")
	public String login(String id, String password, HttpSession session) {
		
		User user = userService.login(id, password);
		session.setAttribute("loginUser", user);
		
		return "redirect:home";
	}
login-form.jsp

<script type="text/javascript">
$(function() {
	$("#form-register").submit(function() {
		let id = $("#form-register :input[name=id]").val();
		let password = $("#form-register :input[name=password]").val();
		
		if (id == "") {
			alert("아이디는 필수입력값입니다.");
			return false;
		}
		if (password == "") {
			alert("비밀번호는 필수입력값입니다.");
			return false;
		}
		return true;
	})
})
</script>
UserService.java

	/*
	* Controller의 요청파라미터와는 달리 매개변수와 다른 이름을 사용해도 상관없다!
	*/
	public User login(String userId, String password) {
		User savedUser = userMapper.getUserById(userId);
		if (savedUser == null) {
		throw new ApplicationException("아이디 혹은 비밀번호가 올바르지 않습니다.");
		}
		if ("Y".equals(savedUser.getDeleted())) {
			throw new ApplicationException("탈퇴처리된 사용자 계정으로 로그인할 수 없습니다.");
		}
		if (!savedUser.getPassword().equals(password)) {
			throw new ApplicationException("아이디 혹은 비밀번호가 올바르지 않습니다.");
		}
		return savedUser;
	}
navbar.jsp

<c:if test="${not empty loginUser }">
			<span class="navbar-text"><strong class="text-white">${loginUser.name }</strong>님 환영합니다.</span>
		</c:if>
		<ul class="navbar-nav">
		    <c:choose>
				<c:when test="${not empty loginUser }">
					<li class="nav-item"><a class="nav-link" href="/logout">로그아웃</a></li>
				</c:when>
				<c:otherwise>
					<li class="nav-item"><a class="nav-link ${menu eq 'login' ? 'active' : '' }" href="/login">로그인</a></li>
					<li class="nav-item"><a class="nav-link ${menu eq 'register' ? 'active' : '' }" href="/register">회원가입</a></li>
				</c:otherwise>
			</c:choose>

실행결과 (로그인 전)

실행결과 (없는 사용자로 로그인 시)

실행결과 (로그인 시)

  • 이 기능들을 실행하기 위해서는 로그인이 필요하다.
  • 조회 = GetMapping
  • 변경 = PostMapping

  • TomCat이 제공해주는 객체를 안쓰려고 한다.
  • 그런데, 사용자 정보를 가지고 오지 못하므로 새로운 Util을 만들어 지정해준다.
SessionUtil
package com.sample.utils;

import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

/**
 * HttpSession 객체에 속성을 저장하고, 삭제하는 기능이 제공되는 유틸리티 클래스다.
 * @author lee_e
 *
 */
public class SessionUtils {

	/**
	 * HttpSession객체에 속성을 추가한다.
	 * @param name 속성명
	 * @param value 속성값(객체)
	 */
	public static void setAttribute(String name, Object value) {
		getRequestAttributes().setAttribute(name, value, RequestAttributes.SCOPE_SESSION);
	}
	
	/**
	 * HttpSession객체서 지정된 속성을 삭제한다.
	 * @param name 속성명
	 */
	public static void removeAttribute(String name) {
		getRequestAttributes().removeAttribute(name, RequestAttributes.SCOPE_SESSION);
	}
	
	/**
	    * HttpSession 객체에서 지정된 속성을 반환한다.
	    * @param name 속성명
	    * @return 속성값(객체)
	    */
	   public static Object getAttribute(String name) {
	      return getRequestAttributes().getAttribute(name, RequestAttributes.SCOPE_SESSION);
	   }
	
	private static RequestAttributes getRequestAttributes() {
		return RequestContextHolder.getRequestAttributes();
	}
}
  • RequestContextHolder의 RequestAttributes : 지금 현재 요청 정보가 들어있는 객체를 반환한다. (요청객체와 세셕객체의 속성을 삭제,조회,변경 / name과 value를 지정할 수 있다.)
HomeController
@PostMapping("/login")
	public String login(String id, String password) {
		
		User user = userService.login(id, password);
		// HttpSession 객체에 속성으로 로그인 절차가 완료된 사용자 정보를 저장한다.
		SessionUtils.setAttribute("loginUser", user);
		
		return "redirect:home";
	}
  • Util을 통해 접근하기 때문에 HttpSession이 더 이상 필요없게 된다.

로그아웃 기능

HomeController

	/*
	 * 요청 URL 매핑하기
	 * 	요청URL과 요청핸들러 메소드를 매핑시키는 어노테이션
	 * 		@RequestMapping : 요청방식에 상관없이 요청URL을 기준으로 매핑시킨다.
	 * 		@GetMapping		: 요청방식이 GET 방식이고 요청 URL이 일치하는 요청핸들러 메소드와 매핑시킨다.
	 * 		@PostMapping	: 요청방식이 POST 방식이고 요청 URL이 일치하는 요청핸들러 메소드와 매핑시킨다. 
	 * 		@PutMapping		: 요청방식이 PUT 방식이고 요청 URL이 일치하는 요청핸들러 메소드와 매핑시킨다.
	 * 		@DeleteMapping	: 요청방식이 DELETE 방식이고 요청 URL이 일치하는 요청핸들러 메소드와 매핑시킨다.
	 * 
	 * 요청방식
	 * 		GET		: 서버에서 정보를 조회하는 요청
	 * 		POST	: 서버에 정보를 추가하는 요청
	 * 		PUT		: 서버의 정보를 변경하는 요청
	 * 		DELETE	: 서버의 정보를 삭제하는 요청
	 * * 일반적인 웹 애플리케이션에서는 GET, POST 두가지 방식을 사용한다.
	 * * REST 방식의 웹 어플리케이션에서는 GET, POST, PUT, DELETE 방식을 전부 사용한다.
	 */
	@RequestMapping("/logout")
	public String logout() {
		// HttpSession객체에서 로그인된 사용자 정보를 삭제한다.
		SessionUtils.removeAttribute("loginUser");
		
		return "redirect:home";
	}

  • REST방식에서는 json을 많이 사용한다.

실행결과 (로그아웃 전)

실행결과 (로그아웃 후)

기존과의 차이점

  • Util을 사용하여 HttpSession을 적지 않아도 된다. (=HttpSession에서 값을 가지고 오지 않아도 RequestContextHolder를 통해 Sessino객체에 값을 주고 / 가지고 올 수 있게 되었다.)

자바스크립트 변수의 차이

자바스크립트의 변수

	var 
		--------------------------------------------------------------------------------------------------------------------------
		변수의 범위가 함수다. (y와 z가 블록 안에서만 아닌, 함수에서 적용된다. 그래서 블록 밖에서도 사용 가능하다.)
		--------------------------------------------------------------------------------------------------------------------------
		function a() {
			var x = 10;
			if (x > 5) {
				var y = 20;
				var z = x*y;
				console.log(x, y, z);	// 10, 20, 200 출력된다.
			}
			console.log(x, y, z);		// 10, 20, 200 출력된다.
		}

		--------------------------------------------------------------------------------------------------------------------------
		변수 호이스팅(변수 끌어올리기)이 적용된다
		--------------------------------------------------------------------------------------------------------------------------
		function a() {
			console.log(x, y, z); // 오류가 발생하지 않는다 undefined, undefined, undefined가 출력된다.
			var x = 10;
			if (x > 5) {
				var y = 20;
				var z = x*y;
				console.log(x, y, z);	
			}
			console.log(x, y, z);	
		}
		// 자바스크립트 컴파일러는 위의 소스코드를 아래와 같이 변경한다.
		function a() {
			var x, y, z;	// 함수내에서 선언된 모든 변수의 선언을 함수의 첫번째 라인으로 끌어올린다.
			console.log(x, y, z);

			x = 10;
			if (x > 5) {
				y = 20;
				z = x*y;
				console.log(x, y, z);	
			}
			console.log(x, y, z);	
		}
		--------------------------------------------------------------------------------------------------------------------------
		변수명이 중복되어도 오류가 발생하지 않는다.
		--------------------------------------------------------------------------------------------------------------------------
		function x() {
    		var x = 10;
    		console.log(x);	// 10이 출력된다.

    		var x = 20;
    		console.log(x);	// 20이 출력된다.
			}

	let
		--------------------------------------------------------------------------------------------------------------------------
		변수의 범위가 블록이다. (블록 안에서 실행된 함수는 블록 안에서 사라진다. / 블록 밖에서 사용할 수 없다.)
		--------------------------------------------------------------------------------------------------------------------------
		function a() {
			let x = 10;
			if (x > 5) {
				let y = 20;
				let z = x*y;
				console.log(x, y, z);	// 10, 20, 200 출력된다.
			}
			console.log(x, y, z);		// 오류 발생, y, z가 변수는 존재하지 않는다.
		}
		--------------------------------------------------------------------------------------------------------------------------
		변수 호이스팅이 적용되지 않는다.
		--------------------------------------------------------------------------------------------------------------------------
		function a() {
			let x = 10;
			if (x > 5) {
				let y = 20;
				let z = x*y;
				console.log(x, y, z);	// 10, 20, 200 출력된다.
			}
			console.log(x, y, z);		// 오류 발생, y, z가 변수는 존재하지 않는다.
		}
		--------------------------------------------------------------------------------------------------------------------------
		변수명이 중복되면 오류가 발생한다.
		--------------------------------------------------------------------------------------------------------------------------
		function x() {
    		let x = 10;
    		console.log(x);

    		let x = 20;			// 변수명 중복으로 문법 오류가 발생한다.
    		console.log(x);
		}

	const
		--------------------------------------------------------------------------------------------------------------------------
		한번 할당된 값을 변경할 수 없다. (같은 값을 써야할 때 사용)
		--------------------------------------------------------------------------------------------------------------------------
		const x = 10;
		x = 100;	// 오류가 발생한다. 값을 변경할 수 없다.
  • 셋 다 같은 의미 But, 요즘은 let을 많이 쓰는 추세다.

내 정보 보기

navbar.jsp
<li class="nav-item"><a class="nav-link ${menu eq 'user' ? 'active' : '' }" href="/user/info">내정보 보기</a></li>

실행결과

  • 그러나, 모든 사용자 정보가 담긴 User 객체를 담지 않고, ID와 이름 정도만 있는 객체를 따로 만든다.
LoginUserInfo.java
package com.sample.web.login;

/*
 * 로그인된 사용자의 정보를 담는다.
 * id와 이름만 가지고 있다.
 */
public class LoginUserInfo {

	private String id;
	private String name;
	
	public LoginUserInfo(String id, String name) {
		this.id = id;
		this.name = name;
	}

	public String getId() {
		return id;
	}

	public String getName() {
		return name;
	}
	
}
HomeController
@PostMapping("/login")
	public String login(String id, String password) {
		// 아이디, 비밀번호 로그인 검증
		User user = userService.login(id, password);
		
		// HttpSession 객체에 로그인 절차가 완료된 사용자 정보를 저장한다.
		LoginUserInfo loginUserInfo = new LoginUserInfo(user.getId(), user.getName());
		// HttpSession 객체에 속성으로 로그인 절차가 완료된 사용자 정보를 저장한다.
		SessionUtils.setAttribute("loginUser", loginUserInfo);
		
		return "redirect:home";
	}
  • 이제 loginUserInfo가 찾아진다. (id와 name만 나오게)
  • 값을 조회하기 위해서는 DB에 엑세스 해야 한다.
  • 내 정보 보기에서 "아이디"는 User에 있고 접근권한은 User_Role에 있다. (서로 다른 곳에 있다.)
  • 이 둘을 한꺼번에 표시하기 위해 새로운 클래스를 만든다.
UserDetailDto.java
package com.sample.dto;

import java.sql.Date;
import java.util.List;

import com.sample.vo.UserRole;

public class UserDetailDto {

	private String id;
	private String name;
	private String email;
	private String tel;
	private Date createdDate;
	private List<UserRole> userRoles;
	
	public UserDetailDto() {}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getTel() {
		return tel;
	}

	public void setTel(String tel) {
		this.tel = tel;
	}

	public Date getCreatedDate() {
		return createdDate;
	}

	public void setCreatedDate(Date createdDate) {
		this.createdDate = createdDate;
	}

	public List<UserRole> getUserRoles() {
		return userRoles;
	}

	public void setUserRoles(List<UserRole> userRoles) {
		this.userRoles = userRoles;
	}
    @Override
	public String toString() {
		return "UserDetailDto [id=" + id + ", name=" + name + ", email=" + email + ", tel=" + tel + ", createdDate="
				+ createdDate + ", userRoles=" + userRoles + "]";
	}
}
UserService.java
public UserDetailDto getUserDetail(String userId) {
		// 사용자 정보 조회
		User user = userMapper.getUserById(userId);
		// 사용자의 권한 정보 조회
		List<UserRole> userRoles = userRoleMapper.getUserRolesByUserId(userId);
		
		// 사용자 정보와 권한정보를 모두 저장하는 UserDetailDto 객체 생성
		UserDetailDto userDetailDto = new UserDetailDto();
		// User객체의 값을 UserDetailDto객체로 복사하기
		BeanUtils.copyProperties(user, userDetailDto);
		// 사용자권한정보를 UserDetailDto객체에 저장하기
		userDetailDto.setUserRoles(userRoles);
		
		return userDetailDto;
	}
	
UserController
package com.sample.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import com.sample.dto.UserDetailDto;
import com.sample.exception.ApplicationException;
import com.sample.service.UserService;
import com.sample.utils.SessionUtils;
import com.sample.web.login.LoginUserInfo;

@Controller
@RequestMapping("/user")
public class UserController {
	
    @Autowired
	private UserService userService;
	
	@GetMapping("/info")
	public String info(Model model) {
		
		LoginUserInfo loginUserInfo = (LoginUserInfo) SessionUtils.getAttribute("loginUser");
		if (loginUserInfo == null) {
			throw new ApplicationException("로그인 정보가 존재하지 않습니다.");
		}
		
		UserDetailDto userDetailDto = userService.getUserDetail(loginUserInfo.getId());
		model.addAttribute("user", userDetailDto);
		
		return "user/detail";
	}
}
  • 로그인 하지 않은 상태에서 info를 갔을 때 예외처리를 하였다.

  • 웹과 관련된 코드는 Controller에 DB 엑세스 코드는 Service에 나눠서 구현했다.

  • 표현계층은 서버와 직접적인 영역이 있다.

  • 프론트엔드 -> 표현계층 -> 벡엔드 -> 표현계층 -> 프론트엔드 순서로 실행된다.

  • 그러나 서비스는 웹이 아닌 곳에서도 보여져야 하기 때문에 로그인 체크를 Controller에 작성하였다.

  • 싱글턴 객체에서 멤버변수는 무조건 read-only여야 한다. (꺼내서 사용하는 것만 가능! / 변경 금지!)

detail.jsp
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
<title>애플리케이션</title>
</head>
<body>
<c:set var="menu" value="user" />
<%@ include file="../common/navbar.jsp" %>
<div class="container">
	<div class="row mb-3">
		<div class="col-12">
			<h1 class="border bg-light p-2 fs-4">내 정보</h1>
		</div>
	</div>
	<div class="row mb-3">
		<div class="col-3">
			<div class="card">
				<div class="card-header">
					메뉴
				</div>
				<div class="card-body">
					<div class="list-group">
						<a href="/user/info" class="list-group-item list-group-item-action active">내 정보 보기</a>
						<a href="/user/password" class="list-group-item list-group-item-action">비밀번호 변경</a>
						<a href="/user/delete" class="list-group-item list-group-item-action">탈퇴하기</a>
					</div>
				</div>
			</div>
		</div>
		<div class="col-9">
			<p>내 정보를 확인하세요.</p>
			<table class="table table-bordered">
				<colgroup>
					<col width="15%">
					<col width="35%">
					<col width="15%">
					<col width="35%">
				</colgroup>
				<tbody>
					<tr>
						<th>아이디</th>
						<td>${user.id }</td>
						<th>가입일</th>
						<td><fmt:formatDate value="${user.createdDate }"/></td>
					</tr>
					<tr>
						<th>이름</th>
						<td>${user.name }</td>
						<th>접근권한</th>
						<td>
							<c:forEach var="userRole" items="${user.userRoles }">
								<c:choose>
									<c:when test="${userRole.roleName eq 'ROLE_GUEST' }">
										<span class="badge text-bg-primary">${userRole.roleName }</span>
									</c:when>
									<c:when test="${userRole.roleName eq 'ROLE_USER' }">
										<span class="badge text-bg-warning">${userRole.roleName }</span>
									</c:when>
									<c:when test="${userRole.roleName eq 'ROLE_ADMIN' }">
										<span class="badge text-bg-success">${userRole.roleName }</span>
									</c:when>
								</c:choose>
							</c:forEach>
						</td>
					</tr>
					<tr>
						<th>이메일</th>
						<td>${user.email }</td>
						<th>전화번호</th>
						<td>${user.tel }</td>
					</tr>
				</tbody>
			</table>
		</div>
	</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
</body>
</html>

실행결과

profile
한 걸음 한 걸음 나아가는 개발자

0개의 댓글