@ResponseBodyAdvice & @RequestBodyAdivce invalid

Background

Recently, projects need to have the ability to provide services to the outside world, but considering data security issues, the interface must be encrypted and decrypted; there are many solutions to implement encryption and decryption, such as filters, interceptors, inheriting RequestResponseBodyMethodProcessor, etc., but I am learning about it recently @ResponseBodyAdvice @RequestBodyAdvice These two annotations are intended to be used in practice and are intended to be used to implement encryption and decryption functions.
However, after configuration, requests cannot enter these two annotated classes. After groping for a day, @RestController and @ResponseBody were added, and it was confirmed that they had been scanned into the container for management, but it just couldn’t take effect.

Reason

Later, I discovered that the project previously had a unified package for returning results from all controllers, which was implemented by inheriting the RequestResponseBodyMethodProcessor class;
Just now, @ResponseBodyAdvice and @RequestBodyAdvice have been unable to take effect, so I performed encryption actions in RequestResponseBodyMethodProcessor. Later, I inadvertently commented out the code imported by this class in WebMvcConfigurer. I was surprised to find that @ResponseBodyAdvice @RequestBodyAdvice The annotation takes effect.
Therefore, the initial positioning of @ResponseBodyAdvice @RequestBodyAdvice and RequestResponseBodyMethodProcessor will conflict and not take effect.

Solution

The logic in RequestResponseBodyMethodProcessor is extracted into @ResponseBodyAdvice. Originally, this also enhanced the returned results, so it is very reasonable to put it here.
At the same time, the encryption logic is expanded.

Core code

@ControllerAdvice
public class ResponseProcessor implements ResponseBodyAdvice<Object> {
    private ObjectMapper om = new ObjectMapper();
    @Autowired
    EncryptProperties encryptProperties;

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return methodParameter.hasMethodAnnotation(Encrypt.class);
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        byte[] keyBytes = encryptProperties.getKey().getBytes();
        try {
            if(!methodParameter.hasMethodAnnotation(NoResponseWrapperAnnotation.class)){
                body = new ResponseWrapper<>(body);
            }
            body = AESUtils.encrypt(JSONObject.toJSONString(body),encryptProperties.getKey());

        } catch (Exception e) {
            e.printStackTrace();
        }
        return body;
    }
}
```


```java
@ControllerAdvice
public class RequestProcessor extends RequestBodyAdviceAdapter {
    @Autowired
    private EncryptProperties encryptProperties;
    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return methodParameter.hasMethodAnnotation(Decrypt.class) || methodParameter.hasParameterAnnotation(Decrypt.class);
    }

    @Override
    public HttpInputMessage beforeBodyRead(final HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
        byte[] body = new byte[inputMessage.getBody().available()];
        inputMessage.getBody().read(body);
        try {
            String decrypt = AESUtils.decrypt(new String(body), encryptProperties.getKey());
            final ByteArrayInputStream bais = new ByteArrayInputStream(decrypt.getBytes());
            return new HttpInputMessage() {
                @Override
                public InputStream getBody() throws IOException {
                    return bais;
                }

                @Override
                public HttpHeaders getHeaders() {
                    return inputMessage.getHeaders();
                }
            };
        } catch (Exception e) {
            e.printStackTrace();
        }
        return super.beforeBodyRead(inputMessage, parameter, targetType, converterType);
    }
}
```

```java
public class AESUtils {
    private static final String KEY_ALGORITHM = "AES";
    private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";//Default encryption algorithm

    public static String getKey(int len){
        if(len % 16 != 0){
            System.out.println("The length must be an integer multiple of 16");
            return null;
        }

        char[] chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
        char[] uuid = new char[len];

        if (len > 0) {
            for (int i = 0; i < len; i + + ) {
                int x = (int) (Math.random() * (len - 0 + 1) + 0);
                uuid[i] = chars[x % chars.length];
            }
        }

        return new String(uuid);
    }


    public static String byteToHexString(byte[] bytes){
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < bytes.length; i + + ) {
            String strHex=Integer.toHexString(bytes[i]);
            if(strHex.length() > 3){
                sb.append(strHex.substring(6));
            } else {
                if(strHex.length() < 2){
                    sb.append("0" + strHex);
                } else {
                    sb.append(strHex);
                }
            }
        }
        return sb.toString();
    }

    /**
     * AES encryption operation
     *
     * @param content content to be encrypted
     * @param key encryption password
     * @return Returns the encrypted data after Base64 transcoding
     */
    public static String encrypt(String content, String key) {
        try {
            Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);//Create cipher

            byte[] byteContent = content.getBytes("utf-8");

            cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(key));//Initialize the cipher to encryption mode

            byte[] result = cipher.doFinal(byteContent);//Encryption

            return org.apache.commons.codec.binary.Base64.encodeBase64String(result);//Return through Base64 transcoding
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    /**
     * AES decryption operation
     *
     * @param content
     * @param key
     * @return
     */
    public static String decrypt(String content, String key) {

        try {
            //instantiation
            Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);

            //Initialize with key and set to decryption mode
            cipher.init(Cipher.DECRYPT_MODE, getSecretKey(key));

            //Execute the operation
            byte[] result = cipher.doFinal(org.apache.commons.codec.binary.Base64.decodeBase64(content));

            return new String(result, "utf-8");
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    private static SecretKeySpec getSecretKey(final String key) throws UnsupportedEncodingException {
        //Return the KeyGenerator object that generates the specified algorithm key generator
// KeyGenerator kg = null;

        // kg = KeyGenerator.getInstance(KEY_ALGORITHM);
//
// //AES requires a key length of 128
// kg.init(128, new SecureRandom(key.getBytes()));
//
// //Generate a key
// SecretKey secretKey = kg.generateKey();

        return new SecretKeySpec(Arrays.copyOf(key.getBytes("utf-8"), 16), KEY_ALGORITHM);//Convert to AES private key

    }
}
```