Srikanth Technologies

To-dos Application using Spring MVC + Hibernate + Derby

To-dos is a simple web application developed using Spring MVC, Hibernate and Apache Derby database to demonstrate how to integrate Spring MVC, Spring JPA with Hibernate, which uses Apache Derby database.

These are the following tasks to be performed by this web application.

This application uses the following technologies:

How to download and run project

Follow the steps given below to import this project into Eclipse and run it.

Application Components

Here are various components related to this application with relevant required explanation:

pom.xml

This file lists all dependencies in the application. This is used by Maven to download required librariries from Maven repositories.

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.st</groupId>
	<artifactId>todo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>todo</name>
	<packaging>war</packaging>
	<description>To do list </description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.4.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<java.version>13</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>

		<dependency>
			<groupId>org.apache.derby</groupId>
			<artifactId>derby</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</scope>
		</dependency>


		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
		</dependency>

	</dependencies>

	<build>
		<finalName>todos</finalName>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

application.properties

This file contains properties related to JPA, embedded Tomcat and others.

logging.level.root=ERROR

# Derby Database with embedded driver - a directory called database is created when app runs first time
spring.datasource.url=jdbc:derby:database;create=true
spring.datasource.username=todo
spring.datasource.password=todo
spring.datasource.driver-class=org.apache.derby.jdbc.EmbeddedDriver 
 
#Tomcat related 
server.port=8888

# Spring MVC View Related 
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp

# JPA
spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.DerbyTenFiveDialect 

User.java

This class represents a User and is mapped to Users table.

package todo;

import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
 
@Entity
@Table(name = "users", schema = "app")
public class User {
	@Id
	@Column(length=10)
	private String username;
	@Column(length=10)
	private String password;
	@Transient 
	private String confirmPassword; // This is not mapped to table because of @Transient 
	
	@Column(length=50)
	private String email;
	// One user - many Todos 
	@OneToMany(mappedBy = "username")
	private List<Todo> todos = new ArrayList<Todo>();

	public List<Todo> getTodos() {
		return todos;
	}

	public void setTodos(List<Todo> todos) {
		this.todos = todos;
	}

	 
	public String getUsername() {
		return username;
	}

	 
	public String getConfirmPassword() {
		return confirmPassword;
	}

	public void setConfirmPassword(String confirmPassword) {
		this.confirmPassword = confirmPassword;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}
}

Todo.java

This class represents a Todo and is mapped to Todos table.

package todo;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "todos", schema = "app")
public class Todo {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;
	private String text;
	@Column( length = 10)
	private String category;
	@Column( length = 10)
	private String username;

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}

	public String getCategory() {
		return category;
	}

	public void setCategory(String category) {
		this.category = category;
	}
}

UserRepo.java

Interface UserRepo provides methods to perform CRUD operations related to User.

package todo;

import org.springframework.data.repository.CrudRepository;

public interface UserRepo  extends CrudRepository<User,String> {

}

TodoRepo.java

Interface TodoRepo provides methods to perform CRUD operations related to Todos and also some custom query methods.

package todo;

import java.util.List;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;

public interface TodoRepo  extends CrudRepository<Todo,Integer> {
     // Gets all Todos of the given user 
	 @Query("SELECT t FROM Todo t WHERE t.username = ?1")   
	 List<Todo> getTodosByUser(String username);
	 
     // Gets Todos related to given user in the desc order of id so that most recent comes first 
	 @Query("SELECT t FROM Todo t WHERE t.username = ?1 order by id desc")
	 List<Todo> getRecentTodosByUser(String username);

	 // Performs case insensitive search for the given text
	 @Query("SELECT t FROM Todo t WHERE t.username = ?1 and upper(t.text) like ?2 order by id desc")
	 List<Todo> getTodosByText(String username, String text);
}   

UserController.java

UserController provides methods to perform tasks related to User such as login, registration and logout.

package todo;

import java.util.List;
import java.util.Optional;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
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 UserController {
	@Autowired
	private UserRepo userRepo;

	@Autowired
	private TodoRepo todoRepo;

	@RequestMapping(value = "logout")
	public String logout(HttpSession session) {
		session.invalidate();
		return "redirect:login";
	}

	@RequestMapping(value = "login")
	public String login(ModelMap model) {
		User u = new User();
		model.addAttribute("user", u);
		return "login";
	}

	@RequestMapping(value = "login", method = RequestMethod.POST)
	public String login(ModelMap model, User u, HttpSession session) {
		// check whether user is present in Users table
		Optional<User> user = userRepo.findById(u.getUsername());
		if (user.isPresent() && user.get().getPassword().equals(u.getPassword())) {
			session.setAttribute("username", u.getUsername());
			return "redirect:home";

		} else {

			model.addAttribute("user", u);
			model.addAttribute("message", "Login Failed!");
			return "login";
		}
	}

	@RequestMapping(value = "register")
	public String register(ModelMap model) {
		User u = new User();
		model.addAttribute("user", u);
		return "register";
	}

	@RequestMapping(value = "register", method = RequestMethod.POST)
	public String register(ModelMap model, User u) {
		// Insert user details into table
		try {
			userRepo.save(u);
			return "redirect:login";
		} catch (Exception ex) {
			System.out.println(ex);
			model.addAttribute("user", u);
			model.addAttribute("message", "Sorry! Registration Failed. Please try again!");
			return "register";
		}
	}

	@RequestMapping(value = "home")
	public String home(ModelMap model, HttpSession session) {
		String username = (String) session.getAttribute("username");
		List<Todo> todos = todoRepo.getRecentTodosByUser(username);
		// Take only first 5 todos from the list
		model.addAttribute("todos", todos.stream().limit(5).toArray());
		return "home";
	}
}

TodoController.java

TodoController provides operations related to Todos. It depends on UserRepo and TodoRepo.

package todo;

import java.util.List;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class TodoController {
	@Autowired
	private TodoRepo todoRepo;

	@Autowired
	private UserRepo userRepo;

	@RequestMapping(value = "add")
	public String add(ModelMap model) {
		Todo todo = new Todo();
		model.addAttribute("todo", todo);
		return "add";
	}

	@RequestMapping(value = "add", method = RequestMethod.POST)
	public String add(ModelMap model, Todo todo, HttpSession session) {
		// Insert Todo details into table
		try {
			// Set user to current user
			String username = (String) session.getAttribute("username");
			todo.setUsername(username);
			todoRepo.save(todo);
			return "redirect:/home";
		} catch (Exception ex) {
			System.out.println(ex);
			model.addAttribute("todo", todo);
			model.addAttribute("message", "Sorry! Could not add todo entry. Please try again!");
			return "add";
		}
	}

	@RequestMapping(value = "list")
	public String list(ModelMap model, HttpSession session) {
		// get current user
		String username = (String) session.getAttribute("username");
		User user = userRepo.findById(username).get();

		List<Todo> todos = user.getTodos();
		model.addAttribute("todos", todos);
		return "list";
	}

	@RequestMapping(value = "delete/{id}")
	public String delete(ModelMap model, @PathVariable("id") int id) {
		Todo todo = todoRepo.findById(id).get();
		todoRepo.delete(todo);
		return "redirect:/home";
	}

	@RequestMapping(value = "edit/{id}")
	public String edit(ModelMap model, @PathVariable("id") int id) {
		Todo todo = todoRepo.findById(id).get();
		model.addAttribute("todo", todo);
		return "edit";
	}

	@RequestMapping(value = "edit/{id}", method = RequestMethod.POST)
	public String edit(ModelMap model, Todo todo, @PathVariable("id") int id) {
		// Update todo details into table
		try {
			Todo dbTodo = todoRepo.findById(id).get();
			dbTodo.setText(todo.getText());
			dbTodo.setCategory(todo.getCategory());
			todoRepo.save(dbTodo);
			return "redirect:/home";
		} catch (Exception ex) {
			System.out.println(ex);
			model.addAttribute("todo", todo);
			model.addAttribute("message", "Sorry! Could not update todo entry. Please try again!");
			return "edit";
		}
	}

	@RequestMapping(value = "searchform")
	public String search() {
		return "search";
	}

	@RequestMapping(value = "search")
	public String search(String text, HttpSession session, ModelMap model) {
		System.out.println(text);
		List<Todo> todos = todoRepo.getTodosByText(session.getAttribute("username").toString(),
				"%" + text.toUpperCase() + "%");
		if (todos.size() > 0)
			model.addAttribute("todos", todos);
		else
			model.addAttribute("message", "Sorry! No todos found!");
		return "search";
	}
}

AuthenticationFilter.java

This is used to check whether user is authenticated or not. If user is not already authenticated (logged in) then it will redirect user to login page.

package todo;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Order(1)
public class AuthenticationFilter implements Filter {

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		String allowedUrls[] = { "login", "register", "styles.css", "allheaders.jsp" };

		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse res = (HttpServletResponse) response;

		// Allow some specific requests without authentication
		boolean allowed = false;
		String url = req.getRequestURI();

		for (String u : allowedUrls)
			if (url.endsWith(u))
				allowed = true;

		if (allowed) {
			chain.doFilter(request, response);
		}else {
			// URL is not allowed unless authentication is done
			HttpSession session = req.getSession();
			if (session == null || session.getAttribute("username") == null) // Authentication is not done
				res.sendRedirect("/login");
			else
				chain.doFilter(request, response);
		}
	}
}

TodoApplication.java

This starts Spring boot application. It extends SpringBootServletInitializer to enable the application to run in any Servlet container such as Tomcat, Glassfish etc.

package todo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class TodoApplication extends SpringBootServletInitializer {

	public static void main(String[] args) {
		SpringApplication.run(TodoApplication.class, args);
	}
}

JSPs

The following are JSPs as views to present data. Core tags of JSTL are used for conditional statements and loops.

styles.css

.banner {
	font-family: Arial;
	font-size: 30pt;
	background-color: red;
	color: white;
}

.menu {
	font-family: verdana;
	font-size: 12pt;
	font-weight: bold;
	background-color: silver;
}

.tableheader {
	font-family: calibri;
	font-size: 12pt;
	font-weight: bold;
	background-color: black;
	color: white;
}

body {
	font-family: calibri;
	font-size: 12pt;
}    

allheader.jsp

<link rel="stylesheet" href="styles.css" />
<div class="banner">ToDo List</div>
    

header.jsp

<link rel="stylesheet" href="/styles.css" />
<div class="banner">ToDo List</div>
<div class="menu">
	<a href="/home">Home</a>   <a href="/add">Add Todo</a>   <a
		href="/list">List Todos</a>   <a href="/searchform">Search Todos</a>  
	<span style="float: right"> User :  ${sessionScope.username}  
	  <a href="/logout">Logout</a>
	</span>
</div>
    

login.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<%@include file="allheader.jsp"%>
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form"%>

<title>Login</title>
</head>
<body>
	<h1>Login</h1>
	<sf:form modelAttribute="user" method="post">
     Username <br>
		<sf:input required="true" path="username" />
		<p />
     Password <br />
		<sf:password path="password" />
		<p />
		<button type="submit">Login</button>
	</sf:form>

	<h4>
		<a href="/register">Register as new user!</a>
	</h4>

	<h4>${message}</h4>
</body>
</html>
    

register.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<%@include file="allheader.jsp"%>
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form"%>
<title>Registration</title>
</head>
<body>
	<h1>Registration</h1>
	<sf:form modelAttribute="user" method="post">
     Username <br>
		<sf:input required="true" path="username" />
		<p />
     Password <br />
		<sf:password path="password" />
		<p />
		 Confirm Password <br />
		<sf:password path="confirmPassword" />
		<p />
		 Email Address <br>
		<sf:input required="true" path="email" />
		<p />
		<button type="submit">Register</button>
	</sf:form>
	<p />
	<a href="/login">Login</a>
	<h4>${message}</h4>
</body>
</html>

home.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<%@ include file="header.jsp"%>
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<title>Login</title>
</head>
<body>
	<h1>Recently Added</h1>
	<jsp:include page="list_todos.jsp" />
</body>
</html>

list_todos.jsp


<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>

<!--  find out whether we have any items in the list using length() function of JSTL  -->

<c:if test="${fn:length(todos) gt 0}">
	<table style="width: 100%">
		<tr class="tableheader">
			<td style="text-align: center">Description</td>
			<td style="text-align: center">Category</td>
			<td></td>

			<c:forEach var="todo" items="${todos}">
				<tr>
					<td style="text-align: center">${todo.text}</td>
					<td style="width: 20%; text-align: center">${todo.category}</td>
					<td style="text-align: center; width: 10%"><a
						href="edit/${todo.id}">Edit</a> <a
						onclick="return confirm('Do you really want to delete?')"
						href="delete/${todo.id}">Delete</a></td>
				</tr>
			</c:forEach>
	</table>
</c:if>

<c:if test="${fn:length(todos) == 0}">
	<h4>Sorry! No todos found!</h4>
</c:if>

add.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<%@include file="header.jsp"%>
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form"%>
<title>Add Todo</title>
</head>
<body>
	<h1>Add Todo</h1>
	<sf:form modelAttribute="todo" method="post">
        Text <br>
		<sf:input required="true" path="text" size="50" />
		<p />
        Category <br />
		<sf:select path="category">
			<sf:option value="education" label="Education" />
			<sf:option value="finance" label="Finance" />
			<sf:option value="ent" label="Entertainment" />
			<sf:option value="family" label="Family and Friends" />
			<sf:option value="maint" label="Maintenance" />
			<sf:option value="others" label="Others" />
		</sf:select>
		<p />
		<button type="submit">Add Todo</button>
	</sf:form>
	<h4>${message}</h4>
</body>
</html>

edit.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form"%>
<title>Edit Todo</title>
</head>

<body>
	<%@include file="header.jsp"%>
	<h1>Edit Todo</h1>
	<sf:form modelAttribute="todo" method="post">
        Text <br>
		<sf:input required="true" path="text" size="50" />
		<p />
        Category <br />
		<sf:select path="category">
			<sf:option value="education" label="Education" />
			<sf:option value="finance" label="Finance" />
			<sf:option value="ent" label="Entertainment" />
			<sf:option value="family" label="Family and Friends" />
			<sf:option value="maint" label="Maintenance" />
			<sf:option value="others" label="Others" />
		</sf:select>
		<p />
		<button type="submit">Update Todo</button>
	</sf:form>
	<h4>${message}</h4>
</body>
</html>

search.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<%@include file="header.jsp"%>
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<title>Search Todo</title>
</head>
<body>
	<h1>Search Todos</h1>
	<form action="search">
		Text <br> <input required="true" name="text" size="20" />
		<p />
		<button type="submit">Search</button>
	</form>

	<c:if test="${!empty todos}">
		<jsp:include page="list_todos.jsp" />
	</c:if>

	<h4>${message}</h4>

</body>
</html>

list.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<%@ include file="header.jsp"%>
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<title>Todos</title>
</head>
<body>
	<h1>Todos</h1>
	<jsp:include page="list_todos.jsp" />
</body>
</html>