├── .circleci └── config.yml ├── .gitignore ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── guru │ │ └── springframework │ │ ├── Spring5RecipeAppApplication.java │ │ ├── bootstrap │ │ └── RecipeBootstrap.java │ │ ├── commands │ │ ├── CategoryCommand.java │ │ ├── IngredientCommand.java │ │ ├── NotesCommand.java │ │ ├── RecipeCommand.java │ │ └── UnitOfMeasureCommand.java │ │ ├── controllers │ │ ├── ControllerExceptionHandler.java │ │ ├── ImageController.java │ │ ├── IndexController.java │ │ ├── IngredientController.java │ │ └── RecipeController.java │ │ ├── converters │ │ ├── CategoryCommandToCategory.java │ │ ├── CategoryToCategoryCommand.java │ │ ├── IngredientCommandToIngredient.java │ │ ├── IngredientToIngredientCommand.java │ │ ├── NotesCommandToNotes.java │ │ ├── NotesToNotesCommand.java │ │ ├── RecipeCommandToRecipe.java │ │ ├── RecipeToRecipeCommand.java │ │ ├── UnitOfMeasureCommandToUnitOfMeasure.java │ │ └── UnitOfMeasureToUnitOfMeasureCommand.java │ │ ├── domain │ │ ├── Category.java │ │ ├── Difficulty.java │ │ ├── Ingredient.java │ │ ├── Notes.java │ │ ├── Recipe.java │ │ └── UnitOfMeasure.java │ │ ├── exceptions │ │ └── NotFoundException.java │ │ ├── repositories │ │ ├── CategoryRepository.java │ │ ├── RecipeRepository.java │ │ └── UnitOfMeasureRepository.java │ │ └── services │ │ ├── ImageService.java │ │ ├── ImageServiceImpl.java │ │ ├── IngredientService.java │ │ ├── IngredientServiceImpl.java │ │ ├── RecipeService.java │ │ ├── RecipeServiceImpl.java │ │ ├── UnitOfMeasureService.java │ │ └── UnitOfMeasureServiceImpl.java ├── resources │ ├── application.properties │ ├── data.sql │ ├── messages.properties │ ├── messages_en.properties │ ├── messages_en_GB.properties │ ├── messages_en_US.properties │ ├── static │ │ └── images │ │ │ ├── guacamole400x400.jpg │ │ │ ├── guacamole400x400WithX.jpg │ │ │ └── tacos400x400.jpg │ └── templates │ │ ├── 400error.html │ │ ├── 404error.html │ │ ├── index.html │ │ └── recipe │ │ ├── imageuploadform.html │ │ ├── ingredient │ │ ├── ingredientform.html │ │ ├── list.html │ │ └── show.html │ │ ├── recipeform.html │ │ └── show.html └── scripts │ └── README.md └── test └── java └── guru └── springframework ├── Spring5RecipeAppApplicationTests.java ├── controllers ├── ImageControllerTest.java ├── IndexControllerTest.java ├── IngredientControllerTest.java └── RecipeControllerTest.java ├── converters ├── CategoryCommandToCategoryTest.java ├── CategoryToCategoryCommandTest.java ├── IngredientCommandToIngredientTest.java ├── IngredientToIngredientCommandTest.java ├── NotesCommandToNotesTest.java ├── NotesToNotesCommandTest.java ├── RecipeCommandToRecipeTest.java ├── RecipeToRecipeCommandTest.java ├── UnitOfMeasureCommandToUnitOfMeasureTest.java └── UnitOfMeasureToUnitOfMeasureCommandTest.java ├── domain └── CategoryTest.java ├── repositories └── UnitOfMeasureRepositoryIT.java └── services ├── ImageServiceImplTest.java ├── IngredientServiceImplTest.java ├── RecipeServiceIT.java ├── RecipeServiceImplTest.java └── UnitOfMeasureServiceImplTest.java /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Java Maven CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-java/ for more details 4 | # 5 | version: 2 6 | jobs: 7 | build: 8 | docker: 9 | # specify the version you desire here 10 | - image: circleci/openjdk:8-jdk 11 | 12 | # Specify service dependencies here if necessary 13 | # CircleCI maintains a library of pre-built images 14 | # documented at https://circleci.com/docs/2.0/circleci-images/ 15 | # - image: circleci/postgres:9.4 16 | 17 | working_directory: ~/repo 18 | 19 | environment: 20 | # Customize the JVM maximum heap limit 21 | MAVEN_OPTS: -Xmx3200m 22 | 23 | steps: 24 | - checkout 25 | 26 | # Download and cache dependencies 27 | - restore_cache: 28 | keys: 29 | - v1-dependencies-{{ checksum "pom.xml" }} 30 | # fallback to using the latest cache if no exact match is found 31 | - v1-dependencies- 32 | 33 | - run: mvn dependency:go-offline 34 | 35 | - save_cache: 36 | paths: 37 | - ~/.m2 38 | key: v1-dependencies-{{ checksum "pom.xml" }} 39 | 40 | # run tests! and gen code coverage 41 | - run: mvn integration-test cobertura:cobertura 42 | 43 | - store_test_results: 44 | path: target/surefire-reports 45 | 46 | - run: 47 | name: Send to CodeCov 48 | command: bash <(curl -s https://codecov.io/bash) 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ###################### 2 | # Project Specific 3 | ###################### 4 | /build/www/** 5 | /src/test/javascript/coverage/ 6 | /src/test/javascript/PhantomJS*/ 7 | 8 | ###################### 9 | # Node 10 | ###################### 11 | /node/ 12 | node_tmp/ 13 | node_modules/ 14 | npm-debug.log.* 15 | 16 | ###################### 17 | # SASS 18 | ###################### 19 | .sass-cache/ 20 | 21 | ###################### 22 | # Eclipse 23 | ###################### 24 | *.pydevproject 25 | .project 26 | .metadata 27 | tmp/ 28 | tmp/**/* 29 | *.tmp 30 | *.bak 31 | *.swp 32 | *~.nib 33 | local.properties 34 | .classpath 35 | .settings/ 36 | .loadpath 37 | .factorypath 38 | /src/main/resources/rebel.xml 39 | 40 | # External tool builders 41 | .externalToolBuilders/** 42 | 43 | # Locally stored "Eclipse launch configurations" 44 | *.launch 45 | 46 | # CDT-specific 47 | .cproject 48 | 49 | # PDT-specific 50 | .buildpath 51 | 52 | ###################### 53 | # Intellij 54 | ###################### 55 | .idea/ 56 | *.iml 57 | *.iws 58 | *.ipr 59 | *.ids 60 | *.orig 61 | 62 | ###################### 63 | # Visual Studio Code 64 | ###################### 65 | .vscode/ 66 | 67 | ###################### 68 | # Maven 69 | ###################### 70 | /log/ 71 | /target/ 72 | 73 | ###################### 74 | # Gradle 75 | ###################### 76 | .gradle/ 77 | /build/ 78 | 79 | ###################### 80 | # Package Files 81 | ###################### 82 | *.jar 83 | *.war 84 | *.ear 85 | *.db 86 | 87 | ###################### 88 | # Windows 89 | ###################### 90 | # Windows image file caches 91 | Thumbs.db 92 | 93 | # Folder config file 94 | Desktop.ini 95 | 96 | ###################### 97 | # Mac OSX 98 | ###################### 99 | .DS_Store 100 | .svn 101 | 102 | # Thumbnails 103 | ._* 104 | 105 | # Files that might appear on external disk 106 | .Spotlight-V100 107 | .Trashes 108 | 109 | ###################### 110 | # Directories 111 | ###################### 112 | /bin/ 113 | /deploy/ 114 | 115 | ###################### 116 | # Logs 117 | ###################### 118 | *.log 119 | 120 | ###################### 121 | # Others 122 | ###################### 123 | *.class 124 | *.*~ 125 | *~ 126 | .merge_file* 127 | 128 | ###################### 129 | # Gradle Wrapper 130 | ###################### 131 | !gradle/wrapper/gradle-wrapper.jar 132 | 133 | ###################### 134 | # Maven Wrapper 135 | ###################### 136 | !.mvn/wrapper/maven-wrapper.jar 137 | 138 | ###################### 139 | # ESLint 140 | ###################### 141 | .eslintcache 142 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spring Boot Recipe Application 2 | 3 | [![CircleCI](https://circleci.com/gh/springframeworkguru/spring5-recipe-app.svg?style=svg)](https://circleci.com/gh/springframeworkguru/spring5-recipe-app) 4 | 5 | [![codecov](https://codecov.io/gh/springframeworkguru/spring5-mysql-recipe-app/branch/master/graph/badge.svg)](https://codecov.io/gh/springframeworkguru/spring5-mysql-recipe-app) 6 | 7 | This repository is for an example application built in my Spring Framework 5 - Beginner to Guru 8 | 9 | You can learn about my Spring Framework 5 Online course [here.](http://courses.springframework.guru/p/spring-framework-5-begginer-to-guru/?product_id=363173) -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Migwn, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 204 | echo $MAVEN_PROJECTBASEDIR 205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 206 | 207 | # For Cygwin, switch paths to Windows format before running java 208 | if $cygwin; then 209 | [ -n "$M2_HOME" ] && 210 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 211 | [ -n "$JAVA_HOME" ] && 212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 213 | [ -n "$CLASSPATH" ] && 214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 215 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 217 | fi 218 | 219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 220 | 221 | exec "$JAVACMD" \ 222 | $MAVEN_OPTS \ 223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 226 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | guru.springframework 7 | spring5-mysql-recipe-app 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | spring5-recipe-app 12 | Recipe Application 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.1.0.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-data-jpa 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-thymeleaf 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-web 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-devtools 44 | runtime 45 | 46 | 47 | com.h2database 48 | h2 49 | runtime 50 | 51 | 52 | 53 | org.projectlombok 54 | lombok 55 | 56 | 57 | org.webjars 58 | bootstrap 59 | 3.3.7-1 60 | 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-starter-test 65 | test 66 | 67 | 68 | 69 | 70 | 71 | 72 | org.springframework.boot 73 | spring-boot-maven-plugin 74 | 75 | 76 | org.codehaus.mojo 77 | cobertura-maven-plugin 78 | 2.7 79 | 80 | 81 | html 82 | xml 83 | 84 | 85 | 86 | 87 | 88 | 89 | org.apache.maven.plugins 90 | maven-surefire-plugin 91 | 92 | false 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | spring-snapshots 101 | Spring Snapshots 102 | https://repo.spring.io/snapshot 103 | 104 | true 105 | 106 | 107 | 108 | spring-milestones 109 | Spring Milestones 110 | https://repo.spring.io/milestone 111 | 112 | false 113 | 114 | 115 | 116 | 117 | 118 | 119 | spring-snapshots 120 | Spring Snapshots 121 | https://repo.spring.io/snapshot 122 | 123 | true 124 | 125 | 126 | 127 | spring-milestones 128 | Spring Milestones 129 | https://repo.spring.io/milestone 130 | 131 | false 132 | 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/Spring5RecipeAppApplication.java: -------------------------------------------------------------------------------- 1 | package guru.springframework; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Spring5RecipeAppApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Spring5RecipeAppApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/bootstrap/RecipeBootstrap.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.bootstrap; 2 | 3 | import guru.springframework.domain.*; 4 | import guru.springframework.repositories.CategoryRepository; 5 | import guru.springframework.repositories.RecipeRepository; 6 | import guru.springframework.repositories.UnitOfMeasureRepository; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.springframework.context.ApplicationListener; 9 | import org.springframework.context.event.ContextRefreshedEvent; 10 | import org.springframework.stereotype.Component; 11 | import org.springframework.transaction.annotation.Transactional; 12 | 13 | import java.math.BigDecimal; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import java.util.Optional; 17 | 18 | /** 19 | * Created by jt on 6/13/17. 20 | */ 21 | @Slf4j 22 | @Component 23 | public class RecipeBootstrap implements ApplicationListener { 24 | 25 | private final CategoryRepository categoryRepository; 26 | private final RecipeRepository recipeRepository; 27 | private final UnitOfMeasureRepository unitOfMeasureRepository; 28 | 29 | public RecipeBootstrap(CategoryRepository categoryRepository, RecipeRepository recipeRepository, UnitOfMeasureRepository unitOfMeasureRepository) { 30 | this.categoryRepository = categoryRepository; 31 | this.recipeRepository = recipeRepository; 32 | this.unitOfMeasureRepository = unitOfMeasureRepository; 33 | } 34 | 35 | @Override 36 | @Transactional 37 | public void onApplicationEvent(ContextRefreshedEvent event) { 38 | recipeRepository.saveAll(getRecipes()); 39 | log.debug("Loading Bootstrap Data"); 40 | } 41 | 42 | private List getRecipes() { 43 | 44 | List recipes = new ArrayList<>(2); 45 | 46 | //get UOMs 47 | Optional eachUomOptional = unitOfMeasureRepository.findByDescription("Each"); 48 | 49 | if(!eachUomOptional.isPresent()){ 50 | throw new RuntimeException("Expected UOM Not Found"); 51 | } 52 | 53 | Optional tableSpoonUomOptional = unitOfMeasureRepository.findByDescription("Tablespoon"); 54 | 55 | if(!tableSpoonUomOptional.isPresent()){ 56 | throw new RuntimeException("Expected UOM Not Found"); 57 | } 58 | 59 | Optional teaSpoonUomOptional = unitOfMeasureRepository.findByDescription("Teaspoon"); 60 | 61 | if(!teaSpoonUomOptional.isPresent()){ 62 | throw new RuntimeException("Expected UOM Not Found"); 63 | } 64 | 65 | Optional dashUomOptional = unitOfMeasureRepository.findByDescription("Dash"); 66 | 67 | if(!dashUomOptional.isPresent()){ 68 | throw new RuntimeException("Expected UOM Not Found"); 69 | } 70 | 71 | Optional pintUomOptional = unitOfMeasureRepository.findByDescription("Pint"); 72 | 73 | if(!pintUomOptional.isPresent()){ 74 | throw new RuntimeException("Expected UOM Not Found"); 75 | } 76 | 77 | Optional cupsUomOptional = unitOfMeasureRepository.findByDescription("Cup"); 78 | 79 | if(!cupsUomOptional.isPresent()){ 80 | throw new RuntimeException("Expected UOM Not Found"); 81 | } 82 | 83 | //get optionals 84 | UnitOfMeasure eachUom = eachUomOptional.get(); 85 | UnitOfMeasure tableSpoonUom = tableSpoonUomOptional.get(); 86 | UnitOfMeasure teapoonUom = tableSpoonUomOptional.get(); 87 | UnitOfMeasure dashUom = dashUomOptional.get(); 88 | UnitOfMeasure pintUom = dashUomOptional.get(); 89 | UnitOfMeasure cupsUom = cupsUomOptional.get(); 90 | 91 | //get Categories 92 | Optional americanCategoryOptional = categoryRepository.findByDescription("American"); 93 | 94 | if(!americanCategoryOptional.isPresent()){ 95 | throw new RuntimeException("Expected Category Not Found"); 96 | } 97 | 98 | Optional mexicanCategoryOptional = categoryRepository.findByDescription("Mexican"); 99 | 100 | if(!mexicanCategoryOptional.isPresent()){ 101 | throw new RuntimeException("Expected Category Not Found"); 102 | } 103 | 104 | Category americanCategory = americanCategoryOptional.get(); 105 | Category mexicanCategory = mexicanCategoryOptional.get(); 106 | 107 | //Yummy Guac 108 | Recipe guacRecipe = new Recipe(); 109 | guacRecipe.setDescription("Perfect Guacamole"); 110 | guacRecipe.setPrepTime(10); 111 | guacRecipe.setCookTime(0); 112 | guacRecipe.setDifficulty(Difficulty.EASY); 113 | guacRecipe.setDirections("1 Cut avocado, remove flesh: Cut the avocados in half. Remove seed. Score the inside of the avocado with a blunt knife and scoop out the flesh with a spoon" + 114 | "\n" + 115 | "2 Mash with a fork: Using a fork, roughly mash the avocado. (Don't overdo it! The guacamole should be a little chunky.)" + 116 | "\n" + 117 | "3 Add salt, lime juice, and the rest: Sprinkle with salt and lime (or lemon) juice. The acid in the lime juice will provide some balance to the richness of the avocado and will help delay the avocados from turning brown.\n" + 118 | "Add the chopped onion, cilantro, black pepper, and chiles. Chili peppers vary individually in their hotness. So, start with a half of one chili pepper and add to the guacamole to your desired degree of hotness.\n" + 119 | "Remember that much of this is done to taste because of the variability in the fresh ingredients. Start with this recipe and adjust to your taste.\n" + 120 | "4 Cover with plastic and chill to store: Place plastic wrap on the surface of the guacamole cover it and to prevent air reaching it. (The oxygen in the air causes oxidation which will turn the guacamole brown.) Refrigerate until ready to serve.\n" + 121 | "Chilling tomatoes hurts their flavor, so if you want to add chopped tomato to your guacamole, add it just before serving.\n" + 122 | "\n" + 123 | "\n" + 124 | "Read more: http://www.simplyrecipes.com/recipes/perfect_guacamole/#ixzz4jvpiV9Sd"); 125 | 126 | Notes guacNotes = new Notes(); 127 | guacNotes.setRecipeNotes("For a very quick guacamole just take a 1/4 cup of salsa and mix it in with your mashed avocados.\n" + 128 | "Feel free to experiment! One classic Mexican guacamole has pomegranate seeds and chunks of peaches in it (a Diana Kennedy favorite). Try guacamole with added pineapple, mango, or strawberries.\n" + 129 | "The simplest version of guacamole is just mashed avocados with salt. Don't let the lack of availability of other ingredients stop you from making guacamole.\n" + 130 | "To extend a limited supply of avocados, add either sour cream or cottage cheese to your guacamole dip. Purists may be horrified, but so what? It tastes great.\n" + 131 | "\n" + 132 | "\n" + 133 | "Read more: http://www.simplyrecipes.com/recipes/perfect_guacamole/#ixzz4jvoun5ws"); 134 | 135 | guacRecipe.setNotes(guacNotes); 136 | 137 | //very redundent - could add helper method, and make this simpler 138 | guacRecipe.addIngredient(new Ingredient("ripe avocados", new BigDecimal(2), eachUom)); 139 | guacRecipe.addIngredient(new Ingredient("Kosher salt", new BigDecimal(".5"), teapoonUom)); 140 | guacRecipe.addIngredient(new Ingredient("fresh lime juice or lemon juice", new BigDecimal(2), tableSpoonUom)); 141 | guacRecipe.addIngredient(new Ingredient("minced red onion or thinly sliced green onion", new BigDecimal(2), tableSpoonUom)); 142 | guacRecipe.addIngredient(new Ingredient("serrano chiles, stems and seeds removed, minced", new BigDecimal(2), eachUom)); 143 | guacRecipe.addIngredient(new Ingredient("Cilantro", new BigDecimal(2), tableSpoonUom)); 144 | guacRecipe.addIngredient(new Ingredient("freshly grated black pepper", new BigDecimal(2), dashUom)); 145 | guacRecipe.addIngredient(new Ingredient("ripe tomato, seeds and pulp removed, chopped", new BigDecimal(".5"), eachUom)); 146 | 147 | guacRecipe.getCategories().add(americanCategory); 148 | guacRecipe.getCategories().add(mexicanCategory); 149 | 150 | guacRecipe.setUrl("http://www.simplyrecipes.com/recipes/perfect_guacamole/"); 151 | guacRecipe.setServings(4); 152 | guacRecipe.setSource("Simply Recipes"); 153 | 154 | //add to return list 155 | recipes.add(guacRecipe); 156 | 157 | //Yummy Tacos 158 | Recipe tacosRecipe = new Recipe(); 159 | tacosRecipe.setDescription("Spicy Grilled Chicken Taco"); 160 | tacosRecipe.setCookTime(9); 161 | tacosRecipe.setPrepTime(20); 162 | tacosRecipe.setDifficulty(Difficulty.MODERATE); 163 | 164 | tacosRecipe.setDirections("1 Prepare a gas or charcoal grill for medium-high, direct heat.\n" + 165 | "2 Make the marinade and coat the chicken: In a large bowl, stir together the chili powder, oregano, cumin, sugar, salt, garlic and orange zest. Stir in the orange juice and olive oil to make a loose paste. Add the chicken to the bowl and toss to coat all over.\n" + 166 | "Set aside to marinate while the grill heats and you prepare the rest of the toppings.\n" + 167 | "\n" + 168 | "\n" + 169 | "3 Grill the chicken: Grill the chicken for 3 to 4 minutes per side, or until a thermometer inserted into the thickest part of the meat registers 165F. Transfer to a plate and rest for 5 minutes.\n" + 170 | "4 Warm the tortillas: Place each tortilla on the grill or on a hot, dry skillet over medium-high heat. As soon as you see pockets of the air start to puff up in the tortilla, turn it with tongs and heat for a few seconds on the other side.\n" + 171 | "Wrap warmed tortillas in a tea towel to keep them warm until serving.\n" + 172 | "5 Assemble the tacos: Slice the chicken into strips. On each tortilla, place a small handful of arugula. Top with chicken slices, sliced avocado, radishes, tomatoes, and onion slices. Drizzle with the thinned sour cream. Serve with lime wedges.\n" + 173 | "\n" + 174 | "\n" + 175 | "Read more: http://www.simplyrecipes.com/recipes/spicy_grilled_chicken_tacos/#ixzz4jvtrAnNm"); 176 | 177 | Notes tacoNotes = new Notes(); 178 | tacoNotes.setRecipeNotes("We have a family motto and it is this: Everything goes better in a tortilla.\n" + 179 | "Any and every kind of leftover can go inside a warm tortilla, usually with a healthy dose of pickled jalapenos. I can always sniff out a late-night snacker when the aroma of tortillas heating in a hot pan on the stove comes wafting through the house.\n" + 180 | "Today’s tacos are more purposeful – a deliberate meal instead of a secretive midnight snack!\n" + 181 | "First, I marinate the chicken briefly in a spicy paste of ancho chile powder, oregano, cumin, and sweet orange juice while the grill is heating. You can also use this time to prepare the taco toppings.\n" + 182 | "Grill the chicken, then let it rest while you warm the tortillas. Now you are ready to assemble the tacos and dig in. The whole meal comes together in about 30 minutes!\n" + 183 | "\n" + 184 | "\n" + 185 | "Read more: http://www.simplyrecipes.com/recipes/spicy_grilled_chicken_tacos/#ixzz4jvu7Q0MJ"); 186 | 187 | tacosRecipe.setNotes(tacoNotes); 188 | 189 | tacosRecipe.addIngredient(new Ingredient("Ancho Chili Powder", new BigDecimal(2), tableSpoonUom)); 190 | tacosRecipe.addIngredient(new Ingredient("Dried Oregano", new BigDecimal(1), teapoonUom)); 191 | tacosRecipe.addIngredient(new Ingredient("Dried Cumin", new BigDecimal(1), teapoonUom)); 192 | tacosRecipe.addIngredient(new Ingredient("Sugar", new BigDecimal(1), teapoonUom)); 193 | tacosRecipe.addIngredient(new Ingredient("Salt", new BigDecimal(".5"), teapoonUom)); 194 | tacosRecipe.addIngredient(new Ingredient("Clove of Garlic, Choppedr", new BigDecimal(1), eachUom)); 195 | tacosRecipe.addIngredient(new Ingredient("finely grated orange zestr", new BigDecimal(1), tableSpoonUom)); 196 | tacosRecipe.addIngredient(new Ingredient("fresh-squeezed orange juice", new BigDecimal(3), tableSpoonUom)); 197 | tacosRecipe.addIngredient(new Ingredient("Olive Oil", new BigDecimal(2), tableSpoonUom)); 198 | tacosRecipe.addIngredient(new Ingredient("boneless chicken thighs", new BigDecimal(4), tableSpoonUom)); 199 | tacosRecipe.addIngredient(new Ingredient("small corn tortillasr", new BigDecimal(8), eachUom)); 200 | tacosRecipe.addIngredient(new Ingredient("packed baby arugula", new BigDecimal(3), cupsUom)); 201 | tacosRecipe.addIngredient(new Ingredient("medium ripe avocados, slic", new BigDecimal(2), eachUom)); 202 | tacosRecipe.addIngredient(new Ingredient("radishes, thinly sliced", new BigDecimal(4), eachUom)); 203 | tacosRecipe.addIngredient(new Ingredient("cherry tomatoes, halved", new BigDecimal(".5"), pintUom)); 204 | tacosRecipe.addIngredient(new Ingredient("red onion, thinly sliced", new BigDecimal(".25"), eachUom)); 205 | tacosRecipe.addIngredient(new Ingredient("Roughly chopped cilantro", new BigDecimal(4), eachUom)); 206 | tacosRecipe.addIngredient(new Ingredient("cup sour cream thinned with 1/4 cup milk", new BigDecimal(4), cupsUom)); 207 | tacosRecipe.addIngredient(new Ingredient("lime, cut into wedges", new BigDecimal(4), eachUom)); 208 | 209 | tacosRecipe.getCategories().add(americanCategory); 210 | tacosRecipe.getCategories().add(mexicanCategory); 211 | 212 | tacosRecipe.setUrl("http://www.simplyrecipes.com/recipes/spicy_grilled_chicken_tacos/"); 213 | tacosRecipe.setServings(4); 214 | tacosRecipe.setSource("Simply Recipes"); 215 | 216 | recipes.add(tacosRecipe); 217 | return recipes; 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/commands/CategoryCommand.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.commands; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | 7 | /** 8 | * Created by jt on 6/21/17. 9 | */ 10 | @Setter 11 | @Getter 12 | @NoArgsConstructor 13 | public class CategoryCommand { 14 | private Long id; 15 | private String description; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/commands/IngredientCommand.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.commands; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | 7 | import java.math.BigDecimal; 8 | 9 | /** 10 | * Created by jt on 6/21/17. 11 | */ 12 | @Getter 13 | @Setter 14 | @NoArgsConstructor 15 | public class IngredientCommand { 16 | private Long id; 17 | private Long recipeId; 18 | private String description; 19 | private BigDecimal amount; 20 | private UnitOfMeasureCommand uom; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/commands/NotesCommand.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.commands; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | 7 | /** 8 | * Created by jt on 6/21/17. 9 | */ 10 | @Getter 11 | @Setter 12 | @NoArgsConstructor 13 | public class NotesCommand { 14 | private Long id; 15 | private String recipeNotes; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/commands/RecipeCommand.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.commands; 2 | 3 | import guru.springframework.domain.Difficulty; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | import org.hibernate.validator.constraints.NotBlank; 8 | import org.hibernate.validator.constraints.URL; 9 | 10 | import javax.validation.constraints.Max; 11 | import javax.validation.constraints.Min; 12 | import javax.validation.constraints.Size; 13 | import java.util.HashSet; 14 | import java.util.Set; 15 | 16 | /** 17 | * Created by jt on 6/21/17. 18 | */ 19 | @Getter 20 | @Setter 21 | @NoArgsConstructor 22 | public class RecipeCommand { 23 | private Long id; 24 | 25 | @NotBlank 26 | @Size(min = 3, max = 255) 27 | private String description; 28 | 29 | @Min(1) 30 | @Max(999) 31 | private Integer prepTime; 32 | 33 | @Min(1) 34 | @Max(999) 35 | private Integer cookTime; 36 | 37 | @Min(1) 38 | @Max(100) 39 | private Integer servings; 40 | private String source; 41 | 42 | @URL 43 | private String url; 44 | 45 | @NotBlank 46 | private String directions; 47 | 48 | private Set ingredients = new HashSet<>(); 49 | private Byte[] image; 50 | private Difficulty difficulty; 51 | private NotesCommand notes; 52 | private Set categories = new HashSet<>(); 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/commands/UnitOfMeasureCommand.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.commands; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | 7 | /** 8 | * Created by jt on 6/21/17. 9 | */ 10 | @Getter 11 | @Setter 12 | @NoArgsConstructor 13 | public class UnitOfMeasureCommand { 14 | private Long id; 15 | private String description; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/controllers/ControllerExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.controllers; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.http.HttpStatus; 5 | import org.springframework.web.bind.annotation.ControllerAdvice; 6 | import org.springframework.web.bind.annotation.ExceptionHandler; 7 | import org.springframework.web.bind.annotation.ResponseStatus; 8 | import org.springframework.web.servlet.ModelAndView; 9 | 10 | /** 11 | * Created by jt on 7/14/17. 12 | */ 13 | @Slf4j 14 | @ControllerAdvice 15 | public class ControllerExceptionHandler { 16 | 17 | @ResponseStatus(HttpStatus.BAD_REQUEST) 18 | @ExceptionHandler(NumberFormatException.class) 19 | public ModelAndView handleNumberFormat(Exception exception){ 20 | 21 | log.error("Handling Number Format Exception"); 22 | log.error(exception.getMessage()); 23 | 24 | ModelAndView modelAndView = new ModelAndView(); 25 | 26 | modelAndView.setViewName("400error"); 27 | modelAndView.addObject("exception", exception); 28 | 29 | return modelAndView; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/controllers/ImageController.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.controllers; 2 | 3 | import guru.springframework.commands.RecipeCommand; 4 | import guru.springframework.services.ImageService; 5 | import guru.springframework.services.RecipeService; 6 | import org.apache.tomcat.util.http.fileupload.IOUtils; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.ui.Model; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.PathVariable; 11 | import org.springframework.web.bind.annotation.PostMapping; 12 | import org.springframework.web.bind.annotation.RequestParam; 13 | import org.springframework.web.multipart.MultipartFile; 14 | 15 | import javax.servlet.http.HttpServletResponse; 16 | import java.io.ByteArrayInputStream; 17 | import java.io.IOException; 18 | import java.io.InputStream; 19 | 20 | /** 21 | * Created by jt on 7/3/17. 22 | */ 23 | @Controller 24 | public class ImageController { 25 | 26 | private final ImageService imageService; 27 | private final RecipeService recipeService; 28 | 29 | public ImageController(ImageService imageService, RecipeService recipeService) { 30 | this.imageService = imageService; 31 | this.recipeService = recipeService; 32 | } 33 | 34 | @GetMapping("recipe/{id}/image") 35 | public String showUploadForm(@PathVariable String id, Model model){ 36 | model.addAttribute("recipe", recipeService.findCommandById(Long.valueOf(id))); 37 | 38 | return "recipe/imageuploadform"; 39 | } 40 | 41 | @PostMapping("recipe/{id}/image") 42 | public String handleImagePost(@PathVariable String id, @RequestParam("imagefile") MultipartFile file){ 43 | 44 | imageService.saveImageFile(Long.valueOf(id), file); 45 | 46 | return "redirect:/recipe/" + id + "/show"; 47 | } 48 | 49 | @GetMapping("recipe/{id}/recipeimage") 50 | public void renderImageFromDB(@PathVariable String id, HttpServletResponse response) throws IOException { 51 | RecipeCommand recipeCommand = recipeService.findCommandById(Long.valueOf(id)); 52 | 53 | if (recipeCommand.getImage() != null) { 54 | byte[] byteArray = new byte[recipeCommand.getImage().length]; 55 | int i = 0; 56 | 57 | for (Byte wrappedByte : recipeCommand.getImage()){ 58 | byteArray[i++] = wrappedByte; //auto unboxing 59 | } 60 | 61 | response.setContentType("image/jpeg"); 62 | InputStream is = new ByteArrayInputStream(byteArray); 63 | IOUtils.copy(is, response.getOutputStream()); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/controllers/IndexController.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.controllers; 2 | 3 | import guru.springframework.services.RecipeService; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.ui.Model; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | 9 | /** 10 | * Created by jt on 6/1/17. 11 | */ 12 | @Slf4j 13 | @Controller 14 | public class IndexController { 15 | 16 | private final RecipeService recipeService; 17 | 18 | public IndexController(RecipeService recipeService) { 19 | this.recipeService = recipeService; 20 | } 21 | 22 | @RequestMapping({"", "/", "/index"}) 23 | public String getIndexPage(Model model) { 24 | log.debug("Getting Index page"); 25 | 26 | model.addAttribute("recipes", recipeService.getRecipes()); 27 | 28 | return "index"; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/controllers/IngredientController.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.controllers; 2 | 3 | import guru.springframework.commands.IngredientCommand; 4 | import guru.springframework.commands.RecipeCommand; 5 | import guru.springframework.commands.UnitOfMeasureCommand; 6 | import guru.springframework.services.IngredientService; 7 | import guru.springframework.services.RecipeService; 8 | import guru.springframework.services.UnitOfMeasureService; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.stereotype.Controller; 11 | import org.springframework.ui.Model; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.ModelAttribute; 14 | import org.springframework.web.bind.annotation.PathVariable; 15 | import org.springframework.web.bind.annotation.PostMapping; 16 | 17 | /** 18 | * Created by jt on 6/28/17. 19 | */ 20 | @Slf4j 21 | @Controller 22 | public class IngredientController { 23 | 24 | private final IngredientService ingredientService; 25 | private final RecipeService recipeService; 26 | private final UnitOfMeasureService unitOfMeasureService; 27 | 28 | public IngredientController(IngredientService ingredientService, RecipeService recipeService, UnitOfMeasureService unitOfMeasureService) { 29 | this.ingredientService = ingredientService; 30 | this.recipeService = recipeService; 31 | this.unitOfMeasureService = unitOfMeasureService; 32 | } 33 | 34 | @GetMapping("/recipe/{recipeId}/ingredients") 35 | public String listIngredients(@PathVariable String recipeId, Model model){ 36 | log.debug("Getting ingredient list for recipe id: " + recipeId); 37 | 38 | // use command object to avoid lazy load errors in Thymeleaf. 39 | model.addAttribute("recipe", recipeService.findCommandById(Long.valueOf(recipeId))); 40 | 41 | return "recipe/ingredient/list"; 42 | } 43 | 44 | @GetMapping("recipe/{recipeId}/ingredient/{id}/show") 45 | public String showRecipeIngredient(@PathVariable String recipeId, 46 | @PathVariable String id, Model model){ 47 | model.addAttribute("ingredient", ingredientService.findByRecipeIdAndIngredientId(Long.valueOf(recipeId), Long.valueOf(id))); 48 | return "recipe/ingredient/show"; 49 | } 50 | 51 | @GetMapping("recipe/{recipeId}/ingredient/new") 52 | public String newRecipe(@PathVariable String recipeId, Model model){ 53 | 54 | //make sure we have a good id value 55 | RecipeCommand recipeCommand = recipeService.findCommandById(Long.valueOf(recipeId)); 56 | //todo raise exception if null 57 | 58 | //need to return back parent id for hidden form property 59 | IngredientCommand ingredientCommand = new IngredientCommand(); 60 | ingredientCommand.setRecipeId(Long.valueOf(recipeId)); 61 | model.addAttribute("ingredient", ingredientCommand); 62 | 63 | //init uom 64 | ingredientCommand.setUom(new UnitOfMeasureCommand()); 65 | 66 | model.addAttribute("uomList", unitOfMeasureService.listAllUoms()); 67 | 68 | return "recipe/ingredient/ingredientform"; 69 | } 70 | 71 | @GetMapping("recipe/{recipeId}/ingredient/{id}/update") 72 | public String updateRecipeIngredient(@PathVariable String recipeId, 73 | @PathVariable String id, Model model){ 74 | model.addAttribute("ingredient", ingredientService.findByRecipeIdAndIngredientId(Long.valueOf(recipeId), Long.valueOf(id))); 75 | 76 | model.addAttribute("uomList", unitOfMeasureService.listAllUoms()); 77 | return "recipe/ingredient/ingredientform"; 78 | } 79 | 80 | @PostMapping("recipe/{recipeId}/ingredient") 81 | public String saveOrUpdate(@ModelAttribute IngredientCommand command){ 82 | IngredientCommand savedCommand = ingredientService.saveIngredientCommand(command); 83 | 84 | log.debug("saved receipe id:" + savedCommand.getRecipeId()); 85 | log.debug("saved ingredient id:" + savedCommand.getId()); 86 | 87 | return "redirect:/recipe/" + savedCommand.getRecipeId() + "/ingredient/" + savedCommand.getId() + "/show"; 88 | } 89 | 90 | @GetMapping("recipe/{recipeId}/ingredient/{id}/delete") 91 | public String deleteIngredient(@PathVariable String recipeId, 92 | @PathVariable String id){ 93 | 94 | log.debug("deleting ingredient id:" + id); 95 | ingredientService.deleteById(Long.valueOf(recipeId), Long.valueOf(id)); 96 | 97 | return "redirect:/recipe/" + recipeId + "/ingredients"; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/controllers/RecipeController.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.controllers; 2 | 3 | import guru.springframework.commands.RecipeCommand; 4 | import guru.springframework.exceptions.NotFoundException; 5 | import guru.springframework.services.RecipeService; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.stereotype.Controller; 9 | import org.springframework.ui.Model; 10 | import org.springframework.validation.BindingResult; 11 | import org.springframework.web.bind.annotation.*; 12 | import org.springframework.web.servlet.ModelAndView; 13 | 14 | import javax.validation.Valid; 15 | 16 | /** 17 | * Created by jt on 6/19/17. 18 | */ 19 | @Slf4j 20 | @Controller 21 | public class RecipeController { 22 | 23 | private static final String RECIPE_RECIPEFORM_URL = "recipe/recipeform"; 24 | private final RecipeService recipeService; 25 | 26 | public RecipeController(RecipeService recipeService) { 27 | this.recipeService = recipeService; 28 | } 29 | 30 | @GetMapping("/recipe/{id}/show") 31 | public String showById(@PathVariable String id, Model model){ 32 | 33 | model.addAttribute("recipe", recipeService.findById(new Long(id))); 34 | 35 | return "recipe/show"; 36 | } 37 | 38 | @GetMapping("recipe/new") 39 | public String newRecipe(Model model){ 40 | model.addAttribute("recipe", new RecipeCommand()); 41 | 42 | return "recipe/recipeform"; 43 | } 44 | 45 | @GetMapping("recipe/{id}/update") 46 | public String updateRecipe(@PathVariable String id, Model model){ 47 | model.addAttribute("recipe", recipeService.findCommandById(Long.valueOf(id))); 48 | return RECIPE_RECIPEFORM_URL; 49 | } 50 | 51 | @PostMapping("recipe") 52 | public String saveOrUpdate(@Valid @ModelAttribute("recipe") RecipeCommand command, BindingResult bindingResult){ 53 | 54 | if(bindingResult.hasErrors()){ 55 | 56 | bindingResult.getAllErrors().forEach(objectError -> { 57 | log.debug(objectError.toString()); 58 | }); 59 | 60 | return RECIPE_RECIPEFORM_URL; 61 | } 62 | 63 | RecipeCommand savedCommand = recipeService.saveRecipeCommand(command); 64 | 65 | return "redirect:/recipe/" + savedCommand.getId() + "/show"; 66 | } 67 | 68 | @GetMapping("recipe/{id}/delete") 69 | public String deleteById(@PathVariable String id){ 70 | 71 | log.debug("Deleting id: " + id); 72 | 73 | recipeService.deleteById(Long.valueOf(id)); 74 | return "redirect:/"; 75 | } 76 | 77 | @ResponseStatus(HttpStatus.NOT_FOUND) 78 | @ExceptionHandler(NotFoundException.class) 79 | public ModelAndView handleNotFound(Exception exception){ 80 | 81 | log.error("Handling not found exception"); 82 | log.error(exception.getMessage()); 83 | 84 | ModelAndView modelAndView = new ModelAndView(); 85 | 86 | modelAndView.setViewName("404error"); 87 | modelAndView.addObject("exception", exception); 88 | 89 | return modelAndView; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/converters/CategoryCommandToCategory.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.converters; 2 | 3 | 4 | import guru.springframework.commands.CategoryCommand; 5 | import guru.springframework.domain.Category; 6 | import lombok.Synchronized; 7 | import org.springframework.core.convert.converter.Converter; 8 | import org.springframework.lang.Nullable; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * Created by jt on 6/21/17. 13 | */ 14 | @Component 15 | public class CategoryCommandToCategory implements Converter{ 16 | 17 | @Synchronized 18 | @Nullable 19 | @Override 20 | public Category convert(CategoryCommand source) { 21 | if (source == null) { 22 | return null; 23 | } 24 | 25 | final Category category = new Category(); 26 | category.setId(source.getId()); 27 | category.setDescription(source.getDescription()); 28 | return category; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/converters/CategoryToCategoryCommand.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.converters; 2 | 3 | import guru.springframework.commands.CategoryCommand; 4 | import guru.springframework.domain.Category; 5 | import lombok.Synchronized; 6 | import org.springframework.core.convert.converter.Converter; 7 | import org.springframework.lang.Nullable; 8 | import org.springframework.stereotype.Component; 9 | 10 | /** 11 | * Created by jt on 6/21/17. 12 | */ 13 | @Component 14 | public class CategoryToCategoryCommand implements Converter { 15 | 16 | @Synchronized 17 | @Nullable 18 | @Override 19 | public CategoryCommand convert(Category source) { 20 | if (source == null) { 21 | return null; 22 | } 23 | 24 | final CategoryCommand categoryCommand = new CategoryCommand(); 25 | 26 | categoryCommand.setId(source.getId()); 27 | categoryCommand.setDescription(source.getDescription()); 28 | 29 | return categoryCommand; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/converters/IngredientCommandToIngredient.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.converters; 2 | 3 | import guru.springframework.commands.IngredientCommand; 4 | import guru.springframework.domain.Ingredient; 5 | import guru.springframework.domain.Recipe; 6 | import org.springframework.core.convert.converter.Converter; 7 | import org.springframework.lang.Nullable; 8 | import org.springframework.stereotype.Component; 9 | 10 | /** 11 | * Created by jt on 6/21/17. 12 | */ 13 | @Component 14 | public class IngredientCommandToIngredient implements Converter { 15 | 16 | private final UnitOfMeasureCommandToUnitOfMeasure uomConverter; 17 | 18 | public IngredientCommandToIngredient(UnitOfMeasureCommandToUnitOfMeasure uomConverter) { 19 | this.uomConverter = uomConverter; 20 | } 21 | 22 | @Nullable 23 | @Override 24 | public Ingredient convert(IngredientCommand source) { 25 | if (source == null) { 26 | return null; 27 | } 28 | 29 | final Ingredient ingredient = new Ingredient(); 30 | ingredient.setId(source.getId()); 31 | 32 | if(source.getRecipeId() != null){ 33 | Recipe recipe = new Recipe(); 34 | recipe.setId(source.getRecipeId()); 35 | ingredient.setRecipe(recipe); 36 | recipe.addIngredient(ingredient); 37 | } 38 | 39 | ingredient.setAmount(source.getAmount()); 40 | ingredient.setDescription(source.getDescription()); 41 | ingredient.setUom(uomConverter.convert(source.getUom())); 42 | return ingredient; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/converters/IngredientToIngredientCommand.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.converters; 2 | 3 | import guru.springframework.commands.IngredientCommand; 4 | import guru.springframework.domain.Ingredient; 5 | import lombok.Synchronized; 6 | import org.springframework.core.convert.converter.Converter; 7 | import org.springframework.lang.Nullable; 8 | import org.springframework.stereotype.Component; 9 | 10 | /** 11 | * Created by jt on 6/21/17. 12 | */ 13 | @Component 14 | public class IngredientToIngredientCommand implements Converter { 15 | 16 | private final UnitOfMeasureToUnitOfMeasureCommand uomConverter; 17 | 18 | public IngredientToIngredientCommand(UnitOfMeasureToUnitOfMeasureCommand uomConverter) { 19 | this.uomConverter = uomConverter; 20 | } 21 | 22 | @Synchronized 23 | @Nullable 24 | @Override 25 | public IngredientCommand convert(Ingredient ingredient) { 26 | if (ingredient == null) { 27 | return null; 28 | } 29 | 30 | IngredientCommand ingredientCommand = new IngredientCommand(); 31 | ingredientCommand.setId(ingredient.getId()); 32 | if (ingredient.getRecipe() != null) { 33 | ingredientCommand.setRecipeId(ingredient.getRecipe().getId()); 34 | } 35 | ingredientCommand.setAmount(ingredient.getAmount()); 36 | ingredientCommand.setDescription(ingredient.getDescription()); 37 | ingredientCommand.setUom(uomConverter.convert(ingredient.getUom())); 38 | return ingredientCommand; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/converters/NotesCommandToNotes.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.converters; 2 | 3 | import guru.springframework.commands.NotesCommand; 4 | import guru.springframework.domain.Notes; 5 | import lombok.Synchronized; 6 | import org.springframework.core.convert.converter.Converter; 7 | import org.springframework.lang.Nullable; 8 | import org.springframework.stereotype.Component; 9 | 10 | /** 11 | * Created by jt on 6/21/17. 12 | */ 13 | @Component 14 | public class NotesCommandToNotes implements Converter { 15 | 16 | @Synchronized 17 | @Nullable 18 | @Override 19 | public Notes convert(NotesCommand source) { 20 | if(source == null) { 21 | return null; 22 | } 23 | 24 | final Notes notes = new Notes(); 25 | notes.setId(source.getId()); 26 | notes.setRecipeNotes(source.getRecipeNotes()); 27 | return notes; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/converters/NotesToNotesCommand.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.converters; 2 | 3 | import guru.springframework.commands.NotesCommand; 4 | import guru.springframework.domain.Notes; 5 | import lombok.Synchronized; 6 | import org.springframework.core.convert.converter.Converter; 7 | import org.springframework.lang.Nullable; 8 | import org.springframework.stereotype.Component; 9 | 10 | /** 11 | * Created by jt on 6/21/17. 12 | */ 13 | @Component 14 | public class NotesToNotesCommand implements Converter{ 15 | 16 | @Synchronized 17 | @Nullable 18 | @Override 19 | public NotesCommand convert(Notes source) { 20 | if (source == null) { 21 | return null; 22 | } 23 | 24 | final NotesCommand notesCommand = new NotesCommand(); 25 | notesCommand.setId(source.getId()); 26 | notesCommand.setRecipeNotes(source.getRecipeNotes()); 27 | return notesCommand; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/converters/RecipeCommandToRecipe.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.converters; 2 | 3 | import guru.springframework.commands.RecipeCommand; 4 | import guru.springframework.domain.Recipe; 5 | import lombok.Synchronized; 6 | import org.springframework.core.convert.converter.Converter; 7 | import org.springframework.lang.Nullable; 8 | import org.springframework.stereotype.Component; 9 | 10 | /** 11 | * Created by jt on 6/21/17. 12 | */ 13 | @Component 14 | public class RecipeCommandToRecipe implements Converter { 15 | 16 | private final CategoryCommandToCategory categoryConveter; 17 | private final IngredientCommandToIngredient ingredientConverter; 18 | private final NotesCommandToNotes notesConverter; 19 | 20 | public RecipeCommandToRecipe(CategoryCommandToCategory categoryConveter, IngredientCommandToIngredient ingredientConverter, 21 | NotesCommandToNotes notesConverter) { 22 | this.categoryConveter = categoryConveter; 23 | this.ingredientConverter = ingredientConverter; 24 | this.notesConverter = notesConverter; 25 | } 26 | 27 | @Synchronized 28 | @Nullable 29 | @Override 30 | public Recipe convert(RecipeCommand source) { 31 | if (source == null) { 32 | return null; 33 | } 34 | 35 | final Recipe recipe = new Recipe(); 36 | recipe.setId(source.getId()); 37 | recipe.setCookTime(source.getCookTime()); 38 | recipe.setPrepTime(source.getPrepTime()); 39 | recipe.setDescription(source.getDescription()); 40 | recipe.setDifficulty(source.getDifficulty()); 41 | recipe.setDirections(source.getDirections()); 42 | recipe.setServings(source.getServings()); 43 | recipe.setSource(source.getSource()); 44 | recipe.setUrl(source.getUrl()); 45 | recipe.setNotes(notesConverter.convert(source.getNotes())); 46 | 47 | if (source.getCategories() != null && source.getCategories().size() > 0){ 48 | source.getCategories() 49 | .forEach( category -> recipe.getCategories().add(categoryConveter.convert(category))); 50 | } 51 | 52 | if (source.getIngredients() != null && source.getIngredients().size() > 0){ 53 | source.getIngredients() 54 | .forEach(ingredient -> recipe.getIngredients().add(ingredientConverter.convert(ingredient))); 55 | } 56 | 57 | return recipe; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/converters/RecipeToRecipeCommand.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.converters; 2 | 3 | import guru.springframework.commands.RecipeCommand; 4 | import guru.springframework.domain.Category; 5 | import guru.springframework.domain.Recipe; 6 | import lombok.Synchronized; 7 | import org.springframework.core.convert.converter.Converter; 8 | import org.springframework.lang.Nullable; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * Created by jt on 6/21/17. 13 | */ 14 | @Component 15 | public class RecipeToRecipeCommand implements Converter{ 16 | 17 | private final CategoryToCategoryCommand categoryConveter; 18 | private final IngredientToIngredientCommand ingredientConverter; 19 | private final NotesToNotesCommand notesConverter; 20 | 21 | public RecipeToRecipeCommand(CategoryToCategoryCommand categoryConveter, IngredientToIngredientCommand ingredientConverter, 22 | NotesToNotesCommand notesConverter) { 23 | this.categoryConveter = categoryConveter; 24 | this.ingredientConverter = ingredientConverter; 25 | this.notesConverter = notesConverter; 26 | } 27 | 28 | @Synchronized 29 | @Nullable 30 | @Override 31 | public RecipeCommand convert(Recipe source) { 32 | if (source == null) { 33 | return null; 34 | } 35 | 36 | final RecipeCommand command = new RecipeCommand(); 37 | command.setId(source.getId()); 38 | command.setCookTime(source.getCookTime()); 39 | command.setPrepTime(source.getPrepTime()); 40 | command.setDescription(source.getDescription()); 41 | command.setDifficulty(source.getDifficulty()); 42 | command.setDirections(source.getDirections()); 43 | command.setServings(source.getServings()); 44 | command.setSource(source.getSource()); 45 | command.setUrl(source.getUrl()); 46 | command.setImage(source.getImage()); 47 | command.setNotes(notesConverter.convert(source.getNotes())); 48 | 49 | if (source.getCategories() != null && source.getCategories().size() > 0){ 50 | source.getCategories() 51 | .forEach((Category category) -> command.getCategories().add(categoryConveter.convert(category))); 52 | } 53 | 54 | if (source.getIngredients() != null && source.getIngredients().size() > 0){ 55 | source.getIngredients() 56 | .forEach(ingredient -> command.getIngredients().add(ingredientConverter.convert(ingredient))); 57 | } 58 | 59 | return command; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/converters/UnitOfMeasureCommandToUnitOfMeasure.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.converters; 2 | 3 | import guru.springframework.commands.UnitOfMeasureCommand; 4 | import guru.springframework.domain.UnitOfMeasure; 5 | import lombok.Synchronized; 6 | import org.springframework.core.convert.converter.Converter; 7 | import org.springframework.lang.Nullable; 8 | import org.springframework.stereotype.Component; 9 | 10 | /** 11 | * Created by jt on 6/21/17. 12 | */ 13 | @Component 14 | public class UnitOfMeasureCommandToUnitOfMeasure implements Converter{ 15 | 16 | @Synchronized 17 | @Nullable 18 | @Override 19 | public UnitOfMeasure convert(UnitOfMeasureCommand source) { 20 | if (source == null) { 21 | return null; 22 | } 23 | 24 | final UnitOfMeasure uom = new UnitOfMeasure(); 25 | uom.setId(source.getId()); 26 | uom.setDescription(source.getDescription()); 27 | return uom; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/converters/UnitOfMeasureToUnitOfMeasureCommand.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.converters; 2 | 3 | import guru.springframework.commands.UnitOfMeasureCommand; 4 | import guru.springframework.domain.UnitOfMeasure; 5 | import lombok.Synchronized; 6 | import org.springframework.core.convert.converter.Converter; 7 | import org.springframework.lang.Nullable; 8 | import org.springframework.stereotype.Component; 9 | 10 | /** 11 | * Created by jt on 6/21/17. 12 | */ 13 | @Component 14 | public class UnitOfMeasureToUnitOfMeasureCommand implements Converter { 15 | 16 | @Synchronized 17 | @Nullable 18 | @Override 19 | public UnitOfMeasureCommand convert(UnitOfMeasure unitOfMeasure) { 20 | 21 | if (unitOfMeasure != null) { 22 | final UnitOfMeasureCommand uomc = new UnitOfMeasureCommand(); 23 | uomc.setId(unitOfMeasure.getId()); 24 | uomc.setDescription(unitOfMeasure.getDescription()); 25 | return uomc; 26 | } 27 | return null; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/domain/Category.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.domain; 2 | 3 | import lombok.EqualsAndHashCode; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | import javax.persistence.*; 8 | import java.util.Set; 9 | 10 | /** 11 | * Created by jt on 6/13/17. 12 | */ 13 | @Getter 14 | @Setter 15 | @EqualsAndHashCode(exclude = {"recipes"}) 16 | @Entity 17 | public class Category { 18 | 19 | @Id 20 | @GeneratedValue(strategy = GenerationType.IDENTITY) 21 | private Long id; 22 | private String description; 23 | 24 | @ManyToMany(mappedBy = "categories") 25 | private Set recipes; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/domain/Difficulty.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.domain; 2 | 3 | /** 4 | * Created by jt on 6/13/17. 5 | */ 6 | public enum Difficulty { 7 | 8 | EASY, MODERATE, KIND_OF_HARD, HARD 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/domain/Ingredient.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.domain; 2 | 3 | import lombok.EqualsAndHashCode; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | import javax.persistence.*; 8 | import java.math.BigDecimal; 9 | 10 | /** 11 | * Created by jt on 6/13/17. 12 | */ 13 | @Getter 14 | @Setter 15 | @EqualsAndHashCode(exclude = {"recipe"}) 16 | @Entity 17 | public class Ingredient { 18 | 19 | @Id 20 | @GeneratedValue(strategy = GenerationType.IDENTITY) 21 | private Long id; 22 | private String description; 23 | private BigDecimal amount; 24 | 25 | @OneToOne(fetch = FetchType.EAGER) 26 | private UnitOfMeasure uom; 27 | 28 | @ManyToOne 29 | private Recipe recipe; 30 | 31 | public Ingredient() { 32 | } 33 | 34 | public Ingredient(String description, BigDecimal amount, UnitOfMeasure uom) { 35 | this.description = description; 36 | this.amount = amount; 37 | this.uom = uom; 38 | } 39 | 40 | public Ingredient(String description, BigDecimal amount, UnitOfMeasure uom, Recipe recipe) { 41 | this.description = description; 42 | this.amount = amount; 43 | this.uom = uom; 44 | this.recipe = recipe; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/domain/Notes.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.domain; 2 | 3 | import lombok.EqualsAndHashCode; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | import javax.persistence.*; 8 | 9 | /** 10 | * Created by jt on 6/13/17. 11 | */ 12 | @Getter 13 | @Setter 14 | @EqualsAndHashCode(exclude = {"recipe"}) 15 | @Entity 16 | public class Notes { 17 | 18 | @Id 19 | @GeneratedValue(strategy = GenerationType.IDENTITY) 20 | private Long id; 21 | 22 | @OneToOne 23 | private Recipe recipe; 24 | 25 | @Lob 26 | private String recipeNotes; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/domain/Recipe.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.domain; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | import javax.persistence.*; 7 | import java.util.HashSet; 8 | import java.util.Set; 9 | 10 | /** 11 | * Created by jt on 6/13/17. 12 | */ 13 | @Getter 14 | @Setter 15 | @Entity 16 | public class Recipe { 17 | 18 | @Id 19 | @GeneratedValue(strategy = GenerationType.IDENTITY) 20 | private Long id; 21 | 22 | private String description; 23 | private Integer prepTime; 24 | private Integer cookTime; 25 | private Integer servings; 26 | private String source; 27 | private String url; 28 | 29 | @Lob 30 | private String directions; 31 | 32 | @OneToMany(cascade = CascadeType.ALL, mappedBy = "recipe") 33 | private Set ingredients = new HashSet<>(); 34 | 35 | @Lob 36 | private Byte[] image; 37 | 38 | @Enumerated(value = EnumType.STRING) 39 | private Difficulty difficulty; 40 | 41 | @OneToOne(cascade = CascadeType.ALL) 42 | private Notes notes; 43 | 44 | @ManyToMany 45 | @JoinTable(name = "recipe_category", 46 | joinColumns = @JoinColumn(name = "recipe_id"), 47 | inverseJoinColumns = @JoinColumn(name = "category_id")) 48 | private Set categories = new HashSet<>(); 49 | 50 | public void setNotes(Notes notes) { 51 | if (notes != null) { 52 | this.notes = notes; 53 | notes.setRecipe(this); 54 | } 55 | } 56 | 57 | public Recipe addIngredient(Ingredient ingredient){ 58 | ingredient.setRecipe(this); 59 | this.ingredients.add(ingredient); 60 | return this; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/domain/UnitOfMeasure.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.domain; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | import javax.persistence.Entity; 7 | import javax.persistence.GeneratedValue; 8 | import javax.persistence.GenerationType; 9 | import javax.persistence.Id; 10 | 11 | /** 12 | * Created by jt on 6/13/17. 13 | */ 14 | @Getter 15 | @Setter 16 | @Entity 17 | public class UnitOfMeasure { 18 | 19 | @Id 20 | @GeneratedValue(strategy = GenerationType.IDENTITY) 21 | private Long id; 22 | private String description; 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/exceptions/NotFoundException.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.exceptions; 2 | 3 | import org.springframework.http.HttpStatus; 4 | import org.springframework.web.bind.annotation.ResponseStatus; 5 | 6 | /** 7 | * Created by jt on 7/13/17. 8 | */ 9 | @ResponseStatus(HttpStatus.NOT_FOUND) 10 | public class NotFoundException extends RuntimeException { 11 | 12 | public NotFoundException() { 13 | super(); 14 | } 15 | 16 | public NotFoundException(String message) { 17 | super(message); 18 | } 19 | 20 | public NotFoundException(String message, Throwable cause) { 21 | super(message, cause); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/repositories/CategoryRepository.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.repositories; 2 | 3 | import guru.springframework.domain.Category; 4 | import org.springframework.data.repository.CrudRepository; 5 | 6 | import java.util.Optional; 7 | 8 | /** 9 | * Created by jt on 6/13/17. 10 | */ 11 | public interface CategoryRepository extends CrudRepository { 12 | 13 | Optional findByDescription(String description); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/repositories/RecipeRepository.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.repositories; 2 | 3 | import guru.springframework.domain.Recipe; 4 | import org.springframework.data.repository.CrudRepository; 5 | 6 | /** 7 | * Created by jt on 6/13/17. 8 | */ 9 | public interface RecipeRepository extends CrudRepository { 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/repositories/UnitOfMeasureRepository.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.repositories; 2 | 3 | import guru.springframework.domain.UnitOfMeasure; 4 | import org.springframework.data.repository.CrudRepository; 5 | 6 | import java.util.Optional; 7 | 8 | /** 9 | * Created by jt on 6/13/17. 10 | */ 11 | public interface UnitOfMeasureRepository extends CrudRepository { 12 | 13 | Optional findByDescription(String description); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/services/ImageService.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.services; 2 | 3 | import org.springframework.web.multipart.MultipartFile; 4 | 5 | /** 6 | * Created by jt on 7/3/17. 7 | */ 8 | public interface ImageService { 9 | 10 | void saveImageFile(Long recipeId, MultipartFile file); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/services/ImageServiceImpl.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.services; 2 | 3 | import guru.springframework.domain.Recipe; 4 | import guru.springframework.repositories.RecipeRepository; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.stereotype.Service; 7 | import org.springframework.transaction.annotation.Transactional; 8 | import org.springframework.web.multipart.MultipartFile; 9 | 10 | import java.io.IOException; 11 | 12 | /** 13 | * Created by jt on 7/3/17. 14 | */ 15 | @Slf4j 16 | @Service 17 | public class ImageServiceImpl implements ImageService { 18 | 19 | 20 | private final RecipeRepository recipeRepository; 21 | 22 | public ImageServiceImpl( RecipeRepository recipeService) { 23 | 24 | this.recipeRepository = recipeService; 25 | } 26 | 27 | @Override 28 | @Transactional 29 | public void saveImageFile(Long recipeId, MultipartFile file) { 30 | 31 | try { 32 | Recipe recipe = recipeRepository.findById(recipeId).get(); 33 | 34 | Byte[] byteObjects = new Byte[file.getBytes().length]; 35 | 36 | int i = 0; 37 | 38 | for (byte b : file.getBytes()){ 39 | byteObjects[i++] = b; 40 | } 41 | 42 | recipe.setImage(byteObjects); 43 | 44 | recipeRepository.save(recipe); 45 | } catch (IOException e) { 46 | //todo handle better 47 | log.error("Error occurred", e); 48 | 49 | e.printStackTrace(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/services/IngredientService.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.services; 2 | 3 | import guru.springframework.commands.IngredientCommand; 4 | 5 | /** 6 | * Created by jt on 6/27/17. 7 | */ 8 | public interface IngredientService { 9 | 10 | IngredientCommand findByRecipeIdAndIngredientId(Long recipeId, Long ingredientId); 11 | 12 | IngredientCommand saveIngredientCommand(IngredientCommand command); 13 | 14 | void deleteById(Long recipeId, Long idToDelete); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/services/IngredientServiceImpl.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.services; 2 | 3 | import guru.springframework.commands.IngredientCommand; 4 | import guru.springframework.converters.IngredientCommandToIngredient; 5 | import guru.springframework.converters.IngredientToIngredientCommand; 6 | import guru.springframework.domain.Ingredient; 7 | import guru.springframework.domain.Recipe; 8 | import guru.springframework.repositories.RecipeRepository; 9 | import guru.springframework.repositories.UnitOfMeasureRepository; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.stereotype.Service; 12 | import org.springframework.transaction.annotation.Transactional; 13 | 14 | import java.util.Optional; 15 | 16 | /** 17 | * Created by jt on 6/28/17. 18 | */ 19 | @Slf4j 20 | @Service 21 | public class IngredientServiceImpl implements IngredientService { 22 | 23 | private final IngredientToIngredientCommand ingredientToIngredientCommand; 24 | private final IngredientCommandToIngredient ingredientCommandToIngredient; 25 | private final RecipeRepository recipeRepository; 26 | private final UnitOfMeasureRepository unitOfMeasureRepository; 27 | 28 | public IngredientServiceImpl(IngredientToIngredientCommand ingredientToIngredientCommand, 29 | IngredientCommandToIngredient ingredientCommandToIngredient, 30 | RecipeRepository recipeRepository, UnitOfMeasureRepository unitOfMeasureRepository) { 31 | this.ingredientToIngredientCommand = ingredientToIngredientCommand; 32 | this.ingredientCommandToIngredient = ingredientCommandToIngredient; 33 | this.recipeRepository = recipeRepository; 34 | this.unitOfMeasureRepository = unitOfMeasureRepository; 35 | } 36 | 37 | @Override 38 | public IngredientCommand findByRecipeIdAndIngredientId(Long recipeId, Long ingredientId) { 39 | 40 | Optional recipeOptional = recipeRepository.findById(recipeId); 41 | 42 | if (!recipeOptional.isPresent()){ 43 | //todo impl error handling 44 | log.error("recipe id not found. Id: " + recipeId); 45 | } 46 | 47 | Recipe recipe = recipeOptional.get(); 48 | 49 | Optional ingredientCommandOptional = recipe.getIngredients().stream() 50 | .filter(ingredient -> ingredient.getId().equals(ingredientId)) 51 | .map( ingredient -> ingredientToIngredientCommand.convert(ingredient)).findFirst(); 52 | 53 | if(!ingredientCommandOptional.isPresent()){ 54 | //todo impl error handling 55 | log.error("Ingredient id not found: " + ingredientId); 56 | } 57 | 58 | return ingredientCommandOptional.get(); 59 | } 60 | 61 | @Override 62 | @Transactional 63 | public IngredientCommand saveIngredientCommand(IngredientCommand command) { 64 | Optional recipeOptional = recipeRepository.findById(command.getRecipeId()); 65 | 66 | if(!recipeOptional.isPresent()){ 67 | 68 | //todo toss error if not found! 69 | log.error("Recipe not found for id: " + command.getRecipeId()); 70 | return new IngredientCommand(); 71 | } else { 72 | Recipe recipe = recipeOptional.get(); 73 | 74 | Optional ingredientOptional = recipe 75 | .getIngredients() 76 | .stream() 77 | .filter(ingredient -> ingredient.getId().equals(command.getId())) 78 | .findFirst(); 79 | 80 | if(ingredientOptional.isPresent()){ 81 | Ingredient ingredientFound = ingredientOptional.get(); 82 | ingredientFound.setDescription(command.getDescription()); 83 | ingredientFound.setAmount(command.getAmount()); 84 | ingredientFound.setUom(unitOfMeasureRepository 85 | .findById(command.getUom().getId()) 86 | .orElseThrow(() -> new RuntimeException("UOM NOT FOUND"))); //todo address this 87 | } else { 88 | //add new Ingredient 89 | Ingredient ingredient = ingredientCommandToIngredient.convert(command); 90 | ingredient.setRecipe(recipe); 91 | recipe.addIngredient(ingredient); 92 | } 93 | 94 | Recipe savedRecipe = recipeRepository.save(recipe); 95 | 96 | Optional savedIngredientOptional = savedRecipe.getIngredients().stream() 97 | .filter(recipeIngredients -> recipeIngredients.getId().equals(command.getId())) 98 | .findFirst(); 99 | 100 | //check by description 101 | if(!savedIngredientOptional.isPresent()){ 102 | //not totally safe... But best guess 103 | savedIngredientOptional = savedRecipe.getIngredients().stream() 104 | .filter(recipeIngredients -> recipeIngredients.getDescription().equals(command.getDescription())) 105 | .filter(recipeIngredients -> recipeIngredients.getAmount().equals(command.getAmount())) 106 | .filter(recipeIngredients -> recipeIngredients.getUom().getId().equals(command.getUom().getId())) 107 | .findFirst(); 108 | } 109 | 110 | //to do check for fail 111 | return ingredientToIngredientCommand.convert(savedIngredientOptional.get()); 112 | } 113 | 114 | } 115 | 116 | @Override 117 | public void deleteById(Long recipeId, Long idToDelete) { 118 | 119 | log.debug("Deleting ingredient: " + recipeId + ":" + idToDelete); 120 | 121 | Optional recipeOptional = recipeRepository.findById(recipeId); 122 | 123 | if(recipeOptional.isPresent()){ 124 | Recipe recipe = recipeOptional.get(); 125 | log.debug("found recipe"); 126 | 127 | Optional ingredientOptional = recipe 128 | .getIngredients() 129 | .stream() 130 | .filter(ingredient -> ingredient.getId().equals(idToDelete)) 131 | .findFirst(); 132 | 133 | if(ingredientOptional.isPresent()){ 134 | log.debug("found Ingredient"); 135 | Ingredient ingredientToDelete = ingredientOptional.get(); 136 | ingredientToDelete.setRecipe(null); 137 | recipe.getIngredients().remove(ingredientOptional.get()); 138 | recipeRepository.save(recipe); 139 | } 140 | } else { 141 | log.debug("Recipe Id Not found. Id:" + recipeId); 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/services/RecipeService.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.services; 2 | 3 | import guru.springframework.commands.RecipeCommand; 4 | import guru.springframework.domain.Recipe; 5 | 6 | import java.util.Set; 7 | 8 | /** 9 | * Created by jt on 6/13/17. 10 | */ 11 | public interface RecipeService { 12 | 13 | Set getRecipes(); 14 | 15 | Recipe findById(Long l); 16 | 17 | RecipeCommand findCommandById(Long l); 18 | 19 | RecipeCommand saveRecipeCommand(RecipeCommand command); 20 | 21 | void deleteById(Long idToDelete); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/services/RecipeServiceImpl.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.services; 2 | 3 | import guru.springframework.commands.RecipeCommand; 4 | import guru.springframework.converters.RecipeCommandToRecipe; 5 | import guru.springframework.converters.RecipeToRecipeCommand; 6 | import guru.springframework.domain.Recipe; 7 | import guru.springframework.exceptions.NotFoundException; 8 | import guru.springframework.repositories.RecipeRepository; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.transaction.annotation.Transactional; 12 | 13 | import java.util.HashSet; 14 | import java.util.Optional; 15 | import java.util.Set; 16 | 17 | /** 18 | * Created by jt on 6/13/17. 19 | */ 20 | @Slf4j 21 | @Service 22 | public class RecipeServiceImpl implements RecipeService { 23 | 24 | private final RecipeRepository recipeRepository; 25 | private final RecipeCommandToRecipe recipeCommandToRecipe; 26 | private final RecipeToRecipeCommand recipeToRecipeCommand; 27 | 28 | public RecipeServiceImpl(RecipeRepository recipeRepository, RecipeCommandToRecipe recipeCommandToRecipe, RecipeToRecipeCommand recipeToRecipeCommand) { 29 | this.recipeRepository = recipeRepository; 30 | this.recipeCommandToRecipe = recipeCommandToRecipe; 31 | this.recipeToRecipeCommand = recipeToRecipeCommand; 32 | } 33 | 34 | @Override 35 | public Set getRecipes() { 36 | log.debug("I'm in the service"); 37 | 38 | Set recipeSet = new HashSet<>(); 39 | recipeRepository.findAll().iterator().forEachRemaining(recipeSet::add); 40 | return recipeSet; 41 | } 42 | 43 | @Override 44 | public Recipe findById(Long l) { 45 | 46 | Optional recipeOptional = recipeRepository.findById(l); 47 | 48 | if (!recipeOptional.isPresent()) { 49 | throw new NotFoundException("Recipe Not Found. For ID value: " + l.toString() ); 50 | } 51 | 52 | return recipeOptional.get(); 53 | } 54 | 55 | @Override 56 | @Transactional 57 | public RecipeCommand findCommandById(Long l) { 58 | return recipeToRecipeCommand.convert(findById(l)); 59 | } 60 | 61 | @Override 62 | @Transactional 63 | public RecipeCommand saveRecipeCommand(RecipeCommand command) { 64 | Recipe detachedRecipe = recipeCommandToRecipe.convert(command); 65 | 66 | Recipe savedRecipe = recipeRepository.save(detachedRecipe); 67 | log.debug("Saved RecipeId:" + savedRecipe.getId()); 68 | return recipeToRecipeCommand.convert(savedRecipe); 69 | } 70 | 71 | @Override 72 | public void deleteById(Long idToDelete) { 73 | recipeRepository.deleteById(idToDelete); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/services/UnitOfMeasureService.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.services; 2 | 3 | import guru.springframework.commands.UnitOfMeasureCommand; 4 | 5 | import java.util.Set; 6 | 7 | /** 8 | * Created by jt on 6/28/17. 9 | */ 10 | public interface UnitOfMeasureService { 11 | 12 | Set listAllUoms(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/services/UnitOfMeasureServiceImpl.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.services; 2 | 3 | import guru.springframework.commands.UnitOfMeasureCommand; 4 | import guru.springframework.converters.UnitOfMeasureToUnitOfMeasureCommand; 5 | import guru.springframework.repositories.UnitOfMeasureRepository; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.util.Set; 9 | import java.util.stream.Collectors; 10 | import java.util.stream.StreamSupport; 11 | 12 | /** 13 | * Created by jt on 6/28/17. 14 | */ 15 | @Service 16 | public class UnitOfMeasureServiceImpl implements UnitOfMeasureService { 17 | 18 | private final UnitOfMeasureRepository unitOfMeasureRepository; 19 | private final UnitOfMeasureToUnitOfMeasureCommand unitOfMeasureToUnitOfMeasureCommand; 20 | 21 | public UnitOfMeasureServiceImpl(UnitOfMeasureRepository unitOfMeasureRepository, UnitOfMeasureToUnitOfMeasureCommand unitOfMeasureToUnitOfMeasureCommand) { 22 | this.unitOfMeasureRepository = unitOfMeasureRepository; 23 | this.unitOfMeasureToUnitOfMeasureCommand = unitOfMeasureToUnitOfMeasureCommand; 24 | } 25 | 26 | @Override 27 | public Set listAllUoms() { 28 | 29 | return StreamSupport.stream(unitOfMeasureRepository.findAll() 30 | .spliterator(), false) 31 | .map(unitOfMeasureToUnitOfMeasureCommand::convert) 32 | .collect(Collectors.toSet()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | logging.level.guru.springframework=debug -------------------------------------------------------------------------------- /src/main/resources/data.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO category (description) VALUES ('American'); 2 | INSERT INTO category (description) VALUES ('Italian'); 3 | INSERT INTO category (description) VALUES ('Mexican'); 4 | INSERT INTO category (description) VALUES ('Fast Food'); 5 | INSERT INTO unit_of_measure (description) VALUES ('Teaspoon'); 6 | INSERT INTO unit_of_measure (description) VALUES ('Tablespoon'); 7 | INSERT INTO unit_of_measure (description) VALUES ('Cup'); 8 | INSERT INTO unit_of_measure (description) VALUES ('Pinch'); 9 | INSERT INTO unit_of_measure (description) VALUES ('Ounce'); 10 | INSERT INTO unit_of_measure (description) VALUES ('Each'); 11 | INSERT INTO unit_of_measure (description) VALUES ('Dash'); 12 | INSERT INTO unit_of_measure (description) VALUES ('Pint'); -------------------------------------------------------------------------------- /src/main/resources/messages.properties: -------------------------------------------------------------------------------- 1 | # Set names of properties 2 | recipe.description=Description (default) 3 | 4 | #Validaiton Messages 5 | #Order of precedence 6 | # 1 code.objectName.fieldName 7 | # 2 code.fieldName 8 | # 3 code.fieldType (Java data type) 9 | # 4 code 10 | NotBlank.recipe.description=Description Cannot Be Blank 11 | Size.recipe.description={0} must be between {2} and {1} characters long. 12 | Max.recipe.cookTime={0} must be less than {1} 13 | URL.recipe.url=Please provide a valid URL 14 | -------------------------------------------------------------------------------- /src/main/resources/messages_en.properties: -------------------------------------------------------------------------------- 1 | recipe.description=Description (Just - en) -------------------------------------------------------------------------------- /src/main/resources/messages_en_GB.properties: -------------------------------------------------------------------------------- 1 | recipe.description=Description (GB) -------------------------------------------------------------------------------- /src/main/resources/messages_en_US.properties: -------------------------------------------------------------------------------- 1 | recipe.description=Description (US) -------------------------------------------------------------------------------- /src/main/resources/static/images/guacamole400x400.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springframeworkguru/spring5-mysql-recipe-app/bb13e57adfda5836aee3f96534a3d4fcf0fa0303/src/main/resources/static/images/guacamole400x400.jpg -------------------------------------------------------------------------------- /src/main/resources/static/images/guacamole400x400WithX.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springframeworkguru/spring5-mysql-recipe-app/bb13e57adfda5836aee3f96534a3d4fcf0fa0303/src/main/resources/static/images/guacamole400x400WithX.jpg -------------------------------------------------------------------------------- /src/main/resources/static/images/tacos400x400.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springframeworkguru/spring5-mysql-recipe-app/bb13e57adfda5836aee3f96534a3d4fcf0fa0303/src/main/resources/static/images/tacos400x400.jpg -------------------------------------------------------------------------------- /src/main/resources/templates/400error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 404 Not Found Error 6 | 7 | 8 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 |
21 |
22 |
23 |

400 Bad Request

24 |

25 |
26 |
27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /src/main/resources/templates/404error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 404 Not Found Error 6 | 7 | 8 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 |
21 |
22 |
23 |

404 Not Found

24 |

25 |
26 |
27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Recipe Home 6 | 7 | 8 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 | 22 |
23 |
24 |
25 |
26 | 27 |
28 |

My Recipes!

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 | 59 |
IDDescriptionViewUpdateDelete
123Tasty Goodnees 1View
12333Tasty Goodnees 2View
334Tasty Goodnees 3ViewUpdateDelete
60 |
61 |
62 |
63 |
64 |
65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /src/main/resources/templates/recipe/imageuploadform.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Image Upload Form 6 | 7 | 8 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 |
22 |
23 |
24 |
25 |
26 |
27 |

Upload a new recipe image

28 |
29 |
30 |
31 |
32 |
34 | 35 | 36 | 37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | 47 | -------------------------------------------------------------------------------- /src/main/resources/templates/recipe/ingredient/ingredientform.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Edit Ingredient 6 | 7 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | 19 | 20 |
21 |
22 |
23 | 24 |
25 | 26 |
27 |
28 |
29 |

Edit Ingredient Information

30 |
31 |
32 | 33 | 34 |
35 |
36 | 37 | 38 |
39 | 40 |
41 | 42 | 43 |
44 | 45 |
46 | 47 | 53 |
54 |
55 |
56 |
57 | 58 |
59 |
60 |
61 |
62 |
63 | 64 | -------------------------------------------------------------------------------- /src/main/resources/templates/recipe/ingredient/list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | List Ingredients 6 | 7 | 8 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 | 22 |
23 |
24 |
25 |
26 | 27 |
28 |
29 |
30 |

Ingredients

31 |
32 |
33 | New 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 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 |
IDDescriptionViewUpdateDelete
123Tasty Goodnees 1ViewUpdateDelete
12333Tasty Goodnees 2ViewUpdateDelete
334Tasty Goodnees 3ViewUpdateDelete
73 |
74 |
75 |
76 |
77 |
78 |
79 | 80 | -------------------------------------------------------------------------------- /src/main/resources/templates/recipe/ingredient/show.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | View Ingredient 6 | 7 | 8 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 |
22 |
23 |
24 |
25 | 26 |
27 |

Ingredient

28 |
29 |
30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
IDDescription
12333Tasty Goodnees 2ViewUpdateDelete
334Tasty Goodnees 3
51 |
52 |
53 |
54 |
55 |
56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /src/main/resources/templates/recipe/recipeform.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Recipe Form 6 | 7 | 8 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 |
22 |
23 |
24 |
25 | 26 |
27 |

Please Correct Errors Below

28 |
29 | 30 | 31 |
32 |
33 |
34 |

Edit Recipe Information

35 |
36 |
37 |
38 |
40 | 41 | 42 | 43 |
    44 |
  • 45 |
46 |
47 |
48 |
49 |
50 |
51 | 52 |
53 |
54 |
55 | 59 |
60 |
61 | 65 |
66 |
67 |
68 |
69 |
71 | 72 | 73 | 74 |
    75 |
  • 76 |
77 |
78 |
79 |
81 | 82 | 83 | 84 |
    85 |
  • 86 |
87 |
88 |
89 |
90 | 91 | 98 | 103 |
104 |
105 |
106 |
108 | 109 | 110 | 111 |
    112 |
  • 113 |
114 |
115 |
116 |
117 | 118 | 119 |
120 |
122 | 123 | 124 | 125 |
    126 |
  • 127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |

Ingredients

138 |
139 |
140 | View 142 |
143 |
144 |
145 |
146 |
147 |
148 |
    149 |
  • 1 Cup of milk
  • 150 |
  • 1 Teaspoon of chocolate
  • 151 |
  • asdf
  • 152 |
  • 1 Teaspoon of Sugar 156 |
  • 157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |

Directions

165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |

Notes

176 |
177 |
178 |
179 |
180 | 181 |
182 |
183 |
184 |
185 | 186 |
187 |
188 |
189 |
190 |
191 | 192 | -------------------------------------------------------------------------------- /src/main/resources/templates/recipe/show.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Show Recipe 6 | 7 | 8 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |

Recipe Description Here!

30 |
31 | 32 |
33 | Change Image 35 |
36 |
37 |
38 |
39 |
40 |
41 |
Categories:
42 |
43 |
44 |
    45 |
  • cat one
  • 46 |
  • cat two
  • 47 |
  • cat three 49 |
  • 50 |
51 |
52 |
53 | 56 |
57 |
58 |
59 |
60 |
Prep Time:
61 |
62 |
63 |

30 min

64 |
65 |
66 |
Difficulty:
67 |
68 |
69 |

Easy

70 |
71 |
72 |
73 |
74 |
Cooktime:
75 |
76 |
77 |

30 min

78 |
79 |
80 |
Servings:
81 |
82 |
83 |

4

84 |
85 |
86 |
87 |
88 |
Source:
89 |
90 |
91 |

30 min

92 |
93 |
94 |
URL:
95 |
96 |
97 |

View Original

98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |

Ingredients

107 |
108 |
109 | View 111 |
112 |
113 |
114 |
115 |
116 |
117 |
    118 |
  • 1 Cup of milk
  • 119 |
  • 1 Teaspoon of chocolate
  • 120 |
  • 1 Teaspoon of Sugar 124 |
  • 125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |

Directions

133 |
134 |
135 |
136 |
137 |

Lorem ipsum dolor sit amet, consectetuer adipiscing 138 | elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus 139 | et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies 140 | nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede 141 | justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, 142 | imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. 143 | Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate 144 | eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, 145 | enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus 146 | viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam 147 | ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam 148 | rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, 149 | sit amet adipiscing sem neque sed ipsum.

150 |
151 |
152 |
153 |
154 |
155 |
156 |

Notes

157 |
158 |
159 |
160 |
161 |

Lorem ipsum dolor sit amet, consectetuer 162 | adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque 163 | penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, 164 | ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. 165 | Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, 166 | rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis 167 | pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean 168 | vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, 169 | eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. 170 | Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. 171 | Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. 172 | Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper 173 | libero, sit amet adipiscing sem neque sed ipsum.

174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 | 183 | -------------------------------------------------------------------------------- /src/main/scripts/README.md: -------------------------------------------------------------------------------- 1 | # Scripts Directory 2 | This directory will contain SQL Migration Scripts -------------------------------------------------------------------------------- /src/test/java/guru/springframework/Spring5RecipeAppApplicationTests.java: -------------------------------------------------------------------------------- 1 | package guru.springframework; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class Spring5RecipeAppApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/guru/springframework/controllers/ImageControllerTest.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.controllers; 2 | 3 | import guru.springframework.commands.RecipeCommand; 4 | import guru.springframework.services.ImageService; 5 | import guru.springframework.services.RecipeService; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | import org.mockito.Mock; 9 | import org.mockito.MockitoAnnotations; 10 | import org.springframework.mock.web.MockHttpServletResponse; 11 | import org.springframework.mock.web.MockMultipartFile; 12 | import org.springframework.test.web.servlet.MockMvc; 13 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 14 | 15 | import static org.junit.Assert.assertEquals; 16 | import static org.mockito.Mockito.*; 17 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 18 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; 19 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; 20 | 21 | public class ImageControllerTest { 22 | 23 | @Mock 24 | ImageService imageService; 25 | 26 | @Mock 27 | RecipeService recipeService; 28 | 29 | ImageController controller; 30 | 31 | MockMvc mockMvc; 32 | 33 | @Before 34 | public void setUp() throws Exception { 35 | MockitoAnnotations.initMocks(this); 36 | 37 | controller = new ImageController(imageService, recipeService); 38 | mockMvc = MockMvcBuilders.standaloneSetup(controller) 39 | .setControllerAdvice(new ControllerExceptionHandler()) 40 | .build(); 41 | } 42 | 43 | @Test 44 | public void getImageForm() throws Exception { 45 | //given 46 | RecipeCommand command = new RecipeCommand(); 47 | command.setId(1L); 48 | 49 | when(recipeService.findCommandById(anyLong())).thenReturn(command); 50 | 51 | //when 52 | mockMvc.perform(get("/recipe/1/image")) 53 | .andExpect(status().isOk()) 54 | .andExpect(model().attributeExists("recipe")); 55 | 56 | verify(recipeService, times(1)).findCommandById(anyLong()); 57 | 58 | } 59 | 60 | @Test 61 | public void handleImagePost() throws Exception { 62 | MockMultipartFile multipartFile = 63 | new MockMultipartFile("imagefile", "testing.txt", "text/plain", 64 | "Spring Framework Guru".getBytes()); 65 | 66 | mockMvc.perform(multipart("/recipe/1/image").file(multipartFile)) 67 | .andExpect(status().is3xxRedirection()) 68 | .andExpect(header().string("Location", "/recipe/1/show")); 69 | 70 | verify(imageService, times(1)).saveImageFile(anyLong(), any()); 71 | } 72 | 73 | 74 | @Test 75 | public void renderImageFromDB() throws Exception { 76 | 77 | //given 78 | RecipeCommand command = new RecipeCommand(); 79 | command.setId(1L); 80 | 81 | String s = "fake image text"; 82 | Byte[] bytesBoxed = new Byte[s.getBytes().length]; 83 | 84 | int i = 0; 85 | 86 | for (byte primByte : s.getBytes()){ 87 | bytesBoxed[i++] = primByte; 88 | } 89 | 90 | command.setImage(bytesBoxed); 91 | 92 | when(recipeService.findCommandById(anyLong())).thenReturn(command); 93 | 94 | //when 95 | MockHttpServletResponse response = mockMvc.perform(get("/recipe/1/recipeimage")) 96 | .andExpect(status().isOk()) 97 | .andReturn().getResponse(); 98 | 99 | byte[] reponseBytes = response.getContentAsByteArray(); 100 | 101 | assertEquals(s.getBytes().length, reponseBytes.length); 102 | } 103 | 104 | @Test 105 | public void testGetImageNumberFormatException() throws Exception { 106 | 107 | mockMvc.perform(get("/recipe/asdf/recipeimage")) 108 | .andExpect(status().isBadRequest()) 109 | .andExpect(view().name("400error")); 110 | } 111 | } -------------------------------------------------------------------------------- /src/test/java/guru/springframework/controllers/IndexControllerTest.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.controllers; 2 | 3 | import guru.springframework.domain.Recipe; 4 | import guru.springframework.services.RecipeService; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | import org.mockito.ArgumentCaptor; 8 | import org.mockito.Mock; 9 | import org.mockito.MockitoAnnotations; 10 | import org.springframework.test.web.servlet.MockMvc; 11 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 12 | import org.springframework.ui.Model; 13 | 14 | import java.util.HashSet; 15 | import java.util.Set; 16 | 17 | import static org.junit.Assert.assertEquals; 18 | import static org.mockito.Mockito.*; 19 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 20 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 21 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; 22 | 23 | /** 24 | * Created by jt on 6/17/17. 25 | */ 26 | public class IndexControllerTest { 27 | 28 | @Mock 29 | RecipeService recipeService; 30 | 31 | @Mock 32 | Model model; 33 | 34 | IndexController controller; 35 | 36 | @Before 37 | public void setUp() throws Exception { 38 | MockitoAnnotations.initMocks(this); 39 | 40 | controller = new IndexController(recipeService); 41 | } 42 | 43 | @Test 44 | public void testMockMVC() throws Exception { 45 | MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); 46 | 47 | mockMvc.perform(get("/")) 48 | .andExpect(status().isOk()) 49 | .andExpect(view().name("index")); 50 | } 51 | 52 | @Test 53 | public void getIndexPage() throws Exception { 54 | 55 | //given 56 | Set recipes = new HashSet<>(); 57 | recipes.add(new Recipe()); 58 | 59 | Recipe recipe = new Recipe(); 60 | recipe.setId(1L); 61 | 62 | recipes.add(recipe); 63 | 64 | when(recipeService.getRecipes()).thenReturn(recipes); 65 | 66 | ArgumentCaptor> argumentCaptor = ArgumentCaptor.forClass(Set.class); 67 | 68 | //when 69 | String viewName = controller.getIndexPage(model); 70 | 71 | 72 | //then 73 | assertEquals("index", viewName); 74 | verify(recipeService, times(1)).getRecipes(); 75 | verify(model, times(1)).addAttribute(eq("recipes"), argumentCaptor.capture()); 76 | Set setInController = argumentCaptor.getValue(); 77 | assertEquals(2, setInController.size()); 78 | } 79 | 80 | } -------------------------------------------------------------------------------- /src/test/java/guru/springframework/controllers/IngredientControllerTest.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.controllers; 2 | 3 | import guru.springframework.commands.IngredientCommand; 4 | import guru.springframework.commands.RecipeCommand; 5 | import guru.springframework.services.IngredientService; 6 | import guru.springframework.services.RecipeService; 7 | import guru.springframework.services.UnitOfMeasureService; 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | import org.mockito.Mock; 11 | import org.mockito.MockitoAnnotations; 12 | import org.springframework.http.MediaType; 13 | import org.springframework.test.web.servlet.MockMvc; 14 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 15 | 16 | import java.util.HashSet; 17 | 18 | import static org.mockito.ArgumentMatchers.anyLong; 19 | import static org.mockito.Mockito.*; 20 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 21 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; 22 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; 23 | 24 | public class IngredientControllerTest { 25 | 26 | @Mock 27 | IngredientService ingredientService; 28 | 29 | @Mock 30 | UnitOfMeasureService unitOfMeasureService; 31 | 32 | @Mock 33 | RecipeService recipeService; 34 | 35 | IngredientController controller; 36 | 37 | MockMvc mockMvc; 38 | 39 | @Before 40 | public void setUp() throws Exception { 41 | MockitoAnnotations.initMocks(this); 42 | 43 | controller = new IngredientController(ingredientService, recipeService, unitOfMeasureService); 44 | mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); 45 | } 46 | 47 | @Test 48 | public void testListIngredients() throws Exception { 49 | //given 50 | RecipeCommand recipeCommand = new RecipeCommand(); 51 | when(recipeService.findCommandById(anyLong())).thenReturn(recipeCommand); 52 | 53 | //when 54 | mockMvc.perform(get("/recipe/1/ingredients")) 55 | .andExpect(status().isOk()) 56 | .andExpect(view().name("recipe/ingredient/list")) 57 | .andExpect(model().attributeExists("recipe")); 58 | 59 | //then 60 | verify(recipeService, times(1)).findCommandById(anyLong()); 61 | } 62 | 63 | @Test 64 | public void testShowIngredient() throws Exception { 65 | //given 66 | IngredientCommand ingredientCommand = new IngredientCommand(); 67 | 68 | //when 69 | when(ingredientService.findByRecipeIdAndIngredientId(anyLong(), anyLong())).thenReturn(ingredientCommand); 70 | 71 | //then 72 | mockMvc.perform(get("/recipe/1/ingredient/2/show")) 73 | .andExpect(status().isOk()) 74 | .andExpect(view().name("recipe/ingredient/show")) 75 | .andExpect(model().attributeExists("ingredient")); 76 | } 77 | 78 | @Test 79 | public void testNewIngredientForm() throws Exception { 80 | //given 81 | RecipeCommand recipeCommand = new RecipeCommand(); 82 | recipeCommand.setId(1L); 83 | 84 | //when 85 | when(recipeService.findCommandById(anyLong())).thenReturn(recipeCommand); 86 | when(unitOfMeasureService.listAllUoms()).thenReturn(new HashSet<>()); 87 | 88 | //then 89 | mockMvc.perform(get("/recipe/1/ingredient/new")) 90 | .andExpect(status().isOk()) 91 | .andExpect(view().name("recipe/ingredient/ingredientform")) 92 | .andExpect(model().attributeExists("ingredient")) 93 | .andExpect(model().attributeExists("uomList")); 94 | 95 | verify(recipeService, times(1)).findCommandById(anyLong()); 96 | 97 | } 98 | 99 | @Test 100 | public void testUpdateIngredientForm() throws Exception { 101 | //given 102 | IngredientCommand ingredientCommand = new IngredientCommand(); 103 | 104 | //when 105 | when(ingredientService.findByRecipeIdAndIngredientId(anyLong(), anyLong())).thenReturn(ingredientCommand); 106 | when(unitOfMeasureService.listAllUoms()).thenReturn(new HashSet<>()); 107 | 108 | //then 109 | mockMvc.perform(get("/recipe/1/ingredient/2/update")) 110 | .andExpect(status().isOk()) 111 | .andExpect(view().name("recipe/ingredient/ingredientform")) 112 | .andExpect(model().attributeExists("ingredient")) 113 | .andExpect(model().attributeExists("uomList")); 114 | } 115 | 116 | @Test 117 | public void testSaveOrUpdate() throws Exception { 118 | //given 119 | IngredientCommand command = new IngredientCommand(); 120 | command.setId(3L); 121 | command.setRecipeId(2L); 122 | 123 | //when 124 | when(ingredientService.saveIngredientCommand(any())).thenReturn(command); 125 | 126 | //then 127 | mockMvc.perform(post("/recipe/2/ingredient") 128 | .contentType(MediaType.APPLICATION_FORM_URLENCODED) 129 | .param("id", "") 130 | .param("description", "some string") 131 | ) 132 | .andExpect(status().is3xxRedirection()) 133 | .andExpect(view().name("redirect:/recipe/2/ingredient/3/show")); 134 | 135 | } 136 | 137 | @Test 138 | public void testDeleteIngredient() throws Exception { 139 | 140 | //then 141 | mockMvc.perform(get("/recipe/2/ingredient/3/delete") 142 | ) 143 | .andExpect(status().is3xxRedirection()) 144 | .andExpect(view().name("redirect:/recipe/2/ingredients")); 145 | 146 | verify(ingredientService, times(1)).deleteById(anyLong(), anyLong()); 147 | 148 | } 149 | } -------------------------------------------------------------------------------- /src/test/java/guru/springframework/controllers/RecipeControllerTest.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.controllers; 2 | 3 | import guru.springframework.commands.RecipeCommand; 4 | import guru.springframework.domain.Recipe; 5 | import guru.springframework.exceptions.NotFoundException; 6 | import guru.springframework.services.RecipeService; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | import org.mockito.Mock; 10 | import org.mockito.MockitoAnnotations; 11 | import org.springframework.http.MediaType; 12 | import org.springframework.test.web.servlet.MockMvc; 13 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 14 | 15 | import static org.mockito.ArgumentMatchers.any; 16 | import static org.mockito.ArgumentMatchers.anyLong; 17 | import static org.mockito.Mockito.*; 18 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 19 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; 20 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; 21 | 22 | /** 23 | * Created by jt on 6/19/17. 24 | */ 25 | public class RecipeControllerTest { 26 | 27 | @Mock 28 | RecipeService recipeService; 29 | 30 | RecipeController controller; 31 | 32 | MockMvc mockMvc; 33 | 34 | @Before 35 | public void setUp() throws Exception { 36 | MockitoAnnotations.initMocks(this); 37 | 38 | controller = new RecipeController(recipeService); 39 | mockMvc = MockMvcBuilders.standaloneSetup(controller) 40 | .setControllerAdvice(new ControllerExceptionHandler()) 41 | .build(); 42 | } 43 | 44 | @Test 45 | public void testGetRecipe() throws Exception { 46 | 47 | Recipe recipe = new Recipe(); 48 | recipe.setId(1L); 49 | 50 | when(recipeService.findById(anyLong())).thenReturn(recipe); 51 | 52 | mockMvc.perform(get("/recipe/1/show")) 53 | .andExpect(status().isOk()) 54 | .andExpect(view().name("recipe/show")) 55 | .andExpect(model().attributeExists("recipe")); 56 | } 57 | 58 | @Test 59 | public void testGetRecipeNotFound() throws Exception { 60 | 61 | when(recipeService.findById(anyLong())).thenThrow(NotFoundException.class); 62 | 63 | mockMvc.perform(get("/recipe/1/show")) 64 | .andExpect(status().isNotFound()) 65 | .andExpect(view().name("404error")); 66 | } 67 | 68 | @Test 69 | public void testGetRecipeNumberFormatException() throws Exception { 70 | 71 | mockMvc.perform(get("/recipe/asdf/show")) 72 | .andExpect(status().isBadRequest()) 73 | .andExpect(view().name("400error")); 74 | } 75 | 76 | @Test 77 | public void testGetNewRecipeForm() throws Exception { 78 | RecipeCommand command = new RecipeCommand(); 79 | 80 | mockMvc.perform(get("/recipe/new")) 81 | .andExpect(status().isOk()) 82 | .andExpect(view().name("recipe/recipeform")) 83 | .andExpect(model().attributeExists("recipe")); 84 | } 85 | 86 | @Test 87 | public void testPostNewRecipeForm() throws Exception { 88 | RecipeCommand command = new RecipeCommand(); 89 | command.setId(2L); 90 | 91 | when(recipeService.saveRecipeCommand(any())).thenReturn(command); 92 | 93 | mockMvc.perform(post("/recipe") 94 | .contentType(MediaType.APPLICATION_FORM_URLENCODED) 95 | .param("id", "") 96 | .param("description", "some string") 97 | .param("directions", "some directions") 98 | ) 99 | .andExpect(status().is3xxRedirection()) 100 | .andExpect(view().name("redirect:/recipe/2/show")); 101 | } 102 | 103 | @Test 104 | public void testPostNewRecipeFormValidationFail() throws Exception { 105 | RecipeCommand command = new RecipeCommand(); 106 | command.setId(2L); 107 | 108 | when(recipeService.saveRecipeCommand(any())).thenReturn(command); 109 | 110 | mockMvc.perform(post("/recipe") 111 | .contentType(MediaType.APPLICATION_FORM_URLENCODED) 112 | .param("id", "") 113 | .param("cookTime", "3000") 114 | 115 | ) 116 | .andExpect(status().isOk()) 117 | .andExpect(model().attributeExists("recipe")) 118 | .andExpect(view().name("recipe/recipeform")); 119 | } 120 | 121 | @Test 122 | public void testGetUpdateView() throws Exception { 123 | RecipeCommand command = new RecipeCommand(); 124 | command.setId(2L); 125 | 126 | when(recipeService.findCommandById(anyLong())).thenReturn(command); 127 | 128 | mockMvc.perform(get("/recipe/1/update")) 129 | .andExpect(status().isOk()) 130 | .andExpect(view().name("recipe/recipeform")) 131 | .andExpect(model().attributeExists("recipe")); 132 | } 133 | 134 | @Test 135 | public void testDeleteAction() throws Exception { 136 | mockMvc.perform(get("/recipe/1/delete")) 137 | .andExpect(status().is3xxRedirection()) 138 | .andExpect(view().name("redirect:/")); 139 | 140 | verify(recipeService, times(1)).deleteById(anyLong()); 141 | } 142 | } -------------------------------------------------------------------------------- /src/test/java/guru/springframework/converters/CategoryCommandToCategoryTest.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.converters; 2 | 3 | import guru.springframework.commands.CategoryCommand; 4 | import guru.springframework.domain.Category; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | public class CategoryCommandToCategoryTest { 11 | 12 | public static final Long ID_VALUE = new Long(1L); 13 | public static final String DESCRIPTION = "description"; 14 | CategoryCommandToCategory conveter; 15 | 16 | @Before 17 | public void setUp() throws Exception { 18 | conveter = new CategoryCommandToCategory(); 19 | } 20 | 21 | @Test 22 | public void testNullObject() throws Exception { 23 | assertNull(conveter.convert(null)); 24 | } 25 | 26 | @Test 27 | public void testEmptyObject() throws Exception { 28 | assertNotNull(conveter.convert(new CategoryCommand())); 29 | } 30 | 31 | @Test 32 | public void convert() throws Exception { 33 | //given 34 | CategoryCommand categoryCommand = new CategoryCommand(); 35 | categoryCommand.setId(ID_VALUE); 36 | categoryCommand.setDescription(DESCRIPTION); 37 | 38 | //when 39 | Category category = conveter.convert(categoryCommand); 40 | 41 | //then 42 | assertEquals(ID_VALUE, category.getId()); 43 | assertEquals(DESCRIPTION, category.getDescription()); 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /src/test/java/guru/springframework/converters/CategoryToCategoryCommandTest.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.converters; 2 | 3 | import guru.springframework.commands.CategoryCommand; 4 | import guru.springframework.domain.Category; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | /** 11 | * Created by jt on 6/21/17. 12 | */ 13 | public class CategoryToCategoryCommandTest { 14 | 15 | public static final Long ID_VALUE = new Long(1L); 16 | public static final String DESCRIPTION = "descript"; 17 | CategoryToCategoryCommand convter; 18 | 19 | @Before 20 | public void setUp() throws Exception { 21 | convter = new CategoryToCategoryCommand(); 22 | } 23 | 24 | @Test 25 | public void testNullObject() throws Exception { 26 | assertNull(convter.convert(null)); 27 | } 28 | 29 | @Test 30 | public void testEmptyObject() throws Exception { 31 | assertNotNull(convter.convert(new Category())); 32 | } 33 | 34 | @Test 35 | public void convert() throws Exception { 36 | //given 37 | Category category = new Category(); 38 | category.setId(ID_VALUE); 39 | category.setDescription(DESCRIPTION); 40 | 41 | //when 42 | CategoryCommand categoryCommand = convter.convert(category); 43 | 44 | //then 45 | assertEquals(ID_VALUE, categoryCommand.getId()); 46 | assertEquals(DESCRIPTION, categoryCommand.getDescription()); 47 | 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /src/test/java/guru/springframework/converters/IngredientCommandToIngredientTest.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.converters; 2 | 3 | import guru.springframework.commands.IngredientCommand; 4 | import guru.springframework.commands.UnitOfMeasureCommand; 5 | import guru.springframework.domain.Ingredient; 6 | import guru.springframework.domain.Recipe; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import java.math.BigDecimal; 11 | 12 | import static org.junit.Assert.*; 13 | 14 | public class IngredientCommandToIngredientTest { 15 | 16 | public static final Recipe RECIPE = new Recipe(); 17 | public static final BigDecimal AMOUNT = new BigDecimal("1"); 18 | public static final String DESCRIPTION = "Cheeseburger"; 19 | public static final Long ID_VALUE = new Long(1L); 20 | public static final Long UOM_ID = new Long(2L); 21 | 22 | IngredientCommandToIngredient converter; 23 | 24 | @Before 25 | public void setUp() throws Exception { 26 | converter = new IngredientCommandToIngredient(new UnitOfMeasureCommandToUnitOfMeasure()); 27 | } 28 | 29 | @Test 30 | public void testNullObject() throws Exception { 31 | assertNull(converter.convert(null)); 32 | } 33 | 34 | @Test 35 | public void testEmptyObject() throws Exception { 36 | assertNotNull(converter.convert(new IngredientCommand())); 37 | } 38 | 39 | @Test 40 | public void convert() throws Exception { 41 | //given 42 | IngredientCommand command = new IngredientCommand(); 43 | command.setId(ID_VALUE); 44 | command.setAmount(AMOUNT); 45 | command.setDescription(DESCRIPTION); 46 | UnitOfMeasureCommand unitOfMeasureCommand = new UnitOfMeasureCommand(); 47 | unitOfMeasureCommand.setId(UOM_ID); 48 | command.setUom(unitOfMeasureCommand); 49 | 50 | //when 51 | Ingredient ingredient = converter.convert(command); 52 | 53 | //then 54 | assertNotNull(ingredient); 55 | assertNotNull(ingredient.getUom()); 56 | assertEquals(ID_VALUE, ingredient.getId()); 57 | assertEquals(AMOUNT, ingredient.getAmount()); 58 | assertEquals(DESCRIPTION, ingredient.getDescription()); 59 | assertEquals(UOM_ID, ingredient.getUom().getId()); 60 | } 61 | 62 | @Test 63 | public void convertWithNullUOM() throws Exception { 64 | //given 65 | IngredientCommand command = new IngredientCommand(); 66 | command.setId(ID_VALUE); 67 | command.setAmount(AMOUNT); 68 | command.setDescription(DESCRIPTION); 69 | UnitOfMeasureCommand unitOfMeasureCommand = new UnitOfMeasureCommand(); 70 | 71 | 72 | //when 73 | Ingredient ingredient = converter.convert(command); 74 | 75 | //then 76 | assertNotNull(ingredient); 77 | assertNull(ingredient.getUom()); 78 | assertEquals(ID_VALUE, ingredient.getId()); 79 | assertEquals(AMOUNT, ingredient.getAmount()); 80 | assertEquals(DESCRIPTION, ingredient.getDescription()); 81 | } 82 | 83 | } -------------------------------------------------------------------------------- /src/test/java/guru/springframework/converters/IngredientToIngredientCommandTest.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.converters; 2 | 3 | import guru.springframework.commands.IngredientCommand; 4 | import guru.springframework.domain.Ingredient; 5 | import guru.springframework.domain.Recipe; 6 | import guru.springframework.domain.UnitOfMeasure; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import java.math.BigDecimal; 11 | 12 | import static org.junit.Assert.*; 13 | 14 | /** 15 | * Created by jt on 6/21/17. 16 | */ 17 | public class IngredientToIngredientCommandTest { 18 | 19 | public static final Recipe RECIPE = new Recipe(); 20 | public static final BigDecimal AMOUNT = new BigDecimal("1"); 21 | public static final String DESCRIPTION = "Cheeseburger"; 22 | public static final Long UOM_ID = new Long(2L); 23 | public static final Long ID_VALUE = new Long(1L); 24 | 25 | 26 | IngredientToIngredientCommand converter; 27 | 28 | @Before 29 | public void setUp() throws Exception { 30 | converter = new IngredientToIngredientCommand(new UnitOfMeasureToUnitOfMeasureCommand()); 31 | } 32 | 33 | @Test 34 | public void testNullConvert() throws Exception { 35 | assertNull(converter.convert(null)); 36 | } 37 | 38 | @Test 39 | public void testEmptyObject() throws Exception { 40 | assertNotNull(converter.convert(new Ingredient())); 41 | } 42 | 43 | @Test 44 | public void testConvertNullUOM() throws Exception { 45 | //given 46 | Ingredient ingredient = new Ingredient(); 47 | ingredient.setId(ID_VALUE); 48 | ingredient.setRecipe(RECIPE); 49 | ingredient.setAmount(AMOUNT); 50 | ingredient.setDescription(DESCRIPTION); 51 | ingredient.setUom(null); 52 | //when 53 | IngredientCommand ingredientCommand = converter.convert(ingredient); 54 | //then 55 | assertNull(ingredientCommand.getUom()); 56 | assertEquals(ID_VALUE, ingredientCommand.getId()); 57 | assertEquals(AMOUNT, ingredientCommand.getAmount()); 58 | assertEquals(DESCRIPTION, ingredientCommand.getDescription()); 59 | } 60 | 61 | @Test 62 | public void testConvertWithUom() throws Exception { 63 | //given 64 | Ingredient ingredient = new Ingredient(); 65 | ingredient.setId(ID_VALUE); 66 | ingredient.setRecipe(RECIPE); 67 | ingredient.setAmount(AMOUNT); 68 | ingredient.setDescription(DESCRIPTION); 69 | 70 | UnitOfMeasure uom = new UnitOfMeasure(); 71 | uom.setId(UOM_ID); 72 | 73 | ingredient.setUom(uom); 74 | //when 75 | IngredientCommand ingredientCommand = converter.convert(ingredient); 76 | //then 77 | assertEquals(ID_VALUE, ingredientCommand.getId()); 78 | assertNotNull(ingredientCommand.getUom()); 79 | assertEquals(UOM_ID, ingredientCommand.getUom().getId()); 80 | // assertEquals(RECIPE, ingredientCommand.get); 81 | assertEquals(AMOUNT, ingredientCommand.getAmount()); 82 | assertEquals(DESCRIPTION, ingredientCommand.getDescription()); 83 | } 84 | } -------------------------------------------------------------------------------- /src/test/java/guru/springframework/converters/NotesCommandToNotesTest.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.converters; 2 | 3 | import guru.springframework.commands.NotesCommand; 4 | import guru.springframework.domain.Notes; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | public class NotesCommandToNotesTest { 11 | 12 | public static final Long ID_VALUE = new Long(1L); 13 | public static final String RECIPE_NOTES = "Notes"; 14 | NotesCommandToNotes converter; 15 | 16 | @Before 17 | public void setUp() throws Exception { 18 | converter = new NotesCommandToNotes(); 19 | 20 | } 21 | 22 | @Test 23 | public void testNullParameter() throws Exception { 24 | assertNull(converter.convert(null)); 25 | } 26 | 27 | @Test 28 | public void testEmptyObject() throws Exception { 29 | assertNotNull(converter.convert(new NotesCommand())); 30 | } 31 | 32 | @Test 33 | public void convert() throws Exception { 34 | //given 35 | NotesCommand notesCommand = new NotesCommand(); 36 | notesCommand.setId(ID_VALUE); 37 | notesCommand.setRecipeNotes(RECIPE_NOTES); 38 | 39 | //when 40 | Notes notes = converter.convert(notesCommand); 41 | 42 | //then 43 | assertNotNull(notes); 44 | assertEquals(ID_VALUE, notes.getId()); 45 | assertEquals(RECIPE_NOTES, notes.getRecipeNotes()); 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /src/test/java/guru/springframework/converters/NotesToNotesCommandTest.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.converters; 2 | 3 | import guru.springframework.commands.NotesCommand; 4 | import guru.springframework.domain.Notes; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | /** 11 | * Created by jt on 6/21/17. 12 | */ 13 | public class NotesToNotesCommandTest { 14 | 15 | public static final Long ID_VALUE = new Long(1L); 16 | public static final String RECIPE_NOTES = "Notes"; 17 | NotesToNotesCommand converter; 18 | 19 | @Before 20 | public void setUp() throws Exception { 21 | converter = new NotesToNotesCommand(); 22 | } 23 | 24 | @Test 25 | public void convert() throws Exception { 26 | //given 27 | Notes notes = new Notes(); 28 | notes.setId(ID_VALUE); 29 | notes.setRecipeNotes(RECIPE_NOTES); 30 | 31 | //when 32 | NotesCommand notesCommand = converter.convert(notes); 33 | 34 | //then 35 | assertEquals(ID_VALUE, notesCommand.getId()); 36 | assertEquals(RECIPE_NOTES, notesCommand.getRecipeNotes()); 37 | } 38 | 39 | @Test 40 | public void testNull() throws Exception { 41 | assertNull(converter.convert(null)); 42 | } 43 | 44 | @Test 45 | public void testEmptyObject() throws Exception { 46 | assertNotNull(converter.convert(new Notes())); 47 | } 48 | } -------------------------------------------------------------------------------- /src/test/java/guru/springframework/converters/RecipeCommandToRecipeTest.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.converters; 2 | 3 | import guru.springframework.commands.CategoryCommand; 4 | import guru.springframework.commands.IngredientCommand; 5 | import guru.springframework.commands.NotesCommand; 6 | import guru.springframework.commands.RecipeCommand; 7 | import guru.springframework.domain.Difficulty; 8 | import guru.springframework.domain.Recipe; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | import static org.junit.Assert.*; 13 | 14 | public class RecipeCommandToRecipeTest { 15 | public static final Long RECIPE_ID = 1L; 16 | public static final Integer COOK_TIME = Integer.valueOf("5"); 17 | public static final Integer PREP_TIME = Integer.valueOf("7"); 18 | public static final String DESCRIPTION = "My Recipe"; 19 | public static final String DIRECTIONS = "Directions"; 20 | public static final Difficulty DIFFICULTY = Difficulty.EASY; 21 | public static final Integer SERVINGS = Integer.valueOf("3"); 22 | public static final String SOURCE = "Source"; 23 | public static final String URL = "Some URL"; 24 | public static final Long CAT_ID_1 = 1L; 25 | public static final Long CAT_ID2 = 2L; 26 | public static final Long INGRED_ID_1 = 3L; 27 | public static final Long INGRED_ID_2 = 4L; 28 | public static final Long NOTES_ID = 9L; 29 | 30 | RecipeCommandToRecipe converter; 31 | 32 | 33 | @Before 34 | public void setUp() throws Exception { 35 | converter = new RecipeCommandToRecipe(new CategoryCommandToCategory(), 36 | new IngredientCommandToIngredient(new UnitOfMeasureCommandToUnitOfMeasure()), 37 | new NotesCommandToNotes()); 38 | } 39 | 40 | @Test 41 | public void testNullObject() throws Exception { 42 | assertNull(converter.convert(null)); 43 | } 44 | 45 | @Test 46 | public void testEmptyObject() throws Exception { 47 | assertNotNull(converter.convert(new RecipeCommand())); 48 | } 49 | 50 | @Test 51 | public void convert() throws Exception { 52 | //given 53 | RecipeCommand recipeCommand = new RecipeCommand(); 54 | recipeCommand.setId(RECIPE_ID); 55 | recipeCommand.setCookTime(COOK_TIME); 56 | recipeCommand.setPrepTime(PREP_TIME); 57 | recipeCommand.setDescription(DESCRIPTION); 58 | recipeCommand.setDifficulty(DIFFICULTY); 59 | recipeCommand.setDirections(DIRECTIONS); 60 | recipeCommand.setServings(SERVINGS); 61 | recipeCommand.setSource(SOURCE); 62 | recipeCommand.setUrl(URL); 63 | 64 | NotesCommand notes = new NotesCommand(); 65 | notes.setId(NOTES_ID); 66 | 67 | recipeCommand.setNotes(notes); 68 | 69 | CategoryCommand category = new CategoryCommand(); 70 | category.setId(CAT_ID_1); 71 | 72 | CategoryCommand category2 = new CategoryCommand(); 73 | category2.setId(CAT_ID2); 74 | 75 | recipeCommand.getCategories().add(category); 76 | recipeCommand.getCategories().add(category2); 77 | 78 | IngredientCommand ingredient = new IngredientCommand(); 79 | ingredient.setId(INGRED_ID_1); 80 | 81 | IngredientCommand ingredient2 = new IngredientCommand(); 82 | ingredient2.setId(INGRED_ID_2); 83 | 84 | recipeCommand.getIngredients().add(ingredient); 85 | recipeCommand.getIngredients().add(ingredient2); 86 | 87 | //when 88 | Recipe recipe = converter.convert(recipeCommand); 89 | 90 | assertNotNull(recipe); 91 | assertEquals(RECIPE_ID, recipe.getId()); 92 | assertEquals(COOK_TIME, recipe.getCookTime()); 93 | assertEquals(PREP_TIME, recipe.getPrepTime()); 94 | assertEquals(DESCRIPTION, recipe.getDescription()); 95 | assertEquals(DIFFICULTY, recipe.getDifficulty()); 96 | assertEquals(DIRECTIONS, recipe.getDirections()); 97 | assertEquals(SERVINGS, recipe.getServings()); 98 | assertEquals(SOURCE, recipe.getSource()); 99 | assertEquals(URL, recipe.getUrl()); 100 | assertEquals(NOTES_ID, recipe.getNotes().getId()); 101 | assertEquals(2, recipe.getCategories().size()); 102 | assertEquals(2, recipe.getIngredients().size()); 103 | } 104 | 105 | } -------------------------------------------------------------------------------- /src/test/java/guru/springframework/converters/RecipeToRecipeCommandTest.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.converters; 2 | 3 | import guru.springframework.commands.RecipeCommand; 4 | import guru.springframework.domain.*; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | public class RecipeToRecipeCommandTest { 11 | 12 | public static final Long RECIPE_ID = 1L; 13 | public static final Integer COOK_TIME = Integer.valueOf("5"); 14 | public static final Integer PREP_TIME = Integer.valueOf("7"); 15 | public static final String DESCRIPTION = "My Recipe"; 16 | public static final String DIRECTIONS = "Directions"; 17 | public static final Difficulty DIFFICULTY = Difficulty.EASY; 18 | public static final Integer SERVINGS = Integer.valueOf("3"); 19 | public static final String SOURCE = "Source"; 20 | public static final String URL = "Some URL"; 21 | public static final Long CAT_ID_1 = 1L; 22 | public static final Long CAT_ID2 = 2L; 23 | public static final Long INGRED_ID_1 = 3L; 24 | public static final Long INGRED_ID_2 = 4L; 25 | public static final Long NOTES_ID = 9L; 26 | RecipeToRecipeCommand converter; 27 | 28 | @Before 29 | public void setUp() throws Exception { 30 | converter = new RecipeToRecipeCommand( 31 | new CategoryToCategoryCommand(), 32 | new IngredientToIngredientCommand(new UnitOfMeasureToUnitOfMeasureCommand()), 33 | new NotesToNotesCommand()); 34 | } 35 | 36 | @Test 37 | public void testNullObject() throws Exception { 38 | assertNull(converter.convert(null)); 39 | } 40 | 41 | @Test 42 | public void testEmptyObject() throws Exception { 43 | assertNotNull(converter.convert(new Recipe())); 44 | } 45 | 46 | @Test 47 | public void convert() throws Exception { 48 | //given 49 | Recipe recipe = new Recipe(); 50 | recipe.setId(RECIPE_ID); 51 | recipe.setCookTime(COOK_TIME); 52 | recipe.setPrepTime(PREP_TIME); 53 | recipe.setDescription(DESCRIPTION); 54 | recipe.setDifficulty(DIFFICULTY); 55 | recipe.setDirections(DIRECTIONS); 56 | recipe.setServings(SERVINGS); 57 | recipe.setSource(SOURCE); 58 | recipe.setUrl(URL); 59 | 60 | Notes notes = new Notes(); 61 | notes.setId(NOTES_ID); 62 | 63 | recipe.setNotes(notes); 64 | 65 | Category category = new Category(); 66 | category.setId(CAT_ID_1); 67 | 68 | Category category2 = new Category(); 69 | category2.setId(CAT_ID2); 70 | 71 | recipe.getCategories().add(category); 72 | recipe.getCategories().add(category2); 73 | 74 | Ingredient ingredient = new Ingredient(); 75 | ingredient.setId(INGRED_ID_1); 76 | 77 | Ingredient ingredient2 = new Ingredient(); 78 | ingredient2.setId(INGRED_ID_2); 79 | 80 | recipe.getIngredients().add(ingredient); 81 | recipe.getIngredients().add(ingredient2); 82 | 83 | //when 84 | RecipeCommand command = converter.convert(recipe); 85 | 86 | //then 87 | assertNotNull(command); 88 | assertEquals(RECIPE_ID, command.getId()); 89 | assertEquals(COOK_TIME, command.getCookTime()); 90 | assertEquals(PREP_TIME, command.getPrepTime()); 91 | assertEquals(DESCRIPTION, command.getDescription()); 92 | assertEquals(DIFFICULTY, command.getDifficulty()); 93 | assertEquals(DIRECTIONS, command.getDirections()); 94 | assertEquals(SERVINGS, command.getServings()); 95 | assertEquals(SOURCE, command.getSource()); 96 | assertEquals(URL, command.getUrl()); 97 | assertEquals(NOTES_ID, command.getNotes().getId()); 98 | assertEquals(2, command.getCategories().size()); 99 | assertEquals(2, command.getIngredients().size()); 100 | 101 | } 102 | 103 | } -------------------------------------------------------------------------------- /src/test/java/guru/springframework/converters/UnitOfMeasureCommandToUnitOfMeasureTest.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.converters; 2 | 3 | import guru.springframework.commands.UnitOfMeasureCommand; 4 | import guru.springframework.domain.UnitOfMeasure; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | public class UnitOfMeasureCommandToUnitOfMeasureTest { 11 | 12 | public static final String DESCRIPTION = "description"; 13 | public static final Long LONG_VALUE = new Long(1L); 14 | 15 | UnitOfMeasureCommandToUnitOfMeasure converter; 16 | 17 | @Before 18 | public void setUp() throws Exception { 19 | converter = new UnitOfMeasureCommandToUnitOfMeasure(); 20 | 21 | } 22 | 23 | @Test 24 | public void testNullParamter() throws Exception { 25 | assertNull(converter.convert(null)); 26 | } 27 | 28 | @Test 29 | public void testEmptyObject() throws Exception { 30 | assertNotNull(converter.convert(new UnitOfMeasureCommand())); 31 | } 32 | 33 | @Test 34 | public void convert() throws Exception { 35 | //given 36 | UnitOfMeasureCommand command = new UnitOfMeasureCommand(); 37 | command.setId(LONG_VALUE); 38 | command.setDescription(DESCRIPTION); 39 | 40 | //when 41 | UnitOfMeasure uom = converter.convert(command); 42 | 43 | //then 44 | assertNotNull(uom); 45 | assertEquals(LONG_VALUE, uom.getId()); 46 | assertEquals(DESCRIPTION, uom.getDescription()); 47 | 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /src/test/java/guru/springframework/converters/UnitOfMeasureToUnitOfMeasureCommandTest.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.converters; 2 | 3 | import guru.springframework.commands.UnitOfMeasureCommand; 4 | import guru.springframework.domain.UnitOfMeasure; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | /** 11 | * Created by jt on 6/21/17. 12 | */ 13 | public class UnitOfMeasureToUnitOfMeasureCommandTest { 14 | 15 | public static final String DESCRIPTION = "description"; 16 | public static final Long LONG_VALUE = new Long(1L); 17 | 18 | UnitOfMeasureToUnitOfMeasureCommand converter; 19 | 20 | @Before 21 | public void setUp() throws Exception { 22 | converter = new UnitOfMeasureToUnitOfMeasureCommand(); 23 | } 24 | 25 | @Test 26 | public void testNullObjectConvert() throws Exception { 27 | assertNull(converter.convert(null)); 28 | } 29 | 30 | @Test 31 | public void testEmptyObj() throws Exception { 32 | assertNotNull(converter.convert(new UnitOfMeasure())); 33 | } 34 | 35 | @Test 36 | public void convert() throws Exception { 37 | //given 38 | UnitOfMeasure uom = new UnitOfMeasure(); 39 | uom.setId(LONG_VALUE); 40 | uom.setDescription(DESCRIPTION); 41 | //when 42 | UnitOfMeasureCommand uomc = converter.convert(uom); 43 | 44 | //then 45 | assertEquals(LONG_VALUE, uomc.getId()); 46 | assertEquals(DESCRIPTION, uomc.getDescription()); 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /src/test/java/guru/springframework/domain/CategoryTest.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.domain; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | 6 | import static org.junit.Assert.assertEquals; 7 | 8 | /** 9 | * Created by jt on 6/17/17. 10 | */ 11 | public class CategoryTest { 12 | 13 | Category category; 14 | 15 | @Before 16 | public void setUp(){ 17 | category = new Category(); 18 | } 19 | 20 | @Test 21 | public void getId() throws Exception { 22 | Long idValue = 4L; 23 | 24 | category.setId(idValue); 25 | 26 | assertEquals(idValue, category.getId()); 27 | } 28 | 29 | @Test 30 | public void getDescription() throws Exception { 31 | } 32 | 33 | @Test 34 | public void getRecipes() throws Exception { 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /src/test/java/guru/springframework/repositories/UnitOfMeasureRepositoryIT.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.repositories; 2 | 3 | import guru.springframework.domain.UnitOfMeasure; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; 9 | import org.springframework.test.context.junit4.SpringRunner; 10 | 11 | import java.util.Optional; 12 | 13 | import static org.junit.Assert.assertEquals; 14 | 15 | /** 16 | * Created by jt on 6/17/17. 17 | */ 18 | @RunWith(SpringRunner.class) 19 | @DataJpaTest 20 | public class UnitOfMeasureRepositoryIT { 21 | 22 | @Autowired 23 | UnitOfMeasureRepository unitOfMeasureRepository; 24 | 25 | @Before 26 | public void setUp() throws Exception { 27 | } 28 | 29 | @Test 30 | public void findByDescription() throws Exception { 31 | 32 | Optional uomOptional = unitOfMeasureRepository.findByDescription("Teaspoon"); 33 | 34 | assertEquals("Teaspoon", uomOptional.get().getDescription()); 35 | } 36 | 37 | @Test 38 | public void findByDescriptionCup() throws Exception { 39 | 40 | Optional uomOptional = unitOfMeasureRepository.findByDescription("Cup"); 41 | 42 | assertEquals("Cup", uomOptional.get().getDescription()); 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /src/test/java/guru/springframework/services/ImageServiceImplTest.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.services; 2 | 3 | import guru.springframework.domain.Recipe; 4 | import guru.springframework.repositories.RecipeRepository; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | import org.mockito.ArgumentCaptor; 8 | import org.mockito.Mock; 9 | import org.mockito.MockitoAnnotations; 10 | import org.springframework.mock.web.MockMultipartFile; 11 | import org.springframework.web.multipart.MultipartFile; 12 | 13 | import java.util.Optional; 14 | 15 | import static org.junit.Assert.assertEquals; 16 | import static org.mockito.Mockito.*; 17 | 18 | 19 | public class ImageServiceImplTest { 20 | 21 | @Mock 22 | RecipeRepository recipeRepository; 23 | 24 | ImageService imageService; 25 | 26 | @Before 27 | public void setUp() throws Exception { 28 | MockitoAnnotations.initMocks(this); 29 | 30 | imageService = new ImageServiceImpl(recipeRepository); 31 | } 32 | 33 | @Test 34 | public void saveImageFile() throws Exception { 35 | //given 36 | Long id = 1L; 37 | MultipartFile multipartFile = new MockMultipartFile("imagefile", "testing.txt", "text/plain", 38 | "Spring Framework Guru".getBytes()); 39 | 40 | Recipe recipe = new Recipe(); 41 | recipe.setId(id); 42 | Optional recipeOptional = Optional.of(recipe); 43 | 44 | when(recipeRepository.findById(anyLong())).thenReturn(recipeOptional); 45 | 46 | ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Recipe.class); 47 | 48 | //when 49 | imageService.saveImageFile(id, multipartFile); 50 | 51 | //then 52 | verify(recipeRepository, times(1)).save(argumentCaptor.capture()); 53 | Recipe savedRecipe = argumentCaptor.getValue(); 54 | assertEquals(multipartFile.getBytes().length, savedRecipe.getImage().length); 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /src/test/java/guru/springframework/services/IngredientServiceImplTest.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.services; 2 | 3 | import guru.springframework.commands.IngredientCommand; 4 | import guru.springframework.converters.IngredientCommandToIngredient; 5 | import guru.springframework.converters.IngredientToIngredientCommand; 6 | import guru.springframework.converters.UnitOfMeasureCommandToUnitOfMeasure; 7 | import guru.springframework.converters.UnitOfMeasureToUnitOfMeasureCommand; 8 | import guru.springframework.domain.Ingredient; 9 | import guru.springframework.domain.Recipe; 10 | import guru.springframework.repositories.RecipeRepository; 11 | import guru.springframework.repositories.UnitOfMeasureRepository; 12 | import org.junit.Before; 13 | import org.junit.Test; 14 | import org.mockito.Mock; 15 | import org.mockito.MockitoAnnotations; 16 | 17 | import java.util.Optional; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | import static org.mockito.ArgumentMatchers.anyLong; 21 | import static org.mockito.Mockito.*; 22 | 23 | public class IngredientServiceImplTest { 24 | 25 | private final IngredientToIngredientCommand ingredientToIngredientCommand; 26 | private final IngredientCommandToIngredient ingredientCommandToIngredient; 27 | 28 | @Mock 29 | RecipeRepository recipeRepository; 30 | 31 | @Mock 32 | UnitOfMeasureRepository unitOfMeasureRepository; 33 | 34 | IngredientService ingredientService; 35 | 36 | //init converters 37 | public IngredientServiceImplTest() { 38 | this.ingredientToIngredientCommand = new IngredientToIngredientCommand(new UnitOfMeasureToUnitOfMeasureCommand()); 39 | this.ingredientCommandToIngredient = new IngredientCommandToIngredient(new UnitOfMeasureCommandToUnitOfMeasure()); 40 | } 41 | 42 | @Before 43 | public void setUp() throws Exception { 44 | MockitoAnnotations.initMocks(this); 45 | 46 | ingredientService = new IngredientServiceImpl(ingredientToIngredientCommand, ingredientCommandToIngredient, 47 | recipeRepository, unitOfMeasureRepository); 48 | } 49 | 50 | @Test 51 | public void findByRecipeIdAndId() throws Exception { 52 | } 53 | 54 | @Test 55 | public void findByRecipeIdAndReceipeIdHappyPath() throws Exception { 56 | //given 57 | Recipe recipe = new Recipe(); 58 | recipe.setId(1L); 59 | 60 | Ingredient ingredient1 = new Ingredient(); 61 | ingredient1.setId(1L); 62 | 63 | Ingredient ingredient2 = new Ingredient(); 64 | ingredient2.setId(1L); 65 | 66 | Ingredient ingredient3 = new Ingredient(); 67 | ingredient3.setId(3L); 68 | 69 | recipe.addIngredient(ingredient1); 70 | recipe.addIngredient(ingredient2); 71 | recipe.addIngredient(ingredient3); 72 | Optional recipeOptional = Optional.of(recipe); 73 | 74 | when(recipeRepository.findById(anyLong())).thenReturn(recipeOptional); 75 | 76 | //then 77 | IngredientCommand ingredientCommand = ingredientService.findByRecipeIdAndIngredientId(1L, 3L); 78 | 79 | //when 80 | assertEquals(Long.valueOf(3L), ingredientCommand.getId()); 81 | assertEquals(Long.valueOf(1L), ingredientCommand.getRecipeId()); 82 | verify(recipeRepository, times(1)).findById(anyLong()); 83 | } 84 | 85 | 86 | @Test 87 | public void testSaveRecipeCommand() throws Exception { 88 | //given 89 | IngredientCommand command = new IngredientCommand(); 90 | command.setId(3L); 91 | command.setRecipeId(2L); 92 | 93 | Optional recipeOptional = Optional.of(new Recipe()); 94 | 95 | Recipe savedRecipe = new Recipe(); 96 | savedRecipe.addIngredient(new Ingredient()); 97 | savedRecipe.getIngredients().iterator().next().setId(3L); 98 | 99 | when(recipeRepository.findById(anyLong())).thenReturn(recipeOptional); 100 | when(recipeRepository.save(any())).thenReturn(savedRecipe); 101 | 102 | //when 103 | IngredientCommand savedCommand = ingredientService.saveIngredientCommand(command); 104 | 105 | //then 106 | assertEquals(Long.valueOf(3L), savedCommand.getId()); 107 | verify(recipeRepository, times(1)).findById(anyLong()); 108 | verify(recipeRepository, times(1)).save(any(Recipe.class)); 109 | 110 | } 111 | 112 | @Test 113 | public void testDeleteById() throws Exception { 114 | //given 115 | Recipe recipe = new Recipe(); 116 | Ingredient ingredient = new Ingredient(); 117 | ingredient.setId(3L); 118 | recipe.addIngredient(ingredient); 119 | ingredient.setRecipe(recipe); 120 | Optional recipeOptional = Optional.of(recipe); 121 | 122 | when(recipeRepository.findById(anyLong())).thenReturn(recipeOptional); 123 | 124 | //when 125 | ingredientService.deleteById(1L, 3L); 126 | 127 | //then 128 | verify(recipeRepository, times(1)).findById(anyLong()); 129 | verify(recipeRepository, times(1)).save(any(Recipe.class)); 130 | } 131 | } -------------------------------------------------------------------------------- /src/test/java/guru/springframework/services/RecipeServiceIT.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.services; 2 | 3 | import guru.springframework.commands.RecipeCommand; 4 | import guru.springframework.converters.RecipeCommandToRecipe; 5 | import guru.springframework.converters.RecipeToRecipeCommand; 6 | import guru.springframework.domain.Recipe; 7 | import guru.springframework.repositories.RecipeRepository; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | import org.springframework.test.context.junit4.SpringRunner; 13 | import org.springframework.transaction.annotation.Transactional; 14 | 15 | import static org.junit.Assert.assertEquals; 16 | 17 | 18 | /** 19 | * Created by jt on 6/21/17. 20 | */ 21 | @RunWith(SpringRunner.class) 22 | @SpringBootTest 23 | public class RecipeServiceIT { 24 | 25 | public static final String NEW_DESCRIPTION = "New Description"; 26 | 27 | @Autowired 28 | RecipeService recipeService; 29 | 30 | @Autowired 31 | RecipeRepository recipeRepository; 32 | 33 | @Autowired 34 | RecipeCommandToRecipe recipeCommandToRecipe; 35 | 36 | @Autowired 37 | RecipeToRecipeCommand recipeToRecipeCommand; 38 | 39 | @Transactional 40 | @Test 41 | public void testSaveOfDescription() throws Exception { 42 | //given 43 | Iterable recipes = recipeRepository.findAll(); 44 | Recipe testRecipe = recipes.iterator().next(); 45 | RecipeCommand testRecipeCommand = recipeToRecipeCommand.convert(testRecipe); 46 | 47 | //when 48 | testRecipeCommand.setDescription(NEW_DESCRIPTION); 49 | RecipeCommand savedRecipeCommand = recipeService.saveRecipeCommand(testRecipeCommand); 50 | 51 | //then 52 | assertEquals(NEW_DESCRIPTION, savedRecipeCommand.getDescription()); 53 | assertEquals(testRecipe.getId(), savedRecipeCommand.getId()); 54 | assertEquals(testRecipe.getCategories().size(), savedRecipeCommand.getCategories().size()); 55 | assertEquals(testRecipe.getIngredients().size(), savedRecipeCommand.getIngredients().size()); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/guru/springframework/services/RecipeServiceImplTest.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.services; 2 | 3 | 4 | import guru.springframework.commands.RecipeCommand; 5 | import guru.springframework.converters.RecipeCommandToRecipe; 6 | import guru.springframework.converters.RecipeToRecipeCommand; 7 | import guru.springframework.domain.Recipe; 8 | import guru.springframework.exceptions.NotFoundException; 9 | import guru.springframework.repositories.RecipeRepository; 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | import org.mockito.Mock; 13 | import org.mockito.MockitoAnnotations; 14 | 15 | import java.util.HashSet; 16 | import java.util.Optional; 17 | import java.util.Set; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | import static org.junit.Assert.assertNotNull; 21 | import static org.mockito.Mockito.*; 22 | 23 | /** 24 | * Created by jt on 6/17/17. 25 | */ 26 | public class RecipeServiceImplTest { 27 | 28 | RecipeServiceImpl recipeService; 29 | 30 | @Mock 31 | RecipeRepository recipeRepository; 32 | 33 | @Mock 34 | RecipeToRecipeCommand recipeToRecipeCommand; 35 | 36 | @Mock 37 | RecipeCommandToRecipe recipeCommandToRecipe; 38 | 39 | @Before 40 | public void setUp() throws Exception { 41 | MockitoAnnotations.initMocks(this); 42 | 43 | recipeService = new RecipeServiceImpl(recipeRepository, recipeCommandToRecipe, recipeToRecipeCommand); 44 | } 45 | 46 | @Test 47 | public void getRecipeByIdTest() throws Exception { 48 | Recipe recipe = new Recipe(); 49 | recipe.setId(1L); 50 | Optional recipeOptional = Optional.of(recipe); 51 | 52 | when(recipeRepository.findById(anyLong())).thenReturn(recipeOptional); 53 | 54 | Recipe recipeReturned = recipeService.findById(1L); 55 | 56 | assertNotNull("Null recipe returned", recipeReturned); 57 | verify(recipeRepository, times(1)).findById(anyLong()); 58 | verify(recipeRepository, never()).findAll(); 59 | } 60 | 61 | @Test(expected = NotFoundException.class) 62 | public void getRecipeByIdTestNotFound() throws Exception { 63 | 64 | Optional recipeOptional = Optional.empty(); 65 | 66 | when(recipeRepository.findById(anyLong())).thenReturn(recipeOptional); 67 | 68 | Recipe recipeReturned = recipeService.findById(1L); 69 | 70 | //should go boom 71 | } 72 | 73 | @Test 74 | public void getRecipeCommandByIdTest() throws Exception { 75 | Recipe recipe = new Recipe(); 76 | recipe.setId(1L); 77 | Optional recipeOptional = Optional.of(recipe); 78 | 79 | when(recipeRepository.findById(anyLong())).thenReturn(recipeOptional); 80 | 81 | RecipeCommand recipeCommand = new RecipeCommand(); 82 | recipeCommand.setId(1L); 83 | 84 | when(recipeToRecipeCommand.convert(any())).thenReturn(recipeCommand); 85 | 86 | RecipeCommand commandById = recipeService.findCommandById(1L); 87 | 88 | assertNotNull("Null recipe returned", commandById); 89 | verify(recipeRepository, times(1)).findById(anyLong()); 90 | verify(recipeRepository, never()).findAll(); 91 | } 92 | 93 | @Test 94 | public void getRecipesTest() throws Exception { 95 | 96 | Recipe recipe = new Recipe(); 97 | HashSet receipesData = new HashSet(); 98 | receipesData.add(recipe); 99 | 100 | when(recipeService.getRecipes()).thenReturn(receipesData); 101 | 102 | Set recipes = recipeService.getRecipes(); 103 | 104 | assertEquals(recipes.size(), 1); 105 | verify(recipeRepository, times(1)).findAll(); 106 | verify(recipeRepository, never()).findById(anyLong()); 107 | } 108 | 109 | @Test 110 | public void testDeleteById() throws Exception { 111 | 112 | //given 113 | Long idToDelete = Long.valueOf(2L); 114 | 115 | //when 116 | recipeService.deleteById(idToDelete); 117 | 118 | //no 'when', since method has void return type 119 | 120 | //then 121 | verify(recipeRepository, times(1)).deleteById(anyLong()); 122 | } 123 | } -------------------------------------------------------------------------------- /src/test/java/guru/springframework/services/UnitOfMeasureServiceImplTest.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.services; 2 | 3 | import guru.springframework.commands.UnitOfMeasureCommand; 4 | import guru.springframework.converters.UnitOfMeasureToUnitOfMeasureCommand; 5 | import guru.springframework.domain.UnitOfMeasure; 6 | import guru.springframework.repositories.UnitOfMeasureRepository; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | import org.mockito.Mock; 10 | import org.mockito.MockitoAnnotations; 11 | 12 | import java.util.HashSet; 13 | import java.util.Set; 14 | 15 | import static org.junit.Assert.assertEquals; 16 | import static org.mockito.Mockito.*; 17 | 18 | public class UnitOfMeasureServiceImplTest { 19 | 20 | UnitOfMeasureToUnitOfMeasureCommand unitOfMeasureToUnitOfMeasureCommand = new UnitOfMeasureToUnitOfMeasureCommand(); 21 | UnitOfMeasureService service; 22 | 23 | @Mock 24 | UnitOfMeasureRepository unitOfMeasureRepository; 25 | 26 | @Before 27 | public void setUp() throws Exception { 28 | MockitoAnnotations.initMocks(this); 29 | 30 | service = new UnitOfMeasureServiceImpl(unitOfMeasureRepository, unitOfMeasureToUnitOfMeasureCommand); 31 | } 32 | 33 | @Test 34 | public void listAllUoms() throws Exception { 35 | //given 36 | Set unitOfMeasures = new HashSet<>(); 37 | UnitOfMeasure uom1 = new UnitOfMeasure(); 38 | uom1.setId(1L); 39 | unitOfMeasures.add(uom1); 40 | 41 | UnitOfMeasure uom2 = new UnitOfMeasure(); 42 | uom2.setId(2L); 43 | unitOfMeasures.add(uom2); 44 | 45 | when(unitOfMeasureRepository.findAll()).thenReturn(unitOfMeasures); 46 | 47 | //when 48 | Set commands = service.listAllUoms(); 49 | 50 | //then 51 | assertEquals(2, commands.size()); 52 | verify(unitOfMeasureRepository, times(1)).findAll(); 53 | } 54 | 55 | } --------------------------------------------------------------------------------