본문 바로가기

카테고리 없음

AWS BeansTalk(빈스톡)을 활용한 웹사이트 제작 - 3

안녕하세요

저번시간에는 Beanstalk로 서버를 구성하고 DB를 구축함으로써 개발시작 할 수 있는 단계까지 진행하였습니다.

이번 시간에는 프로젝트를 직접 생성해서 개발을하고 서버에 배포하는 시간을 갖겠습니다. 

너무 길어 지면 2부로 나눠야 할거 같네요

웹사이트 내용은 UBD 계산사이트 입니다. (간단한 원페이지 사이트)

 

프로젝트의 개발환경은 아래와 같습니다.

언어: 자바

도구: 이클립스

프레임워크: SpringBoot

DB: Mysql 

그외: html, css, javascript

 

 

첫번째로 이클립스안에서 스프링부트 프로젝트를 생성하겠습니다. 

1. NewProject 에서 Spring Starter Project를 선택합니다. 

2. 프로젝트명은 umbokdong으로 했습니다.  또한 type은 maven, 패키징 방식은 War를 선택합니다. 

3. 다음으로 기본적으로 필요한 dependencies들을 추가 합니다. 기본적으로 웹관련, 디비관련, 뷰와 컨트롤러와의 통신관려 항목들을 추가 했습니다. 

프로젝트가 생성되었으니 기본 웹화면부터 만들어 보겠습니다. 

Bootstrap를 쓸것이며, 처음에 잘정리된 폼을 다운받아서 적용할 것입니다(무료탬플릿)

https://startbootstrap.com/ 이 사이트에서 SB Admin2라는 탬플릿을 다운 받습니다. 

다운받은 파일을 압축 풀어줍니다. 

압축을 푼뒤 폴더안의 내용 전체를 프로젝트의 static 폴더에 모두 복사해줍니다. 

(사실 정통적인 방식으로 개발을 위해 정적파일은 static에 html 파일은 templates 폴더에 넣는게 맞지만 이 사이트는 원페이지 이기 때문에 간단하게 구현하였습니다.)

이제 기본적인 화면까지 구성되었으니 프로젝트를 실행해 보겠습니다. 

프로젝트 우클릭 -> Run As -> Spring Boot App 하면 실행이 되지만 에러가 떨어지며 실패할 것입니다.

이유는 디비설정이 되어있지 않기 때문인데요, 디비설정에 앞서 우선 테스트를 위해 메인 소스에 DB설정 우회하는 코드를 넣어주고 테스트 해봅니다. 

UmbokdongApplication.java 파일에 들어가서 

@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class}) 

코드를 추가합니다. 

그리고 다시 프로젝트를 실행하고 http://127.0.0.1:8080/ 로컬 페이지에 들어가면 다음과 같이 서버가 잘 실행되는것을 확인할 수 있습니다. 

이제 구동까지 확인하였으니 소스상의 blank.html 안에서 이 소스안의 다른 컴포넌트들을 활용하여 페이지를 만들어 보겠습니다. 

 

먼저 만들어진 페이지를 보고 구성을 설명 해 보겠습니다. 

상단에 input 박스두개와 아래 테이블이 있는 단순한 구조 입니다. 

위 박스에 숫자를 입력하면 알아서 UBD를 계산해주고 그와 비슷한 영화목록을 DB에서 가져오는 방식입니다.

blank.html 코드는 아래와 같습니다. (나중에 이 파일명을 index.html로 바꿀것입니다)

input에 숫자가 들어오면 oninput 이벤트가 발생하여 UBD를 계산해 주고, 그 UBD가지고 ajax통신을 통해 데이터를 가져와 테이블을 만들어줍니다.  

<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org">  <head>    <meta charset="utf-8">   <meta http-equiv="X-UA-Compatible" content="IE=edge">   <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">   <meta name="description" content="">   <meta name="author" content="">    <title>UBD 계산기</title>    <!-- Custom fonts for this template-->   <link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">   <link href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i" rel="stylesheet">    <!-- Custom styles for this template-->   <link href="css/sb-admin-2.min.css" rel="stylesheet">  </head>  <body id="page-top">    <!-- Page Wrapper -->   <div id="wrapper">      <!-- Sidebar -->     <ul class="navbar-nav bg-gradient-primary sidebar sidebar-dark accordion" id="accordionSidebar">        <!-- Sidebar - Brand -->       <a class="sidebar-brand d-flex align-items-center justify-content-center" href="index.html">                  <div class="sidebar-brand-text mx-3">UMBOKDONG</div>       </a>        <!-- Divider -->       <hr class="sidebar-divider my-0">        <!-- Nav Item - Dashboard -->       <li class="nav-item active">         <a class="nav-link" href="index.html">           <i class="fas fa-fw fa-tachometer-alt"></i>           <span>UBD 계산</span></a>       </li>               <!-- Divider -->       <hr class="sidebar-divider d-none d-md-block">        <!-- Sidebar Toggler (Sidebar) -->       <div class="text-center d-none d-md-inline">         <button class="rounded-circle border-0" id="sidebarToggle"></button>       </div>      </ul>     <!-- End of Sidebar -->      <!-- Content Wrapper -->     <div id="content-wrapper" class="d-flex flex-column">        <!-- Main Content -->       <div id="content">          <!-- Topbar -->                  <!-- End of Topbar -->          <!-- Begin Page Content -->         <div class="container-fluid">            <!-- Page Heading -->           <h1 class="h3 mb-4 text-gray-800">엄복동 하나만 기억해주세요</h1> 			 			<div class="form-group row">                   <div class="col-sm-2 mb-3 mb-sm-0">                     <input type="number" min=170000 class="form-control form-control-user" oninput="calUbd()" id="count" placeholder="관객수">                   </div>                   <div class="col-sm-1">                     	<h1 class="h3 mb-4 text-gray-800">관객</h1>                   </div>                   <div class="col-sm-2">                     <input type="number" class="form-control form-control-user" oninput="calCount()" id="ubd" placeholder="UBD">                   </div>                   <div class="col-sm-1">                     	<h1 class="h3 mb-4 text-gray-800">UBD</h1>                   </div>                 </div>                               <div class="card shadow mb-4">             <div class="card-header py-3">               <h6 class="m-0 font-weight-bold text-primary">비슷한 영화</h6>             </div>             <div class="card-body">               <div class="table-responsive">                 <table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">                   <thead>                     <tr>                       <th>제목</th>                       <th>개봉일</th>                       <th>국적</th>                       <th>배급사</th>                       <th>관객수</th>                       <th>UBD</th>                     </tr>                   </thead>                                      <tbody>                                       </tbody>                 </table>               </div>             </div>           </div>         </div>         <!-- /.container-fluid --> 		       </div>       <!-- End of Main Content -->        <!-- Footer -->       <footer class="sticky-footer bg-white">         <div class="container my-auto">           <div class="copyright text-center my-auto">             <span>Copyright &copy; coding 2019</span>           </div>         </div>       </footer>       <!-- End of Footer -->      </div>     <!-- End of Content Wrapper -->    </div>   <!-- End of Page Wrapper -->    <!-- Scroll to Top Button-->   <a class="scroll-to-top rounded" href="#page-top">     <i class="fas fa-angle-up"></i>   </a>    <!-- Logout Modal-->   <div class="modal fade" id="logoutModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">     <div class="modal-dialog" role="document">       <div class="modal-content">         <div class="modal-header">           <h5 class="modal-title" id="exampleModalLabel">Ready to Leave?</h5>           <button class="close" type="button" data-dismiss="modal" aria-label="Close">             <span aria-hidden="true">×</span>           </button>         </div>         <div class="modal-body">Select "Logout" below if you are ready to end your current session.</div>         <div class="modal-footer">           <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>           <a class="btn btn-primary" href="login.html">Logout</a>         </div>       </div>     </div>   </div>    <!-- Bootstrap core JavaScript-->   <script src="vendor/jquery/jquery.min.js"></script>   <script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>    <!-- Core plugin JavaScript-->   <script src="vendor/jquery-easing/jquery.easing.min.js"></script>    <!-- Custom scripts for all pages-->   <script src="js/sb-admin-2.min.js"></script>       <script>   var globalUbd =0;  var calUbd =  function() { 	  var ubd = $("#count").val()/170000; 	  $("#ubd").val(ubd); 	  var diff = globalUbd - ubd 	  if(ubd > 1 && Math.abs(diff)>1){ 		  check(ubd); 	  }   }     var calCount =  function() { 	  var count = $("#ubd").val()*170000; 	  var ubd = $("#ubd").val(); 	  $("#count").val(count); 	  var diff = globalUbd - ubd 	  if(ubd > 1 && Math.abs(diff)>=1){ 		  check(ubd); 	  }   }    var check=  function(ubd) { 	  $.ajax({           type: "POST",           url: "checkMovie",           dataType: 'json',           data : {ubd:Math.floor(ubd)},           success: function (data) {           	var html = "";           		globalUbd = ubd; 				 				for (var i = 0; i < data.result.box.length; i++) { 					html+="<tr>"+ 					"<td>"+data.result.box[i].subject+"</td>"+ 					"<td>"+data.result.box[i].open+"</td>"+ 					"<td>"+data.result.box[i].nation+"</td>"+ 					"<td>"+data.result.box[i].company+"</td>"+ 					"<td>"+data.result.box[i].attendance+"</td>"+ 					"<td>"+data.result.box[i].ubd+"</td>"+ 					"</tr>" 				} 				$("#dataTable tbody").html(html); 				             },           error: function (e) {                 console.log("ERROR : ", e);                          }       });   }      </script> </body>  </html> 

 

이제 front단은 완성되었으니 backend 단을살펴보겠습니다. 

첫번째로 Mysql의 테이블을 만듭니다. 이전 시간에 실습한 RDS에 Workbench를 통해 접속한 다음 스키마을 만듭니다. 스키마 명은 umbokdong으로 하였습니다. 

스미카을 생성 후 그 안에 boxoffice라는 테이블을 만들었는데 아래와 같이 생성하였습니다. 

테이블안의 데이터를 넣기 위해 영화관입장권통합전산망의 데이터를 활용하였습니다. 

http://www.kobis.or.kr 이 사이트에서 박스오피스-> 역대 페이지에 들어가서 조회 후 엑셀로 다운받아서 테이블에 insert 하였습니다. (insert 시에 ubd도 함께 계산하여 추가하였습니다)

이 후 조회한 결과입니다. 

테이블 까지 완성하였으니 backEnd(java)를 만들어 보겠습니다. 

1. application.properties 파일에 DB정보를 넣어 줍니다. RDS생성시에 나온 end 포인트 및 계정 정보를 넣습니다. 

spring.application.name=HelloSpringBoot spring.datasource.driverClassName=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://aa1aewvk94uwejr.c9p0x2nvzezc.ap-northeast-2.rds.amazonaws.com/umbokdong?autoReconnect=true&useUnicode=true&characterEncoding=utf8 spring.datasource.username=kongnamu spring.datasource.password=yourpw spring.datasource.maxIdle=20 spring.datasource.maxActive=400 spring.datasource.maxWait=10000 spring.datasource.validationQuery=SELECT 1

2. 통신 및 DB 작업을 위한 세개의 파일을 작성합니다. 

2-1) BoxDao.java

package com.example.umbokdong;  import java.util.List;  import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository;  @Repository public class BoxDao { 	@Autowired 	private JdbcTemplate jdbcTemplate; 	 	public List<BoxVo> boxResult(String ubd){ 		String query = "select * from boxoffice where ubd = "+ ubd; 		return jdbcTemplate.query(query, new BeanPropertyRowMapper<BoxVo>(BoxVo.class)); 	} } 

2-2) BoxVo.java

package com.example.umbokdong;  public class BoxVo { 	private String num; 	private String subject; 	private String open; 	private String take; 	private String attendance; 	private String screen; 	private String nation; 	private String company; 	private String ubd; 	 	public BoxVo() { 		super(); 		// TODO Auto-generated constructor stub 	}  	public String getNum() { 		return num; 	}  	public void setNum(String num) { 		this.num = num; 	}  	public String getSubject() { 		return subject; 	}  	public void setSubject(String subject) { 		this.subject = subject; 	}  	public String getOpen() { 		return open; 	}  	public void setOpen(String open) { 		this.open = open; 	}  	public String getTake() { 		return take; 	}  	public void setTake(String take) { 		this.take = take; 	}  	public String getAttendance() { 		return attendance; 	}  	public void setAttendance(String attendance) { 		this.attendance = attendance; 	}  	public String getScreen() { 		return screen; 	}  	public void setScreen(String screen) { 		this.screen = screen; 	}  	public String getNation() { 		return nation; 	}  	public void setNation(String nation) { 		this.nation = nation; 	}  	public String getCompany() { 		return company; 	}  	public void setCompany(String company) { 		this.company = company; 	}  	public String getUbd() { 		return ubd; 	}  	public void setUbd(String ubd) { 		this.ubd = ubd; 	}  	 } 

2-3) WebController.java

package com.example.umbokdong;  import java.util.HashMap; import java.util.Map;  import javax.servlet.http.HttpServletRequest;  import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.ResponseBody;  @Controller public class WebController { 	@Autowired 	private BoxDao BDao; 	 	 	@PostMapping("/checkMovie") 	public @ResponseBody Map getBoardList( Model model, HttpServletRequest req) { 		String ubd = req.getParameter("ubd"); 		model.addAttribute("box", BDao.boxResult(ubd)); 		 		Map result = new HashMap(); 		result.put("result",model); 		return result; 	} 	 	 } 

 

DB도 연결하고 컨트롤러도 만들어 졌으니 처음 UmbokdongApplication.java 파일에 작성한 

@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})  을 주석처리 또는 삭제 합니다. 

그리고 blank.html파일명을 index.html 파일명으로 바꿔줍니다. 

 

그리고 실행하면 완성된 페이지가 나오게됩니다. 

 

 

이제 완성된 프로젝트를 배포해 보겠습니다. 프로젝트 우클릭을 하고 Export-> WAR file을 선택합니다.  

Destination(저장장소 및 이름) 을 선택하고 finish를 클릭하면 war 파일이 생성됩니다. 

WAR 파일이 생성 되었으니 AWSConsole 의 beanstalk 페이지로 들어갑니다. 

기존의 만든 kongnamu 환경을 선택하면 다음과 같은 화면이 나오는데 여기서 Upload and Deploy를 선택 후 팝업 창이 나오면 좀전에 만든 War 파일을 넣은 후 Deploy를 선택합니다. 

 

몇분의 시간이 흐른 후 배포가 완료되고 beanstalk에서 기본적으로 생성된 URL을 클릭하면 완성된 사이트에 접속할 수 있습니다. 

저는 AWS Route53의 도메인 서비스를 사용하여

http://umbokdong.net/ 으로 맵핑 하였습니다. (이곳에 들어가면 사이트를 바로 확인 할 수 있습니다)

 

AWS Route53 등록 방법은 다음 기회에 설명 하겠습니다. 

 

지금까지 서버를 구성하고 개발을 통해 하나의 웹사이트를 만드는 과정을 해보았습니다. AWS의 Beanstalk를 활용하면 이처럼 빠르고 간단하게 자신만의 웹사이트를 구축할 수 있습니다. 

 

지금은  역대 순위에 영화정보만 직접 데이터베이스의 넣었지만 다음 시간에는 AWS lambda를 통해 배치작업으로 주기적으로 영화 정보를 넣는 것을 구현해 보겠습니다.

 

질문 주시면 성실히 답변해드리겠습니다. 감사합니다.