springboot 拦截器 统一处理head参数工具类

/**
 * 拦截器配置
 */
@Configuration
public class WebHeadFilter {

    @Bean
    public FilterRegistrationBean modifyParametersFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new MyHeadFilter());
        registration.addUrlPatterns("/*");              // 拦截路径
        registration.setName("headParametersFilter"); // 拦截器名称
        registration.setOrder(1);                       // 顺序
        return registration;
    }

    /**
     * 自定义拦截器
     */
    class MyHeadFilter extends OncePerRequestFilter {
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            // tenantId信息处理
            HeadRequestWrapper headRequestWrapper = new HeadRequestWrapper(request);
            if (StringUtils.isBlank(headRequestWrapper.getHeader("tenantId"))) {
                headRequestWrapper.addHead("tenantId", DEFAULT_TENANT_ID);
            }
            TenantInfoUtil.set(headRequestWrapper.getHeader("tenantId"));
            // finish
            filterChain.doFilter(headRequestWrapper, response);
        }
    }

    /**
     * 修改head信息
     */
    class HeadRequestWrapper extends HttpServletRequestWrapper {
        private Map<String, String> headers;

        HeadRequestWrapper(HttpServletRequest request) {
            super(request);
            this.headers = new HashMap<>();
        }

        @Override
        public String getHeader(String name) {
            String headervalue = super.getHeader(name);
            if (headers.containsKey(name)) {
                headervalue = headers.get(name);
            }
            return headervalue;
        }

        @Override
        public Enumeration<String> getHeaderNames() {
            List<String> values = Collections.list(super.getHeaderNames());
            for (String value : headers.keySet()) {
                values.add(value);
            }
            return Collections.enumeration(values);
        }

        @Override
        public Enumeration<String> getHeaders(String name) {
            List<String> values = Collections.list(super.getHeaders(name));
            if (headers.containsKey(name)) {
                values = Arrays.asList(headers.get(name));
            }
            return Collections.enumeration(values);
        }

        public void addHead(String name, String value) {
            this.headers.put(name, value);
        }
    }

<think>好的,我需要为SpringBoot项目设计一个通用的返回类,使得所有接口的返回结构都保持一致。根据提供的JSON样例,返回报文包含HEAD和BODY两部分,其中HEAD有SYSTEMCODE和SENDTIME,BODY包含respond_code、respond_des以及REQINFO等可能变化的键值对。 首先,考虑创建一个通用的响应类,可能命名为ApiResponse。这个类应该包含HEAD和BODY两个部分。HEAD部分的结构是固定的,包含SYSTEMCODE和SENDTIME,可以单独作为一个内部类或者独立的类。BODY部分的结构比较灵活,不同接口返回的数据不同,但respond_code和respond_des是必须的,而REQINFO和其他动态字段可能需要用Map或自定义对象来容纳。 接下来,我需要确定如何构造BODY部分。因为BODY中的键值对可能变化,除了固定的respond_code和respond_des,其他字段可以使用一个Map来存储动态的内容。例如,REQINFO可以作为一个嵌套的Map,或者使用一个特定的对象。但为了灵活性,可能使用Map<String, Object>来存储额外的键值对,这样不同的接口可以添不同的字段。然后,考虑如何构建HEAD部分。SYSTEMCODE通常是固定的,比如"ETONG",而SENDTIME应该是当前时间戳。这部分可以在创建ApiResponse时自动生成,不需要每次手动设置。 在Spring Boot中,通常使用@RestControllerAdvice或拦截器统一处理响应结构。但这里可能更关注如何定义这个通用的类结构。需要确保生成的JSON结构与示例一致,包括嵌套层次和字段名称。 可能的实现步骤: 1.创建ApiResponse类,包含head和body两个属性。 2.创建Head类,包含systemCode和sendTime字段,使用@JsonProperty("SYSTEMCODE")等注解来匹配JSON键名。3. 创建Body类,包含respondCode、respondDes,以及一个Map<String, Object>来存放其他动态字段,如reqInfo和其他可能的键值对。4. 提供静态工厂方法或Builder模式来方便构造ApiResponse实例,特别是自动生成HEAD部分的时间戳。 5.确保使用Jackson库的注解(如@JsonInclude)来处理空值的序列化问题,避免出现不必要的null字段。 例如,Body类可能需要这样的结构: public class Body{ private Stringrespond_code;private String respond_des; privateMap<String, Object> reqInfo =new HashMap<>();// 其他动态字段可以通过Map存放//或者使用单独的字段,但这样不够灵活 } 但根据示例中的REQINFO是BODY下的一个嵌套对象,可能需要将REQINFO作为Map中的一个键,或者作为Body类的一个属性。如果REQINFO是动态的,可能更灵活的方式是用一个Map来存储所有额外的字段,例如: public classBody { privateString respond_code;private String respond_des;private Map<String,Object> REQINFO = new HashMap<>(); //其他动态字段可以添到这个Map中} 但这样可能不够,因为有些接口可能在BODY中添其他键,而不仅仅是REQINFO。比如,BODY可能包含其他键如data、list等。因此,或许应该让Body类包含一个通用的Map来存储除respond_code和respond_des之外的所有字段,或者使用一个单独的字段如additionalParams,但这样可能不符合示例结构。 或者,可以将Body设计为包含固定的respond_code和respond_des,以及一个Map<String, Object>来存放其他所有动态字段,包括REQINFO。例如: public class Body{ private Stringrespond_code;private String respond_des; privateMap<String, Object> dynamicFields =new HashMap<>();// getters andsetters }然后在生成JSON时,dynamicFields中的键值对会被平铺到BODY中。但这样可能不符合要求,因为示例中的REQINFO是BODY下的一个键,而不是dynamicFields的子级。因此,这种方法可能不可行。 另一种方法是,让Body类包含固定的respond_code、respond_des,以及一个专门用于存放REQINFO的Map或其他对象,同时允许添其他字段。但这样可能不够灵活,因为不同接口可能有不同的结构。 考虑到示例中的BODY结构是: "BODY": {"respond_code":"1", "respond_des":"已申请","REQINFO": { "BDH": "111111"} } 因此,除了respond_code和respond_des,其他字段如REQINFO可能需要作为独立的属性。但不同的接口可能会有不同的额外字段,比如有的接口可能有data、list等。这样,可能需要将这些动态字段作为Map的一部分,或者使用一个通用的对象来容纳。 可能的解决方案是,在Body类中使用一个Map来存储所有动态的键值对,除了固定的respond_code和respond_des。但这需要在序列化时将这些动态字段平铺到BODY层级下,而不是作为Map的子级。这可以通过使用@JsonAnyGetter注解来实现。 例如,Body类可以设计为: public classBody { privateString respond_code;private String respond_des;private Map<String,Object> additionalParams= new HashMap<>();@JsonAnyGetter publicMap<String, Object> getAdditionalParams() { returnadditionalParams;} public voidaddAdditionalParam(Stringkey, Object value) { additionalParams.put(key,value); }} 这样,当序列化时,additionalParams中的键值对会被平铺到BODY层级下,而不是作为additionalParams的子对象。例如,如果additionalParams中有REQINFO键,其值是一个Map,那么生成的JSON会是: "BODY": {"respond_code": "1","respond_des": "已申请", "REQINFO":{ "BDH": "111111" }} 这样就能满足示例的结构。同时,其他接口可以添其他键,比如: body.addAdditionalParam("data", someObject);生成的JSON就会包含data字段。 接下来,Head类需要包含SYSTEMCODE和SENDTIME。SYSTEMCODE可以设置为固定值,而SENDTIME可以设置为当前时间,格式为"yyyy-MM-ddHH:mm:ss"。可以使用Java的LocalDateTime和DateTimeFormatter来处理时间格式。因此,Head类可能如下: publicclass Head {private String SYSTEMCODE= "ETONG"; private StringSENDTIME;public Head(){ DateTimeFormatterformatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");this.SENDTIME= LocalDateTime.now().format(formatter); }// getters} 这样,每次创建Head实例时,SENDTIME会自动设置为当前时间。 然后,ApiResponse类将包含Head和Body的实例: public classApiResponse {private Head HEAD;private Body BODY; publicApiResponse(Bodybody) {this.HEAD =new Head();this.BODY =body; }// getters} 接下来,如何构造ApiResponse实例?可以提供一个工具类或静态方法,例如:public class ApiResponseBuilder { publicstatic ApiResponse success(String respondCode,String respondDes){ Body body= new Body();body.setRespond_code(respondCode); body.setRespond_des(respondDes);return new ApiResponse(body); }public static ApiResponse success(String respondCode, String respondDes, Map<String, Object> additionalParams) {Body body = newBody(); body.setRespond_code(respondCode);body.setRespond_des(respondDes); additionalParams.forEach(body::addAdditionalParam);return new ApiResponse(body); }} 这样,在控制器中可以这样使用: @GetMapping("/someEndpoint") publicApiResponse someMethod() { Bodybody = new Body(); body.setRespond_code("1"); body.setRespond_des("成功"); body.addAdditionalParam("REQINFO",Map.of("BDH", "111111")); returnnew ApiResponse(body); } 或者使用构建器: returnApiResponseBuilder.success("1", "已申请", Map.of("REQINFO", Map.of("BDH","111111"))); 这样生成的JSON结构应该符合要求。 另外,需要注意字段的命名与JSON键的对应关系。例如,Java类中的字段名是respond_code,而JSON中的键是"respond_code",可以使用@JsonProperty注解来确保正确映射,或者在Spring Boot的配置中设置属性命名策略为SNAKE_CASE,这样默认会将驼峰式转换为下划线式。 可能还需要处理空值的情况,使用@JsonInclude(JsonInclude.Include.NON_NULL)来避免序列化null值。 综上所述,完整的代码实现可能如下: Head类: public classHead { @JsonProperty("SYSTEMCODE") privateString systemCode ="ETONG";@JsonProperty("SENDTIME")private String sendTime; publicHead() {DateTimeFormatter formatter= DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); this.sendTime = LocalDateTime.now().format(formatter); }// getters} Body类: @JsonInclude(JsonInclude.Include.NON_EMPTY)public class Body {@JsonProperty("respond_code")private String respondCode; @JsonProperty("respond_des") private StringrespondDes;private Map<String,Object> additionalParams= new HashMap<>();@JsonAnyGetter publicMap<String, Object> getAdditionalParams() { returnadditionalParams;} public voidaddAdditionalParam(Stringkey, Object value) { additionalParams.put(key,value); }// gettersand setters forrespondCode and respondDes } ApiResponse类: publicclass ApiResponse {@JsonProperty("HEAD") privateHead head;@JsonProperty("BODY") privateBody body;public ApiResponse(Body body) {this.head =new Head();this.body = body; }// getters} 构建响应示例: Body body =new Body(); body.setRespondCode("1"); body.setRespondDes("已申请"); body.addAdditionalParam("REQINFO", Collections.singletonMap("BDH","111111"));ApiResponse response =new ApiResponse(body); 这样生成的JSON结构应该与示例一致。 另外,还可以考虑使用Lombok来简化getter和setter的编写,增代码简洁性。 可能遇到的问题:1. 时间格式是否正确,需要确保LocalDateTime的格式与示例一致。 2.使用@JsonAnyGetter是否正确,是否会导致其他字段被忽略。 3.动态字段的添是否方便,比如如何嵌套多层结构(如REQINFO中的BDH)。 4.是否支持多个动态字段,比如同时有REQINFO和其他键。测试这个结构时,可以创建一个简单的Spring Boot控制器,返回这个ApiResponse对象,查看生成的JSON是否符合预期。最后,提供一个工具类或方法,方便不同接口构造响应,确保respond_code和respond_des的正确设置,以及动态字段的添。</think>在Spring Boot项目中创建统一响应类,可以按照以下方式实现: ```java import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.Map; @Data public class ApiResponse { @JsonProperty("HEAD") private Head head = new Head(); @JsonProperty("BODY") private Body body; public ApiResponse(String respondCode, String respondDes) { this.body = new Body(respondCode, respondDes); } // 用于添动态BODY字段 public void addBodyParam(String key, Object value) { body.addAdditionalParam(key, value); } // HEAD内部类 @Data public static class Head { @JsonProperty("SYSTEMCODE") private String systemCode = "ETONG"; @JsonProperty("SENDTIME") private String sendTime = LocalDateTime.now() .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); } // BODY内部类 @Data @JsonInclude(JsonInclude.Include.NON_EMPTY) public static class Body { @JsonProperty("respond_code") private String respondCode; @JsonProperty("respond_des") private String respondDes; private Map<String, Object> additionalParams = new HashMap<>(); public Body(String respondCode, String respondDes) { this.respondCode = respondCode; this.respondDes = respondDes; } @JsonAnyGetter public Map<String, Object> getAdditionalParams() { return additionalParams; } public void addAdditionalParam(String key, Object value) { additionalParams.put(key, value); } } } ``` **代码解释:** 1. `Head`内部类处理固定头部信息 - SYSTEMCODE 硬编码为"ETONG" - SENDTIME 自动生成当前时间戳 - 使用Jackson注解保证JSON字段命名规范 2. `Body`内部类处理动态响应内容 - 包含必须的respond_code和respond_des字段 - 使用`@JsonAnyGetter`+Map实现动态字段扩展 - `@JsonInclude`过滤空值字段 3. 使用示例: ```java @RestController public class DemoController { @GetMapping("/demo") public ApiResponse demo() { ApiResponse response = new ApiResponse("1", "已申请"); response.addBodyParam("REQINFO", Map.of("BDH", "111111")); return response; } } ``` **生成JSON效果:** ```json { "HEAD": { "SYSTEMCODE": "ETONG", "SENDTIME": "2024-03-20 14:30:45" }, "BODY": { "respond_code": "1", "respond_des": "已申请", "REQINFO": { "BDH": "111111" } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

焱童鞋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值