본문 바로가기
개발/Spring 블로그 만들기

Spring 블로그 만들기 - 17. 로그인 화면 만들기 및 레이아웃 나누기

by 똘똘이박사 2019. 4. 9.

 

 

이 포스팅의 샘플 게시판 개발 환경은 MAC OS, STS, OpenJDK11 입니다.

 

 

Spring 블로그 만들기 - 16. 로그인화면 만들기 및 레이아웃 나누기

이제 게시판을 여러 개 만들 수 있게 되었으니 회원권한에 따라 게시판 노출을 제한하려고 합니다. 하지만 아직 로그인 기능이나 회원가입 프로그램이 만들어 져있지 않습니다. 이번 포스팅에서는 로그인 화면을 만들어 봅니다. 

부트스트랩을 이용해 간단한 로그인 화면을 만들었습니다. 그런데 지난번에 만들어 놓은 메뉴바가 보이지 않습니다. 사용자의 권한에 의해 메뉴의 구성이 달라지기 때문에 로그인 화면이나 회원가입 단계 에서는 필수적인 메뉴 이외에는 노출 시키지 않는 것이 일반적입니다. 샘플용 게시판에서는 메뉴를 노출시키지 않도록 하겠습니다.

페이지에 따라 메뉴를 노출 시키는 방법은 여러가지가 있습니다. 지금까지의 방식은 메뉴관련 부분을 별도의 header 파일로 분리 시켜, 필요한 화면에 header 파일 include 하여 구성을 하였습니다. 하지만 화면의 구성이 복잡해질 경우, 파일을 include 시키는 것만으로는 관리가 힘들어 지게 됩니다. 스프링에서는 화면의 구성(레이아웃)을 쉽게 할 수 있도록 Tiles라는 도구를 제공하고 있습니다. 이번 포스팅에서는 Spring tiles를 이용해 화면을 구성하는 방법까지 같이 알아 보고자 합니다.

 

 

로그인 화면 만들기

화면 구성에 필요한 화면을 우선 만들어 봅시다. 먼저 로그인 화면을 만들어 봅니다. 샘플로 사용한 부트스트랩은 이곳을 클릭하면 확인하실 수 있습니다.

우선 url을 입력 했을때 요청을 처리할 Controller먼저 작성해 봅니다. login 관련 컨트롤러는 지금까지와는 다르게 패키지를 작성 하였습니다.

LoginController.java (신규)

package com.freehoon.web.login;

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

import com.freehoon.web.user.model.UserVO;

@Controller
@RequestMapping(value = "/login")
public class LoginController {
	
	@RequestMapping(value = "/login", method = RequestMethod.GET)
	public String loginForm(Model model) throws Exception {
		model.addAttribute("userVO", new UserVO());
		return "login/login";
	}
}

 

View 화면은 아래의 경로에 작성합니다.

login.jsp (신규)

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

<!-- login form {s} -->
<form:form class="form-signin" name="form" id="form" role="form" modelAttribute="userVO" method="post" action="${pageContext.request.contextPath}/board/saveBoard">
	<div class="text-center mb-4">
		<h1 class="h3 mb-3 font-weight-normal">FREEHOON.COM</h1>
	</div>
	
	<div class="form-label-group">
		<form:input path="uid" id="uid" class="form-control" placeholder="User ID" required="" autofocus="" />
		<label for="uid" class="sr-only">User ID</label>
	</div>
	
	<div class="form-label-group">
		<form:password path="pwd" id="pwd" class="form-control" placeholder="User Password" required="" />
		<label for="pwd" class="sr-only">User Password</label>
	</div>
	
	<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
	
	<span style="font-size:11pt;">Sign up</span>
	
	<p class="mt-5 mb-3 text-muted text-center">© 2019. FREEHOON. All rights reserved.</p>
</form:form>
<!-- login form {e} -->

 

위의 소스를 실행하면 아직 정상적인 화면을 볼수는 없습니다. 아직 스타일시트를 삽입하지 않았기 때문입니다. 스타일시트는 레이아웃 작업을 하면서 추가할 예정이므로 지금은 그냥 넘어 가도록 합니다.

 

 

Spring Tiles 사용하기

의존성 추가

스프링 타일즈를 사용하기 위해선 우선 maven을 통해 의존성을 추가해야 합니다. 

		<!-- tiles -->
		<!-- https://mvnrepository.com/artifact/org.apache.tiles/tiles-jsp -->
		<dependency>
		    <groupId>org.apache.tiles</groupId>
		    <artifactId>tiles-jsp</artifactId>
		    <version>3.0.8</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/org.apache.tiles/tiles-servlet -->
		<dependency>
		    <groupId>org.apache.tiles</groupId>
		    <artifactId>tiles-servlet</artifactId>
		    <version>3.0.8</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/org.apache.tiles/tiles-core -->
		<dependency>
		    <groupId>org.apache.tiles</groupId>
		    <artifactId>tiles-core</artifactId>
		    <version>3.0.8</version>
		</dependency>

 

 

servlet-context.xml 수정하기

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
		<beans:property name="order" value="2" />
	</beans:bean>

	<!-- Tiles View Resolver -->
	<beans:bean id="tielsViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
		<beans:property name="viewClass" value="org.springframework.web.servlet.view.tiles3.TilesView" />
		<beans:property name="order" value="1" />
	</beans:bean>
	
	<!-- Tiles Configurer -->
	<beans:bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
		<beans:property name="definitions">
			<beans:list>
				<beans:value>/WEB-INF/tiles/tiles.xml</beans:value>
			</beans:list>
		</beans:property>
	</beans:bean>

기존의 Internal View Resolver 의 order값을 2로 수정하였습니다. Tiles View Resolver의 우선순위(order)가 더 빨라야 하기 때문입니다.

이제 서비스 패턴에 따라 불러와야 할 레이아웃을 정의 할 페이지를 만들 차례 입니다.

아래와 같이 tiles 관련 디렉토리를 신규 생성하고, tiles.xml 이라는 파일을 만들어 추가해 줍니다.

tiles.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN" "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
    <!-- login -->
    <definition name="login-layout"    template="/WEB-INF/tiles/layouts/login_layout.jsp">
    </definition>
    <definition name="login/*" extends="login-layout">
        <put-attribute name="tile_body" value="/WEB-INF/views/login/{1}.jsp" />
    </definition>
    
    <!-- base -->
    <definition name="base-layout"    template="/WEB-INF/tiles/layouts/base_layout.jsp">
        <put-attribute name="tile_header" value="/WEB-INF/tiles/layouts/header.jsp" />
    </definition>
    <definition name="board/*" extends="base-layout">
        <put-attribute name="tile_body" value="/WEB-INF/views/board/{1}.jsp" />
    </definition>
</tiles-definitions>

내용을 분석해 보면, 레이아웃의 기본 형태를 2가지로 구분하였습니다. 로그인 레이아웃과 기본 레이아웃입니다. 기본 레이아웃을 기준으로 설명을 드리자면, 레이아웃의 기본틀은 template 속성에 지정을 합니다. 속성 값으로는 틀을 담고 있는 페이지를 지정합니다. 따라서 기본 레이아웃의 틀은 /WEB-INF/tiles/layouts/base_layout.jsp 이고, 이름은 'base-layout' 입니다. <put-attribute> 속성을 통해 레이아웃을 구성하는 여러 개의 페이지를 지정할 수가 있습니다. 여기서는 header.jsp 파일 하나만 불러왔습니다. 만약 여기에 추가적으로 불러와야 할 페이지가 더 있다면 <put-attribute>를 추가하여 주면 됩니다. Spring Tiles는 상속과 비슷한 개념을 사용하는데 extends 속성을 통해 확장이 가능합니다. extends에는 부모가 되는 definition 의 이름을 적어 줍니다. 보통 확장을 통해 불러 오는 페이지는 view의 내용이 변하는 경우 사용합니다. 예를 들어 게시판의 리스트와 상세보기, 글 작성 페이지는 모두 레이아웃이 다른 페이지 입니다. 확장 부분의 name는 브라우저의 주소창에 입력할 URL이 아닙니다. 여기에 사용된 URL은 Controller에서 리턴하는 View의 이름입니다. 따라서 Controller 에서 리턴 값이 "board/index" 라고 하면 "board/*"이 호출되고 *이 index와 대응되어 {1}에 index를 할당 하게 됩니다. 결국 최종 View의 주소는 /WEB-INF/views/board/index.jsp 가 됩니다. 이 내용을 간단히 표현하면 아래와 같습니다.

마지막 put-attribute의 value 값에 {1}의 의미는 주소가 단순히 board/* 로 끝나지 않을 수도 있다는 의미 입니다. 컨트롤러의 반환값이 board/index/123 이라고 가정하였을 경우 definition의 name 값은 "board/*/*" 과 같이 설정 할 수 있습니다. 따라서 put-attribute의 value 값은 /board/{1}/{2}.jsp 하는 식으로 순차적으로 늘려 갈 수 있습니다.

 

 

template 파일 만들기 

이제 기본틀을 만들 차례 입니다. 위에서 설정한 기본틀이 2개(login_layout.jsp, base_layout.jsp) 이므로 해당 파일을 모두 만들어야 합니다. 

login_layout.jsp

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>

<!DOCTYPE html>

<html lang="kr">
<head>
  <meta charset="utf-8">

<!-- jQuery -->
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">

<!-- common CSS -->
<link rel="stylesheet" href="<c:url value='/resources/common/css/common.css'/>" >

<!-- Custom styles for this template -->
<link rel="stylesheet" href="<c:url value='/resources/common/css/signin.css'/>" >

  
  <style>
  body{padding : 0px}
  	
  	#tile_body {
  		width:100%; 
  		float:left;
  	}
  </style>
</head>

<body class="text-center">

<div id="tile_body"><tiles:insertAttribute name="tile_body" /></div>


</body>
</html>

지금까지 일반적으로 만들어왔던 jsp페이지와 동일합니다. 다만 <body>에 아무 내용이 없고, <div>태그로 <tiles:insertAttribute> 태그를 감싸주어 body 영역을 잡아 주었습니다. tiles:insertAttribute를 사용해 추가해야 할 페이지를 지정할 수 있는데, name 속성을 사용합니다. name 속성에 "tile_body"가 지정되어 있습니다. 이 부분은 조금 전에 만들었던 tiles.xml에서 <put-attribute>의 name 속성과 일치하는 파일을 찾아 불러오게 됩니다. 따라서 위 내용은 /WEB-INF/views/login/{1}.jsp 를 불러온다는 의미 입니다.

 

base_layout.jsp

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>

<!DOCTYPE html>

<html lang="kr">
<head>
  <meta charset="utf-8">

<!-- jQuery -->
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
<!-- common CSS -->
<link rel="stylesheet" href="<c:url value='/resources/common/css/common.css'/>" >
 
  <style>
  body{padding : 0px}
  
  	#tile_header {
  		width:100%;
  	}
  	
  	#tile_body {
  		width:100%; 
  		float:left;
  	}
  </style>
</head>

<body>

<div id="tile_header"><tiles:insertAttribute name="tile_header" /></div>
<div id="tile_body"><tiles:insertAttribute name="tile_body" /></div>


</body>
</html>

base_layout.jsp에서는 login_layout.jsp와 비슷하지만 메뉴를 출력하는 header.jsp가 들어가 있습니다.

 

loginin.css 파일

loginin.css 파일은 로그인 폼의 디자인 스타일 시트 입니다.

html,
body {
  height: 100%;
}

body {
  display: -ms-flexbox;
  display: flex;
  -ms-flex-align: center;
  align-items: center;
  padding-top: 40px;
  padding-bottom: 40px;
}

.form-signin {
  width: 100%;
  max-width: 330px;
  padding: 15px;
  margin: auto;
}
.form-signin .checkbox {
  font-weight: 400;
}
.form-signin .form-control {
  position: relative;
  box-sizing: border-box;
  height: auto;
  padding: 10px;
  font-size: 16px;
}
.form-signin .form-control:focus {
  z-index: 2;
}
.form-signin input[id="uid"] {
  margin-bottom: -1px;
  border-bottom-right-radius: 0;
  border-bottom-left-radius: 0;
}
.form-signin input[id="pwd"] {
  margin-bottom: 10px;
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}

 

수정 내용을 모두 저장하였다면 서버를 실행하여 login 페이지의 화면을 확인해 봅니다.

 

 

board, menu관리 프로그램에 tiles 적용하기

board와 menu관리 프로그램에 tiles를 적용해 봅니다. 두 프로그램은 base_layout.jsp의 영향을 받습니다. 따라서 각 페이지 상단에 있는 <include> 문을 모두 삭제해야 합니다. 또한 header.jsp 파일의 위치나 내용에도 약간의 변화가 있습니다. 새로 작성할 header.jsp는 layout 파일들과 동일한 위치에 생성합니다.

<nav class="navbar navbar-expand-sm navbar-dark bg-dark">
  <a class="navbar-brand" href="#">FREEHOON.COM</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExample03" aria-controls="navbarsExample03" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarsExample03">
    <ul class="navbar-nav mr-auto">
      <li class="nav-item">
        <a class="nav-link" href="#">Board</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Q&A</a>
      </li>
    </ul>
    <form class="form-inline my-2 my-md-0">
      <input class="form-control" type="text" placeholder="Search">
    </form>
  </div>
</nav>

기존의 header.jsp에서 메뉴와 관련된 부분만 별도로 뽑아낸 것입니다. 스타일시트는 base_layout.jsp에서 추가 하였으므로 header.jsp 에서는 별도로 추가하지 않아도 괜찮습니다. 

 

수정 사항을 모두 저장하였으면 board와 menu관리 프로그램에도 접근하여 기존과 동일하게 화면이 나오는지 확인해 봅니다.

 

 

 

 

 

 

 

 

 

 

※ 포스팅에 오타나 잘못된 부분, 추가적으로 더 알고 싶은 부분이 있으면 댓글 주세요~

 

반응형