Backend Development 12 min read

Implementing Request and Response Encryption in Spring MVC with ControllerAdvice

This article presents a step‑by‑step guide on securing Spring MVC interfaces by encrypting and decrypting both GET and POST requests using symmetric AES, custom ControllerAdvice components, and Jackson configuration to ensure consistent JSON serialization across mobile, H5, and backend services.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Implementing Request and Response Encryption in Spring MVC with ControllerAdvice

The author introduces an interface security requirement that mandates minimal impact on existing business logic, symmetric AES encryption for Android, iOS, and H5 clients, separate keys for H5, and support for both GET and POST endpoints.

Data models are defined using Lombok: a @Data public class User { Integer id; String name; UserType userType = UserType.COMMON; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime registerTime; } and an enum @Getter @JsonFormat(shape = JsonFormat.Shape.OBJECT) public enum UserType { VIP("VIP用户"), COMMON("普通用户"); private String code; private String type; UserType(String type){ this.code = name(); this.type = type; } } .

A simple controller demonstrates a user‑list endpoint: @RestController @RequestMapping({"/user","/secret/user"}) public class UserController { @RequestMapping("/list") ResponseEntity > listUser(){ /* create sample user and return */ } } .

For request decryption, @ControllerAdvice @Order(Ordered.HIGHEST_PRECEDENCE) @Slf4j public class SecretRequestAdvice extends RequestBodyAdviceAdapter { @Override public boolean supports(...) { return true; } @Override public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, ...) throws IOException { String httpBody; if (Boolean.TRUE.equals(SecretFilter.secretThreadLocal.get())) { httpBody = decryptBody(inputMessage); } else { httpBody = StreamUtils.copyToString(inputMessage.getBody(), Charset.defaultCharset()); } return new SecretHttpMessage(new ByteArrayInputStream(httpBody.getBytes()), inputMessage.getHeaders()); } private String decryptBody(HttpInputMessage inputMessage) throws IOException { /* signature verification and AES decryption */ } } .

Response encryption is handled by @ControllerAdvice public class SecretResponseAdvice implements ResponseBodyAdvice { @Autowired private ObjectMapper objectMapper; @Override public boolean supports(MethodParameter methodParameter, Class aClass) { return true; } @Override public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest request, ServerHttpResponse response) { Boolean respSecret = SecretFilter.secretThreadLocal.get(); String secretKey = SecretFilter.clientPrivateKeyThreadLocal.get(); SecretFilter.secretThreadLocal.remove(); SecretFilter.clientPrivateKeyThreadLocal.remove(); if (respSecret != null && respSecret && o instanceof ResponseBasic) { try { String dataStr = objectMapper.writeValueAsString(o); String data = EncryptUtils.aesEncrypt(dataStr, secretKey); long timestamp = System.currentTimeMillis() / 1000; int salt = EncryptUtils.genSalt(); String newSignature = Md5Utils.genSignature(timestamp + "" + salt + "" + data + secretKey); return SecretResponseBasic.success(data, timestamp, salt, newSignature); } catch (Exception e) { /* log and return error */ } } return o; } } .

Testing reveals serialization mismatches for the enum and LocalDateTime fields; the author switches from FastJSON to Jackson and configures custom serializers: ObjectMapper mapper = new Jackson2ObjectMapperBuilder() .serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))) .deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))) .build(); . After replacing JSON.toJSONString(o) with mapper.writeValueAsString(o) , the encrypted response matches the original unencrypted format.

The article concludes with notes on handling GET request encryption, cross‑origin issues, and invites further discussion.

JavaJSONREST APIEncryptionSpring MVCAESControllerAdvice
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

0 followers
Reader feedback

How this landed with the community

login 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.