DEV Community

Masui Masanori
Masui Masanori

Posted on

1

Try Spring Boot

Intro

In this time, I will create a web application with Spring Boot.

Adding a Thymeleaf page

First, I will add pages to access web APIs.

To use Thymeleaf, I add "org.springframework.boot:spring-boot-starter-thymeleaf" into build.gradle.

build.gradle

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.5'
    id 'io.spring.dependency-management' version '1.1.3'
}
group = 'jp.masanori'
version = '0.0.1-SNAPSHOT'
java {
    sourceCompatibility = '17'
}
repositories {
    mavenCentral()
}
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
    useJUnitPlatform()
}
Enter fullscreen mode Exit fullscreen mode

I can put an HTML file as Thymeleaf template file into src/main/resources/templates.

index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <title>Hello</title>
        <meta charset="utf-8">
    </head>
    <body>
        <h1>Hello world!</h1>
        <p class="template_value" th:text="|Hello ${name}!!!|" />
        <button onclick="IndexPage.getKey()">Get key</button>
        <script src="/js/index.page.js"></script>
        <script>IndexPage.init("Hello world!");</script>
    </body>
</html>
Enter fullscreen mode Exit fullscreen mode

The controller class should has a "@Controller" anotation.

PageController.java

package jp.masanori.springbootsample;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class PageController {

    @GetMapping("/")
    public String hello(@RequestParam(value = "name", defaultValue = "World") String name, Model model) {
      model.addAttribute("name", name);
      return "index";
    }
}
Enter fullscreen mode Exit fullscreen mode

I put JavaScript files and CSS files into src/main/resources/static as static files.

CORS

I will try getting string data from another Spring Boot application(localhost:8081).

[localhost:8080] index.page.ts

window.IndexPage = {
    init(message: string) {
        console.log(message);

    },
    getKey() {
        fetch("http://localhost:8081/key", {
            mode: "cors",
            "method": "GET"
        }).then(res => res.text())
        .then(res => console.log(res))
        .catch(err => console.error(err));
    }
}
Enter fullscreen mode Exit fullscreen mode

[localhost:8081] ApiController.java

package jp.masanori.corssample.controllers;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ApiController {
    private static final String ALGORITHM = "HmacSHA256";

    @GetMapping("/key")
    public String getKey() {
        String key = generateKey();
        return key;
    }

    private String generateKey() {
        try {
            DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss SSS");
            String currentTime = LocalDateTime.now().format(dateFormat);
            Mac sha256 = Mac.getInstance(ALGORITHM);

            sha256.init(new SecretKeySpec(currentTime.getBytes("UTF-8"), ALGORITHM));
            var base64 = Base64.getEncoder();
            return base64.encodeToString(sha256.doFinal(currentTime.getBytes("UTF-8")));
        } catch (NoSuchAlgorithmException ex) {
            System.out.println(ex.getMessage());
        } catch (InvalidKeyException ex) {
            System.out.println(ex.getMessage());
        } catch (UnsupportedEncodingException ex) {
            System.out.println(ex.getMessage());
        }
        return "";
    }
}
Enter fullscreen mode Exit fullscreen mode

But my request is blocked by CORS error.

Access to fetch at 'http://localhost:8081/key' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Enter fullscreen mode Exit fullscreen mode

To resolve the error, I add configurations of CORS into the Spring Boot projects.

[localhost:8081] CorsConfigurer.java

package jp.masanori.corssample.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfigurer implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/*")
                .allowedOrigins("http://localhost:8080", "http://localhost:8081")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTION")
                .allowedHeaders("*")
                // To set custom headers
                .exposedHeaders("Sample-Key")
                .allowCredentials(false).maxAge(3600);
    }
}
Enter fullscreen mode Exit fullscreen mode

Getting parameters

I can get data what are sent from clients by annotations.

URL params

[localhost:8081] ApiController.java

...
    @GetMapping("/params")
    public String getUrlParams(@RequestParam(value = "name") String name,
            @RequestParam(value = "message") String message) {
        return String.format("Name: %s Message: %s", name, message);
    }
...
Enter fullscreen mode Exit fullscreen mode

Request URL

http://localhost:8081/params?name=masa&message=hello+world
Enter fullscreen mode Exit fullscreen mode

Request Body

[localhost:8080] index.page.ts

...
    sendMessage() {
        const message = {
            name: "masa",
            message: "hello world"
        };
        fetch("http://localhost:8081/params", {
            mode: "cors",
            method: "POST",
            headers: {
                "Content-Type": "application/json",
            },
            body: JSON.stringify(message),
        }).then(res => res.text())
            .then(res => {
                console.log(res);

            }).catch(err => console.error(err));
    }
}
Enter fullscreen mode Exit fullscreen mode

[localhost:8081] ApiController.java

...
    @PostMapping("/params")
    public String getBodyParams(@RequestBody SampleMessage message) {
        return String.format("Name: %s Message: %s", message.getName(), message.getMessage());
    }
...
Enter fullscreen mode Exit fullscreen mode

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more