diff --git a/BE/.gitignore b/BE/.gitignore new file mode 100644 index 000000000..c2065bc26 --- /dev/null +++ b/BE/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/BE/build.gradle b/BE/build.gradle new file mode 100644 index 000000000..727a35a42 --- /dev/null +++ b/BE/build.gradle @@ -0,0 +1,24 @@ +plugins { + id 'org.springframework.boot' version '2.4.5' + id 'io.spring.dependency-management' version '1.0.11.RELEASE' + id 'java' +} + +group = 'com.example' +version = '0.0.1-SNAPSHOT' +sourceCompatibility = '1.8' + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-data-jdbc' + implementation 'org.springframework.boot:spring-boot-starter-web' + runtimeOnly 'mysql:mysql-connector-java' + testImplementation 'org.springframework.boot:spring-boot-starter-test' +} + +test { + useJUnitPlatform() +} diff --git a/BE/gradle/wrapper/gradle-wrapper.jar b/BE/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..e708b1c02 Binary files /dev/null and b/BE/gradle/wrapper/gradle-wrapper.jar differ diff --git a/BE/gradle/wrapper/gradle-wrapper.properties b/BE/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..442d9132e --- /dev/null +++ b/BE/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/BE/gradlew b/BE/gradlew new file mode 100644 index 000000000..4f906e0c8 --- /dev/null +++ b/BE/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/BE/gradlew.bat b/BE/gradlew.bat new file mode 100644 index 000000000..107acd32c --- /dev/null +++ b/BE/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/BE/settings.gradle b/BE/settings.gradle new file mode 100644 index 000000000..aab815121 --- /dev/null +++ b/BE/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'airbnb' diff --git a/BE/src/main/java/airbnb/AirbnbApplication.java b/BE/src/main/java/airbnb/AirbnbApplication.java new file mode 100644 index 000000000..a902aad41 --- /dev/null +++ b/BE/src/main/java/airbnb/AirbnbApplication.java @@ -0,0 +1,12 @@ +package airbnb; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class AirbnbApplication { + + public static void main(String[] args) { + SpringApplication.run(AirbnbApplication.class, args); + } +} diff --git a/BE/src/main/java/airbnb/Service/CategoryService.java b/BE/src/main/java/airbnb/Service/CategoryService.java new file mode 100644 index 000000000..c4fb8c189 --- /dev/null +++ b/BE/src/main/java/airbnb/Service/CategoryService.java @@ -0,0 +1,30 @@ +package airbnb.Service; + +import airbnb.dao.CategoryDao; +import airbnb.domain.Category; +import airbnb.dto.CategoryResponse; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class CategoryService { + + private final CategoryDao categoryDao; + + public CategoryService(CategoryDao categoryDao) { + this.categoryDao = categoryDao; + } + + public List findAll() { + return categoryDao.findAll(); + } + + public List createAllToCategoryResponseList() { + List categories = findAll(); + return categories.stream().map(category -> CategoryResponse.of(category, category.findMainImageUrl())) + .collect(Collectors.toList()); + } +} diff --git a/BE/src/main/java/airbnb/Service/CityService.java b/BE/src/main/java/airbnb/Service/CityService.java new file mode 100644 index 000000000..db6be17e3 --- /dev/null +++ b/BE/src/main/java/airbnb/Service/CityService.java @@ -0,0 +1,32 @@ +package airbnb.Service; + +import airbnb.dao.CityDao; +import airbnb.domain.City; +import airbnb.domain.Location; +import airbnb.dto.CityResponse; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class CityService { + + private final CityDao cityDao; + + public CityService(CityDao cityDao) { + this.cityDao = cityDao; + } + + public List findAll() { + return cityDao.findAll(); + } + + public List createAllToCityResponseList() { + Location codeSquadLocation = new Location(37.491016774047345, 127.03339554026415); + List cities = findAll(); + return cities.stream().map(city -> CityResponse.of(city, city.findMainImageUrl(), codeSquadLocation)) + .collect(Collectors.toList()); + } +} diff --git a/BE/src/main/java/airbnb/Service/ImageService.java b/BE/src/main/java/airbnb/Service/ImageService.java new file mode 100644 index 000000000..f5af04f69 --- /dev/null +++ b/BE/src/main/java/airbnb/Service/ImageService.java @@ -0,0 +1,20 @@ +package airbnb.Service; + +import airbnb.dao.ImageDao; +import airbnb.domain.Image; +import airbnb.domain.ImageType; +import org.springframework.stereotype.Service; + +@Service +public class ImageService { + + private final ImageDao imageDao; + + public ImageService(ImageDao imageDao) { + this.imageDao = imageDao; + } + + public Image findHeroImage() { + return imageDao.findByType(ImageType.HERO.name()).get(0); + } +} diff --git a/BE/src/main/java/airbnb/Service/RoomService.java b/BE/src/main/java/airbnb/Service/RoomService.java new file mode 100644 index 000000000..f59f032db --- /dev/null +++ b/BE/src/main/java/airbnb/Service/RoomService.java @@ -0,0 +1,41 @@ +package airbnb.Service; + +import airbnb.dao.RoomDao; +import airbnb.domain.Room; +import airbnb.dto.PriceRequest; +import airbnb.dto.RoomResponse; +import airbnb.dto.RoomSearchRequest; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class RoomService { + + private final RoomDao roomDao; + + public RoomService(RoomDao roomDao) { + this.roomDao = roomDao; + } + + public List findAllRoomPrice() { + List rooms = findAll(); + return rooms.stream().map(Room::getPrice).sorted().collect(Collectors.toList()); + } + + public List findAll() { + return roomDao.findAll(); + } + + public List findSearchRoomPrice(PriceRequest priceRequest) { + List rooms = roomDao.findByCityIdAndSchedule(priceRequest.getCityId(), priceRequest.getSchedule()); + return rooms.stream().map(Room::getPrice).sorted().collect(Collectors.toList()); + } + + public List SearchRoomToRoomResponseList(RoomSearchRequest roomSearchRequest) { + List rooms = roomDao.findSearchRooms(roomSearchRequest.getCityId(), roomSearchRequest.getSchedule(), + roomSearchRequest.getCost(), roomSearchRequest.getReservationPeopleCount()); + return rooms.stream().map(RoomResponse::of).collect(Collectors.toList()); + } +} diff --git a/BE/src/main/java/airbnb/config/WebConfig.java b/BE/src/main/java/airbnb/config/WebConfig.java new file mode 100644 index 000000000..f715726a0 --- /dev/null +++ b/BE/src/main/java/airbnb/config/WebConfig.java @@ -0,0 +1,16 @@ +package airbnb.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebConfig implements WebMvcConfigurer { + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins("*") + .allowedMethods("GET", "POST"); + } +} + diff --git a/BE/src/main/java/airbnb/controller/HomeController.java b/BE/src/main/java/airbnb/controller/HomeController.java new file mode 100644 index 000000000..80e0983d0 --- /dev/null +++ b/BE/src/main/java/airbnb/controller/HomeController.java @@ -0,0 +1,30 @@ +package airbnb.controller; + +import airbnb.Service.CategoryService; +import airbnb.Service.CityService; +import airbnb.Service.ImageService; +import airbnb.dto.MainPageResponse; +import airbnb.wrapper.MainPageWrapper; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class HomeController { + + private final CityService cityService; + private final CategoryService categoryService; + private final ImageService imageService; + + public HomeController(CityService cityService, CategoryService categoryService, ImageService imageService) { + this.cityService = cityService; + this.categoryService = categoryService; + this.imageService = imageService; + } + + @GetMapping + public MainPageWrapper home() { + MainPageResponse mainPageResponse = MainPageResponse.of(imageService.findHeroImage(), cityService.createAllToCityResponseList(), + categoryService.createAllToCategoryResponseList()); + return new MainPageWrapper(mainPageResponse); + } +} diff --git a/BE/src/main/java/airbnb/controller/RoomController.java b/BE/src/main/java/airbnb/controller/RoomController.java new file mode 100644 index 000000000..2342be331 --- /dev/null +++ b/BE/src/main/java/airbnb/controller/RoomController.java @@ -0,0 +1,37 @@ +package airbnb.controller; + +import airbnb.Service.RoomService; +import airbnb.domain.Room; +import airbnb.dto.PriceRequest; +import airbnb.dto.RoomSearchRequest; +import airbnb.wrapper.PricesWrapper; +import airbnb.wrapper.RoomResponseWrapper; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/rooms") +public class RoomController { + + private final RoomService roomService; + + public RoomController(RoomService roomService) { + this.roomService = roomService; + } + + @GetMapping("/price") + public PricesWrapper readAllRoomPrices() { + return new PricesWrapper(roomService.findAllRoomPrice()); + } + + @PostMapping("/price") + public PricesWrapper readSearchRoomPrices(@RequestBody PriceRequest priceRequest) { + return new PricesWrapper(roomService.findSearchRoomPrice(priceRequest)); + } + + @PostMapping + public RoomResponseWrapper searchRooms(@RequestBody RoomSearchRequest roomSearchRequest) { + return new RoomResponseWrapper(roomService.SearchRoomToRoomResponseList(roomSearchRequest)); + } +} diff --git a/BE/src/main/java/airbnb/dao/CategoryDao.java b/BE/src/main/java/airbnb/dao/CategoryDao.java new file mode 100644 index 000000000..63a6f775e --- /dev/null +++ b/BE/src/main/java/airbnb/dao/CategoryDao.java @@ -0,0 +1,28 @@ +package airbnb.dao; + +import airbnb.domain.Category; +import airbnb.mapper.CategoryMapper; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public class CategoryDao { + + private final JdbcTemplate jdbcTemplate; + private final ImageDao imageDao; + private final CategoryMapper categoryMapper = new CategoryMapper(); + + public CategoryDao(JdbcTemplate jdbcTemplate, ImageDao imageDao) { + this.jdbcTemplate = jdbcTemplate; + this.imageDao = imageDao; + } + + public List findAll() { + String sql = "SELECT id, name FROM category"; + List categories = jdbcTemplate.query(sql, categoryMapper); + categories.forEach(category -> category.setImages(imageDao.findByCategoryId(category.getId()))); + return categories; + } +} diff --git a/BE/src/main/java/airbnb/dao/CityDao.java b/BE/src/main/java/airbnb/dao/CityDao.java new file mode 100644 index 000000000..15e1c3124 --- /dev/null +++ b/BE/src/main/java/airbnb/dao/CityDao.java @@ -0,0 +1,28 @@ +package airbnb.dao; + +import airbnb.domain.City; +import airbnb.mapper.CityMapper; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public class CityDao { + + private final JdbcTemplate jdbcTemplate; + private final ImageDao imageDao; + private final CityMapper cityMapper = new CityMapper(); + + public CityDao(JdbcTemplate jdbcTemplate, ImageDao imageDao) { + this.jdbcTemplate = jdbcTemplate; + this.imageDao = imageDao; + } + + public List findAll() { + String sql = "SELECT id, name, latitude, longitude FROM city"; + List cities = jdbcTemplate.query(sql, cityMapper); + cities.forEach(city -> city.setImages(imageDao.findByCityId(city.getId()))); + return cities; + } +} diff --git a/BE/src/main/java/airbnb/dao/ImageDao.java b/BE/src/main/java/airbnb/dao/ImageDao.java new file mode 100644 index 000000000..aa666d481 --- /dev/null +++ b/BE/src/main/java/airbnb/dao/ImageDao.java @@ -0,0 +1,52 @@ +package airbnb.dao; + +import airbnb.domain.Image; +import airbnb.mapper.ImageMapper; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public class ImageDao { + + private final NamedParameterJdbcTemplate jdbcTemplate; + private final ImageMapper imageMapper = new ImageMapper(); + + public ImageDao(NamedParameterJdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public List findByCityId(Long cityId) { + String sql = "SELECT id, url, room_id, city_id, category_id, image_type FROM image " + + "WHERE city_id = :cityId"; + MapSqlParameterSource parameter = new MapSqlParameterSource(); + parameter.addValue("cityId", cityId); + return jdbcTemplate.query(sql, parameter, imageMapper); + } + + public List findByCategoryId(Long categoryId) { + String sql = "SELECT id, url, room_id, city_id, category_id, image_type FROM image " + + "WHERE category_id = :categoryId"; + MapSqlParameterSource parameter = new MapSqlParameterSource(); + parameter.addValue("categoryId", categoryId); + return jdbcTemplate.query(sql, parameter, imageMapper); + } + + public List findByType(String imageType) { + String sql = "SELECT id, url, room_id, city_id, category_id, image_type FROM image " + + "WHERE image_type = :imageType"; + MapSqlParameterSource parameter = new MapSqlParameterSource(); + parameter.addValue("imageType", imageType); + return jdbcTemplate.query(sql, parameter, imageMapper); + } + + public List findByRoomId(Long roomId) { + String sql = "SELECT id, url, room_id, city_id, category_id, image_type FROM image " + + "WHERE room_id = :roomId ORDER BY FIELD(image_type, 'MAIN', 'DETAIL')"; + MapSqlParameterSource parameter = new MapSqlParameterSource(); + parameter.addValue("roomId", roomId); + return jdbcTemplate.query(sql, parameter, imageMapper); + } +} diff --git a/BE/src/main/java/airbnb/dao/RoomDao.java b/BE/src/main/java/airbnb/dao/RoomDao.java new file mode 100644 index 000000000..99857079f --- /dev/null +++ b/BE/src/main/java/airbnb/dao/RoomDao.java @@ -0,0 +1,79 @@ +package airbnb.dao; + +import airbnb.domain.City; +import airbnb.domain.Cost; +import airbnb.domain.Room; +import airbnb.domain.Schedule; +import airbnb.mapper.ImageMapper; +import airbnb.mapper.RoomMapper; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.stereotype.Repository; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Repository +public class RoomDao { + + private final NamedParameterJdbcTemplate jdbcTemplate; + private final ImageDao imageDao; + private final RoomMapper roomMapper = new RoomMapper(); + private final MapSqlParameterSource parameter = new MapSqlParameterSource(); + + public RoomDao(NamedParameterJdbcTemplate jdbcTemplate, ImageDao imageDao) { + this.jdbcTemplate = jdbcTemplate; + this.imageDao = imageDao; + } + + public List findAll() { + String sql = "SELECT id, price, title, description, people, oneroom, bed, bath, hair_dryer, air_conditioner, wifi, clean_tax FROM room"; + List rooms = jdbcTemplate.query(sql, roomMapper); + rooms.forEach(room -> room.setImages(imageDao.findByRoomId(room.getId()))); + return rooms; + } + + public List findByCityIdAndSchedule(Long cityId, Schedule schedule) { + String sql = "SELECT a.id, price, title, description, people, oneroom, bed, bath, hair_dryer, air_conditioner, wifi, clean_tax FROM room AS a left join reservation AS b ON a.id = b.room_id " + + "WHERE (b.id IS NULL OR ((b.check_in NOT BETWEEN :checkIn AND :checkOut) AND (b.check_out NOT BETWEEN :checkIn AND :checkOut)))" + + "AND (a.city_id = :cityId)"; + LocalDate chekIn = schedule.getCheckIn(); + LocalDate chekOut = schedule.getCheckOut(); + + parameter.addValue("cityId", cityId); + parameter.addValue("checkIn", chekIn); + parameter.addValue("checkOut", chekOut); + + List rooms = jdbcTemplate.query(sql, parameter, roomMapper); + rooms.forEach(room -> room.setImages(imageDao.findByRoomId(room.getId()))); + return rooms; + } + + public List findSearchRooms(Long cityId, Schedule schedule, Cost cost, int reservationPeopleCount) { + String sql = "SELECT a.id, price, title, description, people, oneroom, bed, bath, hair_dryer, air_conditioner, wifi, clean_tax FROM room AS a left join reservation AS b ON a.id = b.room_id " + + "WHERE (b.id IS NULL OR ((b.check_in NOT BETWEEN :checkIn AND :checkOut) AND (b.check_out NOT BETWEEN :checkIn AND :checkOut))) " + + "AND (a.price between :minCost AND :maxCost) " + + "AND (a.people >= :reservationPeopleCount) " + + "AND (a.city_id = :cityId)"; + + LocalDate chekIn = schedule.getCheckIn(); + LocalDate chekOut = schedule.getCheckOut(); + int minCost = cost.getMinCost(); + int maxCost = cost.getMaxCost(); + + parameter.addValue("cityId", cityId); + parameter.addValue("checkIn", chekIn); + parameter.addValue("checkOut", chekOut); + parameter.addValue("minCost", minCost); + parameter.addValue("maxCost", maxCost); + parameter.addValue("reservationPeopleCount", reservationPeopleCount); + + List rooms = jdbcTemplate.query(sql, parameter, roomMapper); + rooms.forEach(room -> room.setImages(imageDao.findByRoomId(room.getId()))); + return rooms; + } +} diff --git a/BE/src/main/java/airbnb/domain/Category.java b/BE/src/main/java/airbnb/domain/Category.java new file mode 100644 index 000000000..aca7bb967 --- /dev/null +++ b/BE/src/main/java/airbnb/domain/Category.java @@ -0,0 +1,40 @@ +package airbnb.domain; + +import org.springframework.data.annotation.Id; + +import java.util.List; + +public class Category { + + @Id + private Long id; + private String name; + private List images; + + public Category(Long id, String name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public List getImages() { + return images; + } + + public void setImages(List images) { + this.images = images; + } + + public String findMainImageUrl() { + Image mainImage = images.stream().filter(image -> ImageType.MAIN.equals(image.getImageType())) + .findFirst().orElseThrow(NullPointerException::new); + return mainImage.getUrl(); + } +} diff --git a/BE/src/main/java/airbnb/domain/City.java b/BE/src/main/java/airbnb/domain/City.java new file mode 100644 index 000000000..ec03d9bfe --- /dev/null +++ b/BE/src/main/java/airbnb/domain/City.java @@ -0,0 +1,51 @@ +package airbnb.domain; + +import org.springframework.data.annotation.Id; +import org.springframework.data.relational.core.mapping.Embedded; + +import java.util.List; + +public class City { + + @Id + private Long id; + private String name; + private List images; + private Location location; + + public City(Long id, String name, Location location) { + this.id = id; + this.name = name; + this.location = location; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public List getImages() { + return images; + } + + public Location getLocation() { + return location; + } + + public void addImage(Image image) { + images.add(image); + } + + public void setImages(List images) { + this.images = images; + } + + public String findMainImageUrl() { + Image mainImage = images.stream().filter(image -> ImageType.MAIN.equals(image.getImageType())) + .findFirst().orElseThrow(NullPointerException::new); + return mainImage.getUrl(); + } +} diff --git a/BE/src/main/java/airbnb/domain/Cost.java b/BE/src/main/java/airbnb/domain/Cost.java new file mode 100644 index 000000000..5c749caac --- /dev/null +++ b/BE/src/main/java/airbnb/domain/Cost.java @@ -0,0 +1,23 @@ +package airbnb.domain; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Cost { + @JsonProperty(value = "max") + private int maxCost; + @JsonProperty(value = "min") + private int minCost; + + public Cost(int maxPrice, int minPrice) { + this.maxCost = maxPrice; + this.minCost = minPrice; + } + + public int getMaxCost() { + return maxCost; + } + + public int getMinCost() { + return minCost; + } +} diff --git a/BE/src/main/java/airbnb/domain/Image.java b/BE/src/main/java/airbnb/domain/Image.java new file mode 100644 index 000000000..ee568f6cc --- /dev/null +++ b/BE/src/main/java/airbnb/domain/Image.java @@ -0,0 +1,75 @@ +package airbnb.domain; + +import org.springframework.data.annotation.Id; + +public class Image { + + @Id + private Long id; + private String url; + private ImageType imageType; + private Long cityId; + private Long roomId; + private Long categoryId; + + private Image(Builder builder) { + this.id = builder.id; + this.url = builder.url; + this.imageType = builder.imageType; + this.cityId = builder.cityId; + this.roomId = builder.roomId; + this.categoryId = builder.categoryId; + } + + public static class Builder { + + private final Long id; + private final String url; + + private ImageType imageType; + private Long cityId; + private Long roomId; + private Long categoryId; + + public Builder(Long id, String url) { + this.id = id; + this.url = url; + } + + public Builder imageType(ImageType imageType) { + this.imageType = imageType; + return this; + } + + public Builder cityId(Long cityId) { + this.cityId = cityId; + return this; + } + + public Builder roomId(Long roomId) { + this.roomId = roomId; + return this; + } + + public Builder categoryId(Long categoryId) { + this.categoryId = categoryId; + return this; + } + + public Image build() { + return new Image(this); + } + } + + public Long getId() { + return id; + } + + public String getUrl() { + return url; + } + + public ImageType getImageType() { + return imageType; + } +} diff --git a/BE/src/main/java/airbnb/domain/ImageType.java b/BE/src/main/java/airbnb/domain/ImageType.java new file mode 100644 index 000000000..05b81bd78 --- /dev/null +++ b/BE/src/main/java/airbnb/domain/ImageType.java @@ -0,0 +1,7 @@ +package airbnb.domain; + +public enum ImageType { + HERO, + MAIN, + DETAIL +} diff --git a/BE/src/main/java/airbnb/domain/Location.java b/BE/src/main/java/airbnb/domain/Location.java new file mode 100644 index 000000000..22bd90a03 --- /dev/null +++ b/BE/src/main/java/airbnb/domain/Location.java @@ -0,0 +1,40 @@ +package airbnb.domain; + +public class Location { + + private double latitude; + private double longitude; + private static final double STRAIGHT_ANGLE = 180.0; + + public Location(double latitude, double longitude) { + this.latitude = latitude; + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public double getLongitude() { + return longitude; + } + + public long calculatorTravelTime(Location location) { + double theta = this.longitude - location.longitude; + double distance = Math.sin(deg2rad(this.latitude)) * Math.sin(deg2rad(location.latitude)) + + Math.cos(deg2rad(this.latitude)) * Math.cos(deg2rad(location.latitude)) * Math.cos(deg2rad(theta)); + return Math.round(convertToKilometer(distance)); + } + + private double deg2rad(double degree) { + return (degree * Math.PI / STRAIGHT_ANGLE); + } + + private double rad2deg(double radian) { + return (radian * STRAIGHT_ANGLE / Math.PI); + } + + private double convertToKilometer(double distance) { + return (rad2deg(Math.acos(distance)) * 60 * 1.1515 * 1.609344); + } +} diff --git a/BE/src/main/java/airbnb/domain/Room.java b/BE/src/main/java/airbnb/domain/Room.java new file mode 100644 index 000000000..02e2d43cf --- /dev/null +++ b/BE/src/main/java/airbnb/domain/Room.java @@ -0,0 +1,114 @@ +package airbnb.domain; + +import org.springframework.data.annotation.Id; + +import java.util.List; + +public class Room { + + @Id + private Long id; + private int price; + private String title; + private String description; + private RoomDetail roomDetail; + private Tax tax; + private List images; + private int maxPeopleCount; + + private Room(Builder builder) { + this.id = builder.id; + this.price = builder.price; + this.title = builder.title; + this.description = builder.description; + this.roomDetail = builder.roomDetail; + this.tax = builder.tax; + this.maxPeopleCount = builder.maxPeopleCount; + } + + public static class Builder { + + private final Long id; + + private int price; + private String title; + private String description; + private RoomDetail roomDetail; + private Tax tax; + private int maxPeopleCount; + + public Builder(Long id) { + this.id = id; + } + + public Builder price(int price) { + this.price = price; + return this; + } + + public Builder title(String title) { + this.title = title; + return this; + } + + public Builder description(String description) { + this.description = description; + return this; + } + + public Builder roomDetail(RoomDetail roomDetail) { + this.roomDetail = roomDetail; + return this; + } + + public Builder tax(Tax tax) { + this.tax = tax; + return this; + } + + public Builder maxPeopleCount(int maxPeopleCount) { + this.maxPeopleCount = maxPeopleCount; + return this; + } + + public Room build() { + return new Room(this); + } + } + + public Long getId() { + return id; + } + + public int getPrice() { + return price; + } + + public String getTitle() { + return title; + } + + public String getDescription() { + return description; + } + + public RoomDetail getRoomDetail() { + return roomDetail; + } + + public Tax getTax() { + return tax; + } + + public List getImages() { + return images; + } + + public int getMaxPeopleCount() { + return maxPeopleCount; + } + + public void setImages(List images) { + this.images = images; + } +} diff --git a/BE/src/main/java/airbnb/domain/RoomDetail.java b/BE/src/main/java/airbnb/domain/RoomDetail.java new file mode 100644 index 000000000..ff63992a0 --- /dev/null +++ b/BE/src/main/java/airbnb/domain/RoomDetail.java @@ -0,0 +1,88 @@ +package airbnb.domain; + +public class RoomDetail { + private boolean oneRoom; + private int bedCount; + private int bathCount; + private boolean hairDryer; + private boolean airConditioner; + private boolean wiFi; + + + public RoomDetail(Builder builder) { + this.oneRoom = builder.oneRoom; + this.bedCount = builder.bedCount; + this.bathCount = builder.bathCount; + this.hairDryer = builder.hairDryer; + this.airConditioner = builder.airConditioner; + this.wiFi = builder.wiFi; + } + + public static class Builder { + private boolean oneRoom; + private int bedCount; + private int bathCount; + private boolean hairDryer; + private boolean airConditioner; + private boolean wiFi; + + + public Builder oneRoom(boolean oneRoom) { + this.oneRoom = oneRoom; + return this; + } + + public Builder bedCount(int bedCount) { + this.bedCount = bedCount; + return this; + } + + public Builder bathCount(int bathCount) { + this.bathCount = bathCount; + return this; + } + + public Builder hairDryer(boolean hairDryer) { + this.hairDryer = hairDryer; + return this; + } + + public Builder airConditioner(boolean airConditioner) { + this.airConditioner = airConditioner; + return this; + } + + public Builder wiFi(boolean wiFi) { + this.wiFi = wiFi; + return this; + } + + public RoomDetail build() { + return new RoomDetail(this); + } + } + + public boolean isOneRoom() { + return oneRoom; + } + + public int getBedCount() { + return bedCount; + } + + public int getBathCount() { + return bathCount; + } + + public boolean isHairDryer() { + return hairDryer; + } + + public boolean isAirConditioner() { + return airConditioner; + } + + public boolean isWiFi() { + return wiFi; + } +} diff --git a/BE/src/main/java/airbnb/domain/Schedule.java b/BE/src/main/java/airbnb/domain/Schedule.java new file mode 100644 index 000000000..d5648f521 --- /dev/null +++ b/BE/src/main/java/airbnb/domain/Schedule.java @@ -0,0 +1,22 @@ +package airbnb.domain; + +import java.time.LocalDate; + +public class Schedule { + + private final LocalDate checkIn; + private final LocalDate checkOut; + + public Schedule(LocalDate checkIn, LocalDate checkOut) { + this.checkIn = checkIn; + this.checkOut = checkOut; + } + + public LocalDate getCheckIn() { + return checkIn; + } + + public LocalDate getCheckOut() { + return checkOut; + } +} diff --git a/BE/src/main/java/airbnb/domain/Tax.java b/BE/src/main/java/airbnb/domain/Tax.java new file mode 100644 index 000000000..1a9d84b9e --- /dev/null +++ b/BE/src/main/java/airbnb/domain/Tax.java @@ -0,0 +1,29 @@ +package airbnb.domain; + +public class Tax { + private int cleanTax; + private int serviceTax; + private int accommodationTax; + + public Tax(int cleanTax, int serviceTax, int accommodationTax) { + this.cleanTax = cleanTax; + this.serviceTax = serviceTax; + this.accommodationTax = accommodationTax; + } + + public int getCleanTax() { + return cleanTax; + } + + public int getServiceTax() { + return serviceTax; + } + + public int getAccommodationTax() { + return accommodationTax; + } + + public static Tax of(int cleanTax, int price) { + return new Tax(cleanTax, (int) Math.round(price * 0.15), (int) Math.round(price * 0.015)); + } +} diff --git a/BE/src/main/java/airbnb/dto/CategoryResponse.java b/BE/src/main/java/airbnb/dto/CategoryResponse.java new file mode 100644 index 000000000..fd39e2c81 --- /dev/null +++ b/BE/src/main/java/airbnb/dto/CategoryResponse.java @@ -0,0 +1,60 @@ +package airbnb.dto; + +import airbnb.domain.Category; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class CategoryResponse { + + @JsonIgnore + private final Long id; + + @JsonProperty(value = "Category") + private final String name; + private final String image; + + private CategoryResponse(Builder builder) { + this.id = builder.id; + this.name = builder.name; + this.image = builder.image; + } + + public static class Builder { + + private final Long id; + private final String name; + + private String image; + + public Builder(Long id, String name) { + this.id = id; + this.name = name; + } + + public Builder image(String image) { + this.image = image; + return this; + } + + public CategoryResponse build() { + return new CategoryResponse(this); + } + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getImage() { + return image; + } + + public static CategoryResponse of(Category category, String imageUrl) { + return new CategoryResponse.Builder(category.getId(), category.getName()) + .image(imageUrl).build(); + } +} diff --git a/BE/src/main/java/airbnb/dto/CityResponse.java b/BE/src/main/java/airbnb/dto/CityResponse.java new file mode 100644 index 000000000..cd9dab5d2 --- /dev/null +++ b/BE/src/main/java/airbnb/dto/CityResponse.java @@ -0,0 +1,71 @@ +package airbnb.dto; + +import airbnb.domain.City; +import airbnb.domain.Location; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class CityResponse { + + private final Long id; + private final String name; + private final String image; + + @JsonProperty(value = "distance") + private final long travelTime; + + private CityResponse(Builder builder) { + this.id = builder.id; + this.name = builder.name; + this.image = builder.image; + this.travelTime = builder.travelTime; + } + + public static class Builder { + + private final Long id; + private final String name; + + private String image; + private long travelTime; + + public Builder(Long id, String name) { + this.id = id; + this.name = name; + } + + public Builder image(String image) { + this.image = image; + return this; + } + + public Builder travelTime(long travelTime) { + this.travelTime = travelTime; + return this; + } + + public CityResponse build() { + return new CityResponse(this); + } + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getImage() { + return image; + } + + public long getTravelTime() { + return travelTime; + } + + public static CityResponse of(City city, String imageUrl, Location location) { + return new Builder(city.getId(), city.getName()) + .image(imageUrl).travelTime(location.calculatorTravelTime(city.getLocation())).build(); + } +} diff --git a/BE/src/main/java/airbnb/dto/Host.java b/BE/src/main/java/airbnb/dto/Host.java new file mode 100644 index 000000000..57fde20d2 --- /dev/null +++ b/BE/src/main/java/airbnb/dto/Host.java @@ -0,0 +1,4 @@ +package airbnb.dto; + +public class Host { +} diff --git a/BE/src/main/java/airbnb/dto/ImageResponse.java b/BE/src/main/java/airbnb/dto/ImageResponse.java new file mode 100644 index 000000000..86ba12578 --- /dev/null +++ b/BE/src/main/java/airbnb/dto/ImageResponse.java @@ -0,0 +1,29 @@ +package airbnb.dto; + +import airbnb.domain.Image; +import airbnb.domain.ImageType; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; +import java.util.stream.Collectors; + +public class ImageResponse { + + @JsonProperty(value = "mainImage") + private String mainImageUrl; + + @JsonProperty(value = "detailImage") + private List detailImageUrls; + + private ImageResponse(String mainImageUrl, List detailImageUrls) { + this.mainImageUrl = mainImageUrl; + this.detailImageUrls = detailImageUrls; + } + + public static ImageResponse of(List images) { + String mainImageUrl = images.stream().filter(image -> ImageType.MAIN.equals(image.getImageType())).findFirst() + .orElseThrow(NullPointerException::new).getUrl(); + List imageUrls = images.stream().map(Image::getUrl).collect(Collectors.toList()); + return new ImageResponse(mainImageUrl, imageUrls); + } +} diff --git a/BE/src/main/java/airbnb/dto/MainPageResponse.java b/BE/src/main/java/airbnb/dto/MainPageResponse.java new file mode 100644 index 000000000..bfac5f614 --- /dev/null +++ b/BE/src/main/java/airbnb/dto/MainPageResponse.java @@ -0,0 +1,34 @@ +package airbnb.dto; + +import airbnb.domain.Image; + +import java.util.List; + +public class MainPageResponse { + + private final String heroImage; + private final List cities; + private final List categories; + + private MainPageResponse(String heroImage, List cities, List categories) { + this.heroImage = heroImage; + this.cities = cities; + this.categories = categories; + } + + public String getHeroImage() { + return heroImage; + } + + public List getCities() { + return cities; + } + + public List getCategories() { + return categories; + } + + public static MainPageResponse of(Image heroImage, List cities, List categories) { + return new MainPageResponse(heroImage.getUrl(), cities, categories); + } +} diff --git a/BE/src/main/java/airbnb/dto/PriceRequest.java b/BE/src/main/java/airbnb/dto/PriceRequest.java new file mode 100644 index 000000000..21bb79dd6 --- /dev/null +++ b/BE/src/main/java/airbnb/dto/PriceRequest.java @@ -0,0 +1,22 @@ +package airbnb.dto; + +import airbnb.domain.Schedule; + +public class PriceRequest { + + private final Long cityId; + private final Schedule schedule; + + public PriceRequest(Long cityId, Schedule schedule) { + this.cityId = cityId; + this.schedule = schedule; + } + + public Long getCityId() { + return cityId; + } + + public Schedule getSchedule() { + return schedule; + } +} diff --git a/BE/src/main/java/airbnb/dto/RoomResponse.java b/BE/src/main/java/airbnb/dto/RoomResponse.java new file mode 100644 index 000000000..b0ab88a7f --- /dev/null +++ b/BE/src/main/java/airbnb/dto/RoomResponse.java @@ -0,0 +1,158 @@ +package airbnb.dto; + +import airbnb.domain.Room; +import airbnb.domain.RoomDetail; +import airbnb.domain.Tax; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class RoomResponse { + + private final Long roomId; + private final int price; + private final String title; + private final String description; + private final Host host; + private final ImageResponse images; + private final int grade; + private final int reviewCount; + private final Tax tax; + + @JsonProperty(value = "people") + private final int maxPeopleCount; + + @JsonProperty(value = "detail") + private final RoomDetail roomDetail; + + private RoomResponse(Builder builder) { + this.roomId = builder.roomId; + this.price = builder.price; + this.title = builder.title; + this.description = builder.description; + this.host = builder.host; + this.images = builder.images; + this.grade = builder.grade; + this.reviewCount = builder.reviewCount; + this.tax = builder.tax; + this.roomDetail = builder.roomDetail; + this.maxPeopleCount = builder.maxPeopleCount; + } + + public static class Builder { + private Long roomId; + private int price; + private String title; + private String description; + private ImageResponse images; + private int grade; + private int reviewCount; + private Tax tax; + private Host host; + private RoomDetail roomDetail; + private int maxPeopleCount; + + public Builder roomId(Long roomId) { + this.roomId = roomId; + return this; + } + + public Builder price(int price) { + this.price = price; + return this; + } + + public Builder title(String title) { + this.title = title; + return this; + } + + public Builder description(String description) { + this.description = description; + return this; + } + + public Builder images(ImageResponse images) { + this.images = images; + return this; + } + + public Builder grade(int grade) { + this.grade = grade; + return this; + } + + public Builder reviewCount(int reviewCount) { + this.reviewCount = reviewCount; + return this; + } + + public Builder tax(Tax tax) { + this.tax = tax; + return this; + } + + public Builder host(Host host) { + this.host = host; + return this; + } + + public Builder roomDetail(RoomDetail roomDetail) { + this.roomDetail = roomDetail; + return this; + } + + public Builder maxPeopleCount(int maxPeopleCount) { + this.maxPeopleCount = maxPeopleCount; + return this; + } + + public RoomResponse build() { + return new RoomResponse(this); + } + } + + public Long getRoomId() { + return roomId; + } + + public int getPrice() { + return price; + } + + public String getTitle() { + return title; + } + + public String getDescription() { + return description; + } + + public Host getHost() { + return host; + } + + public ImageResponse getImages() { + return images; + } + + public int getGrade() { + return grade; + } + + public int getReviewCount() { + return reviewCount; + } + + public Tax getTax() { + return tax; + } + + public RoomDetail getRoomDetail() { + return roomDetail; + } + + public static RoomResponse of(Room room) { + return new Builder().roomId(room.getId()).price(room.getPrice()).title(room.getTitle()) + .description(room.getDescription()).maxPeopleCount(room.getMaxPeopleCount()).tax(room.getTax()) + .roomDetail(room.getRoomDetail()).images(ImageResponse.of(room.getImages())).build(); + } +} diff --git a/BE/src/main/java/airbnb/dto/RoomSearchRequest.java b/BE/src/main/java/airbnb/dto/RoomSearchRequest.java new file mode 100644 index 000000000..2aaa3d4b8 --- /dev/null +++ b/BE/src/main/java/airbnb/dto/RoomSearchRequest.java @@ -0,0 +1,40 @@ +package airbnb.dto; + +import airbnb.domain.Cost; +import airbnb.domain.Schedule; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class RoomSearchRequest { + + private final Long cityId; + private final Schedule schedule; + + @JsonProperty(value = "price") + private final Cost cost; + + @JsonProperty(value = "people") + private final int reservationPeopleCount; + + public RoomSearchRequest(Long cityId, int reservationPeopleCount, Schedule schedule, Cost cost) { + this.cityId = cityId; + this.reservationPeopleCount = reservationPeopleCount; + this.schedule = schedule; + this.cost = cost; + } + + public Long getCityId() { + return cityId; + } + + public int getReservationPeopleCount() { + return reservationPeopleCount; + } + + public Schedule getSchedule() { + return schedule; + } + + public Cost getCost() { + return cost; + } +} diff --git a/BE/src/main/java/airbnb/mapper/CategoryMapper.java b/BE/src/main/java/airbnb/mapper/CategoryMapper.java new file mode 100644 index 000000000..587843d26 --- /dev/null +++ b/BE/src/main/java/airbnb/mapper/CategoryMapper.java @@ -0,0 +1,15 @@ +package airbnb.mapper; + +import airbnb.domain.Category; +import org.springframework.jdbc.core.RowMapper; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class CategoryMapper implements RowMapper { + + @Override + public Category mapRow(ResultSet rs, int rowNum) throws SQLException { + return new Category(rs.getLong("id"), rs.getString("name")); + } +} diff --git a/BE/src/main/java/airbnb/mapper/CityMapper.java b/BE/src/main/java/airbnb/mapper/CityMapper.java new file mode 100644 index 000000000..a340815a9 --- /dev/null +++ b/BE/src/main/java/airbnb/mapper/CityMapper.java @@ -0,0 +1,17 @@ +package airbnb.mapper; + +import airbnb.domain.City; +import airbnb.domain.Location; +import org.springframework.jdbc.core.RowMapper; + +import java.sql.ResultSet; +import java.sql.SQLException; + + +public class CityMapper implements RowMapper { + + @Override + public City mapRow(ResultSet rs, int rowNum) throws SQLException { + return new City(rs.getLong("id"), rs.getString("name"), new Location(rs.getDouble("latitude"), rs.getDouble("longitude"))); + } +} diff --git a/BE/src/main/java/airbnb/mapper/ImageMapper.java b/BE/src/main/java/airbnb/mapper/ImageMapper.java new file mode 100644 index 000000000..8de553a95 --- /dev/null +++ b/BE/src/main/java/airbnb/mapper/ImageMapper.java @@ -0,0 +1,21 @@ +package airbnb.mapper; + +import airbnb.domain.Image; +import airbnb.domain.ImageType; +import org.springframework.jdbc.core.RowMapper; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class ImageMapper implements RowMapper { + + @Override + public Image mapRow(ResultSet rs, int rowNum) throws SQLException { + return new Image.Builder(rs.getLong("id"), rs.getString("url")) + .imageType(ImageType.valueOf(rs.getString("image_type"))) + .cityId(rs.getLong("city_id")) + .roomId(rs.getLong("room_id")) + .categoryId(rs.getLong("category_id")) + .build(); + } +} diff --git a/BE/src/main/java/airbnb/mapper/RoomMapper.java b/BE/src/main/java/airbnb/mapper/RoomMapper.java new file mode 100644 index 000000000..56c1cbe93 --- /dev/null +++ b/BE/src/main/java/airbnb/mapper/RoomMapper.java @@ -0,0 +1,22 @@ +package airbnb.mapper; + +import airbnb.domain.*; +import org.springframework.jdbc.core.RowMapper; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class RoomMapper implements RowMapper { + @Override + public Room mapRow(ResultSet rs, int rowNum) throws SQLException { + return new Room.Builder(rs.getLong("id")).price(rs.getInt("price")) + .title(rs.getString("title")).description(rs.getString("description")).maxPeopleCount(rs.getInt("people")) + .roomDetail(createRoomDetail(rs)).tax(Tax.of(rs.getInt("clean_tax"), rs.getInt("price"))).build(); + } + + private RoomDetail createRoomDetail(ResultSet rs) throws SQLException { + return new RoomDetail.Builder().oneRoom(rs.getBoolean("oneRoom")).bedCount(rs.getInt("bed")).bathCount(rs.getInt("bath")) + .hairDryer(rs.getBoolean("hair_dryer")).airConditioner(rs.getBoolean("air_conditioner")) + .wiFi(rs.getBoolean("wifi")).build(); + } +} diff --git a/BE/src/main/java/airbnb/wrapper/MainPageWrapper.java b/BE/src/main/java/airbnb/wrapper/MainPageWrapper.java new file mode 100644 index 000000000..cffda5aac --- /dev/null +++ b/BE/src/main/java/airbnb/wrapper/MainPageWrapper.java @@ -0,0 +1,16 @@ +package airbnb.wrapper; + +import airbnb.dto.MainPageResponse; + +public class MainPageWrapper { + + private MainPageResponse mainPageResponse; + + public MainPageWrapper(MainPageResponse mainPageResponse) { + this.mainPageResponse = mainPageResponse; + } + + public MainPageResponse getMainPage() { + return mainPageResponse; + } +} diff --git a/BE/src/main/java/airbnb/wrapper/PricesWrapper.java b/BE/src/main/java/airbnb/wrapper/PricesWrapper.java new file mode 100644 index 000000000..e7d15c11c --- /dev/null +++ b/BE/src/main/java/airbnb/wrapper/PricesWrapper.java @@ -0,0 +1,16 @@ +package airbnb.wrapper; + +import java.util.List; + +public class PricesWrapper { + + private List prices; + + public PricesWrapper(List prices) { + this.prices = prices; + } + + public List getPrices() { + return prices; + } +} diff --git a/BE/src/main/java/airbnb/wrapper/RoomResponseWrapper.java b/BE/src/main/java/airbnb/wrapper/RoomResponseWrapper.java new file mode 100644 index 000000000..3c5e1485c --- /dev/null +++ b/BE/src/main/java/airbnb/wrapper/RoomResponseWrapper.java @@ -0,0 +1,18 @@ +package airbnb.wrapper; + +import airbnb.dto.RoomResponse; + +import java.util.List; + +public class RoomResponseWrapper { + + private List rooms; + + public RoomResponseWrapper(List rooms) { + this.rooms = rooms; + } + + public List getRooms() { + return rooms; + } +} diff --git a/BE/src/main/resources/application.properties b/BE/src/main/resources/application.properties new file mode 100644 index 000000000..f173bdc68 --- /dev/null +++ b/BE/src/main/resources/application.properties @@ -0,0 +1,6 @@ +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +spring.datasource.url=jdbc:mysql://localhost:3306/airbnb +spring.datasource.username=root +spring.datasource.password=password +logging.level.baseball.*=debug +logging.level.org.springframework.jdbc.*=trace diff --git a/BE/src/main/resources/data.sql b/BE/src/main/resources/data.sql new file mode 100644 index 000000000..a4e3d4fa8 --- /dev/null +++ b/BE/src/main/resources/data.sql @@ -0,0 +1,110 @@ +INSERT INTO city(name) +values ('서울'),('경기도'),('강원도'),('충청도'),('경상남도'),('경상북도'),('전라남도'),('전라북도'); + +INSERT INTO image_type(type) +values ('HERO'),('MAIN'),('DETAIL'); + +INSERT INTO category(name) +values ('자연생활을 만끽 할 수 있는 숙소'),('독특한 공간'),('집 전체'),('반려 동물과 함께 할 수 있는 공간'); + +INSERT INTO image(url,image_type) +values ('https://a0.muscache.com/im/pictures/ddc7f01f-3fb3-483c-87e6-701dad52c930.jpg?im_w=1920', 'HERO'); + +INSERT INTO image(url,image_type,city_id) +values ('https://a0.muscache.com/im/pictures/71e23854-a3c7-491c-b715-6e86233a293f.jpg?im_q=medq&im_w=240','MAIN',1), + ('https://a0.muscache.com/im/pictures/a0eb36e7-b468-4c5e-93b2-819e793563b2.jpg?im_q=medq&im_w=240','MAIN',2), + ('https://a0.muscache.com/im/pictures/926d56aa-8b36-4138-8eae-ad991868b858.jpg?im_q=medq&im_w=240','MAIN',3), + ('https://a0.muscache.com/im/pictures/f7736f4a-f8b9-4527-b46c-d0d8df856984.jpg?im_q=medq&im_w=240','MAIN',4), + ('https://a0.muscache.com/im/pictures/31e445ed-8b69-477b-aefd-d04dae6d0bb1.jpg?im_q=medq&im_w=240','MAIN',5), + ('https://a0.muscache.com/im/pictures/087a8dff-a609-4084-86db-f45051c6f23a.jpg?im_q=medq&im_w=240','MAIN',6), + ('https://a0.muscache.com/im/pictures/558a403a-aeed-4829-83a6-c9b0ccf21866.jpg?im_q=medq&im_w=240','MAIN',7), + ('https://a0.muscache.com/im/pictures/a161fb95-6875-4aaa-aecd-3a46dead3220.jpg?im_q=medq&im_w=240','MAIN',8); + +INSERT INTO image(url,image_type,category_id) +values ('https://a0.muscache.com/im/pictures/36f53e61-db8d-403c-9122-5b761c0e4264.jpg?im_w=480','MAIN',1), + ('https://a0.muscache.com/im/pictures/2f13349d-879d-43c6-83e3-8e5679291d53.jpg?im_w=480','MAIN',2), + ('https://a0.muscache.com/im/pictures/7d82ca14-56e5-4465-8218-dcfa7d69b6ac.jpg?im_w=480','MAIN',3), + ('https://a0.muscache.com/im/pictures/10a638e1-6aff-4313-8033-1275cec83987.jpg?im_w=480','MAIN',4); + +INSERT INTO image(url,image_type,room_id) +values ('https://a0.muscache.com/im/pictures/c45d08e5-f560-44f0-83fc-83290ccd1670.jpg?im_w=1200', 'MAIN', 1), + ('https://a0.muscache.com/im/pictures/83ea7cb5-a925-4fc8-835f-da8df7f24bec.jpg?im_w=1200', 'MAIN', 2), + ('https://a0.muscache.com/im/pictures/miso/Hosting-44159716/original/04dc2ade-cd11-4599-a7fb-a6f4b6176f4e.jpeg?im_w=1200', 'MAIN', 3), + ('https://a0.muscache.com/im/pictures/42c6cd5c-512c-4f39-9e9c-9ed274f2f0e5.jpg?im_w=1200', 'MAIN', 4), + ('https://a0.muscache.com/im/pictures/miso/Hosting-44090615/original/c2904e87-4014-4d26-a977-b789248c77ce.jpeg?im_w=1200', 'MAIN', 5), + ('https://a0.muscache.com/im/pictures/miso/Hosting-47435529/original/82c508c8-e0b5-4da2-805f-8772ad9bfe9d.jpeg?im_w=1200', 'MAIN', 6), + ('https://a0.muscache.com/im/pictures/a63a845b-c16e-4a0f-b0ca-a124a677b3d2.jpg?im_w=1200', 'MAIN', 7), + ('https://a0.muscache.com/im/pictures/miso/Hosting-47897490/original/b0238603-d063-4f5c-9e10-c835132669e4.jpeg?im_w=1200', 'MAIN', 8); + +INSERT INTO image(url,image_type, room_id) +values ('https://a0.muscache.com/im/pictures/41ee09fc-eddb-49c5-a3b4-ae2caacaf759.jpg?im_w=720', 'DETAIL', 1), + ('https://a0.muscache.com/im/pictures/e3258341-b4f3-4988-b958-bec903936a0b.jpg?im_w=720', 'DETAIL', 1), + ('https://a0.muscache.com/im/pictures/adca4292-084c-45a2-a9c5-1e4679ba81fe.jpg?im_w=720', 'DETAIL', 1), + ('https://a0.muscache.com/im/pictures/a13322a6-c136-4df0-9a10-348dd91a926c.jpg?im_w=720', 'DETAIL', 1), + ('https://a0.muscache.com/im/pictures/ecf38b8f-9986-4a66-99de-4273e12942f7.jpg?im_w=720', 'DETAIL', 2), + ('https://a0.muscache.com/im/pictures/b7aea036-c13b-4cbd-9472-24832c3360d9.jpg?im_w=720', 'DETAIL', 2), + ('https://a0.muscache.com/im/pictures/4210eef3-ae67-488b-bc8d-d55f8fe690dc.jpg?im_w=720', 'DETAIL', 2), + ('https://a0.muscache.com/im/pictures/de1c13f8-554b-4abb-9fa6-98299a10f67c.jpg?im_w=720', 'DETAIL', 2), + ('https://a0.muscache.com/im/pictures/miso/Hosting-44159716/original/c6c1a442-b449-495a-8ee9-f1779f36b5b4.jpeg?im_w=720', 'DETAIL', 3), + ('https://a0.muscache.com/im/pictures/miso/Hosting-44159716/original/66bd535a-ba05-43e7-adbe-6953bbc13da5.jpeg?im_w=720', 'DETAIL', 3), + ('https://a0.muscache.com/im/pictures/miso/Hosting-44159716/original/d1857908-90c8-48fd-9e68-a743187664ed.jpeg?im_w=720', 'DETAIL', 3), + ('https://a0.muscache.com/im/pictures/39b76268-042e-4a89-aa3b-89abe9865c58.jpg?im_w=720', 'DETAIL', 3), + ('https://a0.muscache.com/im/pictures/063465ea-3f1f-4b83-b0b4-75952fc4c424.jpg?im_w=720', 'DETAIL', 4), + ('https://a0.muscache.com/im/pictures/dddaa2fd-78a9-4105-92cd-bfefebe65d5f.jpg?im_w=720', 'DETAIL', 4), + ('https://a0.muscache.com/im/pictures/c1c9e49b-2e5a-47e5-bda8-95390cfde907.jpg?im_w=720', 'DETAIL', 4), + ('https://a0.muscache.com/im/pictures/800c7310-bf61-4fac-a248-06cdc7081629.jpg?im_w=720', 'DETAIL', 4), + ('https://a0.muscache.com/im/pictures/miso/Hosting-44090615/original/c5f66ab8-24fe-479d-8b67-a512176ddbef.jpeg?im_w=720', 'DETAIL', 5), + ('https://a0.muscache.com/im/pictures/miso/Hosting-44090615/original/149e034a-2716-4bb2-8561-a7ccede18571.jpeg?im_w=720', 'DETAIL', 5), + ('https://a0.muscache.com/im/pictures/02b368b7-63b0-4748-847f-bf5a81c08dd5.jpg?im_w=720', 'DETAIL', 5), + ('https://a0.muscache.com/im/pictures/58b752dd-8143-4636-83ce-09ebe235683f.jpg?im_w=720', 'DETAIL', 5), + ('https://a0.muscache.com/im/pictures/miso/Hosting-47435529/original/08d1c75c-4a6b-423e-a908-a624419f4cf6.jpeg?im_w=720', 'DETAIL', 6), + ('https://a0.muscache.com/im/pictures/miso/Hosting-47435529/original/7c29ac12-fd28-4b6a-a40d-bf193a418c57.jpeg?im_w=720', 'DETAIL', 6), + ('https://a0.muscache.com/im/pictures/miso/Hosting-47435529/original/a15d42b5-c8c9-47a1-aee6-627fcb64bb9f.jpeg?im_w=720', 'DETAIL', 6), + ('https://a0.muscache.com/im/pictures/miso/Hosting-47435529/original/2fe6bde7-9e85-4fb2-bbc6-e1cd780b5679.jpeg?im_w=720', 'DETAIL', 6), + ('https://a0.muscache.com/im/pictures/44ae81dc-e8a9-4623-bccd-97af889a8b16.jpg?im_w=720', 'DETAIL', 7), + ('https://a0.muscache.com/im/pictures/61b3e6ed-a29f-44a0-8edb-f6985bf2aa62.jpg?im_w=720', 'DETAIL', 7), + ('https://a0.muscache.com/im/pictures/92bc9188-4c09-40dc-9984-b38a6f1fa70a.jpg?im_w=720', 'DETAIL', 7), + ('https://a0.muscache.com/im/pictures/50e7a497-3675-4e66-b487-db58f4e5d6c3.jpg?im_w=720', 'DETAIL', 7), + ('https://a0.muscache.com/im/pictures/miso/Hosting-47897490/original/56311d70-1328-4f37-bd10-15ef43f576c2.jpeg?im_w=720', 'DETAIL', 8), + ('https://a0.muscache.com/im/pictures/3be5bd86-f7fe-46d8-80ba-d138cf920df5.jpg?im_w=720', 'DETAIL', 8), + ('https://a0.muscache.com/im/pictures/ef4e5dfc-4da9-4101-ae90-5ad2aaab3c77.jpg?im_w=720', 'DETAIL', 8), + ('https://a0.muscache.com/im/pictures/1a5e31a5-7b1e-4276-9751-8f1a308dd324.jpg?im_w=720', 'DETAIL', 8); + + + +INSERT INTO room(cost, title, description, people, oneroom, bed, bath, hair_dryer, air_conditioner, wifi, clean_tax, city_id, category_id) +values (153200, '이태원에 아늑한 숙소 Y 하우스', '이태원역에서 도보로 4분거리에 위치하고 있고 대로변에서 상당히 가까운 지역에 위치하여 여성분들도 안전하게 머무시며 이태원을 만끽하실 수 있으세요.' + , 2, false, 2, 1, true, true, true, 25000, 1, 1), + (223000, '강남역 1번 출구 바로 옆 편리하고 깔끔한 숙소', '- 전철까지 도보 30초 +- 침구로 매번 깨끗이 교체 +- 18층으로 좋은 전망 +- 세탁기 + 건조기 +- 지하창고에 짐 보관 무료 +- 주차는 1시간에 1000원으로 꼭 미리 문의 주셔야합니다' , 3, false, 3, 1, true, true, true, 22000, 1, 1), + (345300, '1호선 제기동 역에서 부터 도보로 30초거리에 위치' , '1. 1호선 제기동 역에서 부터 도보로 30초거리에 위치하고 있어 접근성이 훌륭합니다. +2. 모든 가구와 인테리어가 새것이라 매우 청결합니다. +3. 퀸사이즈 침대가 설치되어 있어 매우 편한 수면을 취할 수 있습니다. +4. 스마트 티비가 있습니다. 다양한 채널의 TV는 물론 본인 계정의 유튜브, 넷플릭스 계정을 연결하여 시청 할 수 있습니다. +5. 고급형 접이식 식탁이 있어서 공간을 유용하게 사용 할 수 있습니다. +6. 최신형 공기청정기가 있어 쾌적한 공기를 유지합니다. +7. 게스트분들의 피드백으로 전자레인지가 추가 되었습니다.', 3, false, 3, 1, true, true, true, 23000, 1, 2), + (53400, '뷰가 너무 좋은 숙소', '본 숙소는 친구, 지인들과의 모임장소나 회포를 풀고 생일파티를 하는 등 밤 늦게까지 술를 마시는 장소로는 적합하지 않습니다. 만약 그런 이유로 민원이 발생할경우 바로 퇴실조치 하겠습니다.', + 4, false, 3, 2, true, true, true, 18000, 1, 3), + (72500, '자가격리만 전문으로 하는 숙소입니다 :-)', '호텔에서 쓰는 40수 프리미엄 침구류로 이불, 배게 쾌적한 환경을 자랑합니다. +빔프로젝터(넷플릭스&왓챠 등), WIFI 가능 +식사를 위한 인덕션, 후라이팬, 냄비, 조리도구, 접시 등 모든 취사에 필요한 도구들이 준비되어 있습니다.' , 2, true, 2, 1, true, true, true, 20100, 1, 2), + (85100, '스마트 숙소관리 프리모(Premo)를 사용할 수 있는 AI 숙소', '-비대면 언택트 스마트 도어락 사용 +-일회용 비밀번호 사용으로 안전합니다. +▶응암역(6호선) 도보 7분 내외 +▶신축 / 엘레베이터 +▶이마트 도보 2분' , 3, false, 2, 1, true, true, true, 23000, 1, 3), + (153000, '당산역 1분거리에 있는 고층아파트', '무료주차(입.출차 1회제공) +빌트인가구와 퀸침대 55인치 tv +sk인터넷,tv, 와이파이제공 +선유도와 여의도한강공원산책가능', 2, true, 2, 1, true, true, true, 20000, 1, 1), + (418000, '어반스테이 더 남산', '말이 필요없다 일단 와라!!!', 4, false, 4, 2, true, true, true, 30000, 1, 4); + +INSERT INTO reservation(room_id, check_in, check_out) +values (1, '2021-05-27', '2021-05-28'), + (2, '2021-06-02', '2021-06-07'), + (5, '2021-05-30', '2021-06-10'); diff --git a/BE/src/main/resources/shcema.sql b/BE/src/main/resources/shcema.sql new file mode 100644 index 000000000..065b24e17 --- /dev/null +++ b/BE/src/main/resources/shcema.sql @@ -0,0 +1,95 @@ +create databases airbnb; + + +drop table city; +create table city( + id int not null auto_increment, + name varchar(45) not null, + latitude int, + longitude int, + primary key(id) +); + +drop table category; +create table category( + id int not null auto_increment, + name varchar(45) not null, + primary key(id) +); + +drop tabel room; +create table room( + id int not null auto_increment, + cost int not null, + title varchar (45) not null, + description varchar (300), + people int not null, + oneroom tinyint(1) not null default 0, + bed int not null default 0, + bath int not null default 0, + hair_dryer tinyint(1) not null default 0, + air_conditioner tinyint(1) not null default 0, + wifi tinyint(1) not null default 0, + clean_tax int , + city_id int not null, + category_id int not null, + + primary key (id), + foreign key (city_id) references city(id), + foreign key (category_id) references category(id) +); + +drop table image; +create table image( + id int not null auto_increment, + url varchar(300) not null, + room_id int, + category_id int, + city_id int, + image_type varchar(10) not null, + primary key (id), + foreign key (room_id) references room(id), + foreign key (category_id) references category(id), + foreign key (city_id) references city(id), + foreign key (image_type) references image_type(type) +); + +drop table image_type; +create table image_type( + type varchar(10) not null, + primary key (type) +); + +drop table 'user'; +create table user( + id varchar(45) not null, + primary key (id) +); + +drop table wish_list; +create table wish_list( + id int not null auto_increment, + room_id int not null, + user_id varchar(45) not null, + save tinyint(1) not null default 1, + primary key (id), + foreign key (room_id) references room(id), + foreign key (user_id) references `user`(id) +); + +drop table reservation; +create table reservation( + id int not null auto_increment, + room_id int not null, + user_id varchar(45), + check_in datetime, + check_out datetime, + cancel tinyint(1) not null default 0, + primary key (id), + foreign key (room_id) references room(id), + foreign key (user_id) references user(id) +); + + + + diff --git a/BE/src/test/java/airbnb/AirbnbApplicationTests.java b/BE/src/test/java/airbnb/AirbnbApplicationTests.java new file mode 100644 index 000000000..47467f5fd --- /dev/null +++ b/BE/src/test/java/airbnb/AirbnbApplicationTests.java @@ -0,0 +1,7 @@ +package airbnb; + +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class AirbnbApplicationTests { +} diff --git a/README.md b/README.md index 8ec09bd21..e5a374931 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,34 @@ -# airbnb -그룹 프로젝트 #4 +# ✈️ airbnb + +## Team-08 + +### TMI로 똘똘뭉친 우리의 이야기 +[저희의 TMI,, 들어보실래요 ?](https://www.notion.so/f3914a95f61a4128a580cd4051d4aeb3) + +## 👨‍👧‍👦 Members + +[Swing](https://github.com/swing-park) 🏌️‍♂️ : 뷰깎기인형🧚‍♂️

+[Marco](https://github.com/95degree) 👻 : 명상으로 코드 석가모니가 된 ⛩⛩

+[Lia](https://github.com/Lia316) 🐿 : 까먹지...않을 거에요..🌰

+ +--- + +## 🔗 Links + +- ### [Notion](https://www.notion.so/Team08-768dcf3cb1054933817c84a567c7ac97) +- ### [Team Convention](https://github.com/swing-park/airbnb/wiki) +- ### [IOS 데모 화면]() +- ### [FE 데모 화면]() + +--- + +## 📜 스케줄표 + +| 시간 | 내용 | +|-----|-----| +|10:00 ~ 10:30| 데일리 스크럼 | +|10:30 ~ 12:30| 클래스별 수업 or 프로젝트 진행 | +|12:30 ~ 14:00| 점심 시간 🍚 | +|14:00 ~ 14:30| 팀 회의 | +|14:30 ~ 17:30| 프로젝트 진행 | +|17:30 ~ 18:00| 회고 |