0% found this document useful (0 votes)
8 views

4-Creating a Web Application with Spring Boot

The document outlines the process of creating a web application using Spring Boot, focusing on building JSON-based APIs with the help of the Jackson library for serialization and deserialization. It explains how to set up a REST controller, handle HTTP GET and POST requests, and integrate Node.js for JavaScript bundling. Additionally, it introduces React.js for building user interfaces within the Spring Boot application.

Uploaded by

armaganuygunn
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views

4-Creating a Web Application with Spring Boot

The document outlines the process of creating a web application using Spring Boot, focusing on building JSON-based APIs with the help of the Jackson library for serialization and deserialization. It explains how to set up a REST controller, handle HTTP GET and POST requests, and integrate Node.js for JavaScript bundling. Additionally, it introduces React.js for building user interfaces within the Spring Boot application.

Uploaded by

armaganuygunn
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 27

BIM308 – Web Server

Programming
4- Creating a Web Application with
Spring Boot
Creating an Application with Spring Boot -
Creating JSON-based APIs
A key ingredient in building any web application is the ability to provide
an API. In the olden days, this was complex and hard to ensure
compatibility.
In this day and age, the world has mostly converged on a handful of
formats, many based on JSON-based structures.
One of the powerful features of Spring Boot is that when you add
Spring Web to a project, as we did at the beginning of this topic, it adds
Jackson to the classpath. Jackson is a JSON serialization/deserialization
library that has been widely adopted by the Java community.
Creating an Application with Spring Boot -
Creating JSON-based APIs
Jackson’s ability to let us define how to translate Java classes back and
forth with our preferred flavor of JSON combined with Spring Boot’s
ability to autoconfigure things means that we don’t have to lift another
finger of setup to start coding an API.
To start things off, we create a new class in the same package we’ve
been using throughout this topic. Call it ApiController. At the top, apply
the @RestController annotation.
Creating an Application with Spring Boot -
Creating JSON-based APIs
@RestController is similar to the @Controller annotation we used
earlier. It signals to Spring Boot that this class should be automatically
picked up for component scanning as a Spring bean. This bean will be
registered in the application context and also with Spring MVC as a
controller class so it can route web calls.

But it has one additional property—it switches every web method from
being template-based to JSON-based. In other words, instead of a web
method returning the name of a template that Spring MVC renders
through a templating engine, it instead serializes the results using
Jackson.
Creating an Application with Spring Boot -
Creating JSON-based APIs
• We already mentioned how the @RestController
public class ApiController {
@RestController annotation marks this as a private final VideoService videoService;
public ApiController(VideoService videoService) {
Spring MVC controller that returns JSON this.videoService = videoService;
}
• Using constructor injection, we will @GetMapping("/api/videos")
public List<Video> all() {
automatically get a copy of the same return videoService.getVideos();
VideoService we created earlier in this topic }
}

• @GetMapping responds to HTTP GET calls [


from /api/videos {
"name": "Need HELP with your SPRING BOOT 3 App?"

• This web method will fetch that list of Video },


{
records and return them, causing them to },
"name": "Don't do THIS to your own CODE!"

get rendered into a JSON array by Jackson {


"name": "SECRETS to fix BROKEN CODE!"
}
]
Creating an Application with Spring Boot -
Creating JSON-based APIs
[
This barebones JSON array contains three {
entries, one for each of our Video records. "name": "Need HELP with your SPRING BOOT 3 App?"
},
And since the Video record only has one {
attribute, name, this is exactly what Jackson "name": "Don't do THIS to your own CODE!"
},
yields. {
"name": "SECRETS to fix BROKEN CODE!"
There is no need to configure anything to }
make Jackson start producing. ]

Of course, an API that does nothing but


produce JSON isn’t much of an API at all.
Naturally, we need to consume JSON as well.
To do that, we need to create a web method
in our ApiController class that will respond to
HTTP POST calls.
Creating an Application with Spring Boot -
Creating JSON-based APIs
POST versus PUT versus everything else
There are several standard HTTP verbs at our disposal. The most common
ones are GET, POST, PUT, and DELETE. There are actually others, but we
won’t be needing them here. It’s important to understand that GET calls are
expected to do nothing but return data. They are not meant to cause state
changes on the server, which is also known as idempotent. POST calls are
what are used to introduce new data to the system. This is analogous to
inserting a new row of data into a relational database table.
PUT is similar to POST in that it’s used for making changes, but it’s better
described as updating existing records. It’s possible to also update a non-
existent record, but this depends on how things have been set up on the
server. Finally, DELETE is used to remove something from the server.
Creating an Application with Spring Boot -
Creating JSON-based APIs
It is somewhat common behavior, although not a required standard,
that any updates to the system should return to the person or system
making the request, a copy of the new or deleted entry.

Add the following code to the ApiController class, right below the all()
method: • @PostMapping: Maps HTTP POST calls
to /api/videos onto this method
@PostMapping("/api/videos") • @RequestBody: Spring MVC’s annotation to
signal that the incoming HTTP request body
public Video newVideo(@RequestBody Video newVideo) { should be deserialized via Jackson into
return videoService.create(newVideo); the newVideo argument as a Video record
} • We then delegate the actual handling of this
incoming Video record to our VideoService,
returning back the record after it’s been added
to the system
Creating an Application with Spring Boot -
Creating JSON-based APIs
We already coded this create() operation earlier in this topic, so there’s
no need to go back into it.
Tip
Earlier in the section, we said “curl that endpoint” and saw a chunk of
JSON printed out. curl is a popular command-line tool that lets you
interact with web APIs
With our new addition to our API controller, we can interact with it
from the command line as follows:
$ curl -v -X POST localhost:8080/api/videos -d '{"name": "Learning Spring Boot 3"}' -H 'Content-
type:application/json'
Creating an Application with Spring Boot -
Creating JSON-based APIs
$ curl -v -X POST localhost:8080/api/videos -d '{"name": "Learning Spring Boot 3"}' -H 'Content-
type:application/json'

-v: Asks for curl to produce verbose output,


providing extensive details about the whole * Connected to localhost (::1) port 8080 (#0)
interaction. > POST /api/videos HTTP/1.1
> Host: localhost:8080
-X POST: Signals it to use HTTP POST instead of the
default GET call. > User-Agent: curl/7.64.1
> Accept: */*
localhost:8080/api/video: Provides the URL to direct > Content-type:application/json
the command. > Content-Length: 34
-d '{…}': Provides the data. Since the fields in JSON >
are delimited with double quotes, the entire JSON * upload completely sent off: 34 out of 34 bytes
document is handed to curl using single quotes. < HTTP/1.1 200
-H 'Content-type:application/json': Provides the < Content-Type: application/json
HTTP header that alerts the web app that this is a {"name":"Learning Spring Boot 3"}
JSON-formatted request body.
Creating an Application with Spring Boot -
Creating JSON-based APIs
• The command is shown toward the top * Connected to localhost (::1) port 8080 (#0)
including the HTTP verb, the URL, and the > POST /api/videos HTTP/1.1
headers (User-Agent, Accept, Content- > Host: localhost:8080
type, and Content-Length) > User-Agent: curl/7.64.1
> Accept: */*
• The response is shown toward the bottom > Content-type:application/json
including an HTTP 200 success status code > Content-Length: 34
• The response is denoted as >
application/json * upload completely sent off: 34 out of 34 bytes
• The actual response body contains the < HTTP/1.1 200
< Content-Type: application/json
JSON-formatted new Video entry we {"name":"Learning Spring Boot 3"}
created
Creating an Application with Spring Boot -
Creating JSON-based APIs
We can further verify this by re-pinging the /api/videos endpoint and
looking for our latest addition:
$ curl localhost:8080/api/videos
[
{"name":"Need HELP with your SPRING BOOT 3 App?"},
{"name":"Don't do THIS to your own CODE!"},
{"name":"SECRETS to fix BROKEN CODE!"},
{"name":"Learning Spring Boot 3"}
]
Creating an Application with Spring Boot -
Creating JSON-based APIs
What do we have now? We have a web application with two key facets:
• Template-based version rendered in the browser for humans to read
• JSON-based version consumable by third parties.
Creating an Application with Spring Boot -
Hooking in Node.js to a Spring Boot web app
• So, do we need our web app to use JavaScript?
• It’s only the de facto standard tool found in every web browser on the planet.
• In case you didn’t know it, JavaScript is a completely different world when it
comes to tools and app building. So, how do we cross this vast gulf between
Java and JavaScript developer tooling?
• Node.js. There is a Maven plugin that can bridge this gap for us, known as the Maven
frontend plugin (frontend-maven-plugin).
• This plugin unites Node.js actions with Maven’s lifecycles, allowing us to
properly invoke Node.js at the right time to download packages and
assemble JavaScript code into a bundle.
Creating an Application with Spring Boot -
Hooking in Node.js to a Spring Boot web app
Anything found in src/main/resources/static is automatically picked up
and will be put on the base path of our web application when fully
assembled. This means we simply need to direct our Node.js bundling
tool to drop its final results there.
Start with the frontend-maven-plugin.
If we open up the pom.xml file created by start.spring.io, there should
be an entry about two-thirds of the way down called <plugins>. It
should already have an entry for spring-boot-maven-plugin.
Creating an Application with Spring Boot -
Hooking in Node.js to a Spring Boot web app
• We’ve added the coordinates for the latest version of <plugin>
frontend-maven-plugin (at the time of writing) <groupId>com.github.eirslett</groupId>
• Right now, it has one execution, install-node-and- <artifactId>frontend-maven-plugin</artifactId>
npm. This command will download Node.js and its <version>1.12.1</version>
package manager npm
<executions>
• In the configuration section toward the bottom, it <execution>
specifies the latest long-term support (LTS) version
of Node.js <goals>
<goal>install-node-and-npm</goal>
</goals>
This plugin does its thing during Maven’s generate-resources
</execution>
phase
</executions>
<configuration>
<nodeVersion>v16.14.2</nodeVersion>
</configuration>
</plugin>
Creating an Application with Spring Boot -
Hooking in Node.js to a Spring Boot web app
It should be pointed out that the frontend-maven-plugin actually
downloads and unpacks Node.js, npm, and node package execute (npx)
in our project’s root directory underneath the node folder.
Tip
Node.js and all its tools and modules can be considered intermediate
build artifacts. There’s no need to commit them to version control. So,
be sure to add the node folder as well as the intermediate
node_modules folder to your list of items to not commit (for example,
add node and node_modules to the project’s .gitignore file).
Creating an Application with Spring Boot -
Bundling JavaScript with Node.js
At this point, we have the tooling. But no actual modules.
To start adding modules, we’ll use npm. And the first thing we must do is pick a Node.js
package bundler. There are many to pick from, but let’s pick Parcel by typing the following
command:
% node/npm install --save-dev parcel
This will use the locally installed copy of Node.js and its npm command to create a package.json file.
The –save-dev option signals that this is a development module, and not a package used by our app.
Now that we have a package.json file created for our project, we need to hook it into the frontend-
maven-plugin. To do that, we need to add another <execution> entry as follows:
<execution>
<id>npm install</id>
<goals>
<goal>npm</goal>
</goals>
</execution>
Creating an Application with Spring Boot -
Bundling JavaScript with Node.js
This additional fragment will configure the frontend-maven-plugin to run npm
install, the command that will build our JavaScript bundle.
Now so far, we don’t have much in packages. Just the Parcel build tool. Before
we start adding JavaScript modules, we should probably configure it to build
things properly. Edit the package.json that npm just created as shown here so
that Parcel will assemble an ES6 module for us {

"source": "src/main/javascript/index.js",
"targets": {
"default": {
"distDir": "target/classes/static"
}
},

}
Creating an Application with Spring Boot -
Bundling JavaScript with Node.js
This addition to package.json will cause the following {
to happen: …
"source": "src/main/javascript/index.js",
• Source: Points at a yet-to-be-written index.js "targets": {
JavaScript file. This will be our entry point for our "default": {
JavaScript app. As far as Parcel is concerned, it "distDir": "target/classes/static"
doesn’t really matter where this file is. Since we’re }
using a Maven-based project, we can use },
src/main/javascript. …
• As for the target destination, we can configure the }
default target with a distDir setting of
target/classes/static. Parcel supports building
multiple targets such as different browsers, but we
don’t need that. A single, default destination will do.
By putting the results in the target folder, anytime we
run a Maven clean cycle, this compiled bundle will be
cleaned out.
Creating an Application with Spring Boot -
Bundling JavaScript with Node.js
While npm is Node.js' tool for downloading and installing packages, npx is
Node.js’ tool for running commands. By adding another <execution> entry
to the frontend-maven-plugin, we can have it run Parcel’s build command:
<execution>
<id>npx run</id> This extra step runs npx parcel build after the npm
install command is run, ensuring Parcel does its build step.
<goals>
<goal>npx</goal>
</goals>
<phase>generate-resources</phase>
<configuration>
<arguments>parcel build</arguments>
</configuration>
</execution>
Creating an Application with Spring Boot -
Creating a React.js app
There are so many ways to build JavaScript apps and they all have their own features
and benefits. For illustrative purposes, we’ll use React.js, Facebook’s toolkit for app
building.
Type the following command:
node/npm install --save react react-dom

The preceding command will update package.json with the react and react-dom modules.
Now, we can start writing some JavaScript!
Create index.js inside src/main/javascript as follows:
import ReactDOM from "react-dom"
import { App } from "./App"
const app = document.getElementById("app")
ReactDOM.render(<App />, app)
Creating an Application with Spring Boot -
Creating a React.js app
import ReactDOM from "react-dom"
import { App } from "./App"
const app = document.getElementById("app")
ReactDOM.render(<App />, app)

• The first line imports ReactDOM, a key module needed to launch React
• The second line imports the custom UI we’ll build further
• The third line uses vanilla JavaScript to find the element on the web page with id="app" where we can “hang”
our app
• The fourth line actually renders the <App/> component in our soon-to-be-coded app using ReactDOM
Creating an Application with Spring Boot -
Creating a React.js app
React operates with a top-down perspective. You render a top-level component, and then that component, in
turn, renders components nested further down.
It also uses a shadow document object model (DOM) where we don’t specify the actual nodes to render, but
instead use virtual nodes. React computes the changes from whatever the current state is and generates the
changes.
To continue building this application, we need to create App.js in src/main/javascript as follows:

import React from 'react' •We import React to build components.


import ListOfVideos from './ListOfVideos' •The local bits of JavaScript that we will write after this
import NewVideo from "./NewVideo" includes a list of videos (ListOfVideos.js) and from for
export function App() { creating new videos (NewVideo.js).
return (
From here, we have a single function, App(), exported
<div>
publicly. Because it returns some HTML-styled elements,
<ListOfVideos/>
this signals to Parcel that we’re working with JavaScript
<NewVideo/>
XML (JSX), which contains some more React components
</div>
to render.
)
}
Creating an Application with Spring Boot -
Creating a React.js app
import React from "react" React and JSX
class ListOfVideos extends React.Component { React introduces a concept called JSX, where we can combine unique HTML elements with
constructor(props) { JavaScript code. In the past, we were told that mixing HTML and JavaScript was bad. But in
super(props) truth, when laying out a UI that ties together functions, JSX provides an excellent blend.
this.state = {data: []} Instead of using tricky functions to layer JavaScript on top of HTML, React works by
} allowing us to build up tiny bits of HTML combined cohesively with functions that support
async componentDidMount() { their operation. Combined with its internal state management, React has become quite
popular among many for building web apps.
let json = await fetch("/api/videos").json()
this.setState({data: json}) The first thing to replicate from our earlier template is listing all the videos from the
} backend. To generate the same HTML unordered list in React, create ListOfVideos.js in
render() { src/main/javascript:
return ( •This code uses ES6 classes that extend React.Component.
<ul> •Its constructor creates a state field to maintain an internal state.
{this.state.data.map(item => •componentDidMount() is the function called by React right after this component is inserted into
<li> the DOM and rendered. It uses vanilla JavaScript’s fetch() function to retrieve data from the JSON
{item.name} API we created earlier in this topic. Because that function returns a promise, we can use the ES6
</li>)} await function to wait for results and then update the internal state using React.Component’s
</ul> setState(). For this method to work with the rest of things properly, we must mark it async. It’s also
) important to understand that anytime setState() is invoked, React will re-render the component.
} •The sizzle is in the render() method where we actually lay out HTML elements (or more React
} components). This code uses the internal state and maps over the array of data, converting each
export default ListOfVideos piece of JSON into an HTML line item. No elements? No line items!
Creating an Application with Spring Boot -
Creating a React.js app
import React from "react" In the preceding chunk of code, we mentioned both properties and state. Properties
class NewVideo extends React.Component {
constructor(props) {
typically comprise information injected into a React component from the outside.
super(props) State is maintained within. It’s possible to initialize the state from properties, or as
this.state = {name: ""} shown in this code, the component itself can fetch the data stored in the state.
this.handleChange = this.handleChange.bind(this);

}
this.handleSubmit = this.handleSubmit.bind(this);
What’s important to clarify, is that properties are typically considered immutable
handleChange(event) { within the React component that has them injected. State is meant to evolve and
this.setState({name: event.target.value}) change, in turn driving our rendered elements.
}
async handleSubmit(event) {
event.preventDefault()
Our React app wouldn’t be much if we couldn’t create new entries. So, let’s create a
await fetch("/api/videos", { new component that duplicates the HTML form we created earlier in this topic in the
method: "POST", Changing the data through HTML forms section!
headers: {
"Content-type": Create NewVideo.js as shown here in src/main/javascript
"application/json"
},
body: JSON.stringify({name: this.state.name})
This React component has some of the same bits as the other one, such as the import statement as
}).then(response => well as a JavaScript class extending React.Component. But it contains some different parts, which
window.location.href = "/react")
} are as follows:
render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="text"
value={this.state.name}
onChange={this.handleChange}/>
<button type="submit">Submit</button>
</form>
)
}
}
export default NewVideo
References
• https://github.com/PacktPublishing/Learning-Spring-Boot-3.0-Third-
Edition

You might also like