diff --git a/.idea/dataSources.local.xml b/.idea/dataSources.local.xml
new file mode 100644
index 0000000..d80b8c7
--- /dev/null
+++ b/.idea/dataSources.local.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+ master_key
+ postgres
+
+
+
+
\ No newline at end of file
diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
new file mode 100644
index 0000000..2857aeb
--- /dev/null
+++ b/.idea/dataSources.xml
@@ -0,0 +1,12 @@
+
+
+
+
+ postgresql
+ true
+ org.postgresql.Driver
+ jdbc:postgresql://localhost:5432/db_invoice
+ $ProjectFileDir$
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..639900d
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..b139bdc
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/training_microservices.iml b/.idea/training_microservices.iml
new file mode 100644
index 0000000..d6ebd48
--- /dev/null
+++ b/.idea/training_microservices.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..02f665e
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1707353540000
+
+
+ 1707353540000
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/02-todo-web-application-h2/Dockerfile b/02-todo-web-application-h2/Dockerfile
new file mode 100644
index 0000000..f0deecb
--- /dev/null
+++ b/02-todo-web-application-h2/Dockerfile
@@ -0,0 +1,5 @@
+FROM tomcat:8.0.51-jre8-alpine
+EXPOSE 8080
+RUN rm -rf /usr/local/tomcat/webapps/*
+COPY target/*.war /usr/local/tomcat/webapps/ROOT.war
+CMD ["catalina.sh","run"]
\ No newline at end of file
diff --git a/02-todo-web-application-h2/backup/deployment.yaml b/02-todo-web-application-h2/backup/deployment.yaml
new file mode 100644
index 0000000..2c11e40
--- /dev/null
+++ b/02-todo-web-application-h2/backup/deployment.yaml
@@ -0,0 +1,47 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ labels:
+ app: todo-web-application-h2
+ name: todo-web-application-h2
+ namespace: default
+spec:
+ replicas: 2
+ minReadySeconds: 45
+ selector:
+ matchLabels:
+ app: todo-web-application-h2
+ strategy:
+ rollingUpdate:
+ maxSurge: 25%
+ maxUnavailable: 25%
+ type: RollingUpdate
+ template:
+ metadata:
+ labels:
+ app: todo-web-application-h2
+ spec:
+ containers:
+ - image: in28min/todo-web-application-h2:0.0.1-SNAPSHOT
+ imagePullPolicy: IfNotPresent
+ name: todo-web-application-h2
+ restartPolicy: Always
+ terminationGracePeriodSeconds: 30
+---
+apiVersion: v1
+kind: Service
+metadata:
+ labels: #PODS
+ app: todo-web-application-h2
+ name: todo-web-application-h2
+ namespace: default
+spec:
+ ports:
+ - nodePort: 30702
+ port: 8080
+ protocol: TCP
+ targetPort: 8080
+ selector:
+ app: todo-web-application-h2
+ sessionAffinity: ClientIP
+ type: LoadBalancer
\ No newline at end of file
diff --git a/02-todo-web-application-h2/pom.xml b/02-todo-web-application-h2/pom.xml
new file mode 100644
index 0000000..bbfa3d7
--- /dev/null
+++ b/02-todo-web-application-h2/pom.xml
@@ -0,0 +1,143 @@
+
+
+ 4.0.0
+
+ com.in28minutes.springboot.web
+ 02-todo-web-application-h2
+ 0.0.1-SNAPSHOT
+ war
+ todo-web-application-h2
+
+ Demo project for Spring Boot
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.1.7.RELEASE
+
+
+
+
+ UTF-8
+ UTF-8
+ 1.8
+ 3.1.1
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+
+ com.h2database
+ h2
+ runtime
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+ javax.servlet
+ jstl
+
+
+
+ org.webjars
+ bootstrap
+ 3.3.6
+
+
+
+ org.webjars
+ bootstrap-datepicker
+ 1.0.1
+
+
+
+ org.webjars
+ jquery
+ 1.9.1
+
+
+
+ org.apache.tomcat.embed
+ tomcat-embed-jasper
+ provided
+
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+ provided
+
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ runtime
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+ todo-web-application-h2
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ com.spotify
+ dockerfile-maven-plugin
+ 1.4.6
+
+
+ default
+
+ build
+
+
+
+
+ in28min/${project.name}
+ ${project.version}
+ true
+
+
+
+
+
+
+
+ spring-milestones
+ Spring Milestones
+ https://repo.spring.io/milestones
+
+
+
+
+
+ spring-milestones
+ Spring Milestones
+ https://repo.spring.io/milestones
+
+
+
+
\ No newline at end of file
diff --git a/02-todo-web-application-h2/readme.md b/02-todo-web-application-h2/readme.md
new file mode 100644
index 0000000..ce6adef
--- /dev/null
+++ b/02-todo-web-application-h2/readme.md
@@ -0,0 +1,81 @@
+# Todo Web Application using Spring Boot and H2 In memory database
+
+Run com.in28minutes.springboot.web.SpringBootFirstWebApplication as a Java Application.
+
+Runs on default port of Spring Boot - 8080
+
+## Can be run as a Jar or a WAR
+
+`mvn clean install` generate a war which can deployed to your favorite web server.
+
+We will deploy to Docker as a WAR
+
+## Web Application
+
+- http://localhost:8080/login with in28minutes/dummy as credentials
+- You can add, delete and update your todos
+- Spring Security is used to secure the application
+- `com.in28minutes.springboot.web.security.SecurityConfiguration` contains the in memory security credential configuration.
+
+## H2 Console
+
+- http://localhost:8080/h2-console
+- Use `jdbc:h2:mem:testdb` as JDBC URL
+
+
+## Plugins
+
+### Dockerfile Maven
+
+- https://github.com/spotify/dockerfile-maven
+
+```
+
+ com.spotify
+ dockerfile-maven-plugin
+ 1.4.6
+
+
+ default
+
+ build
+
+
+
+
+ in28min/${project.name}
+ ${project.version}
+ true
+
+
+```
+### JIB
+
+- https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin#quickstart
+- https://github.com/GoogleContainerTools/jib/blob/master/docs/faq.md
+- `true` - https://github.com/GoogleContainerTools/jib/issues/413
+
+```
+
+ com.google.cloud.tools
+ jib-maven-plugin
+ 1.6.1
+
+
+ tomcat:8.5-jre8-alpine
+
+
+ /usr/local/tomcat/webapps/my-webapp
+ USE_CURRENT_TIMESTAMP
+
+
+
+
+ package
+
+ dockerBuild
+
+
+
+
+```
\ No newline at end of file
diff --git a/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/EnvironmentConfigurationLogger.java b/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/EnvironmentConfigurationLogger.java
new file mode 100644
index 0000000..027dcb7
--- /dev/null
+++ b/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/EnvironmentConfigurationLogger.java
@@ -0,0 +1,41 @@
+package com.in28minutes.springboot.web;
+
+import java.util.Arrays;
+import java.util.stream.StreamSupport;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.event.ContextRefreshedEvent;
+import org.springframework.context.event.EventListener;
+import org.springframework.core.env.AbstractEnvironment;
+import org.springframework.core.env.EnumerablePropertySource;
+import org.springframework.core.env.Environment;
+import org.springframework.core.env.MutablePropertySources;
+import org.springframework.stereotype.Component;
+
+@Component
+public class EnvironmentConfigurationLogger {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(EnvironmentConfigurationLogger.class);
+
+ @SuppressWarnings("rawtypes")
+ @EventListener
+ public void handleContextRefresh(ContextRefreshedEvent event) {
+ final Environment environment = event.getApplicationContext().getEnvironment();
+ LOGGER.info("====== Environment and configuration ======");
+ LOGGER.info("Active profiles: {}", Arrays.toString(environment.getActiveProfiles()));
+ final MutablePropertySources sources = ((AbstractEnvironment) environment).getPropertySources();
+ StreamSupport.stream(sources.spliterator(), false).filter(ps -> ps instanceof EnumerablePropertySource)
+ .map(ps -> ((EnumerablePropertySource) ps).getPropertyNames()).flatMap(Arrays::stream).distinct()
+ .forEach(prop -> {
+ Object resolved = environment.getProperty(prop, Object.class);
+ if (resolved instanceof String) {
+ LOGGER.info("{} - {}", prop, environment.getProperty(prop));
+ } else {
+ LOGGER.info("{} - {}", prop, "NON-STRING-VALUE");
+ }
+
+ });
+ LOGGER.debug("===========================================");
+ }
+}
diff --git a/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/SpringBootFirstWebApplication.java b/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/SpringBootFirstWebApplication.java
new file mode 100644
index 0000000..4fe5897
--- /dev/null
+++ b/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/SpringBootFirstWebApplication.java
@@ -0,0 +1,22 @@
+package com.in28minutes.springboot.web;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+import org.springframework.context.annotation.ComponentScan;
+
+@SpringBootApplication
+@ComponentScan("com.in28minutes.springboot.web")
+public class SpringBootFirstWebApplication extends SpringBootServletInitializer {
+
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+ return application.sources(SpringBootFirstWebApplication.class);
+ }
+
+ public static void main(String[] args) {
+ SpringApplication.run(SpringBootFirstWebApplication.class, args);
+ }
+
+}
\ No newline at end of file
diff --git a/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/controller/ErrorController.java b/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/controller/ErrorController.java
new file mode 100644
index 0000000..79e0956
--- /dev/null
+++ b/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/controller/ErrorController.java
@@ -0,0 +1,24 @@
+package com.in28minutes.springboot.web.controller;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.servlet.ModelAndView;
+
+@Controller("error")
+public class ErrorController {
+
+ @ExceptionHandler(Exception.class)
+ public ModelAndView handleException
+ (HttpServletRequest request, Exception ex){
+ ModelAndView mv = new ModelAndView();
+
+ mv.addObject("exception", ex.getLocalizedMessage());
+ mv.addObject("url", request.getRequestURL());
+
+ mv.setViewName("error");
+ return mv;
+ }
+
+}
diff --git a/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/controller/LogoutController.java b/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/controller/LogoutController.java
new file mode 100644
index 0000000..5f426a6
--- /dev/null
+++ b/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/controller/LogoutController.java
@@ -0,0 +1,30 @@
+package com.in28minutes.springboot.web.controller;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+@Controller
+public class LogoutController {
+
+ @RequestMapping(value = "/logout", method = RequestMethod.GET)
+ public String logout(HttpServletRequest request,
+ HttpServletResponse response) {
+
+ Authentication authentication = SecurityContextHolder.getContext()
+ .getAuthentication();
+
+ if (authentication != null) {
+ new SecurityContextLogoutHandler().logout(request, response,
+ authentication);
+ }
+
+ return "redirect:/";
+ }
+}
diff --git a/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/controller/TodoController.java b/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/controller/TodoController.java
new file mode 100644
index 0000000..75489e0
--- /dev/null
+++ b/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/controller/TodoController.java
@@ -0,0 +1,111 @@
+package com.in28minutes.springboot.web.controller;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import javax.validation.Valid;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.propertyeditors.CustomDateEditor;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.WebDataBinder;
+import org.springframework.web.bind.annotation.InitBinder;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import com.in28minutes.springboot.web.model.Todo;
+import com.in28minutes.springboot.web.service.TodoRepository;
+
+@Controller
+public class TodoController {
+
+ @Autowired
+ TodoRepository repository;
+
+ @InitBinder
+ public void initBinder(WebDataBinder binder) {
+ // Date - dd/MM/yyyy
+ SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
+ binder.registerCustomEditor(Date.class, new CustomDateEditor(
+ dateFormat, false));
+ }
+
+ @RequestMapping(value = "/list-todos", method = RequestMethod.GET)
+ public String showTodos(ModelMap model) {
+ String name = getLoggedInUserName(model);
+ model.put("todos", repository.findByUser(name));
+ //model.put("todos", service.retrieveTodos(name));
+ return "list-todos";
+ }
+
+ private String getLoggedInUserName(ModelMap model) {
+ Object principal = SecurityContextHolder.getContext()
+ .getAuthentication().getPrincipal();
+
+ if (principal instanceof UserDetails) {
+ return ((UserDetails) principal).getUsername();
+ }
+
+ return principal.toString();
+ }
+
+ @RequestMapping(value = "/add-todo", method = RequestMethod.GET)
+ public String showAddTodoPage(ModelMap model) {
+ model.addAttribute("todo", new Todo(0, getLoggedInUserName(model),
+ "Default Desc", new Date(), false));
+ return "todo";
+ }
+
+ @RequestMapping(value = "/delete-todo", method = RequestMethod.GET)
+ public String deleteTodo(@RequestParam int id) {
+
+ //if(id==1)
+ //throw new RuntimeException("Something went wrong");
+ repository.deleteById(id);
+ //service.deleteTodo(id);
+ return "redirect:/list-todos";
+ }
+
+ @RequestMapping(value = "/update-todo", method = RequestMethod.GET)
+ public String showUpdateTodoPage(@RequestParam int id, ModelMap model) {
+ Todo todo = repository.findById(id).get();
+ //Todo todo = service.retrieveTodo(id);
+ model.put("todo", todo);
+ return "todo";
+ }
+
+ @RequestMapping(value = "/update-todo", method = RequestMethod.POST)
+ public String updateTodo(ModelMap model, @Valid Todo todo,
+ BindingResult result) {
+
+ if (result.hasErrors()) {
+ return "todo";
+ }
+
+ todo.setUser(getLoggedInUserName(model));
+
+ repository.save(todo);
+ //service.updateTodo(todo);
+
+ return "redirect:/list-todos";
+ }
+
+ @RequestMapping(value = "/add-todo", method = RequestMethod.POST)
+ public String addTodo(ModelMap model, @Valid Todo todo, BindingResult result) {
+
+ if (result.hasErrors()) {
+ return "todo";
+ }
+
+ todo.setUser(getLoggedInUserName(model));
+ repository.save(todo);
+ /*service.addTodo(getLoggedInUserName(model), todo.getDesc(), todo.getTargetDate(),
+ false);*/
+ return "redirect:/list-todos";
+ }
+}
diff --git a/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/controller/WelcomeController.java b/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/controller/WelcomeController.java
new file mode 100644
index 0000000..da5018c
--- /dev/null
+++ b/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/controller/WelcomeController.java
@@ -0,0 +1,30 @@
+package com.in28minutes.springboot.web.controller;
+
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+@Controller
+public class WelcomeController {
+
+ @RequestMapping(value = "/", method = RequestMethod.GET)
+ public String showWelcomePage(ModelMap model) {
+ model.put("name", getLoggedinUserName());
+ return "welcome";
+ }
+
+ private String getLoggedinUserName() {
+ Object principal = SecurityContextHolder.getContext()
+ .getAuthentication().getPrincipal();
+
+ if (principal instanceof UserDetails) {
+ return ((UserDetails) principal).getUsername();
+ }
+
+ return principal.toString();
+ }
+
+}
diff --git a/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/model/Todo.java b/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/model/Todo.java
new file mode 100644
index 0000000..e794ac9
--- /dev/null
+++ b/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/model/Todo.java
@@ -0,0 +1,112 @@
+package com.in28minutes.springboot.web.model;
+
+import java.util.Date;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.validation.constraints.Size;
+
+@Entity
+public class Todo {
+
+ @Id
+ @GeneratedValue
+ private int id;
+
+ private String user;
+
+ @Size(min=10, message="Enter at least 10 Characters...")
+ private String desc;
+
+ private Date targetDate;
+ private boolean isDone;
+
+ public Todo() {
+ super();
+ }
+
+ public Todo(int id, String user, String desc, Date targetDate,
+ boolean isDone) {
+ super();
+ this.id = id;
+ this.user = user;
+ this.desc = desc;
+ this.targetDate = targetDate;
+ this.isDone = isDone;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ public void setUser(String user) {
+ this.user = user;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ public Date getTargetDate() {
+ return targetDate;
+ }
+
+ public void setTargetDate(Date targetDate) {
+ this.targetDate = targetDate;
+ }
+
+ public boolean isDone() {
+ return isDone;
+ }
+
+ public void setDone(boolean isDone) {
+ this.isDone = isDone;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + id;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ Todo other = (Todo) obj;
+ if (id != other.id) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "Todo [id=%s, user=%s, desc=%s, targetDate=%s, isDone=%s]", id,
+ user, desc, targetDate, isDone);
+ }
+
+}
\ No newline at end of file
diff --git a/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/security/SecurityConfiguration.java b/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/security/SecurityConfiguration.java
new file mode 100644
index 0000000..7d92bd8
--- /dev/null
+++ b/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/security/SecurityConfiguration.java
@@ -0,0 +1,28 @@
+package com.in28minutes.springboot.web.security;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+@Configuration
+public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
+ //Create User - in28Minutes/dummy
+ @Autowired
+ public void configureGlobalSecurity(AuthenticationManagerBuilder auth)
+ throws Exception {
+ auth.inMemoryAuthentication().withUser("in28minutes").password("{noop}dummy")
+ .roles("USER", "ADMIN");
+ }
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.authorizeRequests().antMatchers("/login", "/h2-console/**").permitAll()
+ .antMatchers("/", "/*todo*/**").access("hasRole('USER')").and()
+ .formLogin();
+
+ http.csrf().disable();
+ http.headers().frameOptions().disable();
+ }
+}
diff --git a/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/service/TodoRepository.java b/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/service/TodoRepository.java
new file mode 100644
index 0000000..0e7fcea
--- /dev/null
+++ b/02-todo-web-application-h2/src/main/java/com/in28minutes/springboot/web/service/TodoRepository.java
@@ -0,0 +1,11 @@
+package com.in28minutes.springboot.web.service;
+
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import com.in28minutes.springboot.web.model.Todo;
+
+public interface TodoRepository extends JpaRepository {
+ List findByUser(String user);
+}
\ No newline at end of file
diff --git a/02-todo-web-application-h2/src/main/resources/application.properties b/02-todo-web-application-h2/src/main/resources/application.properties
new file mode 100644
index 0000000..bff8631
--- /dev/null
+++ b/02-todo-web-application-h2/src/main/resources/application.properties
@@ -0,0 +1,7 @@
+spring.mvc.view.prefix=/WEB-INF/jsp/
+spring.mvc.view.suffix=.jsp
+logging.level.org.springframework.web=INFO
+
+spring.jpa.show-sql=true
+spring.h2.console.enabled=true
+spring.h2.console.settings.web-allow-others=true
\ No newline at end of file
diff --git a/02-todo-web-application-h2/src/main/resources/data.sql b/02-todo-web-application-h2/src/main/resources/data.sql
new file mode 100644
index 0000000..2f16341
--- /dev/null
+++ b/02-todo-web-application-h2/src/main/resources/data.sql
@@ -0,0 +1,6 @@
+insert into TODO
+values(10001, 'Learn Spring Boot', false, sysdate(), 'in28minutes');
+insert into TODO
+values(10002, 'Learn Angular JS', false, sysdate(), 'in28minutes');
+insert into TODO
+values(10003, 'Learn to Dance', false, sysdate(), 'in28minutes');
diff --git a/02-todo-web-application-h2/src/main/webapp/WEB-INF/jsp/common/footer.jspf b/02-todo-web-application-h2/src/main/webapp/WEB-INF/jsp/common/footer.jspf
new file mode 100644
index 0000000..879b276
--- /dev/null
+++ b/02-todo-web-application-h2/src/main/webapp/WEB-INF/jsp/common/footer.jspf
@@ -0,0 +1,12 @@
+
+
+
+
+
+