Features

  • It uses the open-source DayPilot Lite Calendar component to display a drag and drop weekly calendar.

  • You can download a Spring Boot application with JavaScript/HTML5 frontend.

  • It includes a lightweight REST API backend for accessing the database storage (implemented as a RESTful Spring web service).

  • The API is built using Spring Boot 3.0.6.

See also a related tutorial that shows how to create a monthly calendar in Spring Boot.

Code License

Apache License 2.0

HTML5 Event Calendar Initialization

html5 javascript event calendar spring boot java default

In this step, we will start with the fronted that will be created as a simple HTML5 page with embedded JavaScript.

In order to display the JavaScript event calendar it's necessary to include the following code in the HTML page (src/resources/static/index.html):

<!-- DayPilot Pro library-->
<script src="daypilot-all.min.js"></script>

<!-- placeholder, this is where the calendar appears -->
<div id="dp"></div>

<!-- basic calendar config -->
<script>
  const dp = new DayPilot.Calendar("dp");
  dp.init();
</script>

Required steps:

  • First, you need to include the DayPilot library in your project using a script tag.

  • To create a Calendar component using DayPilot, you need to add a placeholder element to your HTML document where the calendar will appear. In the code, this element has the id dp and is represented by a div element.

  • Then, you can create the calendar component by instantiating the DayPilot.Calendar object and passing the id of the placeholder element to the constructor. This will create an empty calendar on the page, using the default configuration (day view, default CSS theme).

  • Finally, you need to call the init method on the DayPilot.Calendar object to initialize the component and display it on the page.

Styling: The default CSS classes are embedded and there is no need to include additional CSS style files. You can create a custom CSS theme using the online CSS theme designer and apply it using theme property.

Switching the Event Calendar to Week View

html5 javascript event calendar spring boot java week

In order to switch the event calendar to a week view we simply use the viewType property. The calendar properties (and events handlers) can be specified using the options object that comes as the second argument of the DayPilot.Calendar constructor.

<script>
  const dp = new DayPilot.Calendar("dp", {
    viewType: "Week"
  });
  dp.init();
</script>

Changing the Visible Date

html5 javascript event calendar spring boot java start date

By default, the event calendar displays the current week. You can set the initial date using using the startDate property:

<script>
  const dp = new DayPilot.Calendar("dp", {
    viewType: "Week",
    startDate: "2021-06-21"
  });
  dp.init();
</script>

To change the visible week later, you can use the update() method and change the startDate property as needed:

dp.update({
  startDate: dp.startDate.addDays(7)
});

This example displays the following week in the calendar.

Changing the Calendar Locale

html5 javascript event calendar spring boot java locale

 The week start is calculated using the current locale. By default, the locale is set to "en-us" but you can change it as needed:

<script>
  const dp = new DayPilot.Calendar("dp", {
    viewType: "Week",
    startDate: "2021-06-21",
    locale: "de-de",
  });
  dp.init();
</script>

You can see that the locale affects the date format in the header (d.M.yyyy vs M/d/yyyy) and also the first day of week (Monday vs Sunday).

Changing the Date Format used in the Calendar Header

html5 javascript event calendar spring boot java date format

Every locale includes a default date format string which is used for the column headers. For the German locale it is "d.M.yyyy". You can also use a custom date format (headerDateFormat property) to customize the header date format:

<script>
  const dp = new DayPilot.Calendar("dp", {
    viewType: "Week",
    startDate: "2023-06-21",
    locale: "de-de",
    headerDateFormat: "d MMMM yyyy"
  });
  dp.init();
</script>

Online Calendar Configurator App

spring boot weekly calendar configurator builder open source

You can use the UI Builder online application to explore some of the most common configuration properties. The application lets you preview the changes using a live calendar component instances and download a project that includes a calendar setup with the selected configuration. It supports JavaScript, TypeScript, Angular, React and Vue projects.

Switching a Date using a Date Picker

html5 javascript event calendar spring boot java date picker

DayPilot includes a date picker component (DayPilot.Navigator) that lets users choose a date using a mini calendar.

We will add a Navigator placeholder to the HTML:

<div id="nav"></div>

And initialize it:

<script>
  const datePicker = new DayPilot.Navigator("nav", {
    showMonths: 3,
    skipMonths: 3,
    selectMode: "week"
  });
  nav.init();
</script>

Now we need to detect changes of the selected week and update the event calendar component accordingly:

<script>
  const nav = new DayPilot.Navigator("nav", {
    showMonths: 3,
    skipMonths: 3,
    selectMode: "week",
    onTimeRangeSelected: (args) => {
        dp.startDate = args.day;
        dp.update();
    }
  });
  nav.init();
</script>

Loading Calendar Data in Spring Boot

html5 javascript event calendar spring boot java loading data

In order to load the event data from a database, we will call events.load() method:

dp.events.load("/api/events");

The event calendar component automatically adds the visible range to this URL (using start and end query string parameters) and makes an HTTP request to get the event data. The sample JSON response looks like this:

[
  {"id":3,"text":"Meeting","start":"2023-06-14T10:00:00","end":"2023-06-14T13:00:00","color":null},
  {"id":4,"text":"Errands","start":"2023-06-16T10:00:00","end":"2023-06-16T13:00:00","color":"#f1c232"}
]

The server-side implementation of the JSON endpoint can be found in MainController.java file:

package org.daypilot.demo.html5eventcalendarspring.controller;

//...

@RestController
public class MainController {

    @Autowired
    EventRepository er;

    @GetMapping("/api/events")
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    Iterable<Event> events(@RequestParam("start") @DateTimeFormat(iso = ISO.DATE_TIME) LocalDateTime start, @RequestParam("end") @DateTimeFormat(iso = ISO.DATE_TIME) LocalDateTime end) {
        return er.findBetween(start, end);
    }

    // ...

}

The Spring controller is very simple and uses an EventRepository interface (that inherits from CrudRepository<Event, Long>) to load the event data.

package org.daypilot.demo.html5eventcalendarspring.repository;

import java.time.LocalDateTime;
import java.util.List;

import org.daypilot.demo.html5eventcalendarspring.domain.Event;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;

public interface EventRepository extends CrudRepository<Event, Long> {
	@Query("from Event e where not(e.end < :from or e.start > :to)")
	public List<Event> findBetween(@Param("from") @DateTimeFormat(iso=ISO.DATE_TIME) LocalDateTime start, @Param("to") @DateTimeFormat(iso=ISO.DATE_TIME) LocalDateTime end);
}

The Event model class defines the event record structure:

package org.daypilot.demo.html5eventcalendarspring.domain;

import jakarta.persistence.*;

import java.time.LocalDateTime;

@Entity
public class Event {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;

    String text;

    @Column(name = "event_start")
    LocalDateTime start;

    @Column(name = "event_end")
    LocalDateTime end;

    String color;

    public Long getId() {
        return id;
    }

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

    public String getText() {
        return text;
    }

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

    public LocalDateTime getStart() {
        return start;
    }

    public void setStart(LocalDateTime start) {
        this.start = start;
    }

    public LocalDateTime getEnd() {
        return end;
    }

    public void setEnd(LocalDateTime end) {
        this.end = end;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

This Spring Boot project uses H2 in-memory database that is automatically initialized on startup (application.properties):

spring.datasource.url=jdbc:h2:mem:mydb
spring.h2.console.enabled=true
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
spring.jpa.defer-datasource-initialization=true

spring.jackson.serialization.write_dates_as_timestamps=false
server.port=${port:8081}

Saving Updated Calendar Events to the Database in Spring Boot

Whenever the user moves an event using drag and drop, the Calendar fires an onEventMove event handler. We can use this event to notify the server using an HTTP API call:

const dp = new DayPilot.Calendar("dp", {
  onEventMove: async (args) => {
    const params = {
      id: args.e.id(),
      start: args.newStart,
      end: args.newEnd
    };
    const {data} = await DayPilot.Http.post("/api/events/move", params);
    console.log("Event moved");
  },
  // ...
});

The onEventMove property is set to an async function that receives an args object containing information about the moved event, including its id, newStart, and newEnd. We then make an HTTP POST request to /api/events/move with these parameters, and log a message to the console when the move is complete.

On the server side, this API call is handled by the moveEvent method of the MainController class:


package org.daypilot.demo.html5eventcalendarspring.controller;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.daypilot.demo.html5eventcalendarspring.domain.Event;
import org.daypilot.demo.html5eventcalendarspring.repository.EventRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;
import org.springframework.web.bind.annotation.*;

import jakarta.transaction.Transactional;
import java.time.LocalDateTime;

@RestController
public class MainController {

    @Autowired
    EventRepository er;

    @PostMapping("/api/events/move")
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @Transactional
    Event moveEvent(@RequestBody EventMoveParams params) {

        Event e = er.findById(params.id).get();

        e.setStart(params.start);
        e.setEnd(params.end);

        er.save(e);

        return e;
    }

    public static class EventMoveParams {
        public Long id;
        public LocalDateTime start;
        public LocalDateTime end;
        public Long resource;
    }

    // ...

}

It updates the start and end properties of the Event instance and saves the changes to the database.

Maven Dependencies (pom.xml)

Here is the Maven pom.xml file that loads the required dependencies (Spring Boot framework and H2 database):

pom.xml

<?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>org.daypilot.demo</groupId>
    <artifactId>html5-event-calendar-spring</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.6</version>
        <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>19</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

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

</project>