ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

springboot插件模式

2022-09-12 14:30:20  阅读:224  来源: 互联网

标签:插件 designer springboot runachina 模式 sc import com public


自定义一个validator

package com.runachina.sc.designer.domain.validator;

import com.runachina.sc.designer.domain.validator.annotations.IconExist;
import com.runachina.sc.designer.domain.validator.utils.IconExistDataStore;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

/**
 * lcx
 * 校验icon的引用是否存在 - icon存在性校验
 */
public class IconExistValidator implements ConstraintValidator<IconExist, String> {

    /**
     * initialize 在注解设置参数时会调用,如果没有设置参数,只调用一次默认的初始化
     * @IconExist 只调用一次 initialize,默认的初始化
     * @IconExist(message = "123") 每设置一次调用一次,多个对象实例的校验也只会调用一次
     */

    @Override
    public void initialize(IconExist iconExist) {
        ConstraintValidator.super.initialize(iconExist);
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
        if (value == null || value.trim().length() == 0) {
            return true;
        }
        return IconExistDataStore.iconCodeExist(value);
    }

}
package com.runachina.sc.designer.domain.validator.annotations;

import com.runachina.sc.designer.domain.validator.IconExistValidator;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Target({ ElementType.FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = IconExistValidator.class)
public @interface IconExist {

    String message() default "图标不存在";

    Class<?>[] groups() default { };

    Class<? extends Payload>[] payload() default { };

}

 

 

自定义的validator需要查库,判断数据是否存在,每次查库的效率比较低,这里采用一次性全部查出来,放到线程变量中,为了保证线程数据一定会被清空,写了一个filter

package com.runachina.sc.designer.filter;

import com.runachina.sc.designer.domain.validator.utils.IconExistDataStore;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter(filterName = "baseFilter", urlPatterns = {"/*"})
@Component
public class BaseFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        filterChain.doFilter(servletRequest, servletResponse);
        IconExistDataStore.removeThreadData();
    }

    @Override
    public void destroy() {

    }
}

说实话,我自己也觉得这么做不好,因为不好维护,谁也不会知道这里会有这样一行代码,作为这样一个功能。

而插件式开发,就可以用插件的方式维护好自己的功能,不牵扯任何其他地方

https://www.cnblogs.com/strongmore/p/15248730.html

<dependency>
   <groupId>org.springframework.plugin</groupId>
   <artifactId>spring-plugin-core</artifactId>
   <version>2.0.0.RELEASE</version>
</dependency>

 

package com.runachina.sc.designer.plugin;

import com.runachina.sc.designer.core.event.hooks.AppSchemaOperateContext;
import com.runachina.sc.designer.core.event.hooks.AppSchemaOperateFilter;
import com.runachina.sc.designer.core.event.hooks.AppSchemaOperateType;
import com.runachina.sc.designer.domain.validator.utils.IconExistDataStore;
import com.runachina.sc.material.client.feign.IconClient;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;

@Slf4j
@AllArgsConstructor
@Component
public class IconExistValidationPlugin implements AppSchemaOperateFilter {

    private final IconClient iconClient;

    @Override
    public boolean supports(AppSchemaOperateType delimiter) {
        return AppSchemaOperateType.VALIDATE.equals(delimiter);
    }

    @Override
    public void onBeforeOperate(AppSchemaOperateContext context) {
        List<String> list = iconClient.getAllIconCode();
        IconExistDataStore.setIconCodeList(list);
    }

    @Override
    public void onAfterOperate(AppSchemaOperateContext context) {
        IconExistDataStore.removeThreadData();
    }

}

 

public List<ValidateProblem> validateApp(ApplicationAggregate aggregate) {
        // 校验
        AppSchemaOperateContext context = AppSchemaOperateContext.validate(Collections.singletonList(aggregate), designerPluginManager);
        List<ValidateProblem> problems = context.getValidateProblems(aggregate.getBaseInfo().getCode());
        return problems;
    }
package com.runachina.sc.designer.core.event.hooks;

import com.runachina.cloud.starter.base.session.RunaCloudSession;
import com.runachina.sc.designer.core.configuration.DesignerPluginManager;
import com.runachina.sc.designer.core.entity.AppVersionEntity;
import com.runachina.sc.designer.core.entity.ReleaseLogEntity;
import com.runachina.sc.designer.core.validate.ValidateProblem;
import com.runachina.sc.designer.core.validate.ValidateUtil;
import com.runachina.sc.designer.domain.aggregate.ApplicationAggregate;
import com.runachina.sc.designer.domain.enums.event.release.ReleaseStatus;
import lombok.Getter;
import org.springframework.util.CollectionUtils;

import java.util.*;

public class AppSchemaOperateContext {

    /**
     * Current Session
     */
    @Getter
    private final RunaCloudSession session;

    /**
     * App schemas to operate!
     */
    private final Map<String, ApplicationAggregate> appSchemas = new HashMap<>();

    /**
     * Key:AppCode
     * Value:APP validate problems
     */

    private final Map<String, List<ValidateProblem>> validateProblems = new HashMap<>();

    /**
     * 应用保存记录
     * Key: APpCode
     * Value: ReleaseLogEntity
     */
    private Map<String, AppVersionEntity> saveLogs = new HashMap<>();

    /**
     * 应用发布记录
     * Key: APpCode
     * Value: ReleaseLogEntity
     */
    private Map<String, ReleaseLogEntity> releaseLogs = new HashMap<>();

    public AppSchemaOperateContext(RunaCloudSession session) {
        this.session = session;
    }

    public static AppSchemaOperateContext validate(List<ApplicationAggregate> appSchemas, DesignerPluginManager plugins) {

        AppSchemaOperateContext context = new AppSchemaOperateContext(RunaCloudSession.get());
        context.setAppSchemas(appSchemas);

        plugins.getOperateFilters().getPluginsFor(AppSchemaOperateType.VALIDATE).forEach(hoos -> hoos.onBeforeOperate(context));

        for (ApplicationAggregate appSchema : appSchemas) {
            context.setValidateProblems(appSchema.getCode(), ValidateUtil.getAppProblems(appSchema));
        }

        plugins.getOperateFilters().getPluginsFor(AppSchemaOperateType.VALIDATE).forEach(hoos -> hoos.onAfterOperate(context));

        return context;
    }

    public Collection<ApplicationAggregate> getAppSchemas(){
        return appSchemas.values();
    }

    public void setAppSchemas(List<ApplicationAggregate> apps){
        apps.forEach(app -> appSchemas.put(app.getCode(), app));
    }

    public void setValidateProblems(String appCode, List<ValidateProblem> appProblems) {
        validateProblems.put(appCode, appProblems);

        if(saveLogs.containsKey(appCode)){
            saveLogs.get(appCode).setProblems(appProblems);
        }
    }

    public void addValidateProblems(String appCode, List<ValidateProblem> problems) {

        List<ValidateProblem> oldProblems = validateProblems.get(appCode);

        if(CollectionUtils.isEmpty(oldProblems)){
            setValidateProblems(appCode, problems);
        } else {
            oldProblems.addAll(problems);
            setValidateProblems(appCode, oldProblems);
        }
    }

    public List<ValidateProblem> getValidateProblems(String appCode) {
        return validateProblems.get(appCode);
    }

    public ReleaseLogEntity addReleaseLog(ApplicationAggregate application) {

        //保存发布记录
        ReleaseLogEntity releaseLog = new ReleaseLogEntity();
        releaseLog.setId(UUID.randomUUID().toString());
        releaseLog.setAppCode(application.getCode());
        releaseLog.setAppName(application.getBaseInfo().getName());
        releaseLog.setAppVersion(application.getBaseInfo().getVersion());
        releaseLog.setStatus(ReleaseStatus.ON_RELEASE);

        releaseLogs.put(application.getCode(), releaseLog);

        return releaseLog;
    }

    public AppVersionEntity addSaveLog(ApplicationAggregate application) {

        // 保存版本记录
        AppVersionEntity appVersion = new AppVersionEntity();
        appVersion.setAppVersion(application.getBaseInfo().getVersion());
        appVersion.setAppCode(application.getCode());
        appVersion.setAppName(application.getBaseInfo().getName());
        appVersion.setProblems(validateProblems.get(application.getCode()));

        saveLogs.put(application.getCode(), appVersion);

        return appVersion;
    }

    public Collection<AppVersionEntity> getSaveLogs() {
        return saveLogs.values();
    }

    public AppVersionEntity getSaveLog(String appCode) {
        return saveLogs.get(appCode);
    }

    public ReleaseLogEntity getReleaseLog(String appCode) {
        return releaseLogs.get(appCode);
    }

    public ApplicationAggregate getAppSchema(String appCode) {
        return appSchemas.get(appCode);
    }
}
package com.runachina.sc.designer.core.configuration;

import com.runachina.sc.designer.core.event.hooks.AppEventListener;
import com.runachina.sc.designer.core.event.hooks.AppEventType;
import com.runachina.sc.designer.core.event.hooks.AppSchemaOperateFilter;
import com.runachina.sc.designer.core.event.hooks.AppSchemaOperateType;
import com.runachina.sc.designer.core.domain.EntityDesigner;
import com.runachina.sc.designer.core.repository.SettingsRepository;
import com.runachina.sc.designer.core.entity.SettingsEntity;
import com.runachina.sc.designer.domain.model.EntityType;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Configuration;
import org.springframework.plugin.core.PluginRegistry;
import org.springframework.plugin.core.config.EnablePluginRegistries;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Configuration
@EnablePluginRegistries({AppSchemaOperateFilter.class, AppEventListener.class, EntityDesigner.class})
@AllArgsConstructor
@Getter
public class DesignerPluginManager implements CommandLineRunner {

    private final PluginRegistry<AppSchemaOperateFilter, AppSchemaOperateType> operateFilters;

    private final PluginRegistry<AppEventListener, AppEventType> eventListeners;

    private final PluginRegistry<EntityDesigner, String> entityDesigners;

    private final SettingsRepository settingsRepository;

    public List<AppSchemaOperateFilter> getOperateFilters(AppSchemaOperateType operateType) {
        return operateFilters.getPluginsFor(operateType);
    }

    public List<AppEventListener> getEventListeners(AppEventType eventType) {
        return eventListeners.getPluginsFor(eventType);
    }

    @Override
    public void run(String... args) {

        List<SettingsEntity> settingsItems = settingsRepository.findAll();

        if (settingsItems.isEmpty()) {
            settingsItems = new ArrayList<>();
            settingsItems.add(newSettingsEntity());
        }

        settingsItems.stream().map(settings -> appendEntityTypeConfig(settings)).collect(Collectors.toSet());
        settingsRepository.saveAll(settingsItems);
    }

    private SettingsEntity newSettingsEntity() {

        SettingsEntity settings = new SettingsEntity();
        return settings;
    }

    private SettingsEntity appendEntityTypeConfig(SettingsEntity settings) {

        final List<EntityType> entityTypes = settings.getEntityTypes() == null ? new ArrayList<>() : settings.getEntityTypes();

        List<EntityType> newTypes = entityDesigners.getPlugins().stream().map(p -> p.getTypeConfig()).collect(Collectors.toList());

        entityTypes.removeIf(t -> newTypes.stream().anyMatch(nt -> nt.getCode().equals(t.getCode())));
        entityTypes.addAll(newTypes);

        settings.setEntityTypes(entityTypes);

        return settings;
    }
}

 

标签:插件,designer,springboot,runachina,模式,sc,import,com,public
来源: https://www.cnblogs.com/LcxSummer/p/16686124.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有