From 4709922f110affd54209e096fa7ecb4d61ff7c03 Mon Sep 17 00:00:00 2001 From: marikattt <49302558+Marikattt@users.noreply.github.com> Date: Sun, 1 Jan 2023 19:57:30 +1100 Subject: [PATCH] feature: add Page Controller pattern (#2202) * feat: create page controller * add test * add documentation * fix: delete img file * fix: modify App, SignupMode, UserController, pom.xml, and Readme * fix: modify MVC files on page controller * fix: modify readme file --- page-controller/README.md | 162 ++++++++++++++++++ page-controller/etc/page-controller.urm.png | Bin 0 -> 75946 bytes page-controller/etc/page-controller.urm.puml | 59 +++++++ page-controller/pom.xml | 101 +++++++++++ .../com.iluwatar.page.controller/App.java | 48 ++++++ .../SignupController.java | 68 ++++++++ .../SignupModel.java | 44 +++++ .../SignupView.java | 49 ++++++ .../UserController.java | 51 ++++++ .../UserModel.java | 40 +++++ .../UserView.java | 42 +++++ .../src/main/resources/application.properties | 25 +++ .../src/main/resources/templates/signup.html | 27 +++ .../src/main/resources/templates/user.html | 12 ++ .../com/iluwatar/page/controller/AppTest.java | 38 ++++ .../page/controller/SignupControllerTest.java | 57 ++++++ .../page/controller/SignupModelTest.java | 63 +++++++ .../page/controller/UserControllerTest.java | 36 ++++ .../page/controller/UserModelTest.java | 27 +++ 19 files changed, 949 insertions(+) create mode 100644 page-controller/README.md create mode 100644 page-controller/etc/page-controller.urm.png create mode 100644 page-controller/etc/page-controller.urm.puml create mode 100644 page-controller/pom.xml create mode 100644 page-controller/src/main/java/com.iluwatar.page.controller/App.java create mode 100644 page-controller/src/main/java/com.iluwatar.page.controller/SignupController.java create mode 100644 page-controller/src/main/java/com.iluwatar.page.controller/SignupModel.java create mode 100644 page-controller/src/main/java/com.iluwatar.page.controller/SignupView.java create mode 100644 page-controller/src/main/java/com.iluwatar.page.controller/UserController.java create mode 100644 page-controller/src/main/java/com.iluwatar.page.controller/UserModel.java create mode 100644 page-controller/src/main/java/com.iluwatar.page.controller/UserView.java create mode 100644 page-controller/src/main/resources/application.properties create mode 100644 page-controller/src/main/resources/templates/signup.html create mode 100644 page-controller/src/main/resources/templates/user.html create mode 100644 page-controller/src/test/java/com/iluwatar/page/controller/AppTest.java create mode 100644 page-controller/src/test/java/com/iluwatar/page/controller/SignupControllerTest.java create mode 100644 page-controller/src/test/java/com/iluwatar/page/controller/SignupModelTest.java create mode 100644 page-controller/src/test/java/com/iluwatar/page/controller/UserControllerTest.java create mode 100644 page-controller/src/test/java/com/iluwatar/page/controller/UserModelTest.java diff --git a/page-controller/README.md b/page-controller/README.md new file mode 100644 index 000000000..6a0e35d1e --- /dev/null +++ b/page-controller/README.md @@ -0,0 +1,162 @@ +--- +title: Page Controller +categories: Structural +language: en +tags: +- Decoupling +--- + +## Name / classification + +Page Controller + +## Intent + +It is an approach of one page leading to one logical file that handles actions or requests on a website. + +## Explanation + +Real-world example + +> In a shopping website, there is a signup page to register a user profile. +> After finishing to signup, the signup page will be redirected to a user page to show the user's registered information. + +In plain words + +> Page controller manages HTTP requests and data in a specific page using MVC idea. +> The idea is that one page contains one Controller that handles Model and View. + +**Programmatic Example** + +Here's Signup controller when a user signup their information for a website. + +```java +@Slf4j +@Controller +@Component +public class SignupController { + SignupView view = new SignupView(); + /** + * Signup Controller can handle http request and decide which model and view use. + */ + SignupController() { + } + + /** + * Handle http GET request. + */ + @GetMapping("/signup") + public String getSignup() { + return view.display(); + } + + /** + * Handle http POST request and access model and view. + */ + @PostMapping("/signup") + public String create(SignupModel form, RedirectAttributes redirectAttributes) { + LOGGER.info(form.getName()); + LOGGER.info(form.getEmail()); + redirectAttributes.addAttribute("name", form.getName()); + redirectAttributes.addAttribute("email", form.getEmail()); + redirectAttributes.addFlashAttribute("userInfo", form); + return view.redirect(form); + } +} +``` +Here's Signup model and view that are handled by Signup controller. + +```java +@Component +@Getter +@Setter +public class SignupModel { + private String name; + private String email; + private String password; + + public SignupModel() { + } +} +``` + +```java +@Slf4j +public class SignupView { + public SignupView() { + } + + public String display() { + LOGGER.info("display signup front page"); + return "/signup"; + } + + /** + * redirect to user page. + */ + public String redirect(SignupModel form) { + LOGGER.info("Redirect to user page with " + "name " + form.getName() + " email " + form.getEmail()); + return "redirect:/user"; + } +} +``` + +Here's User Controller to handle Get request in a user page. + +```java +@Slf4j +@Controller +public class UserController { + UserView view = new UserView(); + + public UserController() {} + + /** + * Handle http GET request and access view and model. + */ + @GetMapping("/user") + public String getUserPath(SignupModel form, Model model) { + model.addAttribute("name", form.getName()); + model.addAttribute("email", form.getEmail()); + return view.display(form); + } +} +``` + +Here's User Model and View that are handled by User controller. +```java +@Getter +@Setter +public class UserModel { + private String name; + private String email; + + public UserModel() {} +} +``` + +```java +@Slf4j +public class UserView { + /** + * displaying command to generate html. + * @param user model content. + */ + public String display(SignupModel user) { + LOGGER.info("display user html" + " name " + user.getName() + " email " + user.getEmail()); + return "/user"; + } +} +``` + +## Class diagram +![alt text](./etc/page-controller.urm.png) + +## Applicability +Use the Page Controller pattern when +- you implement a site where most controller logic is simple +- you implement a site where particular actions are handled with a particular server page + +## Credits +- [Page Controller](https://www.martinfowler.com/eaaCatalog/pageController.html) +- [Pattern of Enterprise Application Architecture](https://www.martinfowler.com/books/eaa.html) \ No newline at end of file diff --git a/page-controller/etc/page-controller.urm.png b/page-controller/etc/page-controller.urm.png new file mode 100644 index 0000000000000000000000000000000000000000..d46bb018755b5ff6aeee6add3a708d65e56838d7 GIT binary patch literal 75946 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 literal 0 HcmV?d00001 diff --git a/page-controller/etc/page-controller.urm.puml b/page-controller/etc/page-controller.urm.puml new file mode 100644 index 000000000..c152ee019 --- /dev/null +++ b/page-controller/etc/page-controller.urm.puml @@ -0,0 +1,59 @@ +@startuml +package com.iluwatar.page.controller { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class SignupController { + - LOGGER : Logger {static} + ~ view : SignupView + ~ SignupController() + + create(form : SignupModel, redirectAttributes : RedirectAttributes) : String + + getSignup() : String + } + class SignupModel { + - email : String + - name : String + - password : String + + SignupModel() + + SignupModel(name : String, email : String, password : String) + + getEmail() : String + + getName() : String + + getPassword() : String + + setEmail(email : String) + + setName(name : String) + + setPassword(password : String) + } + class SignupView { + - LOGGER : Logger {static} + + SignupView() + + display() : String + + redirect(form : SignupModel) : String + } + class UserController { + - LOGGER : Logger {static} + ~ view : UserView + + UserController() + + getUserPath(form : SignupModel, model : Model) : String + } + class UserModel { + - email : String + - name : String + + UserModel() + + getEmail() : String + + getName() : String + + setEmail(email : String) + + setName(name : String) + } + class UserView { + - LOGGER : Logger {static} + + UserView() + + display(user : SignupModel) : String + } +} +UserController --> "-view" UserView +UserController --> "-model" UserModel +SignupController --> "-view" SignupView +SignupController --> "-model" SignupModel +@enduml \ No newline at end of file diff --git a/page-controller/pom.xml b/page-controller/pom.xml new file mode 100644 index 000000000..1e75f7f86 --- /dev/null +++ b/page-controller/pom.xml @@ -0,0 +1,101 @@ + + + + 4.0.0 + page-controller + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + + + org.springframework + spring-webmvc + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework + spring-context + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.mockito + mockito-core + test + + + org.springframework + spring-test + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.page.controller.App + + + + + + + + + diff --git a/page-controller/src/main/java/com.iluwatar.page.controller/App.java b/page-controller/src/main/java/com.iluwatar.page.controller/App.java new file mode 100644 index 000000000..278c01396 --- /dev/null +++ b/page-controller/src/main/java/com.iluwatar.page.controller/App.java @@ -0,0 +1,48 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.page.controller; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * Page Controller pattern is utilized when we want to simplify relationship in a dynamic website. + * It is an approach of one front page leading to one logical file that handles HTTP requests and actions. + * In this example, we build a website with signup page handling an input form with Signup Controller, Signup View, and Signup Model + * and after signup, it is redirected to a user page handling with User Controller, User View, and User Model. +*/ +@Slf4j +@SpringBootApplication +public class App { + /** + * Program entry point. + * + * @param args command line args + */ + public static void main(final String[] args) { + SpringApplication.run(App.class, args); + } +} diff --git a/page-controller/src/main/java/com.iluwatar.page.controller/SignupController.java b/page-controller/src/main/java/com.iluwatar.page.controller/SignupController.java new file mode 100644 index 000000000..2efdc9ef1 --- /dev/null +++ b/page-controller/src/main/java/com.iluwatar.page.controller/SignupController.java @@ -0,0 +1,68 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.page.controller; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +/** + * Signup Controller. + */ +@Slf4j +@Controller +@Component +public class SignupController { + SignupView view = new SignupView(); + /** + * Signup Controller can handle http request and decide which model and view use. + */ + SignupController() { + } + + /** + * Handle http GET request. + */ + @GetMapping("/signup") + public String getSignup() { + return view.display(); + } + + /** + * Handle http POST request and access model and view. + */ + @PostMapping("/signup") + public String create(SignupModel form, RedirectAttributes redirectAttributes) { + LOGGER.info(form.getName()); + LOGGER.info(form.getEmail()); + redirectAttributes.addAttribute("name", form.getName()); + redirectAttributes.addAttribute("email", form.getEmail()); + redirectAttributes.addFlashAttribute("userInfo", form); + return view.redirect(form); + } +} diff --git a/page-controller/src/main/java/com.iluwatar.page.controller/SignupModel.java b/page-controller/src/main/java/com.iluwatar.page.controller/SignupModel.java new file mode 100644 index 000000000..97229c402 --- /dev/null +++ b/page-controller/src/main/java/com.iluwatar.page.controller/SignupModel.java @@ -0,0 +1,44 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.page.controller; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.stereotype.Component; + +/** + * ignup model. + */ +@Component +@Getter +@Setter +public class SignupModel { + private String name; + private String email; + private String password; + + public SignupModel() { + } +} diff --git a/page-controller/src/main/java/com.iluwatar.page.controller/SignupView.java b/page-controller/src/main/java/com.iluwatar.page.controller/SignupView.java new file mode 100644 index 000000000..5d127ea2a --- /dev/null +++ b/page-controller/src/main/java/com.iluwatar.page.controller/SignupView.java @@ -0,0 +1,49 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.page.controller; + +import lombok.extern.slf4j.Slf4j; + +/** + * Signup View. + */ +@Slf4j +public class SignupView { + public SignupView() { + } + + public String display() { + LOGGER.info("display signup front page"); + return "/signup"; + } + + /** + * redirect to user page. + */ + public String redirect(SignupModel form) { + LOGGER.info("Redirect to user page with " + "name " + form.getName() + " email " + form.getEmail()); + return "redirect:/user"; + } +} diff --git a/page-controller/src/main/java/com.iluwatar.page.controller/UserController.java b/page-controller/src/main/java/com.iluwatar.page.controller/UserController.java new file mode 100644 index 000000000..e3bcca6f1 --- /dev/null +++ b/page-controller/src/main/java/com.iluwatar.page.controller/UserController.java @@ -0,0 +1,51 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.page.controller; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; + +/** + * User Controller. + */ +@Slf4j +@Controller +public class UserController { + private final UserView view = new UserView(); + + public UserController() {} + + /** + * Handle http GET request and access view and model. + */ + @GetMapping("/user") + public String getUserPath(SignupModel form, Model model) { + model.addAttribute("name", form.getName()); + model.addAttribute("email", form.getEmail()); + return view.display(form); + } +} diff --git a/page-controller/src/main/java/com.iluwatar.page.controller/UserModel.java b/page-controller/src/main/java/com.iluwatar.page.controller/UserModel.java new file mode 100644 index 000000000..86e9548a2 --- /dev/null +++ b/page-controller/src/main/java/com.iluwatar.page.controller/UserModel.java @@ -0,0 +1,40 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.page.controller; + +import lombok.Getter; +import lombok.Setter; + +/** + * User model. + */ +@Getter +@Setter +public class UserModel { + private String name; + private String email; + + public UserModel() {} +} diff --git a/page-controller/src/main/java/com.iluwatar.page.controller/UserView.java b/page-controller/src/main/java/com.iluwatar.page.controller/UserView.java new file mode 100644 index 000000000..3f4469d7d --- /dev/null +++ b/page-controller/src/main/java/com.iluwatar.page.controller/UserView.java @@ -0,0 +1,42 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.page.controller; + +import lombok.extern.slf4j.Slf4j; + +/** + * User view class generating html file. + */ +@Slf4j +public class UserView { + /** + * displaying command to generate html. + * @param user model content. + */ + public String display(SignupModel user) { + LOGGER.info("display user html" + " name " + user.getName() + " email " + user.getEmail()); + return "/user"; + } +} diff --git a/page-controller/src/main/resources/application.properties b/page-controller/src/main/resources/application.properties new file mode 100644 index 000000000..59cc8812c --- /dev/null +++ b/page-controller/src/main/resources/application.properties @@ -0,0 +1,25 @@ +# +# The MIT License +# Copyright © 2014-2021 Ilkka Seppälä +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +#spring.thymeleaf.mode=HTML + +server.port=51515 diff --git a/page-controller/src/main/resources/templates/signup.html b/page-controller/src/main/resources/templates/signup.html new file mode 100644 index 000000000..56c5487fe --- /dev/null +++ b/page-controller/src/main/resources/templates/signup.html @@ -0,0 +1,27 @@ + + + + + Signup + + + +

Sign Up

+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ diff --git a/page-controller/src/main/resources/templates/user.html b/page-controller/src/main/resources/templates/user.html new file mode 100644 index 000000000..70130cef6 --- /dev/null +++ b/page-controller/src/main/resources/templates/user.html @@ -0,0 +1,12 @@ + + + + + User + + + +

Your Information

+

Name:

+

Email:

+ \ No newline at end of file diff --git a/page-controller/src/test/java/com/iluwatar/page/controller/AppTest.java b/page-controller/src/test/java/com/iluwatar/page/controller/AppTest.java new file mode 100644 index 000000000..9dcbfe3f8 --- /dev/null +++ b/page-controller/src/test/java/com/iluwatar/page/controller/AppTest.java @@ -0,0 +1,38 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.page.controller; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +/** + * Application test + */ +public class AppTest { + @Test + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); + } +} diff --git a/page-controller/src/test/java/com/iluwatar/page/controller/SignupControllerTest.java b/page-controller/src/test/java/com/iluwatar/page/controller/SignupControllerTest.java new file mode 100644 index 000000000..7260c24d4 --- /dev/null +++ b/page-controller/src/test/java/com/iluwatar/page/controller/SignupControllerTest.java @@ -0,0 +1,57 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.page.controller; + +import org.junit.jupiter.api.Test; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; +import org.springframework.web.servlet.mvc.support.RedirectAttributesModelMap; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Test for Signup Controller + */ +public class SignupControllerTest { + + /** + * Verify if user can sign up and redirect to user page + */ + @Test + void testSignup() { + var controller = new SignupController(); + controller.getSignup(); + + RedirectAttributes redirectAttributes = new RedirectAttributesModelMap(); + String redirectPath = controller.create(retrieveSignupData(), redirectAttributes); + assertEquals("redirect:/user", redirectPath); + } + + public static SignupModel retrieveSignupData() { + SignupModel model = new SignupModel(); + model.setName("Lily"); + model.setEmail("lily@email.com"); + model.setPassword("password1234"); + return model; + } +} diff --git a/page-controller/src/test/java/com/iluwatar/page/controller/SignupModelTest.java b/page-controller/src/test/java/com/iluwatar/page/controller/SignupModelTest.java new file mode 100644 index 000000000..46e60eb94 --- /dev/null +++ b/page-controller/src/test/java/com/iluwatar/page/controller/SignupModelTest.java @@ -0,0 +1,63 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.page.controller; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Test for Signup Model + */ +public class SignupModelTest { + /** + * Verify if a user can set a name properly + */ + @Test + void testSetName() { + SignupModel model = new SignupModel(); + model.setName("Lily"); + assertEquals("Lily", model.getName()); + } + + /** + * Verify if a user can set an email properly + */ + @Test + void testSetEmail() { + SignupModel model = new SignupModel(); + model.setEmail("Lily@email"); + assertEquals("Lily@email", model.getEmail()); + } + + /** + * Verify if a user can set a password properly + */ + @Test + void testSetPassword() { + SignupModel model = new SignupModel(); + model.setPassword("password1234"); + assertEquals("password1234", model.getPassword()); + } +} diff --git a/page-controller/src/test/java/com/iluwatar/page/controller/UserControllerTest.java b/page-controller/src/test/java/com/iluwatar/page/controller/UserControllerTest.java new file mode 100644 index 000000000..d20d5e036 --- /dev/null +++ b/page-controller/src/test/java/com/iluwatar/page/controller/UserControllerTest.java @@ -0,0 +1,36 @@ +package com.iluwatar.page.controller; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@ExtendWith(SpringExtension.class) +@SpringBootTest +@AutoConfigureMockMvc +public class UserControllerTest { + private UserController userController; + + @Autowired + MockMvc mockMvc; + + /** + * Verify if view and model are directed properly + */ + @Test + void testGetUserPath () throws Exception { + this.mockMvc.perform(get("/user") + .param("name", "Lily") + .param("email", "Lily@email.com")) + .andExpect(status().isOk()) + .andExpect(model().attribute("name", "Lily")) + .andExpect(model().attribute("email", "Lily@email.com")) + .andReturn(); + } +} diff --git a/page-controller/src/test/java/com/iluwatar/page/controller/UserModelTest.java b/page-controller/src/test/java/com/iluwatar/page/controller/UserModelTest.java new file mode 100644 index 000000000..42e8e0c30 --- /dev/null +++ b/page-controller/src/test/java/com/iluwatar/page/controller/UserModelTest.java @@ -0,0 +1,27 @@ +package com.iluwatar.page.controller; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class UserModelTest { + /** + * Verify if a user can set a name properly + */ + @Test + void testSetName() { + UserModel model = new UserModel(); + model.setName("Lily"); + assertEquals("Lily", model.getName()); + } + + /** + * Verify if a user can set an email properly + */ + @Test + void testSetEmail() { + UserModel model = new UserModel(); + model.setEmail("Lily@email"); + assertEquals("Lily@email", model.getEmail()); + } +}