当前位置: 首页 > article >正文

基于Jeecg-boot开发系统--后端篇

背景

Jeecg-boot是一个后台管理系统,其提供能很多基础的功能,我希望在不修改jeecg-boot代码的前提下增加自己的功能。经过几天的折腾终于搞定了。
首先是基于jeecg-boot微服务的方式来扩展的,jeecg-boot微服务本身的搭建过程就不讲了,主要讲增加的功能如何与jeecg-boot集成在一起。先说步骤:

1.依赖

<parent>
    <groupId>org.jeecgframework.boot</groupId>
    <artifactId>jeecg-boot-parent</artifactId>
    <version>3.7.0</version>
</parent>

<dependency>
    <groupId>org.jeecgframework.boot</groupId>
    <artifactId>jeecg-boot-starter-cloud</artifactId>
</dependency>
<dependency>
    <groupId>org.jeecgframework.boot</groupId>
    <artifactId>jeecg-boot-base-core</artifactId>
</dependency>
<dependency>
    <groupId>org.jeecgframework.boot</groupId>
    <artifactId>jeecg-system-cloud-api</artifactId>
</dependency>
<!-- 加载了上面几个 jeecg-boot核心的就有了,包括授权之类的。  其他按需加载 -->

2.配置

@Slf4j
@EnableFeignClients
@SpringBootApplication
@MapperScan(value={"com.snail.**.mapper*","org.jeecg.**.mapper*"})  // mybatis集成
@ComponentScan(value= {"com.snail","org.jeecg"},excludeFilters = {@ComponentScan.Filter(type= FilterType.ASSIGNABLE_TYPE,classes = {Swagger2Config.class})}) // 重写Swagger2Config
public class SnailDemoApplication extends SpringBootServletInitializer implements CommandLineRunner {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(SnailDemoApplication.class);
    }

    public static void main(String[] args) throws UnknownHostException {
        ConfigurableApplicationContext application = SpringApplication.run(SnailDemoApplication.class, args);
        Environment env = application.getEnvironment();
        String ip = InetAddress.getLocalHost().getHostAddress();
        String port = env.getProperty("server.port");
        String path = StrUtil.blankToDefault(env.getProperty("server.servlet.context-path"),"");
        log.info("\n----------------------------------------------------------\n\t" +
                "Application Jeecg-Boot is running! Access URLs:\n\t" +
                "Local: \t\thttp://localhost:" + port + path + "/\n\t" +
                "External: \thttp://" + ip + ":" + port + path + "/\n\t" +
                "Swagger文档: \thttp://" + ip + ":" + port + path + "/doc.html\n" +
                "----------------------------------------------------------");

    }

    @Override
    public void run(String... args) throws Exception {
        BaseMap params = new BaseMap();
        params.put(GlobalConstants.HANDLER_NAME, GlobalConstants.LODER_ROUDER_HANDLER);
        //刷新网关
        redisTemplate.convertAndSend(GlobalConstants.REDIS_TOPIC_NAME, params);
    }
}

3. swagger 集成

a. 系统管理–>网关路由 : 增加一条记录。(不增加的话,无法在网关上显示).

b. 重写swagger配置文件,主要用于修改swagger上的显示信息及修改扫描的包,若使用的包是org.jeecg又不用改显示信息的话,则不需要重写

c. 若重写了Swagger2Config,则需要禁用原来的Swagger2Config类。在启动类通过excludeFilters排除即可。

package com.snail.demo.config;

import springfox.documentation.RequestHandler;
import io.swagger.annotations.ApiOperation;
import org.jeecg.common.constant.CommonConstant;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import java.util.stream.Collectors;


@EnableSwagger2WebMvc
@Configuration
@Import(BeanValidatorPluginsConfiguration.class)
public class Swagger2Config implements WebMvcConfigurer {

    /**
     * 显示swagger-ui.html文档展示页,还必须注入swagger资源:
     *
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    /**
     * swagger2的配置文件,这里可以配置swagger2的一些基本的内容,比如扫描的包等等
     *
     * @return Docket
     */
    @Bean(value = "defaultApi2", autowireCandidate = true)
    public Docket defaultApi2() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                //此包路径下的类,才生成接口文档
//                .apis(RequestHandlerSelectors.basePackage("com.snail")) // 单个包,使用这个就可以了,
                .apis(basePackage("com.snail;org.jeecg"))  // 需要多个包时使用这个方式
                //加了ApiOperation注解的类,才生成接口文档
                .apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                .paths(PathSelectors.any())
                .build()
                .securitySchemes(Collections.singletonList(securityScheme()))
                .securityContexts(securityContexts())
                .globalOperationParameters(setHeaderToken())
                .pathMapping("/jeecg-demo2");
    }

    public static Predicate<RequestHandler> basePackage(final String basePackage) {
        return input -> declaringClass(input).transform(handlerPackage(basePackage)).or(true);
    }


    private static Function<Class<?>, Boolean> handlerPackage(final String basePackage) {
        return input -> {
            // 循环判断匹配
            for (String strPackage : basePackage.split(";")) {
                boolean isMatch = input.getPackage().getName().startsWith(strPackage);
                if (isMatch) {
                    return true;
                }
            }
            return false;
        };
    }

    private static Optional<? extends Class<?>> declaringClass(RequestHandler input) {
        return Optional.fromNullable(input.declaringClass());
    }

    /***
     * oauth2配置
     * 需要增加swagger授权回调地址
     * http://localhost:8888/webjars/springfox-swagger-ui/o2c.html
     * @return
     */
    @Bean(autowireCandidate = true)
    SecurityScheme securityScheme() {
        return new ApiKey(CommonConstant.X_ACCESS_TOKEN, CommonConstant.X_ACCESS_TOKEN, "header");
    }

    /**
     * JWT token
     *
     * @return
     */
    private List<Parameter> setHeaderToken() {
        ParameterBuilder tokenPar = new ParameterBuilder();
        List<Parameter> pars = new ArrayList<>();
        tokenPar.name(CommonConstant.X_ACCESS_TOKEN).description("token").modelRef(new ModelRef("string")).parameterType("header").required(false).build();
        pars.add(tokenPar.build());
        return pars;
    }

    /**
     * api文档的详细信息函数,注意这里的注解引用的是哪个
     *
     * @return
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                // //大标题
                .title("测试测试")
                // 版本号
                .version("1.0")
//				.termsOfServiceUrl("NO terms of service")
                // 描述
                .description("后台API接口")
                // 作者
                .contact(new Contact("xxxx", "www.llf.com", "shui878412@126.com"))
                .license("xxxx")
                .licenseUrl("ccccc")
                .build();
    }

    /**
     * 新增 securityContexts 保持登录状态
     */
    private List<SecurityContext> securityContexts() {
        return new ArrayList(
                Collections.singleton(SecurityContext.builder()
                        .securityReferences(defaultAuth())
                        .forPaths(PathSelectors.regex("^(?!auth).*$"))
                        .build())
        );
    }

    private List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        return new ArrayList(
                Collections.singleton(new SecurityReference(CommonConstant.X_ACCESS_TOKEN, authorizationScopes)));
    }

    /**
     * 解决springboot2.6 和springfox不兼容问题
     *
     * @return
     */
    @Bean()
    public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
        return new BeanPostProcessor() {

            @Override
            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                if (bean instanceof WebMvcRequestHandlerProvider) {
                    customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
                }
                return bean;
            }

            private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
                List<T> copy = mappings.stream()
                        .filter(mapping -> mapping.getPatternParser() == null)
                        .collect(Collectors.toList());
                mappings.clear();
                mappings.addAll(copy);
            }

            @SuppressWarnings("unchecked")
            private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
                try {
                    Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
                    field.setAccessible(true);
                    return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
                } catch (IllegalArgumentException | IllegalAccessException e) {
                    throw new IllegalStateException(e);
                }
            }
        };
    }

}


http://www.kler.cn/a/319936.html

相关文章:

  • iOS - TLS(线程本地存储)
  • SurfaceFlinger代码笔记
  • Vulnhub DC-8靶机攻击实战(一)
  • ASP.NET Core - .NET 6 以上版本的入口文件
  • Redis集群部署详解:主从复制、Sentinel哨兵模式与Cluster集群的工作原理与配置
  • vue项目引入阿里云svg资源图标
  • OpenHarmony(鸿蒙南向)——平台驱动开发【PIN】
  • Linux系统安装和配置 VNC 服务器
  • C语言 | Leetcode C语言题解之第423题从英文中重建数字
  • Trapezoidal Decomposition梯形分解算法(TCD)
  • 【Linux实践】实验四:Shell实用功能及文件权限
  • PHP API 框架:构建高效API的利器
  • spark读取数据性能提升
  • PostgreSQL技术内幕12:PostgreSQL事务原理解析-锁管理
  • 【Axure视频教程】跨页面控制中继器表格
  • 商城小程序后端开发实践中出现的问题及其解决方法
  • 【算法——双指针】
  • 机器学习中的KNN算法:原理、应用与实践
  • xpath在爬虫中的应用、xpath插件的安装及使用
  • Python爬虫-Post请求中,参数只有value没有key,如何正确处理?
  • 关联式容器——map与set
  • 集合ArrayList常用方法
  • 鸿蒙界面开发——组件(9):进度条Progress 滑动条Slider
  • 开源数据集网站合集
  • 初试Bootstrap前端框架
  • Spring Boot房屋租赁平台:现代化解决方案