Een Todo application with spring and jsp

   todo
     + src
     | + main
     |   + java 
     |   | + com
     |   |   + litteworld
     |   |     + todo
     |   |       + model
     |   |          - Todo.java
     |   |       + controllers
     |   |          - TodoController.java
     |   |       + services
     |   |          - TodoService.java
     |   + webapp
     |     + WEB-INF
     |       - web.xml 
     |       - spring-context.xml
     - pom.xml

Maven POM

In the POM we define the library dependencies of this project

The dependencies are:

We will use the jetty plugin


<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.littleworld</groupId>
  <artifactId>todo</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>todo</name>

   <properties>
    <jdk.version>1.8</jdk.version>
    <springframework.version>4.2.3.RELEASE</springframework.version>
    <hibernate.version>4.3.6.Final</hibernate.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${springframework.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${springframework.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-jpa</artifactId>
      <version>1.9.1.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-orm</artifactId>
      <version>${springframework.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>${springframework.version}</version>
    </dependency>
    
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-entitymanager</artifactId>
      <version>${hibernate.version}</version>
    </dependency>
   
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.37</version>
    </dependency>

    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.1.3</version>
    </dependency>
  
    <dependency>
    	<groupId>com.fasterxml.jackson.core</groupId>
    	<artifactId>jackson-databind</artifactId>
    	<version>2.6.3</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.3</version>
        <configuration>
          <source>${jdk.version}</source>
          <target>${jdk.version}</target>
        </configuration>
      </plugin>

    <plugin>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <version>9.3.6.v20151106</version>
        <configuration>
          <scanIntervalSeconds>10</scanIntervalSeconds>
          <webApp>
            <contextPath>/todo</contextPath>
          </webApp>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-eclipse-plugin</artifactId>
        <version>2.9</version>
        <configuration>
          <wtpversion>2.0</wtpversion>
          <wtpContextName>todo</wtpContextName>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Model

This project uses the todo as model

The fields in the model will be used in the views form and list. Apart from the id field.


/* generated by: ControllerGenerator Tue May 17 22:45:51 CEST 2016 */
package com.littleworld.todo.model;

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

@Entity
public class Todo {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  int id;

  String task;

  public Todo() {}

  public Todo(int id, String task) {
    this.id = id;
    this.task = task;
  }
  public int getId() {
    return id;
  }
  public void setId(int id)  {
    this.id = id;
  } 
  public String getTask() {
    return task;
  }
  public void setTask(String task)  {
    this.task = task;
  } 


  @Override 
  public String toString() {
    return "[Todo: [" + "id" + id + "task" + task + "]"; 
  }
}

Controller

We will use a Spring MVC

/* generated by: ControllerGenerator Tue May 17 22:45:51 CEST 2016 */
package com.littleworld.todo.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;

import com.littleworld.todo.services.TodoService;
import com.littleworld.todo.model.Todo;

@Controller
public class TodoController {

  @Autowired  private TodoService todoService;

  //curl -H "Content-Type: application/json" -X POST -d '{"id": 0, "task": "taskTest"}' http://localhost:8080/todo/create
  @ResponseBody
  @RequestMapping(value = "/create", method = RequestMethod.POST)
  public int createTodo(@RequestBody Todo todo) {
    return todoService.create(todo).getId();
  }

  //curl -H "Content-Type: application/json" -X PUT -d '{"id": 1, "task": "taskTest"}' http://localhost:8080/todo/todo/1
  @ResponseBody
  @RequestMapping(value = "/update/{id}", method = RequestMethod.PUT)
  public int updateTodo(@PathVariable  Integer id, @RequestBody Todo todo) {
    return todoService.update(todo).getId();
  }

  //curl  http://localhost:8080/todo/list
  @ResponseBody
  @RequestMapping(value = "/list", method = RequestMethod.GET)
  public List<Todo> findAllTodos(Model model) {
    return todoService.findAll();

  }
  //curl -X delete http://localhost:8080/todo/delete/1
  @ResponseBody
  @RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE)
  public void deleteTodo(@PathVariable  Integer id) {
      todoService.delete(id);
  }
}

Services

The service layer

TodoService contains 3 methodes We support a simple implementation - TodoServiceImpl will keep the todos in an ArrayList

package com.littleworld.todo.services;

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.context.annotation.Scope;


import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;

import com.littleworld.todo.model.Todo;

@SuppressWarnings("unchecked")
@Transactional
@Repository
public class TodoService {

    @PersistenceContext
    private EntityManager em;

    public Todo create(Todo todo ) {
        em.persist(todo);
        return todo;
    }

    public List<Todo> findAll() {
        return em.createQuery("from " + Todo.class.getSimpleName()).getResultList();
    }
 
    public Todo findById(Integer id) {
        return em.find(Todo.class, id);
    }

    public void delete(Integer id) {
        Todo todo = findById(id);
        em.remove(todo);
    }

    public Todo update(Todo todo) {
        Todo todoAttached = findById(todo.getId());

        todoAttached.setId(todo.getId());
        todoAttached.setTask(todo.getTask());    
        em.merge(todoAttached);
        return todoAttached;
    }
}

Context

We configure this in a web.xml and a spring-context.xml
<web-app xmlns="http://java.sun.com/xml/ns/javaee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	version="3.0">
	<servlet>
		<servlet-name>spring-web</servlet-name>
		<servlet-class>
      org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
		<load-on-startup>1</load-on-startup>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring-context.xml</param-value>
		</init-param>
	</servlet>

	<servlet-mapping>
		<servlet-name>spring-web</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
</web-app>

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
  xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:jpa="http://www.springframework.org/schema/data/jpa"
 	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
		http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

 <!-- Enables the Spring MVC @Controller programming model -->
	<mvc:annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving 
		up static resources in the $webappRoot/resources directory -->
	<mvc:resources mapping="/resources/**" location="/resources/" />

	<bean name="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<property name="url" value="jdbc:mysql://localhost:3306/todo" />
		<property name="username" value="root" />
	</bean>

	<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
      <property name="dataSource" ref="dataSource" />
      <property name="packagesToScan" value="com.littleworld.todo.model" />
      <property name="jpaVendorAdapter">
         <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
      </property>
      <property name="jpaProperties">
         <props>
            <prop key="hibernate.hbm2ddl.auto">create-drop</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
            <prop key="hibernate.show_sql">true</prop>
         </props>
      </property>
  </bean>

  <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
  </bean>
 
  <tx:annotation-driven transaction-manager="transactionManager" />

	<context:component-scan base-package="com.littleworld.todo" />
</beans>

Run the application

To run the application. Goto the root directory of the application and type

(Maven should in the enviroment variable PATH; and JAVA_HOME should be set to the jdk installation dir)

mvn jetty:run
http://localhost:8080/todo/list

Open a console and execute the curl expressions.
De curl expression are inside the TodoController Or use Postman, a chrome extension.