一、特殊名词介绍
WEB组件:本文中所指的组件是指一组用于解决特定业务或实现特定功能的,JS脚本和样式的集合。
二、背景、场景介绍
1.在帆软的决策系统和报表展现时,不同的客户往往对展现的样式和交互风格有自身的审美要求。当产品本身的配置功能不满足需要时,则可以使用该接口进行个性化的处理。
2.在帆软产品的使用过程中,如果客户需要对产品的前端功能进行扩充和变更,则可以使用该接口进行配合实现;(比如:平台功能修改、新增平台功能、新控件、新图表 的开发)
ComposeWebResourceProvider接口是WebResourceProvider的增强版本,WebResourceProvider一次只能引入一个组件,而ComposeWebResourceProvider一次可以引入多个组件。
三、接口介绍
package com.fr.decision.fun;
import com.fr.stable.fun.mark.ComposeWebCoalition;
/**
* @author Roger
* @version 10.0
* @date 2021/1/15
* 给多个web主组件添加子组件
*/
public interface ComposeWebResourceProvider extends ComposeWebCoalition {
String MARK_STRING = "ComposeWebResourceProvider";
int CURRENT_LEVEL = 1;
}
package com.fr.stable.fun.mark;
/**
* @author Roger
* @version 10.0
* @date 2021/1/15
* 多主组件注册
*/
public interface ComposeWebCoalition extends Mutable {
WebCoalition[] webCoalitions();
}
package com.fr.stable.fun.mark;
import com.fr.web.struct.Atom;
/**
* 带有web资源的扩展接口
*/
public interface WebCoalition extends Mutable {
/**
* 需要附加到的主组件
* @return 主组件
*/
Atom attach();
/**
* 客户端所需的组件
*
* @return 组件
*/
@Deprecated
Atom client();
/**
* 客户端所需的组件集合
*
* @return 组件集合
*/
Atom[] clients();
}
关联接口:com.fr.web.struct.Atom
四、支持版本
产品线 | 版本 | 支持情况 | 备注 |
---|
FR | 10.0 | 支持 |
|
BI | 5.1.3 | 支持 |
|
五、插件注册
<extra-decision>
<ComposeWebResourceProvider class="your class name"/>
</extra-decision>
六、原理说明
package com.fr.web.struct;
import com.fr.module.extension.PrepareAdaptor;
import com.fr.plugin.context.PluginContext;
import com.fr.plugin.injectable.PluginInjectionFilter;
import com.fr.stable.ArrayUtils;
import com.fr.stable.fun.mark.ComposeWebCoalition;
import com.fr.stable.fun.mark.WebCoalition;
import com.fr.web.struct.extra.ModificatorInjectUtil;
/**
* Created by juhaoyu on 2018/9/4.
*/
public class AtomActivator extends PrepareAdaptor {
@Override
public void prepare() {
addMutable(PluginInjectionFilter.KEY, new PluginInjectionFilter<WebCoalition>(WebCoalition.class) {
@Override
public void on(WebCoalition webCoalition, PluginContext context) {
register(webCoalition, context);
}
@Override
public void off(WebCoalition webCoalition, PluginContext context) {
remove(webCoalition, context);
}
});
addMutable(PluginInjectionFilter.KEY, new PluginInjectionFilter<ComposeWebCoalition>(ComposeWebCoalition.class) {
@Override
public void on(ComposeWebCoalition composeWebCoalition, PluginContext context) {
for (WebCoalition webCoalition : composeWebCoalition.webCoalitions()) {
register(webCoalition, context);
}
}
@Override
public void off(ComposeWebCoalition composeWebCoalition, PluginContext context) {
for (WebCoalition webCoalition : composeWebCoalition.webCoalitions()) {
remove(webCoalition, context);
}
}
});
}
private void register(WebCoalition webCoalition, PluginContext context) {
if (webCoalition.client() != null) {
Atom wrappedAtom = ModificatorInjectUtil.wrapAtom(webCoalition.client(), context.getID());
Registry.register(webCoalition.attach().getClass(), wrappedAtom);
}
if (ArrayUtils.isNotEmpty(webCoalition.clients())) {
for (Atom client : webCoalition.clients()) {
Atom wrappedAtom = ModificatorInjectUtil.wrapAtom(client, context.getID());
Registry.register(webCoalition.attach().getClass(), wrappedAtom);
}
}
}
private void remove(WebCoalition webCoalition, PluginContext context) {
if (webCoalition.client() != null) {
Atom wrappedAtom = ModificatorInjectUtil.wrapAtom(webCoalition.client(), context.getID());
Registry.remove(webCoalition.attach().getClass(), wrappedAtom);
}
if (ArrayUtils.isNotEmpty(webCoalition.clients())) {
for (Atom client : webCoalition.clients()) {
Atom wrappedAtom = ModificatorInjectUtil.wrapAtom(client, context.getID());
Registry.remove(webCoalition.attach().getClass(), wrappedAtom);
}
}
}
}
package com.fr.web.struct;
import com.fr.common.annotations.Open;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 扩展子组件的管理器
*/
@Open
public class Registry {
private static Map<Class<? extends Atom>, LinkedHashSet<Atom>>
children = new ConcurrentHashMap<Class<? extends Atom>, LinkedHashSet<Atom>>();
/**
* 注册某个组件所需要的子组件
* @param clazz 父组件
* @param atom 子组件
*/
public static void register(Class<? extends Atom> clazz, Atom... atom) {
LinkedHashSet<Atom> set = children.get(clazz);
if (set == null) {
set = new LinkedHashSet<Atom>();
children.put(clazz, set);
}
Collections.addAll(set, atom);
}
public static void remove(Class<? extends Atom> clazz, Atom... atom) {
LinkedHashSet<Atom> set = children.get(clazz);
if (set == null) {
return;
}
set.removeAll(Arrays.asList(atom));
}
/**
* 获取一个组件的所有额外的子组件
* @param clazz 父组件
* @return 所有的子组件组成的数组
*/
public static Atom[] getChildren(Class<? extends Atom> clazz) {
LinkedHashSet<Atom> set = children.get(clazz);
if (set == null) {
return new Atom[0];
}
set.remove(null);
List<Atom> list = new ArrayList<Atom>();
for (Atom atom : set) {
Filter filter = atom.filter();
if (filter == null || filter.accept()) {
list.add(atom);
}
}
return list.toArray(new Atom[0]);
}
}
七、特殊限制说明
从纯技术上说,这个接口能实现的功能使用WebResourceProvider绝大部分场景都能实现,从实践上看主要是有这么两个用途:
1.对于批量组件的引入,能简化plugin.xml的结构。
2.能够在启动阶段配合其他接口,实现组件的动态引入。
其他使用方法直接参考WebResourceProvider即可。
八、常用链接
demo地址:demo-compose-web-resource-provider
三组常见引入JS和CSS的插件接口对比
九、开源案例
免责声明:所有文档中的开源示例,均为开发者自行开发并提供。仅用于参考和学习使用,开发者和官方均无义务对开源案例所涉及的所有成果进行教学和指导。禁止用于任何商业用途,若作为商用一切后果责任由使用者自行承担。
暂无