스프링 프로젝트 주제
여행 정보 공유 웹 애플리케이션 제작
국내를 포함한 각 국가의 교통, 숙소, 맛집 등의 정보를 공유하고 블로그 형식으로
각자의 여행 후기를 업로드 할 수 있는 사이트 제작
주제 선정 이유
- 코로나로 인하여 장기간 해외여행 금지로 내외국인들의 여행 욕구가 커짐으로써
위드 코로나와 함께 해외여행 수요가 급증할 것으로 예상 - 현재 여행 정보 공유를 목적으로 하는 웹 플랫폼의 공급이 수요만큼 활발하지 않다고
생각되어 기획 결정
목표
- Spring Framwork와 Mybatis Framwork 사용
- MVC 패턴을 기반으로 2-Laryered 아키텍처로 구현
- Ajax를 활용한 비동기 방식으로 데이터 처리
- Git을 활용한 형상 관리 경험
- Spring Boot로 마이그레이션
주요 기능
- CKEditor5 라이브러리를 이용하여 게시글 CRUD 구현
- 특정 게시글 검색 기능, 각 게시글에 대한 댓글 및 찜 기능
- 구글 지도 API 활용
- + 카카오/네이버 계정 로그인 API 활용 (추가 예정)
개발 환경
- Language : JAVA (Eclipse)
- Server : Apache Tomcat
- DBMS : Oracle
- Version Control : GitHub
- Framwork : Spring Boot / Mybatis
- Front-End : JSP / Java Script / jQuery / CSS
개발 일정
ERD
각 테이블은 참조되지 않고 트랜잭션 처리
ex) 게시글 삭제 시 해당 게시글의 댓글 및 찜 데이터 모두 트랜잭션으로 delete 처리
User Flow & Logic Process
페이지 별 기능 및 코드 설명
1. 메인 페이지
- 구글 지도 API를 활용하여 마커 클릭 시 해당 국가의 후기 게시판으로 이동
2. 사이드 메뉴 바
- DB에 저장된 카테고리 데이터를 Session 단위로 저장 및 커스텀 태그를 이용하여 모든 화면에 출력
- 상위 카테고리 FOR WANDERIER (여행지 추천 게시판) / 여행 정보 게시판 / 자유 질문 게시판 / 여행 후기 게시판
- FOR WANDERIER / 자유 질문 게시판 클릭 시 해당 게시판으로 이동
- 여행 정보 게시판 / 여행 후기 게시판 클릭 시 해당 하위 카테고리 목록이 아코디언 형식으로 펼쳐짐
3. 로그인 / 회원가입 페이지
- Ajax를 이용하여 데이터 요청 및 응답 처리
- 회원가입 시 JS / jQuery로 모든 입력 값에 대한 유효성 검사를 실시간으로 진행
- 커스텀 태그를 활용하여 로그인 시 우측 상단의 [LOGIN] 버튼이 [MY PAGE] [LOGOUT] 버튼으로 변경
4. 마이페이지
- 비밀번호를 제외한 회원의 아이디 / 이메일 / 휴대폰 번호 출력
- 비밀번호 입력 후 회원 정보 수정 페이지로 이동
- 아이디를 제외한 나머지 정보 수정 가능
- 정보 수정 시 회원가입과 동일하게 실시간 유효성 검사 실행
5-1. FOR WANDERIER (여행지 추천 게시판)
- 관리자계정(admin)만 CRUD가 가능하며 일반 사용자들은 게시글 읽기 및 찜 기능만 가능
5-2. 자유 질문 게시판 / 정보 공유 게시판 / 여행 후기 게시판
- 각 카테고리에 해당하는 게시글이 한 페이지 당 10개의 리스트로 출력
- 제목, 내용, 작성자 기준으로 특정 게시글 검색 가능
- 정보 공유 게시판 / 여행 후기 게시판의 경우 우측 Select Box의 옵션 선택 시 해당 페이지로 이동
- 각 게시글의 제목 클릭 시 해당 게시글 페이지로 이동
6. 게시글 읽기 페이지
- 로그인 계정과 작성자의 계정이 일치하는 경우 제목 우측에 수정 / 삭제 버튼 활성화
- 계정이 일치하지 않는 경우 찜 기능 활성화 및 댓글 작성, 새 글 작성하기 가능
- 비로그인 시 읽기만 가능
찜 기능
- 🤍를 클릭하면 🖤로 변경됨 (찜 취소 시 반대로 적용)
- Ajax와 REST API를 활용한 비동기 방식으로 데이터 처리
7-1. 일반 유저 게시글 수정 / 작성 페이지
- CKEditor5 라이브러리를 이용하여 실제 블로그와 유사한 게시글 작성 및 파일 업로드 가능
- 게시글 수정 시 DB에 저장되어 있는 해당 게시글의 데이터 출력
@Controller
public class FileManageController {
@ResponseBody
@RequestMapping(value="/fileupload.do")
public String uploadFile (@RequestParam Map<String, Object> map, MultipartHttpServletRequest request) throws JsonProcessingException {
List<MultipartFile> fileList = request.getFiles("upload"); // 파일 가져오기
HashMap<String, Object> res = new HashMap<String, Object>(); // 업로드 결과, 이미지 저장 경로 저장할 맵
ObjectMapper mappper = new ObjectMapper();
String jsonStr = ""; // 맵에 저장되어 있는 데이터를 json 형식의 string 타입으로 변환하여 저장할 변수
String imgPath = null;
String savePath = request.getSession().getServletContext().getRealPath("/images/upload/"); // 실제 저장되는 경로
String loadPath = "/images/upload/"; // 서버 상의 경로 - 서버에서 파일에 접근하는 경로, 저장 디렉토리
for (MultipartFile mf : fileList) {
if (fileList.get(0).getSize() > 0) {
String originFileNme = mf.getOriginalFilename(); // 실제 파일명
String ext = FilenameUtils.getExtension(originFileNme); // 실제 파일의 확장자명
String newInfImgFileName = "img_" + UUID.randomUUID() + "." + ext; // 파일명 중복 방지
imgPath = loadPath + newInfImgFileName; // 파일 접근 경로
File file = new File(savePath + newInfImgFileName); // 실제 저장되는 파일 경로 지정
try {
mf.transferTo(file); // 실제 파일로 이동
} catch (IllegalStateException e) {
e.printStackTrace();
res.put("uploaded", false);
jsonStr = mappper.writeValueAsString(res);
return jsonStr;
} catch (IOException e) {
e.printStackTrace();
res.put("uploaded", false);
jsonStr = mappper.writeValueAsString(res); // writeValueAsString : 자바스크립트에 json을 넘겨줄 때 사용
return jsonStr;
}
}
}
res.put("uploaded", true);
res.put("url", imgPath);
jsonStr = mappper.writeValueAsString(res);
return jsonStr;
}
}
Controller
7-2. 관리자 계정 게시글 수정 / 작성 페이지
- 일반 유저 게시글과 동일하며 추가적으로 게시글 목록 출력 시 보여질 썸네일 이미지 저장 및 미리보기 기능 구현
@RequestMapping("/insertAdminBoard.do")
public String insertAdminBoard(HttpSession session, HttpServletRequest request, AdminBoardVO vo) throws IllegalStateException, IOException {
vo.setId((String) session.getAttribute("sessionID"));
String imgPath = null;
String savePath = request.getSession().getServletContext().getRealPath("/images/preview/"); // 실제 저장되는 경로
String loadPath = "/images/preview/"; // 서버 상의 경로 - 서버에서 파일에 접근하는 경로, 저장 디렉토리
MultipartFile fileUpload = vo.getFileUpload(); // 파일 가져오기
if (!fileUpload.isEmpty()) {
String originFileNme = fileUpload.getOriginalFilename(); // 실제 파일명
String ext = FilenameUtils.getExtension(originFileNme); // 실제 파일의 확장자명
String newInfImgFileName = "img_" + UUID.randomUUID() + "." + ext; // 파일 중복 방지
imgPath = loadPath + newInfImgFileName; // 파일 접근 경로
vo.setImg_path(imgPath);
File file = new File(savePath + newInfImgFileName); // 실제 저장되는 파일 경로 지정
fileUpload.transferTo(file);
boardService.insertBoard(vo);
}
return "redirect:/getAdminBoardList.do";
}
Controller
개선 사항
관리자 계정 전용 페이지 제작 - 카테고리 추가/삭제/수정 기능
국내, 아시아, 미주 등 nation category 추가
Spring Boot로 이관 작업 하기(완료)
네이버/카카오 계정 로그인 API 활용하기
느낀점
교육받으면서 처음이자 마지막으로 진행하는 개인 프로젝트였는데 시간도 넉넉치 않았고
MVC를 혼자서 모두 구현해야 했기 때문에 일단은 CRUD만 확실하게 구현하는 것을 목표로 했다.
CKEditor 라이브러리를 사용하는 과정이 - 이미지 저장이 되지 않는 문제 - 녹록지는 않았으나
열심히 구글링 해보고 이것저것 시도해 본 끝에 문제없이 CRUD를 구현해낼 수 있었다.
하다 보니 욕심이 생겨 이것저것 몇 가지 기능을 더 추가하고 싶은 사항들이 계속 생겼지만..
발표까지 시간이 여유롭지 않아 우선 개선 사항으로 남겨뒀다.
(우선은 기한 내에 완성하는 것이 중요하므로..! 위에 써놓고 보니 너무 많네요.. )
아직 100% 마음에 들지는 않지만 그래도 혼자 힘으로 완성했다는 것에 의의를 두기로!
교육이 끝난 후 개인적인 사정으로 프로젝트 develop을 잠시 멈춰뒀었지만
이제는 여유가 생겼으니 취업 준비하면서 공부 겸 개선을 좀 해야겠다!
현재 팀원들과 함께 스터디로 스프링 부트를 공부하고 있고, 해당 프로젝트를 부트로 마이그레이션 할 계획이다.
나머지 사항들도 차근차근 개선해 나가야겠다!
Git : https://github.com/sngynhy/springproject
Git : https://github.com/sngynhy/springboot (Spring Boot Migration)
'PROJECT' 카테고리의 다른 글
[React] 넷플릭스 클론 프로젝트 [2] - 기술 및 도구 (0) | 2025.01.22 |
---|---|
[React] 넷플릭스 클론 프로젝트 [1] - 들어가며 (0) | 2025.01.20 |
[JAVA] 웹 프로젝트 - 영화 리뷰 웹 사이트 'Film-E' (0) | 2021.10.20 |
[JAVA] 네이버 영화 크롤링하여 DB에 저장하기 (영화 정보 및 리뷰) (0) | 2021.10.01 |
[HTML/CSS/JavaScript/jQuery] 미디어쿼리를 이용한 반응형 웹 제작 - 메뉴바 / Footer (0) | 2021.08.23 |