Java Spring Boot 2
Java Spring Boot 2
Terminology
- POJO : Plain Old Java Object (may have more that setters/getters in Spring world)
- Java Beans : Simple objects with only setters/getters
- Spring Beans : POJOs confiugered in the application context
- DTO : Data Transfer Objects are Java Beans used to move state between layers
- IOC : Inversion Of Control
- IoC provides mechanism of dependency injection
- Application Context wraps the Bean Factory which serves the beans at the runtime of the application
- Spring Boot provides auto-configuration of the Application Context
Getting Started
Why Spring Boot?
- Support rapid development
- Remove boilerplate of application setup
- Many uses
- Cloud Native support but also traditional
Key Aspects
- Embedded tomacat (or others)
- Auto-configuration of Application Context
- Automatic Servlet Mappings
- Database support and Hibermate/JPA dialect
- Automatic Controller Mappings
Auto Config
- Default opiniated configuration
- Very to override defaults
- Configuration on presence
Spring Initializr
- start.spring.io
- Spring Boot: pick latest released version (ie. 2.5.6)
- Packaging: Jar
- Add Dependencies:
- Pring Web
- TBD…
- Generate
Now it can build and run as is:
java -jar target/xyz-0.0.1-SNAPSHOT.jar
Use Chrome: localhost:8080
Inversion of Control
- Container mainains your class dependencies
- Objects injected at runtime or startup time
- An object accepts the dependencies for construction instead of constructing them
Spring IoC
- Bean Factory
- Application Context
- References
- Analysis of construction order
Proxies
- Beans in Bean Faactory are proxied
- Annitations drive proxies
- Annitations are easy extension points, for your own abstracts too
- Method calling order matters
Data Access in Spring
Spring Data
- Provides a common set of interfaces
- Provides a common naming convention
- Provides aspected behavior
- Provides Repository and Data Mapping convention
Benefits of Spring Data
- Remove boilerplate code
- Allows for swapping datasources easier
- Allows to focus on buisiness logic
Key Components
- Repository Interface
- Entity Object
- DataSource no accessed directly
Embeedded DB with Spring Boot
Needed dependencies:
org.springframework.boot:spring-boot-starter-data-jpa
com.h2database:h2
Set application.properties:
- logging.level.org.springframework.jdbc.datasource.init.ScriptUtils=debug : by default is set to info
- spring.jpa.hibernate.ddl-auto=none : don’t create schema, and just connect to DB
Repository with Spring Data
-
Java Persistence API (or JPA)
- Mapping Java objects to DB tables and vice versa is called Object-relational Mapping (ORM)
- JPA permits the developer to works directly with objects rather tahn with SQL statements
- Based on Annotations
-
- A class which should be persisted in a database it must be annotated with
javax.persistence.Entity
- JPA uses a database table for every entity
- Persisted instances of the class will be represented as one row in the table
- JPA allows to auto-generate the primary key in the database via the
@GeneratedValue
annotation - By default, the table name corresponds to the class name. You can change this with the addition to the annotation
@Table(name="NEWTABLENAME")
- A class which should be persisted in a database it must be annotated with
Code Example
@Entity
@Table(name="ROOM")
public class Room {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="ROOM_ID")
private long id;
@Column(name="NAME")
private String name;
@Column(name="ROOM_NUMBER")
private String roomNumber;
@Column(name="BED_INFO")
private String bedInfo;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRoomNumber() {
return roomNumber;
}
public void setRoomNumber(String roomNumber) {
this.roomNumber = roomNumber;
}
public String getBedInfo() {
return bedInfo;
}
public void setBedInfo(String bedInfo) {
this.bedInfo = bedInfo;
}
@Override
public String toString() {
return "Room{" +
"id=" + id +
", name='" + name + '\'' +
", roomNumber='" + roomNumber + '\'' +
", bedInfo='" + bedInfo + '\'' +
'}';
}
}
- Create a CrudRepository interface for the created Entity:
Code Example
@Repository
public interface RoomRepository extends CrudRepository<Room, Long> {
// Room is the Entity class
// Long is the ID type
}
-
Create a Component Event:
- A
@Component
Annotation is automatically picked by Spring
- A
Code Example
@Component
public class AppStartupEvent implements ApplicationListener<ApplicationReadyEvent> {
private final RoomRepository roomRepository;
public AppStartupEvent(RoomRepository roomRepository) {
this.roomRepository = roomRepository;
}
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
Iterable<Room> rooms = this.roomRepository.findAll();
rooms.forEach(System.out::println);
}
}
Using remote database
Replace the H2 database for an other database, example a PostgreSQL:
dependencies:
org.postgresql:postgresql
In application.properties
:
spring.jpa.database=postgresql
spring.datasource.url=jdbc:postgresql://localhost:5432/dev
spring.datasource.username=postgres
spring.datasource.password=postgres
Service Tier
Utilizing IoC
Why use IoC?
- Allows you to focus on contracts
- Develoip business code only, leave constuction to the container
- Build intermediate abstractions
- Produce clean code
Srping and IoC:
- IoC container is configured by developer
- Spring maintains handles to objects constucted at startup
- Spring serves singletons to classes during construction
- Spring maintains lifecycle of beans
- Developer only accesses the application context
Service abstraction
Why building Service Abstractions:
- Encapsulate layers?
- Abstract 3rd partys APIs
- Simplify implementations
- Swap out implementations as runtime (ie. factory pattern)
How to build one?
- Define our interface (or class)
- Create the API
- Inject the dependencies
- Annotate or configure (classes)
- Code the implemantation
Spring Service Object
- We mark beans with @Service to indicate that they’re holding the business logic. Besides being used in the service layer, there isn’t any other special use for this annotation.
- Starting with Spring 2.5, the framework introduced annotations-driven Dependency Injection. The main annotation of this feature is @Autowired. It allows Spring to resolve and inject collaborating beans into our bean.
- Using
@Autowired
or either properties or setters/getters isn’t a good practice or easy to test; - Use final properties with constructors to have immutable object. If more than one constructor is defined then using
@Autowired
on the default one will make Spring to use it.
- Using
Code Example
@Service
public class ReservationService {
private final RoomRepository roomRepository;
private final GuestRepository guestRepository;
private final ReservationRepository reservationRepository;
@Autowired // optional if only one constructor
public ReservationService(RoomRepository roomRepository, GuestRepository guestRepository, ReservationRepository reservationRepository) {
this.roomRepository = roomRepository;
this.guestRepository = guestRepository;
this.reservationRepository = reservationRepository;
}
// Business logic here...
}
Web pages with Spring
Controller
Model View Controller (or MVC)
- Fundamental pattern for Web application development
- The
Model
is the data - The
View
is the visual display that is populated - The
Controller
wires the view with the model
Spring Controller
- Spring bean
- Annotated for the servlet mapping
- Responds to incoming web requests
- Output a view or raw data
Template Engines
- Spring supports several
- Thymeleaf most popular
- Provides a DSL for HTML leaving raw html documents
- Placeholders for dynamic data
- Rendiring engin allows for final products
Code Example
@Controller
@RequestMapping("/reservations")
public class RoomReservationController {
private final DateUtils dateUtils;
private final ReservationService reservationService;
public RoomReservationController(DateUtils dateUtils, ReservationService reservationService) {
this.dateUtils = dateUtils;
this.reservationService = reservationService;
}
@RequestMapping(method = RequestMethod.GET)
public String getReservations(@RequestParam(value="date", required=false) String dateString, Model model){
Date date = this.dateUtils.createDateFromDateString(dateString);
List<RoomReservation> roomReservations = this.reservationService.getRoomReservationsForDate(date);
model.addAttribute("roomReservations", roomReservations);
return "roomres";
}
}
Can use Thymeleaf to create HTML pages.
- Add the web page to
src/main/resources/templates