自定义注解类(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,则不需要包装成
*/
@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
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,那么data的数据类型必须是Object.
* 那么每次获取data的时候,就必须做类型转换,比较繁琐。
* 实现的效果是一样的。
* 不同的请求,可能得到相同的状态码和状态信息。
* 这样就会导致,代码冗余。
* 这时候我们就需要创建一个接口,就是统一规范。
* 只要是成功了,那么就返回我这个接口对应的值。
*
*/
@Data
@AllArgsConstructor //省略了带参构造
public class Result {
private int code; //状态码
private String message; //状态码信息
private T data; //返回的具体数据
//第二步:创建构建者的调用方式
public static Builder builder(){
return new Builder<>();
//这个builder对象是空的,要给那个属性赋值,直接 点 方法名即可。
//Result.builder().code(200).message("message");
}
//第2种:通过status接收ResponseStatus后续只需要添加data再build就可以:status(responseStatus).build(data
public static Builder status(ResponseStatus status) {
return Result.builder().status(status);
}
//第3种:提供开发最常见的2种状态的简化方式ok和error
public static Result ok() {
return Result.ok((T) null);
}
public static Result ok(T data) {
return Result.status(ResponseStatusEnum.SUCCESS).data(data).build();
}
public static Builder ok(String message) {
return Result.builder().code(ResponseStatusEnum.SUCCESS.getCode()).message(message);
}
public static Result error() {
return Result.status(ResponseStatusEnum.FAILED).build();
}
public static Result error(String message){
return Result.builder().code(ResponseStatusEnum.FAILED.getCode()).message(message).build();
}
//第一步:创建Result类的构建者,针对Result类中的属性,进行组合
public static class Builder{
private int code; //状态码
private String message; //状态码信息
private T data; //返回的具体数据
private Builder(){}
public Builder status(ResponseStatus status){
this.code=status.getCode();
this.message=status.getMessage();
return this;
}
public Builder code(int code){
this.code=code;
return this;
}
public Builder message(String message){
this.message=message;
return this;
}
public Builder data(T data){
this.data=data;
return this;
}
public Result build(){
return new Result(code,message,data);
}
public Result 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 list(){
System.out.println("==================list=====================");
List 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;
}