
우리스러움
배경
—
핵심 기능 정의
내가 한것
프로젝트 구조
woorinature/
|-- src/
| |-- main/
| | |-- java/com/example/familyscheduler/
| | | |-- WoorinatureApplication.java
| | | |-- controller/
| | | | |-- CalendarController.java
| | | |-- model/
| | | | |-- Event.java
| | | |-- repository/
| | | | |-- EventRepository.java
| | |-- resources/
| | |-- templates/
| | | |-- calendar.html
| | |-- application.properties
|-- pom.xml
application.properties 설정
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
@Entity
public class Event {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String title;
private LocalDate date;
public LocalDate getDate() {
return date;
}
public void setDate(LocalDate date) {
this.date = date;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
@Repository
public interface EventRepository extends JpaRepository<Event, Long> {
List<Event> findByDate(LocalDate date);
}
@Controller
public class CalenderController {
@Autowired
private EventRepository eventRepository;
@GetMapping("/calender")
public String getCalender(Model model) {
List<Event> events = eventRepository.findAll();
model.addAttribute("events", events);
return "calender";
}
@PostMapping("/add-event")
public String addEvent(@RequestParam String title, @RequestParam String date) {
Event event = new Event();
event.setTitle(title);
event.setDate(LocalDate.parse(date));
eventRepository.save(event);
return "redirect:/calender";
}
}
가까운 가족들을 대상으로 최단 시간내 필요성 검증을 시도하고자 최소한의 mvc 코드를 추가하고 테스트해봤습니다!
class EventTest {
@Test
void 이벤트_생성_테스트() {
// given
Event event = new Event();
String expect = "이번주 일요일 가족 식사 모임";
// when
event.setTitle("이번주 일요일 가족 식사 모임");
event.setDate(LocalDate.of(2024, 06, 23));
// then
assertNotNull(event);
assertEquals(expect, event.getTitle());
assertEquals(LocalDate.of(2024, 06, 23), event.getDate());
}
}
@DataJpaTest
class EventRepositoryTest {
@Autowired
private EventRepository eventRepository;
@Test
public void 이벤트_저장과_조회_테스트() {
// given
String expect = "이번주 일요일 가족 식사 모임";
Event event = new Event();
event.setTitle("이번주 일요일 가족 식사 모임");
// when
event.setDate(LocalDate.of(2024, 06, 23));
eventRepository.save(event);
// then
List<Event> events = eventRepository.findByDate(LocalDate.of(2024, 06, 23));
assertFalse(events.isEmpty());
assertEquals(expect, events.get(0).getTitle());
}
}
@Controller
public class CalenderController {
@Autowired
private EventRepository eventRepository;
@GetMapping("/calender")
public String getCalender(Model model) {
List<Event> events = eventRepository.findAll();
model.addAttribute("events", events);
return "calender";
}
@PostMapping("/add-event")
public String addEvent(@RequestParam String title, @RequestParam String date) {
Event event = new Event();
event.setTitle(title);
event.setDate(LocalDate.parse(date));
eventRepository.save(event);
return "redirect:/calender";
}
}
@SpringBootTest
@AutoConfigureMockMvc
class CalenderControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private EventRepository eventRepository;
@BeforeEach
void setUp() {
eventRepository.deleteAll();
}
@Test
public void testGetCalender() throws Exception {
mockMvc.perform(get("/calender"))
.andExpect(status().isOk())
.andExpect(view().name("calender"));
}
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Family Scheduler</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h1>Family Scheduler</h1>
<form method="post" action="/add-event">
<div class="form-group">
<label for="title">Event Title:</label>
<input type="text" id="title" name="title" class="form-control" required>
</div>
<div class="form-group">
<label for="date">Date:</label>
<input type="date" id="date" name="date" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary">Add Event</button>
</form>
<h2>Upcoming Events</h2>
<ul>
<li th:each="event : ${events}">
<span th:text="${event.title}"></span> on
<span th:text="${event.date}"></span>
</li>
</ul>
</div>
</body>
</html>
UI 변경
시도한 것들 목록
결국 AWS EC2를 통해 배포에 성공하고 시연 데모를 제작했습니다
배포 과정은
1. EC2 인스턴스 생성
보안그룹이란?
AWS 에서 제공하는 방화벽으로 인바운드 규칙, 아웃바운드 규칙이 존재합니다.
인바운드 규칙(inbound) : 외부에서 EC2나 RDS 등의 내부로 접근할때 사용되는 방화벽 규칙
아웃바운드 규칙(outbound) : EC2나 RDS 등의 내부에서 외부로 접근할때 사용되는 방화벽 규칙
EC2에 접속해서 서버를 띄우는것이 목적이기 때문에 인바운드 규칙만 설정했습니다

스프링 부트 기반 서버를 열어줄것이기 때문에 사용자 지정으로 8080 포트를 설정해준 뒤 url을 아는 누구나 접속할수있도록 Anywhere-IPv4 로 설정해줍니다.
원격 EC2 인스턴스에 접속할때 사용되는 ssh 관련 방화벽으로 저는 밖에서도 접속할 때가 있으므로 저희집 고정 ip가 아닌 Anywhere-IPv4 로 설정했습니다. 또한 ssh는 기본 포트 연결로 22번 포트가 사용됩니다.
HTTP 연결시 사용됩니다.
HTTPS 연결시 사용됩니다
ssh 디렉토리 터미널에서 권한 설정
chmod 400 sshKey.pem
접속
ssh -i "sshKey.pem" ubuntu@ec2-43-201-104-83.ap-northeast-2.compute.amazonaws.com
이 과정에서 타임아웃 에러가 계속 나와서 아주 많이 고생했습니다..
EC2 git clone 하기 구글 검색시 명령어로 yum을 사용하라는 블로그 글이 많이 나오는데
ubuntu로 진행하는 경우 apt를 사용해야합니다
yum은 Linux 명령어로 보통 리눅스로 많이 EC2를 사용해서 그런 블로그 글이 많은 것 같습니다.
이 글을 보시는 분들은 참고하시기 바랍니다.
6-1. git 설치
sudo apt-get install git
체크
git --version
6-2. 깃헙에서 SSH KEY 생성
cd ~/.ssh ssh-keygen -t rsa -C github계정 메일(example@github.com)
cat id_rsa.pubid_rsa.pub 값 저장
git clone ssh 탭 복사한 값sudo apt install openjdk-17-jdkjava --version./gradlew buildcd build/libs 로 이동nohup java -jar woorinature-0.0.1-SNAPSHOT.jar &cat nohup.out으로 nohup.out 파일 출력 로그를 확인할 수 있습니다jobs로 현재 백그라운드에서 돌아가고 있는 파일을 확인한뒤fg %(인덱스)로 벡그라운드에 돌아가고 있는 프로그램을 가져올 수 있습니다.브라우저 URL로 접속
결과 : 유저와의 만남