├── .gitignore
├── README.md
├── Step01.md
├── Step02.md
├── Step03.md
├── Step04.md
├── Step05.md
├── Step06.md
├── Step07.md
├── Step07.zip
├── Step08.md
├── Step08.zip
├── Step09.md
├── Step10.md
├── Step11.md
├── Step12.md
├── Step12.zip
├── Step13.md
├── Step13.zip
├── Step14.md
├── Step15.md
├── Step15.zip
├── Step16.md
├── Step16.zip
├── Step17.md
├── Step18.md
├── Step18.zip
├── Step19.md
├── Step19.zip
├── Step20.md
├── Step20.zip
├── Step21.md
├── Step21.zip
├── Step22.md
├── Step22.zip
├── Step23.md
├── Step23.zip
├── Step24.md
├── Step25.md
├── Step25.zip
├── Step26.md
├── Step27.md
├── Step27.zip
├── StepReference.md
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── in28minutes
│ │ └── springboot
│ │ └── web
│ │ ├── SpringBootFirstWebApplication.java
│ │ ├── controller
│ │ ├── ErrorController.java
│ │ ├── LogoutController.java
│ │ ├── TodoController.java
│ │ └── WelcomeController.java
│ │ ├── model
│ │ └── Todo.java
│ │ ├── security
│ │ └── SecurityConfiguration.java
│ │ └── service
│ │ └── TodoService.java
├── resources
│ └── application.properties
└── webapp
│ └── WEB-INF
│ └── jsp
│ ├── common
│ ├── footer.jspf
│ ├── header.jspf
│ └── navigation.jspf
│ ├── error.jsp
│ ├── list-todos.jsp
│ ├── todo.jsp
│ └── welcome.jsp
└── test
└── java
└── com
└── in28minutes
└── springboot
└── web
└── SpringBootFirstWebApplicationTests.java
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | # Package Files #
14 | *.jar
15 | *.war
16 | *.ear
17 | *.zip
18 | *.tar.gz
19 | *.rar
20 | *.cmd
21 | *.classpath
22 | *.settings
23 | *.project
24 | *.mvn
25 | mvnw
26 | target
27 | *.DS_Store
28 |
29 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
30 | hs_err_pid*
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Your First Web Application with Spring Boot
2 | Develop your first web application with Spring Boot in more than 25 steps
3 | * [Installing Eclipse, Maven and Java](#installing-tools)
4 | * [Course Overview](#course-overview)
5 | * [About in28Minutes](#about-in28minutes)
6 | - [Our Beliefs](#our-beliefs)
7 | - [Our Approach](#our-approach)
8 | - [Find Us](#useful-links)
9 | - [Other Courses](#other-courses)
10 |
11 | ## Installing Tools
12 | - PDF : https://github.com/in28minutes/SpringIn28Minutes/blob/master/InstallationGuide-JavaEclipseAndMaven_v2.pdf
13 | - Video : https://www.youtube.com/playlist?list=PLBBog2r6uMCSmMVTW_QmDLyASBvovyAO3
14 | - GIT Repository : https://github.com/in28minutes/getting-started-in-5-steps
15 |
16 | ## Course Overview
17 |
18 | ### Introduction
19 | Developing your first Spring Boot Web Application is fun.
20 |
21 | Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can “just run”. We take an opinionated view of the Spring platform and third-party libraries so you can get started with minimum fuss. Most Spring Boot applications need very little Spring configuration.
22 |
23 | In this course, you will learn the basics developing a Basic Todo Management Application using Spring Boot with Login and Logout functionalities.
24 |
25 | You will build the website step by step - in more than 25 steps. This course would be a perfect first step as an introduction to Java Web Application Development.
26 |
27 | You will be using Spring (Dependency Management), Spring MVC, Spring Boot, Spring Security (Authentication and Authorization), BootStrap (Styling Pages), Maven (dependencies management), Eclipse (IDE) and Tomcat Embedded Web Server. We will help you set up each one of these.
28 |
29 | You will learn about
30 | - Basics of Spring Boot
31 | - Basics of Autoconfiguration and Spring Boot Magic
32 | - DispatcherServlet
33 | - Basic Todo Management Application with Login/Logout
34 | - Model, Controllers, ViewResolver and Filters
35 | - Forms - DataBinding, Validation
36 | - Annotation based approach - @RequestParam, @ModelAttribute, @SessionAttributes etc
37 | - Bootstrap to style the page
38 | - Spring Security
39 | - Exception Handling
40 |
41 | ### Step Wise Details
42 | - Step 01: Basic Spring Boot Web Application Setup
43 | - Step 02: First Spring MVC Controller, @ResponseBody, @Controller
44 | - Step 03: Demystifying some of the Spring Boot magic
45 | - Step 04: Redirect to Login JSP - LoginController, @ResponseBody and View Resolver
46 | - Step 05: Show userid and password on the welcome page - ModelMap and @RequestParam
47 | - Step 06: DispatcherServlet and Spring MVC Flow
48 | - Step 07: Your First HTML form
49 | - Step 08: Add hard-coded validation of userid and password
50 | - Step 09: Magic of Spring
51 | - Step 10: Create TodoController and list-todos view. Make TodoService a @Service and inject it.
52 | - Step 11: Architecture of Web Applications
53 | - Step 12: Session vs Model vs Request - @SessionAttributes
54 | - Step 13: Add new todo
55 | - Step 14: Display Todos in a table using JSTL Tags
56 | - Step 15: Bootstrap for Page Formatting using webjars
57 | - Step 16: Let's delete a Todo
58 | - Step 17: Format Add Todo Page and Adding Basic HTML5 form validation
59 | - Step 18: Introduce JSR 349 Validations using Hibernate Validator - First Command Bean.
60 | - Step 19: Updating a todo
61 | - Step 20: Let's add a Target Date for Todo - Use initBinder to Handle Date Fields
62 | - Step 21: JSP Fragments and Navigation Bar
63 | - Step 22: Preparing for Spring Security
64 | - Step 23: Initial Spring Security Setup
65 | - Step 24: Refactor and add Logout Functionality using Spring Security
66 | - Step 25: Exception Handling
67 |
68 | ---
69 |
70 | - We do NOT interact with a Database in this Beginner’s Course.
71 | - We will be building a traditional JSP based web application in this course.
72 |
73 | ---
74 |
75 | ### Expectations
76 | - You should know Java. You should understand usage of Annotations.
77 | - You should understand the basics of Spring framework.
78 | - You are NOT expected to have any experience with Eclipse or Maven.
79 | - We will help you install Eclipse and get up and running with Maven.
80 |
81 | ## Let's have some fun
82 | - What are we waiting for?
83 | - Let's have some fun building a web application Spring Boot in 25 Steps.
84 | - I had fun creating this course and hope you would too.
85 | - Thanks for your interest in Our Course
86 | - I hope you’re as excited as I am!
87 | - If you’re ready to learn more and sign up for the course,
88 | - go ahead and hit that Enroll button,
89 | - or take a test drive by using the Free Preview feature.
90 | - See you in the course!
91 |
92 | ## Getting Started
93 | - Eclipse - https://courses.in28minutes.com/p/eclipse-tutorial-for-beginners
94 | - Maven - https://courses.in28minutes.com/p/maven-tutorial-for-beginners-in-5-steps
95 | - JUnit - https://courses.in28minutes.com/p/junit-tutorial-for-beginners
96 | - Mockito - https://courses.in28minutes.com/p/mockito-for-beginner-in-5-steps
97 |
98 | ## About in28Minutes
99 |
100 | At in28Minutes, we ask ourselves one question everyday
101 | > How do we create more amazing course experiences?
102 | > We use 80-20 Rule. We discuss 20% things used 80% of time in depth.
103 |
104 | We are creating amazing learning experiences for learning Spring Boot with AWS, Azure, GCP, Docker, Kubernetes and Full Stack. 300,000 Learners rely on our expertise. [Find out more.... ](https://github.com/in28minutes/learn#best-selling-courses)
105 |
106 | 
107 |
--------------------------------------------------------------------------------
/Step01.md:
--------------------------------------------------------------------------------
1 | ## What You Will Learn during this Step:
2 | - Lets create a simple web application using Spring Boot
3 | - Lets run the Spring Boot Application
4 | - There is a lot of magic happening in here! We will take a deep dive into the magic in Step 03.
5 |
6 | ## Files List
7 |
8 | ### pom.xml
9 |
10 | ```xml
11 |
12 |
14 | 4.0.0
15 |
16 | com.in28minutes.springboot.web
17 | spring-boot-first-web-application
18 | 0.0.1-SNAPSHOT
19 | jar
20 |
21 | spring-boot-first-web-application
22 | Demo project for Spring Boot
23 |
24 |
25 | org.springframework.boot
26 | spring-boot-starter-parent
27 | 1.4.3.RELEASE
28 |
29 |
30 |
31 |
32 | UTF-8
33 | UTF-8
34 | 1.8
35 |
36 |
37 |
38 |
39 | org.springframework.boot
40 | spring-boot-starter-web
41 |
42 |
43 | org.springframework.boot
44 | spring-boot-devtools
45 | runtime
46 |
47 |
48 | org.springframework.boot
49 | spring-boot-starter-test
50 | test
51 |
52 |
53 |
54 |
55 |
56 |
57 | org.springframework.boot
58 | spring-boot-maven-plugin
59 |
60 |
61 |
62 |
63 |
64 | ```
65 | ---
66 | ### src/main/java/com/in28minutes/springboot/web/SpringBootFirstWebApplication.java
67 |
68 | ```java
69 | package com.in28minutes.springboot.web;
70 |
71 | import org.springframework.boot.SpringApplication;
72 | import org.springframework.boot.autoconfigure.SpringBootApplication;
73 |
74 | @SpringBootApplication
75 | public class SpringBootFirstWebApplication {
76 |
77 | public static void main(String[] args) {
78 | SpringApplication.run(SpringBootFirstWebApplication.class, args);
79 | }
80 | }
81 | ```
82 | ---
83 | ### src/main/resources/application.properties
84 |
85 | ```
86 | ```
87 | ---
88 | ### src/test/java/com/in28minutes/springboot/web/SpringBootFirstWebApplicationTests.java
89 |
90 | ```java
91 | package com.in28minutes.springboot.web;
92 |
93 | import org.junit.Test;
94 | import org.junit.runner.RunWith;
95 | import org.springframework.boot.test.context.SpringBootTest;
96 | import org.springframework.test.context.junit4.SpringRunner;
97 |
98 | @RunWith(SpringRunner.class)
99 | @SpringBootTest
100 | public class SpringBootFirstWebApplicationTests {
101 |
102 | @Test
103 | public void contextLoads() {
104 | }
105 |
106 | }
107 | ```
108 | ---
109 | ### todo.txt
110 |
111 | ```
112 | Spring Boot Starter Parent
113 | Spring Boot Starter Web
114 | @SpringBootApplication
115 | Auto Configuration
116 | ```
117 | ---
118 |
--------------------------------------------------------------------------------
/Step02.md:
--------------------------------------------------------------------------------
1 | ## What You Will Learn during this Step:
2 | - @RequestMapping(value = "/login", method = RequestMethod.GET)
3 | - http://localhost:8080/login
4 | - Why @ResponseBody?
5 | - Important of RequestMapping method
6 | - How do web applications work? Request and Response
7 | - Browser sends Http Request to Web Server
8 | - Code in Web Server => Input:HttpRequest, Output: HttpResponse
9 | - Web Server responds with Http Response
10 |
11 | ## Useful Snippets and References
12 | First Snippet
13 | ```
14 | @Controller
15 | public class LoginController {
16 |
17 | @RequestMapping(value = "/login")
18 | @ResponseBody
19 | public String sayHello() {
20 | return "Hello World dummy";
21 | }
22 |
23 | }
24 | ```
25 | ### src/main/resources/application.properties
26 |
27 | ```
28 | logging.level.org.springframework.web: DEBUG
29 | ```
30 |
31 |
32 | ## Exercises
33 | - Create another method with a different mapping returning some other text!
34 |
35 | ## Files List
36 |
37 | ### pom.xml
38 |
39 | ```xml
40 |
41 |
43 | 4.0.0
44 |
45 | com.in28minutes.springboot.web
46 | spring-boot-first-web-application
47 | 0.0.1-SNAPSHOT
48 | jar
49 |
50 | spring-boot-first-web-application
51 | Demo project for Spring Boot
52 |
53 |
54 | org.springframework.boot
55 | spring-boot-starter-parent
56 | 1.4.3.RELEASE
57 |
58 |
59 |
60 |
61 | UTF-8
62 | UTF-8
63 | 1.8
64 |
65 |
66 |
67 |
68 | org.springframework.boot
69 | spring-boot-starter-web
70 |
71 |
72 | org.springframework.boot
73 | spring-boot-devtools
74 | runtime
75 |
76 |
77 | org.springframework.boot
78 | spring-boot-starter-test
79 | test
80 |
81 |
82 |
83 |
84 |
85 |
86 | org.springframework.boot
87 | spring-boot-maven-plugin
88 |
89 |
90 |
91 |
92 |
93 | ```
94 | ---
95 | ### src/main/java/com/in28minutes/springboot/web/controller/LoginController.java
96 |
97 | ```java
98 | package com.in28minutes.springboot.web.controller;
99 |
100 | import org.springframework.stereotype.Controller;
101 | import org.springframework.web.bind.annotation.RequestMapping;
102 |
103 | @Controller
104 | public class LoginController {
105 |
106 | @RequestMapping("/login")
107 | public String loginMessage(){
108 | return "Hello World";
109 | }
110 | }
111 | ```
112 | ---
113 | ### src/main/java/com/in28minutes/springboot/web/SpringBootFirstWebApplication.java
114 |
115 | ```java
116 | package com.in28minutes.springboot.web;
117 |
118 | import org.springframework.boot.SpringApplication;
119 | import org.springframework.boot.autoconfigure.SpringBootApplication;
120 |
121 | @SpringBootApplication
122 | public class SpringBootFirstWebApplication {
123 |
124 | public static void main(String[] args) {
125 | SpringApplication.run(SpringBootFirstWebApplication.class, args);
126 | }
127 | }
128 | ```
129 | ---
130 | ### src/main/resources/application.properties
131 |
132 | ```
133 | logging.level.org.springframework.web: DEBUG
134 | ```
135 | ---
136 | ### src/test/java/com/in28minutes/springboot/web/SpringBootFirstWebApplicationTests.java
137 |
138 | ```java
139 | package com.in28minutes.springboot.web;
140 |
141 | import org.junit.Test;
142 | import org.junit.runner.RunWith;
143 | import org.springframework.boot.test.context.SpringBootTest;
144 | import org.springframework.test.context.junit4.SpringRunner;
145 |
146 | @RunWith(SpringRunner.class)
147 | @SpringBootTest
148 | public class SpringBootFirstWebApplicationTests {
149 |
150 | @Test
151 | public void contextLoads() {
152 | }
153 |
154 | }
155 | ```
156 | ---
157 | ### todo.txt
158 |
159 | ```
160 | Spring Boot Starter Parent
161 | Spring Boot Starter Web
162 | @SpringBootApplication
163 | Auto Configuration
164 | ```
165 | ---
166 |
--------------------------------------------------------------------------------
/Step03.md:
--------------------------------------------------------------------------------
1 | ## What You Will Learn during this Step:
2 | - Demystifying some of the magic
3 | - Spring Boot Starter Parent
4 | - Spring Boot Starter Web
5 | - Embedded Tomcat
6 | - Dev Tools
7 |
--------------------------------------------------------------------------------
/Step04.md:
--------------------------------------------------------------------------------
1 | ## What You Will Learn during this Step:
2 | - Your First JSP
3 | - There is a bit of setup before we get there!
4 | - Introduction to View Resolver
5 |
6 | ## Useful Snippets and References
7 | First Snippet - /src/main/webapp/WEB-INF/jsp/login.jsp
8 | ```
9 |
10 |
11 | Yahoo!!
12 |
13 |
14 | My First JSP!!!
15 |
16 |
17 | ```
18 |
19 | Second Snippet - /src/main/resources/application.properties
20 | ```
21 | spring.mvc.view.prefix: /WEB-INF/jsp/
22 | spring.mvc.view.suffix: .jsp
23 | logging.level.: DEBUG
24 | ```
25 |
26 | Third Snippet : To enable jsp support in embedded tomcat server!
27 | ```
28 |
29 | org.apache.tomcat.embed
30 | tomcat-embed-jasper
31 | provided
32 |
33 |
34 | ```
35 |
36 | ## Exercises
37 | - Create a new jsp and a new controller method to redirect to it!
38 | - Play around!
39 |
40 | ## Files List
41 |
42 | ### pom.xml
43 |
44 | ```xml
45 |
46 |
48 | 4.0.0
49 |
50 | com.in28minutes.springboot.web
51 | spring-boot-first-web-application
52 | 0.0.1-SNAPSHOT
53 | jar
54 |
55 | spring-boot-first-web-application
56 | Demo project for Spring Boot
57 |
58 |
59 | org.springframework.boot
60 | spring-boot-starter-parent
61 | 1.4.3.RELEASE
62 |
63 |
64 |
65 |
66 | UTF-8
67 | UTF-8
68 | 1.8
69 |
70 |
71 |
72 |
73 | org.springframework.boot
74 | spring-boot-starter-web
75 |
76 |
77 | org.springframework.boot
78 | spring-boot-devtools
79 | runtime
80 |
81 |
82 | org.apache.tomcat.embed
83 | tomcat-embed-jasper
84 | provided
85 |
86 |
87 | org.springframework.boot
88 | spring-boot-starter-test
89 | test
90 |
91 |
92 |
93 |
94 |
95 |
96 | org.springframework.boot
97 | spring-boot-maven-plugin
98 |
99 |
100 |
101 |
102 |
103 | ```
104 | ---
105 | ### src/main/java/com/in28minutes/springboot/web/controller/LoginController.java
106 |
107 | ```java
108 | package com.in28minutes.springboot.web.controller;
109 |
110 | import org.springframework.stereotype.Controller;
111 | import org.springframework.web.bind.annotation.RequestMapping;
112 | import org.springframework.web.bind.annotation.ResponseBody;
113 |
114 | @Controller
115 | public class LoginController {
116 |
117 | @RequestMapping("/login")
118 | public String loginMessage(){
119 | return "login";
120 | }
121 | }
122 | ```
123 | ---
124 | ### src/main/java/com/in28minutes/springboot/web/SpringBootFirstWebApplication.java
125 |
126 | ```java
127 | package com.in28minutes.springboot.web;
128 |
129 | import org.springframework.boot.SpringApplication;
130 | import org.springframework.boot.autoconfigure.SpringBootApplication;
131 |
132 | @SpringBootApplication
133 | public class SpringBootFirstWebApplication {
134 |
135 | public static void main(String[] args) {
136 | SpringApplication.run(SpringBootFirstWebApplication.class, args);
137 | }
138 | }
139 | ```
140 | ---
141 | ### src/main/resources/application.properties
142 |
143 | ```
144 | spring.mvc.view.prefix=/WEB-INF/jsp/
145 | spring.mvc.view.suffix=.jsp
146 | logging.level.org.springframework.web=DEBUG
147 | ```
148 | ---
149 | ### src/main/webapp/WEB-INF/jsp/login.jsp
150 |
151 | ```
152 |
153 |
154 |
155 | First Web Application
156 |
157 |
158 |
159 | My First JSP!!
160 |
161 |
162 |
163 | ```
164 | ---
165 | ### src/test/java/com/in28minutes/springboot/web/SpringBootFirstWebApplicationTests.java
166 |
167 | ```java
168 | package com.in28minutes.springboot.web;
169 |
170 | import org.junit.Test;
171 | import org.junit.runner.RunWith;
172 | import org.springframework.boot.test.context.SpringBootTest;
173 | import org.springframework.test.context.junit4.SpringRunner;
174 |
175 | @RunWith(SpringRunner.class)
176 | @SpringBootTest
177 | public class SpringBootFirstWebApplicationTests {
178 |
179 | @Test
180 | public void contextLoads() {
181 | }
182 |
183 | }
184 | ```
185 | ---
186 | ### todo.txt
187 |
188 | ```
189 | Spring Boot Starter Parent
190 | Spring Boot Starter Web
191 | @SpringBootApplication
192 | Auto Configuration
193 |
194 | Dispatcher Servlet
195 |
196 | /login => "login"
197 |
198 | "login" => src/main/webapp/WEB-INF/jsp/login.jsp
199 |
200 |
201 | Search for a view named "login"
202 |
203 |
204 |
205 | /login => LoginController
206 | ```
207 | ---
208 |
--------------------------------------------------------------------------------
/Step05.md:
--------------------------------------------------------------------------------
1 | ## What You Will Learn during this Step:
2 | - You first GET Parameter.
3 | - Problem with using GET
4 |
5 | ## Snippets
6 | ```
7 | ModelMap model
8 | model.put("name", name);
9 | My First JSP!!! My name is ${name}
10 | ```
11 |
12 | ## Files List
13 |
14 | ### pom.xml
15 |
16 | ```xml
17 |
18 |
20 | 4.0.0
21 |
22 | com.in28minutes.springboot.web
23 | spring-boot-first-web-application
24 | 0.0.1-SNAPSHOT
25 | jar
26 |
27 | spring-boot-first-web-application
28 | Demo project for Spring Boot
29 |
30 |
31 | org.springframework.boot
32 | spring-boot-starter-parent
33 | 1.4.3.RELEASE
34 |
35 |
36 |
37 |
38 | UTF-8
39 | UTF-8
40 | 1.8
41 |
42 |
43 |
44 |
45 | org.springframework.boot
46 | spring-boot-starter-web
47 |
48 |
49 |
50 | org.apache.tomcat.embed
51 | tomcat-embed-jasper
52 | provided
53 |
54 |
55 |
56 | org.springframework.boot
57 | spring-boot-devtools
58 | runtime
59 |
60 |
61 |
62 | org.springframework.boot
63 | spring-boot-starter-test
64 | test
65 |
66 |
67 |
68 |
69 |
70 |
71 | org.springframework.boot
72 | spring-boot-maven-plugin
73 |
74 |
75 |
76 |
77 |
78 | ```
79 | ---
80 | ### src/main/java/com/in28minutes/springboot/web/controller/LoginController.java
81 |
82 | ```java
83 | package com.in28minutes.springboot.web.controller;
84 |
85 | import org.springframework.stereotype.Controller;
86 | import org.springframework.ui.ModelMap;
87 | import org.springframework.web.bind.annotation.RequestMapping;
88 | import org.springframework.web.bind.annotation.RequestParam;
89 |
90 | @Controller
91 | public class LoginController {
92 |
93 | //Model
94 |
95 | @RequestMapping("/login")
96 | public String loginMessage(@RequestParam String name, ModelMap model){
97 | model.put("name", name);
98 | return "login";
99 | }
100 | }
101 | ```
102 | ---
103 | ### src/main/java/com/in28minutes/springboot/web/SpringBootFirstWebApplication.java
104 |
105 | ```java
106 | package com.in28minutes.springboot.web;
107 |
108 | import org.springframework.boot.SpringApplication;
109 | import org.springframework.boot.autoconfigure.SpringBootApplication;
110 |
111 | @SpringBootApplication
112 | public class SpringBootFirstWebApplication {
113 |
114 | public static void main(String[] args) {
115 | SpringApplication.run(SpringBootFirstWebApplication.class, args);
116 | }
117 | }
118 | ```
119 | ---
120 | ### src/main/resources/application.properties
121 |
122 | ```
123 | spring.mvc.view.prefix=/WEB-INF/jsp/
124 | spring.mvc.view.suffix=.jsp
125 | logging.level.org.springframework.web=DEBUG
126 | ```
127 | ---
128 | ### src/main/webapp/WEB-INF/jsp/login.jsp
129 |
130 | ```
131 |
132 |
133 |
134 | First Web Application
135 |
136 |
137 |
138 | My First JSP!! Welcome ${name}!
139 |
140 |
141 |
142 | ```
143 | ---
144 | ### src/test/java/com/in28minutes/springboot/web/SpringBootFirstWebApplicationTests.java
145 |
146 | ```java
147 | package com.in28minutes.springboot.web;
148 |
149 | import org.junit.Test;
150 | import org.junit.runner.RunWith;
151 | import org.springframework.boot.test.context.SpringBootTest;
152 | import org.springframework.test.context.junit4.SpringRunner;
153 |
154 | @RunWith(SpringRunner.class)
155 | @SpringBootTest
156 | public class SpringBootFirstWebApplicationTests {
157 |
158 | @Test
159 | public void contextLoads() {
160 | }
161 |
162 | }
163 | ```
164 | ---
165 | ### todo.txt
166 |
167 | ```
168 | Spring Boot Starter Parent
169 | Spring Boot Starter Web
170 | @SpringBootApplication
171 | Auto Configuration
172 |
173 | Dispatcher Servlet
174 |
175 | /login => "login"
176 |
177 | "login" => src/main/webapp/WEB-INF/jsp/login.jsp
178 |
179 |
180 | Search for a view named "login"
181 |
182 |
183 |
184 | /login => LoginController
185 | ```
186 | ---
187 |
--------------------------------------------------------------------------------
/Step06.md:
--------------------------------------------------------------------------------
1 | ## What You Will Learn during this Step:
2 | - Understand importance of DispatcherServlet.
3 |
4 | ## Spring MVC Request Flow
5 | - DispatcherServlet receives HTTP Request.
6 | - DispatcherServlet identifies the right Controller based on the URL.
7 | - Controller executes Business Logic.
8 | - Controller returns a) Model b) View Name Back to DispatcherServlet.
9 | - DispatcherServlet identifies the correct view (ViewResolver).
10 | - DispatcherServlet makes the model available to view and executes it.
11 | - DispatcherServlet returns HTTP Response Back.
12 | - Flow : http://docs.spring.io/spring-framework/docs/2.0.8/reference/images/mvc.png
13 |
--------------------------------------------------------------------------------
/Step07.md:
--------------------------------------------------------------------------------
1 | ## What You Will Learn during this Step:
2 | - Lets get the name from the user in a form
3 |
4 | ## Useful Snippets and References
5 | First Snippet
6 | ```
7 | @RequestMapping(value = "/login", method = RequestMethod.GET)
8 | public String showLoginPage(ModelMap model, @RequestParam String name) {
9 | return "login";
10 | }
11 |
12 | @RequestMapping(value = "/login", method = RequestMethod.POST)
13 | public String handleLogin(ModelMap model, @RequestParam String name) {
14 | model.put("name", name);
15 | return "welcome";
16 | }
17 |
18 | ```
19 | Second Snippet
20 | ```
21 |
24 |
25 | ```
26 |
27 | ## Files List
28 |
29 | ### pom.xml
30 |
31 | ```xml
32 |
33 |
35 | 4.0.0
36 |
37 | com.in28minutes.springboot.web
38 | spring-boot-first-web-application
39 | 0.0.1-SNAPSHOT
40 | jar
41 |
42 | spring-boot-first-web-application
43 | Demo project for Spring Boot
44 |
45 |
46 | org.springframework.boot
47 | spring-boot-starter-parent
48 | 1.4.3.RELEASE
49 |
50 |
51 |
52 |
53 | UTF-8
54 | UTF-8
55 | 1.8
56 |
57 |
58 |
59 |
60 | org.springframework.boot
61 | spring-boot-starter-web
62 |
63 |
64 |
65 | org.apache.tomcat.embed
66 | tomcat-embed-jasper
67 | provided
68 |
69 |
70 |
71 | org.springframework.boot
72 | spring-boot-devtools
73 | runtime
74 |
75 |
76 |
77 | org.springframework.boot
78 | spring-boot-starter-test
79 | test
80 |
81 |
82 |
83 |
84 |
85 |
86 | org.springframework.boot
87 | spring-boot-maven-plugin
88 |
89 |
90 |
91 |
92 |
93 | ```
94 | ---
95 | ### src/main/java/com/in28minutes/springboot/web/controller/LoginController.java
96 |
97 | ```java
98 | package com.in28minutes.springboot.web.controller;
99 |
100 | import org.springframework.stereotype.Controller;
101 | import org.springframework.ui.ModelMap;
102 | import org.springframework.web.bind.annotation.RequestMapping;
103 | import org.springframework.web.bind.annotation.RequestMethod;
104 | import org.springframework.web.bind.annotation.RequestParam;
105 |
106 | @Controller
107 | public class LoginController {
108 |
109 | @RequestMapping(value="/login", method = RequestMethod.GET)
110 | public String showLoginPage(ModelMap model){
111 | return "login";
112 | }
113 |
114 | @RequestMapping(value="/login", method = RequestMethod.POST)
115 | public String showWelcomePage(ModelMap model, @RequestParam String name){
116 | model.put("name", name);
117 | return "welcome";
118 | }
119 |
120 | }
121 | ```
122 | ---
123 | ### src/main/java/com/in28minutes/springboot/web/SpringBootFirstWebApplication.java
124 |
125 | ```java
126 | package com.in28minutes.springboot.web;
127 |
128 | import org.springframework.boot.SpringApplication;
129 | import org.springframework.boot.autoconfigure.SpringBootApplication;
130 |
131 | @SpringBootApplication
132 | public class SpringBootFirstWebApplication {
133 |
134 | public static void main(String[] args) {
135 | SpringApplication.run(SpringBootFirstWebApplication.class, args);
136 | }
137 | }
138 | ```
139 | ---
140 | ### src/main/resources/application.properties
141 |
142 | ```
143 | spring.mvc.view.prefix=/WEB-INF/jsp/
144 | spring.mvc.view.suffix=.jsp
145 | logging.level.org.springframework.web=DEBUG
146 | ```
147 | ---
148 | ### src/main/webapp/WEB-INF/jsp/login.jsp
149 |
150 | ```
151 |
152 |
153 |
154 | First Web Application
155 |
156 |
157 |
158 |
163 |
164 |
165 |
166 | ```
167 | ---
168 | ### src/main/webapp/WEB-INF/jsp/welcome.jsp
169 |
170 | ```
171 |
172 |
173 |
174 | First Web Application
175 |
176 |
177 |
178 | Welcome ${name}!!
179 |
180 |
181 |
182 | ```
183 | ---
184 | ### src/test/java/com/in28minutes/springboot/web/SpringBootFirstWebApplicationTests.java
185 |
186 | ```java
187 | package com.in28minutes.springboot.web;
188 |
189 | import org.junit.Test;
190 | import org.junit.runner.RunWith;
191 | import org.springframework.boot.test.context.SpringBootTest;
192 | import org.springframework.test.context.junit4.SpringRunner;
193 |
194 | @RunWith(SpringRunner.class)
195 | @SpringBootTest
196 | public class SpringBootFirstWebApplicationTests {
197 |
198 | @Test
199 | public void contextLoads() {
200 | }
201 |
202 | }
203 | ```
204 | ---
205 | ### todo.txt
206 |
207 | ```
208 | Spring Boot Starter Parent
209 | Spring Boot Starter Web
210 | @SpringBootApplication
211 | Auto Configuration
212 |
213 | Dispatcher Servlet
214 |
215 | /login => "login"
216 |
217 | "login" => src/main/webapp/WEB-INF/jsp/login.jsp
218 |
219 |
220 | Search for a view named "login"
221 |
222 |
223 |
224 | /login => LoginController
225 | ```
226 | ---
227 |
--------------------------------------------------------------------------------
/Step07.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/in28minutes/SpringBootWebApplicationStepByStep/7611e5a098e49023ee03ce1446e465a4c567da45/Step07.zip
--------------------------------------------------------------------------------
/Step08.md:
--------------------------------------------------------------------------------
1 | ## What You Will Learn during this Step:
2 | - Add validation for userid and password
3 | - Hard coded validation!!
4 |
5 | ## Useful Snippets and References
6 | First Snippet
7 | ```
8 | package com.in28minutes.springboot.web.service;
9 |
10 | import org.springframework.stereotype.Component;
11 |
12 | @Component
13 | public class LoginService {
14 | public boolean validateUser(String user, String password) {
15 | return user.equalsIgnoreCase("in28Minutes") && password.equals("dummy");
16 | }
17 | }
18 |
19 | ```
20 | Second Snippet
21 | ```
22 | @Autowired
23 | private LoginService service;
24 |
25 | @RequestMapping(value = "/login", method = RequestMethod.POST)
26 | public String handleLogin(ModelMap model, @RequestParam String name,
27 | @RequestParam String password) {
28 |
29 | boolean isValidUser = service.validateUser(name, password);
30 |
31 | if (isValidUser) {
32 | model.put("name", name);
33 | return "welcome";
34 | } else {
35 | model.put("errorMessage", "Invalid Credentials!!");
36 | return "login";
37 | }
38 | }
39 | ```
40 |
41 | ## Files List
42 |
43 | ### pom.xml
44 |
45 | ```xml
46 |
47 |
49 | 4.0.0
50 |
51 | com.in28minutes.springboot.web
52 | spring-boot-first-web-application
53 | 0.0.1-SNAPSHOT
54 | jar
55 |
56 | spring-boot-first-web-application
57 | Demo project for Spring Boot
58 |
59 |
60 | org.springframework.boot
61 | spring-boot-starter-parent
62 | 1.4.3.RELEASE
63 |
64 |
65 |
66 |
67 | UTF-8
68 | UTF-8
69 | 1.8
70 |
71 |
72 |
73 |
74 | org.springframework.boot
75 | spring-boot-starter-web
76 |
77 |
78 |
79 | org.apache.tomcat.embed
80 | tomcat-embed-jasper
81 | provided
82 |
83 |
84 |
85 | org.springframework.boot
86 | spring-boot-devtools
87 | runtime
88 |
89 |
90 |
91 | org.springframework.boot
92 | spring-boot-starter-test
93 | test
94 |
95 |
96 |
97 |
98 |
99 |
100 | org.springframework.boot
101 | spring-boot-maven-plugin
102 |
103 |
104 |
105 |
106 |
107 | ```
108 | ---
109 | ### src/main/java/com/in28minutes/springboot/web/controller/LoginController.java
110 |
111 | ```java
112 | package com.in28minutes.springboot.web.controller;
113 |
114 | import org.springframework.beans.factory.annotation.Autowired;
115 | import org.springframework.stereotype.Controller;
116 | import org.springframework.ui.ModelMap;
117 | import org.springframework.web.bind.annotation.RequestMapping;
118 | import org.springframework.web.bind.annotation.RequestMethod;
119 | import org.springframework.web.bind.annotation.RequestParam;
120 |
121 | import com.in28minutes.springboot.web.service.LoginService;
122 |
123 | @Controller
124 | public class LoginController {
125 |
126 | @Autowired
127 | LoginService service;
128 |
129 | @RequestMapping(value="/login", method = RequestMethod.GET)
130 | public String showLoginPage(ModelMap model){
131 | return "login";
132 | }
133 |
134 | @RequestMapping(value="/login", method = RequestMethod.POST)
135 | public String showWelcomePage(ModelMap model, @RequestParam String name, @RequestParam String password){
136 | boolean isValidUser = service.validateUser(name, password);
137 |
138 | if (!isValidUser) {
139 | model.put("errorMessage", "Invalid Credentials");
140 | return "login";
141 | }
142 |
143 | model.put("name", name);
144 | model.put("password", password);
145 |
146 | return "welcome";
147 | }
148 |
149 | }
150 | ```
151 | ---
152 | ### src/main/java/com/in28minutes/springboot/web/service/LoginService.java
153 |
154 | ```java
155 | package com.in28minutes.springboot.web.service;
156 |
157 | import org.springframework.stereotype.Component;
158 |
159 | @Component
160 | public class LoginService {
161 |
162 | public boolean validateUser(String userid, String password) {
163 | // in28minutes, dummy
164 | return userid.equalsIgnoreCase("in28minutes")
165 | && password.equalsIgnoreCase("dummy");
166 | }
167 |
168 | }
169 | ```
170 | ---
171 | ### src/main/java/com/in28minutes/springboot/web/SpringBootFirstWebApplication.java
172 |
173 | ```java
174 | package com.in28minutes.springboot.web;
175 |
176 | import org.springframework.boot.SpringApplication;
177 | import org.springframework.boot.autoconfigure.SpringBootApplication;
178 |
179 | @SpringBootApplication
180 | public class SpringBootFirstWebApplication {
181 |
182 | public static void main(String[] args) {
183 | SpringApplication.run(SpringBootFirstWebApplication.class, args);
184 | }
185 | }
186 | ```
187 | ---
188 | ### src/main/resources/application.properties
189 |
190 | ```
191 | spring.mvc.view.prefix=/WEB-INF/jsp/
192 | spring.mvc.view.suffix=.jsp
193 | logging.level.org.springframework.web=DEBUG
194 | ```
195 | ---
196 | ### src/main/webapp/WEB-INF/jsp/login.jsp
197 |
198 | ```
199 |
200 |
201 |
202 | First Web Application
203 |
204 |
205 |
206 | ${errorMessage}
207 |
212 |
213 |
214 |
215 | ```
216 | ---
217 | ### src/main/webapp/WEB-INF/jsp/welcome.jsp
218 |
219 | ```
220 |
221 |
222 |
223 | First Web Application
224 |
225 |
226 |
227 | Welcome ${name}!!
228 |
229 |
230 |
231 | ```
232 | ---
233 | ### src/test/java/com/in28minutes/springboot/web/SpringBootFirstWebApplicationTests.java
234 |
235 | ```java
236 | package com.in28minutes.springboot.web;
237 |
238 | import org.junit.Test;
239 | import org.junit.runner.RunWith;
240 | import org.springframework.boot.test.context.SpringBootTest;
241 | import org.springframework.test.context.junit4.SpringRunner;
242 |
243 | @RunWith(SpringRunner.class)
244 | @SpringBootTest
245 | public class SpringBootFirstWebApplicationTests {
246 |
247 | @Test
248 | public void contextLoads() {
249 | }
250 |
251 | }
252 | ```
253 | ---
254 | ### todo.txt
255 |
256 | ```
257 | Component, Service, Repository, Controller
258 | Autowired
259 | ComponentScan
260 |
261 |
262 | Spring Boot Starter Parent
263 | Spring Boot Starter Web
264 | @SpringBootApplication
265 | Auto Configuration
266 |
267 | Dispatcher Servlet
268 |
269 | /login => "login"
270 |
271 | "login" => src/main/webapp/WEB-INF/jsp/login.jsp
272 |
273 |
274 | Search for a view named "login"
275 |
276 |
277 |
278 | /login => LoginController
279 | ```
280 | ---
281 |
--------------------------------------------------------------------------------
/Step08.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/in28minutes/SpringBootWebApplicationStepByStep/7611e5a098e49023ee03ce1446e465a4c567da45/Step08.zip
--------------------------------------------------------------------------------
/Step09.md:
--------------------------------------------------------------------------------
1 | ## What You Will Learn during this Step:
2 | - Magic of Spring
3 | - Learn about Spring Auto-wiring and Dependency Management.
4 | - @Autowired, @Component
5 |
--------------------------------------------------------------------------------
/Step10.md:
--------------------------------------------------------------------------------
1 | ## What we will do:
2 | - Create TodoController and list-todos.jsp
3 | - Make TodoService a @Service and inject it
4 |
5 | ## Pending for Next Step
6 | - ${name} is not available in list-todos.jsp
7 | - in28Minutes is hardcoded in TodoController
8 |
9 | ## Snippets
10 |
11 | Snippet - /src/main/java/com/in28minutes/springboot/web/model/Todo.java
12 | ```
13 | package com.in28minutes.springboot.web.model;
14 |
15 | import java.util.Date;
16 |
17 | public class Todo {
18 | private int id;
19 | private String user;
20 | private String desc;
21 | private Date targetDate;
22 | private boolean isDone;
23 |
24 | public Todo(int id, String user, String desc, Date targetDate,
25 | boolean isDone) {
26 | super();
27 | this.id = id;
28 | this.user = user;
29 | this.desc = desc;
30 | this.targetDate = targetDate;
31 | this.isDone = isDone;
32 | }
33 |
34 | public int getId() {
35 | return id;
36 | }
37 |
38 | public void setId(int id) {
39 | this.id = id;
40 | }
41 |
42 | public String getUser() {
43 | return user;
44 | }
45 |
46 | public void setUser(String user) {
47 | this.user = user;
48 | }
49 |
50 | public String getDesc() {
51 | return desc;
52 | }
53 |
54 | public void setDesc(String desc) {
55 | this.desc = desc;
56 | }
57 |
58 | public Date getTargetDate() {
59 | return targetDate;
60 | }
61 |
62 | public void setTargetDate(Date targetDate) {
63 | this.targetDate = targetDate;
64 | }
65 |
66 | public boolean isDone() {
67 | return isDone;
68 | }
69 |
70 | public void setDone(boolean isDone) {
71 | this.isDone = isDone;
72 | }
73 |
74 | @Override
75 | public int hashCode() {
76 | final int prime = 31;
77 | int result = 1;
78 | result = prime * result + id;
79 | return result;
80 | }
81 |
82 | @Override
83 | public boolean equals(Object obj) {
84 | if (this == obj) {
85 | return true;
86 | }
87 | if (obj == null) {
88 | return false;
89 | }
90 | if (getClass() != obj.getClass()) {
91 | return false;
92 | }
93 | Todo other = (Todo) obj;
94 | if (id != other.id) {
95 | return false;
96 | }
97 | return true;
98 | }
99 |
100 | @Override
101 | public String toString() {
102 | return String.format(
103 | "Todo [id=%s, user=%s, desc=%s, targetDate=%s, isDone=%s]", id,
104 | user, desc, targetDate, isDone);
105 | }
106 |
107 | }
108 | ```
109 |
110 | Snippet - /src/main/java/com/in28minutes/springboot/web/service/TodoService.java
111 | ```
112 | package com.in28minutes.springboot.web.service;
113 |
114 | import java.util.ArrayList;
115 | import java.util.Date;
116 | import java.util.Iterator;
117 | import java.util.List;
118 |
119 | import org.springframework.stereotype.Service;
120 |
121 | import com.in28minutes.springboot.web.model.Todo;
122 |
123 | @Service
124 | public class TodoService {
125 | private static List todos = new ArrayList();
126 | private static int todoCount = 3;
127 |
128 | static {
129 | todos.add(new Todo(1, "in28Minutes", "Learn Spring MVC", new Date(),
130 | false));
131 | todos.add(new Todo(2, "in28Minutes", "Learn Struts", new Date(), false));
132 | todos.add(new Todo(3, "in28Minutes", "Learn Hibernate", new Date(),
133 | false));
134 | }
135 |
136 | public List retrieveTodos(String user) {
137 | List filteredTodos = new ArrayList();
138 | for (Todo todo : todos) {
139 | if (todo.getUser().equals(user)) {
140 | filteredTodos.add(todo);
141 | }
142 | }
143 | return filteredTodos;
144 | }
145 |
146 | public void addTodo(String name, String desc, Date targetDate,
147 | boolean isDone) {
148 | todos.add(new Todo(++todoCount, name, desc, targetDate, isDone));
149 | }
150 |
151 | public void deleteTodo(int id) {
152 | Iterator iterator = todos.iterator();
153 | while (iterator.hasNext()) {
154 | Todo todo = iterator.next();
155 | if (todo.getId() == id) {
156 | iterator.remove();
157 | }
158 | }
159 | }
160 | }
161 | ```
162 |
--------------------------------------------------------------------------------
/Step11.md:
--------------------------------------------------------------------------------
1 | ## What we will do:
2 | - Lets discuss about Architecture of web applications
3 |
--------------------------------------------------------------------------------
/Step12.md:
--------------------------------------------------------------------------------
1 | ## What You Will Learn during this Step:
2 | - Session vs Model vs Request.
3 | - Be cautious about what you use Session for.
4 | - @SessionAttributes("name") and how it works?
5 | - Why use Model? "adding elements directly to the HttpServletRequest (as request attributes) would seem to serve the same purpose. The reason to do this is obvious when taking a look at one of the requirements we have set for the MVC framework: It should be as view-agnostic as possible, which means we’d like to be able to incorporate view technologies not bound to the HttpServletRequest as well." - Rod Johnson et. al’s book Professional Java Development with the Spring Framework
6 | - Spring documentation states that the @SessionAttributes annotation “list the names of model attributes which should be transparently stored in the session or some conversational storage.”
7 |
8 | ## Useful Snippets and References
9 | First Snippet
10 | ```
11 | @SessionAttributes("name")
12 | ```
13 |
14 | ## Files List
15 |
16 | ### pom.xml
17 |
18 | ```xml
19 |
20 |
22 | 4.0.0
23 |
24 | com.in28minutes.springboot.web
25 | spring-boot-first-web-application
26 | 0.0.1-SNAPSHOT
27 | jar
28 |
29 | spring-boot-first-web-application
30 | Demo project for Spring Boot
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter-parent
35 | 1.4.3.RELEASE
36 |
37 |
38 |
39 |
40 | UTF-8
41 | UTF-8
42 | 1.8
43 |
44 |
45 |
46 |
47 | org.springframework.boot
48 | spring-boot-starter-web
49 |
50 |
51 |
52 | org.apache.tomcat.embed
53 | tomcat-embed-jasper
54 | provided
55 |
56 |
57 |
58 | org.springframework.boot
59 | spring-boot-devtools
60 | runtime
61 |
62 |
63 |
64 | org.springframework.boot
65 | spring-boot-starter-test
66 | test
67 |
68 |
69 |
70 |
71 |
72 |
73 | org.springframework.boot
74 | spring-boot-maven-plugin
75 |
76 |
77 |
78 |
79 |
80 | ```
81 | ---
82 | ### src/main/java/com/in28minutes/springboot/web/controller/LoginController.java
83 |
84 | ```java
85 | package com.in28minutes.springboot.web.controller;
86 |
87 | import org.springframework.beans.factory.annotation.Autowired;
88 | import org.springframework.stereotype.Controller;
89 | import org.springframework.ui.ModelMap;
90 | import org.springframework.web.bind.annotation.RequestMapping;
91 | import org.springframework.web.bind.annotation.RequestMethod;
92 | import org.springframework.web.bind.annotation.RequestParam;
93 | import org.springframework.web.bind.annotation.SessionAttributes;
94 |
95 | import com.in28minutes.springboot.web.service.LoginService;
96 |
97 | @Controller
98 | @SessionAttributes("name")
99 | public class LoginController {
100 |
101 | @Autowired
102 | LoginService service;
103 |
104 | @RequestMapping(value="/login", method = RequestMethod.GET)
105 | public String showLoginPage(ModelMap model){
106 | return "login";
107 | }
108 |
109 | @RequestMapping(value="/login", method = RequestMethod.POST)
110 | public String showWelcomePage(ModelMap model, @RequestParam String name, @RequestParam String password){
111 |
112 | boolean isValidUser = service.validateUser(name, password);
113 |
114 | if (!isValidUser) {
115 | model.put("errorMessage", "Invalid Credentials");
116 | return "login";
117 | }
118 |
119 | model.put("name", name);
120 | model.put("password", password);
121 |
122 | return "welcome";
123 | }
124 |
125 | }
126 | ```
127 | ---
128 | ### src/main/java/com/in28minutes/springboot/web/controller/TodoController.java
129 |
130 | ```java
131 | package com.in28minutes.springboot.web.controller;
132 |
133 | import org.springframework.beans.factory.annotation.Autowired;
134 | import org.springframework.stereotype.Controller;
135 | import org.springframework.ui.ModelMap;
136 | import org.springframework.web.bind.annotation.RequestMapping;
137 | import org.springframework.web.bind.annotation.RequestMethod;
138 | import org.springframework.web.bind.annotation.RequestParam;
139 | import org.springframework.web.bind.annotation.SessionAttributes;
140 |
141 | import com.in28minutes.springboot.web.service.LoginService;
142 | import com.in28minutes.springboot.web.service.TodoService;
143 |
144 | @Controller
145 | @SessionAttributes("name")
146 | public class TodoController {
147 |
148 | @Autowired
149 | TodoService service;
150 |
151 | @RequestMapping(value="/list-todos", method = RequestMethod.GET)
152 | public String showTodos(ModelMap model){
153 | String name = (String) model.get("name");
154 | model.put("todos", service.retrieveTodos(name));
155 | return "list-todos";
156 | }
157 | }
158 | ```
159 | ---
160 | ### src/main/java/com/in28minutes/springboot/web/model/Todo.java
161 |
162 | ```java
163 | package com.in28minutes.springboot.web.model;
164 |
165 | import java.util.Date;
166 |
167 | public class Todo {
168 | private int id;
169 | private String user;
170 | private String desc;
171 | private Date targetDate;
172 | private boolean isDone;
173 |
174 | public Todo(int id, String user, String desc, Date targetDate,
175 | boolean isDone) {
176 | super();
177 | this.id = id;
178 | this.user = user;
179 | this.desc = desc;
180 | this.targetDate = targetDate;
181 | this.isDone = isDone;
182 | }
183 |
184 | public int getId() {
185 | return id;
186 | }
187 |
188 | public void setId(int id) {
189 | this.id = id;
190 | }
191 |
192 | public String getUser() {
193 | return user;
194 | }
195 |
196 | public void setUser(String user) {
197 | this.user = user;
198 | }
199 |
200 | public String getDesc() {
201 | return desc;
202 | }
203 |
204 | public void setDesc(String desc) {
205 | this.desc = desc;
206 | }
207 |
208 | public Date getTargetDate() {
209 | return targetDate;
210 | }
211 |
212 | public void setTargetDate(Date targetDate) {
213 | this.targetDate = targetDate;
214 | }
215 |
216 | public boolean isDone() {
217 | return isDone;
218 | }
219 |
220 | public void setDone(boolean isDone) {
221 | this.isDone = isDone;
222 | }
223 |
224 | @Override
225 | public int hashCode() {
226 | final int prime = 31;
227 | int result = 1;
228 | result = prime * result + id;
229 | return result;
230 | }
231 |
232 | @Override
233 | public boolean equals(Object obj) {
234 | if (this == obj) {
235 | return true;
236 | }
237 | if (obj == null) {
238 | return false;
239 | }
240 | if (getClass() != obj.getClass()) {
241 | return false;
242 | }
243 | Todo other = (Todo) obj;
244 | if (id != other.id) {
245 | return false;
246 | }
247 | return true;
248 | }
249 |
250 | @Override
251 | public String toString() {
252 | return String.format(
253 | "Todo [id=%s, user=%s, desc=%s, targetDate=%s, isDone=%s]", id,
254 | user, desc, targetDate, isDone);
255 | }
256 |
257 | }
258 | ```
259 | ---
260 | ### src/main/java/com/in28minutes/springboot/web/service/LoginService.java
261 |
262 | ```java
263 | package com.in28minutes.springboot.web.service;
264 |
265 | import org.springframework.stereotype.Component;
266 | import org.springframework.stereotype.Service;
267 |
268 | @Service
269 | public class LoginService {
270 |
271 | public boolean validateUser(String userid, String password) {
272 | // in28minutes, dummy
273 | return userid.equalsIgnoreCase("in28minutes")
274 | && password.equalsIgnoreCase("dummy");
275 | }
276 |
277 | }
278 | ```
279 | ---
280 | ### src/main/java/com/in28minutes/springboot/web/service/TodoService.java
281 |
282 | ```java
283 | package com.in28minutes.springboot.web.service;
284 |
285 | import java.util.ArrayList;
286 | import java.util.Date;
287 | import java.util.Iterator;
288 | import java.util.List;
289 |
290 | import org.springframework.stereotype.Service;
291 |
292 | import com.in28minutes.springboot.web.model.Todo;
293 |
294 | @Service
295 | public class TodoService {
296 | private static List todos = new ArrayList();
297 | private static int todoCount = 3;
298 |
299 | static {
300 | todos.add(new Todo(1, "in28Minutes", "Learn Spring MVC", new Date(),
301 | false));
302 | todos.add(new Todo(2, "in28Minutes", "Learn Struts", new Date(), false));
303 | todos.add(new Todo(3, "in28Minutes", "Learn Hibernate", new Date(),
304 | false));
305 | }
306 |
307 | public List retrieveTodos(String user) {
308 | List filteredTodos = new ArrayList();
309 | for (Todo todo : todos) {
310 | if (todo.getUser().equals(user)) {
311 | filteredTodos.add(todo);
312 | }
313 | }
314 | return filteredTodos;
315 | }
316 |
317 | public void addTodo(String name, String desc, Date targetDate,
318 | boolean isDone) {
319 | todos.add(new Todo(++todoCount, name, desc, targetDate, isDone));
320 | }
321 |
322 | public void deleteTodo(int id) {
323 | Iterator iterator = todos.iterator();
324 | while (iterator.hasNext()) {
325 | Todo todo = iterator.next();
326 | if (todo.getId() == id) {
327 | iterator.remove();
328 | }
329 | }
330 | }
331 | }
332 | ```
333 | ---
334 | ### src/main/java/com/in28minutes/springboot/web/SpringBootFirstWebApplication.java
335 |
336 | ```java
337 | package com.in28minutes.springboot.web;
338 |
339 | import org.springframework.boot.SpringApplication;
340 | import org.springframework.boot.autoconfigure.SpringBootApplication;
341 | import org.springframework.context.annotation.ComponentScan;
342 |
343 | @SpringBootApplication
344 | @ComponentScan("com.in28minutes.springboot.web")
345 | public class SpringBootFirstWebApplication {
346 |
347 | public static void main(String[] args) {
348 | SpringApplication.run(SpringBootFirstWebApplication.class, args);
349 | }
350 | }
351 | ```
352 | ---
353 | ### src/main/resources/application.properties
354 |
355 | ```
356 | spring.mvc.view.prefix=/WEB-INF/jsp/
357 | spring.mvc.view.suffix=.jsp
358 | logging.level.org.springframework.web=DEBUG
359 | ```
360 | ---
361 | ### src/main/webapp/WEB-INF/jsp/list-todos.jsp
362 |
363 | ```
364 |
365 |
366 |
367 | First Web Application
368 |
369 |
370 |
371 | Here are the list of your todos:
372 | ${todos}
373 |
374 | Your Name is : ${name}
375 |
376 |
377 |
378 | ```
379 | ---
380 | ### src/main/webapp/WEB-INF/jsp/login.jsp
381 |
382 | ```
383 |
384 |
385 |
386 | First Web Application
387 |
388 |
389 |
390 | ${errorMessage}
391 |
396 |
397 |
398 |
399 | ```
400 | ---
401 | ### src/main/webapp/WEB-INF/jsp/welcome.jsp
402 |
403 | ```
404 |
405 |
406 |
407 | First Web Application
408 |
409 |
410 |
411 | Welcome ${name}!! Click here to manage your todo's.
412 |
413 |
414 |
415 | ```
416 | ---
417 | ### src/test/java/com/in28minutes/springboot/web/SpringBootFirstWebApplicationTests.java
418 |
419 | ```java
420 | package com.in28minutes.springboot.web;
421 |
422 | import org.junit.Test;
423 | import org.junit.runner.RunWith;
424 | import org.springframework.boot.test.context.SpringBootTest;
425 | import org.springframework.test.context.junit4.SpringRunner;
426 |
427 | @RunWith(SpringRunner.class)
428 | @SpringBootTest
429 | public class SpringBootFirstWebApplicationTests {
430 |
431 | @Test
432 | public void contextLoads() {
433 | }
434 |
435 | }
436 | ```
437 | ---
438 | ### todo.txt
439 |
440 | ```
441 | LoginController -> adds name to model
442 | welcome.jsp -> shows ${name}
443 |
444 | TodoController -> redirects to list-todos.jsp
445 | ${name} is empty
446 |
447 |
448 | Component, Service, Repository, Controller
449 | Autowired
450 | ComponentScan
451 |
452 | Field dummyService in com.in28minutes.springboot.web.controller.LoginController
453 | required a bean of type 'com.in28minutes.dummy.DummyService'
454 | that could not be found.
455 |
456 | Spring Boot Starter Parent
457 | Spring Boot Starter Web
458 | @SpringBootApplication
459 | Auto Configuration
460 |
461 | Dispatcher Servlet
462 |
463 | /login => "login"
464 |
465 | "login" => src/main/webapp/WEB-INF/jsp/login.jsp
466 |
467 |
468 | Search for a view named "login"
469 |
470 |
471 |
472 | /login => LoginController
473 | ```
474 | ---
475 |
--------------------------------------------------------------------------------
/Step12.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/in28minutes/SpringBootWebApplicationStepByStep/7611e5a098e49023ee03ce1446e465a4c567da45/Step12.zip
--------------------------------------------------------------------------------
/Step13.md:
--------------------------------------------------------------------------------
1 | ## What we will do:
2 | - Add Facility to add New Todo
3 | - todo.jsp
4 | - Importance of redirect:/list-todos
5 |
6 | ## Files List
7 |
8 | ### pom.xml
9 |
10 | ```xml
11 |
12 |
14 | 4.0.0
15 |
16 | com.in28minutes.springboot.web
17 | spring-boot-first-web-application
18 | 0.0.1-SNAPSHOT
19 | jar
20 |
21 | spring-boot-first-web-application
22 | Demo project for Spring Boot
23 |
24 |
25 | org.springframework.boot
26 | spring-boot-starter-parent
27 | 1.4.3.RELEASE
28 |
29 |
30 |
31 |
32 | UTF-8
33 | UTF-8
34 | 1.8
35 |
36 |
37 |
38 |
39 | org.springframework.boot
40 | spring-boot-starter-web
41 |
42 |
43 |
44 | org.apache.tomcat.embed
45 | tomcat-embed-jasper
46 | provided
47 |
48 |
49 |
50 | org.springframework.boot
51 | spring-boot-devtools
52 | runtime
53 |
54 |
55 |
56 | org.springframework.boot
57 | spring-boot-starter-test
58 | test
59 |
60 |
61 |
62 |
63 |
64 |
65 | org.springframework.boot
66 | spring-boot-maven-plugin
67 |
68 |
69 |
70 |
71 |
72 | ```
73 | ---
74 | ### src/main/java/com/in28minutes/springboot/web/controller/LoginController.java
75 |
76 | ```java
77 | package com.in28minutes.springboot.web.controller;
78 |
79 | import org.springframework.beans.factory.annotation.Autowired;
80 | import org.springframework.stereotype.Controller;
81 | import org.springframework.ui.ModelMap;
82 | import org.springframework.web.bind.annotation.RequestMapping;
83 | import org.springframework.web.bind.annotation.RequestMethod;
84 | import org.springframework.web.bind.annotation.RequestParam;
85 | import org.springframework.web.bind.annotation.SessionAttributes;
86 |
87 | import com.in28minutes.springboot.web.service.LoginService;
88 |
89 | @Controller
90 | @SessionAttributes("name")
91 | public class LoginController {
92 |
93 | @Autowired
94 | LoginService service;
95 |
96 | @RequestMapping(value="/login", method = RequestMethod.GET)
97 | public String showLoginPage(ModelMap model){
98 | return "login";
99 | }
100 |
101 | @RequestMapping(value="/login", method = RequestMethod.POST)
102 | public String showWelcomePage(ModelMap model, @RequestParam String name, @RequestParam String password){
103 |
104 | boolean isValidUser = service.validateUser(name, password);
105 |
106 | if (!isValidUser) {
107 | model.put("errorMessage", "Invalid Credentials");
108 | return "login";
109 | }
110 |
111 | model.put("name", name);
112 | model.put("password", password);
113 |
114 | return "welcome";
115 | }
116 |
117 | }
118 | ```
119 | ---
120 | ### src/main/java/com/in28minutes/springboot/web/controller/TodoController.java
121 |
122 | ```java
123 | package com.in28minutes.springboot.web.controller;
124 |
125 | import java.util.Date;
126 |
127 | import org.springframework.beans.factory.annotation.Autowired;
128 | import org.springframework.stereotype.Controller;
129 | import org.springframework.ui.ModelMap;
130 | import org.springframework.web.bind.annotation.RequestMapping;
131 | import org.springframework.web.bind.annotation.RequestMethod;
132 | import org.springframework.web.bind.annotation.RequestParam;
133 | import org.springframework.web.bind.annotation.SessionAttributes;
134 |
135 | import com.in28minutes.springboot.web.service.LoginService;
136 | import com.in28minutes.springboot.web.service.TodoService;
137 |
138 | @Controller
139 | @SessionAttributes("name")
140 | public class TodoController {
141 |
142 | @Autowired
143 | TodoService service;
144 |
145 | @RequestMapping(value="/list-todos", method = RequestMethod.GET)
146 | public String showTodos(ModelMap model){
147 | String name = (String) model.get("name");
148 | model.put("todos", service.retrieveTodos(name));
149 | return "list-todos";
150 | }
151 |
152 | @RequestMapping(value="/add-todo", method = RequestMethod.GET)
153 | public String showAddTodoPage(ModelMap model){
154 | return "todo";
155 | }
156 |
157 | @RequestMapping(value="/add-todo", method = RequestMethod.POST)
158 | public String addTodo(ModelMap model, @RequestParam String desc){
159 | service.addTodo((String) model.get("name"), desc, new Date(), false);
160 | return "redirect:/list-todos";
161 | }
162 |
163 | }
164 | ```
165 | ---
166 | ### src/main/java/com/in28minutes/springboot/web/model/Todo.java
167 |
168 | ```java
169 | package com.in28minutes.springboot.web.model;
170 |
171 | import java.util.Date;
172 |
173 | public class Todo {
174 | private int id;
175 | private String user;
176 | private String desc;
177 | private Date targetDate;
178 | private boolean isDone;
179 |
180 | public Todo(int id, String user, String desc, Date targetDate,
181 | boolean isDone) {
182 | super();
183 | this.id = id;
184 | this.user = user;
185 | this.desc = desc;
186 | this.targetDate = targetDate;
187 | this.isDone = isDone;
188 | }
189 |
190 | public int getId() {
191 | return id;
192 | }
193 |
194 | public void setId(int id) {
195 | this.id = id;
196 | }
197 |
198 | public String getUser() {
199 | return user;
200 | }
201 |
202 | public void setUser(String user) {
203 | this.user = user;
204 | }
205 |
206 | public String getDesc() {
207 | return desc;
208 | }
209 |
210 | public void setDesc(String desc) {
211 | this.desc = desc;
212 | }
213 |
214 | public Date getTargetDate() {
215 | return targetDate;
216 | }
217 |
218 | public void setTargetDate(Date targetDate) {
219 | this.targetDate = targetDate;
220 | }
221 |
222 | public boolean isDone() {
223 | return isDone;
224 | }
225 |
226 | public void setDone(boolean isDone) {
227 | this.isDone = isDone;
228 | }
229 |
230 | @Override
231 | public int hashCode() {
232 | final int prime = 31;
233 | int result = 1;
234 | result = prime * result + id;
235 | return result;
236 | }
237 |
238 | @Override
239 | public boolean equals(Object obj) {
240 | if (this == obj) {
241 | return true;
242 | }
243 | if (obj == null) {
244 | return false;
245 | }
246 | if (getClass() != obj.getClass()) {
247 | return false;
248 | }
249 | Todo other = (Todo) obj;
250 | if (id != other.id) {
251 | return false;
252 | }
253 | return true;
254 | }
255 |
256 | @Override
257 | public String toString() {
258 | return String.format(
259 | "Todo [id=%s, user=%s, desc=%s, targetDate=%s, isDone=%s]", id,
260 | user, desc, targetDate, isDone);
261 | }
262 |
263 | }
264 | ```
265 | ---
266 | ### src/main/java/com/in28minutes/springboot/web/service/LoginService.java
267 |
268 | ```java
269 | package com.in28minutes.springboot.web.service;
270 |
271 | import org.springframework.stereotype.Component;
272 | import org.springframework.stereotype.Service;
273 |
274 | @Service
275 | public class LoginService {
276 |
277 | public boolean validateUser(String userid, String password) {
278 | // in28minutes, dummy
279 | return userid.equalsIgnoreCase("in28minutes")
280 | && password.equalsIgnoreCase("dummy");
281 | }
282 |
283 | }
284 | ```
285 | ---
286 | ### src/main/java/com/in28minutes/springboot/web/service/TodoService.java
287 |
288 | ```java
289 | package com.in28minutes.springboot.web.service;
290 |
291 | import java.util.ArrayList;
292 | import java.util.Date;
293 | import java.util.Iterator;
294 | import java.util.List;
295 |
296 | import org.springframework.stereotype.Service;
297 |
298 | import com.in28minutes.springboot.web.model.Todo;
299 |
300 | @Service
301 | public class TodoService {
302 | private static List todos = new ArrayList();
303 | private static int todoCount = 3;
304 |
305 | static {
306 | todos.add(new Todo(1, "in28Minutes", "Learn Spring MVC", new Date(),
307 | false));
308 | todos.add(new Todo(2, "in28Minutes", "Learn Struts", new Date(), false));
309 | todos.add(new Todo(3, "in28Minutes", "Learn Hibernate", new Date(),
310 | false));
311 | }
312 |
313 | public List retrieveTodos(String user) {
314 | List filteredTodos = new ArrayList();
315 | for (Todo todo : todos) {
316 | if (todo.getUser().equals(user)) {
317 | filteredTodos.add(todo);
318 | }
319 | }
320 | return filteredTodos;
321 | }
322 |
323 | public void addTodo(String name, String desc, Date targetDate,
324 | boolean isDone) {
325 | todos.add(new Todo(++todoCount, name, desc, targetDate, isDone));
326 | }
327 |
328 | public void deleteTodo(int id) {
329 | Iterator iterator = todos.iterator();
330 | while (iterator.hasNext()) {
331 | Todo todo = iterator.next();
332 | if (todo.getId() == id) {
333 | iterator.remove();
334 | }
335 | }
336 | }
337 | }
338 | ```
339 | ---
340 | ### src/main/java/com/in28minutes/springboot/web/SpringBootFirstWebApplication.java
341 |
342 | ```java
343 | package com.in28minutes.springboot.web;
344 |
345 | import org.springframework.boot.SpringApplication;
346 | import org.springframework.boot.autoconfigure.SpringBootApplication;
347 | import org.springframework.context.annotation.ComponentScan;
348 |
349 | @SpringBootApplication
350 | @ComponentScan("com.in28minutes.springboot.web")
351 | public class SpringBootFirstWebApplication {
352 |
353 | public static void main(String[] args) {
354 | SpringApplication.run(SpringBootFirstWebApplication.class, args);
355 | }
356 | }
357 | ```
358 | ---
359 | ### src/main/resources/application.properties
360 |
361 | ```
362 | spring.mvc.view.prefix=/WEB-INF/jsp/
363 | spring.mvc.view.suffix=.jsp
364 | logging.level.org.springframework.web=DEBUG
365 | ```
366 | ---
367 | ### src/main/webapp/WEB-INF/jsp/list-todos.jsp
368 |
369 | ```
370 |
371 |
372 |
373 | First Web Application
374 |
375 |
376 |
377 | Here are the list of ${name}'s todos:
378 | ${todos}.
379 |
380 | Add a Todo
381 |
382 |
383 |
384 | ```
385 | ---
386 | ### src/main/webapp/WEB-INF/jsp/login.jsp
387 |
388 | ```
389 |
390 |
391 |
392 | First Web Application
393 |
394 |
395 |
396 | ${errorMessage}
397 |
402 |
403 |
404 |
405 | ```
406 | ---
407 | ### src/main/webapp/WEB-INF/jsp/todo.jsp
408 |
409 | ```
410 |
411 |
412 |
413 | First Web Application
414 |
415 |
416 |
417 | ADD Todo Page for ${name}
418 |
419 |
423 |
424 |
425 |
426 |
427 | ```
428 | ---
429 | ### src/main/webapp/WEB-INF/jsp/welcome.jsp
430 |
431 | ```
432 |
433 |
434 |
435 | First Web Application
436 |
437 |
438 |
439 | Welcome ${name}!! Click here to manage your todo's.
440 |
441 |
442 |
443 | ```
444 | ---
445 | ### src/test/java/com/in28minutes/springboot/web/SpringBootFirstWebApplicationTests.java
446 |
447 | ```java
448 | package com.in28minutes.springboot.web;
449 |
450 | import org.junit.Test;
451 | import org.junit.runner.RunWith;
452 | import org.springframework.boot.test.context.SpringBootTest;
453 | import org.springframework.test.context.junit4.SpringRunner;
454 |
455 | @RunWith(SpringRunner.class)
456 | @SpringBootTest
457 | public class SpringBootFirstWebApplicationTests {
458 |
459 | @Test
460 | public void contextLoads() {
461 | }
462 |
463 | }
464 | ```
465 | ---
466 | ### todo.txt
467 |
468 | ```
469 | LoginController -> adds name to model
470 | welcome.jsp -> shows ${name}
471 |
472 | TodoController -> redirects to list-todos.jsp
473 | ${name} is empty
474 |
475 |
476 | Component, Service, Repository, Controller
477 | Autowired
478 | ComponentScan
479 |
480 | Field dummyService in com.in28minutes.springboot.web.controller.LoginController
481 | required a bean of type 'com.in28minutes.dummy.DummyService'
482 | that could not be found.
483 |
484 | Spring Boot Starter Parent
485 | Spring Boot Starter Web
486 | @SpringBootApplication
487 | Auto Configuration
488 |
489 | Dispatcher Servlet
490 |
491 | /login => "login"
492 |
493 | "login" => src/main/webapp/WEB-INF/jsp/login.jsp
494 |
495 |
496 | Search for a view named "login"
497 |
498 |
499 |
500 | /login => LoginController
501 | ```
502 | ---
503 |
--------------------------------------------------------------------------------
/Step13.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/in28minutes/SpringBootWebApplicationStepByStep/7611e5a098e49023ee03ce1446e465a4c567da45/Step13.zip
--------------------------------------------------------------------------------
/Step14.md:
--------------------------------------------------------------------------------
1 | ## What we will do:
2 | - Display Todos in a table using JSTL Tags
3 | - <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
4 | - Add Dependency for jstl
5 |
6 | ## Snippet
7 | ```
8 |
9 | javax.servlet
10 | jstl
11 |
12 | ```
13 |
--------------------------------------------------------------------------------
/Step15.md:
--------------------------------------------------------------------------------
1 | ## What we will do:
2 | - Add bootstrap to give basic formatting to the page : We use bootstrap classes container,table and table-striped.
3 | - We will use webjars
4 | - Already auto configured by Spring Boot : o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
5 |
6 | ## Useful Snippets
7 | ```
8 |
9 | org.webjars
10 | bootstrap
11 | 3.3.6
12 |
13 |
14 | org.webjars
15 | jquery
16 | 1.9.1
17 |
18 |
19 |
20 |
21 |
22 |
23 |
25 |
26 | ```
27 |
28 | ## Files List
29 |
30 | ### pom.xml
31 |
32 | ```xml
33 |
34 |
36 | 4.0.0
37 |
38 | com.in28minutes.springboot.web
39 | spring-boot-first-web-application
40 | 0.0.1-SNAPSHOT
41 | jar
42 |
43 | spring-boot-first-web-application
44 | Demo project for Spring Boot
45 |
46 |
47 | org.springframework.boot
48 | spring-boot-starter-parent
49 | 1.4.3.RELEASE
50 |
51 |
52 |
53 |
54 | UTF-8
55 | UTF-8
56 | 1.8
57 |
58 |
59 |
60 |
61 | org.springframework.boot
62 | spring-boot-starter-web
63 |
64 |
65 |
66 | javax.servlet
67 | jstl
68 |
69 |
70 |
71 | org.webjars
72 | bootstrap
73 | 3.3.6
74 |
75 |
76 |
77 | org.webjars
78 | jquery
79 | 1.9.1
80 |
81 |
82 |
83 | org.apache.tomcat.embed
84 | tomcat-embed-jasper
85 | provided
86 |
87 |
88 |
89 | org.springframework.boot
90 | spring-boot-devtools
91 | runtime
92 |
93 |
94 |
95 | org.springframework.boot
96 | spring-boot-starter-test
97 | test
98 |
99 |
100 |
101 |
102 |
103 |
104 | org.springframework.boot
105 | spring-boot-maven-plugin
106 |
107 |
108 |
109 |
110 |
111 | ```
112 | ---
113 | ### src/main/java/com/in28minutes/springboot/web/controller/LoginController.java
114 |
115 | ```java
116 | package com.in28minutes.springboot.web.controller;
117 |
118 | import org.springframework.beans.factory.annotation.Autowired;
119 | import org.springframework.stereotype.Controller;
120 | import org.springframework.ui.ModelMap;
121 | import org.springframework.web.bind.annotation.RequestMapping;
122 | import org.springframework.web.bind.annotation.RequestMethod;
123 | import org.springframework.web.bind.annotation.RequestParam;
124 | import org.springframework.web.bind.annotation.SessionAttributes;
125 |
126 | import com.in28minutes.springboot.web.service.LoginService;
127 |
128 | @Controller
129 | @SessionAttributes("name")
130 | public class LoginController {
131 |
132 | @Autowired
133 | LoginService service;
134 |
135 | @RequestMapping(value="/login", method = RequestMethod.GET)
136 | public String showLoginPage(ModelMap model){
137 | return "login";
138 | }
139 |
140 | @RequestMapping(value="/login", method = RequestMethod.POST)
141 | public String showWelcomePage(ModelMap model, @RequestParam String name, @RequestParam String password){
142 |
143 | boolean isValidUser = service.validateUser(name, password);
144 |
145 | if (!isValidUser) {
146 | model.put("errorMessage", "Invalid Credentials");
147 | return "login";
148 | }
149 |
150 | model.put("name", name);
151 | model.put("password", password);
152 |
153 | return "welcome";
154 | }
155 |
156 | }
157 | ```
158 | ---
159 | ### src/main/java/com/in28minutes/springboot/web/controller/TodoController.java
160 |
161 | ```java
162 | package com.in28minutes.springboot.web.controller;
163 |
164 | import java.util.Date;
165 |
166 | import org.springframework.beans.factory.annotation.Autowired;
167 | import org.springframework.stereotype.Controller;
168 | import org.springframework.ui.ModelMap;
169 | import org.springframework.web.bind.annotation.RequestMapping;
170 | import org.springframework.web.bind.annotation.RequestMethod;
171 | import org.springframework.web.bind.annotation.RequestParam;
172 | import org.springframework.web.bind.annotation.SessionAttributes;
173 |
174 | import com.in28minutes.springboot.web.service.LoginService;
175 | import com.in28minutes.springboot.web.service.TodoService;
176 |
177 | @Controller
178 | @SessionAttributes("name")
179 | public class TodoController {
180 |
181 | @Autowired
182 | TodoService service;
183 |
184 | @RequestMapping(value="/list-todos", method = RequestMethod.GET)
185 | public String showTodos(ModelMap model){
186 | String name = (String) model.get("name");
187 | model.put("todos", service.retrieveTodos(name));
188 | return "list-todos";
189 | }
190 |
191 | @RequestMapping(value="/add-todo", method = RequestMethod.GET)
192 | public String showAddTodoPage(ModelMap model){
193 | return "todo";
194 | }
195 |
196 | @RequestMapping(value="/add-todo", method = RequestMethod.POST)
197 | public String addTodo(ModelMap model, @RequestParam String desc){
198 | service.addTodo((String) model.get("name"), desc, new Date(), false);
199 | return "redirect:/list-todos";
200 | }
201 |
202 | }
203 | ```
204 | ---
205 | ### src/main/java/com/in28minutes/springboot/web/model/Todo.java
206 |
207 | ```java
208 | package com.in28minutes.springboot.web.model;
209 |
210 | import java.util.Date;
211 |
212 | public class Todo {
213 | private int id;
214 | private String user;
215 | private String desc;
216 | private Date targetDate;
217 | private boolean isDone;
218 |
219 | public Todo(int id, String user, String desc, Date targetDate,
220 | boolean isDone) {
221 | super();
222 | this.id = id;
223 | this.user = user;
224 | this.desc = desc;
225 | this.targetDate = targetDate;
226 | this.isDone = isDone;
227 | }
228 |
229 | public int getId() {
230 | return id;
231 | }
232 |
233 | public void setId(int id) {
234 | this.id = id;
235 | }
236 |
237 | public String getUser() {
238 | return user;
239 | }
240 |
241 | public void setUser(String user) {
242 | this.user = user;
243 | }
244 |
245 | public String getDesc() {
246 | return desc;
247 | }
248 |
249 | public void setDesc(String desc) {
250 | this.desc = desc;
251 | }
252 |
253 | public Date getTargetDate() {
254 | return targetDate;
255 | }
256 |
257 | public void setTargetDate(Date targetDate) {
258 | this.targetDate = targetDate;
259 | }
260 |
261 | public boolean isDone() {
262 | return isDone;
263 | }
264 |
265 | public void setDone(boolean isDone) {
266 | this.isDone = isDone;
267 | }
268 |
269 | @Override
270 | public int hashCode() {
271 | final int prime = 31;
272 | int result = 1;
273 | result = prime * result + id;
274 | return result;
275 | }
276 |
277 | @Override
278 | public boolean equals(Object obj) {
279 | if (this == obj) {
280 | return true;
281 | }
282 | if (obj == null) {
283 | return false;
284 | }
285 | if (getClass() != obj.getClass()) {
286 | return false;
287 | }
288 | Todo other = (Todo) obj;
289 | if (id != other.id) {
290 | return false;
291 | }
292 | return true;
293 | }
294 |
295 | @Override
296 | public String toString() {
297 | return String.format(
298 | "Todo [id=%s, user=%s, desc=%s, targetDate=%s, isDone=%s]", id,
299 | user, desc, targetDate, isDone);
300 | }
301 |
302 | }
303 | ```
304 | ---
305 | ### src/main/java/com/in28minutes/springboot/web/service/LoginService.java
306 |
307 | ```java
308 | package com.in28minutes.springboot.web.service;
309 |
310 | import org.springframework.stereotype.Component;
311 | import org.springframework.stereotype.Service;
312 |
313 | @Service
314 | public class LoginService {
315 |
316 | public boolean validateUser(String userid, String password) {
317 | // in28minutes, dummy
318 | return userid.equalsIgnoreCase("in28minutes")
319 | && password.equalsIgnoreCase("dummy");
320 | }
321 |
322 | }
323 | ```
324 | ---
325 | ### src/main/java/com/in28minutes/springboot/web/service/TodoService.java
326 |
327 | ```java
328 | package com.in28minutes.springboot.web.service;
329 |
330 | import java.util.ArrayList;
331 | import java.util.Date;
332 | import java.util.Iterator;
333 | import java.util.List;
334 |
335 | import org.springframework.stereotype.Service;
336 |
337 | import com.in28minutes.springboot.web.model.Todo;
338 |
339 | @Service
340 | public class TodoService {
341 | private static List todos = new ArrayList();
342 | private static int todoCount = 3;
343 |
344 | static {
345 | todos.add(new Todo(1, "in28Minutes", "Learn Spring MVC", new Date(),
346 | false));
347 | todos.add(new Todo(2, "in28Minutes", "Learn Struts", new Date(), false));
348 | todos.add(new Todo(3, "in28Minutes", "Learn Hibernate", new Date(),
349 | false));
350 | }
351 |
352 | public List retrieveTodos(String user) {
353 | List filteredTodos = new ArrayList();
354 | for (Todo todo : todos) {
355 | if (todo.getUser().equals(user)) {
356 | filteredTodos.add(todo);
357 | }
358 | }
359 | return filteredTodos;
360 | }
361 |
362 | public void addTodo(String name, String desc, Date targetDate,
363 | boolean isDone) {
364 | todos.add(new Todo(++todoCount, name, desc, targetDate, isDone));
365 | }
366 |
367 | public void deleteTodo(int id) {
368 | Iterator iterator = todos.iterator();
369 | while (iterator.hasNext()) {
370 | Todo todo = iterator.next();
371 | if (todo.getId() == id) {
372 | iterator.remove();
373 | }
374 | }
375 | }
376 | }
377 | ```
378 | ---
379 | ### src/main/java/com/in28minutes/springboot/web/SpringBootFirstWebApplication.java
380 |
381 | ```java
382 | package com.in28minutes.springboot.web;
383 |
384 | import org.springframework.boot.SpringApplication;
385 | import org.springframework.boot.autoconfigure.SpringBootApplication;
386 | import org.springframework.context.annotation.ComponentScan;
387 |
388 | @SpringBootApplication
389 | @ComponentScan("com.in28minutes.springboot.web")
390 | public class SpringBootFirstWebApplication {
391 |
392 | public static void main(String[] args) {
393 | SpringApplication.run(SpringBootFirstWebApplication.class, args);
394 | }
395 | }
396 | ```
397 | ---
398 | ### src/main/resources/application.properties
399 |
400 | ```
401 | spring.mvc.view.prefix=/WEB-INF/jsp/
402 | spring.mvc.view.suffix=.jsp
403 | logging.level.org.springframework.web=INFO
404 | ```
405 | ---
406 | ### src/main/webapp/WEB-INF/jsp/list-todos.jsp
407 |
408 | ```
409 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
410 |
411 |
412 |
413 |
414 | Todo's for ${name}
415 |
417 |
418 |
419 |
420 |
421 |
422 | Your todos are
423 |
424 |
425 | Description |
426 | Target Date |
427 | Is it Done? |
428 |
429 |
430 |
431 |
432 |
433 | ${todo.desc} |
434 | ${todo.targetDate} |
435 | ${todo.done} |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 | ```
449 | ---
450 | ### src/main/webapp/WEB-INF/jsp/login.jsp
451 |
452 | ```
453 |
454 |
455 |
456 | First Web Application
457 |
458 |
459 |
460 | ${errorMessage}
461 |
466 |
467 |
468 |
469 | ```
470 | ---
471 | ### src/main/webapp/WEB-INF/jsp/todo.jsp
472 |
473 | ```
474 |
475 |
476 |
477 | First Web Application
478 |
479 |
480 |
481 | ADD Todo Page for ${name}
482 |
483 |
487 |
488 |
489 |
490 |
491 | ```
492 | ---
493 | ### src/main/webapp/WEB-INF/jsp/welcome.jsp
494 |
495 | ```
496 |
497 |
498 |
499 | First Web Application
500 |
501 |
502 |
503 | Welcome ${name}!! Click here to manage your todo's.
504 |
505 |
506 |
507 | ```
508 | ---
509 | ### src/test/java/com/in28minutes/springboot/web/SpringBootFirstWebApplicationTests.java
510 |
511 | ```java
512 | package com.in28minutes.springboot.web;
513 |
514 | import org.junit.Test;
515 | import org.junit.runner.RunWith;
516 | import org.springframework.boot.test.context.SpringBootTest;
517 | import org.springframework.test.context.junit4.SpringRunner;
518 |
519 | @RunWith(SpringRunner.class)
520 | @SpringBootTest
521 | public class SpringBootFirstWebApplicationTests {
522 |
523 | @Test
524 | public void contextLoads() {
525 | }
526 |
527 | }
528 | ```
529 | ---
530 | ### todo.txt
531 |
532 | ```
533 | LoginController -> adds name to model
534 | welcome.jsp -> shows ${name}
535 |
536 | TodoController -> redirects to list-todos.jsp
537 | ${name} is empty
538 |
539 |
540 | Component, Service, Repository, Controller
541 | Autowired
542 | ComponentScan
543 |
544 | Field dummyService in com.in28minutes.springboot.web.controller.LoginController
545 | required a bean of type 'com.in28minutes.dummy.DummyService'
546 | that could not be found.
547 |
548 | Spring Boot Starter Parent
549 | Spring Boot Starter Web
550 | @SpringBootApplication
551 | Auto Configuration
552 |
553 | Dispatcher Servlet
554 |
555 | /login => "login"
556 |
557 | "login" => src/main/webapp/WEB-INF/jsp/login.jsp
558 |
559 |
560 | Search for a view named "login"
561 |
562 |
563 |
564 | /login => LoginController
565 | ```
566 | ---
567 |
--------------------------------------------------------------------------------
/Step15.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/in28minutes/SpringBootWebApplicationStepByStep/7611e5a098e49023ee03ce1446e465a4c567da45/Step15.zip
--------------------------------------------------------------------------------
/Step16.md:
--------------------------------------------------------------------------------
1 | ## What we will do:
2 | - Add functionality to delete a todo
3 |
4 | ## Useful Snippets
5 | ```
6 | Delete
8 | ```
9 | ## Files List
10 |
11 | ### pom.xml
12 |
13 | ```xml
14 |
15 |
17 | 4.0.0
18 |
19 | com.in28minutes.springboot.web
20 | spring-boot-first-web-application
21 | 0.0.1-SNAPSHOT
22 | jar
23 |
24 | spring-boot-first-web-application
25 | Demo project for Spring Boot
26 |
27 |
28 | org.springframework.boot
29 | spring-boot-starter-parent
30 | 1.4.3.RELEASE
31 |
32 |
33 |
34 |
35 | UTF-8
36 | UTF-8
37 | 1.8
38 |
39 |
40 |
41 |
42 | org.springframework.boot
43 | spring-boot-starter-web
44 |
45 |
46 |
47 | javax.servlet
48 | jstl
49 |
50 |
51 |
52 | org.webjars
53 | bootstrap
54 | 3.3.6
55 |
56 |
57 |
58 | org.webjars
59 | jquery
60 | 1.9.1
61 |
62 |
63 |
64 | org.apache.tomcat.embed
65 | tomcat-embed-jasper
66 | provided
67 |
68 |
69 |
70 | org.springframework.boot
71 | spring-boot-devtools
72 | runtime
73 |
74 |
75 |
76 | org.springframework.boot
77 | spring-boot-starter-test
78 | test
79 |
80 |
81 |
82 |
83 |
84 |
85 | org.springframework.boot
86 | spring-boot-maven-plugin
87 |
88 |
89 |
90 |
91 |
92 | ```
93 | ---
94 | ### src/main/java/com/in28minutes/springboot/web/controller/LoginController.java
95 |
96 | ```java
97 | package com.in28minutes.springboot.web.controller;
98 |
99 | import org.springframework.beans.factory.annotation.Autowired;
100 | import org.springframework.stereotype.Controller;
101 | import org.springframework.ui.ModelMap;
102 | import org.springframework.web.bind.annotation.RequestMapping;
103 | import org.springframework.web.bind.annotation.RequestMethod;
104 | import org.springframework.web.bind.annotation.RequestParam;
105 | import org.springframework.web.bind.annotation.SessionAttributes;
106 |
107 | import com.in28minutes.springboot.web.service.LoginService;
108 |
109 | @Controller
110 | @SessionAttributes("name")
111 | public class LoginController {
112 |
113 | @Autowired
114 | LoginService service;
115 |
116 | @RequestMapping(value="/login", method = RequestMethod.GET)
117 | public String showLoginPage(ModelMap model){
118 | return "login";
119 | }
120 |
121 | @RequestMapping(value="/login", method = RequestMethod.POST)
122 | public String showWelcomePage(ModelMap model, @RequestParam String name, @RequestParam String password){
123 |
124 | boolean isValidUser = service.validateUser(name, password);
125 |
126 | if (!isValidUser) {
127 | model.put("errorMessage", "Invalid Credentials");
128 | return "login";
129 | }
130 |
131 | model.put("name", name);
132 | model.put("password", password);
133 |
134 | return "welcome";
135 | }
136 |
137 | }
138 | ```
139 | ---
140 | ### src/main/java/com/in28minutes/springboot/web/controller/TodoController.java
141 |
142 | ```java
143 | package com.in28minutes.springboot.web.controller;
144 |
145 | import java.util.Date;
146 |
147 | import org.springframework.beans.factory.annotation.Autowired;
148 | import org.springframework.stereotype.Controller;
149 | import org.springframework.ui.ModelMap;
150 | import org.springframework.web.bind.annotation.RequestMapping;
151 | import org.springframework.web.bind.annotation.RequestMethod;
152 | import org.springframework.web.bind.annotation.RequestParam;
153 | import org.springframework.web.bind.annotation.SessionAttributes;
154 |
155 | import com.in28minutes.springboot.web.service.LoginService;
156 | import com.in28minutes.springboot.web.service.TodoService;
157 |
158 | @Controller
159 | @SessionAttributes("name")
160 | public class TodoController {
161 |
162 | @Autowired
163 | TodoService service;
164 |
165 | @RequestMapping(value="/list-todos", method = RequestMethod.GET)
166 | public String showTodos(ModelMap model){
167 | String name = (String) model.get("name");
168 | model.put("todos", service.retrieveTodos(name));
169 | return "list-todos";
170 | }
171 |
172 | @RequestMapping(value="/add-todo", method = RequestMethod.GET)
173 | public String showAddTodoPage(ModelMap model){
174 | return "todo";
175 | }
176 |
177 | @RequestMapping(value="/delete-todo", method = RequestMethod.GET)
178 | public String deleteTodo(@RequestParam int id){
179 | service.deleteTodo(id);
180 | return "redirect:/list-todos";
181 | }
182 |
183 | @RequestMapping(value="/add-todo", method = RequestMethod.POST)
184 | public String addTodo(ModelMap model, @RequestParam String desc){
185 | service.addTodo((String) model.get("name"), desc, new Date(), false);
186 | return "redirect:/list-todos";
187 | }
188 |
189 | }
190 | ```
191 | ---
192 | ### src/main/java/com/in28minutes/springboot/web/model/Todo.java
193 |
194 | ```java
195 | package com.in28minutes.springboot.web.model;
196 |
197 | import java.util.Date;
198 |
199 | public class Todo {
200 | private int id;
201 | private String user;
202 | private String desc;
203 | private Date targetDate;
204 | private boolean isDone;
205 |
206 | public Todo(int id, String user, String desc, Date targetDate,
207 | boolean isDone) {
208 | super();
209 | this.id = id;
210 | this.user = user;
211 | this.desc = desc;
212 | this.targetDate = targetDate;
213 | this.isDone = isDone;
214 | }
215 |
216 | public int getId() {
217 | return id;
218 | }
219 |
220 | public void setId(int id) {
221 | this.id = id;
222 | }
223 |
224 | public String getUser() {
225 | return user;
226 | }
227 |
228 | public void setUser(String user) {
229 | this.user = user;
230 | }
231 |
232 | public String getDesc() {
233 | return desc;
234 | }
235 |
236 | public void setDesc(String desc) {
237 | this.desc = desc;
238 | }
239 |
240 | public Date getTargetDate() {
241 | return targetDate;
242 | }
243 |
244 | public void setTargetDate(Date targetDate) {
245 | this.targetDate = targetDate;
246 | }
247 |
248 | public boolean isDone() {
249 | return isDone;
250 | }
251 |
252 | public void setDone(boolean isDone) {
253 | this.isDone = isDone;
254 | }
255 |
256 | @Override
257 | public int hashCode() {
258 | final int prime = 31;
259 | int result = 1;
260 | result = prime * result + id;
261 | return result;
262 | }
263 |
264 | @Override
265 | public boolean equals(Object obj) {
266 | if (this == obj) {
267 | return true;
268 | }
269 | if (obj == null) {
270 | return false;
271 | }
272 | if (getClass() != obj.getClass()) {
273 | return false;
274 | }
275 | Todo other = (Todo) obj;
276 | if (id != other.id) {
277 | return false;
278 | }
279 | return true;
280 | }
281 |
282 | @Override
283 | public String toString() {
284 | return String.format(
285 | "Todo [id=%s, user=%s, desc=%s, targetDate=%s, isDone=%s]", id,
286 | user, desc, targetDate, isDone);
287 | }
288 |
289 | }
290 | ```
291 | ---
292 | ### src/main/java/com/in28minutes/springboot/web/service/LoginService.java
293 |
294 | ```java
295 | package com.in28minutes.springboot.web.service;
296 |
297 | import org.springframework.stereotype.Component;
298 | import org.springframework.stereotype.Service;
299 |
300 | @Service
301 | public class LoginService {
302 |
303 | public boolean validateUser(String userid, String password) {
304 | // in28minutes, dummy
305 | return userid.equalsIgnoreCase("in28minutes")
306 | && password.equalsIgnoreCase("dummy");
307 | }
308 |
309 | }
310 | ```
311 | ---
312 | ### src/main/java/com/in28minutes/springboot/web/service/TodoService.java
313 |
314 | ```java
315 | package com.in28minutes.springboot.web.service;
316 |
317 | import java.util.ArrayList;
318 | import java.util.Date;
319 | import java.util.Iterator;
320 | import java.util.List;
321 |
322 | import org.springframework.stereotype.Service;
323 |
324 | import com.in28minutes.springboot.web.model.Todo;
325 |
326 | @Service
327 | public class TodoService {
328 | private static List todos = new ArrayList();
329 | private static int todoCount = 3;
330 |
331 | static {
332 | todos.add(new Todo(1, "in28Minutes", "Learn Spring MVC", new Date(),
333 | false));
334 | todos.add(new Todo(2, "in28Minutes", "Learn Struts", new Date(), false));
335 | todos.add(new Todo(3, "in28Minutes", "Learn Hibernate", new Date(),
336 | false));
337 | }
338 |
339 | public List retrieveTodos(String user) {
340 | List filteredTodos = new ArrayList();
341 | for (Todo todo : todos) {
342 | if (todo.getUser().equals(user)) {
343 | filteredTodos.add(todo);
344 | }
345 | }
346 | return filteredTodos;
347 | }
348 |
349 | public void addTodo(String name, String desc, Date targetDate,
350 | boolean isDone) {
351 | todos.add(new Todo(++todoCount, name, desc, targetDate, isDone));
352 | }
353 |
354 | public void deleteTodo(int id) {
355 | Iterator iterator = todos.iterator();
356 | while (iterator.hasNext()) {
357 | Todo todo = iterator.next();
358 | if (todo.getId() == id) {
359 | iterator.remove();
360 | }
361 | }
362 | }
363 | }
364 | ```
365 | ---
366 | ### src/main/java/com/in28minutes/springboot/web/SpringBootFirstWebApplication.java
367 |
368 | ```java
369 | package com.in28minutes.springboot.web;
370 |
371 | import org.springframework.boot.SpringApplication;
372 | import org.springframework.boot.autoconfigure.SpringBootApplication;
373 | import org.springframework.context.annotation.ComponentScan;
374 |
375 | @SpringBootApplication
376 | @ComponentScan("com.in28minutes.springboot.web")
377 | public class SpringBootFirstWebApplication {
378 |
379 | public static void main(String[] args) {
380 | SpringApplication.run(SpringBootFirstWebApplication.class, args);
381 | }
382 | }
383 | ```
384 | ---
385 | ### src/main/resources/application.properties
386 |
387 | ```
388 | spring.mvc.view.prefix=/WEB-INF/jsp/
389 | spring.mvc.view.suffix=.jsp
390 | logging.level.org.springframework.web=INFO
391 | ```
392 | ---
393 | ### src/main/webapp/WEB-INF/jsp/list-todos.jsp
394 |
395 | ```
396 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
397 |
398 |
399 |
400 |
401 | Todo's for ${name}
402 |
404 |
405 |
406 |
407 |
408 |
409 | Your todos are
410 |
411 |
412 | Description |
413 | Target Date |
414 | Is it Done? |
415 | |
416 |
417 |
418 |
419 |
420 |
421 | ${todo.desc} |
422 | ${todo.targetDate} |
423 | ${todo.done} |
424 | Delete |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 | ```
438 | ---
439 | ### src/main/webapp/WEB-INF/jsp/login.jsp
440 |
441 | ```
442 |
443 |
444 |
445 | First Web Application
446 |
447 |
448 |
449 | ${errorMessage}
450 |
455 |
456 |
457 |
458 | ```
459 | ---
460 | ### src/main/webapp/WEB-INF/jsp/todo.jsp
461 |
462 | ```
463 |
464 |
465 |
466 | First Web Application
467 |
468 |
469 |
470 | ADD Todo Page for ${name}
471 |
472 |
476 |
477 |
478 |
479 |
480 | ```
481 | ---
482 | ### src/main/webapp/WEB-INF/jsp/welcome.jsp
483 |
484 | ```
485 |
486 |
487 |
488 | First Web Application
489 |
490 |
491 |
492 | Welcome ${name}!! Click here to manage your todo's.
493 |
494 |
495 |
496 | ```
497 | ---
498 | ### src/test/java/com/in28minutes/springboot/web/SpringBootFirstWebApplicationTests.java
499 |
500 | ```java
501 | package com.in28minutes.springboot.web;
502 |
503 | import org.junit.Test;
504 | import org.junit.runner.RunWith;
505 | import org.springframework.boot.test.context.SpringBootTest;
506 | import org.springframework.test.context.junit4.SpringRunner;
507 |
508 | @RunWith(SpringRunner.class)
509 | @SpringBootTest
510 | public class SpringBootFirstWebApplicationTests {
511 |
512 | @Test
513 | public void contextLoads() {
514 | }
515 |
516 | }
517 | ```
518 | ---
519 | ### todo.txt
520 |
521 | ```
522 | LoginController -> adds name to model
523 | welcome.jsp -> shows ${name}
524 |
525 | TodoController -> redirects to list-todos.jsp
526 | ${name} is empty
527 |
528 |
529 | Component, Service, Repository, Controller
530 | Autowired
531 | ComponentScan
532 |
533 | Field dummyService in com.in28minutes.springboot.web.controller.LoginController
534 | required a bean of type 'com.in28minutes.dummy.DummyService'
535 | that could not be found.
536 |
537 | Spring Boot Starter Parent
538 | Spring Boot Starter Web
539 | @SpringBootApplication
540 | Auto Configuration
541 |
542 | Dispatcher Servlet
543 |
544 | /login => "login"
545 |
546 | "login" => src/main/webapp/WEB-INF/jsp/login.jsp
547 |
548 |
549 | Search for a view named "login"
550 |
551 |
552 |
553 | /login => LoginController
554 | ```
555 | ---
556 |
--------------------------------------------------------------------------------
/Step16.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/in28minutes/SpringBootWebApplicationStepByStep/7611e5a098e49023ee03ce1446e465a4c567da45/Step16.zip
--------------------------------------------------------------------------------
/Step17.md:
--------------------------------------------------------------------------------
1 | ## What we will do:
2 | In this short step:
3 | - Format Add Todo Page
4 | - Add Html5 Form Validations
5 |
6 | ## Useful Snippets
7 | ```
8 |
12 |
13 | ```
14 |
15 | ## Files List
16 |
17 | ### pom.xml
18 |
19 | ```xml
20 |
21 |
23 | 4.0.0
24 |
25 | com.in28minutes.springboot.web
26 | spring-boot-first-web-application
27 | 0.0.1-SNAPSHOT
28 | jar
29 |
30 | spring-boot-first-web-application
31 | Demo project for Spring Boot
32 |
33 |
34 | org.springframework.boot
35 | spring-boot-starter-parent
36 | 1.4.3.RELEASE
37 |
38 |
39 |
40 |
41 | UTF-8
42 | UTF-8
43 | 1.8
44 |
45 |
46 |
47 |
48 | org.springframework.boot
49 | spring-boot-starter-web
50 |
51 |
52 |
53 | javax.servlet
54 | jstl
55 |
56 |
57 |
58 | org.webjars
59 | bootstrap
60 | 3.3.6
61 |
62 |
63 |
64 | org.webjars
65 | jquery
66 | 1.9.1
67 |
68 |
69 |
70 | org.apache.tomcat.embed
71 | tomcat-embed-jasper
72 | provided
73 |
74 |
75 |
76 | org.springframework.boot
77 | spring-boot-devtools
78 | runtime
79 |
80 |
81 |
82 | org.springframework.boot
83 | spring-boot-starter-test
84 | test
85 |
86 |
87 |
88 |
89 |
90 |
91 | org.springframework.boot
92 | spring-boot-maven-plugin
93 |
94 |
95 |
96 |
97 |
98 | ```
99 | ---
100 | ### src/main/java/com/in28minutes/springboot/web/controller/LoginController.java
101 |
102 | ```java
103 | package com.in28minutes.springboot.web.controller;
104 |
105 | import org.springframework.beans.factory.annotation.Autowired;
106 | import org.springframework.stereotype.Controller;
107 | import org.springframework.ui.ModelMap;
108 | import org.springframework.web.bind.annotation.RequestMapping;
109 | import org.springframework.web.bind.annotation.RequestMethod;
110 | import org.springframework.web.bind.annotation.RequestParam;
111 | import org.springframework.web.bind.annotation.SessionAttributes;
112 |
113 | import com.in28minutes.springboot.web.service.LoginService;
114 |
115 | @Controller
116 | @SessionAttributes("name")
117 | public class LoginController {
118 |
119 | @Autowired
120 | LoginService service;
121 |
122 | @RequestMapping(value="/login", method = RequestMethod.GET)
123 | public String showLoginPage(ModelMap model){
124 | return "login";
125 | }
126 |
127 | @RequestMapping(value="/login", method = RequestMethod.POST)
128 | public String showWelcomePage(ModelMap model, @RequestParam String name, @RequestParam String password){
129 |
130 | boolean isValidUser = service.validateUser(name, password);
131 |
132 | if (!isValidUser) {
133 | model.put("errorMessage", "Invalid Credentials");
134 | return "login";
135 | }
136 |
137 | model.put("name", name);
138 | model.put("password", password);
139 |
140 | return "welcome";
141 | }
142 |
143 | }
144 | ```
145 | ---
146 | ### src/main/java/com/in28minutes/springboot/web/controller/TodoController.java
147 |
148 | ```java
149 | package com.in28minutes.springboot.web.controller;
150 |
151 | import java.util.Date;
152 |
153 | import org.springframework.beans.factory.annotation.Autowired;
154 | import org.springframework.stereotype.Controller;
155 | import org.springframework.ui.ModelMap;
156 | import org.springframework.web.bind.annotation.RequestMapping;
157 | import org.springframework.web.bind.annotation.RequestMethod;
158 | import org.springframework.web.bind.annotation.RequestParam;
159 | import org.springframework.web.bind.annotation.SessionAttributes;
160 |
161 | import com.in28minutes.springboot.web.service.LoginService;
162 | import com.in28minutes.springboot.web.service.TodoService;
163 |
164 | @Controller
165 | @SessionAttributes("name")
166 | public class TodoController {
167 |
168 | @Autowired
169 | TodoService service;
170 |
171 | @RequestMapping(value="/list-todos", method = RequestMethod.GET)
172 | public String showTodos(ModelMap model){
173 | String name = (String) model.get("name");
174 | model.put("todos", service.retrieveTodos(name));
175 | return "list-todos";
176 | }
177 |
178 | @RequestMapping(value="/add-todo", method = RequestMethod.GET)
179 | public String showAddTodoPage(ModelMap model){
180 | return "todo";
181 | }
182 |
183 | @RequestMapping(value="/delete-todo", method = RequestMethod.GET)
184 | public String deleteTodo(@RequestParam int id){
185 | service.deleteTodo(id);
186 | return "redirect:/list-todos";
187 | }
188 |
189 | @RequestMapping(value="/add-todo", method = RequestMethod.POST)
190 | public String addTodo(ModelMap model, @RequestParam String desc){
191 | service.addTodo((String) model.get("name"), desc, new Date(), false);
192 | return "redirect:/list-todos";
193 | }
194 |
195 | }
196 | ```
197 | ---
198 | ### src/main/java/com/in28minutes/springboot/web/model/Todo.java
199 |
200 | ```java
201 | package com.in28minutes.springboot.web.model;
202 |
203 | import java.util.Date;
204 |
205 | public class Todo {
206 | private int id;
207 | private String user;
208 | private String desc;
209 | private Date targetDate;
210 | private boolean isDone;
211 |
212 | public Todo(int id, String user, String desc, Date targetDate,
213 | boolean isDone) {
214 | super();
215 | this.id = id;
216 | this.user = user;
217 | this.desc = desc;
218 | this.targetDate = targetDate;
219 | this.isDone = isDone;
220 | }
221 |
222 | public int getId() {
223 | return id;
224 | }
225 |
226 | public void setId(int id) {
227 | this.id = id;
228 | }
229 |
230 | public String getUser() {
231 | return user;
232 | }
233 |
234 | public void setUser(String user) {
235 | this.user = user;
236 | }
237 |
238 | public String getDesc() {
239 | return desc;
240 | }
241 |
242 | public void setDesc(String desc) {
243 | this.desc = desc;
244 | }
245 |
246 | public Date getTargetDate() {
247 | return targetDate;
248 | }
249 |
250 | public void setTargetDate(Date targetDate) {
251 | this.targetDate = targetDate;
252 | }
253 |
254 | public boolean isDone() {
255 | return isDone;
256 | }
257 |
258 | public void setDone(boolean isDone) {
259 | this.isDone = isDone;
260 | }
261 |
262 | @Override
263 | public int hashCode() {
264 | final int prime = 31;
265 | int result = 1;
266 | result = prime * result + id;
267 | return result;
268 | }
269 |
270 | @Override
271 | public boolean equals(Object obj) {
272 | if (this == obj) {
273 | return true;
274 | }
275 | if (obj == null) {
276 | return false;
277 | }
278 | if (getClass() != obj.getClass()) {
279 | return false;
280 | }
281 | Todo other = (Todo) obj;
282 | if (id != other.id) {
283 | return false;
284 | }
285 | return true;
286 | }
287 |
288 | @Override
289 | public String toString() {
290 | return String.format(
291 | "Todo [id=%s, user=%s, desc=%s, targetDate=%s, isDone=%s]", id,
292 | user, desc, targetDate, isDone);
293 | }
294 |
295 | }
296 | ```
297 | ---
298 | ### src/main/java/com/in28minutes/springboot/web/service/LoginService.java
299 |
300 | ```java
301 | package com.in28minutes.springboot.web.service;
302 |
303 | import org.springframework.stereotype.Component;
304 | import org.springframework.stereotype.Service;
305 |
306 | @Service
307 | public class LoginService {
308 |
309 | public boolean validateUser(String userid, String password) {
310 | // in28minutes, dummy
311 | return userid.equalsIgnoreCase("in28minutes")
312 | && password.equalsIgnoreCase("dummy");
313 | }
314 |
315 | }
316 | ```
317 | ---
318 | ### src/main/java/com/in28minutes/springboot/web/service/TodoService.java
319 |
320 | ```java
321 | package com.in28minutes.springboot.web.service;
322 |
323 | import java.util.ArrayList;
324 | import java.util.Date;
325 | import java.util.Iterator;
326 | import java.util.List;
327 |
328 | import org.springframework.stereotype.Service;
329 |
330 | import com.in28minutes.springboot.web.model.Todo;
331 |
332 | @Service
333 | public class TodoService {
334 | private static List todos = new ArrayList();
335 | private static int todoCount = 3;
336 |
337 | static {
338 | todos.add(new Todo(1, "in28Minutes", "Learn Spring MVC", new Date(),
339 | false));
340 | todos.add(new Todo(2, "in28Minutes", "Learn Struts", new Date(), false));
341 | todos.add(new Todo(3, "in28Minutes", "Learn Hibernate", new Date(),
342 | false));
343 | }
344 |
345 | public List retrieveTodos(String user) {
346 | List filteredTodos = new ArrayList();
347 | for (Todo todo : todos) {
348 | if (todo.getUser().equals(user)) {
349 | filteredTodos.add(todo);
350 | }
351 | }
352 | return filteredTodos;
353 | }
354 |
355 | public void addTodo(String name, String desc, Date targetDate,
356 | boolean isDone) {
357 | todos.add(new Todo(++todoCount, name, desc, targetDate, isDone));
358 | }
359 |
360 | public void deleteTodo(int id) {
361 | Iterator iterator = todos.iterator();
362 | while (iterator.hasNext()) {
363 | Todo todo = iterator.next();
364 | if (todo.getId() == id) {
365 | iterator.remove();
366 | }
367 | }
368 | }
369 | }
370 | ```
371 | ---
372 | ### src/main/java/com/in28minutes/springboot/web/SpringBootFirstWebApplication.java
373 |
374 | ```java
375 | package com.in28minutes.springboot.web;
376 |
377 | import org.springframework.boot.SpringApplication;
378 | import org.springframework.boot.autoconfigure.SpringBootApplication;
379 | import org.springframework.context.annotation.ComponentScan;
380 |
381 | @SpringBootApplication
382 | @ComponentScan("com.in28minutes.springboot.web")
383 | public class SpringBootFirstWebApplication {
384 |
385 | public static void main(String[] args) {
386 | SpringApplication.run(SpringBootFirstWebApplication.class, args);
387 | }
388 | }
389 | ```
390 | ---
391 | ### src/main/resources/application.properties
392 |
393 | ```
394 | spring.mvc.view.prefix=/WEB-INF/jsp/
395 | spring.mvc.view.suffix=.jsp
396 | logging.level.org.springframework.web=INFO
397 | ```
398 | ---
399 | ### src/main/webapp/WEB-INF/jsp/list-todos.jsp
400 |
401 | ```
402 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
403 |
404 |
405 |
406 |
407 | Todo's for ${name}
408 |
410 |
411 |
412 |
413 |
414 |
415 | Your todos are
416 |
417 |
418 | Description |
419 | Target Date |
420 | Is it Done? |
421 | |
422 |
423 |
424 |
425 |
426 |
427 | ${todo.desc} |
428 | ${todo.targetDate} |
429 | ${todo.done} |
430 | Delete |
432 |
433 |
434 |
435 |
436 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 | ```
448 | ---
449 | ### src/main/webapp/WEB-INF/jsp/login.jsp
450 |
451 | ```
452 |
453 |
454 |
455 | First Web Application
456 |
457 |
458 |
459 | ${errorMessage}
460 |
465 |
466 |
467 |
468 | ```
469 | ---
470 | ### src/main/webapp/WEB-INF/jsp/todo.jsp
471 |
472 | ```
473 |
474 |
475 |
476 | First Web Application
477 |
479 |
480 |
481 |
482 |
483 |
484 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 | ```
502 | ---
503 | ### src/main/webapp/WEB-INF/jsp/welcome.jsp
504 |
505 | ```
506 |
507 |
508 |
509 | First Web Application
510 |
511 |
512 |
513 | Welcome ${name}!! Click here to manage your todo's.
514 |
515 |
516 |
517 | ```
518 | ---
519 | ### src/test/java/com/in28minutes/springboot/web/SpringBootFirstWebApplicationTests.java
520 |
521 | ```java
522 | package com.in28minutes.springboot.web;
523 |
524 | import org.junit.Test;
525 | import org.junit.runner.RunWith;
526 | import org.springframework.boot.test.context.SpringBootTest;
527 | import org.springframework.test.context.junit4.SpringRunner;
528 |
529 | @RunWith(SpringRunner.class)
530 | @SpringBootTest
531 | public class SpringBootFirstWebApplicationTests {
532 |
533 | @Test
534 | public void contextLoads() {
535 | }
536 |
537 | }
538 | ```
539 | ---
540 | ### todo.txt
541 |
542 | ```
543 | LoginController -> adds name to model
544 | welcome.jsp -> shows ${name}
545 |
546 | TodoController -> redirects to list-todos.jsp
547 | ${name} is empty
548 |
549 |
550 | Component, Service, Repository, Controller
551 | Autowired
552 | ComponentScan
553 |
554 | Field dummyService in com.in28minutes.springboot.web.controller.LoginController
555 | required a bean of type 'com.in28minutes.dummy.DummyService'
556 | that could not be found.
557 |
558 | Spring Boot Starter Parent
559 | Spring Boot Starter Web
560 | @SpringBootApplication
561 | Auto Configuration
562 |
563 | Dispatcher Servlet
564 |
565 | /login => "login"
566 |
567 | "login" => src/main/webapp/WEB-INF/jsp/login.jsp
568 |
569 |
570 | Search for a view named "login"
571 |
572 |
573 |
574 | /login => LoginController
575 | ```
576 | ---
577 |
--------------------------------------------------------------------------------
/Step18.md:
--------------------------------------------------------------------------------
1 | ## What we will do:
2 | - Lets use a command bean for Todo
3 | - Add Validations
4 | - The JSR 303 and JSR 349 defines specification for the Bean Validation API (version 1.0 and 1.1, respectively), and Hibernate Validator is the reference implementation.
5 | - org.hibernate:hibernate-validator
6 |
7 | ## Useful Snippets
8 | ```
9 | <%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
10 |
11 |
12 |
16 |
17 |
18 | @Size(min = 10, message = "Enter atleast 10 Characters.")
19 |
20 | @Valid Todo todo, BindingResult result
21 |
22 | if (result.hasErrors())
23 | return "todo";
24 |
25 |
26 |
27 | ```
28 | ## Files List
29 |
30 | ### pom.xml
31 |
32 | ```xml
33 |
34 |
36 | 4.0.0
37 |
38 | com.in28minutes.springboot.web
39 | spring-boot-first-web-application
40 | 0.0.1-SNAPSHOT
41 | jar
42 |
43 | spring-boot-first-web-application
44 | Demo project for Spring Boot
45 |
46 |
47 | org.springframework.boot
48 | spring-boot-starter-parent
49 | 1.4.3.RELEASE
50 |
51 |
52 |
53 |
54 | UTF-8
55 | UTF-8
56 | 1.8
57 |
58 |
59 |
60 |
61 | org.springframework.boot
62 | spring-boot-starter-web
63 |
64 |
65 |
66 | javax.servlet
67 | jstl
68 |
69 |
70 |
71 | org.webjars
72 | bootstrap
73 | 3.3.6
74 |
75 |
76 |
77 | org.webjars
78 | jquery
79 | 1.9.1
80 |
81 |
82 |
83 | org.apache.tomcat.embed
84 | tomcat-embed-jasper
85 | provided
86 |
87 |
88 |
89 | org.springframework.boot
90 | spring-boot-devtools
91 | runtime
92 |
93 |
94 |
95 | org.springframework.boot
96 | spring-boot-starter-test
97 | test
98 |
99 |
100 |
101 |
102 |
103 |
104 | org.springframework.boot
105 | spring-boot-maven-plugin
106 |
107 |
108 |
109 |
110 |
111 | ```
112 | ---
113 | ### src/main/java/com/in28minutes/springboot/web/controller/LoginController.java
114 |
115 | ```java
116 | package com.in28minutes.springboot.web.controller;
117 |
118 | import org.springframework.beans.factory.annotation.Autowired;
119 | import org.springframework.stereotype.Controller;
120 | import org.springframework.ui.ModelMap;
121 | import org.springframework.web.bind.annotation.RequestMapping;
122 | import org.springframework.web.bind.annotation.RequestMethod;
123 | import org.springframework.web.bind.annotation.RequestParam;
124 | import org.springframework.web.bind.annotation.SessionAttributes;
125 |
126 | import com.in28minutes.springboot.web.service.LoginService;
127 |
128 | @Controller
129 | @SessionAttributes("name")
130 | public class LoginController {
131 |
132 | @Autowired
133 | LoginService service;
134 |
135 | @RequestMapping(value="/login", method = RequestMethod.GET)
136 | public String showLoginPage(ModelMap model){
137 | return "login";
138 | }
139 |
140 | @RequestMapping(value="/login", method = RequestMethod.POST)
141 | public String showWelcomePage(ModelMap model, @RequestParam String name, @RequestParam String password){
142 |
143 | boolean isValidUser = service.validateUser(name, password);
144 |
145 | if (!isValidUser) {
146 | model.put("errorMessage", "Invalid Credentials");
147 | return "login";
148 | }
149 |
150 | model.put("name", name);
151 | model.put("password", password);
152 |
153 | return "welcome";
154 | }
155 |
156 | }
157 | ```
158 | ---
159 | ### src/main/java/com/in28minutes/springboot/web/controller/TodoController.java
160 |
161 | ```java
162 | package com.in28minutes.springboot.web.controller;
163 |
164 | import java.util.Date;
165 |
166 | import javax.validation.Valid;
167 |
168 | import org.springframework.beans.factory.annotation.Autowired;
169 | import org.springframework.stereotype.Controller;
170 | import org.springframework.ui.ModelMap;
171 | import org.springframework.validation.BindingResult;
172 | import org.springframework.web.bind.annotation.RequestMapping;
173 | import org.springframework.web.bind.annotation.RequestMethod;
174 | import org.springframework.web.bind.annotation.RequestParam;
175 | import org.springframework.web.bind.annotation.SessionAttributes;
176 |
177 | import com.in28minutes.springboot.web.model.Todo;
178 | import com.in28minutes.springboot.web.service.LoginService;
179 | import com.in28minutes.springboot.web.service.TodoService;
180 |
181 | @Controller
182 | @SessionAttributes("name")
183 | public class TodoController {
184 |
185 | @Autowired
186 | TodoService service;
187 |
188 | @RequestMapping(value = "/list-todos", method = RequestMethod.GET)
189 | public String showTodos(ModelMap model) {
190 | String name = (String) model.get("name");
191 | model.put("todos", service.retrieveTodos(name));
192 | return "list-todos";
193 | }
194 |
195 | @RequestMapping(value = "/add-todo", method = RequestMethod.GET)
196 | public String showAddTodoPage(ModelMap model) {
197 | model.addAttribute("todo", new Todo(0, (String) model.get("name"), "Default Desc",
198 | new Date(), false));
199 | return "todo";
200 | }
201 |
202 | @RequestMapping(value = "/delete-todo", method = RequestMethod.GET)
203 | public String deleteTodo(@RequestParam int id) {
204 | service.deleteTodo(id);
205 | return "redirect:/list-todos";
206 | }
207 |
208 | @RequestMapping(value = "/add-todo", method = RequestMethod.POST)
209 | public String addTodo(ModelMap model, @Valid Todo todo, BindingResult result) {
210 |
211 | if(result.hasErrors()){
212 | return "todo";
213 | }
214 |
215 | service.addTodo((String) model.get("name"), todo.getDesc(), new Date(),
216 | false);
217 | return "redirect:/list-todos";
218 | }
219 | }
220 | ```
221 | ---
222 | ### src/main/java/com/in28minutes/springboot/web/model/Todo.java
223 |
224 | ```java
225 | package com.in28minutes.springboot.web.model;
226 |
227 | import java.util.Date;
228 |
229 | import javax.validation.constraints.Size;
230 |
231 | public class Todo {
232 | private int id;
233 | private String user;
234 |
235 | @Size(min=10, message="Enter at least 10 Characters...")
236 | private String desc;
237 |
238 | private Date targetDate;
239 | private boolean isDone;
240 |
241 | public Todo() {
242 | super();
243 | }
244 |
245 | public Todo(int id, String user, String desc, Date targetDate,
246 | boolean isDone) {
247 | super();
248 | this.id = id;
249 | this.user = user;
250 | this.desc = desc;
251 | this.targetDate = targetDate;
252 | this.isDone = isDone;
253 | }
254 |
255 | public int getId() {
256 | return id;
257 | }
258 |
259 | public void setId(int id) {
260 | this.id = id;
261 | }
262 |
263 | public String getUser() {
264 | return user;
265 | }
266 |
267 | public void setUser(String user) {
268 | this.user = user;
269 | }
270 |
271 | public String getDesc() {
272 | return desc;
273 | }
274 |
275 | public void setDesc(String desc) {
276 | this.desc = desc;
277 | }
278 |
279 | public Date getTargetDate() {
280 | return targetDate;
281 | }
282 |
283 | public void setTargetDate(Date targetDate) {
284 | this.targetDate = targetDate;
285 | }
286 |
287 | public boolean isDone() {
288 | return isDone;
289 | }
290 |
291 | public void setDone(boolean isDone) {
292 | this.isDone = isDone;
293 | }
294 |
295 | @Override
296 | public int hashCode() {
297 | final int prime = 31;
298 | int result = 1;
299 | result = prime * result + id;
300 | return result;
301 | }
302 |
303 | @Override
304 | public boolean equals(Object obj) {
305 | if (this == obj) {
306 | return true;
307 | }
308 | if (obj == null) {
309 | return false;
310 | }
311 | if (getClass() != obj.getClass()) {
312 | return false;
313 | }
314 | Todo other = (Todo) obj;
315 | if (id != other.id) {
316 | return false;
317 | }
318 | return true;
319 | }
320 |
321 | @Override
322 | public String toString() {
323 | return String.format(
324 | "Todo [id=%s, user=%s, desc=%s, targetDate=%s, isDone=%s]", id,
325 | user, desc, targetDate, isDone);
326 | }
327 |
328 | }
329 | ```
330 | ---
331 | ### src/main/java/com/in28minutes/springboot/web/service/LoginService.java
332 |
333 | ```java
334 | package com.in28minutes.springboot.web.service;
335 |
336 | import org.springframework.stereotype.Component;
337 | import org.springframework.stereotype.Service;
338 |
339 | @Service
340 | public class LoginService {
341 |
342 | public boolean validateUser(String userid, String password) {
343 | // in28minutes, dummy
344 | return userid.equalsIgnoreCase("in28minutes")
345 | && password.equalsIgnoreCase("dummy");
346 | }
347 |
348 | }
349 | ```
350 | ---
351 | ### src/main/java/com/in28minutes/springboot/web/service/TodoService.java
352 |
353 | ```java
354 | package com.in28minutes.springboot.web.service;
355 |
356 | import java.util.ArrayList;
357 | import java.util.Date;
358 | import java.util.Iterator;
359 | import java.util.List;
360 |
361 | import org.springframework.stereotype.Service;
362 |
363 | import com.in28minutes.springboot.web.model.Todo;
364 |
365 | @Service
366 | public class TodoService {
367 | private static List todos = new ArrayList();
368 | private static int todoCount = 3;
369 |
370 | static {
371 | todos.add(new Todo(1, "in28Minutes", "Learn Spring MVC", new Date(),
372 | false));
373 | todos.add(new Todo(2, "in28Minutes", "Learn Struts", new Date(), false));
374 | todos.add(new Todo(3, "in28Minutes", "Learn Hibernate", new Date(),
375 | false));
376 | }
377 |
378 | public List retrieveTodos(String user) {
379 | List filteredTodos = new ArrayList();
380 | for (Todo todo : todos) {
381 | if (todo.getUser().equals(user)) {
382 | filteredTodos.add(todo);
383 | }
384 | }
385 | return filteredTodos;
386 | }
387 |
388 | public void addTodo(String name, String desc, Date targetDate,
389 | boolean isDone) {
390 | todos.add(new Todo(++todoCount, name, desc, targetDate, isDone));
391 | }
392 |
393 | public void deleteTodo(int id) {
394 | Iterator iterator = todos.iterator();
395 | while (iterator.hasNext()) {
396 | Todo todo = iterator.next();
397 | if (todo.getId() == id) {
398 | iterator.remove();
399 | }
400 | }
401 | }
402 | }
403 | ```
404 | ---
405 | ### src/main/java/com/in28minutes/springboot/web/SpringBootFirstWebApplication.java
406 |
407 | ```java
408 | package com.in28minutes.springboot.web;
409 |
410 | import org.springframework.boot.SpringApplication;
411 | import org.springframework.boot.autoconfigure.SpringBootApplication;
412 | import org.springframework.context.annotation.ComponentScan;
413 |
414 | @SpringBootApplication
415 | @ComponentScan("com.in28minutes.springboot.web")
416 | public class SpringBootFirstWebApplication {
417 |
418 | public static void main(String[] args) {
419 | SpringApplication.run(SpringBootFirstWebApplication.class, args);
420 | }
421 | }
422 | ```
423 | ---
424 | ### src/main/resources/application.properties
425 |
426 | ```
427 | spring.mvc.view.prefix=/WEB-INF/jsp/
428 | spring.mvc.view.suffix=.jsp
429 | logging.level.org.springframework.web=INFO
430 | ```
431 | ---
432 | ### src/main/webapp/WEB-INF/jsp/list-todos.jsp
433 |
434 | ```
435 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
436 |
437 |
438 |
439 |
440 | Todo's for ${name}
441 |
443 |
444 |
445 |
446 |
447 |
448 | Your todos are
449 |
450 |
451 | Description |
452 | Target Date |
453 | Is it Done? |
454 | |
455 |
456 |
457 |
458 |
459 |
460 | ${todo.desc} |
461 | ${todo.targetDate} |
462 | ${todo.done} |
463 | Delete |
465 |
466 |
467 |
468 |
469 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 | ```
481 | ---
482 | ### src/main/webapp/WEB-INF/jsp/login.jsp
483 |
484 | ```
485 |
486 |
487 |
488 | First Web Application
489 |
490 |
491 |
492 | ${errorMessage}
493 |
498 |
499 |
500 |
501 | ```
502 | ---
503 | ### src/main/webapp/WEB-INF/jsp/todo.jsp
504 |
505 | ```
506 | <%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
507 |
508 |
509 |
510 | First Web Application
511 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 | ```
537 | ---
538 | ### src/main/webapp/WEB-INF/jsp/welcome.jsp
539 |
540 | ```
541 |
542 |
543 |
544 | First Web Application
545 |
546 |
547 |
548 | Welcome ${name}!! Click here to manage your todo's.
549 |
550 |
551 |
552 | ```
553 | ---
554 | ### src/test/java/com/in28minutes/springboot/web/SpringBootFirstWebApplicationTests.java
555 |
556 | ```java
557 | package com.in28minutes.springboot.web;
558 |
559 | import org.junit.Test;
560 | import org.junit.runner.RunWith;
561 | import org.springframework.boot.test.context.SpringBootTest;
562 | import org.springframework.test.context.junit4.SpringRunner;
563 |
564 | @RunWith(SpringRunner.class)
565 | @SpringBootTest
566 | public class SpringBootFirstWebApplicationTests {
567 |
568 | @Test
569 | public void contextLoads() {
570 | }
571 |
572 | }
573 | ```
574 | ---
575 | ### todo.txt
576 |
577 | ```
578 | Implementing Server Side Validation
579 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
580 | Command Bean or Form Backing Bean
581 |
582 | Add Validation
583 | Use Validation on Controller
584 | Display Errors in View
585 |
586 | Command Bean
587 | ~~~~~~~~~~~~
588 | Controller
589 | View - Spring Form Tags
590 |
591 |
592 |
593 | LoginController -> adds name to model
594 | welcome.jsp -> shows ${name}
595 |
596 | TodoController -> redirects to list-todos.jsp
597 | ${name} is empty
598 |
599 |
600 | Component, Service, Repository, Controller
601 | Autowired
602 | ComponentScan
603 |
604 | Field dummyService in com.in28minutes.springboot.web.controller.LoginController
605 | required a bean of type 'com.in28minutes.dummy.DummyService'
606 | that could not be found.
607 |
608 | Spring Boot Starter Parent
609 | Spring Boot Starter Web
610 | @SpringBootApplication
611 | Auto Configuration
612 |
613 | Dispatcher Servlet
614 |
615 | /login => "login"
616 |
617 | "login" => src/main/webapp/WEB-INF/jsp/login.jsp
618 |
619 |
620 | Search for a view named "login"
621 |
622 |
623 |
624 | /login => LoginController
625 | ```
626 | ---
627 |
--------------------------------------------------------------------------------
/Step18.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/in28minutes/SpringBootWebApplicationStepByStep/7611e5a098e49023ee03ce1446e465a4c567da45/Step18.zip
--------------------------------------------------------------------------------
/Step19.md:
--------------------------------------------------------------------------------
1 | ## What we will do:
2 | - Add Update Functionality
3 | - Lets Use the Same JSP as earlier.
4 |
5 | ## Useful Snippets
6 | ```
7 | public Todo retrieveTodo(int id) {
8 | for (Todo todo : todos) {
9 | if (todo.getId() == id)
10 | return todo;
11 | }
12 | return null;
13 | }
14 |
15 | public void updateTodo(Todo todo) {
16 | todos.remove(todo);
17 | todos.add(todo);
18 | }
19 |
20 | todo.setUser("in28Minutes"); //TODO:Remove Hardcoding Later
21 | service.updateTodo(todo);
22 |
23 |
24 | ```
25 |
26 | ## Files List
27 |
28 | ### pom.xml
29 |
30 | ```xml
31 |
32 |
34 | 4.0.0
35 |
36 | com.in28minutes.springboot.web
37 | spring-boot-first-web-application
38 | 0.0.1-SNAPSHOT
39 | jar
40 |
41 | spring-boot-first-web-application
42 | Demo project for Spring Boot
43 |
44 |
45 | org.springframework.boot
46 | spring-boot-starter-parent
47 | 1.4.3.RELEASE
48 |
49 |
50 |
51 |
52 | UTF-8
53 | UTF-8
54 | 1.8
55 |
56 |
57 |
58 |
59 | org.springframework.boot
60 | spring-boot-starter-web
61 |
62 |
63 |
64 | javax.servlet
65 | jstl
66 |
67 |
68 |
69 | org.webjars
70 | bootstrap
71 | 3.3.6
72 |
73 |
74 |
75 | org.webjars
76 | jquery
77 | 1.9.1
78 |
79 |
80 |
81 | org.apache.tomcat.embed
82 | tomcat-embed-jasper
83 | provided
84 |
85 |
86 |
87 | org.springframework.boot
88 | spring-boot-devtools
89 | runtime
90 |
91 |
92 |
93 | org.springframework.boot
94 | spring-boot-starter-test
95 | test
96 |
97 |
98 |
99 |
100 |
101 |
102 | org.springframework.boot
103 | spring-boot-maven-plugin
104 |
105 |
106 |
107 |
108 |
109 | ```
110 | ---
111 | ### src/main/java/com/in28minutes/springboot/web/controller/LoginController.java
112 |
113 | ```java
114 | package com.in28minutes.springboot.web.controller;
115 |
116 | import org.springframework.beans.factory.annotation.Autowired;
117 | import org.springframework.stereotype.Controller;
118 | import org.springframework.ui.ModelMap;
119 | import org.springframework.web.bind.annotation.RequestMapping;
120 | import org.springframework.web.bind.annotation.RequestMethod;
121 | import org.springframework.web.bind.annotation.RequestParam;
122 | import org.springframework.web.bind.annotation.SessionAttributes;
123 |
124 | import com.in28minutes.springboot.web.service.LoginService;
125 |
126 | @Controller
127 | @SessionAttributes("name")
128 | public class LoginController {
129 |
130 | @Autowired
131 | LoginService service;
132 |
133 | @RequestMapping(value="/login", method = RequestMethod.GET)
134 | public String showLoginPage(ModelMap model){
135 | return "login";
136 | }
137 |
138 | @RequestMapping(value="/login", method = RequestMethod.POST)
139 | public String showWelcomePage(ModelMap model, @RequestParam String name, @RequestParam String password){
140 |
141 | boolean isValidUser = service.validateUser(name, password);
142 |
143 | if (!isValidUser) {
144 | model.put("errorMessage", "Invalid Credentials");
145 | return "login";
146 | }
147 |
148 | model.put("name", name);
149 | model.put("password", password);
150 |
151 | return "welcome";
152 | }
153 |
154 | }
155 | ```
156 | ---
157 | ### src/main/java/com/in28minutes/springboot/web/controller/TodoController.java
158 |
159 | ```java
160 | package com.in28minutes.springboot.web.controller;
161 |
162 | import java.util.Date;
163 |
164 | import javax.validation.Valid;
165 |
166 | import org.springframework.beans.factory.annotation.Autowired;
167 | import org.springframework.stereotype.Controller;
168 | import org.springframework.ui.ModelMap;
169 | import org.springframework.validation.BindingResult;
170 | import org.springframework.web.bind.annotation.RequestMapping;
171 | import org.springframework.web.bind.annotation.RequestMethod;
172 | import org.springframework.web.bind.annotation.RequestParam;
173 | import org.springframework.web.bind.annotation.SessionAttributes;
174 |
175 | import com.in28minutes.springboot.web.model.Todo;
176 | import com.in28minutes.springboot.web.service.LoginService;
177 | import com.in28minutes.springboot.web.service.TodoService;
178 |
179 | @Controller
180 | @SessionAttributes("name")
181 | public class TodoController {
182 |
183 | @Autowired
184 | TodoService service;
185 |
186 | @RequestMapping(value = "/list-todos", method = RequestMethod.GET)
187 | public String showTodos(ModelMap model) {
188 | String name = (String) model.get("name");
189 | model.put("todos", service.retrieveTodos(name));
190 | return "list-todos";
191 | }
192 |
193 | @RequestMapping(value = "/add-todo", method = RequestMethod.GET)
194 | public String showAddTodoPage(ModelMap model) {
195 | model.addAttribute("todo", new Todo(0, (String) model.get("name"),
196 | "Default Desc", new Date(), false));
197 | return "todo";
198 | }
199 |
200 | @RequestMapping(value = "/delete-todo", method = RequestMethod.GET)
201 | public String deleteTodo(@RequestParam int id) {
202 | service.deleteTodo(id);
203 | return "redirect:/list-todos";
204 | }
205 |
206 | @RequestMapping(value = "/update-todo", method = RequestMethod.GET)
207 | public String showUpdateTodoPage(@RequestParam int id, ModelMap model) {
208 | Todo todo = service.retrieveTodo(id);
209 | model.put("todo", todo);
210 | return "todo";
211 | }
212 |
213 | @RequestMapping(value = "/update-todo", method = RequestMethod.POST)
214 | public String updateTodo(ModelMap model, @Valid Todo todo, BindingResult result) {
215 |
216 | if (result.hasErrors()) {
217 | return "todo";
218 | }
219 |
220 | todo.setUser((String) model.get("name"));
221 |
222 | service.updateTodo(todo);
223 |
224 | return "redirect:/list-todos";
225 | }
226 |
227 | @RequestMapping(value = "/add-todo", method = RequestMethod.POST)
228 | public String addTodo(ModelMap model, @Valid Todo todo, BindingResult result) {
229 |
230 | if (result.hasErrors()) {
231 | return "todo";
232 | }
233 |
234 | service.addTodo((String) model.get("name"), todo.getDesc(), new Date(),
235 | false);
236 | return "redirect:/list-todos";
237 | }
238 | }
239 | ```
240 | ---
241 | ### src/main/java/com/in28minutes/springboot/web/model/Todo.java
242 |
243 | ```java
244 | package com.in28minutes.springboot.web.model;
245 |
246 | import java.util.Date;
247 |
248 | import javax.validation.constraints.Size;
249 |
250 | public class Todo {
251 | private int id;
252 | private String user;
253 |
254 | @Size(min=10, message="Enter at least 10 Characters...")
255 | private String desc;
256 |
257 | private Date targetDate;
258 | private boolean isDone;
259 |
260 | public Todo() {
261 | super();
262 | }
263 |
264 | public Todo(int id, String user, String desc, Date targetDate,
265 | boolean isDone) {
266 | super();
267 | this.id = id;
268 | this.user = user;
269 | this.desc = desc;
270 | this.targetDate = targetDate;
271 | this.isDone = isDone;
272 | }
273 |
274 | public int getId() {
275 | return id;
276 | }
277 |
278 | public void setId(int id) {
279 | this.id = id;
280 | }
281 |
282 | public String getUser() {
283 | return user;
284 | }
285 |
286 | public void setUser(String user) {
287 | this.user = user;
288 | }
289 |
290 | public String getDesc() {
291 | return desc;
292 | }
293 |
294 | public void setDesc(String desc) {
295 | this.desc = desc;
296 | }
297 |
298 | public Date getTargetDate() {
299 | return targetDate;
300 | }
301 |
302 | public void setTargetDate(Date targetDate) {
303 | this.targetDate = targetDate;
304 | }
305 |
306 | public boolean isDone() {
307 | return isDone;
308 | }
309 |
310 | public void setDone(boolean isDone) {
311 | this.isDone = isDone;
312 | }
313 |
314 | @Override
315 | public int hashCode() {
316 | final int prime = 31;
317 | int result = 1;
318 | result = prime * result + id;
319 | return result;
320 | }
321 |
322 | @Override
323 | public boolean equals(Object obj) {
324 | if (this == obj) {
325 | return true;
326 | }
327 | if (obj == null) {
328 | return false;
329 | }
330 | if (getClass() != obj.getClass()) {
331 | return false;
332 | }
333 | Todo other = (Todo) obj;
334 | if (id != other.id) {
335 | return false;
336 | }
337 | return true;
338 | }
339 |
340 | @Override
341 | public String toString() {
342 | return String.format(
343 | "Todo [id=%s, user=%s, desc=%s, targetDate=%s, isDone=%s]", id,
344 | user, desc, targetDate, isDone);
345 | }
346 |
347 | }
348 | ```
349 | ---
350 | ### src/main/java/com/in28minutes/springboot/web/service/LoginService.java
351 |
352 | ```java
353 | package com.in28minutes.springboot.web.service;
354 |
355 | import org.springframework.stereotype.Component;
356 | import org.springframework.stereotype.Service;
357 |
358 | @Service
359 | public class LoginService {
360 |
361 | public boolean validateUser(String userid, String password) {
362 | // in28minutes, dummy
363 | return userid.equalsIgnoreCase("in28minutes")
364 | && password.equalsIgnoreCase("dummy");
365 | }
366 |
367 | }
368 | ```
369 | ---
370 | ### src/main/java/com/in28minutes/springboot/web/service/TodoService.java
371 |
372 | ```java
373 | package com.in28minutes.springboot.web.service;
374 |
375 | import java.util.ArrayList;
376 | import java.util.Date;
377 | import java.util.Iterator;
378 | import java.util.List;
379 |
380 | import org.springframework.stereotype.Service;
381 |
382 | import com.in28minutes.springboot.web.model.Todo;
383 |
384 | @Service
385 | public class TodoService {
386 | private static List todos = new ArrayList();
387 | private static int todoCount = 3;
388 |
389 | static {
390 | todos.add(new Todo(1, "in28Minutes", "Learn Spring MVC", new Date(),
391 | false));
392 | todos.add(new Todo(2, "in28Minutes", "Learn Struts", new Date(), false));
393 | todos.add(new Todo(3, "in28Minutes", "Learn Hibernate", new Date(),
394 | false));
395 | }
396 |
397 | public List retrieveTodos(String user) {
398 | List filteredTodos = new ArrayList();
399 | for (Todo todo : todos) {
400 | if (todo.getUser().equalsIgnoreCase(user)) {
401 | filteredTodos.add(todo);
402 | }
403 | }
404 | return filteredTodos;
405 | }
406 |
407 | public Todo retrieveTodo(int id) {
408 | for (Todo todo : todos) {
409 | if (todo.getId()==id) {
410 | return todo;
411 | }
412 | }
413 | return null;
414 | }
415 |
416 | public void updateTodo(Todo todo){
417 | todos.remove(todo);
418 | todos.add(todo);
419 | }
420 |
421 | public void addTodo(String name, String desc, Date targetDate,
422 | boolean isDone) {
423 | todos.add(new Todo(++todoCount, name, desc, targetDate, isDone));
424 | }
425 |
426 | public void deleteTodo(int id) {
427 | Iterator iterator = todos.iterator();
428 | while (iterator.hasNext()) {
429 | Todo todo = iterator.next();
430 | if (todo.getId() == id) {
431 | iterator.remove();
432 | }
433 | }
434 | }
435 | }
436 | ```
437 | ---
438 | ### src/main/java/com/in28minutes/springboot/web/SpringBootFirstWebApplication.java
439 |
440 | ```java
441 | package com.in28minutes.springboot.web;
442 |
443 | import org.springframework.boot.SpringApplication;
444 | import org.springframework.boot.autoconfigure.SpringBootApplication;
445 | import org.springframework.context.annotation.ComponentScan;
446 |
447 | @SpringBootApplication
448 | @ComponentScan("com.in28minutes.springboot.web")
449 | public class SpringBootFirstWebApplication {
450 |
451 | public static void main(String[] args) {
452 | SpringApplication.run(SpringBootFirstWebApplication.class, args);
453 | }
454 | }
455 | ```
456 | ---
457 | ### src/main/resources/application.properties
458 |
459 | ```
460 | spring.mvc.view.prefix=/WEB-INF/jsp/
461 | spring.mvc.view.suffix=.jsp
462 | logging.level.org.springframework.web=INFO
463 | ```
464 | ---
465 | ### src/main/webapp/WEB-INF/jsp/list-todos.jsp
466 |
467 | ```
468 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
469 |
470 |
471 |
472 |
473 | Todo's for ${name}
474 |
476 |
477 |
478 |
479 |
480 |
481 | Your todos are
482 |
483 |
484 | Description |
485 | Target Date |
486 | Is it Done? |
487 | |
488 | |
489 |
490 |
491 |
492 |
493 |
494 | ${todo.desc} |
495 | ${todo.targetDate} |
496 | ${todo.done} |
497 | Update |
499 | Delete |
501 |
502 |
503 |
504 |
505 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 | ```
517 | ---
518 | ### src/main/webapp/WEB-INF/jsp/login.jsp
519 |
520 | ```
521 |
522 |
523 |
524 | First Web Application
525 |
526 |
527 |
528 | ${errorMessage}
529 |
534 |
535 |
536 |
537 | ```
538 | ---
539 | ### src/main/webapp/WEB-INF/jsp/todo.jsp
540 |
541 | ```
542 | <%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
543 |
544 |
545 |
546 | First Web Application
547 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 | ```
576 | ---
577 | ### src/main/webapp/WEB-INF/jsp/welcome.jsp
578 |
579 | ```
580 |
581 |
582 |
583 | First Web Application
584 |
585 |
586 |
587 | Welcome ${name}!! Click here to manage your todo's.
588 |
589 |
590 |
591 | ```
592 | ---
593 | ### src/test/java/com/in28minutes/springboot/web/SpringBootFirstWebApplicationTests.java
594 |
595 | ```java
596 | package com.in28minutes.springboot.web;
597 |
598 | import org.junit.Test;
599 | import org.junit.runner.RunWith;
600 | import org.springframework.boot.test.context.SpringBootTest;
601 | import org.springframework.test.context.junit4.SpringRunner;
602 |
603 | @RunWith(SpringRunner.class)
604 | @SpringBootTest
605 | public class SpringBootFirstWebApplicationTests {
606 |
607 | @Test
608 | public void contextLoads() {
609 | }
610 |
611 | }
612 | ```
613 | ---
614 | ### todo.txt
615 |
616 | ```
617 | Implementing Server Side Validation
618 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
619 | Command Bean or Form Backing Bean
620 |
621 | Add Validation
622 | Use Validation on Controller
623 | Display Errors in View
624 |
625 | Command Bean
626 | ~~~~~~~~~~~~
627 | Controller
628 | View - Spring Form Tags
629 |
630 |
631 |
632 | LoginController -> adds name to model
633 | welcome.jsp -> shows ${name}
634 |
635 | TodoController -> redirects to list-todos.jsp
636 | ${name} is empty
637 |
638 |
639 | Component, Service, Repository, Controller
640 | Autowired
641 | ComponentScan
642 |
643 | Field dummyService in com.in28minutes.springboot.web.controller.LoginController
644 | required a bean of type 'com.in28minutes.dummy.DummyService'
645 | that could not be found.
646 |
647 | Spring Boot Starter Parent
648 | Spring Boot Starter Web
649 | @SpringBootApplication
650 | Auto Configuration
651 |
652 | Dispatcher Servlet
653 |
654 | /login => "login"
655 |
656 | "login" => src/main/webapp/WEB-INF/jsp/login.jsp
657 |
658 |
659 | Search for a view named "login"
660 |
661 |
662 |
663 | /login => LoginController
664 | ```
665 | ---
666 |
--------------------------------------------------------------------------------
/Step19.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/in28minutes/SpringBootWebApplicationStepByStep/7611e5a098e49023ee03ce1446e465a4c567da45/Step19.zip
--------------------------------------------------------------------------------
/Step20.md:
--------------------------------------------------------------------------------
1 | ## What we will do:
2 | - Make real use of the Target Date Field
3 | - initBinder method
4 |
5 | ## Useful Snippets
6 | ```
7 | <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
8 |
10 |
11 |
12 | @InitBinder
13 | protected void initBinder(WebDataBinder binder) {
14 | SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
15 | binder.registerCustomEditor(Date.class, new CustomDateEditor(
16 | dateFormat, false));
17 | }
18 |
19 |
20 | org.webjars
21 | bootstrap-datepicker
22 | 1.0.1
23 |
24 |
25 |
27 |
28 |
33 |
34 | ```
35 |
36 | ## Files List
37 |
38 | ### pom.xml
39 |
40 | ```xml
41 |
42 |
44 | 4.0.0
45 |
46 | com.in28minutes.springboot.web
47 | spring-boot-first-web-application
48 | 0.0.1-SNAPSHOT
49 | jar
50 |
51 | spring-boot-first-web-application
52 | Demo project for Spring Boot
53 |
54 |
55 | org.springframework.boot
56 | spring-boot-starter-parent
57 | 1.4.3.RELEASE
58 |
59 |
60 |
61 |
62 | UTF-8
63 | UTF-8
64 | 1.8
65 |
66 |
67 |
68 |
69 | org.springframework.boot
70 | spring-boot-starter-web
71 |
72 |
73 |
74 | javax.servlet
75 | jstl
76 |
77 |
78 |
79 | org.webjars
80 | bootstrap
81 | 3.3.6
82 |
83 |
84 |
85 | org.webjars
86 | bootstrap-datepicker
87 | 1.0.1
88 |
89 |
90 |
91 | org.webjars
92 | jquery
93 | 1.9.1
94 |
95 |
96 |
97 | org.apache.tomcat.embed
98 | tomcat-embed-jasper
99 | provided
100 |
101 |
102 |
103 | org.springframework.boot
104 | spring-boot-devtools
105 | runtime
106 |
107 |
108 |
109 | org.springframework.boot
110 | spring-boot-starter-test
111 | test
112 |
113 |
114 |
115 |
116 |
117 |
118 | org.springframework.boot
119 | spring-boot-maven-plugin
120 |
121 |
122 |
123 |
124 |
125 | ```
126 | ---
127 | ### src/main/java/com/in28minutes/springboot/web/controller/LoginController.java
128 |
129 | ```java
130 | package com.in28minutes.springboot.web.controller;
131 |
132 | import org.springframework.beans.factory.annotation.Autowired;
133 | import org.springframework.stereotype.Controller;
134 | import org.springframework.ui.ModelMap;
135 | import org.springframework.web.bind.annotation.RequestMapping;
136 | import org.springframework.web.bind.annotation.RequestMethod;
137 | import org.springframework.web.bind.annotation.RequestParam;
138 | import org.springframework.web.bind.annotation.SessionAttributes;
139 |
140 | import com.in28minutes.springboot.web.service.LoginService;
141 |
142 | @Controller
143 | @SessionAttributes("name")
144 | public class LoginController {
145 |
146 | @Autowired
147 | LoginService service;
148 |
149 | @RequestMapping(value="/login", method = RequestMethod.GET)
150 | public String showLoginPage(ModelMap model){
151 | return "login";
152 | }
153 |
154 | @RequestMapping(value="/login", method = RequestMethod.POST)
155 | public String showWelcomePage(ModelMap model, @RequestParam String name, @RequestParam String password){
156 |
157 | boolean isValidUser = service.validateUser(name, password);
158 |
159 | if (!isValidUser) {
160 | model.put("errorMessage", "Invalid Credentials");
161 | return "login";
162 | }
163 |
164 | model.put("name", name);
165 | model.put("password", password);
166 |
167 | return "welcome";
168 | }
169 |
170 | }
171 | ```
172 | ---
173 | ### src/main/java/com/in28minutes/springboot/web/controller/TodoController.java
174 |
175 | ```java
176 | package com.in28minutes.springboot.web.controller;
177 |
178 | import java.text.SimpleDateFormat;
179 | import java.util.Date;
180 |
181 | import javax.validation.Valid;
182 |
183 | import org.springframework.beans.factory.annotation.Autowired;
184 | import org.springframework.beans.propertyeditors.CustomDateEditor;
185 | import org.springframework.stereotype.Controller;
186 | import org.springframework.ui.ModelMap;
187 | import org.springframework.validation.BindingResult;
188 | import org.springframework.web.bind.WebDataBinder;
189 | import org.springframework.web.bind.annotation.InitBinder;
190 | import org.springframework.web.bind.annotation.RequestMapping;
191 | import org.springframework.web.bind.annotation.RequestMethod;
192 | import org.springframework.web.bind.annotation.RequestParam;
193 | import org.springframework.web.bind.annotation.SessionAttributes;
194 |
195 | import com.in28minutes.springboot.web.model.Todo;
196 | import com.in28minutes.springboot.web.service.LoginService;
197 | import com.in28minutes.springboot.web.service.TodoService;
198 |
199 | @Controller
200 | @SessionAttributes("name")
201 | public class TodoController {
202 |
203 | @Autowired
204 | TodoService service;
205 |
206 | @InitBinder
207 | public void initBinder(WebDataBinder binder) {
208 | // Date - dd/MM/yyyy
209 | SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
210 | binder.registerCustomEditor(Date.class, new CustomDateEditor(
211 | dateFormat, false));
212 | }
213 |
214 | @RequestMapping(value = "/list-todos", method = RequestMethod.GET)
215 | public String showTodos(ModelMap model) {
216 | String name = (String) model.get("name");
217 | model.put("todos", service.retrieveTodos(name));
218 | return "list-todos";
219 | }
220 |
221 | @RequestMapping(value = "/add-todo", method = RequestMethod.GET)
222 | public String showAddTodoPage(ModelMap model) {
223 | model.addAttribute("todo", new Todo(0, (String) model.get("name"),
224 | "Default Desc", new Date(), false));
225 | return "todo";
226 | }
227 |
228 | @RequestMapping(value = "/delete-todo", method = RequestMethod.GET)
229 | public String deleteTodo(@RequestParam int id) {
230 | service.deleteTodo(id);
231 | return "redirect:/list-todos";
232 | }
233 |
234 | @RequestMapping(value = "/update-todo", method = RequestMethod.GET)
235 | public String showUpdateTodoPage(@RequestParam int id, ModelMap model) {
236 | Todo todo = service.retrieveTodo(id);
237 | model.put("todo", todo);
238 | return "todo";
239 | }
240 |
241 | @RequestMapping(value = "/update-todo", method = RequestMethod.POST)
242 | public String updateTodo(ModelMap model, @Valid Todo todo,
243 | BindingResult result) {
244 |
245 | if (result.hasErrors()) {
246 | return "todo";
247 | }
248 |
249 | todo.setUser((String) model.get("name"));
250 |
251 | service.updateTodo(todo);
252 |
253 | return "redirect:/list-todos";
254 | }
255 |
256 | @RequestMapping(value = "/add-todo", method = RequestMethod.POST)
257 | public String addTodo(ModelMap model, @Valid Todo todo, BindingResult result) {
258 |
259 | if (result.hasErrors()) {
260 | return "todo";
261 | }
262 |
263 | service.addTodo((String) model.get("name"), todo.getDesc(), todo.getTargetDate(),
264 | false);
265 | return "redirect:/list-todos";
266 | }
267 | }
268 | ```
269 | ---
270 | ### src/main/java/com/in28minutes/springboot/web/model/Todo.java
271 |
272 | ```java
273 | package com.in28minutes.springboot.web.model;
274 |
275 | import java.util.Date;
276 |
277 | import javax.validation.constraints.Size;
278 |
279 | public class Todo {
280 | private int id;
281 | private String user;
282 |
283 | @Size(min=10, message="Enter at least 10 Characters...")
284 | private String desc;
285 |
286 | private Date targetDate;
287 | private boolean isDone;
288 |
289 | public Todo() {
290 | super();
291 | }
292 |
293 | public Todo(int id, String user, String desc, Date targetDate,
294 | boolean isDone) {
295 | super();
296 | this.id = id;
297 | this.user = user;
298 | this.desc = desc;
299 | this.targetDate = targetDate;
300 | this.isDone = isDone;
301 | }
302 |
303 | public int getId() {
304 | return id;
305 | }
306 |
307 | public void setId(int id) {
308 | this.id = id;
309 | }
310 |
311 | public String getUser() {
312 | return user;
313 | }
314 |
315 | public void setUser(String user) {
316 | this.user = user;
317 | }
318 |
319 | public String getDesc() {
320 | return desc;
321 | }
322 |
323 | public void setDesc(String desc) {
324 | this.desc = desc;
325 | }
326 |
327 | public Date getTargetDate() {
328 | return targetDate;
329 | }
330 |
331 | public void setTargetDate(Date targetDate) {
332 | this.targetDate = targetDate;
333 | }
334 |
335 | public boolean isDone() {
336 | return isDone;
337 | }
338 |
339 | public void setDone(boolean isDone) {
340 | this.isDone = isDone;
341 | }
342 |
343 | @Override
344 | public int hashCode() {
345 | final int prime = 31;
346 | int result = 1;
347 | result = prime * result + id;
348 | return result;
349 | }
350 |
351 | @Override
352 | public boolean equals(Object obj) {
353 | if (this == obj) {
354 | return true;
355 | }
356 | if (obj == null) {
357 | return false;
358 | }
359 | if (getClass() != obj.getClass()) {
360 | return false;
361 | }
362 | Todo other = (Todo) obj;
363 | if (id != other.id) {
364 | return false;
365 | }
366 | return true;
367 | }
368 |
369 | @Override
370 | public String toString() {
371 | return String.format(
372 | "Todo [id=%s, user=%s, desc=%s, targetDate=%s, isDone=%s]", id,
373 | user, desc, targetDate, isDone);
374 | }
375 |
376 | }
377 | ```
378 | ---
379 | ### src/main/java/com/in28minutes/springboot/web/service/LoginService.java
380 |
381 | ```java
382 | package com.in28minutes.springboot.web.service;
383 |
384 | import org.springframework.stereotype.Component;
385 | import org.springframework.stereotype.Service;
386 |
387 | @Service
388 | public class LoginService {
389 |
390 | public boolean validateUser(String userid, String password) {
391 | // in28minutes, dummy
392 | return userid.equalsIgnoreCase("in28minutes")
393 | && password.equalsIgnoreCase("dummy");
394 | }
395 |
396 | }
397 | ```
398 | ---
399 | ### src/main/java/com/in28minutes/springboot/web/service/TodoService.java
400 |
401 | ```java
402 | package com.in28minutes.springboot.web.service;
403 |
404 | import java.util.ArrayList;
405 | import java.util.Date;
406 | import java.util.Iterator;
407 | import java.util.List;
408 |
409 | import org.springframework.stereotype.Service;
410 |
411 | import com.in28minutes.springboot.web.model.Todo;
412 |
413 | @Service
414 | public class TodoService {
415 | private static List todos = new ArrayList();
416 | private static int todoCount = 3;
417 |
418 | static {
419 | todos.add(new Todo(1, "in28Minutes", "Learn Spring MVC", new Date(),
420 | false));
421 | todos.add(new Todo(2, "in28Minutes", "Learn Struts", new Date(), false));
422 | todos.add(new Todo(3, "in28Minutes", "Learn Hibernate", new Date(),
423 | false));
424 | }
425 |
426 | public List retrieveTodos(String user) {
427 | List filteredTodos = new ArrayList();
428 | for (Todo todo : todos) {
429 | if (todo.getUser().equalsIgnoreCase(user)) {
430 | filteredTodos.add(todo);
431 | }
432 | }
433 | return filteredTodos;
434 | }
435 |
436 | public Todo retrieveTodo(int id) {
437 | for (Todo todo : todos) {
438 | if (todo.getId()==id) {
439 | return todo;
440 | }
441 | }
442 | return null;
443 | }
444 |
445 | public void updateTodo(Todo todo){
446 | todos.remove(todo);
447 | todos.add(todo);
448 | }
449 |
450 | public void addTodo(String name, String desc, Date targetDate,
451 | boolean isDone) {
452 | todos.add(new Todo(++todoCount, name, desc, targetDate, isDone));
453 | }
454 |
455 | public void deleteTodo(int id) {
456 | Iterator iterator = todos.iterator();
457 | while (iterator.hasNext()) {
458 | Todo todo = iterator.next();
459 | if (todo.getId() == id) {
460 | iterator.remove();
461 | }
462 | }
463 | }
464 | }
465 | ```
466 | ---
467 | ### src/main/java/com/in28minutes/springboot/web/SpringBootFirstWebApplication.java
468 |
469 | ```java
470 | package com.in28minutes.springboot.web;
471 |
472 | import org.springframework.boot.SpringApplication;
473 | import org.springframework.boot.autoconfigure.SpringBootApplication;
474 | import org.springframework.context.annotation.ComponentScan;
475 |
476 | @SpringBootApplication
477 | @ComponentScan("com.in28minutes.springboot.web")
478 | public class SpringBootFirstWebApplication {
479 |
480 | public static void main(String[] args) {
481 | SpringApplication.run(SpringBootFirstWebApplication.class, args);
482 | }
483 | }
484 | ```
485 | ---
486 | ### src/main/resources/application.properties
487 |
488 | ```
489 | spring.mvc.view.prefix=/WEB-INF/jsp/
490 | spring.mvc.view.suffix=.jsp
491 | logging.level.org.springframework.web=INFO
492 | ```
493 | ---
494 | ### src/main/webapp/WEB-INF/jsp/list-todos.jsp
495 |
496 | ```
497 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
498 | <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
499 |
500 |
501 |
502 |
503 | Todo's for ${name}
504 |
506 |
507 |
508 |
509 |
510 |
511 | Your todos are
512 |
513 |
514 | Description |
515 | Target Date |
516 | Is it Done? |
517 | |
518 | |
519 |
520 |
521 |
522 |
523 |
524 | ${todo.desc} |
525 | |
526 | ${todo.done} |
527 | Update |
529 | Delete |
531 |
532 |
533 |
534 |
535 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 | ```
547 | ---
548 | ### src/main/webapp/WEB-INF/jsp/login.jsp
549 |
550 | ```
551 |
552 |
553 |
554 | First Web Application
555 |
556 |
557 |
558 | ${errorMessage}
559 |
564 |
565 |
566 |
567 | ```
568 | ---
569 | ### src/main/webapp/WEB-INF/jsp/todo.jsp
570 |
571 | ```
572 | <%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
573 |
574 |
575 |
576 | First Web Application
577 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
594 |
595 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
610 |
615 |
616 |
617 |
618 | ```
619 | ---
620 | ### src/main/webapp/WEB-INF/jsp/welcome.jsp
621 |
622 | ```
623 |
624 |
625 |
626 | First Web Application
627 |
628 |
629 |
630 | Welcome ${name}!! Click here to manage your todo's.
631 |
632 |
633 |
634 | ```
635 | ---
636 | ### src/test/java/com/in28minutes/springboot/web/SpringBootFirstWebApplicationTests.java
637 |
638 | ```java
639 | package com.in28minutes.springboot.web;
640 |
641 | import org.junit.Test;
642 | import org.junit.runner.RunWith;
643 | import org.springframework.boot.test.context.SpringBootTest;
644 | import org.springframework.test.context.junit4.SpringRunner;
645 |
646 | @RunWith(SpringRunner.class)
647 | @SpringBootTest
648 | public class SpringBootFirstWebApplicationTests {
649 |
650 | @Test
651 | public void contextLoads() {
652 | }
653 |
654 | }
655 | ```
656 | ---
657 | ### todo.txt
658 |
659 | ```
660 | Implementing Server Side Validation
661 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
662 | Command Bean or Form Backing Bean
663 |
664 | Add Validation
665 | Use Validation on Controller
666 | Display Errors in View
667 |
668 | Command Bean
669 | ~~~~~~~~~~~~
670 | Controller
671 | View - Spring Form Tags
672 |
673 |
674 |
675 | LoginController -> adds name to model
676 | welcome.jsp -> shows ${name}
677 |
678 | TodoController -> redirects to list-todos.jsp
679 | ${name} is empty
680 |
681 |
682 | Component, Service, Repository, Controller
683 | Autowired
684 | ComponentScan
685 |
686 | Field dummyService in com.in28minutes.springboot.web.controller.LoginController
687 | required a bean of type 'com.in28minutes.dummy.DummyService'
688 | that could not be found.
689 |
690 | Spring Boot Starter Parent
691 | Spring Boot Starter Web
692 | @SpringBootApplication
693 | Auto Configuration
694 |
695 | Dispatcher Servlet
696 |
697 | /login => "login"
698 |
699 | "login" => src/main/webapp/WEB-INF/jsp/login.jsp
700 |
701 |
702 | Search for a view named "login"
703 |
704 |
705 |
706 | /login => LoginController
707 | ```
708 | ---
709 |
--------------------------------------------------------------------------------
/Step20.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/in28minutes/SpringBootWebApplicationStepByStep/7611e5a098e49023ee03ce1446e465a4c567da45/Step20.zip
--------------------------------------------------------------------------------
/Step21.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/in28minutes/SpringBootWebApplicationStepByStep/7611e5a098e49023ee03ce1446e465a4c567da45/Step21.zip
--------------------------------------------------------------------------------
/Step22.md:
--------------------------------------------------------------------------------
1 | ## What we will do:
2 | - Prepare for Using Spring Security
3 | - Remove All the Login Related Functionality
4 | - Make Welcome the default page - with some hardcoding to start with.
5 | - Refactor getLoggedInUserName
6 | - Update Home Page Link in navigation
7 |
8 | ## Files List
9 |
10 | ### pom.xml
11 |
12 | ```xml
13 |
14 |
16 | 4.0.0
17 |
18 | com.in28minutes.springboot.web
19 | spring-boot-first-web-application
20 | 0.0.1-SNAPSHOT
21 | jar
22 |
23 | spring-boot-first-web-application
24 | Demo project for Spring Boot
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-starter-parent
29 | 1.4.3.RELEASE
30 |
31 |
32 |
33 |
34 | UTF-8
35 | UTF-8
36 | 1.8
37 |
38 |
39 |
40 |
41 | org.springframework.boot
42 | spring-boot-starter-web
43 |
44 |
45 |
46 | javax.servlet
47 | jstl
48 |
49 |
50 |
51 | org.webjars
52 | bootstrap
53 | 3.3.6
54 |
55 |
56 |
57 | org.webjars
58 | bootstrap-datepicker
59 | 1.0.1
60 |
61 |
62 |
63 | org.webjars
64 | jquery
65 | 1.9.1
66 |
67 |
68 |
69 | org.apache.tomcat.embed
70 | tomcat-embed-jasper
71 | provided
72 |
73 |
74 |
75 | org.springframework.boot
76 | spring-boot-devtools
77 | runtime
78 |
79 |
80 |
81 | org.springframework.boot
82 | spring-boot-starter-test
83 | test
84 |
85 |
86 |
87 |
88 |
89 |
90 | org.springframework.boot
91 | spring-boot-maven-plugin
92 |
93 |
94 |
95 |
96 |
97 | ```
98 | ---
99 | ### src/main/java/com/in28minutes/springboot/web/controller/LoginController.java
100 |
101 | ```java
102 | package com.in28minutes.springboot.web.controller;
103 |
104 | import org.springframework.beans.factory.annotation.Autowired;
105 | import org.springframework.stereotype.Controller;
106 | import org.springframework.ui.ModelMap;
107 | import org.springframework.web.bind.annotation.RequestMapping;
108 | import org.springframework.web.bind.annotation.RequestMethod;
109 | import org.springframework.web.bind.annotation.SessionAttributes;
110 |
111 | import com.in28minutes.springboot.web.service.LoginService;
112 |
113 | @Controller
114 | @SessionAttributes("name")
115 | public class LoginController {
116 |
117 | @Autowired
118 | LoginService service;
119 |
120 | @RequestMapping(value = "/", method = RequestMethod.GET)
121 | public String showLoginPage(ModelMap model) {
122 | model.put("name", "in28Minutes");
123 | return "welcome";
124 | }
125 |
126 | }
127 | ```
128 | ---
129 | ### src/main/java/com/in28minutes/springboot/web/controller/TodoController.java
130 |
131 | ```java
132 | package com.in28minutes.springboot.web.controller;
133 |
134 | import java.text.SimpleDateFormat;
135 | import java.util.Date;
136 |
137 | import javax.validation.Valid;
138 |
139 | import org.springframework.beans.factory.annotation.Autowired;
140 | import org.springframework.beans.propertyeditors.CustomDateEditor;
141 | import org.springframework.stereotype.Controller;
142 | import org.springframework.ui.ModelMap;
143 | import org.springframework.validation.BindingResult;
144 | import org.springframework.web.bind.WebDataBinder;
145 | import org.springframework.web.bind.annotation.InitBinder;
146 | import org.springframework.web.bind.annotation.RequestMapping;
147 | import org.springframework.web.bind.annotation.RequestMethod;
148 | import org.springframework.web.bind.annotation.RequestParam;
149 | import org.springframework.web.bind.annotation.SessionAttributes;
150 |
151 | import com.in28minutes.springboot.web.model.Todo;
152 | import com.in28minutes.springboot.web.service.LoginService;
153 | import com.in28minutes.springboot.web.service.TodoService;
154 |
155 | @Controller
156 | @SessionAttributes("name")
157 | public class TodoController {
158 |
159 | @Autowired
160 | TodoService service;
161 |
162 | @InitBinder
163 | public void initBinder(WebDataBinder binder) {
164 | // Date - dd/MM/yyyy
165 | SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
166 | binder.registerCustomEditor(Date.class, new CustomDateEditor(
167 | dateFormat, false));
168 | }
169 |
170 | @RequestMapping(value = "/list-todos", method = RequestMethod.GET)
171 | public String showTodos(ModelMap model) {
172 | String name = getLoggedInUserName(model);
173 | model.put("todos", service.retrieveTodos(name));
174 | return "list-todos";
175 | }
176 |
177 | private String getLoggedInUserName(ModelMap model) {
178 | return (String) model.get("name");
179 | }
180 |
181 | @RequestMapping(value = "/add-todo", method = RequestMethod.GET)
182 | public String showAddTodoPage(ModelMap model) {
183 | model.addAttribute("todo", new Todo(0, getLoggedInUserName(model),
184 | "Default Desc", new Date(), false));
185 | return "todo";
186 | }
187 |
188 | @RequestMapping(value = "/delete-todo", method = RequestMethod.GET)
189 | public String deleteTodo(@RequestParam int id) {
190 | service.deleteTodo(id);
191 | return "redirect:/list-todos";
192 | }
193 |
194 | @RequestMapping(value = "/update-todo", method = RequestMethod.GET)
195 | public String showUpdateTodoPage(@RequestParam int id, ModelMap model) {
196 | Todo todo = service.retrieveTodo(id);
197 | model.put("todo", todo);
198 | return "todo";
199 | }
200 |
201 | @RequestMapping(value = "/update-todo", method = RequestMethod.POST)
202 | public String updateTodo(ModelMap model, @Valid Todo todo,
203 | BindingResult result) {
204 |
205 | if (result.hasErrors()) {
206 | return "todo";
207 | }
208 |
209 | todo.setUser(getLoggedInUserName(model));
210 |
211 | service.updateTodo(todo);
212 |
213 | return "redirect:/list-todos";
214 | }
215 |
216 | @RequestMapping(value = "/add-todo", method = RequestMethod.POST)
217 | public String addTodo(ModelMap model, @Valid Todo todo, BindingResult result) {
218 |
219 | if (result.hasErrors()) {
220 | return "todo";
221 | }
222 |
223 | service.addTodo(getLoggedInUserName(model), todo.getDesc(), todo.getTargetDate(),
224 | false);
225 | return "redirect:/list-todos";
226 | }
227 | }
228 | ```
229 | ---
230 | ### src/main/java/com/in28minutes/springboot/web/model/Todo.java
231 |
232 | ```java
233 | package com.in28minutes.springboot.web.model;
234 |
235 | import java.util.Date;
236 |
237 | import javax.validation.constraints.Size;
238 |
239 | public class Todo {
240 | private int id;
241 | private String user;
242 |
243 | @Size(min=10, message="Enter at least 10 Characters...")
244 | private String desc;
245 |
246 | private Date targetDate;
247 | private boolean isDone;
248 |
249 | public Todo() {
250 | super();
251 | }
252 |
253 | public Todo(int id, String user, String desc, Date targetDate,
254 | boolean isDone) {
255 | super();
256 | this.id = id;
257 | this.user = user;
258 | this.desc = desc;
259 | this.targetDate = targetDate;
260 | this.isDone = isDone;
261 | }
262 |
263 | public int getId() {
264 | return id;
265 | }
266 |
267 | public void setId(int id) {
268 | this.id = id;
269 | }
270 |
271 | public String getUser() {
272 | return user;
273 | }
274 |
275 | public void setUser(String user) {
276 | this.user = user;
277 | }
278 |
279 | public String getDesc() {
280 | return desc;
281 | }
282 |
283 | public void setDesc(String desc) {
284 | this.desc = desc;
285 | }
286 |
287 | public Date getTargetDate() {
288 | return targetDate;
289 | }
290 |
291 | public void setTargetDate(Date targetDate) {
292 | this.targetDate = targetDate;
293 | }
294 |
295 | public boolean isDone() {
296 | return isDone;
297 | }
298 |
299 | public void setDone(boolean isDone) {
300 | this.isDone = isDone;
301 | }
302 |
303 | @Override
304 | public int hashCode() {
305 | final int prime = 31;
306 | int result = 1;
307 | result = prime * result + id;
308 | return result;
309 | }
310 |
311 | @Override
312 | public boolean equals(Object obj) {
313 | if (this == obj) {
314 | return true;
315 | }
316 | if (obj == null) {
317 | return false;
318 | }
319 | if (getClass() != obj.getClass()) {
320 | return false;
321 | }
322 | Todo other = (Todo) obj;
323 | if (id != other.id) {
324 | return false;
325 | }
326 | return true;
327 | }
328 |
329 | @Override
330 | public String toString() {
331 | return String.format(
332 | "Todo [id=%s, user=%s, desc=%s, targetDate=%s, isDone=%s]", id,
333 | user, desc, targetDate, isDone);
334 | }
335 |
336 | }
337 | ```
338 | ---
339 | ### src/main/java/com/in28minutes/springboot/web/service/LoginService.java
340 |
341 | ```java
342 | package com.in28minutes.springboot.web.service;
343 |
344 | import org.springframework.stereotype.Component;
345 | import org.springframework.stereotype.Service;
346 |
347 | @Service
348 | public class LoginService {
349 |
350 | public boolean validateUser(String userid, String password) {
351 | // in28minutes, dummy
352 | return userid.equalsIgnoreCase("in28minutes")
353 | && password.equalsIgnoreCase("dummy");
354 | }
355 |
356 | }
357 | ```
358 | ---
359 | ### src/main/java/com/in28minutes/springboot/web/service/TodoService.java
360 |
361 | ```java
362 | package com.in28minutes.springboot.web.service;
363 |
364 | import java.util.ArrayList;
365 | import java.util.Date;
366 | import java.util.Iterator;
367 | import java.util.List;
368 |
369 | import org.springframework.stereotype.Service;
370 |
371 | import com.in28minutes.springboot.web.model.Todo;
372 |
373 | @Service
374 | public class TodoService {
375 | private static List todos = new ArrayList();
376 | private static int todoCount = 3;
377 |
378 | static {
379 | todos.add(new Todo(1, "in28Minutes", "Learn Spring MVC", new Date(),
380 | false));
381 | todos.add(new Todo(2, "in28Minutes", "Learn Struts", new Date(), false));
382 | todos.add(new Todo(3, "in28Minutes", "Learn Hibernate", new Date(),
383 | false));
384 | }
385 |
386 | public List retrieveTodos(String user) {
387 | List filteredTodos = new ArrayList();
388 | for (Todo todo : todos) {
389 | if (todo.getUser().equalsIgnoreCase(user)) {
390 | filteredTodos.add(todo);
391 | }
392 | }
393 | return filteredTodos;
394 | }
395 |
396 | public Todo retrieveTodo(int id) {
397 | for (Todo todo : todos) {
398 | if (todo.getId()==id) {
399 | return todo;
400 | }
401 | }
402 | return null;
403 | }
404 |
405 | public void updateTodo(Todo todo){
406 | todos.remove(todo);
407 | todos.add(todo);
408 | }
409 |
410 | public void addTodo(String name, String desc, Date targetDate,
411 | boolean isDone) {
412 | todos.add(new Todo(++todoCount, name, desc, targetDate, isDone));
413 | }
414 |
415 | public void deleteTodo(int id) {
416 | Iterator iterator = todos.iterator();
417 | while (iterator.hasNext()) {
418 | Todo todo = iterator.next();
419 | if (todo.getId() == id) {
420 | iterator.remove();
421 | }
422 | }
423 | }
424 | }
425 | ```
426 | ---
427 | ### src/main/java/com/in28minutes/springboot/web/SpringBootFirstWebApplication.java
428 |
429 | ```java
430 | package com.in28minutes.springboot.web;
431 |
432 | import org.springframework.boot.SpringApplication;
433 | import org.springframework.boot.autoconfigure.SpringBootApplication;
434 | import org.springframework.context.annotation.ComponentScan;
435 |
436 | @SpringBootApplication
437 | @ComponentScan("com.in28minutes.springboot.web")
438 | public class SpringBootFirstWebApplication {
439 |
440 | public static void main(String[] args) {
441 | SpringApplication.run(SpringBootFirstWebApplication.class, args);
442 | }
443 | }
444 | ```
445 | ---
446 | ### src/main/resources/application.properties
447 |
448 | ```
449 | spring.mvc.view.prefix=/WEB-INF/jsp/
450 | spring.mvc.view.suffix=.jsp
451 | logging.level.org.springframework.web=INFO
452 | ```
453 | ---
454 | ### src/main/webapp/WEB-INF/jsp/common/footer.jspf
455 |
456 | ```
457 |
458 |
459 |
461 |
466 |
467 |