SpringBoot API Encryption & Decryption Made Easy with a Custom Starter

This article walks through building a reusable SpringBoot starter that automatically encrypts response data and decrypts request payloads using hutool‑crypto, request/response body advice, and a reusable request‑stream wrapper, eliminating repetitive security code.

Architect's Guide
Architect's Guide
Architect's Guide
SpringBoot API Encryption & Decryption Made Easy with a Custom Starter

1. Introduction

In typical Java micro‑service development, data exchanged between services often needs confidentiality. The article proposes a reusable SpringBoot starter that automatically encrypts outgoing responses and decrypts incoming requests, eliminating repetitive encryption code.

2. Prerequisites

2.1 hutool‑crypto

hutool‑crypto supplies symmetric, asymmetric and digest algorithms; the guide uses its AES implementation.

2.2 Single‑read request stream problem

HttpServletRequest’s input stream can be read only once. If a filter or AOP reads it for validation, subsequent reads return empty.

2.2.1 Solution

Extend HttpServletRequestWrapper, copy the original stream into a byte array, and override getInputStream() and getReader() to return a new stream each time. A filter replaces the original request with this wrapper so the stream can be read repeatedly.

public class InputStreamHttpServletRequestWrapper extends HttpServletRequestWrapper {
    private ByteArrayOutputStream cachedBytes;
    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (cachedBytes == null) {
            cacheInputStream();
        }
        return new CachedServletInputStream(cachedBytes.toByteArray());
    }
    // other methods omitted for brevity
}

2.3 SpringBoot validation

Using SpringBoot‑validation, annotate DTO fields with @NotBlank, @NotNull, @Range, etc. The controller method must be marked with @Validated or @Valid. A utility class (ValidationUtils) wraps the Validator API and throws a custom ParamException when constraints fail.

2.4 Custom starter creation

Create functional code and factory classes.

Declare an auto‑configuration class and list it in spring.factories under the key

org.springframework.boot.autoconfigure.EnableAutoConfiguration

.

2.5 RequestBodyAdvice and ResponseBodyAdvice

RequestBodyAdvice

intercepts the request body, decrypts the JSON payload, validates the timestamp, and converts it to the target DTO. ResponseBodyAdvice encrypts the response data, injects a timestamp, and wraps the result in a unified Result object.

3. Function Overview

When a controller method is annotated with @EncryptionAnnotation, the response body is encrypted; when annotated with @DecryptionAnnotation, the incoming JSON is decrypted before binding.

4. Implementation Details

Encryption uses AES with CTS mode and PKCS5Padding, configured via crypto.properties. A common parent class RequestBase carries a timestamp; requests older than 60 seconds are rejected.

5. Code Structure

Project layout: crypto-common – shared utilities and constants. crypto-spring-boot-starter – the starter, auto‑configuration, and advice classes. crypto-test – sample application with Teacher DTO, configuration, and a test controller.

Key configuration files:

# crypto.properties
crypto.mode=CTS
crypto.padding=PKCS5Padding
crypto.key=testkey123456789
crypto.iv=testiv1234567890
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    xyz.hlh.crypto.config.AppConfig

Auto‑configuration creates an AES bean using the properties above.

Request decryption advice extracts the encrypted field text from a RequestData wrapper, decrypts it with AESUtil.decrypt, validates the timestamp, and returns the real DTO.

Response encryption advice converts the response data to JSON, checks that the payload length is at least 16 characters, encrypts it with AESUtil.encryptHex, and builds a Result object.

Sample DTO:

@Data
public class Teacher extends RequestBase implements Serializable {
    @NotBlank(message="姓名不能为空")
    private String name;
    @NotNull(message="年龄不能为空")
    @Range(min=0, max=150, message="年龄不合法")
    private Integer age;
    @NotNull(message="生日不能为空")
    private Date birthday;
}

Sample controller demonstrates three endpoints: plain return, encrypted return, and encrypted request handling.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

SpringBootEncryptionResponseBodyAdviceRequestBodyAdviceCustom Starterhutool-crypto
Architect's Guide
Written by

Architect's Guide

Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.