├── .circleci └── config.yml ├── .gitignore ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src ├── main ├── java │ └── guru │ │ └── springframework │ │ ├── Spring5MongoRecipeAppApplication.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 │ ├── messages.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 └── 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 | JVM_OPTS: -Xmx3200m 22 | TERM: dumb 23 | 24 | steps: 25 | - checkout 26 | 27 | # Download and cache dependencies 28 | - restore_cache: 29 | keys: 30 | - v1-dependencies-{{ checksum "build.gradle" }} 31 | # fallback to using the latest cache if no exact match is found 32 | - v1-dependencies- 33 | 34 | - run: gradle dependencies 35 | 36 | - save_cache: 37 | paths: 38 | - ~/.m2 39 | key: v1-dependencies-{{ checksum "build.gradle" }} 40 | 41 | # run tests! and gen code coverage 42 | - run: ./gradlew clean test jacocoTestReport 43 | 44 | - run: 45 | name: Save test results 46 | command: | 47 | mkdir -p ~/junit/ 48 | find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/junit/ \; 49 | when: always 50 | 51 | - store_test_results: 52 | path: ~/junit 53 | 54 | - store_artifacts: 55 | path: ~/junit 56 | 57 | - run: 58 | name: Send to CodeCov 59 | command: bash <(curl -s https://codecov.io/bash) 60 | -------------------------------------------------------------------------------- /.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 | [![CircleCI](https://circleci.com/gh/springframeworkguru/spring5-reactive-mongo-recipe-app.svg?style=svg)](https://circleci.com/gh/springframeworkguru/spring5-reactive-mongo-recipe-app) 2 | 3 | [![codecov](https://codecov.io/gh/springframeworkguru/spring5-reactive-mongo-recipe-app/branch/master/graph/badge.svg)](https://codecov.io/gh/springframeworkguru/spring5-reactive-mongo-recipe-app) 4 | 5 | # spring5-reactive-mongo-recipe-app 6 | Reactive Recipe Application Using MongoDB 7 | 8 | This repository is for an example application built in my Spring Framework 5 - Beginner to Guru 9 | 10 | 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) -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '2.1.0.RELEASE' 4 | } 5 | repositories { 6 | mavenCentral() 7 | maven { url "https://repo.spring.io/snapshot" } 8 | maven { url "https://repo.spring.io/milestone" } 9 | } 10 | dependencies { 11 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 12 | } 13 | } 14 | 15 | apply plugin: 'java' 16 | apply plugin: 'eclipse' 17 | apply plugin: 'org.springframework.boot' 18 | apply plugin: 'io.spring.dependency-management' 19 | apply plugin: 'jacoco' 20 | 21 | version = '0.0.1-SNAPSHOT' 22 | sourceCompatibility = 1.8 23 | 24 | repositories { 25 | mavenCentral() 26 | maven { url "https://repo.spring.io/snapshot" } 27 | maven { url "https://repo.spring.io/milestone" } 28 | } 29 | 30 | 31 | dependencies { 32 | compile('org.springframework.boot:spring-boot-starter-data-mongodb') 33 | compile('org.springframework.boot:spring-boot-starter-thymeleaf') 34 | compile('org.springframework.boot:spring-boot-starter-web') 35 | runtime('org.springframework.boot:spring-boot-devtools') 36 | compile('de.flapdoodle.embed:de.flapdoodle.embed.mongo') 37 | compile group: 'cz.jirutka.spring', name: 'embedmongo-spring', version: '1.3.1' 38 | compile 'org.webjars:bootstrap:3.3.7-1' 39 | compileOnly('org.projectlombok:lombok') 40 | testCompile('org.springframework.boot:spring-boot-starter-test') 41 | } 42 | 43 | //export test coverage 44 | jacocoTestReport { 45 | reports { 46 | xml.enabled true 47 | html.enabled false 48 | } 49 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springframeworkguru/spring5-reactive-mongo-recipe-app/03a153588aa0b5c05e651b977c5a87fb12ae6970/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Aug 02 18:09:02 EDT 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/Spring5MongoRecipeAppApplication.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 Spring5MongoRecipeAppApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Spring5MongoRecipeAppApplication.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, 30 | RecipeRepository recipeRepository, UnitOfMeasureRepository unitOfMeasureRepository) { 31 | this.categoryRepository = categoryRepository; 32 | this.recipeRepository = recipeRepository; 33 | this.unitOfMeasureRepository = unitOfMeasureRepository; 34 | } 35 | 36 | @Override 37 | @Transactional 38 | public void onApplicationEvent(ContextRefreshedEvent event) { 39 | loadCategories(); 40 | loadUom(); 41 | recipeRepository.saveAll(getRecipes()); 42 | log.debug("Loading Bootstrap Data"); 43 | } 44 | 45 | private void loadCategories(){ 46 | Category cat1 = new Category(); 47 | cat1.setDescription("American"); 48 | categoryRepository.save(cat1); 49 | 50 | Category cat2 = new Category(); 51 | cat2.setDescription("Italian"); 52 | categoryRepository.save(cat2); 53 | 54 | Category cat3 = new Category(); 55 | cat3.setDescription("Mexican"); 56 | categoryRepository.save(cat3); 57 | 58 | Category cat4 = new Category(); 59 | cat4.setDescription("Fast Food"); 60 | categoryRepository.save(cat4); 61 | } 62 | 63 | private void loadUom(){ 64 | UnitOfMeasure uom1 = new UnitOfMeasure(); 65 | uom1.setDescription("Teaspoon"); 66 | unitOfMeasureRepository.save(uom1); 67 | 68 | UnitOfMeasure uom2 = new UnitOfMeasure(); 69 | uom2.setDescription("Tablespoon"); 70 | unitOfMeasureRepository.save(uom2); 71 | 72 | UnitOfMeasure uom3 = new UnitOfMeasure(); 73 | uom3.setDescription("Cup"); 74 | unitOfMeasureRepository.save(uom3); 75 | 76 | UnitOfMeasure uom4 = new UnitOfMeasure(); 77 | uom4.setDescription("Pinch"); 78 | unitOfMeasureRepository.save(uom4); 79 | 80 | UnitOfMeasure uom5 = new UnitOfMeasure(); 81 | uom5.setDescription("Ounce"); 82 | unitOfMeasureRepository.save(uom5); 83 | 84 | UnitOfMeasure uom6 = new UnitOfMeasure(); 85 | uom6.setDescription("Each"); 86 | unitOfMeasureRepository.save(uom6); 87 | 88 | UnitOfMeasure uom7 = new UnitOfMeasure(); 89 | uom7.setDescription("Pint"); 90 | unitOfMeasureRepository.save(uom7); 91 | 92 | UnitOfMeasure uom8 = new UnitOfMeasure(); 93 | uom8.setDescription("Dash"); 94 | unitOfMeasureRepository.save(uom8); 95 | } 96 | 97 | private List getRecipes() { 98 | 99 | List recipes = new ArrayList<>(2); 100 | 101 | //get UOMs 102 | Optional eachUomOptional = unitOfMeasureRepository.findByDescription("Each"); 103 | 104 | if(!eachUomOptional.isPresent()){ 105 | throw new RuntimeException("Expected UOM Not Found"); 106 | } 107 | 108 | Optional tableSpoonUomOptional = unitOfMeasureRepository.findByDescription("Tablespoon"); 109 | 110 | if(!tableSpoonUomOptional.isPresent()){ 111 | throw new RuntimeException("Expected UOM Not Found"); 112 | } 113 | 114 | Optional teaSpoonUomOptional = unitOfMeasureRepository.findByDescription("Teaspoon"); 115 | 116 | if(!teaSpoonUomOptional.isPresent()){ 117 | throw new RuntimeException("Expected UOM Not Found"); 118 | } 119 | 120 | Optional dashUomOptional = unitOfMeasureRepository.findByDescription("Dash"); 121 | 122 | if(!dashUomOptional.isPresent()){ 123 | throw new RuntimeException("Expected UOM Not Found"); 124 | } 125 | 126 | Optional pintUomOptional = unitOfMeasureRepository.findByDescription("Pint"); 127 | 128 | if(!pintUomOptional.isPresent()){ 129 | throw new RuntimeException("Expected UOM Not Found"); 130 | } 131 | 132 | Optional cupsUomOptional = unitOfMeasureRepository.findByDescription("Cup"); 133 | 134 | if(!cupsUomOptional.isPresent()){ 135 | throw new RuntimeException("Expected UOM Not Found"); 136 | } 137 | 138 | //get optionals 139 | UnitOfMeasure eachUom = eachUomOptional.get(); 140 | UnitOfMeasure tableSpoonUom = tableSpoonUomOptional.get(); 141 | UnitOfMeasure teapoonUom = tableSpoonUomOptional.get(); 142 | UnitOfMeasure dashUom = dashUomOptional.get(); 143 | UnitOfMeasure pintUom = dashUomOptional.get(); 144 | UnitOfMeasure cupsUom = cupsUomOptional.get(); 145 | 146 | //get Categories 147 | Optional americanCategoryOptional = categoryRepository.findByDescription("American"); 148 | 149 | if(!americanCategoryOptional.isPresent()){ 150 | throw new RuntimeException("Expected Category Not Found"); 151 | } 152 | 153 | Optional mexicanCategoryOptional = categoryRepository.findByDescription("Mexican"); 154 | 155 | if(!mexicanCategoryOptional.isPresent()){ 156 | throw new RuntimeException("Expected Category Not Found"); 157 | } 158 | 159 | Category americanCategory = americanCategoryOptional.get(); 160 | Category mexicanCategory = mexicanCategoryOptional.get(); 161 | 162 | //Yummy Guac 163 | Recipe guacRecipe = new Recipe(); 164 | guacRecipe.setDescription("Perfect Guacamole"); 165 | guacRecipe.setPrepTime(10); 166 | guacRecipe.setCookTime(0); 167 | guacRecipe.setDifficulty(Difficulty.EASY); 168 | 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" + 169 | "\n" + 170 | "2 Mash with a fork: Using a fork, roughly mash the avocado. (Don't overdo it! The guacamole should be a little chunky.)" + 171 | "\n" + 172 | "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" + 173 | "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" + 174 | "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" + 175 | "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" + 176 | "Chilling tomatoes hurts their flavor, so if you want to add chopped tomato to your guacamole, add it just before serving.\n" + 177 | "\n" + 178 | "\n" + 179 | "Read more: http://www.simplyrecipes.com/recipes/perfect_guacamole/#ixzz4jvpiV9Sd"); 180 | 181 | Notes guacNotes = new Notes(); 182 | guacNotes.setRecipeNotes("For a very quick guacamole just take a 1/4 cup of salsa and mix it in with your mashed avocados.\n" + 183 | "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" + 184 | "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" + 185 | "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" + 186 | "\n" + 187 | "\n" + 188 | "Read more: http://www.simplyrecipes.com/recipes/perfect_guacamole/#ixzz4jvoun5ws"); 189 | 190 | guacRecipe.setNotes(guacNotes); 191 | 192 | //very redundent - could add helper method, and make this simpler 193 | guacRecipe.addIngredient(new Ingredient("ripe avocados", new BigDecimal(2), eachUom)); 194 | guacRecipe.addIngredient(new Ingredient("Kosher salt", new BigDecimal(".5"), teapoonUom)); 195 | guacRecipe.addIngredient(new Ingredient("fresh lime juice or lemon juice", new BigDecimal(2), tableSpoonUom)); 196 | guacRecipe.addIngredient(new Ingredient("minced red onion or thinly sliced green onion", new BigDecimal(2), tableSpoonUom)); 197 | guacRecipe.addIngredient(new Ingredient("serrano chiles, stems and seeds removed, minced", new BigDecimal(2), eachUom)); 198 | guacRecipe.addIngredient(new Ingredient("Cilantro", new BigDecimal(2), tableSpoonUom)); 199 | guacRecipe.addIngredient(new Ingredient("freshly grated black pepper", new BigDecimal(2), dashUom)); 200 | guacRecipe.addIngredient(new Ingredient("ripe tomato, seeds and pulp removed, chopped", new BigDecimal(".5"), eachUom)); 201 | 202 | guacRecipe.getCategories().add(americanCategory); 203 | guacRecipe.getCategories().add(mexicanCategory); 204 | 205 | guacRecipe.setUrl("http://www.simplyrecipes.com/recipes/perfect_guacamole/"); 206 | guacRecipe.setServings(4); 207 | guacRecipe.setSource("Simply Recipes"); 208 | 209 | //add to return list 210 | recipes.add(guacRecipe); 211 | 212 | //Yummy Tacos 213 | Recipe tacosRecipe = new Recipe(); 214 | tacosRecipe.setDescription("Spicy Grilled Chicken Taco"); 215 | tacosRecipe.setCookTime(9); 216 | tacosRecipe.setPrepTime(20); 217 | tacosRecipe.setDifficulty(Difficulty.MODERATE); 218 | 219 | tacosRecipe.setDirections("1 Prepare a gas or charcoal grill for medium-high, direct heat.\n" + 220 | "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" + 221 | "Set aside to marinate while the grill heats and you prepare the rest of the toppings.\n" + 222 | "\n" + 223 | "\n" + 224 | "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" + 225 | "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" + 226 | "Wrap warmed tortillas in a tea towel to keep them warm until serving.\n" + 227 | "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" + 228 | "\n" + 229 | "\n" + 230 | "Read more: http://www.simplyrecipes.com/recipes/spicy_grilled_chicken_tacos/#ixzz4jvtrAnNm"); 231 | 232 | Notes tacoNotes = new Notes(); 233 | tacoNotes.setRecipeNotes("We have a family motto and it is this: Everything goes better in a tortilla.\n" + 234 | "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" + 235 | "Today’s tacos are more purposeful – a deliberate meal instead of a secretive midnight snack!\n" + 236 | "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" + 237 | "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" + 238 | "\n" + 239 | "\n" + 240 | "Read more: http://www.simplyrecipes.com/recipes/spicy_grilled_chicken_tacos/#ixzz4jvu7Q0MJ"); 241 | 242 | tacosRecipe.setNotes(tacoNotes); 243 | 244 | tacosRecipe.addIngredient(new Ingredient("Ancho Chili Powder", new BigDecimal(2), tableSpoonUom)); 245 | tacosRecipe.addIngredient(new Ingredient("Dried Oregano", new BigDecimal(1), teapoonUom)); 246 | tacosRecipe.addIngredient(new Ingredient("Dried Cumin", new BigDecimal(1), teapoonUom)); 247 | tacosRecipe.addIngredient(new Ingredient("Sugar", new BigDecimal(1), teapoonUom)); 248 | tacosRecipe.addIngredient(new Ingredient("Salt", new BigDecimal(".5"), teapoonUom)); 249 | tacosRecipe.addIngredient(new Ingredient("Clove of Garlic, Choppedr", new BigDecimal(1), eachUom)); 250 | tacosRecipe.addIngredient(new Ingredient("finely grated orange zestr", new BigDecimal(1), tableSpoonUom)); 251 | tacosRecipe.addIngredient(new Ingredient("fresh-squeezed orange juice", new BigDecimal(3), tableSpoonUom)); 252 | tacosRecipe.addIngredient(new Ingredient("Olive Oil", new BigDecimal(2), tableSpoonUom)); 253 | tacosRecipe.addIngredient(new Ingredient("boneless chicken thighs", new BigDecimal(4), tableSpoonUom)); 254 | tacosRecipe.addIngredient(new Ingredient("small corn tortillasr", new BigDecimal(8), eachUom)); 255 | tacosRecipe.addIngredient(new Ingredient("packed baby arugula", new BigDecimal(3), cupsUom)); 256 | tacosRecipe.addIngredient(new Ingredient("medium ripe avocados, slic", new BigDecimal(2), eachUom)); 257 | tacosRecipe.addIngredient(new Ingredient("radishes, thinly sliced", new BigDecimal(4), eachUom)); 258 | tacosRecipe.addIngredient(new Ingredient("cherry tomatoes, halved", new BigDecimal(".5"), pintUom)); 259 | tacosRecipe.addIngredient(new Ingredient("red onion, thinly sliced", new BigDecimal(".25"), eachUom)); 260 | tacosRecipe.addIngredient(new Ingredient("Roughly chopped cilantro", new BigDecimal(4), eachUom)); 261 | tacosRecipe.addIngredient(new Ingredient("cup sour cream thinned with 1/4 cup milk", new BigDecimal(4), cupsUom)); 262 | tacosRecipe.addIngredient(new Ingredient("lime, cut into wedges", new BigDecimal(4), eachUom)); 263 | 264 | tacosRecipe.getCategories().add(americanCategory); 265 | tacosRecipe.getCategories().add(mexicanCategory); 266 | 267 | tacosRecipe.setUrl("http://www.simplyrecipes.com/recipes/spicy_grilled_chicken_tacos/"); 268 | tacosRecipe.setServings(4); 269 | tacosRecipe.setSource("Simply Recipes"); 270 | 271 | recipes.add(tacosRecipe); 272 | return recipes; 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /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 String 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 String id; 17 | private String 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 String 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.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * Created by jt on 6/21/17. 18 | */ 19 | @Getter 20 | @Setter 21 | @NoArgsConstructor 22 | public class RecipeCommand { 23 | private String 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 List ingredients = new ArrayList<>(); 49 | private Byte[] image; 50 | private Difficulty difficulty; 51 | private NotesCommand notes; 52 | private List categories = new ArrayList<>(); 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 String 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(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(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(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(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(recipeId, 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(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 | model.addAttribute("ingredient", ingredientCommand); 61 | 62 | //init uom 63 | ingredientCommand.setUom(new UnitOfMeasureCommand()); 64 | 65 | model.addAttribute("uomList", unitOfMeasureService.listAllUoms()); 66 | 67 | return "recipe/ingredient/ingredientform"; 68 | } 69 | 70 | @GetMapping("recipe/{recipeId}/ingredient/{id}/update") 71 | public String updateRecipeIngredient(@PathVariable String recipeId, 72 | @PathVariable String id, Model model){ 73 | model.addAttribute("ingredient", ingredientService.findByRecipeIdAndIngredientId(recipeId, id)); 74 | 75 | model.addAttribute("uomList", unitOfMeasureService.listAllUoms()); 76 | return "recipe/ingredient/ingredientform"; 77 | } 78 | 79 | @PostMapping("recipe/{recipeId}/ingredient") 80 | public String saveOrUpdate(@ModelAttribute IngredientCommand command){ 81 | IngredientCommand savedCommand = ingredientService.saveIngredientCommand(command); 82 | 83 | log.debug("saved ingredient id:" + savedCommand.getId()); 84 | 85 | return "redirect:/recipe/" + savedCommand.getRecipeId() + "/ingredient/" + savedCommand.getId() + "/show"; 86 | } 87 | 88 | @GetMapping("recipe/{recipeId}/ingredient/{id}/delete") 89 | public String deleteIngredient(@PathVariable String recipeId, 90 | @PathVariable String id){ 91 | 92 | log.debug("deleting ingredient id:" + id); 93 | ingredientService.deleteById(recipeId, id); 94 | 95 | return "redirect:/recipe/" + recipeId + "/ingredients"; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /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(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(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(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 | recipe.addIngredient(ingredient); 36 | } 37 | 38 | ingredient.setAmount(source.getAmount()); 39 | ingredient.setDescription(source.getDescription()); 40 | ingredient.setUom(uomConverter.convert(source.getUom())); 41 | return ingredient; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /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 | 33 | ingredientCommand.setAmount(ingredient.getAmount()); 34 | ingredientCommand.setDescription(ingredient.getDescription()); 35 | ingredientCommand.setUom(uomConverter.convert(ingredient.getUom())); 36 | return ingredientCommand; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /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.Getter; 4 | import lombok.Setter; 5 | import org.springframework.data.annotation.Id; 6 | import org.springframework.data.mongodb.core.mapping.DBRef; 7 | import org.springframework.data.mongodb.core.mapping.Document; 8 | 9 | import java.util.Set; 10 | 11 | /** 12 | * Created by jt on 6/13/17. 13 | */ 14 | @Getter 15 | @Setter 16 | @Document 17 | public class Category { 18 | @Id 19 | private String id; 20 | private String description; 21 | 22 | @DBRef 23 | private Set recipes; 24 | } 25 | -------------------------------------------------------------------------------- /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.Getter; 4 | import lombok.Setter; 5 | import org.springframework.data.mongodb.core.mapping.DBRef; 6 | 7 | import java.math.BigDecimal; 8 | import java.util.UUID; 9 | 10 | /** 11 | * Created by jt on 6/13/17. 12 | */ 13 | @Getter 14 | @Setter 15 | public class Ingredient { 16 | 17 | private String id = UUID.randomUUID().toString(); 18 | private String description; 19 | private BigDecimal amount; 20 | 21 | @DBRef 22 | private UnitOfMeasure uom; 23 | 24 | public Ingredient() { 25 | 26 | } 27 | 28 | public Ingredient(String description, BigDecimal amount, UnitOfMeasure uom) { 29 | this.description = description; 30 | this.amount = amount; 31 | this.uom = uom; 32 | } 33 | 34 | public Ingredient(String description, BigDecimal amount, UnitOfMeasure uom, Recipe recipe) { 35 | this.description = description; 36 | this.amount = amount; 37 | this.uom = uom; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/domain/Notes.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.domain; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import org.springframework.data.annotation.Id; 6 | 7 | 8 | /** 9 | * Created by jt on 6/13/17. 10 | */ 11 | @Getter 12 | @Setter 13 | public class Notes { 14 | 15 | @Id 16 | private String id; 17 | private String recipeNotes; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/domain/Recipe.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.domain; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import org.springframework.data.annotation.Id; 6 | import org.springframework.data.mongodb.core.mapping.DBRef; 7 | import org.springframework.data.mongodb.core.mapping.Document; 8 | 9 | import java.util.HashSet; 10 | import java.util.Set; 11 | 12 | /** 13 | * Created by jt on 6/13/17. 14 | */ 15 | @Getter 16 | @Setter 17 | @Document 18 | public class Recipe { 19 | 20 | @Id 21 | private String id; 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 | private String directions; 29 | private Set ingredients = new HashSet<>(); 30 | private Byte[] image; 31 | private Difficulty difficulty; 32 | private Notes notes; 33 | 34 | @DBRef 35 | private Set categories = new HashSet<>(); 36 | 37 | public void setNotes(Notes notes) { 38 | if (notes != null) { 39 | this.notes = notes; 40 | } 41 | } 42 | 43 | public Recipe addIngredient(Ingredient ingredient){ 44 | this.ingredients.add(ingredient); 45 | return this; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/guru/springframework/domain/UnitOfMeasure.java: -------------------------------------------------------------------------------- 1 | package guru.springframework.domain; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import org.springframework.data.annotation.Id; 6 | import org.springframework.data.mongodb.core.mapping.Document; 7 | 8 | 9 | /** 10 | * Created by jt on 6/13/17. 11 | */ 12 | @Getter 13 | @Setter 14 | @Document 15 | public class UnitOfMeasure { 16 | 17 | @Id 18 | private String id; 19 | private String description; 20 | } 21 | -------------------------------------------------------------------------------- /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(String 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(String 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(String recipeId, String ingredientId); 11 | 12 | IngredientCommand saveIngredientCommand(IngredientCommand command); 13 | 14 | void deleteById(String recipeId, String 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 | 13 | import java.util.Optional; 14 | 15 | /** 16 | * Created by jt on 6/28/17. 17 | */ 18 | @Slf4j 19 | @Service 20 | public class IngredientServiceImpl implements IngredientService { 21 | 22 | private final IngredientToIngredientCommand ingredientToIngredientCommand; 23 | private final IngredientCommandToIngredient ingredientCommandToIngredient; 24 | private final RecipeRepository recipeRepository; 25 | private final UnitOfMeasureRepository unitOfMeasureRepository; 26 | 27 | public IngredientServiceImpl(IngredientToIngredientCommand ingredientToIngredientCommand, 28 | IngredientCommandToIngredient ingredientCommandToIngredient, 29 | RecipeRepository recipeRepository, UnitOfMeasureRepository unitOfMeasureRepository) { 30 | this.ingredientToIngredientCommand = ingredientToIngredientCommand; 31 | this.ingredientCommandToIngredient = ingredientCommandToIngredient; 32 | this.recipeRepository = recipeRepository; 33 | this.unitOfMeasureRepository = unitOfMeasureRepository; 34 | } 35 | 36 | @Override 37 | public IngredientCommand findByRecipeIdAndIngredientId(String recipeId, String ingredientId) { 38 | 39 | Optional recipeOptional = recipeRepository.findById(recipeId); 40 | 41 | if (!recipeOptional.isPresent()){ 42 | //todo impl error handling 43 | log.error("recipe id not found. Id: " + recipeId); 44 | } 45 | 46 | Recipe recipe = recipeOptional.get(); 47 | 48 | Optional ingredientCommandOptional = recipe.getIngredients().stream() 49 | .filter(ingredient -> ingredient.getId().equals(ingredientId)) 50 | .map( ingredient -> ingredientToIngredientCommand.convert(ingredient)).findFirst(); 51 | 52 | if(!ingredientCommandOptional.isPresent()){ 53 | //todo impl error handling 54 | log.error("Ingredient id not found: " + ingredientId); 55 | } 56 | 57 | //enhance command object with recipe id 58 | IngredientCommand ingredientCommand = ingredientCommandOptional.get(); 59 | ingredientCommand.setRecipeId(recipe.getId()); 60 | 61 | return ingredientCommandOptional.get(); 62 | } 63 | 64 | @Override 65 | public IngredientCommand saveIngredientCommand(IngredientCommand command) { 66 | Optional recipeOptional = recipeRepository.findById(command.getRecipeId()); 67 | 68 | if(!recipeOptional.isPresent()){ 69 | 70 | //todo toss error if not found! 71 | log.error("Recipe not found for id: " + command.getRecipeId()); 72 | return new IngredientCommand(); 73 | } else { 74 | Recipe recipe = recipeOptional.get(); 75 | 76 | Optional ingredientOptional = recipe 77 | .getIngredients() 78 | .stream() 79 | .filter(ingredient -> ingredient.getId().equals(command.getId())) 80 | .findFirst(); 81 | 82 | if(ingredientOptional.isPresent()){ 83 | Ingredient ingredientFound = ingredientOptional.get(); 84 | ingredientFound.setDescription(command.getDescription()); 85 | ingredientFound.setAmount(command.getAmount()); 86 | ingredientFound.setUom(unitOfMeasureRepository 87 | .findById(command.getUom().getId()) 88 | .orElseThrow(() -> new RuntimeException("UOM NOT FOUND"))); //todo address this 89 | } else { 90 | //add new Ingredient 91 | Ingredient ingredient = ingredientCommandToIngredient.convert(command); 92 | // ingredient.setRecipe(recipe); 93 | recipe.addIngredient(ingredient); 94 | } 95 | 96 | Recipe savedRecipe = recipeRepository.save(recipe); 97 | 98 | Optional savedIngredientOptional = savedRecipe.getIngredients().stream() 99 | .filter(recipeIngredients -> recipeIngredients.getId().equals(command.getId())) 100 | .findFirst(); 101 | 102 | //check by description 103 | if(!savedIngredientOptional.isPresent()){ 104 | //not totally safe... But best guess 105 | savedIngredientOptional = savedRecipe.getIngredients().stream() 106 | .filter(recipeIngredients -> recipeIngredients.getDescription().equals(command.getDescription())) 107 | .filter(recipeIngredients -> recipeIngredients.getAmount().equals(command.getAmount())) 108 | .filter(recipeIngredients -> recipeIngredients.getUom().getId().equals(command.getUom().getId())) 109 | .findFirst(); 110 | } 111 | 112 | //todo check for fail 113 | 114 | //enhance with id value 115 | IngredientCommand ingredientCommandSaved = ingredientToIngredientCommand.convert(savedIngredientOptional.get()); 116 | ingredientCommandSaved.setRecipeId(recipe.getId()); 117 | 118 | return ingredientCommandSaved; 119 | } 120 | 121 | } 122 | 123 | @Override 124 | public void deleteById(String recipeId, String idToDelete) { 125 | 126 | log.debug("Deleting ingredient: " + recipeId + ":" + idToDelete); 127 | 128 | Optional recipeOptional = recipeRepository.findById(recipeId); 129 | 130 | if(recipeOptional.isPresent()){ 131 | Recipe recipe = recipeOptional.get(); 132 | log.debug("found recipe"); 133 | 134 | Optional ingredientOptional = recipe 135 | .getIngredients() 136 | .stream() 137 | .filter(ingredient -> ingredient.getId().equals(idToDelete)) 138 | .findFirst(); 139 | 140 | if(ingredientOptional.isPresent()){ 141 | log.debug("found Ingredient"); 142 | Ingredient ingredientToDelete = ingredientOptional.get(); 143 | // ingredientToDelete.setRecipe(null); 144 | recipe.getIngredients().remove(ingredientOptional.get()); 145 | recipeRepository.save(recipe); 146 | } 147 | } else { 148 | log.debug("Recipe Id Not found. Id:" + recipeId); 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /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(String id); 16 | 17 | RecipeCommand findCommandById(String id); 18 | 19 | RecipeCommand saveRecipeCommand(RecipeCommand command); 20 | 21 | void deleteById(String 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(String id) { 45 | 46 | Optional recipeOptional = recipeRepository.findById(id); 47 | 48 | if (!recipeOptional.isPresent()) { 49 | throw new NotFoundException("Recipe Not Found. For ID value: " + id ); 50 | } 51 | 52 | return recipeOptional.get(); 53 | } 54 | 55 | @Override 56 | @Transactional 57 | public RecipeCommand findCommandById(String id) { 58 | 59 | RecipeCommand recipeCommand = recipeToRecipeCommand.convert(findById(id)); 60 | 61 | //enhance command object with id value 62 | if(recipeCommand.getIngredients() != null && recipeCommand.getIngredients().size() > 0){ 63 | recipeCommand.getIngredients().forEach(rc -> { 64 | rc.setRecipeId(recipeCommand.getId()); 65 | }); 66 | } 67 | 68 | return recipeCommand; 69 | } 70 | 71 | @Override 72 | @Transactional 73 | public RecipeCommand saveRecipeCommand(RecipeCommand command) { 74 | Recipe detachedRecipe = recipeCommandToRecipe.convert(command); 75 | 76 | Recipe savedRecipe = recipeRepository.save(detachedRecipe); 77 | log.debug("Saved RecipeId:" + savedRecipe.getId()); 78 | return recipeToRecipeCommand.convert(savedRecipe); 79 | } 80 | 81 | @Override 82 | public void deleteById(String idToDelete) { 83 | recipeRepository.deleteById(idToDelete); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /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 | spring.data.mongodb.port=0 2 | spring.data.mongodb.host=localhost -------------------------------------------------------------------------------- /src/main/resources/messages.properties: -------------------------------------------------------------------------------- 1 | # Set names of properties 2 | recipe.description=Description 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_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-reactive-mongo-recipe-app/03a153588aa0b5c05e651b977c5a87fb12ae6970/src/main/resources/static/images/guacamole400x400.jpg -------------------------------------------------------------------------------- /src/main/resources/static/images/guacamole400x400WithX.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springframeworkguru/spring5-reactive-mongo-recipe-app/03a153588aa0b5c05e651b977c5a87fb12ae6970/src/main/resources/static/images/guacamole400x400WithX.jpg -------------------------------------------------------------------------------- /src/main/resources/static/images/tacos400x400.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springframeworkguru/spring5-reactive-mongo-recipe-app/03a153588aa0b5c05e651b977c5a87fb12ae6970/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 |
165 | 166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |

Directions

174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |

Notes

185 |
186 |
187 |
188 |
189 | 190 |
191 |
192 |
193 |
194 | 195 |
196 |
197 |
198 |
199 |
200 | 201 | -------------------------------------------------------------------------------- /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/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 | //@Ignore 9 | @RunWith(SpringRunner.class) 10 | @SpringBootTest 11 | public class Spring5RecipeAppApplicationTests { 12 | 13 | @Test 14 | public void contextLoads() { 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /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("1"); 48 | 49 | when(recipeService.findCommandById(anyString())).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(anyString()); 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(anyString(), any()); 71 | } 72 | 73 | 74 | @Test 75 | public void renderImageFromDB() throws Exception { 76 | 77 | //given 78 | RecipeCommand command = new RecipeCommand(); 79 | command.setId("1"); 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(anyString())).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 | } -------------------------------------------------------------------------------- /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("1"); 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.anyString; 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(anyString())).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(anyString()); 61 | } 62 | 63 | @Test 64 | public void testShowIngredient() throws Exception { 65 | //given 66 | IngredientCommand ingredientCommand = new IngredientCommand(); 67 | 68 | //when 69 | when(ingredientService.findByRecipeIdAndIngredientId(anyString(), anyString())).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("1"); 83 | 84 | //when 85 | when(recipeService.findCommandById(anyString())).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(anyString()); 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(anyString(), anyString())).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("3"); 121 | command.setRecipeId("2"); 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(anyString(), anyString()); 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.anyString; 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("1"); 49 | 50 | when(recipeService.findById(anyString())).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(anyString())).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 testGetNewRecipeForm() throws Exception { 70 | RecipeCommand command = new RecipeCommand(); 71 | 72 | mockMvc.perform(get("/recipe/new")) 73 | .andExpect(status().isOk()) 74 | .andExpect(view().name("recipe/recipeform")) 75 | .andExpect(model().attributeExists("recipe")); 76 | } 77 | 78 | @Test 79 | public void testPostNewRecipeForm() throws Exception { 80 | RecipeCommand command = new RecipeCommand(); 81 | command.setId("2"); 82 | 83 | when(recipeService.saveRecipeCommand(any())).thenReturn(command); 84 | 85 | mockMvc.perform(post("/recipe") 86 | .contentType(MediaType.APPLICATION_FORM_URLENCODED) 87 | .param("id", "") 88 | .param("description", "some string") 89 | .param("directions", "some directions") 90 | ) 91 | .andExpect(status().is3xxRedirection()) 92 | .andExpect(view().name("redirect:/recipe/2/show")); 93 | } 94 | 95 | @Test 96 | public void testPostNewRecipeFormValidationFail() throws Exception { 97 | RecipeCommand command = new RecipeCommand(); 98 | command.setId("2"); 99 | 100 | when(recipeService.saveRecipeCommand(any())).thenReturn(command); 101 | 102 | mockMvc.perform(post("/recipe") 103 | .contentType(MediaType.APPLICATION_FORM_URLENCODED) 104 | .param("id", "") 105 | .param("cookTime", "3000") 106 | 107 | ) 108 | .andExpect(status().isOk()) 109 | .andExpect(model().attributeExists("recipe")) 110 | .andExpect(view().name("recipe/recipeform")); 111 | } 112 | 113 | @Test 114 | public void testGetUpdateView() throws Exception { 115 | RecipeCommand command = new RecipeCommand(); 116 | command.setId("2"); 117 | 118 | when(recipeService.findCommandById(anyString())).thenReturn(command); 119 | 120 | mockMvc.perform(get("/recipe/1/update")) 121 | .andExpect(status().isOk()) 122 | .andExpect(view().name("recipe/recipeform")) 123 | .andExpect(model().attributeExists("recipe")); 124 | } 125 | 126 | @Test 127 | public void testDeleteAction() throws Exception { 128 | mockMvc.perform(get("/recipe/1/delete")) 129 | .andExpect(status().is3xxRedirection()) 130 | .andExpect(view().name("redirect:/")); 131 | 132 | verify(recipeService, times(1)).deleteById(anyString()); 133 | } 134 | } -------------------------------------------------------------------------------- /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 String ID_VALUE = "1"; 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 String ID_VALUE = "1"; 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 String ID_VALUE = "1"; 20 | public static final String UOM_ID = "2"; 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 String UOM_ID = "2"; 23 | public static final String ID_VALUE = "1"; 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.setAmount(AMOUNT); 49 | ingredient.setDescription(DESCRIPTION); 50 | ingredient.setUom(null); 51 | //when 52 | IngredientCommand ingredientCommand = converter.convert(ingredient); 53 | //then 54 | assertNull(ingredientCommand.getUom()); 55 | assertEquals(ID_VALUE, ingredientCommand.getId()); 56 | assertEquals(AMOUNT, ingredientCommand.getAmount()); 57 | assertEquals(DESCRIPTION, ingredientCommand.getDescription()); 58 | } 59 | 60 | @Test 61 | public void testConvertWithUom() throws Exception { 62 | //given 63 | Ingredient ingredient = new Ingredient(); 64 | ingredient.setId(ID_VALUE); 65 | ingredient.setAmount(AMOUNT); 66 | ingredient.setDescription(DESCRIPTION); 67 | 68 | UnitOfMeasure uom = new UnitOfMeasure(); 69 | uom.setId(UOM_ID); 70 | 71 | ingredient.setUom(uom); 72 | //when 73 | IngredientCommand ingredientCommand = converter.convert(ingredient); 74 | //then 75 | assertEquals(ID_VALUE, ingredientCommand.getId()); 76 | assertNotNull(ingredientCommand.getUom()); 77 | assertEquals(UOM_ID, ingredientCommand.getUom().getId()); 78 | // assertEquals(RECIPE, ingredientCommand.get); 79 | assertEquals(AMOUNT, ingredientCommand.getAmount()); 80 | assertEquals(DESCRIPTION, ingredientCommand.getDescription()); 81 | } 82 | } -------------------------------------------------------------------------------- /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 String ID_VALUE = "1"; 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 String ID_VALUE = "1"; 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 String RECIPE_ID = "1"; 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 String CAT_ID_1 = "1"; 25 | public static final String CAT_ID2 = "2"; 26 | public static final String INGRED_ID_1 = "3"; 27 | public static final String INGRED_ID_2 = "4"; 28 | public static final String NOTES_ID = "4"; 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 String RECIPE_ID = "1"; 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 String CAT_ID_1 = "1"; 22 | public static final String CAT_ID2 = "2"; 23 | public static final String INGRED_ID_1 = "3"; 24 | public static final String INGRED_ID_2 = "4"; 25 | public static final String NOTES_ID = "9"; 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 String LONG_VALUE = "1"; 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 String LONG_VALUE = "1"; 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 | String idValue = "4"; 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.Ignore; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; 10 | import org.springframework.test.context.junit4.SpringRunner; 11 | 12 | import java.util.Optional; 13 | 14 | import static org.junit.Assert.assertEquals; 15 | 16 | /** 17 | * Created by jt on 6/17/17. 18 | */ 19 | @Ignore 20 | @RunWith(SpringRunner.class) 21 | @DataJpaTest 22 | public class UnitOfMeasureRepositoryIT { 23 | 24 | @Autowired 25 | UnitOfMeasureRepository unitOfMeasureRepository; 26 | 27 | @Before 28 | public void setUp() throws Exception { 29 | } 30 | 31 | @Test 32 | public void findByDescription() throws Exception { 33 | 34 | Optional uomOptional = unitOfMeasureRepository.findByDescription("Teaspoon"); 35 | 36 | assertEquals("Teaspoon", uomOptional.get().getDescription()); 37 | } 38 | 39 | @Test 40 | public void findByDescriptionCup() throws Exception { 41 | 42 | Optional uomOptional = unitOfMeasureRepository.findByDescription("Cup"); 43 | 44 | assertEquals("Cup", uomOptional.get().getDescription()); 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /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 | String id = "1"; 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(anyString())).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.anyString; 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("1"); 59 | 60 | Ingredient ingredient1 = new Ingredient(); 61 | ingredient1.setId("1"); 62 | 63 | Ingredient ingredient2 = new Ingredient(); 64 | ingredient2.setId("1"); 65 | 66 | Ingredient ingredient3 = new Ingredient(); 67 | ingredient3.setId("3"); 68 | 69 | recipe.addIngredient(ingredient1); 70 | recipe.addIngredient(ingredient2); 71 | recipe.addIngredient(ingredient3); 72 | Optional recipeOptional = Optional.of(recipe); 73 | 74 | when(recipeRepository.findById(anyString())).thenReturn(recipeOptional); 75 | 76 | //then 77 | IngredientCommand ingredientCommand = ingredientService.findByRecipeIdAndIngredientId("1", "3"); 78 | 79 | //when 80 | assertEquals("3", ingredientCommand.getId()); 81 | verify(recipeRepository, times(1)).findById(anyString()); 82 | } 83 | 84 | 85 | @Test 86 | public void testSaveRecipeCommand() throws Exception { 87 | //given 88 | IngredientCommand command = new IngredientCommand(); 89 | command.setId("3"); 90 | command.setRecipeId("2"); 91 | 92 | Optional recipeOptional = Optional.of(new Recipe()); 93 | 94 | Recipe savedRecipe = new Recipe(); 95 | savedRecipe.addIngredient(new Ingredient()); 96 | savedRecipe.getIngredients().iterator().next().setId("3"); 97 | 98 | when(recipeRepository.findById(anyString())).thenReturn(recipeOptional); 99 | when(recipeRepository.save(any())).thenReturn(savedRecipe); 100 | 101 | //when 102 | IngredientCommand savedCommand = ingredientService.saveIngredientCommand(command); 103 | 104 | //then 105 | assertEquals("3", savedCommand.getId()); 106 | verify(recipeRepository, times(1)).findById(anyString()); 107 | verify(recipeRepository, times(1)).save(any(Recipe.class)); 108 | 109 | } 110 | 111 | @Test 112 | public void testDeleteById() throws Exception { 113 | //given 114 | Recipe recipe = new Recipe(); 115 | Ingredient ingredient = new Ingredient(); 116 | ingredient.setId("3"); 117 | recipe.addIngredient(ingredient); 118 | Optional recipeOptional = Optional.of(recipe); 119 | 120 | when(recipeRepository.findById(anyString())).thenReturn(recipeOptional); 121 | 122 | //when 123 | ingredientService.deleteById("1", "3"); 124 | 125 | //then 126 | verify(recipeRepository, times(1)).findById(anyString()); 127 | verify(recipeRepository, times(1)).save(any(Recipe.class)); 128 | } 129 | } -------------------------------------------------------------------------------- /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 | 14 | import static org.junit.Assert.assertEquals; 15 | 16 | 17 | /** 18 | * Created by jt on 6/21/17. 19 | */ 20 | //@DataMongoTest 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("1"); 50 | Optional recipeOptional = Optional.of(recipe); 51 | 52 | when(recipeRepository.findById(anyString())).thenReturn(recipeOptional); 53 | 54 | Recipe recipeReturned = recipeService.findById("1"); 55 | 56 | assertNotNull("Null recipe returned", recipeReturned); 57 | verify(recipeRepository, times(1)).findById(anyString()); 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(anyString())).thenReturn(recipeOptional); 67 | 68 | Recipe recipeReturned = recipeService.findById("1"); 69 | 70 | //should go boom 71 | } 72 | 73 | @Test 74 | public void getRecipeCommandByIdTest() throws Exception { 75 | Recipe recipe = new Recipe(); 76 | recipe.setId("1"); 77 | Optional recipeOptional = Optional.of(recipe); 78 | 79 | when(recipeRepository.findById(anyString())).thenReturn(recipeOptional); 80 | 81 | RecipeCommand recipeCommand = new RecipeCommand(); 82 | recipeCommand.setId("1"); 83 | 84 | when(recipeToRecipeCommand.convert(any())).thenReturn(recipeCommand); 85 | 86 | RecipeCommand commandById = recipeService.findCommandById("1"); 87 | 88 | assertNotNull("Null recipe returned", commandById); 89 | verify(recipeRepository, times(1)).findById(anyString()); 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(anyString()); 107 | } 108 | 109 | @Test 110 | public void testDeleteById() throws Exception { 111 | 112 | //given 113 | String idToDelete = "2"; 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(anyString()); 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("1"); 39 | unitOfMeasures.add(uom1); 40 | 41 | UnitOfMeasure uom2 = new UnitOfMeasure(); 42 | uom2.setId("2"); 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 | } --------------------------------------------------------------------------------