ECE366 - Lesson 6
Spring Boot, JPA
Instructor: Professor Hong
## Spring Boot
- a service layer that will connect your database to your user interface
- use the Spring Initializr: [https://start.spring.io/](https://start.spring.io/)
- you may have to remove the test dependency (or fix the test) or use an older version of spring boot
## pom.xml
[https://mvnrepository.com/](https://mvnrepository.com/)
```
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.chrishong</groupId>
<artifactId>rps</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>rps</name>
<description>RPS Game</description>
<properties>
<java.version>19</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.5.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
```
## Maven
```
$ mvn package
$ java -jar target/rps-0.0.1-SNAPSHOT.jar
```
## Docker Compose
```
services:
db:
image: postgres
volumes:
- $HOME/srv/postgres:/var/lib/postgresql/data
environment:
- POSTGRES_DB=rps
- POSTGRES_PASSWORD=password
expose:
- 5432:5432
ports:
- 5432:5432
restart: always
app:
build: .
ports:
- 8080:8080
environment:
- POSTGRES_DB=rps
- POSTGRES_HOST=db
- POSTGRES_PASSWORD=password
depends_on:
- db
```
- Set up your database and service to communicate
- Expose ports as necessary (db port)
## Dockerfile
```
FROM maven:3.8.7-eclipse-temurin-19 AS build
ADD . /project
WORKDIR /project
RUN mvn -e package
FROM eclipse-temurin:latest
COPY --from=build /project/target/rps-0.0.1-SNAPSHOT.jar /app/rps.jar
ENTRYPOINT ["java","-jar","/app/rps.jar"]
```
## Docker Compose Commands
```
$ docker compose build
$ docker compose up
```
## DBeaver
- Connect to your docker's Postgres
- localhost
- db: rps
- port: 5432
- user name: postgres
- password: password
## Java Persistence API (JPA)
- Standard Java EE (Jakarta EE) specification for ORM (Object–Relational Mapping)
- Allows you to map between objects and database tables
- Streamlines persistence to standard format
- Reduces JDBC code
- Focus on OOP
## application.properties
```
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:postgresql://${POSTGRES_HOST}:5432/${POSTGRES_DB}
spring.datasource.username=postgres
spring.datasource.password=${POSTGRES_PASSWORD}
```
## Hard coded
```
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:postgresql://$localhost:5432/rps
spring.datasource.username=postgres
spring.datasource.password=password
```
## pom.xml
```
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
```
## Important Annotations
- ```@RestController``` - enables API endpoints
- ```@Entity``` - a row from the database
- ```@Table``` - the table name
- ```@Id``` - the ID of a table row
- ```@Column``` - a column of the table
- ```@GeneratedValue``` - strategies for primary key
## Code Organization for JPA
## User Class
data/User.java
```
package com.chrishong.rps.data;
import jakarta.persistence.*;
@Entity
@Table(name="USERS")
public class User {
@Id
@Column(name="USER_ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long userId;
@Column(name="USER_NAME")
private String userName;
@Column(name="PASSWORD")
private String password;
@Column(name="TOTAL_GAMES")
private int totalGames;
@Column(name="TOTAL_WIN")
private int totalWin;
@Column(name="TOTAL_LOSS")
private int totalLoss;
@Column(name="TOTAL_TIE")
private int totalTie;
public long getUserId() {
return userId;
}
public void setUserId(long userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getTotalGames() {
return totalGames;
}
public void setTotalGames(int totalGames) {
this.totalGames = totalGames;
}
public int getTotalWin() {
return totalWin;
}
public void setTotalWin(int totalWin) {
this.totalWin = totalWin;
}
public int getTotalLoss() {
return totalLoss;
}
public void setTotalLoss(int totalLoss) {
this.totalLoss = totalLoss;
}
public int getTotalTie() {
return totalTie;
}
public void setTotalTie(int totalTie) {
this.totalTie = totalTie;
}
@Override
public String toString() {
return "User{" +
"userId=" + userId +
", userName='" + userName + '\'' +
", password='" + password + '\'' +
", totalGames=" + totalGames +
", totalWin=" + totalWin +
", totalLoss=" + totalLoss +
", totalTie=" + totalTie +
'}';
}
}
```
## UserRepository Interface
data/UserRepository.java
```
package com.chrishong.rps.data;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository {
}
```
## UserService
business/UserService
```
package com.chrishong.rps.business;
import com.chrishong.rps.data.User;
import com.chrishong.rps.data.UserRepository;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public List getUsers(){
Iterable users = this.userRepository.findAll();
List userList = new ArrayList<>();
users.forEach(user->{userList.add(user);});
return userList;
}
}
```
## WebserviceController
webservice/WebserviceController.java
```
package com.chrishong.rps.webservice;
import com.chrishong.rps.business.UserService;
import com.chrishong.rps.data.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class WebserviceController {
private final UserService userService;
public WebserviceController(UserService userService) {
this.userService = userService;
}
@GetMapping("/users")
public List getUsers(){
System.out.println("getUsers");
return this.userService.getUsers();
}
@GetMapping("/testuser")
public String getTestUser() {
return "TEST USERS";
}
}
```