网站刚做怎么做seo优化,爱南宁健康码app下载,空间商指定的网站目录,包装设计网站排行榜简介 PS: advice, 在这里意思是顾问, 其余很多场景也是顾问的意思由于篇幅问题, 注释已删, 如想看注释, 请在github中查看 作用: 用于在Controller返回后, HttpMessageConverter执行转换之前执行一些转换
常见场景: 统一响应结构, 如json统一包装
由于版本不同, 多少有些差异…简介 PS: advice, 在这里意思是顾问, 其余很多场景也是顾问的意思由于篇幅问题, 注释已删, 如想看注释, 请在github中查看 作用: 用于在Controller返回后, HttpMessageConverter执行转换之前执行一些转换
常见场景: 统一响应结构, 如json统一包装
由于版本不同, 多少有些差异, 所以不贴源码了, 基本上springboot2.x和3.x是通用的
简单做个翻译(springboot3.1.5为例):
public interface ResponseBodyAdviceT {/*** 此Advice是否使用于该返回类型和Converter类型(意思是可以配置多个哦)* param returnType 返回类型(这里可以获取很多东西, 别被名字误导了)* param converterType 自动选择的转换器类型* return 返回true表示将会走接下来的方法(beforeBodyWrite), 否则不会*/boolean supports(MethodParameter returnType, Class? extends HttpMessageConverter? converterType);/*** HttpMessageConverter转换之前进行的操作* param body 要转换的body* param returnType 返回类型* param selectedContentType 根据请求头协商的ContentType* param selectedConverterType 自动选择的转换器类型* param request 当前请求* param response 当前响应* return 修改后的响应内容*/NullableT beforeBodyWrite(Nullable T body, MethodParameter returnType, MediaType selectedContentType,Class? extends HttpMessageConverter? selectedConverterType,ServerHttpRequest request, ServerHttpResponse response);}
示例
RestControllerAdvice
public class ResAdvice implements ResponseBodyAdviceObject {Overridepublic boolean supports(NotNull MethodParameter returnType, NotNull Class? extends HttpMessageConverter? converterType) {return returnType.getContainingClass().getPackageName().startsWith(kim.nzxy.ly);}Overridepublic Object beforeBodyWrite(Object body,NotNull MethodParameter returnType,NotNull MediaType selectedContentType,NotNull Class? extends HttpMessageConverter? selectedConverterType,NotNull ServerHttpRequest request,NotNull ServerHttpResponse response) {if (body instanceof Res? || !selectedContentType.equals(MediaType.APPLICATION_JSON)) {return body;}if (body instanceof Page?) {// 我的分页有特殊处理return Res.page((Page?)body);}return Res.ok(body);}
}解释一下代码: supports判断, 如果类为自己的包下的类, 则允许处理 beforeBodyWrite作用: 如果响应内容不是JSON(可能是文件之类的), 或者已经被公共响应(Res)类包装过了, 就直接返回; 否则则在外面包装一层Res类 附Res.java
package kim.nzxy.ly.common.res;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import kim.nzxy.ly.common.exception.LyException;
import lombok.Data;
import lombok.experimental.Accessors;Data
public class ResT {private static final String SUCCESS_MESSAGE 操作成功;private String message;private int code;private T data;private long timestamp System.currentTimeMillis();public static T ResT ok(T data, String message) {if (data instanceof Page) {throw new LyException.Panic(使用Res#page方法来返回分页数据);}ResT msg new ResT();msg.setCode(2000);msg.setMessage(message);msg.setData(data);return msg;}public static T ResT ok(T data) {return Res.ok(data, SUCCESS_MESSAGE);}public static T ResT ok(String message) {// noinspection uncheckedreturn Res.ok((T) message, message);}public static T ResT ok() {return Res.ok(null, SUCCESS_MESSAGE);}public static T ResT fail(String message, int code) {ResT msg new Res();msg.setCode(code);msg.setMessage(message);return msg;}public static T ResT fail(String message) {return Res.fail(message, 5000);}public static T ResPagingVOT page(PageT page) {PagingVOT data new PagingVO();data.setPages(Math.toIntExact(page.getPages()));data.setPageSize(Math.toIntExact(page.getSize()));data.setList(page.getRecords());data.setTotal(Math.toIntExact(page.getTotal()));data.setPageNum(Math.toIntExact(page.getCurrent()));return ok(data);}
}常见问题 Controller中返回String类型, 会报类转换异常错误 解决方案: 如果项目中String类型都是要统一包装的, 那就直接干掉所有StringHttpMessageConverter Configuration
public class StringHttpMessageConvertRemover implements WebMvcConfigurer {Overridepublic void extendMessageConverters(ListHttpMessageConverter? converters) {converters.removeIf(it - it instanceof StringHttpMessageConverter);}
}或者不管String类型了 Override
public boolean supports(NotNull MethodParameter returnType, NotNull Class? extends HttpMessageConverter? converterType) {if (java.lang.String.equals(returnType.getParameterType().getName())) {return false;}return returnType.getContainingClass().getPackageName().startsWith(kim.nzxy.ly);
}OpenAPI Knife4J等, 额外包装一层 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import kim.nzxy.ly.common.res.PagingVO;
import kim.nzxy.ly.common.res.Res;
import org.apache.commons.lang3.reflect.TypeUtils;
import org.springdoc.core.parsers.ReturnTypeParser;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.MethodParameter;
import org.springframework.core.io.Resource;import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Optional;/*** author ly-chn* since 2024/1/24 10:58*/
Configuration
public class ApiDocOperationCustomizer {Beanpublic ReturnTypeParser returnTypeParser() {return new ReturnTypeParser() {Overridepublic Type getReturnType(MethodParameter methodParameter) {Type returnType ReturnTypeParser.super.getReturnType(methodParameter);Class? parameterType methodParameter.getParameterType();// 资源文件或者已经被包装了, 直接返回if (parameterType.isAssignableFrom(Resource.class) || parameterType.isAssignableFrom(Res.class)) {return returnType;}// 分页特殊处理, 转为PagingVO类if (parameterType.isAssignableFrom(Page.class) returnType instanceof ParameterizedType) {OptionalType t TypeUtils.getTypeArguments((ParameterizedType) returnType).values().stream().findFirst();Type type t.orElse(Object.class);return TypeUtils.parameterize(Res.class, TypeUtils.parameterize(PagingVO.class, type));}// void转为ResObjectif (parameterType.isAssignableFrom(void.class)) {return TypeUtils.parameterize(Res.class, Object.class);}// 包装Resreturn TypeUtils.parameterize(Res.class, returnType);}};}
}直接写Response 直接写 OutputStream 怎么办 本来我也担心, 但是ResponseBodyAdvice类是Controller返回后, HttpMessageConverter执行转换之前执行, 所以无需担心直接写, 然后返回void的问题 我做了这么一个测试, 不会走ResponseBodyAdvice, 但是此时Swagger/Knife4f, openapi就无能为力了, 因为没法从代码中获取是否有文件下载 GetMapping(void-with-byte)
public void testVoidWithByte(HttpServletResponse response) throws IOException {response.setContentType(application/octet-stream;charsetutf-8);response.setHeader(HttpHeaders.CONTENT_DISPOSITION, attachment;filenameapplication.yml);ClassPathResource resource new ClassPathResource(application.yml);response.getOutputStream().write(resource.getContentAsByteArray());
}