定制@ResponseBody

自定义注解类(annotation):

IgnoreResult该类用于忽略不使用@ResponseBody

java 复制代码
package com.baizhi.mall.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//元注解:描述注解的注解
@Retention(RetentionPolicy.RUNTIME)//设置当前注解保留到什么项目的什么阶段
//当前的注解类可以作用到什么位置上
@Target({ElementType.TYPE,ElementType.METHOD})
//@interface:声明为注解类
public @interface IgnoreResult {
}

ResultBody使用该类声明使用定制的@ResponseBody

java 复制代码
package com.baizhi.mall.api.annotation;

import org.springframework.web.bind.annotation.ResponseBody;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//元注解:描述注解的注解
@Retention(RetentionPolicy.RUNTIME) //设置当前注解保留到什么项目的什么阶段
@Target({ElementType.TYPE, ElementType.METHOD}) //当前的注解可以作用在类的什么位置上
//如果类或者方法上面有此注解,那么就代表。当前类中所有的方法都需要我们自动类型包装
public @interface ResultBody {
}

配置自定义的ResponseBodyAdvice

java 复制代码
package com.baizhi.mall.advice;

import com.baizhi.mall.annotation.IgnoreResult;
import com.baizhi.mall.annotation.ResultBody;
import com.baizhi.mall.api.vo.Result;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

//ResponseBodyAdvice springboot中自定义@ResponseBody需要的通知接口
//扫描Controller中定义的自定义注解 或 @restControllerAdvice
@ControllerAdvice                               
public class MyResponseBodyAdvice implements ResponseBodyAdvice {

    /**
     * 本方法代表我们的返回值是否需要进行自动类型保证为beforeBodyWrite中定义的转换值
     * @param returnType  方法的参数:返回值信息
     * @param converterType    转换的类型
     *                         比如:Controller中方法的返回值是String,那么converterType就会是StringHttpMessageConverter
     *                              Controller中方法的返回值不是String,那么converterType就会是MappingJackson2HttpMessageConverter
     * @return  如果返回值是true则需要包装成Result类型;如果返回值是fasle,则不需要包装成
     */
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        System.out.println("=============supports========returnType======》"+returnType);
        //返回值本身就是Result,不需要转换
        if (returnType.getParameterType().isAssignableFrom(Result.class)){
            return  false;
        }
        //如果方法上或者类上有@IgnoreResult,不需要转换
        if (returnType.hasMethodAnnotation(IgnoreResult.class)|| AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(),IgnoreResult.class)){
            return false;
        }
        //如果方法上或者类上有@ResultBody,需要转换
        if (returnType.hasMethodAnnotation(ResultBody.class)|| AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(),ResultBody.class)){
            return true;
        }
        return false;
    }

    /**
     * 进行实际类型保证的方法
     * body:就是我们方法的返回值
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        System.out.println("=============beforeBodyWrite=========body=====》"+body);
        //创建JSON转换的类对象
        ObjectMapper mapper= Jackson2ObjectMapperBuilder.json().build();
        //如果body是字符串,我们需要转换成Json格式
        if(body instanceof String){
            //以Result规范式返回值返回
            Result<Object> result=Result.ok(body);
            try {
              return   mapper.writeValueAsString(result);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
        return Result.ok(body); //不是String类型, 直接转换。 body就变成了Resuslt类中的data
    }
}

Result该类为响应返回时alibaba规范式的返回值

java 复制代码
package com.baizhi.mall.api.vo;

import com.baizhi.mall.api.ResponseStatus;
import com.baizhi.mall.api.constant.ResponseStatusEnum;
import lombok.AllArgsConstructor;
import lombok.Data;

/**
 * @param <T>  :就是参数化类型!
 *           简而言之,就是用户调用的时候,传什么,T就是什么!
 *  如果不写泛型T,那么data的数据类型必须是Object.
 *           那么每次获取data的时候,就必须做类型转换,比较繁琐。
 *           实现的效果是一样的。
 *  不同的请求,可能得到相同的状态码和状态信息。
 *           这样就会导致,代码冗余。
 *           这时候我们就需要创建一个接口,就是统一规范。
 *           只要是成功了,那么就返回我这个接口对应的值。
 *
 */
@Data
@AllArgsConstructor //省略了带参构造
public class Result<T> {
    private  int code; //状态码
    private  String message; //状态码信息
    private  T data; //返回的具体数据

    //第二步:创建构建者的调用方式
    public  static <T>Builder<T> builder(){
        return  new  Builder<>();
        //这个builder对象是空的,要给那个属性赋值,直接 点 方法名即可。
        //Result.builder().code(200).message("message");
    }

    //第2种:通过status接收ResponseStatus后续只需要添加data再build就可以:status(responseStatus).build(data
    public static <T> Builder<T> status(ResponseStatus status) {
        return Result.<T>builder().status(status);
    }

    //第3种:提供开发最常见的2种状态的简化方式ok和error
    public static <T> Result<T> ok() {
        return Result.ok((T) null);
    }

    public static <T> Result<T> ok(T data) {
        return Result.<T>status(ResponseStatusEnum.SUCCESS).data(data).build();
    }

    public static <T> Builder<T> ok(String message) {
        return Result.<T>builder().code(ResponseStatusEnum.SUCCESS.getCode()).message(message);
    }

    public static <T> Result<T> error() {
        return Result.<T>status(ResponseStatusEnum.FAILED).build();
    }

    public static <T> Result<T> error(String message){
        return Result.<T>builder().code(ResponseStatusEnum.FAILED.getCode()).message(message).build();
    }


    //第一步:创建Result类的构建者,针对Result类中的属性,进行组合
    public static  class Builder<T>{
        private  int code; //状态码
        private  String message; //状态码信息
        private  T data; //返回的具体数据
        private  Builder(){}
        public  Builder<T> status(ResponseStatus status){
            this.code=status.getCode();
            this.message=status.getMessage();
            return  this;
        }
        public  Builder<T> code(int code){
            this.code=code;
            return  this;
        }
        public  Builder<T> message(String message){
            this.message=message;
            return  this;
        }
        public  Builder<T> data(T data){
            this.data=data;
            return  this;
        }
        public  Result<T> build(){
            return  new Result(code,message,data);
        }
        public  Result<T> build(T data){
            this.data(data);
            return  build();
        }
    }

}

使用自定义注解在Controller的类和方法上

复制代码
@GetMapping("/haha")
@ResultBody //自定义注解  转换成Result对象
public String haha(){
    System.out.println("==================haha=====================");
    return "haha";
}
@GetMapping("/haha1")
@IgnoreResult //不转换成Result对象
public String haha1(){
    System.out.println("==================haha1=====================");
    return "haha1";
}
@GetMapping("/list")
@ResultBody //自定义注解  转换成Result对象
public List<Student> list(){
    System.out.println("==================list=====================");
    List<Student> students=new ArrayList<>();
    students.add(new Student(1,18,"小黑1"));
    students.add(new Student(2,14,"小黑2"));
    students.add(new Student(3,16,"小黑3"));
    return students;
}
相关推荐
Scott9999HH6 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔6 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社7 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海7 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖8 小时前
JDK 26 新特性详解
java·开发语言
马优晨8 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区10 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大11 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai11 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
维天说11 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json