├── .gitignore ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── profile_dev.gradle ├── profile_fast.gradle ├── profile_prod.gradle ├── profile_test.gradle └── src ├── main ├── java │ └── com │ │ └── springboot │ │ └── demo │ │ ├── Application.java │ │ ├── ApplicationWebXml.java │ │ ├── async │ │ └── ExceptionHandlingAsyncTaskExecutor.java │ │ ├── common │ │ ├── AuditingDateTimeProvider.java │ │ ├── ConstantDateTimeService.java │ │ ├── CurrentTimeDateTimeService.java │ │ └── DateTimeService.java │ │ ├── config │ │ ├── AsyncConfiguration.java │ │ ├── Constants.java │ │ ├── DatabaseConfiguration.java │ │ ├── JacksonConfiguration.java │ │ ├── MetricsConfiguration.java │ │ ├── RedisConfiguration.java │ │ └── apidoc │ │ │ └── SwaggerConfiguration.java │ │ ├── domain │ │ ├── BaseEntity.java │ │ ├── City.java │ │ ├── Hotel.java │ │ ├── HotelSummary.java │ │ ├── Rating.java │ │ ├── RatingCount.java │ │ ├── Review.java │ │ ├── TripType.java │ │ └── util │ │ │ ├── CustomDateTimeDeserializer.java │ │ │ ├── CustomDateTimeSerializer.java │ │ │ ├── CustomLocalDateSerializer.java │ │ │ ├── FixedH2Dialect.java │ │ │ └── ISO8601LocalDateDeserializer.java │ │ ├── repository │ │ ├── CityRepository.java │ │ ├── HotelRepository.java │ │ ├── ReviewRepository.java │ │ └── redis │ │ │ ├── HashCache.java │ │ │ ├── KeyUtils.java │ │ │ ├── ListCache.java │ │ │ ├── RedisJsonMapper.java │ │ │ ├── SetCache.java │ │ │ ├── ValueCache.java │ │ │ └── impl │ │ │ ├── HashCacheRedisRepository.java │ │ │ ├── ListCacheRedisRepository.java │ │ │ ├── SetCacheRedisRepository.java │ │ │ └── ValueCacheRedisRepository.java │ │ ├── service │ │ ├── CityService.java │ │ ├── HotelService.java │ │ ├── ReviewsSummary.java │ │ ├── criteria │ │ │ └── CitySearchCriteria.java │ │ └── impl │ │ │ ├── CityServiceImpl.java │ │ │ └── HotelServiceImpl.java │ │ └── web │ │ ├── filter │ │ └── CachingHttpHeadersFilter.java │ │ ├── propertyeditors │ │ └── LocaleDateTimeEditor.java │ │ └── rest │ │ ├── BaseController.java │ │ ├── CityController.java │ │ ├── HotelController.java │ │ ├── LogsController.java │ │ ├── dto │ │ ├── LoggerDTO.java │ │ └── ReviewDetailsDto.java │ │ ├── errors │ │ ├── CityNotFoundException.java │ │ ├── CustomParameterizedException.java │ │ ├── ErrorConstants.java │ │ ├── ErrorDTO.java │ │ ├── ExceptionTranslator.java │ │ ├── FieldErrorDTO.java │ │ ├── ParameterizedErrorDTO.java │ │ └── RestErrorHandler.java │ │ └── util │ │ ├── HeaderUtil.java │ │ └── PaginationUtil.java └── resources │ ├── config │ ├── application-dev.yml │ ├── application-prod.yml │ └── application.yml │ └── logback.xml └── test ├── java └── com │ └── springboot │ └── demo │ ├── AbstractControllerTest.java │ ├── AbstractTest.java │ ├── repository │ └── CityRepositoryTests.java │ ├── service │ └── CityServiceTest.java │ ├── util │ └── TestUtil.java │ └── web │ └── rest │ ├── CityControllerIntegrationTests.java │ └── CityControllerTest.java └── resources ├── afterTestRun.sql ├── beforeTestRun.sql └── config └── application-test.yml /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | **/target/* 3 | *.ipr 4 | *.iml 5 | *.iws 6 | *.idea 7 | spider.log 8 | **/build/* 9 | .gradle/* 10 | *.DS_Store 11 | build/ 12 | logs/ 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # spring-boot-base-template 2 | 3 | 1. Spring Boot 4 | 2. Hibernate 5 | 3. MySql 6 | 4. Redis 7 | 5. Dropwizard Metrics(Codahale) 8 | 6. Swagger 9 | 7. Mockito for Tests 10 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | jcenter() 5 | } 6 | dependencies { 7 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${spring_boot_version}") 8 | classpath("io.spring.gradle:dependency-management-plugin:0.5.2.RELEASE") 9 | } 10 | } 11 | 12 | apply plugin: 'java' 13 | apply plugin: 'eclipse' 14 | apply plugin: 'idea' 15 | apply plugin: 'spring-boot' 16 | apply plugin: 'io.spring.dependency-management' 17 | defaultTasks 'bootRun' 18 | 19 | jar { 20 | baseName = 'springbootdemo' 21 | version = '0.0.1-SNAPSHOT' 22 | } 23 | 24 | bootRepackage { 25 | mainClass = 'com.springboot.demo.Application' 26 | } 27 | 28 | springBoot { 29 | mainClass = 'com.springboot.demo.Application' 30 | } 31 | 32 | bootRun { 33 | addResources = false 34 | } 35 | 36 | if (project.hasProperty('prod')) { //./gradlew -Pprod bootRun 37 | apply from: 'profile_prod.gradle' 38 | } else if (project.hasProperty('fast')) { 39 | apply from: 'profile_fast.gradle' 40 | } else { 41 | apply from: 'profile_dev.gradle' 42 | } 43 | 44 | sourceCompatibility = 1.8 45 | targetCompatibility = 1.8 46 | 47 | repositories { 48 | mavenCentral() 49 | maven { url 'http://repo.spring.io/milestone' } 50 | maven { url 'http://repo.spring.io/snapshot' } 51 | maven { url 'https://repository.jboss.org/nexus/content/repositories/releases' } 52 | maven { url 'https://oss.sonatype.org/content/repositories/releases' } 53 | maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } 54 | maven { url 'http://repo.maven.apache.org/maven2' } 55 | } 56 | 57 | 58 | dependencies { 59 | 60 | compile group: 'io.dropwizard.metrics', name: 'metrics-core', version: dropwizard_metrics_version 61 | compile group: 'io.dropwizard.metrics', name: 'metrics-annotation', version: dropwizard_metrics_version 62 | compile group: 'com.ryantenney.metrics', name: 'metrics-spring', version: '3.1.3' 63 | 64 | compile group: 'org.springframework.boot', name: 'spring-boot-actuator' ,version: spring_boot_version 65 | compile group: 'org.springframework.boot', name: 'spring-boot-autoconfigure' , version: spring_boot_version 66 | compile group: 'org.springframework.boot', name: 'spring-boot-starter-aop', version: spring_boot_version 67 | compile group: 'org.springframework.boot', name: 'spring-boot-loader-tools', version: spring_boot_version 68 | compile group: 'org.springframework.boot', name: 'spring-boot-starter-logging', version: spring_boot_version 69 | compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: spring_boot_version 70 | compile(group: 'org.springframework.boot', name: 'spring-boot-starter-redis', version: spring_boot_version) { 71 | exclude group: 'commons-logging' 72 | } 73 | compile group: 'org.springframework.boot', name: 'spring-boot-starter', version: spring_boot_version 74 | compile group: 'org.springframework.boot', name: 'spring-boot-starter-jetty', version: spring_boot_version 75 | compile(group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: spring_boot_version) { 76 | exclude module: 'spring-boot-starter-tomcat' 77 | } 78 | 79 | 80 | compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-json-org', 81 | version: jackson_version 82 | compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-hppc', 83 | version: jackson_version 84 | compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-joda', 85 | version: jackson_version 86 | compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-hibernate4', 87 | version: jackson_version 88 | compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', 89 | version: jackson_version 90 | compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', 91 | version:jackson_version 92 | 93 | compile group: 'org.codehaus.jackson', name: 'jackson-mapper-asl', version: '1.9.13' 94 | 95 | compile(group: 'com.zaxxer', name: 'HikariCP', version: HikariCP_version) { 96 | exclude(module: 'tools') 97 | } 98 | compile group: 'commons-lang', name: 'commons-lang', version: commons_lang_version 99 | compile group: 'commons-io', name: 'commons-io', version: commons_io_version 100 | compile group: 'javax.inject', name: 'javax.inject', version: javax_inject_version 101 | compile group: 'javax.transaction', name: 'javax.transaction-api', version: javax_transaction_version 102 | compile group: 'joda-time', name: 'joda-time', version: joda_time_version 103 | compile group: 'joda-time', name: 'joda-time-hibernate', version: joda_time_hibernate_version 104 | compile group: 'org.hibernate', name: 'hibernate-core', version: hibernate_entitymanager_version 105 | compile group: 'org.hibernate', name: 'hibernate-envers' 106 | compile(group: 'org.hibernate', name: 'hibernate-ehcache') { 107 | exclude(module: 'ehcache-core') 108 | } 109 | compile group: 'org.hibernate', name: 'hibernate-validator', version: hibernate_validator_version 110 | compile group: 'org.jadira.usertype', name: 'usertype.core', version: usertype_core_version 111 | 112 | compile group: 'org.projectlombok', name: 'lombok', version: lombok_version 113 | 114 | compile(group: 'io.springfox', name: 'springfox-swagger2', version: springfox_version) { 115 | exclude module: 'mapstruct' 116 | } 117 | compile group: 'io.springfox', name: 'springfox-swagger-ui', version: springfox_version 118 | 119 | runtime("com.h2database:h2") 120 | runtime("mysql:mysql-connector-java") 121 | 122 | testCompile group: 'com.jayway.awaitility', name: 'awaitility', version: awaility_version 123 | testCompile group: 'com.jayway.jsonpath', name: 'json-path' 124 | testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test' 125 | testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-jetty' 126 | testCompile group: 'org.assertj', name: 'assertj-core', version: assertj_core_version 127 | testCompile group: 'junit', name: 'junit' 128 | testCompile group: 'org.mockito', name: 'mockito-core' 129 | testCompile group: 'org.hamcrest', name: 'hamcrest-library' 130 | } 131 | 132 | configurations.all { 133 | resolutionStrategy { 134 | // force certain versions of dependencies (including transitive) 135 | // *append new forced modules: 136 | force group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: jackson_version 137 | force group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: jackson_version 138 | force group: 'joda-time', name: 'joda-time', version: joda_time_version 139 | } 140 | } 141 | 142 | eclipse { 143 | classpath { 144 | containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER') 145 | containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8' 146 | } 147 | } 148 | 149 | clean { 150 | delete "target" 151 | } 152 | 153 | task wrapper(type: Wrapper) { 154 | gradleVersion = '2.6' 155 | } 156 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | rootProject.name=SpringBootBase 2 | profile=dev 3 | 4 | assertj_core_version=3.1.0 5 | awaility_version=1.4.0 6 | commons_lang_version=2.6 7 | commons_io_version=2.4 8 | dropwizard_metrics_version=3.1.2 9 | javax_inject_version=1 10 | javax_transaction_version=1.2 11 | joda_time_hibernate_version=1.4 12 | joda_time_version=2.5 13 | json_path_version=2.0.0 14 | jackson_version=2.4.6 15 | hibernate_entitymanager_version=4.3.10.Final 16 | HikariCP_version=2.4.0 17 | liquibase_slf4j_version=1.2.1 18 | liquibase_core_version=3.4.1 19 | liquibase_hibernate4_version=3.5 20 | hibernate_validator_version=5.2.1.Final 21 | springfox_version=2.2.2 22 | spring_boot_version=1.3.5.RELEASE 23 | mysql_connector_java_version=5.1.36 24 | h2_version=1.4.187 25 | usertype_core_version=4.0.0.GA 26 | lombok_version=1.16.4 27 | 28 | ## below are some of the gradle performance improvement settings that can be used as required, these are not enabled by default 29 | 30 | ## The Gradle daemon aims to improve the startup and execution time of Gradle. 31 | ## When set to true the Gradle daemon is to run the build. 32 | ## TODO: disable daemon on CI, since builds should be clean and reliable on servers 33 | ## un comment the below line to enable the daemon 34 | 35 | org.gradle.daemon=true 36 | 37 | ## Specifies the JVM arguments used for the daemon process. 38 | ## The setting is particularly useful for tweaking memory settings. 39 | ## Default value: -Xmx1024m -XX:MaxPermSize=256m 40 | ## un comment the below line to override the daemon defaults 41 | 42 | #org.gradle.jvmargs=-Xmx1024m -XX:MaxPermSize=256m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 43 | 44 | ## When configured, Gradle will run in incubating parallel mode. 45 | ## This option should only be used with decoupled projects. More details, visit 46 | ## http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 47 | ## un comment the below line to enable parellel mode 48 | 49 | #org.gradle.parallel=true 50 | 51 | ## Enables new incubating mode that makes Gradle selective when configuring projects. 52 | ## Only relevant projects are configured which results in faster builds for large multi-projects. 53 | ## http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:configuration_on_demand 54 | ## un comment the below line to enable the selective mode 55 | 56 | #org.gradle.configureondemand=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himanshuvirmani/spring-boot-base-template/707025079464c1fdc868883188c2b55689caf154/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Jun 04 16:19:20 IST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.6-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /profile_dev.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'spring-boot' 2 | 3 | ext { 4 | logbackLoglevel = "DEBUG" 5 | } 6 | 7 | dependencies { 8 | compile group: 'org.springframework.boot', name: 'spring-boot-starter-tomcat', 9 | version: spring_boot_version 10 | } 11 | 12 | bootRun { 13 | args = ["--spring.profiles.active=dev"] 14 | } 15 | 16 | task setProdProperties(dependsOn: bootRun) << { 17 | doFirst { 18 | System.setProperty('spring.profiles.active', 'dev') 19 | } 20 | } 21 | 22 | processResources { 23 | filesMatching('**/logback.xml') { 24 | filter { 25 | it.replace('${logback.loglevel}', logbackLoglevel) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /profile_fast.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'spring-boot' 2 | 3 | ext { 4 | logbackLoglevel = "DEBUG" 5 | } 6 | 7 | dependencies { 8 | compile group: 'org.springframework.boot', name: 'spring-boot-starter-undertow', 9 | version: spring_boot_version 10 | } 11 | 12 | bootRun { 13 | args = ["--spring.profiles.active=dev,fast"] 14 | } 15 | 16 | processResources { 17 | filesMatching('**/logback.xml') { 18 | filter { 19 | it.replace('${logback.loglevel}', logbackLoglevel) 20 | } 21 | } 22 | } 23 | 24 | task setProdProperties(dependsOn: bootRun) << { 25 | doFirst { 26 | System.setProperty('spring.profiles.active', 'dev,fast') 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /profile_prod.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'spring-boot' 2 | 3 | ext { 4 | logbackLoglevel = "INFO" 5 | } 6 | 7 | bootRun { 8 | args = ["--spring.profiles.active=prod"] 9 | } 10 | 11 | processResources { 12 | filesMatching('**/logback.xml') { 13 | filter { 14 | it.replace('${logback.loglevel}', logbackLoglevel) 15 | } 16 | } 17 | } 18 | 19 | task setProdProperties(dependsOn: bootRun) << { 20 | doFirst { 21 | System.setProperty('spring.profiles.active', 'prod') 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /profile_test.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'spring-boot' 2 | 3 | ext { 4 | logbackLoglevel = "INFO" 5 | } 6 | 7 | bootRun { 8 | args = ["--spring.profiles.active=test"] 9 | } 10 | 11 | processResources { 12 | filesMatching('**/logback.xml') { 13 | filter { 14 | it.replace('${logback.loglevel}', logbackLoglevel) 15 | } 16 | } 17 | } 18 | 19 | task setProdProperties(dependsOn: bootRun) << { 20 | doFirst { 21 | System.setProperty('spring.profiles.active', 'test') 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/Application.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo; 2 | 3 | import com.codahale.metrics.JmxReporter; 4 | import com.codahale.metrics.MetricRegistry; 5 | import com.springboot.demo.config.Constants; 6 | import com.springboot.demo.web.filter.CachingHttpHeadersFilter; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.boot.SpringApplication; 11 | import org.springframework.boot.autoconfigure.SpringBootApplication; 12 | import org.springframework.boot.context.embedded.FilterRegistrationBean; 13 | import org.springframework.context.annotation.Bean; 14 | import org.springframework.core.env.Environment; 15 | import org.springframework.core.env.SimpleCommandLinePropertySource; 16 | 17 | import javax.annotation.PostConstruct; 18 | import javax.inject.Inject; 19 | import javax.servlet.DispatcherType; 20 | import java.io.IOException; 21 | import java.net.InetAddress; 22 | import java.net.UnknownHostException; 23 | import java.util.Arrays; 24 | import java.util.Collection; 25 | 26 | @SpringBootApplication 27 | public class Application { 28 | 29 | private static final Logger log = LoggerFactory.getLogger(Application.class); 30 | 31 | @Autowired 32 | private MetricRegistry registry; 33 | 34 | @Inject 35 | private Environment env; 36 | 37 | @PostConstruct 38 | public void initApplication() throws IOException { 39 | if (env.getActiveProfiles().length == 0) { 40 | log.warn("No Spring profile configured, running with default configuration"); 41 | } else { 42 | log.info("Running with Spring profile(s) : {}", Arrays.toString(env.getActiveProfiles())); 43 | Collection activeProfiles = Arrays.asList(env.getActiveProfiles()); 44 | if (activeProfiles.contains(Constants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains( 45 | Constants.SPRING_PROFILE_PRODUCTION)) { 46 | log.error("You have misconfigured your application! " + 47 | "It should not run with both the 'dev' and 'prod' profiles at the same time."); 48 | } 49 | if (activeProfiles.contains(Constants.SPRING_PROFILE_PRODUCTION) && activeProfiles.contains( 50 | Constants.SPRING_PROFILE_FAST)) { 51 | log.error("You have misconfigured your application! " + 52 | "It should not run with both the 'prod' and 'fast' profiles at the same time."); 53 | } 54 | } 55 | } 56 | 57 | // sample filter bean to test if request/response filtering works. 58 | @Bean 59 | public FilterRegistrationBean myFilter() { 60 | FilterRegistrationBean registration = new FilterRegistrationBean(); 61 | registration.setFilter(new CachingHttpHeadersFilter(env)); 62 | // registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class)); 63 | registration.setDispatcherTypes(DispatcherType.REQUEST); 64 | return registration; 65 | } 66 | 67 | /** 68 | * Main method, used to run the application. 69 | */ 70 | public static void main(String[] args) throws UnknownHostException { 71 | SpringApplication app = new SpringApplication(Application.class); 72 | app.setShowBanner(false); 73 | SimpleCommandLinePropertySource source = new SimpleCommandLinePropertySource(args); 74 | addDefaultProfile(app, source); 75 | Environment env = app.run(args).getEnvironment(); 76 | log.info("Access URLs:\n----------------------------------------------------------\n\t" + 77 | "Local: \t\thttp://127.0.0.1:{}\n\t" + 78 | "External: \thttp://{}:{}\n----------------------------------------------------------", 79 | env.getProperty("server.port"), 80 | InetAddress.getLocalHost().getHostAddress(), 81 | env.getProperty("server.port")); 82 | } 83 | 84 | /** 85 | * If no profile has been configured, set by default the "dev" profile. 86 | */ 87 | private static void addDefaultProfile(SpringApplication app, 88 | SimpleCommandLinePropertySource source) { 89 | if (!source.containsProperty("spring.profiles.active") && 90 | !System.getenv().containsKey("SPRING_PROFILES_ACTIVE")) { 91 | 92 | app.setAdditionalProfiles(Constants.SPRING_PROFILE_DEVELOPMENT); 93 | } 94 | } 95 | 96 | @Bean 97 | public JmxReporter jmxReporter() { 98 | JmxReporter reporter = JmxReporter.forRegistry(registry).build(); 99 | reporter.start(); 100 | return reporter; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/ApplicationWebXml.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo; 2 | 3 | import com.springboot.demo.config.Constants; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.boot.builder.SpringApplicationBuilder; 7 | import org.springframework.boot.context.web.SpringBootServletInitializer; 8 | 9 | /** 10 | * This is a helper Java class that provides an alternative to creating a web.xml. 11 | */ 12 | public class ApplicationWebXml extends SpringBootServletInitializer { 13 | 14 | private final Logger log = LoggerFactory.getLogger(ApplicationWebXml.class); 15 | 16 | @Override 17 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 18 | return application.profiles(addDefaultProfile()) 19 | .showBanner(false) 20 | .sources(Application.class); 21 | } 22 | 23 | /** 24 | * Set a default profile if it has not been set.

Please use -Dspring.profiles.active=dev 25 | *

26 | */ 27 | private String addDefaultProfile() { 28 | String profile = System.getProperty("spring.profiles.active"); 29 | if (profile != null) { 30 | log.info("Running with Spring profile(s) : {}", profile); 31 | return profile; 32 | } 33 | 34 | log.warn("No Spring profile configured, running with default configuration"); 35 | return Constants.SPRING_PROFILE_DEVELOPMENT; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/async/ExceptionHandlingAsyncTaskExecutor.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.async; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.DisposableBean; 6 | import org.springframework.beans.factory.InitializingBean; 7 | import org.springframework.core.task.AsyncTaskExecutor; 8 | 9 | import java.util.concurrent.Callable; 10 | import java.util.concurrent.Future; 11 | 12 | public class ExceptionHandlingAsyncTaskExecutor implements AsyncTaskExecutor, 13 | InitializingBean, DisposableBean { 14 | 15 | private final Logger log = LoggerFactory.getLogger(ExceptionHandlingAsyncTaskExecutor.class); 16 | 17 | private final AsyncTaskExecutor executor; 18 | 19 | public ExceptionHandlingAsyncTaskExecutor(AsyncTaskExecutor executor) { 20 | this.executor = executor; 21 | } 22 | 23 | @Override 24 | public void execute(Runnable task) { 25 | executor.execute(task); 26 | } 27 | 28 | @Override 29 | public void execute(Runnable task, long startTimeout) { 30 | executor.execute(createWrappedRunnable(task), startTimeout); 31 | } 32 | 33 | private Callable createCallable(final Callable task) { 34 | return () -> { 35 | try { 36 | return task.call(); 37 | } catch (Exception e) { 38 | handle(e); 39 | throw e; 40 | } 41 | }; 42 | } 43 | 44 | private Runnable createWrappedRunnable(final Runnable task) { 45 | return () -> { 46 | try { 47 | task.run(); 48 | } catch (Exception e) { 49 | handle(e); 50 | } 51 | }; 52 | } 53 | 54 | protected void handle(Exception e) { 55 | log.error("Caught async exception", e); 56 | } 57 | 58 | @Override 59 | public Future submit(Runnable task) { 60 | return executor.submit(createWrappedRunnable(task)); 61 | } 62 | 63 | @Override 64 | public Future submit(Callable task) { 65 | return executor.submit(createCallable(task)); 66 | } 67 | 68 | @Override 69 | public void destroy() throws Exception { 70 | if (executor instanceof DisposableBean) { 71 | DisposableBean bean = (DisposableBean) executor; 72 | bean.destroy(); 73 | } 74 | } 75 | 76 | @Override 77 | public void afterPropertiesSet() throws Exception { 78 | if (executor instanceof InitializingBean) { 79 | InitializingBean bean = (InitializingBean) executor; 80 | bean.afterPropertiesSet(); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/common/AuditingDateTimeProvider.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.common; 2 | 3 | import org.springframework.data.auditing.DateTimeProvider; 4 | 5 | import java.util.Calendar; 6 | import java.util.GregorianCalendar; 7 | 8 | /** 9 | * This class obtains the current time by using a {@link DateTimeService} 10 | * object. The reason for this is that we can use a different implementation in our integration tests. 11 | *

12 | * In other words: 13 | *

    14 | *
  • 15 | * Our application always returns the correct time because it uses the 16 | * {@link CurrentTimeDateTimeService} class. 17 | *
  • 18 | *
  • 19 | * When our integration tests are running, we can return a constant time which gives us the possibility 20 | * to assert the creation and modification times saved to the database. 21 | *
  • 22 | *
23 | * 24 | * @author Petri Kainulainen 25 | */ 26 | public class AuditingDateTimeProvider implements DateTimeProvider { 27 | 28 | private final DateTimeService dateTimeService; 29 | 30 | public AuditingDateTimeProvider(DateTimeService dateTimeService) { 31 | this.dateTimeService = dateTimeService; 32 | } 33 | 34 | @Override 35 | public Calendar getNow() { 36 | return GregorianCalendar.from(dateTimeService.getCurrentDateAndTime()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/common/ConstantDateTimeService.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.common; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.time.ZoneId; 8 | import java.time.ZonedDateTime; 9 | import java.time.format.DateTimeFormatter; 10 | 11 | /** 12 | * This class is used in our integration tests and it always returns the same time. This gives us 13 | * the possibility to verify that the correct timestamps are saved to the database. 14 | * 15 | * @author Petri Kainulainen 16 | */ 17 | @Component("constantDateTimeService") 18 | public class ConstantDateTimeService implements DateTimeService { 19 | 20 | public static final String CURRENT_DATE_AND_TIME = getConstantDateAndTime(); 21 | 22 | private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_ZONED_DATE_TIME; 23 | 24 | private static final Logger LOGGER = LoggerFactory.getLogger(ConstantDateTimeService.class); 25 | 26 | private static String getConstantDateAndTime() { 27 | return "2015-07-19T12:52:28" + 28 | getSystemZoneOffset() + 29 | getSystemZoneId(); 30 | } 31 | 32 | private static String getSystemZoneOffset() { 33 | return ZonedDateTime.now().getOffset().toString(); 34 | } 35 | 36 | private static String getSystemZoneId() { 37 | return "[" + ZoneId.systemDefault().toString() + "]"; 38 | } 39 | 40 | @Override 41 | public ZonedDateTime getCurrentDateAndTime() { 42 | ZonedDateTime constantDateAndTime = ZonedDateTime.from(FORMATTER.parse(CURRENT_DATE_AND_TIME)); 43 | 44 | LOGGER.info("Returning constant date and time: {}", constantDateAndTime); 45 | 46 | return constantDateAndTime; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/common/CurrentTimeDateTimeService.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.common; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.time.ZonedDateTime; 8 | 9 | /** 10 | * This class returns the current time. 11 | * 12 | * @author Petri Kainulainen 13 | */ 14 | @Component("dateTimeService") 15 | public class CurrentTimeDateTimeService implements DateTimeService { 16 | 17 | private static final Logger LOGGER = LoggerFactory.getLogger(CurrentTimeDateTimeService.class); 18 | 19 | @Override 20 | public ZonedDateTime getCurrentDateAndTime() { 21 | ZonedDateTime currentDateAndTime = ZonedDateTime.now(); 22 | 23 | LOGGER.info("Returning current date and time: {}", currentDateAndTime); 24 | 25 | return currentDateAndTime; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/common/DateTimeService.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.common; 2 | 3 | import java.time.ZonedDateTime; 4 | 5 | /** 6 | * This interface defines the methods used to get the current 7 | * date and time. 8 | * 9 | * @author Petri Kainulainen 10 | */ 11 | public interface DateTimeService { 12 | 13 | /** 14 | * Returns the current date and time. 15 | * 16 | * @return 17 | */ 18 | ZonedDateTime getCurrentDateAndTime(); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/config/AsyncConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.config; 2 | 3 | import com.springboot.demo.async.ExceptionHandlingAsyncTaskExecutor; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; 7 | import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler; 8 | import org.springframework.boot.bind.RelaxedPropertyResolver; 9 | import org.springframework.context.EnvironmentAware; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | import org.springframework.context.annotation.Profile; 13 | import org.springframework.core.env.Environment; 14 | import org.springframework.scheduling.annotation.AsyncConfigurer; 15 | import org.springframework.scheduling.annotation.EnableAsync; 16 | import org.springframework.scheduling.annotation.EnableScheduling; 17 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 18 | 19 | import java.util.concurrent.Executor; 20 | 21 | @Configuration 22 | @EnableAsync 23 | @EnableScheduling 24 | @Profile("!" + Constants.SPRING_PROFILE_FAST) 25 | public class AsyncConfiguration implements AsyncConfigurer, EnvironmentAware { 26 | 27 | private final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class); 28 | 29 | private RelaxedPropertyResolver propertyResolver; 30 | 31 | @Override 32 | public void setEnvironment(Environment environment) { 33 | this.propertyResolver = new RelaxedPropertyResolver(environment, "async."); 34 | } 35 | 36 | @Override 37 | @Bean 38 | public Executor getAsyncExecutor() { 39 | log.debug("Creating Async Task Executor"); 40 | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 41 | executor.setCorePoolSize(propertyResolver.getProperty("corePoolSize", Integer.class, 2)); 42 | executor.setMaxPoolSize(propertyResolver.getProperty("maxPoolSize", Integer.class, 50)); 43 | executor.setQueueCapacity(propertyResolver.getProperty("queueCapacity", Integer.class, 10000)); 44 | executor.setThreadNamePrefix("samplegradle-Executor-"); 45 | return new ExceptionHandlingAsyncTaskExecutor(executor); 46 | } 47 | 48 | @Override 49 | public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { 50 | return new SimpleAsyncUncaughtExceptionHandler(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/config/Constants.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.config; 2 | 3 | /** 4 | * Application constants. 5 | */ 6 | public final class Constants { 7 | 8 | // Spring profile for development, production and "fast", see http://jhipster.github.io/profiles.html 9 | public static final String SPRING_PROFILE_DEVELOPMENT = "dev"; 10 | public static final String SPRING_PROFILE_PRODUCTION = "prod"; 11 | public static final String SPRING_PROFILE_FAST = "fast"; 12 | public static final String SPRING_PROFILE_TEST = "test"; 13 | 14 | private Constants() { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/config/DatabaseConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.config; 2 | 3 | import com.fasterxml.jackson.datatype.hibernate4.Hibernate4Module; 4 | import com.springboot.demo.common.AuditingDateTimeProvider; 5 | import com.springboot.demo.common.DateTimeService; 6 | import com.zaxxer.hikari.HikariConfig; 7 | import com.zaxxer.hikari.HikariDataSource; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.boot.bind.RelaxedPropertyResolver; 11 | import org.springframework.context.ApplicationContextException; 12 | import org.springframework.context.EnvironmentAware; 13 | import org.springframework.context.annotation.Bean; 14 | import org.springframework.context.annotation.Configuration; 15 | import org.springframework.core.env.Environment; 16 | import org.springframework.data.auditing.DateTimeProvider; 17 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing; 18 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 19 | import org.springframework.transaction.annotation.EnableTransactionManagement; 20 | import org.springframework.util.StringUtils; 21 | 22 | import javax.sql.DataSource; 23 | import java.util.Arrays; 24 | 25 | @Configuration 26 | @EnableJpaAuditing(dateTimeProviderRef = "dateTimeProvider") 27 | @EnableJpaRepositories("com.springboot.demo.repository") 28 | @EnableTransactionManagement 29 | public class DatabaseConfiguration implements EnvironmentAware { 30 | 31 | private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class); 32 | 33 | private RelaxedPropertyResolver dataSourcePropertyResolver; 34 | 35 | private Environment env; 36 | 37 | @Override 38 | public void setEnvironment(Environment env) { 39 | this.env = env; 40 | this.dataSourcePropertyResolver = new RelaxedPropertyResolver(env, "spring.datasource."); 41 | } 42 | 43 | @Bean(destroyMethod = "close") 44 | public DataSource dataSource() { 45 | log.debug("Configuring Datasource"); 46 | if (dataSourcePropertyResolver.getProperty("url") == null 47 | && dataSourcePropertyResolver.getProperty("databaseName") == null) { 48 | log.error("Your database connection pool configuration is incorrect! The application" + 49 | " cannot start. Please check your Spring profile, current profiles are: {}", 50 | Arrays.toString(env.getActiveProfiles())); 51 | 52 | throw new ApplicationContextException("Database connection pool is not configured correctly"); 53 | } 54 | HikariConfig config = new HikariConfig(); 55 | config.setDataSourceClassName(dataSourcePropertyResolver.getProperty("dataSourceClassName")); 56 | if (StringUtils.isEmpty(dataSourcePropertyResolver.getProperty("url"))) { 57 | config.addDataSourceProperty("databaseName", 58 | dataSourcePropertyResolver.getProperty("databaseName")); 59 | config.addDataSourceProperty("serverName", 60 | dataSourcePropertyResolver.getProperty("serverName")); 61 | } else { 62 | config.addDataSourceProperty("url", dataSourcePropertyResolver.getProperty("url")); 63 | } 64 | config.addDataSourceProperty("user", dataSourcePropertyResolver.getProperty("username")); 65 | config.addDataSourceProperty("password", dataSourcePropertyResolver.getProperty("password")); 66 | 67 | //MySQL optimizations, see https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration 68 | if ("com.mysql.jdbc.jdbc2.optional.MysqlDataSource".equals( 69 | dataSourcePropertyResolver.getProperty("dataSourceClassName"))) { 70 | config.addDataSourceProperty("cachePrepStmts", 71 | dataSourcePropertyResolver.getProperty("cachePrepStmts", "true")); 72 | config.addDataSourceProperty("prepStmtCacheSize", 73 | dataSourcePropertyResolver.getProperty("prepStmtCacheSize", "250")); 74 | config.addDataSourceProperty("prepStmtCacheSqlLimit", dataSourcePropertyResolver 75 | .getProperty("prepStmtCacheSqlLimit", "2048")); 76 | } 77 | return new HikariDataSource(config); 78 | } 79 | 80 | @Bean 81 | public Hibernate4Module hibernate4Module() { 82 | return new Hibernate4Module(); 83 | } 84 | 85 | @Bean 86 | DateTimeProvider dateTimeProvider(DateTimeService dateTimeService) { 87 | return new AuditingDateTimeProvider(dateTimeService); 88 | } 89 | 90 | @Bean 91 | DateTimeProvider constantDateTimeProvider(DateTimeService constantDateTimeService) { 92 | return new AuditingDateTimeProvider(constantDateTimeService); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/config/JacksonConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.config; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.fasterxml.jackson.datatype.joda.JodaModule; 5 | import com.springboot.demo.domain.util.CustomDateTimeDeserializer; 6 | import com.springboot.demo.domain.util.CustomDateTimeSerializer; 7 | import com.springboot.demo.domain.util.CustomLocalDateSerializer; 8 | import com.springboot.demo.domain.util.ISO8601LocalDateDeserializer; 9 | import org.joda.time.DateTime; 10 | import org.joda.time.LocalDate; 11 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 12 | import org.springframework.context.annotation.Bean; 13 | import org.springframework.context.annotation.Configuration; 14 | import org.springframework.context.annotation.Primary; 15 | 16 | @Configuration 17 | public class JacksonConfiguration { 18 | 19 | @Bean 20 | public JodaModule jacksonJodaModule() { 21 | JodaModule module = new JodaModule(); 22 | module.addSerializer(DateTime.class, new CustomDateTimeSerializer()); 23 | module.addDeserializer(DateTime.class, new CustomDateTimeDeserializer()); 24 | module.addSerializer(LocalDate.class, new CustomLocalDateSerializer()); 25 | module.addDeserializer(LocalDate.class, new ISO8601LocalDateDeserializer()); 26 | return module; 27 | } 28 | 29 | @Primary 30 | @Bean 31 | public ObjectMapper jacksonObjectMapper() { 32 | return new ObjectMapper(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/config/MetricsConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.config; 2 | 3 | import com.ryantenney.metrics.spring.config.annotation.EnableMetrics; 4 | import org.springframework.boot.actuate.autoconfigure.ExportMetricWriter; 5 | import org.springframework.boot.actuate.metrics.jmx.JmxMetricWriter; 6 | import org.springframework.boot.actuate.metrics.writer.MetricWriter; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.context.annotation.Profile; 10 | import org.springframework.jmx.export.MBeanExporter; 11 | 12 | 13 | @Configuration 14 | @EnableMetrics(proxyTargetClass = true) 15 | @Profile("!" + Constants.SPRING_PROFILE_TEST) 16 | 17 | public class MetricsConfiguration { 18 | @Bean 19 | @ExportMetricWriter 20 | MetricWriter metricWriter(MBeanExporter exporter) { 21 | return new JmxMetricWriter(exporter); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/config/RedisConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.config; 2 | 3 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | import org.springframework.data.redis.connection.RedisConnectionFactory; 8 | import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; 9 | import org.springframework.data.redis.core.StringRedisTemplate; 10 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 11 | import redis.clients.jedis.JedisPoolConfig; 12 | 13 | 14 | @Configuration 15 | @EnableAutoConfiguration 16 | public class RedisConfiguration { 17 | @Bean 18 | public RedisConnectionFactory jedisConnectionFactory() { 19 | JedisPoolConfig poolConfig = new JedisPoolConfig(); 20 | poolConfig.setMaxTotal(5); 21 | poolConfig.setTestOnBorrow(true); 22 | poolConfig.setTestOnReturn(true); 23 | JedisConnectionFactory ob = new JedisConnectionFactory(poolConfig); 24 | ob.setUsePool(true); 25 | ob.setHostName("localhost"); 26 | ob.setPort(6379); 27 | return ob; 28 | } 29 | 30 | @Bean 31 | public StringRedisTemplate stringRedisTemplate(){ 32 | StringRedisTemplate template = new StringRedisTemplate(jedisConnectionFactory()); 33 | template.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class)); 34 | template.setHashKeySerializer(new Jackson2JsonRedisSerializer<>(Object.class)); 35 | template.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class)); 36 | return new StringRedisTemplate(jedisConnectionFactory()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/config/apidoc/SwaggerConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.config.apidoc; 2 | 3 | import com.springboot.demo.config.Constants; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.boot.bind.RelaxedPropertyResolver; 7 | import org.springframework.context.EnvironmentAware; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.context.annotation.Profile; 11 | import org.springframework.core.env.Environment; 12 | import org.springframework.http.ResponseEntity; 13 | import org.springframework.util.StopWatch; 14 | import springfox.documentation.service.ApiInfo; 15 | import springfox.documentation.spi.DocumentationType; 16 | import springfox.documentation.spring.web.plugins.Docket; 17 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 18 | 19 | import java.util.Date; 20 | 21 | import static springfox.documentation.builders.PathSelectors.regex; 22 | 23 | /** 24 | * Springfox Swagger configuration. 25 | *

26 | * Warning! When having a lot of REST endpoints, Springfox can become a performance issue. In that 27 | * case, you can use a specific Spring profile for this class, so that only front-end developers 28 | * have access to the Swagger view. 29 | */ 30 | @Configuration 31 | @EnableSwagger2 32 | @Profile("!" + Constants.SPRING_PROFILE_PRODUCTION) 33 | public class SwaggerConfiguration implements EnvironmentAware { 34 | 35 | private final Logger log = LoggerFactory.getLogger(SwaggerConfiguration.class); 36 | 37 | public static final String DEFAULT_INCLUDE_PATTERN = "/.*"; 38 | 39 | private RelaxedPropertyResolver propertyResolver; 40 | 41 | @Override 42 | public void setEnvironment(Environment environment) { 43 | this.propertyResolver = new RelaxedPropertyResolver(environment, "swagger."); 44 | } 45 | 46 | /** 47 | * Swagger Springfox configuration. 48 | */ 49 | @Bean 50 | public Docket swaggerSpringfoxDocket() { 51 | log.info("Starting Swagger"); 52 | StopWatch watch = new StopWatch(); 53 | watch.start(); 54 | Docket docket = new Docket(DocumentationType.SWAGGER_2) 55 | .apiInfo(apiInfo()) 56 | .genericModelSubstitutes(ResponseEntity.class) 57 | .forCodeGeneration(true) 58 | .genericModelSubstitutes(ResponseEntity.class) 59 | .directModelSubstitute(org.joda.time.LocalDate.class, String.class) 60 | .directModelSubstitute(org.joda.time.LocalDateTime.class, Date.class) 61 | .directModelSubstitute(org.joda.time.DateTime.class, Date.class) 62 | .directModelSubstitute(java.time.LocalDate.class, String.class) 63 | .directModelSubstitute(java.time.ZonedDateTime.class, Date.class) 64 | .directModelSubstitute(java.time.LocalDateTime.class, Date.class) 65 | .select() 66 | .paths(regex(DEFAULT_INCLUDE_PATTERN)) 67 | .build(); 68 | watch.stop(); 69 | log.info("Started Swagger in {} ms", watch.getTotalTimeMillis()); 70 | return docket; 71 | } 72 | 73 | /** 74 | * API Info as it appears on the swagger-ui page. 75 | */ 76 | private ApiInfo apiInfo() { 77 | return new ApiInfo( 78 | propertyResolver.getProperty("title"), 79 | propertyResolver.getProperty("description"), 80 | propertyResolver.getProperty("version"), 81 | propertyResolver.getProperty("termsOfServiceUrl"), 82 | propertyResolver.getProperty("contact"), 83 | propertyResolver.getProperty("license"), 84 | propertyResolver.getProperty("licenseUrl")); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/domain/BaseEntity.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.domain; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 7 | import com.springboot.demo.domain.util.CustomDateTimeDeserializer; 8 | import com.springboot.demo.domain.util.CustomDateTimeSerializer; 9 | import lombok.Data; 10 | import lombok.EqualsAndHashCode; 11 | import org.hibernate.annotations.Type; 12 | import org.joda.time.DateTime; 13 | import org.springframework.data.annotation.CreatedDate; 14 | import org.springframework.data.annotation.LastModifiedDate; 15 | import org.springframework.data.jpa.domain.support.AuditingEntityListener; 16 | 17 | import javax.persistence.*; 18 | import java.io.Serializable; 19 | 20 | @Data 21 | @MappedSuperclass 22 | @EntityListeners(AuditingEntityListener.class) 23 | @EqualsAndHashCode(of = {"id"}) 24 | public class BaseEntity implements Serializable { 25 | 26 | @Id 27 | @GeneratedValue(strategy = GenerationType.AUTO) 28 | @Column(name = "id") 29 | @JsonProperty(value = "id") 30 | private Long id; 31 | 32 | @Version 33 | @Column(name = "version") 34 | @JsonIgnore 35 | private Long version; 36 | 37 | @Column(name = "created_at") 38 | @JsonIgnore 39 | @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime") 40 | @JsonSerialize(using = CustomDateTimeSerializer.class) 41 | @JsonDeserialize(using = CustomDateTimeDeserializer.class) 42 | @CreatedDate 43 | private DateTime createdAt; 44 | 45 | @Column(name = "updated_at") 46 | @JsonIgnore 47 | @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime") 48 | @JsonSerialize(using = CustomDateTimeSerializer.class) 49 | @JsonDeserialize(using = CustomDateTimeDeserializer.class) 50 | @LastModifiedDate 51 | private DateTime updatedAt; 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/domain/City.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.springboot.demo.domain; 18 | 19 | import com.fasterxml.jackson.core.JsonProcessingException; 20 | import com.fasterxml.jackson.databind.ObjectMapper; 21 | import com.springboot.demo.repository.redis.RedisJsonMapper; 22 | import lombok.Data; 23 | import lombok.NoArgsConstructor; 24 | 25 | import javax.persistence.Column; 26 | import javax.persistence.Entity; 27 | import javax.persistence.GeneratedValue; 28 | import javax.persistence.Id; 29 | import java.io.IOException; 30 | import java.io.Serializable; 31 | 32 | @Data 33 | @Entity 34 | @NoArgsConstructor 35 | public class City implements Serializable, RedisJsonMapper{ 36 | 37 | private static final long serialVersionUID = 1L; 38 | 39 | @Id 40 | @GeneratedValue 41 | private Long id; 42 | 43 | @Column(nullable = false) 44 | private String name; 45 | 46 | @Column(nullable = false) 47 | private String state; 48 | 49 | @Column(nullable = false) 50 | private String country; 51 | 52 | @Column(nullable = false) 53 | private String map; 54 | 55 | public City(String name, String country) { 56 | super(); 57 | this.name = name; 58 | this.country = country; 59 | } 60 | 61 | @Override 62 | public String toJsonString() { 63 | final ObjectMapper jacksonObjectMapper = new ObjectMapper(); 64 | try { 65 | return jacksonObjectMapper.writeValueAsString(this); 66 | } catch (JsonProcessingException e) { 67 | e.printStackTrace(); 68 | } 69 | return null; 70 | } 71 | 72 | @Override 73 | public City fromJson(String json) { 74 | final ObjectMapper jacksonObjectMapper = new ObjectMapper(); 75 | try { 76 | return jacksonObjectMapper.readValue(json, City.class); 77 | } catch (IOException e) { 78 | e.printStackTrace(); 79 | } 80 | return null; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/domain/Hotel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.springboot.demo.domain; 18 | 19 | import org.hibernate.annotations.NaturalId; 20 | 21 | import javax.persistence.*; 22 | import java.io.Serializable; 23 | import java.util.Set; 24 | 25 | @Entity 26 | public class Hotel implements Serializable { 27 | 28 | private static final long serialVersionUID = 1L; 29 | 30 | @Id 31 | @GeneratedValue 32 | private Long id; 33 | 34 | @ManyToOne(optional = false, cascade = CascadeType.ALL) 35 | @NaturalId 36 | private City city; 37 | 38 | @Column(nullable = false) 39 | @NaturalId 40 | private String name; 41 | 42 | @Column(nullable = false) 43 | private String address; 44 | 45 | @Column(nullable = false) 46 | private String zip; 47 | 48 | @OneToMany(fetch = FetchType.LAZY, mappedBy = "hotel") 49 | private Set reviews; 50 | 51 | protected Hotel() { 52 | } 53 | 54 | public Hotel(City city, String name) { 55 | this.city = city; 56 | this.name = name; 57 | } 58 | 59 | public City getCity() { 60 | return this.city; 61 | } 62 | 63 | public String getName() { 64 | return this.name; 65 | } 66 | 67 | public String getAddress() { 68 | return this.address; 69 | } 70 | 71 | public String getZip() { 72 | return this.zip; 73 | } 74 | 75 | public Long getId() { 76 | return this.id; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/domain/HotelSummary.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.springboot.demo.domain; 18 | 19 | import java.io.Serializable; 20 | import java.math.BigDecimal; 21 | import java.math.MathContext; 22 | import java.math.RoundingMode; 23 | 24 | public class HotelSummary implements Serializable { 25 | 26 | private static final long serialVersionUID = 1L; 27 | 28 | private static final MathContext MATH_CONTEXT = new MathContext(2, 29 | RoundingMode.HALF_UP); 30 | 31 | private final City city; 32 | 33 | private final String name; 34 | 35 | private final Double averageRating; 36 | 37 | private final Integer averageRatingRounded; 38 | 39 | public HotelSummary(City city, String name, Double averageRating) { 40 | this.city = city; 41 | this.name = name; 42 | this.averageRating = averageRating == null ? null : new BigDecimal(averageRating, 43 | MATH_CONTEXT).doubleValue(); 44 | this.averageRatingRounded = averageRating == null ? null : (int) Math 45 | .round(averageRating); 46 | } 47 | 48 | public City getCity() { 49 | return this.city; 50 | } 51 | 52 | public String getName() { 53 | return this.name; 54 | } 55 | 56 | public Double getAverageRating() { 57 | return this.averageRating; 58 | } 59 | 60 | public Integer getAverageRatingRounded() { 61 | return this.averageRatingRounded; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/domain/Rating.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.springboot.demo.domain; 18 | 19 | public enum Rating { 20 | TERRIBLE, POOR, AVERAGE, GOOD, EXCELLENT, 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/domain/RatingCount.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.springboot.demo.domain; 18 | 19 | import com.fasterxml.jackson.core.JsonProcessingException; 20 | import com.fasterxml.jackson.databind.ObjectMapper; 21 | import com.springboot.demo.repository.redis.RedisJsonMapper; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import lombok.Setter; 25 | 26 | import java.io.IOException; 27 | import java.io.Serializable; 28 | 29 | @NoArgsConstructor 30 | @Getter 31 | @Setter 32 | public class RatingCount implements Serializable,RedisJsonMapper { 33 | 34 | private static final long serialVersionUID = 1L; 35 | 36 | private Rating rating; 37 | 38 | private long count; 39 | 40 | public RatingCount(Rating rating, long count) { 41 | this.rating = rating; 42 | this.count = count; 43 | } 44 | 45 | @Override 46 | public String toJsonString() { 47 | final ObjectMapper jacksonObjectMapper = new ObjectMapper(); 48 | try { 49 | return jacksonObjectMapper.writeValueAsString(this); 50 | } catch (JsonProcessingException e) { 51 | e.printStackTrace(); 52 | } 53 | return null; 54 | } 55 | 56 | @Override 57 | public RatingCount fromJson(String json) { 58 | final ObjectMapper jacksonObjectMapper = new ObjectMapper(); 59 | try { 60 | return jacksonObjectMapper.readValue(json, RatingCount.class); 61 | } catch (IOException e) { 62 | e.printStackTrace(); 63 | } 64 | return null; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/domain/Review.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.springboot.demo.domain; 18 | 19 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 20 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 21 | import com.springboot.demo.domain.util.CustomDateTimeDeserializer; 22 | import com.springboot.demo.domain.util.CustomDateTimeSerializer; 23 | import com.springboot.demo.web.rest.dto.ReviewDetailsDto; 24 | import lombok.Data; 25 | import lombok.EqualsAndHashCode; 26 | import org.hibernate.annotations.Type; 27 | import org.hibernate.envers.Audited; 28 | import org.joda.time.DateTime; 29 | import org.springframework.util.Assert; 30 | 31 | import javax.persistence.*; 32 | import javax.validation.constraints.NotNull; 33 | 34 | @Data 35 | @EqualsAndHashCode(callSuper = true) 36 | @Entity 37 | public class Review extends BaseEntity { 38 | 39 | @ManyToOne(optional = false) 40 | private Hotel hotel; 41 | 42 | @Column(nullable = false, name = "idx") 43 | private int index; 44 | 45 | @Column(nullable = false) 46 | @Enumerated(EnumType.ORDINAL) 47 | private Rating rating; 48 | 49 | @NotNull 50 | @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime") 51 | @JsonSerialize(using = CustomDateTimeSerializer.class) 52 | @JsonDeserialize(using = CustomDateTimeDeserializer.class) 53 | private DateTime checkInDate; 54 | 55 | @Column(nullable = false) 56 | @Enumerated(EnumType.ORDINAL) 57 | @Audited 58 | private TripType tripType; 59 | 60 | @Column(nullable = false) 61 | @Audited 62 | private String title; 63 | 64 | @Column(nullable = false, length = 5000) 65 | @Audited 66 | private String details; 67 | 68 | protected Review() { 69 | } 70 | 71 | public Review(Hotel hotel, int index, ReviewDetailsDto details) { 72 | Assert.notNull(hotel, "Hotel must not be null"); 73 | Assert.notNull(details, "Details must not be null"); 74 | this.hotel = hotel; 75 | this.index = index; 76 | this.rating = details.getRating(); 77 | this.checkInDate = details.getCheckInDate(); 78 | this.tripType = details.getTripType(); 79 | this.title = details.getTitle(); 80 | this.details = details.getDetails(); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/domain/TripType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.springboot.demo.domain; 18 | 19 | public enum TripType { 20 | BUSINESS, COUPLES, FAMILY, FRIENDS, SOLO 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/domain/util/CustomDateTimeDeserializer.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.domain.util; 2 | 3 | import com.fasterxml.jackson.core.JsonParser; 4 | import com.fasterxml.jackson.core.JsonToken; 5 | import com.fasterxml.jackson.databind.DeserializationContext; 6 | import com.fasterxml.jackson.databind.JsonDeserializer; 7 | import org.joda.time.DateTime; 8 | import org.joda.time.format.ISODateTimeFormat; 9 | 10 | import java.io.IOException; 11 | 12 | /** 13 | * Custom Jackson deserializer for transforming a JSON object to a Joda DateTime object. 14 | */ 15 | public class CustomDateTimeDeserializer extends JsonDeserializer { 16 | 17 | @Override 18 | public DateTime deserialize(JsonParser jp, DeserializationContext ctxt) 19 | throws IOException { 20 | JsonToken t = jp.getCurrentToken(); 21 | if (t == JsonToken.VALUE_STRING) { 22 | String str = jp.getText().trim(); 23 | return ISODateTimeFormat.dateTimeParser().parseDateTime(str); 24 | } 25 | if (t == JsonToken.VALUE_NUMBER_INT) { 26 | return new DateTime(jp.getLongValue()); 27 | } 28 | throw ctxt.mappingException(handledType()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/domain/util/CustomDateTimeSerializer.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.domain.util; 2 | 3 | import com.fasterxml.jackson.core.JsonGenerator; 4 | import com.fasterxml.jackson.databind.JsonSerializer; 5 | import com.fasterxml.jackson.databind.SerializerProvider; 6 | import org.joda.time.DateTime; 7 | import org.joda.time.DateTimeZone; 8 | import org.joda.time.format.DateTimeFormat; 9 | import org.joda.time.format.DateTimeFormatter; 10 | 11 | import java.io.IOException; 12 | 13 | /** 14 | * Custom Jackson serializer for transforming a Joda DateTime object to JSON. 15 | */ 16 | public class CustomDateTimeSerializer extends JsonSerializer { 17 | 18 | private static DateTimeFormatter formatter = DateTimeFormat 19 | .forPattern("yyyy-MM-dd'T'HH:mm:ss'Z'"); 20 | 21 | @Override 22 | public void serialize(DateTime value, JsonGenerator generator, 23 | SerializerProvider serializerProvider) 24 | throws IOException { 25 | generator.writeString(formatter.print(value.toDateTime(DateTimeZone.UTC))); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/domain/util/CustomLocalDateSerializer.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.domain.util; 2 | 3 | import com.fasterxml.jackson.core.JsonGenerator; 4 | import com.fasterxml.jackson.databind.JsonSerializer; 5 | import com.fasterxml.jackson.databind.SerializerProvider; 6 | import org.joda.time.LocalDate; 7 | import org.joda.time.format.DateTimeFormat; 8 | import org.joda.time.format.DateTimeFormatter; 9 | 10 | import java.io.IOException; 11 | 12 | /** 13 | * Custom Jackson serializer for transforming a Joda LocalDate object to JSON. 14 | */ 15 | public class CustomLocalDateSerializer extends JsonSerializer { 16 | 17 | private static DateTimeFormatter formatter = DateTimeFormat 18 | .forPattern("yyyy-MM-dd"); 19 | 20 | @Override 21 | public void serialize(LocalDate value, JsonGenerator jgen, SerializerProvider provider) 22 | throws IOException { 23 | jgen.writeString(formatter.print(value)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/domain/util/FixedH2Dialect.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.domain.util; 2 | 3 | import org.hibernate.dialect.H2Dialect; 4 | 5 | import java.sql.Types; 6 | 7 | public class FixedH2Dialect extends H2Dialect { 8 | public FixedH2Dialect() { 9 | super(); 10 | registerColumnType(Types.FLOAT, "real"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/domain/util/ISO8601LocalDateDeserializer.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.domain.util; 2 | 3 | import com.fasterxml.jackson.core.JsonParser; 4 | import com.fasterxml.jackson.core.JsonToken; 5 | import com.fasterxml.jackson.databind.DeserializationContext; 6 | import com.fasterxml.jackson.databind.JsonDeserializer; 7 | import org.joda.time.LocalDate; 8 | import org.joda.time.format.ISODateTimeFormat; 9 | 10 | import java.io.IOException; 11 | 12 | /** 13 | * Custom Jackson deserializer for transforming a JSON object (using the ISO 8601 date format) to a 14 | * Joda LocalDate object. 15 | */ 16 | public class ISO8601LocalDateDeserializer extends JsonDeserializer { 17 | 18 | @Override 19 | public LocalDate deserialize(JsonParser jp, DeserializationContext ctxt) 20 | throws IOException { 21 | JsonToken t = jp.getCurrentToken(); 22 | if (t == JsonToken.VALUE_STRING) { 23 | String str = jp.getText().trim(); 24 | return ISODateTimeFormat.dateTimeParser().parseDateTime(str).toLocalDate(); 25 | } 26 | if (t == JsonToken.VALUE_NUMBER_INT) { 27 | return new LocalDate(jp.getLongValue()); 28 | } 29 | throw ctxt.mappingException(handledType()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/repository/CityRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.springboot.demo.repository; 18 | 19 | import com.springboot.demo.domain.City; 20 | import org.springframework.data.domain.Page; 21 | import org.springframework.data.domain.Pageable; 22 | import org.springframework.data.repository.Repository; 23 | 24 | public interface CityRepository extends Repository { 25 | 26 | Page findAll(Pageable pageable); 27 | 28 | Page findByNameContainingAndCountryContainingAllIgnoringCase(String name, 29 | String country, Pageable pageable); 30 | 31 | City findByNameAndCountryAllIgnoringCase(String name, String country); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/repository/HotelRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.springboot.demo.repository; 18 | 19 | import com.springboot.demo.domain.City; 20 | import com.springboot.demo.domain.Hotel; 21 | import com.springboot.demo.domain.HotelSummary; 22 | import com.springboot.demo.domain.RatingCount; 23 | import org.springframework.data.domain.Page; 24 | import org.springframework.data.domain.Pageable; 25 | import org.springframework.data.jpa.repository.Query; 26 | import org.springframework.data.repository.Repository; 27 | 28 | import java.util.List; 29 | 30 | public interface HotelRepository extends Repository { 31 | 32 | Hotel findByCityAndName(City city, String name); 33 | 34 | @Query("select new com.springboot.demo.domain.HotelSummary(h.city, h.name, avg(r.rating)) " 35 | + "from Hotel h left outer join h.reviews r where h.city = ?1 group by h") 36 | Page findByCity(City city, Pageable pageable); 37 | 38 | @Query("select new com.springboot.demo.domain.RatingCount(r.rating, count(r)) " 39 | + "from com.springboot.demo.domain.Review r where r.hotel = ?1 group by r.rating order by r.rating DESC") 40 | List findRatingCounts(Hotel hotel); 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/repository/ReviewRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.springboot.demo.repository; 18 | 19 | import com.springboot.demo.domain.Hotel; 20 | import com.springboot.demo.domain.Review; 21 | import org.springframework.data.domain.Page; 22 | import org.springframework.data.domain.Pageable; 23 | import org.springframework.data.repository.Repository; 24 | 25 | public interface ReviewRepository extends Repository { 26 | 27 | Page findByHotel(Hotel hotel, Pageable pageable); 28 | 29 | Review findByHotelAndIndex(Hotel hotel, int index); 30 | 31 | Review save(Review review); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/repository/redis/HashCache.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.repository.redis; 2 | 3 | 4 | import java.util.concurrent.TimeUnit; 5 | 6 | /** 7 | * Created by himanshu.virmani on 04/06/16. 8 | */ 9 | public interface HashCache { 10 | void put(String key, String hashkey, String value); 11 | 12 | void multiPut(String key, V value); 13 | 14 | String get(String key, String hashkey); 15 | 16 | void delete(String key, String hashkey); 17 | 18 | V multiGet(String key, Class clazz); 19 | 20 | void delete(String key); 21 | 22 | void expire(String key, long time, TimeUnit timeUnit); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/repository/redis/KeyUtils.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.repository.redis; 2 | 3 | /** 4 | * Created by himanshu.virmani on 04/06/16. 5 | */ 6 | public class KeyUtils { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/repository/redis/ListCache.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.repository.redis; 2 | 3 | import java.util.Collection; 4 | import java.util.concurrent.TimeUnit; 5 | 6 | /** 7 | * Created by himanshu.virmani on 04/06/16. 8 | */ 9 | public interface ListCache { 10 | void push(String key, V value, boolean right); 11 | 12 | void multiAdd(String key, Collection values, boolean right); 13 | 14 | Collection get(String key, Class clazz); 15 | 16 | V pop(String key, boolean right, Class clazz); 17 | 18 | void delete(String key); 19 | 20 | void trim(String key, int start, int end); 21 | 22 | Long size(String key); 23 | 24 | void expire(String key, long time, TimeUnit timeUnit); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/repository/redis/RedisJsonMapper.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.repository.redis; 2 | 3 | /** 4 | * Created by himanshu.virmani on 05/06/16. 5 | */ 6 | public interface RedisJsonMapper { 7 | 8 | String toJsonString(); 9 | 10 | T fromJson(String json); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/repository/redis/SetCache.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.repository.redis; 2 | 3 | import java.util.Set; 4 | import java.util.concurrent.TimeUnit; 5 | 6 | /** 7 | * Created by himanshu.virmani on 04/06/16. 8 | */ 9 | public interface SetCache { 10 | void add(String key, V value); 11 | 12 | boolean isMemberOf(String key, V value); 13 | 14 | Set members(String key, Class clazz); 15 | 16 | V pop(String key, Class clazz); 17 | 18 | void delete(String key); 19 | 20 | void expire(String key, long time, TimeUnit timeUnit); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/repository/redis/ValueCache.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.repository.redis; 2 | 3 | import java.util.Collection; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | /** 9 | * Created by himanshu.virmani on 04/06/16. 10 | */ 11 | public interface ValueCache { 12 | void put(String key, V value); 13 | 14 | void multiPut(Map keyValues); 15 | 16 | V get(String key, Class clazz); 17 | 18 | List multiGet(Collection keys); 19 | 20 | void delete(String key); 21 | 22 | void expire(String key, long time, TimeUnit timeUnit); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/repository/redis/impl/HashCacheRedisRepository.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.repository.redis.impl; 2 | 3 | import com.springboot.demo.repository.redis.HashCache; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.data.redis.core.StringRedisTemplate; 6 | import org.springframework.data.redis.hash.DecoratingStringHashMapper; 7 | import org.springframework.data.redis.hash.HashMapper; 8 | import org.springframework.data.redis.hash.JacksonHashMapper; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | import java.util.concurrent.TimeUnit; 14 | 15 | /** 16 | * Created by himanshu.virmani on 04/06/16. 17 | */ 18 | @Component("hashCacheRedisRepository") 19 | public class HashCacheRedisRepository implements HashCache { 20 | 21 | @Autowired 22 | private StringRedisTemplate redisTemplate; 23 | 24 | private HashMapper mapper; 25 | 26 | @Override 27 | public void put(String key, String hashkey, String value) { 28 | redisTemplate.opsForHash().put(key, hashkey, value); 29 | } 30 | 31 | @Override 32 | public void multiPut(String key, V obj) { 33 | if (obj == null) return; 34 | if(mapper == null) { 35 | mapper = new DecoratingStringHashMapper<>(new JacksonHashMapper<>((Class) obj.getClass())); 36 | } 37 | redisTemplate.opsForHash().putAll(key, mapper.toHash(obj)); 38 | } 39 | 40 | @Override 41 | public String get(String key, String hashkey) { 42 | return (String) redisTemplate.opsForHash().get(key, hashkey); 43 | } 44 | 45 | @Override 46 | public void delete(String key, String hashkey) { 47 | redisTemplate.opsForHash().delete(key, hashkey); 48 | } 49 | 50 | @Override 51 | public V multiGet(String key, Class clazz) { 52 | final Map map = redisTemplate.opsForHash().entries(key); 53 | if(map == null || map.isEmpty()) return null; 54 | if(mapper == null) { 55 | mapper = new DecoratingStringHashMapper<>(new JacksonHashMapper<>(clazz)); 56 | } 57 | return mapper.fromHash((HashMap) (Map) map); 58 | } 59 | 60 | @Override 61 | public void delete(String key) { 62 | redisTemplate.delete(key); 63 | } 64 | 65 | @Override 66 | public void expire(String key, long time, TimeUnit timeUnit) { 67 | redisTemplate.expire(key, time, timeUnit); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/repository/redis/impl/ListCacheRedisRepository.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.repository.redis.impl; 2 | 3 | import com.springboot.demo.repository.redis.ListCache; 4 | import com.springboot.demo.repository.redis.RedisJsonMapper; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.data.redis.core.StringRedisTemplate; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Collection; 11 | import java.util.List; 12 | import java.util.concurrent.TimeUnit; 13 | 14 | /** 15 | * Created by himanshu.virmani on 04/06/16. 16 | */ 17 | @Component("listCacheRedisRepository") 18 | public class ListCacheRedisRepository implements ListCache { 19 | 20 | @Autowired 21 | private StringRedisTemplate redisTemplate; 22 | 23 | @Override 24 | public void push(String key, V value, boolean right) { 25 | if (right) { 26 | redisTemplate.opsForList().rightPush(key, value.toJsonString()); 27 | } else { 28 | redisTemplate.opsForList().leftPush(key, value.toJsonString()); 29 | } 30 | } 31 | 32 | @Override 33 | public void multiAdd(String key, Collection values, boolean right) { 34 | // redisTemplate.multi(); 35 | //Have to find better implementation for this 36 | for (V value : values) { 37 | push(key, value, right); 38 | } 39 | // redisTemplate.exec(); 40 | } 41 | 42 | @Override 43 | public Collection get(String key, Class clazz) { 44 | List list = redisTemplate.opsForList().range(key, 0, -1); 45 | if(list == null && list.isEmpty()) return null; 46 | List collection = new ArrayList<>(); 47 | for (String item : list) { 48 | try { 49 | collection.add((V)clazz.newInstance().fromJson(item)); 50 | } catch (InstantiationException | IllegalAccessException e) { 51 | e.printStackTrace(); 52 | } 53 | } 54 | return collection; 55 | } 56 | 57 | @Override 58 | public V pop(String key, boolean right, Class clazz) { 59 | String value; 60 | if (right) { 61 | value = redisTemplate.opsForList().rightPop(key); 62 | } else { 63 | value = redisTemplate.opsForList().leftPop(key); 64 | } 65 | try { 66 | return (V)clazz.newInstance().fromJson(value); 67 | } catch (InstantiationException | IllegalAccessException e) { 68 | e.printStackTrace(); 69 | } 70 | return null; 71 | } 72 | 73 | @Override 74 | public void delete(String key) { 75 | redisTemplate.delete(key); 76 | } 77 | 78 | @Override 79 | public void trim(String key, int start, int end) { 80 | redisTemplate.opsForList().trim(key, start, end); 81 | } 82 | 83 | @Override 84 | public Long size(String key) { 85 | return redisTemplate.opsForList().size(key); 86 | } 87 | 88 | @Override 89 | public void expire(String key, long time, TimeUnit timeUnit) { 90 | redisTemplate.expire(key, time, timeUnit); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/repository/redis/impl/SetCacheRedisRepository.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.repository.redis.impl; 2 | 3 | import com.springboot.demo.repository.redis.RedisJsonMapper; 4 | import com.springboot.demo.repository.redis.SetCache; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.data.redis.core.StringRedisTemplate; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.HashSet; 10 | import java.util.Set; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | /** 14 | * Created by himanshu.virmani on 04/06/16. 15 | */ 16 | @Component("setCacheRedisRepository") 17 | public class SetCacheRedisRepository implements SetCache { 18 | 19 | @Autowired 20 | private StringRedisTemplate redisTemplate; 21 | 22 | @Override 23 | public void add(String key, V value) { 24 | redisTemplate.opsForSet().add(key,value.toJsonString()); 25 | } 26 | 27 | @Override 28 | public boolean isMemberOf(String key, V value) { 29 | return redisTemplate.opsForSet().isMember(key,value.toJsonString()); 30 | } 31 | 32 | @Override 33 | public Set members(String key, Class clazz) { 34 | Set strings = redisTemplate.opsForSet().members(key); 35 | if (strings == null || strings.isEmpty()) return null; 36 | Set set = new HashSet<>(); 37 | for (String value : strings) { 38 | try { 39 | set.add((V)clazz.newInstance().fromJson(value)); 40 | } catch (InstantiationException | IllegalAccessException e) { 41 | e.printStackTrace(); 42 | } 43 | } 44 | return set; 45 | } 46 | 47 | @Override 48 | public V pop(String key, Class clazz) { 49 | final String value = redisTemplate.opsForSet().pop(key); 50 | if (value == null || value.isEmpty()) return null; 51 | try { 52 | return (V)clazz.newInstance().fromJson(value); 53 | } catch (InstantiationException | IllegalAccessException e) { 54 | e.printStackTrace(); 55 | } 56 | return null; 57 | } 58 | 59 | @Override 60 | public void delete(String key) { 61 | redisTemplate.delete(key); 62 | } 63 | 64 | @Override 65 | public void expire(String key, long time, TimeUnit timeUnit) { 66 | redisTemplate.expire(key, time, timeUnit); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/repository/redis/impl/ValueCacheRedisRepository.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.repository.redis.impl; 2 | 3 | import com.springboot.demo.repository.redis.RedisJsonMapper; 4 | import com.springboot.demo.repository.redis.ValueCache; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.data.redis.core.StringRedisTemplate; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.Collection; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.concurrent.TimeUnit; 13 | 14 | /** 15 | * Created by himanshu.virmani on 04/06/16. 16 | */ 17 | @Component("valueCacheRedisRepository") 18 | public class ValueCacheRedisRepository implements ValueCache { 19 | 20 | @Autowired 21 | private StringRedisTemplate redisTemplate; 22 | 23 | @Override 24 | public void put(String key, V value) { 25 | redisTemplate.opsForValue().set(key, value.toJsonString()); 26 | } 27 | 28 | @Override 29 | public void multiPut(Map keyValues) { 30 | redisTemplate.opsForValue().multiSet(keyValues); 31 | } 32 | 33 | @Override 34 | public V get(String key, Class clazz) { 35 | try { 36 | final String json = redisTemplate.opsForValue().get(key); 37 | 38 | if (json == null) return null; 39 | // this below is returning RedisJsonMapper because this reflection only works 40 | // for superclass only 41 | /* return (V) ((Class) GenericTypeResolver. 42 | resolveTypeArgument(getClass(), ValueCacheRedisRepository.class)). 43 | newInstance().fromJson(json);*/ 44 | return (V) (clazz.newInstance().fromJson(json)); 45 | } catch (Exception e) { 46 | e.printStackTrace(); 47 | } 48 | return null; 49 | } 50 | 51 | @Override 52 | public List multiGet(Collection keys) { 53 | return redisTemplate.opsForValue().multiGet(keys); 54 | } 55 | 56 | @Override 57 | public void delete(String key) { 58 | redisTemplate.delete(key); 59 | } 60 | 61 | @Override 62 | public void expire(String key, long time, TimeUnit timeUnit) { 63 | redisTemplate.expire(key, time, timeUnit); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/service/CityService.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.service; 2 | 3 | import com.springboot.demo.domain.City; 4 | import com.springboot.demo.domain.HotelSummary; 5 | import com.springboot.demo.service.criteria.CitySearchCriteria; 6 | import org.springframework.data.domain.Page; 7 | import org.springframework.data.domain.Pageable; 8 | 9 | public interface CityService { 10 | 11 | Page findCities(CitySearchCriteria criteria, Pageable pageable); 12 | 13 | City getCity(String name, String country); 14 | 15 | Page getHotels(City city, Pageable pageable); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/service/HotelService.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.service; 2 | 3 | import com.springboot.demo.domain.City; 4 | import com.springboot.demo.domain.Hotel; 5 | import com.springboot.demo.domain.Review; 6 | import com.springboot.demo.web.rest.dto.ReviewDetailsDto; 7 | import org.springframework.data.domain.Page; 8 | import org.springframework.data.domain.Pageable; 9 | 10 | public interface HotelService { 11 | 12 | Hotel getHotel(City city, String name); 13 | 14 | Page getReviews(Hotel hotel, Pageable pageable); 15 | 16 | Review getReview(Hotel hotel, int index); 17 | 18 | Review addReview(Hotel hotel, ReviewDetailsDto details); 19 | 20 | ReviewsSummary getReviewSummary(Hotel hotel); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/service/ReviewsSummary.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.service; 2 | 3 | import com.springboot.demo.domain.Rating; 4 | 5 | public interface ReviewsSummary { 6 | 7 | long getNumberOfReviewsWithRating(Rating rating); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/service/criteria/CitySearchCriteria.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.service.criteria; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import org.springframework.util.Assert; 6 | 7 | import java.io.Serializable; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | public class CitySearchCriteria implements Serializable { 12 | 13 | private static final long serialVersionUID = 1L; 14 | 15 | private String name; 16 | 17 | public CitySearchCriteria(String name) { 18 | Assert.notNull(name, "Name must not be null"); 19 | this.name = name; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/service/impl/CityServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.service.impl; 2 | 3 | import com.springboot.demo.domain.City; 4 | import com.springboot.demo.domain.HotelSummary; 5 | import com.springboot.demo.repository.CityRepository; 6 | import com.springboot.demo.repository.HotelRepository; 7 | import com.springboot.demo.repository.redis.impl.HashCacheRedisRepository; 8 | import com.springboot.demo.repository.redis.impl.ListCacheRedisRepository; 9 | import com.springboot.demo.repository.redis.impl.ValueCacheRedisRepository; 10 | import com.springboot.demo.service.CityService; 11 | import com.springboot.demo.service.criteria.CitySearchCriteria; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.data.domain.Page; 14 | import org.springframework.data.domain.Pageable; 15 | import org.springframework.stereotype.Component; 16 | import org.springframework.transaction.annotation.Transactional; 17 | import org.springframework.util.Assert; 18 | import org.springframework.util.StringUtils; 19 | 20 | import java.util.concurrent.TimeUnit; 21 | 22 | @Component("cityService") 23 | @Transactional 24 | public class CityServiceImpl implements CityService { 25 | 26 | private final CityRepository cityRepository; 27 | 28 | private final HotelRepository hotelRepository; 29 | 30 | @Autowired 31 | private HashCacheRedisRepository valueCacheRedisRepository; 32 | 33 | @Autowired 34 | public CityServiceImpl(CityRepository cityRepository, HotelRepository hotelRepository) { 35 | this.cityRepository = cityRepository; 36 | this.hotelRepository = hotelRepository; 37 | } 38 | 39 | @Override 40 | public Page findCities(CitySearchCriteria criteria, Pageable pageable) { 41 | 42 | Assert.notNull(criteria, "Criteria must not be null"); 43 | String name = criteria.getName(); 44 | 45 | if (!StringUtils.hasLength(name)) { 46 | return this.cityRepository.findAll(null); 47 | } 48 | 49 | String country = ""; 50 | int splitPos = name.lastIndexOf(","); 51 | 52 | if (splitPos >= 0) { 53 | country = name.substring(splitPos + 1); 54 | name = name.substring(0, splitPos); 55 | } 56 | 57 | return this.cityRepository 58 | .findByNameContainingAndCountryContainingAllIgnoringCase(name.trim(), 59 | country.trim(), pageable); 60 | } 61 | 62 | @Override 63 | public City getCity(String name, String country) { 64 | Assert.notNull(name, "Name must not be null"); 65 | Assert.notNull(country, "Country must not be null"); 66 | City city = valueCacheRedisRepository.multiGet("city:" + name + ":country:" + country, City.class); 67 | 68 | if (city == null) { 69 | city = cityRepository.findByNameAndCountryAllIgnoringCase(name, country); 70 | if (city != null) { 71 | valueCacheRedisRepository.multiPut("city:" + name + ":country:" + country, city); 72 | valueCacheRedisRepository.expire("city:" + name + ":country:" + country, 60, TimeUnit.SECONDS); 73 | } 74 | } 75 | return city; 76 | } 77 | 78 | @Override 79 | public Page getHotels(City city, Pageable pageable) { 80 | Assert.notNull(city, "City must not be null"); 81 | return this.hotelRepository.findByCity(city, pageable); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/service/impl/HotelServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.service.impl; 2 | 3 | import com.springboot.demo.domain.*; 4 | import com.springboot.demo.repository.HotelRepository; 5 | import com.springboot.demo.repository.ReviewRepository; 6 | import com.springboot.demo.repository.redis.impl.ListCacheRedisRepository; 7 | import com.springboot.demo.service.HotelService; 8 | import com.springboot.demo.service.ReviewsSummary; 9 | import com.springboot.demo.web.rest.dto.ReviewDetailsDto; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.data.domain.Page; 12 | import org.springframework.data.domain.Pageable; 13 | import org.springframework.stereotype.Component; 14 | import org.springframework.transaction.annotation.Transactional; 15 | import org.springframework.util.Assert; 16 | 17 | import java.util.*; 18 | import java.util.concurrent.TimeUnit; 19 | 20 | @Component("hotelService") 21 | @Transactional 22 | public class HotelServiceImpl implements HotelService { 23 | 24 | @Autowired 25 | private ListCacheRedisRepository ratingCountListCacheRedisRepository; 26 | 27 | private final HotelRepository hotelRepository; 28 | 29 | private final ReviewRepository reviewRepository; 30 | 31 | @Autowired 32 | public HotelServiceImpl(HotelRepository hotelRepository, 33 | ReviewRepository reviewRepository) { 34 | this.hotelRepository = hotelRepository; 35 | this.reviewRepository = reviewRepository; 36 | } 37 | 38 | @Override 39 | public Hotel getHotel(City city, String name) { 40 | Assert.notNull(city, "City must not be null"); 41 | Assert.hasLength(name, "Name must not be empty"); 42 | return this.hotelRepository.findByCityAndName(city, name); 43 | } 44 | 45 | @Override 46 | public Page getReviews(Hotel hotel, Pageable pageable) { 47 | Assert.notNull(hotel, "Hotel must not be null"); 48 | return this.reviewRepository.findByHotel(hotel, pageable); 49 | } 50 | 51 | @Override 52 | public Review getReview(Hotel hotel, int reviewNumber) { 53 | Assert.notNull(hotel, "Hotel must not be null"); 54 | return this.reviewRepository.findByHotelAndIndex(hotel, reviewNumber); 55 | } 56 | 57 | @Override 58 | public Review addReview(Hotel hotel, ReviewDetailsDto details) { 59 | Review review = new Review(hotel, 1, details); 60 | return reviewRepository.save(review); 61 | } 62 | 63 | @Override 64 | public ReviewsSummary getReviewSummary(Hotel hotel) { 65 | Collection ratingCounts = ratingCountListCacheRedisRepository.get("ratingcounts:hotel:" + hotel.getId(), RatingCount.class); 66 | 67 | if (ratingCounts == null || ratingCounts.isEmpty()) { 68 | ratingCounts = this.hotelRepository.findRatingCounts(hotel); 69 | if (ratingCounts != null) { 70 | ratingCountListCacheRedisRepository.multiAdd("ratingcounts:hotel:" + hotel.getId(),ratingCounts, true); 71 | ratingCountListCacheRedisRepository.expire("ratingcounts:hotel:" + hotel.getId(), 60, TimeUnit.SECONDS); 72 | } 73 | } 74 | 75 | return new ReviewsSummaryImpl(new ArrayList<>(ratingCounts)); 76 | } 77 | 78 | private static class ReviewsSummaryImpl implements ReviewsSummary { 79 | 80 | private final Map ratingCount; 81 | 82 | public ReviewsSummaryImpl(List ratingCounts) { 83 | this.ratingCount = new HashMap<>(); 84 | for (RatingCount ratingCount : ratingCounts) { 85 | this.ratingCount.put(ratingCount.getRating(), ratingCount.getCount()); 86 | } 87 | } 88 | 89 | @Override 90 | public long getNumberOfReviewsWithRating(Rating rating) { 91 | Long count = this.ratingCount.get(rating); 92 | return count == null ? 0 : count; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/web/filter/CachingHttpHeadersFilter.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.web.filter; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.core.env.Environment; 6 | 7 | import javax.servlet.*; 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import java.io.IOException; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | /** 14 | * This filter is used in production, to put HTTP cache headers with a long (1 month) expiration 15 | * time.

16 | */ 17 | public class CachingHttpHeadersFilter implements Filter { 18 | 19 | private final Logger log = LoggerFactory.getLogger(CachingHttpHeadersFilter.class); 20 | 21 | // We consider the last modified date is the start up time of the server 22 | private final static long LAST_MODIFIED = System.currentTimeMillis(); 23 | 24 | private long CACHE_TIME_TO_LIVE = TimeUnit.DAYS.toMillis(31L); 25 | 26 | private Environment env; 27 | 28 | public CachingHttpHeadersFilter(Environment env) { 29 | this.env = env; 30 | } 31 | 32 | @Override 33 | public void init(FilterConfig filterConfig) throws ServletException { 34 | CACHE_TIME_TO_LIVE = 35 | TimeUnit.DAYS.toMillis(env.getProperty("http.cache.timeToLiveInDays", Long.class, 31L)); 36 | } 37 | 38 | @Override 39 | public void destroy() { 40 | // Nothing to destroy 41 | } 42 | 43 | @Override 44 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 45 | throws IOException, ServletException { 46 | HttpServletResponse httpResponse = (HttpServletResponse) response; 47 | HttpServletRequest httpRequest = (HttpServletRequest) request; 48 | 49 | httpResponse.setHeader("Cache-Control", "max-age=" + CACHE_TIME_TO_LIVE + ", public"); 50 | httpResponse.setHeader("Pragma", "cache"); 51 | 52 | // Setting Expires header, for proxy caching 53 | httpResponse.setDateHeader("Expires", CACHE_TIME_TO_LIVE + System.currentTimeMillis()); 54 | 55 | // Setting the Last-Modified header, for browser caching 56 | httpResponse.setDateHeader("Last-Modified", LAST_MODIFIED); 57 | 58 | chain.doFilter(request, response); 59 | 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/web/propertyeditors/LocaleDateTimeEditor.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.web.propertyeditors; 2 | 3 | import org.joda.time.LocalDateTime; 4 | import org.joda.time.format.DateTimeFormat; 5 | import org.joda.time.format.DateTimeFormatter; 6 | import org.springframework.util.StringUtils; 7 | 8 | import java.beans.PropertyEditorSupport; 9 | import java.util.Date; 10 | 11 | /** 12 | * Custom PropertyEditorSupport to convert from String to 13 | * Date using JodaTime (http://www.joda.org/joda-time/). 14 | */ 15 | public class LocaleDateTimeEditor extends PropertyEditorSupport { 16 | 17 | private final DateTimeFormatter formatter; 18 | 19 | private final boolean allowEmpty; 20 | 21 | /** 22 | * Create a new LocaleDateTimeEditor instance, using the given format for 23 | * parsing and rendering. 24 | *

25 | * The "allowEmpty" parameter states if an empty String should be allowed 26 | * for parsing, i.e. get interpreted as null value. Otherwise, an 27 | * IllegalArgumentException gets thrown. 28 | * 29 | * @param dateFormat DateFormat to use for parsing and rendering 30 | * @param allowEmpty if empty strings should be allowed 31 | */ 32 | public LocaleDateTimeEditor(String dateFormat, boolean allowEmpty) { 33 | this.formatter = DateTimeFormat.forPattern(dateFormat); 34 | this.allowEmpty = allowEmpty; 35 | } 36 | 37 | /** 38 | * Format the YearMonthDay as String, using the specified format. 39 | * 40 | * @return DateTime formatted string 41 | */ 42 | @Override 43 | public String getAsText() { 44 | Date value = (Date) getValue(); 45 | return value != null ? new LocalDateTime(value).toString(formatter) : ""; 46 | } 47 | 48 | /** 49 | * Parse the value from the given text, using the specified format. 50 | * 51 | * @param text the text to format 52 | * @throws IllegalArgumentException 53 | */ 54 | @Override 55 | public void setAsText(String text) throws IllegalArgumentException { 56 | if (allowEmpty && !StringUtils.hasText(text)) { 57 | // Treat empty String as null value. 58 | setValue(null); 59 | } else { 60 | setValue(new LocalDateTime(formatter.parseDateTime(text))); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/web/rest/BaseController.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.web.rest; 2 | 3 | /** 4 | * The BaseController class implements common functionality for all Controller 5 | * classes. As of now there is none. But this is used in the Tests for creating 6 | * stand alone controller context 7 | * Controller methods. 8 | * 9 | * @author Matt Warman 10 | */ 11 | public class BaseController { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/web/rest/CityController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.springboot.demo.web.rest; 18 | 19 | import com.springboot.demo.domain.City; 20 | import com.springboot.demo.service.CityService; 21 | import com.springboot.demo.service.criteria.CitySearchCriteria; 22 | import com.springboot.demo.web.rest.errors.CityNotFoundException; 23 | import org.springframework.beans.factory.annotation.Autowired; 24 | import org.springframework.data.domain.Page; 25 | import org.springframework.data.domain.PageRequest; 26 | import org.springframework.http.MediaType; 27 | import org.springframework.transaction.annotation.Transactional; 28 | import org.springframework.web.bind.annotation.*; 29 | 30 | @RestController 31 | @RequestMapping("/city") 32 | public class CityController extends BaseController { 33 | 34 | @Autowired 35 | private CityService cityService; 36 | 37 | 38 | @RequestMapping(value = "/search/{keyword}", method = RequestMethod.GET, 39 | produces = MediaType.APPLICATION_JSON_VALUE) 40 | @ResponseBody 41 | @Transactional(readOnly = true) 42 | public Page search(@PathVariable("keyword") String keyword) { 43 | CitySearchCriteria criteria = new CitySearchCriteria(keyword); 44 | PageRequest pageRequest = new PageRequest(0, 4); 45 | Page result = this.cityService.findCities(criteria, pageRequest); 46 | if (result == null || result.getTotalElements() == 0) { 47 | throw new CityNotFoundException(); 48 | } 49 | return result; 50 | } 51 | 52 | @RequestMapping(value = "/{city}/country/{country}", method = RequestMethod.GET, 53 | produces = MediaType.APPLICATION_JSON_VALUE) 54 | @ResponseBody 55 | @Transactional(readOnly = true) 56 | public City getCity(@PathVariable("city") String city, @PathVariable("country") String country) { 57 | City result = this.cityService.getCity(city, country); 58 | if (result == null) { 59 | throw new CityNotFoundException(); 60 | } 61 | return result; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/web/rest/HotelController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.springboot.demo.web.rest; 18 | 19 | import com.springboot.demo.domain.City; 20 | import com.springboot.demo.domain.Hotel; 21 | import com.springboot.demo.domain.Rating; 22 | import com.springboot.demo.domain.Review; 23 | import com.springboot.demo.service.CityService; 24 | import com.springboot.demo.service.HotelService; 25 | import com.springboot.demo.service.ReviewsSummary; 26 | import com.springboot.demo.web.rest.dto.ReviewDetailsDto; 27 | import org.slf4j.Logger; 28 | import org.slf4j.LoggerFactory; 29 | import org.springframework.beans.factory.annotation.Autowired; 30 | import org.springframework.beans.factory.annotation.Value; 31 | import org.springframework.data.domain.Page; 32 | import org.springframework.data.domain.PageRequest; 33 | import org.springframework.http.MediaType; 34 | import org.springframework.transaction.annotation.Transactional; 35 | import org.springframework.web.bind.annotation.*; 36 | 37 | import java.util.Map; 38 | 39 | @RestController 40 | @RequestMapping("/hotel") 41 | public class HotelController extends BaseController { 42 | 43 | private final Logger log = LoggerFactory.getLogger(HotelController.class); 44 | 45 | @Value("${cache.timeToLiveSeconds}") 46 | private String cacheTime; 47 | 48 | @Autowired 49 | private CityService cityService; 50 | 51 | @Autowired 52 | private HotelService hotelService; 53 | 54 | @RequestMapping(value = "/city/{city}/country/{country}/hotel/{hotel}", method = RequestMethod.GET, 55 | produces = MediaType.APPLICATION_JSON_VALUE) 56 | @ResponseBody 57 | @Transactional(readOnly = true) 58 | public Hotel getHotel(@PathVariable("city") String city, 59 | @PathVariable("country") String country, @PathVariable("hotel") String hotel) { 60 | final City citi = cityService.getCity(city, country); 61 | return this.hotelService.getHotel(citi, hotel); 62 | } 63 | 64 | @RequestMapping(value = "/city/{city}/country/{country}/hotel/{hotel}/review", method = RequestMethod.GET, 65 | produces = MediaType.APPLICATION_JSON_VALUE) 66 | @ResponseBody 67 | @Transactional(readOnly = true) 68 | public Page getHotelReview(@PathVariable("city") String city, 69 | @PathVariable("country") String country, @PathVariable("hotel") String hotel) { 70 | final City citi = cityService.getCity(city, country); 71 | PageRequest pageRequest = new PageRequest(0, 4); 72 | log.info("Cache time config value " + cacheTime); 73 | return this.hotelService.getReviews(this.hotelService.getHotel(citi, hotel), pageRequest); 74 | } 75 | 76 | @RequestMapping(value = "/city/{city}/country/{country}/hotel/{hotel}/review", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) 77 | @ResponseBody 78 | public Review addHotelReview(@PathVariable("city") String city, 79 | @PathVariable("country") String country, @PathVariable("hotel") String hotel, @RequestBody 80 | ReviewDetailsDto reviewDetails) { 81 | final City citi = cityService.getCity(city, country); 82 | log.info("Review Details date : - " + reviewDetails.toString()); 83 | return this.hotelService.addReview(this.hotelService.getHotel(citi, hotel), reviewDetails); 84 | } 85 | 86 | @RequestMapping(value = "/city/{city}/country/{country}/hotel/{hotel}/review_summary", 87 | method = RequestMethod.GET, 88 | produces = MediaType.APPLICATION_JSON_VALUE) 89 | @ResponseBody 90 | @Transactional(readOnly = true) 91 | public Long getReviewSummary(@PathVariable("city") String city, 92 | @PathVariable("country") String country, @PathVariable("hotel") String hotel) { 93 | final City citi = cityService.getCity(city, country); 94 | return this.hotelService.getReviewSummary(this.hotelService.getHotel(citi, hotel)).getNumberOfReviewsWithRating(Rating.AVERAGE); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/web/rest/LogsController.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.web.rest; 2 | 3 | import ch.qos.logback.classic.Level; 4 | import ch.qos.logback.classic.LoggerContext; 5 | import com.codahale.metrics.annotation.Timed; 6 | import com.springboot.demo.web.rest.dto.LoggerDTO; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.http.MediaType; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | import java.util.List; 13 | import java.util.stream.Collectors; 14 | 15 | /** 16 | * Controller for view and managing Log Level at runtime. 17 | */ 18 | @RestController 19 | @RequestMapping("/api") 20 | public class LogsController extends BaseController { 21 | 22 | @RequestMapping(value = "/logs", 23 | method = RequestMethod.GET, 24 | produces = MediaType.APPLICATION_JSON_VALUE) 25 | @Timed 26 | public List getList() { 27 | LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); 28 | return context.getLoggerList() 29 | .stream() 30 | .map(LoggerDTO::new) 31 | .collect(Collectors.toList()); 32 | 33 | } 34 | 35 | @RequestMapping(value = "/logs", 36 | method = RequestMethod.PUT) 37 | @ResponseStatus(HttpStatus.NO_CONTENT) 38 | @Timed 39 | public void changeLevel(@RequestBody LoggerDTO jsonLogger) { 40 | LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); 41 | context.getLogger(jsonLogger.getName()).setLevel(Level.valueOf(jsonLogger.getLevel())); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/web/rest/dto/LoggerDTO.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.web.rest.dto; 2 | 3 | import ch.qos.logback.classic.Logger; 4 | import com.fasterxml.jackson.annotation.JsonCreator; 5 | 6 | public class LoggerDTO { 7 | 8 | private String name; 9 | 10 | private String level; 11 | 12 | public LoggerDTO(Logger logger) { 13 | this.name = logger.getName(); 14 | this.level = logger.getEffectiveLevel().toString(); 15 | } 16 | 17 | @JsonCreator 18 | public LoggerDTO() { 19 | } 20 | 21 | public String getName() { 22 | return name; 23 | } 24 | 25 | public void setName(String name) { 26 | this.name = name; 27 | } 28 | 29 | public String getLevel() { 30 | return level; 31 | } 32 | 33 | public void setLevel(String level) { 34 | this.level = level; 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return "LoggerDTO{" + 40 | "name='" + name + '\'' + 41 | ", level='" + level + '\'' + 42 | '}'; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/web/rest/dto/ReviewDetailsDto.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.springboot.demo.web.rest.dto; 18 | 19 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 20 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 21 | import com.springboot.demo.domain.Rating; 22 | import com.springboot.demo.domain.TripType; 23 | import com.springboot.demo.domain.util.CustomDateTimeDeserializer; 24 | import com.springboot.demo.domain.util.CustomDateTimeSerializer; 25 | import lombok.Data; 26 | import org.hibernate.annotations.Type; 27 | import org.joda.time.DateTime; 28 | 29 | import java.io.Serializable; 30 | 31 | @Data 32 | public class ReviewDetailsDto implements Serializable { 33 | 34 | private static final long serialVersionUID = 1L; 35 | 36 | private Rating rating; 37 | 38 | @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime") 39 | @JsonSerialize(using = CustomDateTimeSerializer.class) 40 | @JsonDeserialize(using = CustomDateTimeDeserializer.class) 41 | private DateTime checkInDate; 42 | 43 | private TripType tripType; 44 | 45 | private String title; 46 | 47 | private String details; 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/web/rest/errors/CityNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.web.rest.errors; 2 | 3 | /** 4 | * Created by neerajsi on 18/09/15. 5 | */ 6 | public class CityNotFoundException extends RuntimeException { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/web/rest/errors/CustomParameterizedException.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.web.rest.errors; 2 | 3 | /** 4 | * Custom, parameterized exception, which can be translated on the client side. 5 | * For example: 6 | *

7 | *

 8 |  * throw new CustomParameterizedException("myCustomError", "hello", "world");
 9 |  * 
10 | *

11 | * Can be translated with: 12 | *

13 | *

14 |  * "error.myCustomError" :  "The server says {{params[0]}} to {{params[1]}}"
15 |  * 
16 | */ 17 | public class CustomParameterizedException extends RuntimeException { 18 | 19 | private static final long serialVersionUID = 1L; 20 | 21 | private final String message; 22 | private final String[] params; 23 | 24 | public CustomParameterizedException(String message, String... params) { 25 | super(message); 26 | this.message = message; 27 | this.params = params; 28 | } 29 | 30 | public ParameterizedErrorDTO getErrorDTO() { 31 | return new ParameterizedErrorDTO(message, params); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/web/rest/errors/ErrorConstants.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.web.rest.errors; 2 | 3 | public final class ErrorConstants { 4 | 5 | public static final String ERR_CONCURRENCY_FAILURE = "error.concurrencyFailure"; 6 | public static final String ERR_ACCESS_DENIED = "error.accessDenied"; 7 | public static final String ERR_VALIDATION = "error.validation"; 8 | public static final String ERR_METHOD_NOT_SUPPORTED = "error.methodNotSupported"; 9 | 10 | private ErrorConstants() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/web/rest/errors/ErrorDTO.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.web.rest.errors; 2 | 3 | import java.io.Serializable; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | /** 8 | * DTO for transfering error message with a list of field errors. 9 | */ 10 | public class ErrorDTO implements Serializable { 11 | private static final long serialVersionUID = 1L; 12 | 13 | private final String message; 14 | private final String description; 15 | 16 | private List fieldErrors; 17 | 18 | ErrorDTO(String message) { 19 | this(message, null); 20 | } 21 | 22 | ErrorDTO(String message, String description) { 23 | this.message = message; 24 | this.description = description; 25 | } 26 | 27 | ErrorDTO(String message, String description, List fieldErrors) { 28 | this.message = message; 29 | this.description = description; 30 | this.fieldErrors = fieldErrors; 31 | } 32 | 33 | public void add(String objectName, String field, String message) { 34 | if (fieldErrors == null) { 35 | fieldErrors = new ArrayList<>(); 36 | } 37 | fieldErrors.add(new FieldErrorDTO(objectName, field, message)); 38 | } 39 | 40 | public String getMessage() { 41 | return message; 42 | } 43 | 44 | public String getDescription() { 45 | return description; 46 | } 47 | 48 | public List getFieldErrors() { 49 | return fieldErrors; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/web/rest/errors/ExceptionTranslator.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.web.rest.errors; 2 | 3 | import org.springframework.dao.ConcurrencyFailureException; 4 | import org.springframework.http.HttpStatus; 5 | import org.springframework.validation.BindingResult; 6 | import org.springframework.validation.FieldError; 7 | import org.springframework.web.HttpRequestMethodNotSupportedException; 8 | import org.springframework.web.bind.MethodArgumentNotValidException; 9 | import org.springframework.web.bind.annotation.ControllerAdvice; 10 | import org.springframework.web.bind.annotation.ExceptionHandler; 11 | import org.springframework.web.bind.annotation.ResponseBody; 12 | import org.springframework.web.bind.annotation.ResponseStatus; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * Controller advice to translate the server side exceptions to client-friendly json structures. 18 | */ 19 | @ControllerAdvice 20 | public class ExceptionTranslator { 21 | 22 | @ExceptionHandler(ConcurrencyFailureException.class) 23 | @ResponseStatus(HttpStatus.CONFLICT) 24 | @ResponseBody 25 | public ErrorDTO processConcurencyError(ConcurrencyFailureException ex) { 26 | return new ErrorDTO(ErrorConstants.ERR_CONCURRENCY_FAILURE); 27 | } 28 | 29 | @ExceptionHandler(MethodArgumentNotValidException.class) 30 | @ResponseStatus(HttpStatus.BAD_REQUEST) 31 | @ResponseBody 32 | public ErrorDTO processValidationError(MethodArgumentNotValidException ex) { 33 | BindingResult result = ex.getBindingResult(); 34 | List fieldErrors = result.getFieldErrors(); 35 | 36 | return processFieldErrors(fieldErrors); 37 | } 38 | 39 | @ExceptionHandler(CustomParameterizedException.class) 40 | @ResponseStatus(HttpStatus.BAD_REQUEST) 41 | @ResponseBody 42 | public ParameterizedErrorDTO processParameterizedValidationError(CustomParameterizedException ex) { 43 | return ex.getErrorDTO(); 44 | } 45 | 46 | private ErrorDTO processFieldErrors(List fieldErrors) { 47 | ErrorDTO dto = new ErrorDTO(ErrorConstants.ERR_VALIDATION); 48 | 49 | for (FieldError fieldError : fieldErrors) { 50 | dto.add(fieldError.getObjectName(), fieldError.getField(), fieldError.getCode()); 51 | } 52 | 53 | return dto; 54 | } 55 | 56 | @ExceptionHandler(HttpRequestMethodNotSupportedException.class) 57 | @ResponseBody 58 | @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) 59 | public ErrorDTO processMethodNotSupportedException(HttpRequestMethodNotSupportedException exception) { 60 | return new ErrorDTO(ErrorConstants.ERR_METHOD_NOT_SUPPORTED, exception.getMessage()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/web/rest/errors/FieldErrorDTO.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.web.rest.errors; 2 | 3 | import java.io.Serializable; 4 | 5 | public class FieldErrorDTO implements Serializable { 6 | 7 | private static final long serialVersionUID = 1L; 8 | 9 | private final String objectName; 10 | 11 | private final String field; 12 | 13 | private final String message; 14 | 15 | FieldErrorDTO(String dto, String field, String message) { 16 | this.objectName = dto; 17 | this.field = field; 18 | this.message = message; 19 | } 20 | 21 | public String getObjectName() { 22 | return objectName; 23 | } 24 | 25 | public String getField() { 26 | return field; 27 | } 28 | 29 | public String getMessage() { 30 | return message; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/web/rest/errors/ParameterizedErrorDTO.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.web.rest.errors; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * DTO for sending a parameterized error message. 7 | */ 8 | public class ParameterizedErrorDTO implements Serializable { 9 | 10 | private static final long serialVersionUID = 1L; 11 | private final String message; 12 | private final String[] params; 13 | 14 | public ParameterizedErrorDTO(String message, String... params) { 15 | this.message = message; 16 | this.params = params; 17 | } 18 | 19 | public String getMessage() { 20 | return message; 21 | } 22 | 23 | public String[] getParams() { 24 | return params; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/web/rest/errors/RestErrorHandler.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.web.rest.errors; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.web.bind.annotation.ControllerAdvice; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | import org.springframework.web.bind.annotation.ResponseStatus; 9 | 10 | /** 11 | * Created by neerajsi on 18/09/15. 12 | */ 13 | 14 | @ControllerAdvice 15 | public class RestErrorHandler { 16 | 17 | private static final Logger LOGGER = LoggerFactory.getLogger(RestErrorHandler.class); 18 | 19 | @ExceptionHandler(CityNotFoundException.class) 20 | @ResponseStatus(HttpStatus.NOT_FOUND) 21 | public void handleTodoNotFoundException(CityNotFoundException ex) { 22 | LOGGER.debug("handling 404 error on a todo entry"); 23 | } 24 | } 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/web/rest/util/HeaderUtil.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.web.rest.util; 2 | 3 | import org.springframework.http.HttpHeaders; 4 | 5 | /** 6 | * Utility class for http header creation. 7 | */ 8 | public class HeaderUtil { 9 | 10 | public static HttpHeaders createAlert(String message, String param) { 11 | HttpHeaders headers = new HttpHeaders(); 12 | headers.add("X-samplegradleApp-alert", message); 13 | headers.add("X-samplegradleApp-params", param); 14 | return headers; 15 | } 16 | 17 | public static HttpHeaders createEntityCreationAlert(String entityName, String param) { 18 | return createAlert("samplegradleApp." + entityName + ".created", param); 19 | } 20 | 21 | public static HttpHeaders createEntityUpdateAlert(String entityName, String param) { 22 | return createAlert("samplegradleApp." + entityName + ".updated", param); 23 | } 24 | 25 | public static HttpHeaders createEntityDeletionAlert(String entityName, String param) { 26 | return createAlert("samplegradleApp." + entityName + ".deleted", param); 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /src/main/java/com/springboot/demo/web/rest/util/PaginationUtil.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.web.rest.util; 2 | 3 | import org.springframework.data.domain.Page; 4 | import org.springframework.data.domain.PageRequest; 5 | import org.springframework.data.domain.Pageable; 6 | import org.springframework.http.HttpHeaders; 7 | 8 | import java.net.URI; 9 | import java.net.URISyntaxException; 10 | 11 | /** 12 | * Utility class for handling pagination. 13 | *

14 | *

15 | * Pagination uses the same principles as the Github API, 16 | * and follow RFC 5988 (Link header). 17 | *

18 | */ 19 | public class PaginationUtil { 20 | 21 | public static final int DEFAULT_OFFSET = 1; 22 | 23 | public static final int MIN_OFFSET = 1; 24 | 25 | public static final int DEFAULT_LIMIT = 20; 26 | 27 | public static final int MAX_LIMIT = 100; 28 | 29 | public static Pageable generatePageRequest(Integer offset, Integer limit) { 30 | if (offset == null || offset < MIN_OFFSET) { 31 | offset = DEFAULT_OFFSET; 32 | } 33 | if (limit == null || limit > MAX_LIMIT) { 34 | limit = DEFAULT_LIMIT; 35 | } 36 | return new PageRequest(offset - 1, limit); 37 | } 38 | 39 | public static HttpHeaders generatePaginationHttpHeaders(Page page, String baseUrl, Integer offset, Integer limit) 40 | throws URISyntaxException { 41 | 42 | if (offset == null || offset < MIN_OFFSET) { 43 | offset = DEFAULT_OFFSET; 44 | } 45 | if (limit == null || limit > MAX_LIMIT) { 46 | limit = DEFAULT_LIMIT; 47 | } 48 | HttpHeaders headers = new HttpHeaders(); 49 | headers.add("X-Total-Count", "" + page.getTotalElements()); 50 | String link = ""; 51 | if (offset < page.getTotalPages()) { 52 | link = "<" + (new URI(baseUrl + "?page=" + (offset + 1) + "&per_page=" + limit)).toString() 53 | + ">; rel=\"next\","; 54 | } 55 | if (offset > 1) { 56 | link += "<" + (new URI(baseUrl + "?page=" + (offset - 1) + "&per_page=" + limit)).toString() 57 | + ">; rel=\"prev\","; 58 | } 59 | link += "<" + (new URI(baseUrl + "?page=" + page.getTotalPages() + "&per_page=" + limit)).toString() 60 | + ">; rel=\"last\"," + 61 | "<" + (new URI(baseUrl + "?page=" + 1 + "&per_page=" + limit)).toString() 62 | + ">; rel=\"first\""; 63 | headers.add(HttpHeaders.LINK, link); 64 | return headers; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/resources/config/application-dev.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: dev 4 | datasource: 5 | dataSourceClassName: com.mysql.jdbc.jdbc2.optional.MysqlDataSource 6 | url: jdbc:mysql://localhost:3306/springbootbase_prod?useUnicode=true&characterEncoding=utf8 7 | databaseName: 8 | serverName: 9 | username: root 10 | password: 11 | cachePrepStmts: true 12 | prepStmtCacheSize: 250 13 | prepStmtCacheSqlLimit: 2048 14 | useServerPrepStmts: true 15 | 16 | jpa: 17 | database-platform: org.hibernate.dialect.MySQL5InnoDBDialect 18 | database: MYSQL 19 | openInView: false 20 | show_sql: true 21 | generate-ddl: false 22 | hibernate: 23 | ddl-auto: update 24 | naming-strategy: org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy 25 | properties: 26 | hibernate.cache.use_second_level_cache: false 27 | hibernate.cache.use_query_cache: false 28 | hibernate.generate_statistics: true 29 | org.hibernate.envers.audit_table_suffix: _history 30 | 31 | http: 32 | cache: 33 | timeToLiveInDays: 31 34 | 35 | cache: 36 | timeToLiveSeconds: 3600 37 | ehcache: 38 | maxBytesLocalHeap: 256M 39 | -------------------------------------------------------------------------------- /src/main/resources/config/application-prod.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: prod 4 | datasource: 5 | dataSourceClassName: com.mysql.jdbc.jdbc2.optional.MysqlDataSource 6 | url: jdbc:mysql://localhost:3306/springbootbase_prod?useUnicode=true&characterEncoding=utf8 7 | databaseName: 8 | serverName: 9 | username: root 10 | password: 11 | cachePrepStmts: true 12 | prepStmtCacheSize: 250 13 | prepStmtCacheSqlLimit: 2048 14 | useServerPrepStmts: true 15 | 16 | jpa: 17 | database-platform: org.hibernate.dialect.MySQL5InnoDBDialect 18 | database: MYSQL 19 | openInView: false 20 | show_sql: true 21 | generate-ddl: false 22 | hibernate: 23 | ddl-auto: update 24 | naming-strategy: org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy 25 | properties: 26 | hibernate.cache.use_second_level_cache: false 27 | hibernate.cache.use_query_cache: false 28 | hibernate.generate_statistics: true 29 | org.hibernate.envers.audit_table_suffix: _history 30 | 31 | http: 32 | cache: 33 | timeToLiveInDays: 31 34 | 35 | cache: 36 | timeToLiveSeconds: 3600 37 | ehcache: 38 | maxBytesLocalHeap: 256M 39 | -------------------------------------------------------------------------------- /src/main/resources/config/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | 4 | async: 5 | corePoolSize: 2 6 | maxPoolSize: 50 7 | queueCapacity: 10000 8 | 9 | swagger: 10 | title: sampleGradle API 11 | description: sampleGradle applications and beyond! 12 | version: 0.0.1 13 | termsOfServiceUrl: http://jhipster.github.io/ 14 | contact: 15 | license: Apache 2.0 16 | licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.html 17 | -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | utf-8 10 | [%p] %c - %m%n 11 | 12 | 13 | 14 | 15 | 16 | ${DEV_HOME}/access.log 17 | 18 | utf-8 19 | %d %-5level [%thread] %logger{0}: %msg%n 20 | 21 | 22 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | true 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /src/test/java/com/springboot/demo/AbstractControllerTest.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo; 2 | 3 | import com.fasterxml.jackson.core.JsonParseException; 4 | import com.fasterxml.jackson.core.JsonProcessingException; 5 | import com.fasterxml.jackson.databind.JsonMappingException; 6 | import com.fasterxml.jackson.databind.ObjectMapper; 7 | import com.springboot.demo.web.rest.BaseController; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.test.web.servlet.MockMvc; 10 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 11 | import org.springframework.web.context.WebApplicationContext; 12 | 13 | import java.io.IOException; 14 | 15 | /** 16 | * This class extends the functionality of AbstractTest. AbstractControllerTest 17 | * is the parent of all web controller unit test classes. The class ensures that 18 | * a type of WebApplicationContext is built and prepares a MockMvc instance for 19 | * use in test methods. 20 | * 21 | * @author Himanshu Virmani 22 | */ 23 | 24 | public abstract class AbstractControllerTest extends AbstractTest { 25 | 26 | protected MockMvc mvc; 27 | 28 | @Autowired 29 | protected WebApplicationContext webApplicationContext; 30 | 31 | /** 32 | * Prepares the test class for execution of web tests. Builds a MockMvc 33 | * instance. Call this method from the concrete JUnit test class in the 34 | * @Before setup method. 35 | */ 36 | protected void setUp() { 37 | mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); 38 | } 39 | 40 | /** 41 | * Prepares the test class for execution of web tests. Builds a MockMvc 42 | * instance using standalone configuration facilitating the injection of 43 | * Mockito resources into the controller class. 44 | * 45 | * @param controller A controller object to be tested. 46 | */ 47 | protected void setUp(BaseController controller) { 48 | mvc = MockMvcBuilders.standaloneSetup(controller).build(); 49 | } 50 | 51 | /** 52 | * Maps an Object into a JSON String. Uses a Jackson ObjectMapper. 53 | * 54 | * @param obj The Object to map. 55 | * @return A String of JSON. 56 | * @throws JsonProcessingException Thrown if an error occurs while mapping. 57 | */ 58 | protected String mapToJson(Object obj) throws JsonProcessingException { 59 | ObjectMapper mapper = new ObjectMapper(); 60 | return mapper.writeValueAsString(obj); 61 | } 62 | 63 | /** 64 | * Maps a String of JSON into an instance of a Class of type T. Uses a 65 | * Jackson ObjectMapper. 66 | * 67 | * @param json A String of JSON. 68 | * @param clazz A Class of type T. The mapper will attempt to convert the 69 | * JSON into an Object of this Class type. 70 | * @return An Object of type T. 71 | * @throws JsonParseException Thrown if an error occurs while mapping. 72 | * @throws JsonMappingException Thrown if an error occurs while mapping. 73 | * @throws IOException Thrown if an error occurs while mapping. 74 | */ 75 | protected T mapFromJson(String json, Class clazz) 76 | throws JsonParseException, JsonMappingException, IOException { 77 | ObjectMapper mapper = new ObjectMapper(); 78 | return mapper.readValue(json, clazz); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/test/java/com/springboot/demo/AbstractTest.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo; 2 | 3 | import org.junit.runner.RunWith; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.boot.test.SpringApplicationConfiguration; 7 | import org.springframework.test.context.ActiveProfiles; 8 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 9 | import org.springframework.test.context.web.WebAppConfiguration; 10 | 11 | /** 12 | * The AbstractTest class is the parent of all JUnit test classes. This class 13 | * configures the test ApplicationContext and test runner environment. 14 | *

15 | * Web application context here because of SpringFox Swagger. Ideally it should 16 | * be required only for controller tests. 17 | * 18 | * @author Himanshu Virmani 19 | */ 20 | @RunWith(SpringJUnit4ClassRunner.class) 21 | @SpringApplicationConfiguration( 22 | classes = Application.class) 23 | @ActiveProfiles("test") 24 | //@WebAppConfiguration needed due to swagger failures while running test. https://github.com/springfox/springfox/issues/654 25 | @WebAppConfiguration 26 | public abstract class AbstractTest { 27 | 28 | protected Logger logger = LoggerFactory.getLogger(this.getClass()); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/springboot/demo/repository/CityRepositoryTests.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.repository; 2 | 3 | import com.springboot.demo.AbstractTest; 4 | import com.springboot.demo.domain.City; 5 | import org.junit.Test; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.data.domain.Page; 8 | import org.springframework.data.domain.PageRequest; 9 | import org.springframework.test.context.jdbc.Sql; 10 | import org.springframework.test.context.jdbc.SqlGroup; 11 | 12 | import static org.hamcrest.Matchers.*; 13 | import static org.junit.Assert.assertThat; 14 | 15 | /** 16 | * Created by neerajsi on 18/09/15. 17 | */ 18 | @SqlGroup({ 19 | @Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:beforeTestRun.sql"), 20 | @Sql(executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, scripts = "classpath:afterTestRun.sql") 21 | }) 22 | //@DirtiesContext(classMode= DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) //not needed as of now.. 23 | public class CityRepositoryTests extends AbstractTest { 24 | 25 | @Autowired 26 | private CityRepository cityRepository; 27 | 28 | @Test 29 | public void findsFirstPageOfCities() { 30 | 31 | Page cities = this.cityRepository.findAll(new PageRequest(0, 10)); 32 | assertThat(cities.getTotalElements(), is(greaterThan(20L))); 33 | } 34 | 35 | @Test 36 | public void findByNameAndCountry() { 37 | City city = this.cityRepository.findByNameAndCountryAllIgnoringCase("Melbourne", 38 | "Australia"); 39 | assertThat(city, notNullValue()); 40 | assertThat(city.getName(), is(equalTo("Melbourne"))); 41 | } 42 | 43 | @Test 44 | public void findContaining() { 45 | Page cities = this.cityRepository 46 | .findByNameContainingAndCountryContainingAllIgnoringCase("", "UK", 47 | new PageRequest(0, 10)); 48 | assertThat(cities.getTotalElements(), is(equalTo(3L))); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/com/springboot/demo/service/CityServiceTest.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.service; 2 | 3 | import com.springboot.demo.AbstractTest; 4 | import com.springboot.demo.domain.City; 5 | import com.springboot.demo.repository.CityRepository; 6 | import com.springboot.demo.repository.HotelRepository; 7 | import com.springboot.demo.service.criteria.CitySearchCriteria; 8 | import com.springboot.demo.service.impl.CityServiceImpl; 9 | import org.junit.Assert; 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | import org.mockito.Mock; 13 | import org.mockito.MockitoAnnotations; 14 | import org.springframework.data.domain.Page; 15 | import org.springframework.data.domain.PageImpl; 16 | import org.springframework.data.domain.PageRequest; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | import static org.mockito.Mockito.when; 22 | 23 | /** 24 | * Created by himanshu.virmani on 20/09/15. 25 | */ 26 | public class CityServiceTest extends AbstractTest { 27 | 28 | private CityService cityService; 29 | 30 | @Mock 31 | private CityRepository cityRepository; 32 | 33 | @Mock 34 | private HotelRepository hotelRepository; 35 | 36 | @Before 37 | public void setUp() { 38 | MockitoAnnotations.initMocks(this); 39 | cityService = new CityServiceImpl(cityRepository, hotelRepository); 40 | } 41 | 42 | @Test 43 | public void testSearchCities() { 44 | PageRequest pageRequest = new PageRequest(0, 4); 45 | when(cityRepository.findByNameContainingAndCountryContainingAllIgnoringCase 46 | ("Test", "", pageRequest)) //we can also use Mockito.any etc if response is independent. 47 | .thenReturn(getEntityListStubData()); 48 | CitySearchCriteria criteria = new CitySearchCriteria("Test"); 49 | 50 | Page cities = cityService.findCities(criteria, pageRequest); 51 | logger.info("testSearchCities " + cities.getContent()); 52 | Assert.assertNotNull("failure - expected not null", cities.getContent()); 53 | Assert.assertEquals("failure - expected 1", 1L, 54 | cities.getTotalElements()); 55 | 56 | } 57 | 58 | private Page getEntityListStubData() { 59 | List list = new ArrayList<>(); 60 | list.add(getEntityStubData()); 61 | PageImpl page = new PageImpl<>(list); 62 | return page; 63 | } 64 | 65 | private City getEntityStubData() { 66 | City entity = new City(); 67 | entity.setId(1L); 68 | entity.setName("Miami"); 69 | entity.setState("Florida"); 70 | return entity; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/test/java/com/springboot/demo/util/TestUtil.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.util; 2 | 3 | 4 | import org.springframework.http.MediaType; 5 | 6 | import java.nio.charset.Charset; 7 | 8 | 9 | /** 10 | * Created by neerajsi on 18/09/15. 11 | */ 12 | public class TestUtil { 13 | 14 | public static final MediaType APPLICATION_JSON_UTF8 = new MediaType(MediaType.APPLICATION_JSON.getType(), 15 | MediaType.APPLICATION_JSON.getSubtype(), 16 | Charset.forName("utf8") 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/springboot/demo/web/rest/CityControllerIntegrationTests.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.web.rest; 2 | 3 | import com.springboot.demo.AbstractControllerTest; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.springframework.http.MediaType; 7 | import org.springframework.test.context.jdbc.Sql; 8 | import org.springframework.test.context.jdbc.SqlGroup; 9 | import org.springframework.test.web.servlet.ResultActions; 10 | import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; 11 | import org.springframework.transaction.annotation.Transactional; 12 | 13 | import static org.hamcrest.Matchers.hasSize; 14 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; 15 | 16 | /** 17 | * Created by neerajsi on 16/09/15. 18 | */ 19 | 20 | 21 | /** 22 | * TODO 23 | * Explore on test utils like EnvironmentTestUtils, ConfigFileApplicationContextInitializer, OutputCapture 24 | */ 25 | @SqlGroup({ 26 | @Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:beforeTestRun.sql"), 27 | @Sql(executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, scripts = "classpath:afterTestRun.sql") 28 | }) 29 | @Transactional 30 | public class CityControllerIntegrationTests extends AbstractControllerTest { 31 | 32 | @Before 33 | public void setUp() { 34 | super.setUp(); 35 | } 36 | 37 | 38 | @Test 39 | public void shouldSearchCity() throws Exception { 40 | 41 | ResultActions s = mvc.perform(MockMvcRequestBuilders.get("/city/search/T") 42 | .accept(MediaType.APPLICATION_JSON)) 43 | .andExpect(status().isOk()) 44 | .andExpect(jsonPath("$.content", hasSize(4))); 45 | 46 | logger.info("shouldSearchCity " + s.andReturn().getResponse().getContentAsString()); 47 | } 48 | 49 | @Test 50 | public void searchCity_CityNotFoundException_ShouldReturnHttpStatusCode404() throws Exception { 51 | 52 | mvc.perform(MockMvcRequestBuilders.get("/city/search/TTT").accept(MediaType.APPLICATION_JSON)) 53 | .andExpect(status().isNotFound()); 54 | logger.info("searchCity_CityNotFoundException_ShouldReturnHttpStatusCode404 " + content()); 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /src/test/java/com/springboot/demo/web/rest/CityControllerTest.java: -------------------------------------------------------------------------------- 1 | package com.springboot.demo.web.rest; 2 | 3 | import com.springboot.demo.AbstractControllerTest; 4 | import com.springboot.demo.domain.City; 5 | import com.springboot.demo.service.CityService; 6 | import com.springboot.demo.service.criteria.CitySearchCriteria; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | import org.mockito.InjectMocks; 10 | import org.mockito.Mock; 11 | import org.mockito.MockitoAnnotations; 12 | import org.springframework.data.domain.Page; 13 | import org.springframework.data.domain.PageImpl; 14 | import org.springframework.data.domain.PageRequest; 15 | import org.springframework.http.MediaType; 16 | import org.springframework.test.web.servlet.ResultActions; 17 | import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; 18 | import org.springframework.transaction.annotation.Transactional; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | import static org.hamcrest.Matchers.hasSize; 24 | import static org.mockito.Mockito.when; 25 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; 26 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 27 | 28 | /** 29 | * Created by himanshu.virmani on 19/09/15. 30 | */ 31 | @Transactional 32 | public class CityControllerTest extends AbstractControllerTest { 33 | 34 | @Mock 35 | private CityService cityService; 36 | 37 | @InjectMocks 38 | private CityController cityController; 39 | 40 | @Before 41 | public void setUp() { 42 | // Initialize Mockito annotated components 43 | MockitoAnnotations.initMocks(this); 44 | // Prepare the Spring MVC Mock components for standalone testing 45 | setUp(cityController); 46 | } 47 | 48 | @Test 49 | public void shouldSearchCity() throws Exception { 50 | 51 | CitySearchCriteria criteria = new CitySearchCriteria("T"); 52 | PageRequest pageRequest = new PageRequest(0, 4); 53 | // Create some test data 54 | Page list = getEntityListStubData(); 55 | 56 | when(cityService.findCities(criteria, pageRequest)).thenReturn(list); 57 | 58 | ResultActions s = mvc.perform(MockMvcRequestBuilders.get("/city/search/T") 59 | .accept(MediaType.APPLICATION_JSON)) 60 | .andExpect(status().isOk()) 61 | .andExpect(jsonPath("$.content", hasSize(1))); 62 | 63 | logger.info("shouldSearchCity " + s.andReturn().getResponse().getContentAsString()); 64 | } 65 | 66 | private Page getEntityListStubData() { 67 | List list = new ArrayList<>(); 68 | list.add(getEntityStubData()); 69 | PageImpl page = new PageImpl<>(list); 70 | return page; 71 | } 72 | 73 | private City getEntityStubData() { 74 | City entity = new City(); 75 | entity.setId(1L); 76 | entity.setName("Miami"); 77 | entity.setState("Florida"); 78 | return entity; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/test/resources/afterTestRun.sql: -------------------------------------------------------------------------------- 1 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT = @@CHARACTER_SET_CLIENT */; 2 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS = @@CHARACTER_SET_RESULTS */; 3 | /*!40101 SET @OLD_COLLATION_CONNECTION = @@COLLATION_CONNECTION */; 4 | /*!40101 SET NAMES utf8 */; 5 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS = @@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS = 0 */; 6 | /*!40101 SET @OLD_SQL_MODE = @@SQL_MODE, SQL_MODE = 'NO_AUTO_VALUE_ON_ZERO' */; 7 | /*!40111 SET @OLD_SQL_NOTES = @@SQL_NOTES, SQL_NOTES = 0 */; 8 | 9 | 10 | DROP TABLE IF EXISTS `city`; 11 | 12 | 13 | DROP TABLE IF EXISTS `hotel`; 14 | 15 | 16 | DROP TABLE IF EXISTS `review`; 17 | 18 | 19 | DROP TABLE IF EXISTS `review_history`; 20 | 21 | 22 | DROP TABLE IF EXISTS `revinfo`; 23 | 24 | 25 | /*!40111 SET SQL_NOTES = @OLD_SQL_NOTES */; 26 | /*!40101 SET SQL_MODE = @OLD_SQL_MODE */; 27 | /*!40014 SET FOREIGN_KEY_CHECKS = @OLD_FOREIGN_KEY_CHECKS */; 28 | /*!40101 SET CHARACTER_SET_CLIENT = @OLD_CHARACTER_SET_CLIENT */; 29 | /*!40101 SET CHARACTER_SET_RESULTS = @OLD_CHARACTER_SET_RESULTS */; 30 | /*!40101 SET COLLATION_CONNECTION = @OLD_COLLATION_CONNECTION */; 31 | -------------------------------------------------------------------------------- /src/test/resources/beforeTestRun.sql: -------------------------------------------------------------------------------- 1 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT = @@CHARACTER_SET_CLIENT */; 2 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS = @@CHARACTER_SET_RESULTS */; 3 | /*!40101 SET @OLD_COLLATION_CONNECTION = @@COLLATION_CONNECTION */; 4 | /*!40101 SET NAMES utf8 */; 5 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS = @@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS = 0 */; 6 | /*!40101 SET @OLD_SQL_MODE = @@SQL_MODE, SQL_MODE = 'NO_AUTO_VALUE_ON_ZERO' */; 7 | /*!40111 SET @OLD_SQL_NOTES = @@SQL_NOTES, SQL_NOTES = 0 */; 8 | 9 | 10 | DROP TABLE IF EXISTS `city`; 11 | 12 | DROP TABLE IF EXISTS `hotel`; 13 | 14 | DROP TABLE IF EXISTS `review`; 15 | 16 | DROP TABLE IF EXISTS `review_history`; 17 | 18 | DROP TABLE IF EXISTS `revinfo`; 19 | 20 | CREATE TABLE `revinfo` ( 21 | `rev` INT(11) NOT NULL AUTO_INCREMENT, 22 | `revtstmp` BIGINT(20) DEFAULT NULL, 23 | PRIMARY KEY (`rev`) 24 | ); 25 | 26 | 27 | CREATE TABLE `review_history` ( 28 | `id` BIGINT(20) NOT NULL, 29 | `rev` INT(11) NOT NULL, 30 | `revtype` TINYINT(4) DEFAULT NULL, 31 | `details` VARCHAR(5000) DEFAULT NULL, 32 | `title` VARCHAR(255) DEFAULT NULL, 33 | `trip_type` INT(11) DEFAULT NULL, 34 | PRIMARY KEY (`id`, `rev`), 35 | FOREIGN KEY (`rev`) REFERENCES `revinfo` (`rev`) 36 | ); 37 | 38 | 39 | CREATE TABLE `city` ( 40 | `id` BIGINT(20) NOT NULL AUTO_INCREMENT, 41 | `country` VARCHAR(255) NOT NULL, 42 | `map` VARCHAR(255) NOT NULL, 43 | `name` VARCHAR(255) NOT NULL, 44 | `state` VARCHAR(255) NOT NULL, 45 | PRIMARY KEY (`id`) 46 | ); 47 | 48 | CREATE TABLE `hotel` ( 49 | `id` BIGINT(20) NOT NULL AUTO_INCREMENT, 50 | `address` VARCHAR(255) NOT NULL, 51 | `name` VARCHAR(255) NOT NULL, 52 | `zip` VARCHAR(255) NOT NULL, 53 | `city_id` BIGINT(20) NOT NULL, 54 | `status` VARCHAR(255) NOT NULL, 55 | PRIMARY KEY (`id`), 56 | FOREIGN KEY (`city_id`) REFERENCES `city` (`id`) 57 | ); 58 | 59 | 60 | CREATE TABLE `review` ( 61 | `id` BIGINT(20) NOT NULL AUTO_INCREMENT, 62 | `check_in_date` DATE NOT NULL, 63 | `details` VARCHAR(5000) NOT NULL, 64 | `idx` INT(11) NOT NULL, 65 | `rating` INT(11) NOT NULL, 66 | `title` VARCHAR(255) NOT NULL, 67 | `trip_type` INT(11) NOT NULL, 68 | `hotel_id` BIGINT(20) NOT NULL, 69 | `created_at` DATETIME DEFAULT NULL, 70 | `updated_at` DATETIME DEFAULT NULL, 71 | `version` BIGINT(20) DEFAULT NULL, 72 | PRIMARY KEY (`id`), 73 | FOREIGN KEY (`hotel_id`) REFERENCES `hotel` (`id`) 74 | ); 75 | 76 | 77 | INSERT INTO `city` (`id`, `country`, `map`, `name`, `state`) 78 | VALUES 79 | (1, 'Australia', '-27.470933, 153.023502', 'Brisbane', 'Queensland'), 80 | (2, 'Australia', '-37.813187, 144.96298', 'Melbourne', 'Victoria'), 81 | (3, 'Australia', '-33.868901, 151.207091', 'Sydney', 'New South Wales'), 82 | (4, 'Canada', '45.508889, -73.554167', 'Montreal', 'Quebec'), 83 | (5, 'Israel', '32.066157, 34.777821', 'Tel Aviv', ''), 84 | (6, 'Japan', '35.689488, 139.691706', 'Tokyo', ''), 85 | (7, 'Spain', '41.387917, 2.169919', 'Barcelona', 'Catalunya'), 86 | (8, 'Switzerland', '46.992979, 6.931933', 'Neuchatel', ''), 87 | (9, 'UK', '51.381428, -2.357454', 'Bath', 'Somerset'), 88 | (10, 'UK', '51.500152, -0.126236', 'London', ''), 89 | (11, 'UK', '50.902571, -1.397238', 'Southampton', 'Hampshire'), 90 | (12, 'USA', '33.748995, -84.387982', 'Atlanta', 'GA'), 91 | (13, 'USA', '41.878114, -87.629798', 'Chicago', 'IL'), 92 | (14, 'USA', '44.811349, -91.498494', 'Eau Claire', 'WI'), 93 | (15, 'USA', '26.011201, -80.14949', 'Hollywood', 'FL'), 94 | (16, 'USA', '25.788969, -80.226439', 'Miami', 'FL'), 95 | (17, 'USA', '28.083627, -80.608109', 'Melbourne', 'FL'), 96 | (18, 'USA', '40.714353, -74.005973', 'New York', 'NY'), 97 | (19, 'USA', '28.034462, -80.588665', 'Palm Bay', 'FL'), 98 | (20, 'USA', '37.77493, -122.419415', 'San Francisco', 'CA'), 99 | (21, 'USA', '38.895112, -77.036366', 'Washington', 'DC'); 100 | 101 | 102 | INSERT INTO `hotel` (`id`, `address`, `name`, `zip`, `city_id`, `status`) 103 | VALUES 104 | (1, 'William & George Streets', 'Conrad Treasury Place', '4001', 1, 'OPENED'), 105 | (2, '1 Southgate Ave, Southbank', 'The Langham', '3006', 2, 'OPENED'), 106 | (3, '68 Market Street', 'Swissotel', '2000', 3, 'OPENED'), 107 | (4, '1228 Sherbrooke St', 'Ritz Carlton', 'H3G1H6', 4, 'OPENED'), 108 | (5, 'Independence Park', 'Hilton Tel Aviv', '63405', 5, 'OPENED'), 109 | (6, 'Takeshiba Pier', 'InterContinental Tokyo Bay', '105', 6, 'OPENED'), 110 | (7, 'Passeig del Taulat 262-264', 'Hilton Diagonal Mar', '08019', 7, 'OPENED'), 111 | (8, ' Esplanade Leopold-Robert 2', 'Hotel Beaulac', '2000', 8, 'OPENED'), 112 | (9, 'Weston Road', 'The Bath Priory Hotel', 'BA1 2XT', 9, 'OPENED'), 113 | (10, 'Rossiter Road, Widcombe Basin', 'Bath Travelodge', 'BA2 4JP', 9, 'OPENED'), 114 | (11, 'Albany Street', 'Melia White House', 'NW1 3UP', 10, 'OPENED'), 115 | (12, 'The Cottage, Southampton Business Park', 'Chilworth Manor', 'SO16 7JF', 11, 'OPENED'), 116 | (13, 'Tower Place, Buckhead', 'Marriott Courtyard', '30305', 12, 'OPENED'), 117 | (14, 'Peachtree Rd, Buckhead', 'Ritz Carlton', '30326', 12, 'OPENED'), 118 | (15, 'Tower Place, Buckhead', 'Doubletree', '30305', 12, 'OPENED'), 119 | (16, '171 West Randolph Street', 'Hotel Allegro', '60601', 13, 'OPENED'), 120 | (17, '2106 N Clairemont Ave', 'Sea Horse Inn', '54703', 14, 'OPENED'), 121 | (18, '1151 W Macarthur Ave', 'Super 8 Eau Claire Campus Area', '54701', 14, 'OPENED'), 122 | (19, '3555 S. Ocean Drive', 'Westin Diplomat', '33019', 15, 'OPENED'), 123 | (20, '1395 Brickell Ave', 'Conrad Miami', '33131', 16, 'OPENED'), 124 | (21, '3101 North Hwy', 'Radisson Suite Hotel Oceanfront', '32903', 17, 'OPENED'), 125 | (22, 'Union Square, Manhattan', 'W Union Hotel', '10011', 18, 'OPENED'), 126 | (23, 'Lexington Ave, Manhattan', 'W Lexington Hotel', '10011', 18, 'OPENED'), 127 | (24, '70 Park Avenue', '70 Park Avenue Hotel', '10011', 18, 'OPENED'), 128 | (25, '890 Palm Bay Rd NE', 'Jameson Inn', '32905', 19, 'OPENED'), 129 | (26, '55 Fourth Street', 'Marriot Downtown', '94103', 20, 'OPENED'), 130 | (27, '1315 16th Street NW', 'Hotel Rouge', '20036', 21, 'OPENED'); 131 | 132 | 133 | INSERT INTO `review` (`id`, `check_in_date`, `details`, `idx`, `rating`, `title`, `trip_type`, `hotel_id`, `created_at`, `updated_at`, `version`) 134 | VALUES 135 | (1, '2005-05-10', 'I stayed in 2005, the hotel was nice enough but nothing special.', 0, 2, 'Pretty average', 4, 2, 136 | NULL, NULL, NULL), 137 | (2, '2006-01-12', 'This hotel has a fantastic lovely big windows. The room we stayed in had lots of space. Recommended.', 1, 4, 'Bright hotel with big rooms', 2, 2, NULL, NULL, NULL), 138 | (3, '2006-05-25', 'I liked this hotel and would stay again.', 2, 3, 'Pretty good', 1, 2, NULL, NULL, NULL), 139 | (4, '2009-01-20', 'The rooms are maintained to a high standard and very clean, the bathroom was spotless!!', 3, 3, 'Nice clean rooms', 2, 2, NULL, NULL, NULL), 140 | (5, '2000-01-23', 'We stayed here after a wedding and it was fantastic. Recommend to all.', 0, 4, 'A lovely hotel', 1, 9, NULL, NULL, NULL), 141 | (6, '2000-08-04', 'A very special hotel with lovely staff.', 1, 3, 'Very special', 1, 9, NULL, NULL, NULL), 142 | (7, '2001-01-01', 'Stayed during the summer heat wave (exceptional for England!) and the room was very hot. Still recommended.', 2, 2, 'Nice but too hot', 4, 9, NULL, NULL, NULL), 143 | (8, '2002-01-20', 'Considering how central this hotel is the rooms are a very good size.', 3, 3, 'Big rooms and a great view', 1, 9, NULL, NULL, NULL), 144 | (9, '2002-11-03', 'A nice hotel but be prepared to pay over the odds for your stay.', 4, 2, 'Good but pricey', 1, 9, NULL, NULL, NULL), 145 | (10, '2003-09-18', 'Just lovely.', 5, 4, 'Fantastic place', 1, 9, NULL, NULL, NULL), 146 | (11, '2004-03-21', 'I stayed here in 2004 and found it to be very relaxing, a nice pool and good gym is cherry on the cake.', 6, 4, 'A very special place', 3, 9, NULL, NULL, NULL), 147 | (12, '2004-04-10', 'I complained after I was told I could not check out after 11pm. Ridiculous!!!', 7, 0, 'Terrible', 0, 9, NULL, NULL, NULL), 148 | (13, '2004-12-20', 'Central location makes this a perfect hotel. Be warned though, its not cheap.', 8, 4, 'A perfect location', 4, 9, NULL, NULL, NULL), 149 | (14, '2005-04-19', 'Dig deep into your pockets and enjoy this lovely City and fantastic hotel.', 9, 3, 'Expensive but worth it', 2, 9, NULL, NULL, NULL), 150 | (15, '2005-05-21', 'Top hotel in the area, would not stay anywhere else.', 10, 4, 'The best hotel in the area', 1, 9, NULL, NULL, NULL), 151 | (16, '2005-11-17', 'The garden upkeep run into thousands (perhaps explaining why the rooms are so much) but so lovely and relaxing.', 11, 4, 'Lovely hotel, fantastic grounds', 2, 9, NULL, NULL, NULL), 152 | (17, '2006-01-04', 'Top draw stuff.', 12, 3, 'Gorgeous Top Quality Hotel', 4, 9, NULL, NULL, NULL), 153 | (18, '2006-01-21', 'The food at this hotel is second to none, try the peppered steak!', 13, 4, 'Fabulous Hotel and Restaurant', 1, 9, NULL, NULL, NULL), 154 | (19, '2006-01-29', 'A lovely home away from home.', 14, 4, 'Feels like home', 4, 9, NULL, NULL, NULL), 155 | (20, '2006-03-21', 'Overpriced, Overpriced, Overpriced!!', 15, 1, 'Far too expensive', 1, 9, NULL, NULL, NULL), 156 | (21, '2006-05-10', 'The staff went out of their way to help us after we missed our last train home, organising a Taxi back to Newport even after we had checked out.', 16, 4, 'Excellent Hotel, Wonderful Staff', 1, 9, NULL, NULL, NULL), 157 | (22, '2007-09-11', 'If you want a relaxing stay, this is the place.', 17, 3, 'The perfect retreat', 2, 9, NULL, NULL, NULL), 158 | (23, '2008-06-01', 'As other reviews have noted, the staff in this hotel really are the best in Bath.', 18, 3, 'Lovely stay, fantastic staff', 3, 9, NULL, NULL, NULL), 159 | (24, '2009-05-14', 'We will stay again for sure.', 19, 4, 'Cant Wait to go back', 2, 9, NULL, NULL, NULL), 160 | (25, '2010-04-26', 'We won a trip here after entering a competition. Not sure we would pay the full price but such a wonderful place.', 20, 4, 'Amazing Hotel', 1, 9, NULL, NULL, NULL), 161 | (26, '2010-10-26', 'The pool was closed, the chief was ill, the staff were rude my wallet is bruised!', 21, 2, 'Dissapointed', 2, 9, NULL, NULL, NULL), 162 | (27, '2002-08-21', 'One of the worst hotels that I have ever stayed in.', 0, 0, 'Terrible hotel', 2, 10, NULL, NULL, NULL), 163 | (28, '2003-01-28', 'The staff refused to help me with any aspect of my stay, I will not stay here again.', 1, 0, 'Rude and unpleasant staff', 0, 10, NULL, NULL, NULL), 164 | (29, '2004-06-17', 'Dont stay here!!', 2, 1, 'Below par', 0, 10, NULL, NULL, NULL), 165 | (30, '2005-07-12', 'The room was far too small and felt unclean. Not recommended.', 3, 0, 'Small and Unpleasant', 1, 10, NULL, NULL, NULL), 166 | (31, '2006-01-07', 'This hotel has some rough edges but I challenge you to find somewhere cheaper.', 4, 1, 'Cheap if you are not fussy', 4, 10, NULL, NULL, NULL), 167 | (32, '2006-01-13', 'Just terrible!', 5, 0, 'Terrible', 2, 10, NULL, NULL, NULL), 168 | (33, '2006-03-25', 'My room smelt of damp and I found the socks of the previous occupant under my bed.', 6, 0, 'Smelly and dirty room', 0, 10, NULL, NULL, NULL), 169 | (34, '2006-04-09', 'Grim. I would try elsewhere before staying here.', 7, 0, 'Grim', 4, 10, NULL, NULL, NULL), 170 | (35, '2006-08-01', 'Building work during the day and a disco at night. Good grief!', 8, 1, 'Very Noisy', 3, 10, NULL, NULL, NULL), 171 | (36, '2009-01-03', 'This hotel is in serious need of refurbishment, the windows are rotting, the paintwork is tired and the carpets are from the 1970s.', 9, 1, 'Tired and falling down', 4, 10, NULL, NULL, NULL), 172 | (37, '2009-07-20', 'I would not put my dog up in this hotel.', 10, 0, 'Not suitable for human habitation', 0, 10, NULL, NULL, NULL), 173 | (38, '2010-05-20', 'Average place but useful if you need to commute', 11, 1, 'Conveient for the railway', 0, 10, NULL, NULL, NULL), 174 | (39, '2010-01-22', 'Some of the reviews seem a bit harsh, its not too bad for the price.', 12, 2, 'Not as bad as the reviews', 2, 10, NULL, NULL, NULL), 175 | (40, '2011-01-10', 'Looks like this hotel has had a major facelift. If you have stayed before 2011 perhaps its time to give this hotel another try. Very good value for money and pretty nice.', 13, 3, 'Reburished and nice', 1, 10, NULL, NULL, NULL), 176 | (41, '2009-01-20', 'Most other hotels is this area are a bit ropey, this one is actually pretty good.', 0, 3, 'Better than most', 0, 13, NULL, NULL, NULL), 177 | (42, '2006-01-12', 'Cheap, no fuss hotel. Good if you are travelling on business and just need a place to stay.', 0, 2, 'No fuss hotel', 3, 15, NULL, NULL, NULL), 178 | (43, '2009-01-20', 'The area felt nice and safe but the rooms are a little on the small side', 1, 2, 'Nice area but small rooms', 2, 15, NULL, NULL, NULL), 179 | (44, '2009-12-15', 'Good value for money, cant really fault it.', 0, 3, 'Cheap and Recommended', 2, 16, NULL, NULL, NULL), 180 | (45, '2006-01-11', 'The hotel has a very bad reputation. I would avoid it if I were you.', 0, 0, 'Avoid', 0, 19, NULL, NULL, NULL), 181 | (46, '2010-01-09', 'Fantastic access to all the local attractions mean you wont mind the small rooms.', 0, 3, 'Close to the local attractions', 2, 20, NULL, NULL, NULL), 182 | (47, '2010-09-10', 'Not expensive and very welcoming staff. I would stay again.', 1, 2, 'Good value and friendly', 2, 20, NULL, NULL, NULL), 183 | (48, '2005-06-15', 'I cant fault this hotel and I have stayed here many times. Always friendly staff and lovely atmosphere.', 0, 3, 'A very nice hotel', 3, 21, NULL, NULL, NULL), 184 | (49, '2006-01-20', 'To complaints at all.', 1, 2, 'Comfortable and good value', 4, 21, NULL, NULL, NULL), 185 | (50, '2007-08-21', 'Better than a lot of hotels in the area and not too pricey.', 2, 3, 'Above average', 1, 21, NULL, NULL, NULL), 186 | (51, '2002-01-19', 'The city never sleeps and neither will you if you say here. The rooms are small and the sound insulation is poor!', 0, 0, 'Too noisy, too small', 1, 22, NULL, NULL, NULL), 187 | (52, '2004-03-10', 'Far too much money for such a tiny room!', 1, 1, 'Overpriced', 4, 22, NULL, NULL, NULL), 188 | (53, '2007-04-11', 'Not brilliant but not too bad either.', 2, 2, 'So so, nothing special', 0, 22, NULL, NULL, NULL), 189 | (54, '2004-07-21', 'So close to the heart of the city. Recommended.', 0, 3, 'Excellent location', 2, 23, NULL, NULL, NULL), 190 | (55, '2006-05-20', 'I cant fault this hotel, clean, good location and nice staff.', 1, 3, 'Very nice', 1, 23, NULL, NULL, NULL), 191 | (56, '2003-11-10', 'I own this hotel and I think it is pretty darn good.', 0, 4, 'Great!!', 1, 24, NULL, NULL, NULL), 192 | (57, '2005-10-20', 'This is the BEST hotel in Palm Bay, not complaints at all.', 0, 3, 'Fantastical', 2, 25, NULL, NULL, NULL), 193 | (58, '2006-01-12', 'I rate this hotel 5 stars, the best in the area by miles.', 1, 4, 'Top marks', 1, 25, NULL, NULL, NULL), 194 | (59, '2006-07-02', 'I stayed in late 2006 with work, the room was very small and the restaurant does not stay open very late.', 0, 2, 'Could be better', 3, 26, NULL, NULL, NULL), 195 | (60, '2008-07-01', 'My room was freezing cold, I would not recommend this place.', 1, 1, 'Brrrr cold!', 4, 26, NULL, NULL, NULL), 196 | (61, '2009-01-05', 'You cant really go wrong here for the money. There may be better places to stay but not for this price.', 2, 3, 'Nice for money', 2, 26, NULL, NULL, NULL), 197 | (62, '2000-01-29', 198 | 'I will never ever stay here again!! They wanted extra cash to get fresh batteries for the TV remote', 0, 0, 199 | 'Never again', 2, 27, NULL, NULL, NULL), 200 | (63, '2006-02-20', 201 | 'This place is the pits, they charged us twice for a single night stay. I only got refunded after contacting my credit card company.', 202 | 1, 0, 'Avoid', 0, 27, NULL, NULL, NULL), 203 | (64, '2012-04-23', 'A nice hotel which I have not visited.', 1, 2, 'Himanshus 1st Review', 1, 9, 204 | '2015-09-15 12:08:30', '2015-09-15 12:08:30', 0); 205 | 206 | 207 | INSERT INTO `revinfo` (`rev`, `revtstmp`) 208 | VALUES 209 | (1, 1442299110393); 210 | 211 | INSERT INTO `review_history` (`id`, `rev`, `revtype`, `details`, `title`, `trip_type`) 212 | VALUES 213 | (64, 1, 0, 'A nice hotel which I have not visited.', 'Himanshu 1st Review', 1); 214 | 215 | /*!40111 SET SQL_NOTES = @OLD_SQL_NOTES */; 216 | /*!40101 SET SQL_MODE = @OLD_SQL_MODE */; 217 | /*!40014 SET FOREIGN_KEY_CHECKS = @OLD_FOREIGN_KEY_CHECKS */; 218 | /*!40101 SET CHARACTER_SET_CLIENT = @OLD_CHARACTER_SET_CLIENT */; 219 | /*!40101 SET CHARACTER_SET_RESULTS = @OLD_CHARACTER_SET_RESULTS */; 220 | /*!40101 SET COLLATION_CONNECTION = @OLD_COLLATION_CONNECTION */; 221 | -------------------------------------------------------------------------------- /src/test/resources/config/application-test.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: test 4 | datasource: 5 | dataSourceClassName: org.h2.jdbcx.JdbcDataSource 6 | url: jdbc:h2:mem:sampleGradle;DB_CLOSE_DELAY=-1 7 | databaseName: 8 | serverName: 9 | username: 10 | password: 11 | 12 | jpa: 13 | database-platform: com.springboot.demo.domain.util.FixedH2Dialect 14 | database: H2 15 | openInView: false 16 | show_sql: true 17 | generate-ddl: false 18 | hibernate: 19 | ddl-auto: none 20 | naming-strategy: org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy 21 | properties: 22 | hibernate.cache.use_second_level_cache: false 23 | hibernate.cache.use_query_cache: false 24 | hibernate.generate_statistics: true 25 | hibernate.hbm2ddl.auto: create 26 | 27 | http: 28 | cache: 29 | timeToLiveInDays: 31 30 | 31 | cache: 32 | timeToLiveSeconds: 3600 33 | ehcache: 34 | maxBytesLocalHeap: 256M 35 | --------------------------------------------------------------------------------