DEV Community

Masui Masanori
Masui Masanori

Posted on

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

Top comments (0)