关于swagger配置及踩坑@Api参数postion无效解决接口排序问题

网友投稿 1647 2022-07-23


目录添加maven依赖添加配置类在application.properties中添加配置添加控制类UserController请求对象类DTO响应对象类最后,上效果图最后还有个坑

添加maven依赖

io.springfox

springfox-swagger2

2.9.2

io.springfox

springfox-swagger-ui

2.9.2

com.google.guava

guava

27.0.1-jre

添加配置类

package top.lidaoyuan.hamster.api.config.swagger;

import java.util.Arrays;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

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

import io.swagger.annotations.ApiOperation;

import springfox.documentation.builders.ApiInfoBuilder;

import springfox.documentation.builders.PathSelectors;

import springfox.documentation.builders.RequestHandlerSelectors;

import springfox.documentation.builders.ResponseMessageBuilder;

import springfox.documentation.service.ApiInfo;

import springfox.documentation.service.ResponseMessage;

import springfox.documentation.spi.DocumentationType;

import springfox.documentation.spring.web.plugins.Docket;

import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration

@EnableSwagger2

public class Swagger2Config {

@Bean

public Docket customDocket() {

// 配置全局参数返回状态

java.util.List resMsgList = Arrays.asList(

new ResponseMessageBuilder().code(200).message("成功!").build(),

new ResponseMessageBuilder().code(-1).message("失败!").build(),

new ResponseMessageBuilder().code(401).message("参数校验错误!").build(),

new ResponseMessageBuilder().code(403).message("没有权限操作,请后台添加相应权限!").build(),

new ResponseMessageBuilder().code(500).message("服务器内部异常,请稍后重试!").build(),

new ResponseMessageBuilder().code(501).message("请登录!").build());

return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()

.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))

.paths(PathSelectors.any())

.build()

.globalResponseMessage(RequestMethod.GET, resMsgList)

.globalResponseMessage(RequestMethod.POST, resMsgList)

.globalResponseMessage(RequestMethod.PUT, resMsgList)

.globalResponseMessage(RequestMethod.DELETE, resMsgList);

}

private ApiInfo apiInfo() {

return new ApiInfoBuilder()

.title("Hamster接口文档")

.description("接口文档说明")

.version("1.0.0")

.build();

}

}

在application.properties中添加配置

logging.level.io.swagger.models.parameters.AbstractSerializableParameter=ERROR

添加控制类UserController

package top.lidaoyuan.hamster.api.web;

import java.util.ArrayList;

import java.util.List;

import java.util.stream.Collectors;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;

import org.springfrahttp://mework.data.domain.Page;

import org.springframework.validation.BindingResult;

import org.springframework.validation.ObjectError;

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

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

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

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

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

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

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

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

import io.swagger.annotations.Api;

import io.swagger.annotations.ApiOperation;

import io.swagger.annotations.ApiParam;

import lombok.extern.slf4j.Slf4j;

import top.lidaoyuan.hamster.api.dto.jsonResultDTO;

import top.lidaoyuan.hamster.api.dto.PageInputDTO;

import top.lidaoyuan.hamster.api.dto.UserInputDTO;

import top.lidaoyuan.hamster.api.entity.User;

import top.lidaoyuan.hamster.api.service.IUserService;

/**

* 用户 前端控制器

* @author Lidy

* @since 2019-03-06

*/

@Api(tags = {"用户接口"})

@RestController

@RequestMapping("/v1/user")

@Slf4j

public class UserController {

@Autowired

private IUserService userService;

@ApiOperation(value = "新增用户")

@PostMapping

public JsonResultDTO create(@RequestBody @Valid UserInputDTO inputDTO, BindingResult bindingResult) {

log.info("create.inputDTO:" + inputDTO);

boolean hasError = bindingResult.hasErrors();

log.info("hasError:" + hasError);

if(hasError) {

List errMsgList = bindingResult.getAllErrors().stream()

.map(ObjectError::getDefaultMessage)

.collect(Collectors.toList());

return JsonResultDTO.errorArgument(errMsgList.toString());

}

User userDb = userService.save(inputDTO.convertToEntity());

log.info("create.userDb:" + userDb );

return JsonResultDTO.ok(inputDTO.convertFor(userDb));

}

@ApiOperation(value = "获取单个用户")

@GetMapping("{id}")

public JsonResultDTO getOne(@ApiParam(value = "用户Id", example = "1", required = true)

@PathVariable Integer id) throws Exception {

log.info("getOne.id:" + id);

User userDb = userService.getOne(id);

log.info("getOne.userDB:" + userDb);

return JsonResultDTO.ok(new UserInputDTO().convertFor(userDb));

}

@ApiOperation(value = "更新单个用户")

@PutMapping("{id}")

public JsonResultDTO update(@ApiParam(value = "用户Id", example = "1", required = true)

@PathVariable Integer id, @RequestBody UserInputDTO inputDTO) {

log.info("update.id:" + id + " inputDTO:" + inputDTO );

User userDb = userService.update(inputDTO.convertToEntity(), id);

log.info("update.userDb:" + userDb );

return JsonResultDTO.ok(inputDTO.convertFor(userDb));

}

@ApiOperation(value = "获取用户列表")

@GetMapping("listExample")

public JsonResultDTO listExample(UserInputDTO inputDTO) {

log.info("listExample.inputDTO:" + inputDTO);

List listDb = null;

if(inputDTO == null) {

listDb = userService.list();

}else {

listDb = userService.list(inputDTO.convertToEntity());

}

log.info("listExample.listDb:" + listDb);

if(listDb == null || listDb.size() ==0) return JsonResultDTO.ok();

List inputDTOList = new ArrayList<>();

for(User user: listDb) {

inputDTOList.add(inputDTO.convertFor(user));

}

return JsonResultDTO.ok(inputDTOList);

}

@ApiOperation(value = "分页获取用户列表")

@GetMapping("listPageExample")

public JsonResultDTO listPageExample(UserInputDTO inputDTO, PageInputDTO pageDTO) {

log.info("listPageExample.inputDTO:" + inputDTO + " pageDTO:" + pageDTO);

Page pageDb = null;

if(inputDTO == null) {

pageDb = userService.page(pageDTO);

}else {

pageDb = userService.page(inputDTO.convertToEntity(), pageDTO);

}

log.info("listPageExample.pageDb:" + pageDb);

if(pageDb == null || pageDb.getSize() ==0) {

return JsonResultDTO.ok();

}

List inputDTOList = new ArrayList<>();

for(User user: pageDb) {

inputDTOList.add(inputDTO.convertFor(user));

}

return JsonResultDTO.page(inputDTOList,pageDb.getTotalElements());

}

@ApiOperation(value = "删除用户")

@DeleteMapping("{id}")

public JsonResultDTO deleteById(@ApiParam(value = "用户Id", example = "1", required = true)

@PathVariable Integer id) {

log.info("del.id:" + id);

userService.deleteById(id);

return JsonResultDTO.ok();

}

}

请求对象类DTO

package top.lidaoyuan.hamster.api.dto;

import java.io.Serializable;

import com.google.common.base.Converter;

import com.fasterxml.jackson.annotation.JsonInclude;

import com.fasterxml.jackson.annotation.JsonInclude.Include;

import io.swagger.annotations.ApiModel;

import io.swagger.annotations.ApiModelProperty;

import lombok.*;

import lombok.experimental.Accessors;

import javax.validation.constraints.*;

import top.lidaoyuan.hamster.api.entity.User;

import top.lidaoyuan.hamster.utils.BeanUtils;

import java.util.Date;

import org.springframework.format.annotation.DateTimeFormat;

import com.fasterxml.jackson.annotation.JsonFormat;

/**

* 用户DTO

* @author Lidy

* @since 2019-03-06

*/

@ApiModel(value = "用户Model")

@Data

@NoArgsConstructor

@AllArgsConstructor

@Accessors(chain = true)

@ToString

@JsonInclude(Include.NON_NULL)

public class UserInputDTO implements Serializable {

private static final long serialVersionUID = 1L;

/** ID */

@ApiModelProperty(hidden = true)

private Integer id;

/** 是否激活 */

@ApiModelProperty(value = "是否激活", position = 1)

private Boolean active;

/** 年龄 */

@ApiModelProperty(value = "年龄", position = 2)

private Integer age;

/** email */

@ApiModelProperty(value = "email", position = 3)

@Email(message = "邮箱格式不正确")

@NotBlank(message = "【email】不能为空")

@Size(max = 255, message = "【email】字段长度应<255")

private String email;

/** 姓 */

@ApiModelProperty(value = "姓", position = 4)

@NotBlank(message = "【姓】不能为空")

@Size(max = 10, message = "【姓】字段长度应<10")

private String firstname;

/** 名 */

@ApiModelProperty(value = "名", position = 5)

@Size(max = 20, message = "【名】字段长度应<20")

private String lastname;

/** 开始时间 */

@ApiModelProperty(value = "开始时间", example = "2019-03-06 17:09:10", position = 6)

@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")

private Date startDate;

/** 结束时间 */

@ApiModelProperty(value = "结束时间", example = "2019-03-06 17:09:10", position = 7)

@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")

private Date endDate;

/** 转换成实体类 */

public User convertToEntity() {

return new UserInputDTOConver().convert(this);

}

/** 转换成InputDTO */

public UserInputDTO convertFor(User bean) {

return new UserInputDTOConver().reverse().convert(bean);

}

/** Conver转换类 */

private static class UserInputDTOConver extends Converter {

@Override

protected User doForward(UserInputDTO dto) {

User bean = new User();

BeanUtils.copyProperties(dto, bean);

return bean;

}

@Override

protected UserInputDTO doBackward(User bean) {

UserInputDTO dto = new UserInputDTO();

BeanUtils.copyProperties(bean, dto);

return dto;

}

}

}

响应对象类

package top.lidaoyuan.hamster.api.dto;

import java.util.Arrays;

import java.util.List;

import org.springframework.data.domain.Page;

import com.fasterxml.jackson.annotation.JsonInclude;

import com.fasterxml.jackson.annotation.JsonInclude.Include;

import io.swagger.annotations.ApiModel;

import io.swagger.annotations.ApiModelProperty;

import lombok.AllArgsConstructor;

import lombok.Data;

import lombok.NoArgsConstructor;

import lombok.ToString;

/**

* Json结果DTO

* @author ex-lidy001

*

*/

@ApiModel(value = "返回JSON对象")

@Data

@ToString

@NoArgsConstructor

@AllArgsConstructor

@JsonInclude(Include.NON_NULL)

public class JsonResultDTO {

@ApiModelProperty(value = "状态码;200:成功")

private Integer code;

@ApiModelProperty(value = "状态说明")

private String msg;

@ApiModelProperty(value = "总记录数")

private Long total;

@ApiModelProperty(value = "返回数据")

private Object data;

public JsonResultDTO(Integer code, String msg) {

this.code = code;

this.msg = msg;

this.data = Arrays.asList();

}

public JsonResultDTO(Integer code, String msg, Object data) {

this.code = code;

this.msg = msg;

this.data = data;

if(data == null) {

this.data = Arrays.asList();

}

}

public static JsonResultDTO ok() {

return new JsonResultDTO(200, "成功");

}

public static JsonResultDTO ok(String msg) {

return new JsonResultDTO(200, msg);

}

public static JsonResultDTO ok(Object data) {

return new JsonResultDTO(200, "成功", data);

}

public static JsonResultDTO page(Page> page) {

JsonResultDTO jrDTO = new JsonResultDTO(200, "成功", page.getContent());

jrDTO.setTotal(page.getTotalElements());

return jrDTO;

}

public static JsonResultDTO page(List> list, Long total) {

JsonResultDTO jrDTO = new JsonResultDTO(200, "成功", list);

jrDTO.setTotal(total);

return jrDTO;

}

public static JsonResultDTO error() {

return new JsonResultDTO(-1, "失败!");

}

public static JsonResultDTO error(String msg) {

return new JsonResultDTO(-1, msg);

}

public static JsonResultDTO errorArgument(String msg) {

return new JsonResultDTO(401, "参数校验:" + msg);

}

public static JsonResultDTO unAuth() {

return new JsonResultDTO(403, "没有权限!");

}

public static JsonResultDTO unlogin() {

return new JsonResultDTO(501, "请登录!");

}

public static JsonResultDTO exception(String msg) {

return new JsonResultDTO(500, "系统内部错误:" + msg);

}

}

最后,上效果图

请求路径http://localhost:8080/swagger-ui.html

请求

响应

最后还有个坑

在使用最新版的springfox-swagger2 2.9.2``position排序的时候没有生效,后来在网上找了相关资料,需要重写swagger的两个类,具体如下。

package top.lidaoyuan.hamster.api.config.swagger;

import java.util.List;

import java.util.stream.Collectors;

import org.springframework.context.annotation.Primary;

import org.springframework.core.Ordered;

import org.springframework.core.annotation.Order;

import org.springframework.stereotype.Component;

import io.swagger.models.parameters.Parameter;

import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2MapperImpl;

/**

* Created by wujie on 2019/2/16.

* 重写 将Document转换成Swagger 类, 根据order进行排序

*/

@Primary //同一个接口,可能会有几种不同的实现类,而默认只会采取其中一种的情况下

@Component("ServiceModelToSwagger2Mapper")

@Order(Ordered.HIGHEST_PRECEDENCE)

public class CustomModelToSwaggerMapper extends ServiceModelToSwagger2MapperImpl {

@Override

protected List parameterListToParameterList(List list) {

//list需要根据order|postion排序

list = list.stream().sorted((p1, p2) -> Integer.compare(p1.getOrder(), p2.getOrder())).collect(Collectors.toList());

// log.debug("************************************list:{}", list.toString());

return super.parameterListToParameterList(list);

}

}

package top.lidaoyuan.hamster.api.config.swagger;

import static springfox.documentation.swagger.common.SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER;

import java.util.Arrays;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Primary;

import org.springframework.stereotype.Component;

import com.google.common.base.Function;

import com.google.common.base.Optional;

import com.google.common.base.Strings;

import com.google.common.collect.Lists;

import io.swagger.annotations.ApiModelProperty;

import io.swagger.annotations.ApiParam;

import springfox.documentation.builders.ParameterBuilder;

import springfox.documentation.service.AllowableListValues;

import springfox.documentation.service.AllowableValues;

import springfox.documentation.spi.DocumentationType;

import springfox.documentation.spi.schema.EnumTypeDeterminer;

import springfox.documentation.spi.service.ExpandedParameterBuilderPlugin;

import springfox.documentation.spi.service.contexts.ParameterExpansionContext;

import springfox.documentation.spring.web.DescriptionResolver;

import springfox.documentation.swagger.common.SwaggerPluginSupport;

import springfox.documentation.swagger.readers.parameter.Examples;

import springfox.documentation.swagger.schema.ApiModelProperties;

/**

* Created by wujie on 2019/2/16.

* 自定义ExpandedParameterBuilderPlugin,主要是修正源码query传入请求参数postion无效

* 这里,将postion赋值给order

*/

@Primary

@Component

public class CustomSwaggerParameterBuilder implements ExpandedParameterBuilderPlugin {

private final DescriptionResolver descriptions;

private final EnumTypeDeterminer enumTypeDeterminer;

@Autowired

public CustomSwaggerParameterBuilder(

DescriptionResolver descriptions,

EnumTypeDeterminer enumTypeDeterminer) {

this.descriptions = descriptions;

this.enumTypeDeterminer = enumTypeDeterminer;

}

@Override

public void apply(ParameterExpansionContext context) {

Optional apiModelPropertyOptional = context.findAnnotation(ApiModelProperty.class);

if (apiModelPropertyOptional.isPresent()) {

fromApiModelProperty(context, apiModelPropertyOptional.get());

}

Optional apiParamOptional = context.findAnnotation(ApiParam.class);

if (apiParamOptional.isPresent()) {

fromApiParam(context, apiParamOptional.get());

}

}

@Override

public boolean supports(DocumentationType delimiter) {

return SwaggerPluginSupport.pluginDoesApply(delimiter);

}

private void fromApiParam(ParameterExpansionContext context, ApiParam apiParam) {

String allowableProperty = Strings.emptyToNull(apiParam.allowableValues());

AllowableValues allowable = allowableValues(

Optional.fromNullable(allowableProperty),

context.getFieldType().getErasedType());

maybeSetParameterName(context, apiParam.name())

.description(descriptions.resolve(apiParam.value()))

.defaultValue(apiParam.defaultValue())

.required(apiParam.required())

.allowMultiple(apiParam.allowMultiple())

.allowableValues(allowable)

.parameterAccess(apiParam.access())

.hidden(apiParam.hidden())

.scalarExample(apiParam.example())

.complexExamples(Examples.examples(apiParam.examples()))

.order(SWAGGER_PLUGIN_ORDER)

.build();

}

private void fromApiModelProperty(ParameterExpansionContext context, ApiModelProperty apiModelProperty) {

String allowableProperty = Strings.emptyToNull(apiModelProperty.allowableValues());

AllowableValues allowable = allowableValues(

Optional.fromNullable(allowableProperty),

context.getFieldType().getErasedType());

maybeSetParameterName(context, apiModelProperty.name())

.description(descriptions.resolve(apiModelProperty.value()))

.required(apiModelProperty.required())

.allowableValues(allowable)

.parameterAccess(apiModelProperty.access())

.hidden(apiModelProperty.hidden())

.scalarExample(apiModelProperty.example())

.order(apiModelProperty.position()) //源码这里是: SWAGGER_PLUGIN_ORDER,需要修正

.build();

}

private ParameterBuilder maybeSetParameterName(ParameterExpansionContext context, String parameterName) {

if (!Strings.isNullOrEmpty(parameterName)) {

context.getParameterBuilder().name(parameterName);

}

return context.getParameterBuilder();

}

private AllowableValues allowableValues(final Optional optionalAllowable, Class> fieldType) {

AllowableValues allowable = null;

if (enumTypeDeterminer.isEnum(fieldType)) {

allowable = new AllowableListValues(getEnumValues(fieldType), "LIST");

} else if (optionalAllowable.isPresent()) {

allowable = ApiModelProperties.allowableValueFromString(optionalAllowable.get());

}

return allowable;

}

private List getEnumValues(final Class> subject) {

return Lists.transform(Arrays.asList(subject.getEnumConstants()), new Function() {

@Override

public String apply(final Object input) {

return input.toString();

}

});

}

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:一文详解Java闭锁和栅栏的实现
下一篇:Java中super和this关键字详解
相关文章

 发表评论

评论列表

2024-05-10 12:18:38

代码 就这么排序得?