浏览代码

springdoc

RuoYi 1 年之前
父节点
当前提交
c65919c600

+ 8 - 0
pom.xml

@@ -29,6 +29,7 @@
         <commons.io.version>2.13.0</commons.io.version>
         <poi.version>4.1.2</poi.version>
         <velocity.version>2.3</velocity.version>
+        <springdoc.version>2.5.0</springdoc.version>
     </properties>
 
     <!-- 依赖声明 -->
@@ -142,6 +143,13 @@
                 <version>${oshi.version}</version>
             </dependency>
 
+            <!-- spring-doc -->
+            <dependency>
+                <groupId>org.springdoc</groupId>
+                <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
+                <version>${springdoc.version}</version>
+            </dependency>
+
             <!-- io常用工具类 -->
             <dependency>
                 <groupId>commons-io</groupId>

+ 6 - 0
ruoyi-admin/pom.xml

@@ -30,6 +30,12 @@
             <optional>true</optional> <!-- 表示依赖不会传递 -->
         </dependency>
 
+        <!-- spring-doc -->
+        <dependency>
+            <groupId>org.springdoc</groupId>
+            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
+        </dependency>
+
         <!-- Mysql驱动包 -->
         <dependency>
             <groupId>com.mysql</groupId>

+ 175 - 183
ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java

@@ -1,183 +1,175 @@
-//package com.ruoyi.web.controller.tool;
-//
-//import java.util.ArrayList;
-//import java.util.LinkedHashMap;
-//import java.util.List;
-//import java.util.Map;
-//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 com.ruoyi.common.core.controller.BaseController;
-//import com.ruoyi.common.core.domain.R;
-//import com.ruoyi.common.utils.StringUtils;
-//import io.swagger.annotations.Api;
-//import io.swagger.annotations.ApiImplicitParam;
-//import io.swagger.annotations.ApiImplicitParams;
-//import io.swagger.annotations.ApiModel;
-//import io.swagger.annotations.ApiModelProperty;
-//import io.swagger.annotations.ApiOperation;
-//
-///**
-// * swagger 用户测试方法
-// * 
-// * @author ruoyi
-// */
-//@Api("用户信息管理")
-//@RestController
-//@RequestMapping("/test/user")
-//public class TestController extends BaseController
-//{
-//    private final static Map<Integer, UserEntity> users = new LinkedHashMap<Integer, UserEntity>();
-//    {
-//        users.put(1, new UserEntity(1, "admin", "admin123", "15888888888"));
-//        users.put(2, new UserEntity(2, "ry", "admin123", "15666666666"));
-//    }
-//
-//    @ApiOperation("获取用户列表")
-//    @GetMapping("/list")
-//    public R<List<UserEntity>> userList()
-//    {
-//        List<UserEntity> userList = new ArrayList<UserEntity>(users.values());
-//        return R.ok(userList);
-//    }
-//
-//    @ApiOperation("获取用户详细")
-//    @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
-//    @GetMapping("/{userId}")
-//    public R<UserEntity> getUser(@PathVariable Integer userId)
-//    {
-//        if (!users.isEmpty() && users.containsKey(userId))
-//        {
-//            return R.ok(users.get(userId));
-//        }
-//        else
-//        {
-//            return R.fail("用户不存在");
-//        }
-//    }
-//
-//    @ApiOperation("新增用户")
-//    @ApiImplicitParams({
-//        @ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", dataTypeClass = Integer.class),
-//        @ApiImplicitParam(name = "username", value = "用户名称", dataType = "String", dataTypeClass = String.class),
-//        @ApiImplicitParam(name = "password", value = "用户密码", dataType = "String", dataTypeClass = String.class),
-//        @ApiImplicitParam(name = "mobile", value = "用户手机", dataType = "String", dataTypeClass = String.class)
-//    })
-//    @PostMapping("/save")
-//    public R<String> save(UserEntity user)
-//    {
-//        if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
-//        {
-//            return R.fail("用户ID不能为空");
-//        }
-//        users.put(user.getUserId(), user);
-//        return R.ok();
-//    }
-//
-//    @ApiOperation("更新用户")
-//    @PutMapping("/update")
-//    public R<String> update(@RequestBody UserEntity user)
-//    {
-//        if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
-//        {
-//            return R.fail("用户ID不能为空");
-//        }
-//        if (users.isEmpty() || !users.containsKey(user.getUserId()))
-//        {
-//            return R.fail("用户不存在");
-//        }
-//        users.remove(user.getUserId());
-//        users.put(user.getUserId(), user);
-//        return R.ok();
-//    }
-//
-//    @ApiOperation("删除用户信息")
-//    @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
-//    @DeleteMapping("/{userId}")
-//    public R<String> delete(@PathVariable Integer userId)
-//    {
-//        if (!users.isEmpty() && users.containsKey(userId))
-//        {
-//            users.remove(userId);
-//            return R.ok();
-//        }
-//        else
-//        {
-//            return R.fail("用户不存在");
-//        }
-//    }
-//}
-//
-//@ApiModel(value = "UserEntity", description = "用户实体")
-//class UserEntity
-//{
-//    @ApiModelProperty("用户ID")
-//    private Integer userId;
-//
-//    @ApiModelProperty("用户名称")
-//    private String username;
-//
-//    @ApiModelProperty("用户密码")
-//    private String password;
-//
-//    @ApiModelProperty("用户手机")
-//    private String mobile;
-//
-//    public UserEntity()
-//    {
-//
-//    }
-//
-//    public UserEntity(Integer userId, String username, String password, String mobile)
-//    {
-//        this.userId = userId;
-//        this.username = username;
-//        this.password = password;
-//        this.mobile = mobile;
-//    }
-//
-//    public Integer getUserId()
-//    {
-//        return userId;
-//    }
-//
-//    public void setUserId(Integer userId)
-//    {
-//        this.userId = userId;
-//    }
-//
-//    public String getUsername()
-//    {
-//        return username;
-//    }
-//
-//    public void setUsername(String username)
-//    {
-//        this.username = username;
-//    }
-//
-//    public String getPassword()
-//    {
-//        return password;
-//    }
-//
-//    public void setPassword(String password)
-//    {
-//        this.password = password;
-//    }
-//
-//    public String getMobile()
-//    {
-//        return mobile;
-//    }
-//
-//    public void setMobile(String mobile)
-//    {
-//        this.mobile = mobile;
-//    }
-//}
+package com.ruoyi.web.controller.tool;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+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 com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.utils.StringUtils;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+/**
+ * swagger 用户测试方法
+ *
+ * @author ruoyi
+ */
+@Tag(name = "用户信息管理")
+@RestController
+@RequestMapping("/test/user")
+public class TestController extends BaseController
+{
+    private final static Map<Integer, UserEntity> users = new LinkedHashMap<Integer, UserEntity>();
+    {
+        users.put(1, new UserEntity(1, "admin", "admin123", "15888888888"));
+        users.put(2, new UserEntity(2, "ry", "admin123", "15666666666"));
+    }
+    
+    @Operation(summary = "获取用户列表")
+    @GetMapping("/list")
+    public R<List<UserEntity>> userList()
+    {
+        List<UserEntity> userList = new ArrayList<UserEntity>(users.values());
+        return R.ok(userList);
+    }
+    
+    @Operation(summary = "获取用户详细")
+    @GetMapping("/{userId}")
+    public R<UserEntity> getUser(@PathVariable(name = "userId")
+    Integer userId)
+    {
+        if (!users.isEmpty() && users.containsKey(userId))
+        {
+            return R.ok(users.get(userId));
+        }
+        else
+        {
+            return R.fail("用户不存在");
+        }
+    }
+    
+    @Operation(summary = "新增用户")
+    @PostMapping("/save")
+    public R<String> save(UserEntity user)
+    {
+        if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
+        {
+            return R.fail("用户ID不能为空");
+        }
+        users.put(user.getUserId(), user);
+        return R.ok();
+    }
+    
+    @Operation(summary = "更新用户")
+    @PutMapping("/update")
+    public R<String> update(@RequestBody
+    UserEntity user)
+    {
+        if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
+        {
+            return R.fail("用户ID不能为空");
+        }
+        if (users.isEmpty() || !users.containsKey(user.getUserId()))
+        {
+            return R.fail("用户不存在");
+        }
+        users.remove(user.getUserId());
+        users.put(user.getUserId(), user);
+        return R.ok();
+    }
+    
+    @Operation(summary = "删除用户信息")
+    @DeleteMapping("/{userId}")
+    public R<String> delete(@PathVariable(name = "userId")
+    Integer userId)
+    {
+        if (!users.isEmpty() && users.containsKey(userId))
+        {
+            users.remove(userId);
+            return R.ok();
+        }
+        else
+        {
+            return R.fail("用户不存在");
+        }
+    }
+}
+
+@Schema(description = "用户实体")
+class UserEntity
+{
+    @Schema(title = "用户ID")
+    private Integer userId;
+    
+    @Schema(title = "用户名称")
+    private String username;
+    
+    @Schema(title = "用户密码")
+    private String password;
+    
+    @Schema(title = "用户手机")
+    private String mobile;
+    
+    public UserEntity()
+    {
+        
+    }
+    
+    public UserEntity(Integer userId, String username, String password, String mobile)
+    {
+        this.userId = userId;
+        this.username = username;
+        this.password = password;
+        this.mobile = mobile;
+    }
+    
+    public Integer getUserId()
+    {
+        return userId;
+    }
+    
+    public void setUserId(Integer userId)
+    {
+        this.userId = userId;
+    }
+    
+    public String getUsername()
+    {
+        return username;
+    }
+    
+    public void setUsername(String username)
+    {
+        this.username = username;
+    }
+    
+    public String getPassword()
+    {
+        return password;
+    }
+    
+    public void setPassword(String password)
+    {
+        this.password = password;
+    }
+    
+    public String getMobile()
+    {
+        return mobile;
+    }
+    
+    public void setMobile(String mobile)
+    {
+        this.mobile = mobile;
+    }
+}

+ 65 - 67
ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java

@@ -1,67 +1,65 @@
-//package com.ruoyi.web.core.config;
-//
-//import org.springframework.beans.factory.annotation.Value;
-//import org.springframework.context.annotation.Bean;
-//import org.springframework.context.annotation.Configuration;
-//import com.ruoyi.common.config.RuoYiConfig;
-//import io.swagger.annotations.ApiOperation;
-//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;
-//
-///**
-// * Swagger2的接口配置
-// * 
-// * @author ruoyi
-// */
-//@Configuration
-//public class SwaggerConfig
-//{
-//    /** 是否开启swagger */
-//    @Value("${swagger.enabled}")
-//    private boolean enabled;
-//    
-//    /**
-//     * 创建API
-//     */
-//    @Bean
-//    public Docket createRestApi()
-//    {
-//        return new Docket(DocumentationType.OAS_30)
-//                // 是否启用Swagger
-//                .enable(enabled)
-//                // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息)
-//                .apiInfo(apiInfo())
-//                // 设置哪些接口暴露给Swagger展示
-//                .select()
-//                // 扫描所有有注解的api,用这种方式更灵活
-//                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
-//                // 扫描指定包中的swagger注解
-//                //.apis(RequestHandlerSelectors.basePackage("com.ruoyi.project.tool.swagger"))
-//                // 扫描所有 .apis(RequestHandlerSelectors.any())
-//                .paths(PathSelectors.any())
-//                .build();
-//    }
-//
-//    /**
-//     * 添加摘要信息
-//     */
-//    private ApiInfo apiInfo()
-//    {
-//        // 用ApiInfoBuilder进行定制
-//        return new ApiInfoBuilder()
-//                // 设置标题
-//                .title("标题:若依管理系统_接口文档")
-//                // 描述
-//                .description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...")
-//                // 作者信息
-//                .contact(new Contact(RuoYiConfig.getName(), null, null))
-//                // 版本
-//                .version("版本号:" + RuoYiConfig.getVersion())
-//                .build();
-//    }
-//}
+package com.ruoyi.web.core.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import com.ruoyi.common.config.RuoYiConfig;
+import io.swagger.v3.oas.models.Components;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Contact;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.security.SecurityRequirement;
+import io.swagger.v3.oas.models.security.SecurityScheme;
+
+/**
+ * Swagger2的接口配置
+ * 
+ * @author ruoyi
+ */
+@Configuration
+public class SwaggerConfig
+{
+    /** 系统基础配置 */
+    @Autowired
+    private RuoYiConfig ruoyiConfig;
+    
+    /**
+     * 自定义的 OpenAPI 对象
+     */
+    @Bean
+    public OpenAPI customOpenApi()
+    {
+        return new OpenAPI().components(new Components()
+            // 设置认证的请求头
+            .addSecuritySchemes("apikey", securityScheme()))
+            .addSecurityItem(new SecurityRequirement().addList("apikey"))
+            .info(getApiInfo());
+    }
+    
+    @Bean
+    public SecurityScheme securityScheme()
+    {
+        return new SecurityScheme()
+            .type(SecurityScheme.Type.APIKEY)
+            .name("Authorization")
+            .in(SecurityScheme.In.HEADER)
+            .scheme("Bearer");
+    }
+    
+    /**
+     * 添加摘要信息
+     */
+    @SuppressWarnings("static-access")
+    public Info getApiInfo()
+    {
+        return new Info()
+            // 设置标题
+            .title("标题:若依管理系统_接口文档")
+            // 描述
+            .description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...")
+            // 作者信息
+            .contact(new Contact().name(ruoyiConfig.getName()))
+            // 版本
+            .version("版本号:" + ruoyiConfig.getVersion());
+    }
+}

+ 14 - 0
ruoyi-admin/src/main/resources/application.yml

@@ -127,6 +127,20 @@ shiro:
     # 是否开启记住我
     enabled: true
 
+# Springdoc配置
+springdoc:
+  api-docs:
+    path: /v3/api-docs
+  swagger-ui:
+    enabled: true
+    path: /swagger-ui.html
+    tags-sorter: alpha
+  group-configs:
+    - group: 'default'
+      display-name: '测试模块'
+      paths-to-match: '/**'
+      packages-to-scan: com.ruoyi.web.controller.tool
+
 # 防止XSS攻击
 xss:
   # 过滤开关

+ 1 - 1
ruoyi-framework/pom.xml

@@ -42,7 +42,7 @@
             <exclusions>
                 <exclusion>
                     <artifactId>servlet-api</artifactId>
-                    <groupId>jakarta.servlet</groupId>
+                    <groupId>javax.servlet</groupId>
                 </exclusion>
             </exclusions>
         </dependency>

+ 0 - 8
ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java

@@ -4,7 +4,6 @@ import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.LinkedHashMap;
-import java.util.List;
 import java.util.Map;
 import org.apache.commons.io.IOUtils;
 import org.apache.shiro.cache.ehcache.EhCacheManager;
@@ -25,7 +24,6 @@ import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.security.CipherUtils;
 import com.ruoyi.common.utils.spring.SpringUtils;
-import com.ruoyi.framework.config.properties.PermitAllUrlProperties;
 import com.ruoyi.framework.shiro.realm.UserRealm;
 import com.ruoyi.framework.shiro.session.OnlineSessionDAO;
 import com.ruoyi.framework.shiro.session.OnlineSessionFactory;
@@ -290,12 +288,6 @@ public class ShiroConfig
         filterChainDefinitionMap.put("/js/**", "anon");
         filterChainDefinitionMap.put("/ruoyi/**", "anon");
         filterChainDefinitionMap.put("/captcha/captchaImage**", "anon");
-        // 匿名访问不鉴权注解列表
-        List<String> permitAllUrl = SpringUtils.getBean(PermitAllUrlProperties.class).getUrls();
-        if (StringUtils.isNotEmpty(permitAllUrl))
-        {
-            permitAllUrl.forEach(url -> filterChainDefinitionMap.put(url, "anon"));
-        }
         // 退出 logout地址,shiro去清除session
         filterChainDefinitionMap.put("/logout", "logout");
         // 不需要拦截的访问

+ 0 - 122
ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/PermitAllUrlProperties.java

@@ -1,122 +0,0 @@
-package com.ruoyi.framework.config.properties;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import org.springframework.aop.framework.Advised;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import com.ruoyi.common.annotation.Anonymous;
-
-/**
- * 设置Anonymous注解允许匿名访问的url
- * 
- * @author ruoyi
- */
-@Configuration
-public class PermitAllUrlProperties implements InitializingBean, ApplicationContextAware
-{
-    private List<String> urls = new ArrayList<>();
-
-    private ApplicationContext applicationContext;
-
-    @Override
-    public void afterPropertiesSet() throws Exception
-    {
-        Map<String, Object> controllers = applicationContext.getBeansWithAnnotation(Controller.class);
-        for (Object bean : controllers.values())
-        {
-            if (!(bean instanceof Advised))
-            {
-                continue;
-            }
-            Class<?> beanClass = ((Advised) bean).getTargetSource().getTarget().getClass();
-            RequestMapping base = beanClass.getAnnotation(RequestMapping.class);
-            String[] baseUrl = {};
-            if (Objects.nonNull(base))
-            {
-                baseUrl = base.value();
-            }
-            Method[] methods = beanClass.getDeclaredMethods();
-            for (Method method : methods)
-            {
-                if (method.isAnnotationPresent(Anonymous.class) && method.isAnnotationPresent(RequestMapping.class))
-                {
-                    RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
-                    String[] uri = requestMapping.value();
-                    urls.addAll(rebuildUrl(baseUrl, uri));
-                }
-                else if (method.isAnnotationPresent(Anonymous.class) && method.isAnnotationPresent(GetMapping.class))
-                {
-                    GetMapping requestMapping = method.getAnnotation(GetMapping.class);
-                    String[] uri = requestMapping.value();
-                    urls.addAll(rebuildUrl(baseUrl, uri));
-                }
-                else if (method.isAnnotationPresent(Anonymous.class) && method.isAnnotationPresent(PostMapping.class))
-                {
-                    PostMapping requestMapping = method.getAnnotation(PostMapping.class);
-                    String[] uri = requestMapping.value();
-                    urls.addAll(rebuildUrl(baseUrl, uri));
-                }
-                else if (method.isAnnotationPresent(Anonymous.class) && method.isAnnotationPresent(PutMapping.class))
-                {
-                    PutMapping requestMapping = method.getAnnotation(PutMapping.class);
-                    String[] uri = requestMapping.value();
-                    urls.addAll(rebuildUrl(baseUrl, uri));
-                }
-                else if (method.isAnnotationPresent(Anonymous.class) && method.isAnnotationPresent(DeleteMapping.class))
-                {
-                    DeleteMapping requestMapping = method.getAnnotation(DeleteMapping.class);
-                    String[] uri = requestMapping.value();
-                    urls.addAll(rebuildUrl(baseUrl, uri));
-                }
-            }
-
-        }
-    }
-
-    private List<String> rebuildUrl(String[] bases, String[] uris)
-    {
-        List<String> urls = new ArrayList<>();
-        for (String base : bases)
-        {
-            for (String uri : uris)
-            {
-                urls.add(prefix(base) + prefix(uri));
-            }
-        }
-        return urls;
-    }
-
-    private String prefix(String seg)
-    {
-        return seg.startsWith("/") ? seg : "/" + seg;
-    }
-
-    @Override
-    public void setApplicationContext(ApplicationContext context) throws BeansException
-    {
-        this.applicationContext = context;
-    }
-
-    public List<String> getUrls()
-    {
-        return urls;
-    }
-
-    public void setUrls(List<String> urls)
-    {
-        this.urls = urls;
-    }
-}