<?xml version =" 1.0" encoding =" UTF-8" ?>
<project xmlns =" http://maven.apache.org/POM/4.0.0" xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=" http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" >
<modelVersion >4.0.0</modelVersion >
<groupId >com.in28minutes.springboot.web</groupId >
<artifactId >spring-boot-first-web-application-git</artifactId >
<version >0.0.1-SNAPSHOT</version >
<packaging >jar</packaging >
<name >spring-boot-first-web-application</name >
<description >Demo project for Spring Boot</description >
<parent >
<groupId >org.springframework.boot</groupId >
<artifactId >spring-boot-starter-parent</artifactId >
<version >2.3.1.RELEASE</version > <!-- Step 33 -->
<relativePath /> <!-- lookup parent from repository -->
</parent >
<properties >
<project .build.sourceEncoding>UTF-8</project .build.sourceEncoding>
<project .reporting.outputEncoding>UTF-8</project .reporting.outputEncoding>
<java .version>1.8</java .version>
<maven-jar-plugin .version>3.1.1</maven-jar-plugin .version>
</properties >
<dependencies >
<dependency >
<groupId >org.springframework.boot</groupId >
<artifactId >spring-boot-starter-web</artifactId >
</dependency >
<!-- START AND STOP THE APPLICATION AFTER MAKING THE CHANGE! -->
<dependency >
<groupId >org.springframework.boot</groupId >
<artifactId >spring-boot-starter-validation</artifactId >
</dependency >
<dependency >
<groupId >org.springframework.boot</groupId >
<artifactId >spring-boot-starter-data-jpa</artifactId >
</dependency >
<dependency >
<groupId >com.h2database</groupId >
<artifactId >h2</artifactId >
<scope >runtime</scope >
</dependency >
<dependency >
<groupId >org.springframework.boot</groupId >
<artifactId >spring-boot-starter-security</artifactId >
</dependency >
<dependency >
<groupId >javax.servlet</groupId >
<artifactId >jstl</artifactId >
</dependency >
<dependency >
<groupId >org.webjars</groupId >
<artifactId >bootstrap</artifactId >
<version >3.3.6</version >
</dependency >
<dependency >
<groupId >org.webjars</groupId >
<artifactId >bootstrap-datepicker</artifactId >
<version >1.0.1</version >
</dependency >
<dependency >
<groupId >org.webjars</groupId >
<artifactId >jquery</artifactId >
<version >1.9.1</version >
</dependency >
<dependency >
<groupId >org.apache.tomcat.embed</groupId >
<artifactId >tomcat-embed-jasper</artifactId >
<scope >provided</scope >
</dependency >
<dependency >
<groupId >org.springframework.boot</groupId >
<artifactId >spring-boot-devtools</artifactId >
<scope >runtime</scope >
</dependency >
<dependency >
<groupId >org.springframework.boot</groupId >
<artifactId >spring-boot-starter-test</artifactId >
<scope >test</scope >
</dependency >
</dependencies >
<build >
<plugins >
<plugin >
<groupId >org.springframework.boot</groupId >
<artifactId >spring-boot-maven-plugin</artifactId >
</plugin >
</plugins >
</build >
<repositories >
<repository >
<id >spring-milestones</id >
<name >Spring Milestones</name >
<url >https://repo.spring.io/milestones</url >
</repository >
</repositories >
<pluginRepositories >
<pluginRepository >
<id >spring-milestones</id >
<name >Spring Milestones</name >
<url >https://repo.spring.io/milestones</url >
</pluginRepository >
</pluginRepositories >
</project >
/src/main/java/com/in28minutes/springboot/web/SpringBootFirstWebApplication.java
package com .in28minutes .springboot .web ;
import org .springframework .boot .SpringApplication ;
import org .springframework .boot .autoconfigure .SpringBootApplication ;
import org .springframework .context .annotation .ComponentScan ;
@ SpringBootApplication
@ ComponentScan ("com.in28minutes.springboot.web" )
public class SpringBootFirstWebApplication {
public static void main (String [] args ) {
SpringApplication .run (SpringBootFirstWebApplication .class , args );
}
}
/src/main/java/com/in28minutes/springboot/web/controller/ErrorController.java
package com .in28minutes .springboot .web .controller ;
import javax .servlet .http .HttpServletRequest ;
import javax .servlet .http .HttpServletResponse ;
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 ;
}
}
/src/main/java/com/in28minutes/springboot/web/controller/LogoutController.java
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 .core .userdetails .UserDetails ;
import org .springframework .security .web .authentication .logout .LogoutHandler ;
import org .springframework .security .web .authentication .logout .SecurityContextLogoutHandler ;
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 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:/" ;
}
}
/src/main/java/com/in28minutes/springboot/web/controller/TodoController.java
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" ;
}
}
/src/main/java/com/in28minutes/springboot/web/controller/WelcomeController.java
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 ();
}
}
/src/main/java/com/in28minutes/springboot/web/model/Todo.java
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 );
}
}
/src/main/java/com/in28minutes/springboot/web/security/SecurityConfiguration.java
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 ;
import org .springframework .security .crypto .password .NoOpPasswordEncoder ;
@ Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
//Create User - in28Minutes/dummy
@ Autowired
public void configureGlobalSecurity (AuthenticationManagerBuilder auth )
throws Exception {
auth .inMemoryAuthentication ()
.passwordEncoder (NoOpPasswordEncoder .getInstance ())
.withUser ("in28Minutes" ).password ("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 ();
}
}
/src/main/java/com/in28minutes/springboot/web/service/TodoRepository.java
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 <Todo , Integer >{
List <Todo > findByUser (String user );
//service.retrieveTodos(name)
//service.deleteTodo(id);
//service.retrieveTodo(id)
//service.updateTodo(todo)
//service.addTodo(getLoggedInUserName(model), todo.getDesc(), todo.getTargetDate(),false);
}
/src/main/java/com/in28minutes/springboot/web/service/TodoService.java
package com .in28minutes .springboot .web .service ;
import java .util .ArrayList ;
import java .util .Date ;
import java .util .Iterator ;
import java .util .List ;
import org .springframework .stereotype .Service ;
import com .in28minutes .springboot .web .model .Todo ;
@ Service
public class TodoService {
private static List <Todo > todos = new ArrayList <Todo >();
private static int todoCount = 3 ;
static {
todos .add (new Todo (1 , "in28Minutes" , "Learn Spring MVC" , new Date (),
false ));
todos .add (new Todo (2 , "in28Minutes" , "Learn Struts" , new Date (), false ));
todos .add (new Todo (3 , "in28Minutes" , "Learn Hibernate" , new Date (),
false ));
}
public List <Todo > retrieveTodos (String user ) {
List <Todo > filteredTodos = new ArrayList <Todo >();
for (Todo todo : todos ) {
if (todo .getUser ().equalsIgnoreCase (user )) {
filteredTodos .add (todo );
}
}
return filteredTodos ;
}
public Todo retrieveTodo (int id ) {
for (Todo todo : todos ) {
if (todo .getId ()==id ) {
return todo ;
}
}
return null ;
}
public void updateTodo (Todo todo ){
todos .remove (todo );
todos .add (todo );
}
public void addTodo (String name , String desc , Date targetDate ,
boolean isDone ) {
todos .add (new Todo (++todoCount , name , desc , targetDate , isDone ));
}
public void deleteTodo (int id ) {
Iterator <Todo > iterator = todos .iterator ();
while (iterator .hasNext ()) {
Todo todo = iterator .next ();
if (todo .getId () == id ) {
iterator .remove ();
}
}
}
}
/src/main/resources/application.properties
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
/src/main/resources/data.sql
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');
/src/main/webapp/WEB-INF/jsp/common/footer.jspf
<script src="webjars/jquery/1.9.1/jquery.min.js"></script>
<script src="webjars/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script
src="webjars/bootstrap-datepicker/1.0.1/js/bootstrap-datepicker.js"></script>
<script>
$('#targetDate').datepicker({
format : 'dd/mm/yyyy'
});
</script>
</body>
</html>
/src/main/webapp/WEB-INF/jsp/common/header.jspf
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
<head>
<title>Spring Boot Normal Web Application</title>
<link href="webjars/bootstrap/3.3.6/css/bootstrap.min.css"
rel="stylesheet">
</head>
<body>
/src/main/webapp/WEB-INF/jsp/common/navigation.jspf
<nav role="navigation" class="navbar navbar-default">
<div class="">
<a href="http://www.in28minutes.com" class="navbar-brand">in28Minutes</a>
</div>
<div class="navbar-collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="/">Home</a></li>
<li><a href="/list-todos">Todos</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="/logout">Logout</a></li>
</ul>
</div>
</nav>
/src/main/webapp/WEB-INF/jsp/error.jsp
<%@ include file="common/header.jspf"%>
<%@ include file="common/navigation.jspf"%>
<div class="container">
An exception occurred! Please contact Support!
</div>
<%@ include file="common/footer.jspf"%>
/src/main/webapp/WEB-INF/jsp/list-todos.jsp
<%@ include file="common/header.jspf" %>
<%@ include file="common/navigation.jspf" %>
<div class="container">
<table class="table table-striped">
<caption>Your todos are</caption>
<thead>
<tr>
<th>Description</th>
<th>Target Date</th>
<th>Is it Done?</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<c:forEach items="${todos}" var="todo">
<tr>
<td>${todo.desc}</td>
<td><fmt:formatDate value="${todo.targetDate}" pattern="dd/MM/yyyy"/></td>
<td>${todo.done}</td>
<td><a type="button" class="btn btn-success"
href="/update-todo?id=${todo.id}">Update</a></td>
<td><a type="button" class="btn btn-warning"
href="/delete-todo?id=${todo.id}">Delete</a></td>
</tr>
</c:forEach>
</tbody>
</table>
<div>
<a class="button" href="/add-todo">Add a Todo</a>
</div>
</div>
<%@ include file="common/footer.jspf" %>
/src/main/webapp/WEB-INF/jsp/todo.jsp
<%@ include file="common/header.jspf" %>
<%@ include file="common/navigation.jspf" %>
<div class="container">
<form:form method="post" modelAttribute="todo">
<form:hidden path="id" />
<fieldset class="form-group">
<form:label path="desc">Description</form:label>
<form:input path="desc" type="text" class="form-control"
required="required" />
<form:errors path="desc" cssClass="text-warning" />
</fieldset>
<fieldset class="form-group">
<form:label path="targetDate">Target Date</form:label>
<form:input path="targetDate" type="text" class="form-control"
required="required" />
<form:errors path="targetDate" cssClass="text-warning" />
</fieldset>
<button type="submit" class="btn btn-success">Add</button>
</form:form>
</div>
<%@ include file="common/footer.jspf" %>
/src/main/webapp/WEB-INF/jsp/welcome.jsp
<%@ include file="common/header.jspf"%>
<%@ include file="common/navigation.jspf"%>
<div class="container">
Welcome ${name}!! <a href="/list-todos">Click here</a> to manage your
todo's.
</div>
<%@ include file="common/footer.jspf"%>
/src/test/java/com/in28minutes/springboot/web/SpringBootFirstWebApplicationTests.java
package com .in28minutes .springboot .web ;
import org .junit .Test ;
import org .junit .runner .RunWith ;
import org .springframework .boot .test .context .SpringBootTest ;
import org .springframework .test .context .junit4 .SpringRunner ;
@ RunWith (SpringRunner .class )
@ SpringBootTest
public class SpringBootFirstWebApplicationTests {
@ Test
public void contextLoads () {
}
}