Arreglo y visualización de procesos | Equipo técnico de JD Cloud

escrito en frente

Aquí solo presentamos el uso básico simple de liteflow y las explicaciones relacionadas del autor sobre la extensión visual de liteflow

1. Antecedentes y significado

Antecedentes: un sistema con una lógica empresarial compleja tiene una lógica empresarial central, que implica operaciones de lógica interna, operaciones de caché, operaciones de persistencia, llamadas a recursos externos, llamadas RPC desde otros sistemas internos, etc. A medida que el proyecto cambia de manos varias veces, el costo de mantenimiento se vuelve cada vez más alto. Hay más y más condiciones de bifurcación para varios juicios de código duro. La abstracción del código, la tasa de reutilización es cada vez menor y el acoplamiento entre los distintos módulos es muy alto. Un pequeño cambio de lógica afectará a otros módulos y se requiere una prueba de regresión completa para verificarlo. Si desea cambiar de manera flexible el orden de los procesos comerciales, debe realizar cambios importantes en el código para abstraer y reescribir el método. El cambio en caliente en tiempo real de los procesos comerciales es casi difícil de lograr

Importancia: desacoplamiento lógico, escalabilidad mejorada, costos de mantenimiento reducidos, reutilización completa de capacidades y disposición de procesos flexible

2. Marco común de orquestación de procesos

  liteflow (código abierto) asyncTool (código abierto) JDEasyFlow (código abierto) disruptor
introducir LiteFlow es un marco de motor de reglas muy potente y moderno que combina características de orquestación y todas las características de un motor de reglas. Si desea reescribir o refactorizar una lógica empresarial compleja, LiteFlow es el más adecuado. Es un marco de motor de reglas de estilo orquestación, orquestación de componentes, ayuda a desacoplar el código comercial y convierte a cada segmento comercial en un componente. Resuelva marcos arbitrarios de simultaneidad de múltiples subprocesos paralelos, seriales, de bloqueo, de dependencia y de devolución de llamada, y puede combinar arbitrariamente el orden de ejecución de cada subproceso, con devolución de llamada de enlace completo y control de tiempo de espera. Componentes de tecnología de orquestación de procesos generales, aplicables a escenarios como orquestación de servicios, flujo de trabajo y flujo de aprobación  
DIRECCIÓN https://liteflow.yomahub.com/ https://gitee.com/jd-platform-opensource/asyncTool https://developer.jdcloud.com/article/2604?mid=30  
ventaja Orquestación de procesos comerciales complejos, comunidad madura y activa Basado en jdk8 CompletableFuture, ligero Simple, flexible y fácil de expandir Basado en el modelo de producción-consumo, diseño sin bloqueo
defecto El marco de código abierto es pesado y tiene un cierto costo de aprendizaje La estabilidad del nuevo marco está por verificar.   Se requiere un empaque secundario de nivel relativamente bajo para escenarios comerciales
ejemplo https://gitee.com/bryan31/liteflow-ejemplo      

3. Uso básico de liteflow

1. Agregar paquete jar dependiente

<dependency>
	<groupId>com.yomahub</groupId>
    <artifactId>liteflow-spring</artifactId>
	<version>2.10.4</version>
</dependency>

2. Definir componentes

Definir componentes e implementar algunos componentes, registrarse en el contexto

@Component("a")
public class ACmp extends NodeComponent {

    @Override
    public void process() {
        //do your business
    }
}

3. Configuración

Agregue la clase de configuración y el archivo de configuración correspondientes

Configuración en Spring xml

<context:component-scan base-package="com.yomahub.flowtest.components" />

<bean id="springAware" class="com.yomahub.liteflow.spi.spring.SpringAware"/>

<bean class="com.yomahub.liteflow.spring.ComponentScanner"/>

<bean id="liteflowConfig" class="com.yomahub.liteflow.property.LiteflowConfig">
    <property name="ruleSource" value="config/flow.el.xml"/>
</bean>

<bean id="flowExecutor" class="com.yomahub.liteflow.core.FlowExecutor">
    <property name="liteflowConfig" ref="liteflowConfig"/>
</bean>

<!-- 如果上述enableLog为false,下面这段也可以省略 -->
<bean class="com.yomahub.liteflow.monitor.MonitorBus">
    <property name="liteflowConfig" ref="liteflowConfig"/>
</bean>

4. Definición de archivo de reglas

--La ​​definición del proceso (liteflowConfig especifica el archivo de reglas como config/flow.xml en el paso 3), por lo que debe crear una nueva configuración de carpeta en recursos, crear un nuevo archivo flow.xml y configurar el proceso que se definirá

<?xml version="1.0" encoding="UTF-8"?>
<flow>
    <chain name="chain1">
        THEN(a, b, c)
    </chain>
</flow>

5. Ejecución

Después del proceso orquestado, inyecte FlowExecutor donde debe ejecutarse y ejecute execute2Resp

@Component
public class YourClass{
    
    @Resource
    private FlowExecutor flowExecutor;
    
    @Test
    public void testConfig(){
        LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
    }
}

4. Aplicación de liteflow en la práctica

El negocio real detrás del debilitamiento aquí solo muestra los casos de aplicación reales del autor.

1. Agregar paquete jar dependiente

    <properties>
        <liteflow-spring.version>2.8.0</liteflow-spring.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.yomahub</groupId>
                <artifactId>liteflow-spring</artifactId>
                <version>${liteflow-spring.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

2. Definir componentes

Definir componentes e implementar algunos componentes, registrarse en el contexto

@LiteflowComponent("checkRealNameAuthCmp")
@LiteflowCmpDefine
public class CheckRealNameAuthCmp {
    private static final Logger log = LoggerFactory.getLogger(CheckRealNameAuthCmp.class);
    @LiteflowMethod(LiteFlowMethodEnum.PROCESS)
    public void process(NodeComponent nodeComponent) throws Exception {
       // 获取请求参数
       GeneratePolicyRightsParam generatePolicyRightsParam = nodeComponent.getSlot().getRequestData();
        // 如果pin为空则结束流程
       if (generatePolicyRightsParam == null || StringUtil.isEmpty(generatePolicyRightsParam.getUserPin())) {
                log.info("CheckRealNameAuthCmp -> process end, nodeComponent={},pin is null.", JsonUtil.toJSONString(nodeComponent));
                nodeComponent.setIsEnd(true);
            }
      //封装设置流程编排上下文信息
      GenerateRightsContext generateRightsContext = nodeComponent.getContextBean(GenerateRightsContext.class);
            generateRightsContext.setGeneratePolicyRightsParam(generatePolicyRightsParam);
    }
}

Componente de flujo ligero: https://liteflow.yomahub.com/pages/v2.8.X/8486fb/

LiteflowCmpDefinir: https://liteflow.yomahub.com/pages/v2.8.X/f33919/

3. Configuración

Agregue la clase de configuración y el archivo de configuración correspondientes

Configuración en Spring xml

primavera-config.xml

 <import resource="classpath*:spring/spring-config-liteflow.xml"/>

primavera-config-liteflow.xml

    <bean id="springAware" class="com.yomahub.liteflow.spi.spring.SpringAware"/>
    <bean id="springComponentScaner" class="com.yomahub.liteflow.spring.ComponentScanner"/>

    <!-- 注入liteflow的配置文件 -->
    <bean id="liteflowConfig" class="com.yomahub.liteflow.property.LiteflowConfig">
        <property name="ruleSource" value="liteflow/flow.xml"/>
    </bean>

    <!-- 注入liteflow的执行引擎 -->
    <bean id="flowExecutor" class="com.yomahub.liteflow.core.FlowExecutor">
        <property name="liteflowConfig" ref="liteflowConfig"/>
    </bean>

    <!-- 注入liteflow的MonitorBus-->
    <bean class="com.yomahub.liteflow.monitor.MonitorBus">
        <constructor-arg ref="liteflowConfig"/>
        <property name="liteflowConfig" ref="liteflowConfig"/>
    </bean>

4. Definición de archivo de reglas

--La ​​definición del proceso (liteflowConfig especifica el archivo de reglas como liteflow/flow.xml en el paso 3), por lo que debe crear una nueva carpeta liteflow en recursos, crear un nuevo archivo flow.xml y configurar el proceso que se definirá

flujo.xml

<?xml version="1.0" encoding="UTF-8"?>
<flow>
    <!-- liteflow流程编排:生成(发放)保单权益-->
    <chain name="sendPolicyRightsChain">
        <when value="checkRealNameAuthCmp"/>
        <then value="checkNewPolicyRightsCmp"/>
        <then value="getPolicyInfoCmp"/>
        <then value="policyMatchServiceRuleCmp"/>
        <then value="initPolicyRightsDataCmp"/>
        <then value="creatPlanGantRightsDataCmp"/>
        <then value="asyncFullFillCmp"/>
    </chain>
</flow>

5. Ejecución

Ejecute el proceso orquestado, inyecte FlowExecutor donde debe ejecutarse y ejecute execute2Resp

 @Resource
 private FlowExecutor flowExecutor;

public Boolean sendPolicyRights(GeneratePolicyRightsParam generatePolicyRightsParam) {
      //todo 入参和上下文不能混用,通用信息用map
      LiteflowResponse response = flowExecutor.execute2Resp("sendPolicyRightsChain", generatePolicyRightsParam, GenerateRightsContext.class,GenerateRightsContext.class);
                  
}

5. Expansión de la capacidad de Liteflow (visualización)

Liteflowt proporciona la capacidad de orquestación de procesos. Solo el personal de I+D puede comprender el significado de esta orquestación de procesos internos. Para otros productos o negocios, no pueden comprender intuitivamente el proceso comercial actual y la visualización no es amigable. ¿Cómo visualizamos el proceso actual en este momento? No tiene sentido escribir una página para leer directamente el archivo de configuración flow.xml para su visualización. Lo que tiene sentido es que podemos visualizar componentes, visualizar procesos, visualizar la orquestación de procesos.

1. pensamiento

Proporcione un nuevo paquete jar, obtenga los famosos componentes y procesos del sistema comercial, muestre procesos y componentes y proporcione capacidades de orquestación.

ilustrar:

1. El paquete jar de herramientas pequeñas es una herramienta pequeña para la organización visual de procesos. Proporciona principalmente componentes para obtener declaraciones de sistemas empresariales, procesos guardados, visualización de procesos y visualización de la organización de procesos. Utiliza el logotipo de liteflow-util para distinguirlo del sistema empresarial.

2. El sistema empresarial es un sistema de declaración de componentes, ejecución de procesos y lógica empresarial, que utiliza el logotipo de prueba de liteflow.

2. Date cuenta

2.1 Obtener una clase o método específico

Cómo obtener componentes declarados en liteflow-test desde liteflow-util

2.1.1 Obtener el contexto

ApplicationContextAware

Cuando se inicializan las propiedades de un bean, volverá a llamar a setApplicationContext para establecer el contexto de la aplicación.

public interface ApplicationContextAware extends Aware {
	/**
	 * Set the ApplicationContext that this object runs in.
	 * Normally this call will be used to initialize the object.
	 * 

Invoked after population of normal bean properties but before an init callback such
	 * as {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}
	 * or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},
	 * {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
	 * {@link MessageSourceAware}, if applicable.
	 * @param applicationContext the ApplicationContext object to be used by this object
	 * @throws ApplicationContextException in case of context initialization errors
	 * @throws BeansException if thrown by application context methods
	 * @see org.springframework.beans.factory.BeanInitializationException
	 */
	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

Use una clase en liteflow-util para implementar ApplicationContextAware, para obtener el contexto de liteflow-test (aplicaciones que dependen del paquete jar actual)

@Configuration
public class LiteFlowApplicationContext implements ApplicationContextAware {
   private static ApplicationContext controllerApplicationContext;
   @Override
   public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
      System.out.println("applicationContext = " + applicationContext);
      LiteFlowApplicationContext.controllerApplicationContext=applicationContext;
   }
   public static ApplicationContext getControllerApplicationContext() {
      return controllerApplicationContext;
   }
}

2.1.2 Obtener clase del contexto

Obtenga la clase de componente de acuerdo con el contexto en liteflow-util El enfoque aquí es Map<String, Object> mvcObjects = context.getBeansWithAnnotation(Service.class);

@Slf4j
public class ReferenceManager {
    private static Map<Class<?>, Object> interfaceMapRef = new ConcurrentHashMap<Class<?>, Object>();
    private static ReferenceManager instance;
    private ReferenceManager() {
    }
    public synchronized static ReferenceManager getInstance() {
        if (null != instance) {
            return instance;
        }
        instance = new ReferenceManager();
        ApplicationContext controllerContext = LiteFlowApplicationContext.getControllerApplicationContext();
        interfaceMapInit(controllerContext);
        return instance;
    }
    private static void interfaceMapInit(ApplicationContext context) {
        try {
            Map<String, Object> objects = Maps.newHashMapWithExpectedSize(64);
            //优化 允许 ServiceBean 被MVC容器扫描
            Map<String, Object> mvcObjects = context.getBeansWithAnnotation(Service.class);
            objects.putAll(mvcObjects);
            if (objects == null || objects.size() == 0) {
                return;
            }
            for (Entry<String, Object> entry : objects.entrySet()) {
                /**
                 * 获取代理对象的原对象
                 * 因为 jdk 动态代理通过接口
                 */
                Object objectImplProxy = entry.getValue();
                Object objectImpl = AopTargetUtils.getTarget(objectImplProxy);
                Class objectImplClass = objectImpl.getClass();
                if (objectImplClass.getInterfaces().length > 0) {
                    /**
                     * 规定 每个interface 只对应 一个实现类
                     * 如果 多个类实现了该接口 接口列表中只 显示第一个实现类
                     */
                    Class interfaceClass = objectImplClass.getInterfaces()[0];
                    Object object = interfaceMapRef.get(interfaceClass);
                    if (object == null) {
                        interfaceMapRef.put(interfaceClass, objectImpl);
                    } else {
                    }
                } else {
                }
            }
        } catch (Exception e) {
        }
    }
    public Map<Class<?>, Object> getInterfaceMapRef() {
        return interfaceMapRef;
    }
}
@Component
public class ServiceScanner {
    public Set<Class<?>> classes() {
        return interfaceMapRef().keySet();
    }
    public Map<Class<?>, Object> interfaceMapRef() {
        return ReferenceManager.getInstance().getInterfaceMapRef();
    }
}
public class AopTargetUtils {
	/**
	 * 获取 目标对象
	 * @param proxy 代理对象
	 * @return
	 * @throws Exception
	 */
	public static Object getTarget(Object proxy) throws Exception {

		if(!AopUtils.isAopProxy(proxy)) {
			return proxy;//不是代理对象
		}
		if(AopUtils.isJdkDynamicProxy(proxy)) {
			return getJdkDynamicProxyTargetObject(proxy);
		} else { //cglib
			return getCglibProxyTargetObject(proxy);
		}
	}
	private static Object getCglibProxyTargetObject(Object proxy) {
		try{
			Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
			h.setAccessible(true);
			Object dynamicAdvisedInterceptor = h.get(proxy);
			Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
			advised.setAccessible(true);
			Object target = ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
			return target;
		} catch(Exception e){
			e.printStackTrace();
			return null;
		}
	}
	private static Object getJdkDynamicProxyTargetObject(Object proxy) {
		try{
			Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
			h.setAccessible(true);
			AopProxy aopProxy = (AopProxy) h.get(proxy);
			Field advised = aopProxy.getClass().getDeclaredField("advised");
			advised.setAccessible(true);
			Object target = ((AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget();
			return target;
		} catch(Exception e){
			e.printStackTrace();
			return null;
		}
	}
}

2.2 Visite la página de liteflow-util

Cómo acceder y mostrar las páginas en el paquete liteflow-util en liteflow-test

(1) Escriba una clase Servlet en liteflow-util, herede directamente HttpServlet y reescriba el método doGet o doPost

(2) Configure la clase Servlet en web.xml en liteflow-util

(3) Prepare la página de inicio (formulario, interacción de botón) en liteflow-util

(4) Introducir dependencias en liteflow-test e iniciar liteflow-test

2.2.1HttpServlet

public class HandServlet extends HttpServlet {
    private static final Logger log = LoggerFactory.getLogger(HandServlet.class);
    private String username = null;
    private String password = null;
    private ServletContext servletContext;
    public HandServlet() {
    }
    @Override
    public void init(ServletConfig config) {
        log.info("HandServlet->init,start");
        this.username = config.getInitParameter("loginUsername");
        this.password = config.getInitParameter("loginPassword");
        this.servletContext = config.getServletContext();
        log.info("HandServlet->init finish");
    }
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String contextPath = request.getContextPath();
        String servletPath = request.getServletPath();
        String requestURI = request.getRequestURI();
        response.setCharacterEncoding("utf-8");
        if (contextPath == null) {
            contextPath = "";
        }
        String uri = contextPath + servletPath;
        String path = requestURI.substring(contextPath.length() + servletPath.length());
        String usernameParam;
        if (!Objects.equals("/submitLogin", path)) {
            if (this.needLogin(request, path)) {
                this.redirect(request, response);
            } else {
                Result result;
                try {
                    result = this.requestHandler(path, request);
                } catch (Throwable var11) {
                    log.error("HandServlet->service,requestHandler error", var11);
                    result = Result.buildFail(var11.getMessage());
                }
                if (null != result) {
                    response.getWriter().print(JSON.toJSONString(result));
                } else {
                    this.returnResourceFile(path, uri, response);
                }
            }
        } else {
            usernameParam = request.getParameter("loginUsername");
            String passwordParam = request.getParameter("loginPassword");
            System.out.println("usernameParam = " + usernameParam);
            System.out.println("passwordParam = " + passwordParam);
//            if (this.username.equals(usernameParam) && this.password.equals(passwordParam)) {
            HttpSession session = request.getSession();
            session.setAttribute("lite-flow", this.username);
            session.setMaxInactiveInterval(300);
            response.getWriter().print(JSON.toJSONString(Result.buildSuccess("success")));
//            } else {
//                response.getWriter().print(JSON.toJSONString(Result.buildFail("用户名或密码错误")));
//            }
        }
    }
    private void redirect(HttpServletRequest request, HttpServletResponse response) throws IOException {
        if (request.getHeader("X-Requested-With") != null && "XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) {
            response.getWriter().print(JSON.toJSONString(Result.buildReLogin()));
        } else if (request.getHeader("Accept") != null && request.getHeader("Accept").contains("application/json")) {
            response.getWriter().print(JSON.toJSONString(Result.buildReLogin()));
        } else {
            response.sendRedirect("/lite-flow/login.html");
        }
    }
    private Result requestHandler(String path, HttpServletRequest request) {
        System.out.println("path = " + path);
        System.out.println("request = " + request);
        String initMenu = "/initMenu";
        String liteflow = "/liteflow";
        if (initMenu.equals(path)) {
            Map<String, Object> map = new HashMap(2);
            List<String> classObjectMap = getClassObjectMap();
            classObjectMap.forEach(item -> {
                int i = item.lastIndexOf(".");
                String substring = item.substring(i+1);
                System.out.println("substring = " + substring);
   LiteFlowNodeBuilder.createCommonNode().setId(substring).setName(substring).setClazz(item).build();
            });
            map.put("interfaceMapRef", classObjectMap);
            return Result.buildSuccess(map);
        } else if (liteflow.equals(path)) {
            try {
                try {
                    String postData = this.getPostData(request);
                    log.info("HandServlet -> requestHandler start, postData={}", postData);
                    JSONObject jsonObject = JSONObject.parseObject(postData);
                    JSONArray checkList = jsonObject.getJSONArray("checkList");
                    String chainId = (String) jsonObject.get("chainId");
                    log.info("HandServlet -> requestHandler start, path={},checkList={}", path, checkList);
                    ArrayList arrayList = new ArrayList();
                    checkList.forEach(item -> {
                        String itemStr = (String) item;
                        int i = itemStr.lastIndexOf(".");
                        String substring = itemStr.substring(i+1);
                        arrayList.add(substring);
                    });
                    String str = StringUtils.join(arrayList, ",");
                    log.info("HandServlet -> requestHandler start, str={}", str);
//                    String elss = "THEN(" + str + ")";
//                    log.info("HandServlet -> requestHandler start, elss={}", elss);
                    Condition condition = LiteFlowConditionBuilder.createCondition(ConditionTypeEnum.TYPE_THEN).setValue(str).build();
                    log.info("HandServlet -> requestHandler start, condition={}", condition);
                    LiteFlowChainBuilder.createChain().setChainName(chainId).setCondition(condition).build();
                } catch (Throwable var3) {
                    log.error("HandServlet -> requestHandler exception 未知异常, var3={}", var3);
                }
            } catch (Throwable var3) {
                log.info("MqUtil->haveProducer,error", var3);
            }
            return Result.buildSuccess(false);
        } else {
            return null;
        }
    }

    public String getPostData(HttpServletRequest request) {
        StringBuilder data = new StringBuilder();
        String line;
        BufferedReader reader;
        try {
            reader = request.getReader();
            while (null != (line = reader.readLine())) {
                data.append(line);
            }
        } catch (IOException e) {
            return null;
        }
        return data.toString();
    }

    private List<String> getClassObjectMap() {
        List<String> result = new ArrayList<>();
        WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        Map<String, ServiceScanner> serviceScannerMap = webApplicationContext.getBeansOfType(ServiceScanner.class);
        ServiceScanner serviceScanner = serviceScannerMap.get("serviceScanner");
        Map<Class<?>, Object> interfaceMapRef = serviceScanner.interfaceMapRef();
        if (null != interfaceMapRef) {
            //排序 所有接口
            List<Map.Entry<Class<?>, Object>> arrayList = new ArrayList<Map.Entry<Class<?>, Object>>(interfaceMapRef.entrySet());
            Collections.sort(arrayList, new Comparator<Map.Entry<Class<?>, Object>>() {
                @Override
                public int compare(Map.Entry<Class<?>, Object> o1, Map.Entry<Class<?>, Object> o2) {
                    return o1.getKey().getSimpleName().compareTo(o2.getKey().getSimpleName());
                }
            });
            //遍历 所有接口
            for (Map.Entry<Class<?>, Object> entry : arrayList) {
                String className = entry.getValue().getClass().getName();
                System.out.println("class = " + className);
                result.add(className);
//                List<Method> interfaceMethodList = Arrays.asList(entry.getKey().getDeclaredMethods());
//                //方法列表排序
//                Collections.sort(interfaceMethodList, new Comparator<Method>() {
//                    @Override
//                    public int compare(Method o1, Method o2) {
//                        return o1.getName().compareTo(o2.getName());
//                    }
//                });
//                for (Method method : interfaceMethodList) {
//                    System.out.println("method = " + method);
//                    System.out.println("methodName = " + method.getName());
//                    System.out.println("methodParameterTypes = " + method.getParameterTypes());
//                    System.out.println("methodReturn = " + method.getReturnType());
//                }
            }

        }
        System.out.println("result = " + result);
        return result;
    }
    private boolean needLogin(HttpServletRequest request, String path) {
        return this.isRequireAuth() && !this.alreadyLogin(request) && !this.checkLoginParam(request) && !"/login.html".equals(path) && !path.startsWith("/css") && !path.startsWith("/js") && !path.startsWith("/img");
    }
    private boolean checkLoginParam(HttpServletRequest request) {
        String usernameParam = request.getParameter("loginUsername");
        String passwordParam = request.getParameter("loginPassword");
        if (null != this.username && null != this.password) {
            return this.username.equals(usernameParam) && this.password.equals(passwordParam);
        } else {
            return false;
        }
    }
    private boolean isRequireAuth() {
        return this.username != null;
    }
    private boolean alreadyLogin(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        return session != null && session.getAttribute("lite-flow") != null;
    }
    private void returnResourceFile(String fileName, String uri, HttpServletResponse response) throws IOException {
        String filePath = this.getFilePath(fileName);
        if (filePath.endsWith(".html")) {
            response.setContentType("text/html; charset=utf-8");
        }
        if (fileName.endsWith(".jpg")) {
            byte[] bytes = Utils.readByteArrayFromResource(filePath);
            if (bytes != null) {
                response.getOutputStream().write(bytes);
            }
        } else {
            String text = Utils.readFromResource(filePath);
            if (text == null) {
                response.sendRedirect(uri + "/login.html");
            } else {
                if (fileName.endsWith(".css")) {
                    response.setContentType("text/css;charset=utf-8");
                } else if (fileName.endsWith(".js")) {
                    response.setContentType("text/javascript;charset=utf-8");
                }

                response.getWriter().write(text);
            }
        }
    }
    private String getFilePath(String fileName) {
        return "view" + fileName;
    }

2.2.2 Configurar web.xml

Configurar servlets personalizados en web.xml en liteflow-util

    <servlet>
        <servlet-name>handOfLite</servlet-name>
        <servlet-class>com.xx.utils.liteflow.handler.HandServlet</servlet-class>
        <init-param>
            <param-name>loginUsername</param-name>
            <param-value>Username</param-value>
        </init-param>
        <init-param>
            <param-name>loginPassword</param-name>
            <param-value>Password</param-value>
        </init-param>
        <load-on-startup>5</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>handOfLite</servlet-name>
        <url-pattern>/hand-of-lite/*</url-pattern>
    </servlet-mapping>

2.2.3 Preparación de la página

Preparar páginas para mostrar componentes dentro de liteflow-util

2.2.4 Visitar la página

Agregar dependencia de liteflow-util en liteflow-test

<dependency>
    <groupId>com.xx.utils</groupId>
    <artifactId>liteflow</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

Inicie el proyecto liteflow-test y visite la ruta correspondiente, vea la página preparada en 2.2.3

2.3 Obtener el componente y el eco

2.3.1 Anotaciones personalizadas

Personalice las anotaciones en liteflow-util para ensamblar e importar las clases y configuraciones de recursos requeridas

@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Documented
@Import({LiteFlowApplicationContext.class, FlowExecutor.class, LiteflowConfig.class, IdGeneratorHolder.class})
@ComponentScan(
        basePackages = {"com.xx.utils", "com.xx.utils.liteflow"}
)
public @interface EnableLiteFlow {

}

2.3.2 Introducción a las dependencias del paquete jar

Introducir dependencias básicas de lite-flow en liteflow-util

<dependency>
    <groupId>com.yomahub</groupId>
    <artifactId>liteflow-spring</artifactId>
    <version>2.8.3</version>
</dependency>

Introducir la dependencia de liteflow-util en liteflow-test

<dependency>
    <groupId>com.xx.utils</groupId>
    <artifactId>liteflow</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

2.3.3 Configurar liteflow-util

Use anotaciones personalizadas para importar configuraciones requeridas en liteflow-test

@Configuration
@EnableLiteFlow
public class LiteFlowConfig {
}

2.3.4 Clase de componente de pantalla

Reinicie liteflow-test, la página de acceso muestra la colección de componentes adquiridos

2.4 Crear nuevos componentes

liteflow-util proporciona RequestMapping para crear y guardar nodos

@RestController
@RequestMapping("/node")
public class NodeController {
    private static final Logger log = LoggerFactory.getLogger(NodeController.class);

    /**
     * 构建一个普通组件
     */
    @RequestMapping("/createCommonNode")
    @ResponseBody
    public Boolean createCommonNode(@RequestBody NodeParam nodeParam) {
        log.info("NodeController -> createCommonNode start, nodeParam={}", nodeParam.toString());
        try {
            //构建一个普通组件
            LiteFlowNodeBuilder.createCommonNode().setId(nodeParam.getId()).setName(nodeParam.getName()).setClazz(nodeParam.getClazz()).build();
            return Boolean.TRUE;
        } catch (Exception e) {
            return Boolean.FALSE;
        }
    }
    /**
     * 构建一个普通条件组件
     */
    @RequestMapping("/createSwitchNode")
    @ResponseBody
    public Boolean createSwitchNode(@RequestBody NodeParam nodeParam) {
        try {
           LiteFlowNodeBuilder.createSwitchNode().setId(nodeParam.getId()).setName(nodeParam.getName()).setClazz(nodeParam.getClazz()).build();
            return Boolean.TRUE;
        } catch (Exception e) {
            return Boolean.FALSE;
        }
    }
}

2.5 Crear un nuevo proceso

https://liteflow.yomahub.com/pages/v2.8.X/9aa85a/

LiteFlowChainELBuilder.createChain().setChainName("chain2").setEL(
  "THEN(a, b, WHEN(c, d))"
).build();

3. Resumen general

De hecho, la idea general es proporcionar un paquete jar. A partir de este paquete jar, puede obtener los componentes correspondientes, el proceso de creación, el proceso de almacenamiento, el proceso de eco, el proceso de ejecución, etc. de las clases en el proyecto dependiente. Esto implica la integración y aplicación del ciclo de vida de Springbean, el entorno de contexto, httpsservlet, anotaciones personalizadas, reflexión, páginas frontales y otros conocimientos relacionados.

Autor: JD Health Ma Renxi

Fuente: Comunidad de desarrolladores de JD Cloud

RustDesk 1.2: Usando Flutter para reescribir la versión de escritorio, apoyando a Wayland acusado de deepin V23 adaptándose con éxito a los lenguajes de programación WSL 8 con la mayor demanda en 2023: PHP es fuerte, la demanda de C/C++ se ralentiza ¿ React está experimentando el momento de Angular.js? El proyecto CentOS afirma estar "abierto a todos" Se lanzan oficialmente MySQL 8.1 y MySQL 8.0.34 Se lanza la versión estable de Rust 1.71.0
{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/u/4090830/blog/10089389
Recomendado
Clasificación