自定义注解类(annotation):
IgnoreResult该类用于忽略不使用@ResponseBody
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
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
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,则不需要包装成*/@Overridepublic 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:就是我们方法的返回值*/@Overridepublic 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规范式的返回值
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(datapublic static <T> Builder<T> status(ResponseStatus status) {return Result.<T>builder().status(status);}//第3种:提供开发最常见的2种状态的简化方式ok和errorpublic 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;
}