定制@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;
}
相关推荐
oi7715 分钟前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
mqiqe21 分钟前
Python MySQL通过Binlog 获取变更记录 恢复数据
开发语言·python·mysql
AttackingLin23 分钟前
2024强网杯--babyheap house of apple2解法
linux·开发语言·python
少说多做34334 分钟前
Android 不同情况下使用 runOnUiThread
android·java
知兀34 分钟前
Java的方法、基本和引用数据类型
java·笔记·黑马程序员
蓝黑20201 小时前
IntelliJ IDEA常用快捷键
java·ide·intellij-idea
Ysjt | 深1 小时前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++
ephemerals__1 小时前
【c++丨STL】list模拟实现(附源码)
开发语言·c++·list