180 lines
5.0 KiB
Markdown
180 lines
5.0 KiB
Markdown
+++
|
||
categories = ["software"]
|
||
tags = ["java"]
|
||
date = 2024-11-10T15:55:42Z
|
||
description = ""
|
||
draft = false
|
||
slug = "java-spring-tomcat"
|
||
title = "☕ Developing Spring REST API - Pt. I"
|
||
author = "nicholas"
|
||
+++
|
||
|
||
Much time has passed since I last worked with Spring framework in Java. I need to build out a development environment to enable me to build Java applications. In this log, the environment will be configured to include the following tools and features:
|
||
* Eclipse IDE
|
||
* Java (JRE, JDK)
|
||
* Maven (dependency manager, etc.)
|
||
* Spring Boot (Java framework)
|
||
|
||
This log is a series of baby steps that will result in basic implementation of a REST API.
|
||
|
||
|
||
## Code Editor
|
||
First, I need a code editor/IDE. I selected Eclipse for no particular reason. My understanding is that IntelliJ IDEA is a more modern, refined alternative that I may try down the line. For now, all I need is a default installation to get started.
|
||
|
||
|
||
## Hello World
|
||
I allow the IDE to walk me through a hello world tutorial to become familiar with the software and remind myself of the basic structure of a Java program.
|
||
|
||
|
||
## Spring REST API endpoint
|
||
My next milestone is to set up a trivial API endpoint to familiarize myself with Spring MVC. I will use this framework to build an endpoint that will return "hello world". Eventually, this project will become an API for a plant simulation app.
|
||
|
||
* I use spring initializr to automate the creation of the necessary boilerplate to run a minimally viable endpoint.
|
||
|
||
* I create a controller class for the API: PlantController.java.
|
||
* This class uses Spring's @RestController and @GetMapping annotations to define the controller and one endpoint.
|
||
* For now, I have defined a GET endpoint at /helloworld, which returns the string "hello world".
|
||
|
||
```java
|
||
package plantsim.PlantSimulatorAPI;
|
||
|
||
import org.springframework.web.bind.annotation.GetMapping;
|
||
import org.springframework.web.bind.annotation.RestController;
|
||
|
||
@RestController
|
||
public class PlantController {
|
||
|
||
@GetMapping("/helloworld")
|
||
public String helloworld() {
|
||
return "hello world";
|
||
}
|
||
|
||
}
|
||
```
|
||
It works. Now I can configure my data models and database.
|
||
|
||
## Database
|
||
Database configuration will require a few steps.
|
||
|
||
* Create in-memory database with h2
|
||
* Using the credentials defined below and in application.properties I am able to connect to the database testdb at /h2-console.
|
||
|
||
```java
|
||
spring.datasource.url=jdbc:h2:mem:testdb
|
||
spring.datasource.driver-class-name=org.h2.Driver
|
||
spring.datasource.username=sa
|
||
spring.datasource.password=password
|
||
spring.h2.console.enabled=true
|
||
```
|
||
|
||
* In the h2 console, I can execute SQL queries and explore the database structure, etc.
|
||
|
||
1. Initialize database – populate with data
|
||
|
||
* Since I have defined an entity class for the plant object, Hibernate will automatically create the plant database table for me. I will need to populate the table data, however.
|
||
* I populate the tale with data using data.sql. By default, Spring Boot will look in src/main/resources for the script and execute it after the table has been initialized (according to application.properties -> spring.jpa.defer-datasource-initialization=true
|
||
* I configure the script below to insert a couple of rows:
|
||
|
||
```sql
|
||
-- Insert rows
|
||
INSERT INTO plant (name) VALUES ('Ficus Audrey');
|
||
INSERT INTO plant (name) VALUES ('Lucky Bamboo');
|
||
INSERT INTO plant (name) VALUES ('Chinese Money Plant');
|
||
```
|
||
3. Configure API endpoint to return plant objects
|
||
|
||
* To return a plant object instead of a string, I will need to configure following:
|
||
* Plant entity that matches database schema – This will use object-relational mapping (ORM) to map my Java entities to my database table plant
|
||
|
||
```java
|
||
package plantsim.PlantSimulatorAPI;
|
||
|
||
import jakarta.persistence.Entity;
|
||
import jakarta.persistence.GeneratedValue;
|
||
import jakarta.persistence.GenerationType;
|
||
import jakarta.persistence.Id;
|
||
|
||
@Entity
|
||
public class Plant {
|
||
|
||
@Id
|
||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||
private Long id;
|
||
private String name;
|
||
|
||
public Plant() {
|
||
}
|
||
|
||
public Plant(Long id, String name) {
|
||
this.id = id;
|
||
}
|
||
|
||
public void setId(Long id) {
|
||
this.id = id;
|
||
}
|
||
|
||
public String getName() {
|
||
return name;
|
||
}
|
||
|
||
public void setName(String name) {
|
||
this.name = name;
|
||
}
|
||
|
||
}
|
||
```
|
||
* Add JPA dependency to pom.xml – JPersistence API
|
||
```
|
||
jakarta.persistence
|
||
jakarta.persistence-api
|
||
3.1.0
|
||
```
|
||
* Create a JPA repository to fetch the Plant objects from testdb.
|
||
|
||
|
||
|
||
|
||
```java
|
||
package plantsim.PlantSimulatorAPI;
|
||
|
||
import org.springframework.data.jpa.repository.JpaRepository;
|
||
|
||
public interface PlantRepository extends JpaRepository {
|
||
}
|
||
```
|
||
|
||
* Update the controller to return the Plant object.
|
||
|
||
|
||
|
||
|
||
```java
|
||
@Autowired
|
||
private PlantRepository plantRepository;
|
||
|
||
@GetMapping("/plant")
|
||
public List getPlants() {
|
||
return plantRepository.findAll();
|
||
}
|
||
```
|
||
|
||
## Results
|
||
|
||
If I navigate to /plant, the program returns a JSON-formatted string of the all of the plants stored in the database. I will use this as a foundation to later build into the project actual functionality.
|
||
|
||
```json
|
||
[
|
||
{
|
||
"name": "Ficus Audrey"
|
||
},
|
||
{
|
||
"name": "Lucky Bamboo"
|
||
},
|
||
{
|
||
"name": "Chinese Money Plant"
|
||
}
|
||
]
|
||
```
|
||
|
||
|