1. pom.xml<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.2.RELEASE</version> <relativePath/> </parent> <groupId>cn.itcast</groupId> <artifactId>knife4j_demo</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-spring-boot-starter</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies></project>2.application.ymlserver: port: 8081niewj: swagger: enabled: true #是否启用swagger base-package: com.niewj.controller# docket:# user:# title: 用户模块# base-package: com.niewj.controller.user# menu:# title: 菜单模块# base-package: com.niewj.controller.menu3. 配置读取属性类SwaggerPropertiespackage com.niewj.config;import lombok.*;import org.springframework.boot.context.properties.ConfigurationProperties;import java.util.ArrayList;import java.util.LinkedHashMap;import java.util.List;import java.util.Map;/**配置属性类,用于封装接口文档相干属性,从配置文件读取信息封装成以后对象*/@Data@ConfigurationProperties(prefix = "niewj.swagger")public class SwaggerProperties { private String title = "在线文档"; //题目 private String group = ""; //自定义组名 private String description = "在线文档"; //形容 private String version = "1.0"; //版本 private Contact contact = new Contact(); //联系人 private String basePackage = "com.niewj"; //swagger会解析的包门路 private List<String> basePath = new ArrayList<>(); //swagger会解析的url规定 private List<String> excludePath = new ArrayList<>();//在basePath根底上须要排除的url规定 private Map<String, DocketInfo> docket = new LinkedHashMap<>(); //分组文档 public String getGroup() { if (group == null || "".equals(group)) { return title; } return group; } @Data public static class DocketInfo { private String title = "在线文档"; //题目 private String group = ""; //自定义组名 private String description = "在线文档"; //形容 private String version = "1.0"; //版本 private Contact contact = new Contact(); //联系人 private String basePackage = ""; //swagger会解析的包门路 private List<String> basePath = new ArrayList<>(); //swagger会解析的url规定 private List<String> excludePath = new ArrayList<>();//在basePath根底上须要排除的url public String getGroup() { if (group == null || "".equals(group)) { return title; } return group; } } @Data public static class Contact { private String name = "niewj"; //联系人 private String url = ""; //联系人url private String email = ""; //联系人email }}4. SwaggerConfigpackage com.niewj.config;import com.google.common.base.Predicate;import com.google.common.base.Predicates;import org.springframework.beans.BeansException;import org.springframework.beans.factory.BeanFactory;import org.springframework.beans.factory.BeanFactoryAware;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.config.ConfigurableBeanFactory;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import springfox.documentation.builders.ApiInfoBuilder;import springfox.documentation.builders.PathSelectors;import springfox.documentation.builders.RequestHandlerSelectors;import springfox.documentation.service.ApiInfo;import springfox.documentation.service.Contact;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;import springfox.documentation.swagger2.annotations.EnableSwagger2;import java.util.ArrayList;import java.util.LinkedList;import java.util.List;@Configuration@ConditionalOnProperty(name = "niewj.swagger.enabled", havingValue = "true", matchIfMissing = true)@EnableSwagger2@EnableConfigurationProperties(SwaggerProperties.class)public class SwaggerConfig implements BeanFactoryAware { @Autowired SwaggerProperties swaggerProperties; private BeanFactory beanFactory; @Bean @ConditionalOnMissingBean public List<Docket> createRestApi() { ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory) beanFactory; List<Docket> docketList = new LinkedList<>(); // 没有分组 if (swaggerProperties.getDocket().isEmpty()) { Docket docket = createDocket(swaggerProperties); configurableBeanFactory.registerSingleton(swaggerProperties.getTitle(), docket); docketList.add(docket); return docketList; } // 分组创立 for (String groupName : swaggerProperties.getDocket().keySet()) { SwaggerProperties.DocketInfo docketInfo = swaggerProperties.getDocket().get(groupName); ApiInfo apiInfo = new ApiInfoBuilder() //页面题目 .title(docketInfo.getTitle()) //创建人 .contact(new Contact(docketInfo.getContact().getName(), docketInfo.getContact().getUrl(), docketInfo.getContact().getEmail())) //版本号 .version(docketInfo.getVersion()) //形容 .description(docketInfo.getDescription()) .build(); // base-path解决 // 当没有配置任何path的时候,解析/** if (docketInfo.getBasePath().isEmpty()) { docketInfo.getBasePath().add("/**"); } List<Predicate<String>> basePath = new ArrayList<>(); for (String path : docketInfo.getBasePath()) { basePath.add(PathSelectors.ant(path)); } // exclude-path解决 List<Predicate<String>> excludePath = new ArrayList<>(); for (String path : docketInfo.getExcludePath()) { excludePath.add(PathSelectors.ant(path)); } Docket docket = new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo) .groupName(docketInfo.getGroup()) .select() //为以后包门路 .apis(RequestHandlerSelectors.basePackage(docketInfo.getBasePackage())) .paths(Predicates.and(Predicates.not(Predicates.or(excludePath)), Predicates.or(basePath))) .build(); configurableBeanFactory.registerSingleton(groupName, docket); docketList.add(docket); } return docketList; } //构建 api文档的详细信息 private ApiInfo apiInfo(SwaggerProperties swaggerProperties) { return new ApiInfoBuilder() //页面题目 .title(swaggerProperties.getTitle()) //创建人 .contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(), swaggerProperties.getContact().getEmail())) //版本号 .version(swaggerProperties.getVersion()) //形容 .description(swaggerProperties.getDescription()) .build(); } //创立接口文档对象 private Docket createDocket(SwaggerProperties swaggerProperties) { //API 根底信息 ApiInfo apiInfo = apiInfo(swaggerProperties); // base-path解决 // 当没有配置任何path的时候,解析/** if (swaggerProperties.getBasePath().isEmpty()) { swaggerProperties.getBasePath().add("/**"); } List<Predicate<String>> basePath = new ArrayList<>(); for (String path : swaggerProperties.getBasePath()) { basePath.add(PathSelectors.ant(path)); } // exclude-path解决 List<Predicate<String>> excludePath = new ArrayList<>(); for (String path : swaggerProperties.getExcludePath()) { excludePath.add(PathSelectors.ant(path)); } return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo) .groupName(swaggerProperties.getGroup()) .select() .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage())) .paths(Predicates.and(Predicates.not(Predicates.or(excludePath)), Predicates.or(basePath))) .build(); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; }}5. 业务相干类5.1 返回后果格局封装Resultpackage com.niewj.common.response;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import java.util.ArrayList;/** * 返回后果格局封装 * * @author nieweijun * @since 2021/6/29 18:43 */@NoArgsConstructor@AllArgsConstructor@Data@ApiModel(description = "返回后果数据封装")public class Result<T> { @ApiModelProperty(value = "返回后果code码") private Integer code; @ApiModelProperty(value = "返回后果信息形容") private String msg; @ApiModelProperty(value = "返回数据胜利标识") private Boolean success; @ApiModelProperty(value = "返回数据详情") private T data; /** * 用枚举来结构 * * @param responseEnum 应用枚举值的code和msg填充Result * @param data 数据对象 * @param ifSuccess 是否申请胜利 */ public Result(ResponseEnum responseEnum, T data, Boolean ifSuccess) { this.setCode(responseEnum.getCode()); this.setMsg(responseEnum.getMsg()); this.setData(data); this.setSuccess(ifSuccess); } /** * success={"code":200,"msg":"胜利","data":"xxx","success":true} * * @param data * @return */ public static <T> Result<T> success(T data) { return new Result<>(ResponseEnum.SUCCESS.getCode(), ResponseEnum.SUCCESS.getMsg(), Boolean.TRUE, data); } /** * success={"code":200,"msg":"胜利","data": null,"success":true} * * @return */ public static <T> Result<T> successWithNull() { return new Result<>(ResponseEnum.SUCCESS.getCode(), ResponseEnum.SUCCESS.getMsg(), Boolean.TRUE, null); } /** * success={"code":200,"msg":"胜利","data": [],"success":true} * * @return */ public static <T> Result<T> successWithEmptyList() { return (Result<T>) Result.success(new ArrayList<T>()); } /** * success=除了返回true指定, 其余的都由参数指定 * * @param code * @param msg * @param data * @param <T> * @return */ public static <T> Result<T> success(Integer code, String msg, T data) { return new Result<>(code, msg, Boolean.TRUE, data); } /** * success等价于new Result(ResponseEnum, T, true) * * @param responseEnum * @param data * @param <T> * @return */ public static <T> Result<T> success(ResponseEnum responseEnum, T data) { return new Result<>(responseEnum, data, Boolean.TRUE); } /** * fail-除了返回false, 其余的参数指定 * 例如: {"code":xxx,"msg":"xxx", "data": "指定的谬误", "success":false} * * @param data * @param <T> * @return */ public static <T> Result<T> fail(Integer code, String msg, T data) { return new Result<>(code, msg, Boolean.FALSE, data); } /** * fail-除了返回false, 其余的参数指定-由枚举类指定 * 例如: {"code":xxx,"msg":"xxx", "data": "指定的谬误", "success":false} * * @param responseEnum * @param <T> * @return */ public static <T> Result<T> fail(ResponseEnum responseEnum, T data) { return new Result<>(responseEnum.getCode(), responseEnum.getMsg(), Boolean.FALSE, data); }}5.2 响应枚举package com.niewj.common.response;/** * 响应枚举:code和message的封装(留神: code申明为int不便比拟; Integer的话须要equals!) * * @author nieweijun * @since 2021/6/29 18:51 */public enum ResponseEnum { SUCCESS(200, "胜利"), REPEAT(201, "反复操作"), BAD_REQUEST(400, "申请参数不合规"), ERROR(500, "服务器异样"), RPC_ERROR(501, "RPC服务器异样"), //=========================业务编码========================= NO_LOGIN(1001, "未登录"), RISK(1002, "零碎忙碌"), RECODE_REPEAT(1003, "有反复数据"), DATA_LACK(1004, "申请数据缺失或超时"), NO_PERMISSION(1005, "用户无权限"), // ========================RPC服务问题======================== RPC_INVOKE_ERROR(2001, "依赖服务产生异样"), RPC_DATA_INVALID(2002, "依赖服务数据有效"), RPC_INVOKE_TIMEOUT(2003, "依赖服务申请超时"), UNDER_REVIEW(2004, "预计10分钟内审核结束,请稍后再从新进入小程序"), RPC_DISASSEMBLY_FAIL(2008, "提交旧机拆解失败"), OTHER(-1, "其余"); // 申明为简略类型是为了不便用==比拟; // 200 == Integer(200) ->true // 200 == 200 -> true // Integer(200) == Integer(200) -> false private int code; private String msg; ResponseEnum(int code, String msg) { this.code = code; this.msg = msg; } public String getMsg() { return msg; } public int getCode() { return code; } public static ResponseEnum getByCode(int code) { for (ResponseEnum responseCode : ResponseEnum.values()) { if (responseCode.getCode() == code) { return responseCode; } } return ERROR; }}5.3 model-1: Menupackage com.niewj.model;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@AllArgsConstructor@NoArgsConstructor@Data@ApiModel(description = "菜单实体")public class Menu { @ApiModelProperty(value = "主键") private int id; @ApiModelProperty(value = "菜单名称") private String name;}5.3 model-2: Userpackage com.niewj.model;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@AllArgsConstructor@NoArgsConstructor@Data@ApiModel(description = "用户实体")public class User { @ApiModelProperty(value = "主键") private int id; @ApiModelProperty(value = "姓名") private String name; @ApiModelProperty(value = "年龄") private int age; @ApiModelProperty(value = "地址") private String address;}5.4 MenuControllerpackage com.niewj.controller;import com.niewj.common.response.Result;import com.niewj.model.Menu;import io.swagger.annotations.Api;import io.swagger.annotations.ApiImplicitParam;import io.swagger.annotations.ApiImplicitParams;import io.swagger.annotations.ApiOperation;import lombok.extern.slf4j.Slf4j;import org.springframework.web.bind.annotation.*;import java.util.ArrayList;import java.util.List;@RestController@RequestMapping("/menu")@Api(tags = "菜单控制器")@Slf4jpublic class MenuController { @GetMapping("/getMenus") @ApiOperation(value = "查问所有菜单", notes = "查问所有菜单信息") public Result<List<Menu>> getMenus() { log.info("getMenus success!"); List<Menu> list = new ArrayList<>(); list.add(new Menu(100, "menu100")); list.add(new Menu(101, "menu101")); list.add(new Menu(102, "menu102")); return Result.success(list); } @PostMapping("/save") @ApiOperation(value = "新增菜单", notes = "新增菜单信息") public Result<Boolean> save(@RequestBody Menu menu) { log.info("save success!"); return Result.success(Boolean.TRUE); } @PutMapping("/update") @ApiOperation(value = "批改菜单", notes = "批改菜单信息") public Result<Boolean> update(@RequestBody Menu menu) { log.info("update success!"); return Result.success(Boolean.TRUE); } @DeleteMapping("/delete") @ApiOperation(value = "删除菜单", notes = "删除菜单信息") public Result<Boolean> delete(int id) { log.info("update success!"); return Result.success(Boolean.TRUE); } @ApiImplicitParams({ @ApiImplicitParam(name = "pageNum", value = "页码", required = true, type = "Integer"), @ApiImplicitParam(name = "pageSize", value = "每页条数", required = true, type = "Integer"), }) @ApiOperation(value = "分页查问菜单信息") @GetMapping(value = "page/{pageNum}/{pageSize}") public String findByPage(@PathVariable Integer pageNum, @PathVariable Integer pageSize) { List<Menu> list = new ArrayList<>(); list.add(new Menu(100, "menu100")); list.add(new Menu(101, "menu101")); list.add(new Menu(102, "menu102")); return "OK"; }}5.5 UserControllerpackage com.niewj.controller;import com.niewj.common.response.Result;import com.niewj.model.User;import io.swagger.annotations.Api;import io.swagger.annotations.ApiImplicitParam;import io.swagger.annotations.ApiImplicitParams;import io.swagger.annotations.ApiOperation;import org.springframework.web.bind.annotation.*;import java.util.ArrayList;import java.util.List;@RestController@RequestMapping("/user")@Api(tags = "用户控制器")public class UserController { @GetMapping("/getUsers") @ApiOperation(value = "查问所有用户", notes = "查问所有用户信息") public Result<List<User>> getAllUsers() { List<User> list = new ArrayList<>(); list.add(new User(100, "小0", 20, "北京")); list.add(new User(101, "小1", 30, "北京")); list.add(new User(102, "小2", 23, "西安")); return Result.success(list); } @PostMapping("/save") @ApiOperation(value = "新增用户", notes = "新增用户信息") public Result<Boolean> save(@RequestBody User user) { return Result.success(Boolean.TRUE); } @PutMapping("/update") @ApiOperation(value = "批改用户", notes = "批改用户信息") public Result<Boolean> update(@RequestBody User user) { return Result.success(Boolean.TRUE); } @DeleteMapping("/delete") @ApiOperation(value = "删除用户", notes = "删除用户信息") public Result<Boolean> delete(int id) { return Result.success(Boolean.TRUE); } @ApiImplicitParams({ @ApiImplicitParam(name = "pageNum", value = "页码", required = true, type = "Integer"), @ApiImplicitParam(name = "pageSize", value = "每页条数", required = true, type = "Integer"), }) @ApiOperation(value = "分页查问用户信息") @GetMapping(value = "page/{pageNum}/{pageSize}") public Result<List<User>> findByPage(@PathVariable Integer pageNum, @PathVariable Integer pageSize) { List<User> list = new ArrayList<>(); list.add(new User(100, "小0", 20, "北京")); list.add(new User(101, "小1", 30, "北京")); list.add(new User(102, "小2", 23, "西安")); return Result.success(list); }}5.6 启动类package com.niewj;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import springfox.documentation.swagger2.annotations.EnableSwagger2;@SpringBootApplicationpublic class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); }}5.7 启动后拜访拜访地址: http://localhost:8081/doc.html即可
...