springboot 自定义消息处理

css 复制代码
package com.my.config;

import cn.hutool.core.io.FileUtil;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.google.gson.Gson;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonInputMessage;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.util.TypeUtils;

import java.io.*;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 自定义消息处理
 */
public class CryptMessageConvertPro extends MappingJackson2HttpMessageConverter {

    private List<MediaType> supportedMediaTypesNew = new ArrayList<>();

    private final static String APPLICATION_CRYPT = "application/crypt;charset=UTF-8";

    private static final Map<String, JsonEncoding> ENCODINGS = new HashMap(JsonEncoding.values().length + 1);

    private static  CryptMessage cryptMessage;

    static {
        JsonEncoding[] var0 = JsonEncoding.values();
        int var1 = var0.length;

        for(int var2 = 0; var2 < var1; ++var2) {
            JsonEncoding encoding = var0[var2];
            ENCODINGS.put(encoding.getJavaName(), encoding);
        }

        ENCODINGS.put("US-ASCII", JsonEncoding.UTF8);

        /**
         * 消息处理工具类,即对数据加解密操作
         */
        cryptMessage = new MessageCryptUtils.Base64Message();//base64加解密
//        cryptMessage = new MessageCryptUtils.AESMessage("1qazxsw23edcvfr4");//aes加解密
//        cryptMessage = new MessageCryptUtils.RSAMessage(FileUtil.readUtf8String("F:\\primary.pem"),FileUtil.readUtf8String("F:\\public.pem"));//rsa加解密
    }



    /**
     * 此处加入自定义的 MediaType
     * @return
     */
    @Override
    public List<MediaType> getSupportedMediaTypes() {
        if (supportedMediaTypesNew.isEmpty()) {
            supportedMediaTypesNew.addAll(super.getSupportedMediaTypes());
            supportedMediaTypesNew.add(new MediaType("application","crypt", StandardCharsets.UTF_8));
        }
        return Collections.unmodifiableList(this.supportedMediaTypesNew);
    }


    @Override
    protected void writeInternal(Object o, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {

        MediaType contentType = outputMessage.getHeaders().getContentType();
        JsonEncoding encoding = this.getJsonEncoding(contentType);
        OutputStream body = outputMessage.getBody();

        Object object  = o;

        /** ========此处做加密处理========== **/
        if (APPLICATION_CRYPT.startsWith(Objects.requireNonNull(outputMessage.getHeaders().getContentType()).toString())) {
            try {
                String jsonString = this.objectMapper.writeValueAsString(object);
                object = cryptMessage.encodeCrypt(jsonString);
            } catch (Exception e) {
                throw new RuntimeException("响应结果加密异常");
            }
        }
        /** =======此处做加密处理========== **/

        JsonGenerator generator = this.objectMapper.getFactory().createGenerator(body, encoding);

        try {
            this.writePrefix(generator, object);
            Object value = object;
            Class<?> serializationView = null;
            FilterProvider filters = null;
            JavaType javaType = null;
            if (object instanceof MappingJacksonValue) {
                MappingJacksonValue container = (MappingJacksonValue)object;
                value = container.getValue();
                serializationView = container.getSerializationView();
                filters = container.getFilters();
            }

            if (type != null && TypeUtils.isAssignable(type, value.getClass())) {
                javaType = this.getJavaType(type, (Class)null);
            }

            ObjectWriter objectWriter = serializationView != null ? this.objectMapper.writerWithView(serializationView) : this.objectMapper.writer();
            if (filters != null) {
                objectWriter = objectWriter.with(filters);
            }

            if (javaType != null && javaType.isContainerType()) {
                objectWriter = objectWriter.forType(javaType);
            }

            SerializationConfig config = objectWriter.getConfig();
            if (contentType != null && contentType.isCompatibleWith(MediaType.TEXT_EVENT_STREAM) && config.isEnabled(SerializationFeature.INDENT_OUTPUT)) {
                objectWriter = objectWriter.with(new DefaultPrettyPrinter());
            }

            objectWriter.writeValue(generator, value);
            this.writeSuffix(generator, object);
            generator.flush();
        } catch (InvalidDefinitionException var13) {
            InvalidDefinitionException ex = var13;
            throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);
        } catch (JsonProcessingException var14) {
            JsonProcessingException ex = var14;
            throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getOriginalMessage(), ex);
        }
    }


    @Override
    protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        JavaType javaType = this.getJavaType(clazz, (Class)null);
        return this.readJavaType(javaType, inputMessage);
    }

    @Override
    public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        JavaType javaType = this.getJavaType(type, contextClass);
        return this.readJavaType(javaType, inputMessage);
    }

    private Object readJavaType(JavaType javaType, HttpInputMessage inputMessage) throws IOException {
        MediaType contentType = inputMessage.getHeaders().getContentType();
        Charset charset = contentType != null && contentType.getCharset() != null ? contentType.getCharset() : StandardCharsets.UTF_8;
        boolean isUnicode = ENCODINGS.containsKey(charset.name());

        try {
            InputStream body = inputMessage.getBody();

            /**=======此处做解密处理==========**/
            if (contentType != null && contentType.toString().equals(APPLICATION_CRYPT)) {//解密加密数据
                try {
                    byte[] bytes = new byte[body.available()];
                    body.read(bytes);
                    String res = cryptMessage.decodeCrypt(bytes);
                    Object result = this.objectMapper.readValue(res.getBytes(StandardCharsets.UTF_8), javaType);
                    return result;
                } catch (Exception e) {
                    throw new RuntimeException("参数解密失败");
                }
            }
            /**==========此处做解密处理=======**/

            if (inputMessage instanceof MappingJacksonInputMessage) {
                Class<?> deserializationView = ((MappingJacksonInputMessage)inputMessage).getDeserializationView();
                if (deserializationView != null) {
                    ObjectReader objectReader = this.objectMapper.readerWithView(deserializationView).forType(javaType);
                    if (isUnicode) {
                        return objectReader.readValue(body);
                    }

                    Reader reader = new InputStreamReader(body, charset);
                    return objectReader.readValue(reader);
                }
            }

            if (isUnicode) {
                return this.objectMapper.readValue(body, javaType);
            } else {
                Reader reader = new InputStreamReader(body, charset);
                return this.objectMapper.readValue(reader, javaType);
            }
        } catch (InvalidDefinitionException var9) {
            InvalidDefinitionException ex = var9;
            throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);
        } catch (JsonProcessingException var10) {
            JsonProcessingException ex = var10;
            throw new HttpMessageNotReadableException("JSON parse error: " + ex.getOriginalMessage(), ex, inputMessage);
        }
    }



}

spring的配置

css 复制代码
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
public class WebConfig implements WebMvcConfigurer {

 @Override
 public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
     // 设置优先级为 0,优先使用
     converters.set(1, new CryptMessageConvertPro());
 }
}

加密工具

css 复制代码
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
public class WebConfig implements WebMvcConfigurer {

 @Override
 public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
     // 设置优先级为 0,优先使用
     converters.set(1, new CryptMessageConvertPro());
 }
}

用法

css 复制代码
    @RequestMapping(method = RequestMethod.POST,value = "/test2",produces = "application/crypt")
    @ResponseBody
    public CryptResult test2(@RequestBody Map<String,Object> param, HttpServletRequest request) throws InterruptedException {
        String string = UUID.randomUUID().toString();
        param.put("uuid", string);
        System.out.println(string);

        return CryptResult.success(param);
    }
相关推荐
信码由缰9 小时前
Spring Boot 面试问题
spring boot·后端·面试
梵得儿SHI9 小时前
(第十篇)Spring AI 核心技术攻坚全梳理:企业级能力矩阵 + 四大技术栈攻坚 + 性能优化 Checklist + 实战项目预告
java·人工智能·spring·rag·企业级ai应用·springai技术体系·多模态和安全防护
一路向北⁢9 小时前
Spring Boot 3 整合 SSE (Server-Sent Events) 企业级最佳实践(三)
java·spring boot·后端·sse
qq_297574679 小时前
SpringBoot项目长时间未访问,Tomcat临时文件夹被删除?解决方案来了
spring boot·后端·tomcat
摇滚侠9 小时前
macbook shell 客户端推荐 Electerm macbook 版本下载链接
java·开发语言
一个有梦有戏的人9 小时前
Python3基础:函数基础,解锁模块化编程新技能
后端·python
程序员布吉岛9 小时前
Java 后端定时任务怎么选:@Scheduled、Quartz 还是 XXL-Job?(对比 + 避坑 + 选型)
java·开发语言
是阿楷啊9 小时前
Java大厂面试场景:音视频场景中的Spring Boot与微服务实战
spring boot·redis·spring cloud·微服务·grafana·prometheus·java面试
知无不研9 小时前
lambda表达式的原理和由来
java·开发语言·c++·lambda表达式