帆软报表设计器源代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

183 lines
7.1 KiB

package com.fr.design.jxbrowser;
import com.fr.base.TemplateUtils;
import com.fr.design.ui.ModernRequestClient;
import com.fr.design.ui.ModernUIConstants;
import com.fr.general.IOUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.EncodeConstants;
import com.fr.stable.StringUtils;
import com.fr.web.struct.AssembleComponent;
import com.fr.web.struct.AtomBuilder;
import com.fr.web.struct.PathGroup;
import com.fr.web.struct.category.ScriptPath;
import com.fr.web.struct.category.StylePath;
import com.teamdev.jxbrowser.net.HttpHeader;
import com.teamdev.jxbrowser.net.HttpStatus;
import com.teamdev.jxbrowser.net.UrlRequest;
import com.teamdev.jxbrowser.net.UrlRequestJob;
import com.teamdev.jxbrowser.net.callback.InterceptUrlRequestCallback;
import org.jetbrains.annotations.NotNull;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
import static com.fr.design.ui.ModernUIConstants.COMPONENT_TAG;
/**
* jxbrowser7 自定义 scheme 处理回调
*
* @author vito
* @since 11.0
* Created on 2023/6/8
*/
public class NxInterceptRequestCallback implements InterceptUrlRequestCallback {
private static final String COLON_DECODE_ESCAPE = "/:";
private static final String SCHEME_SPLIT = ":/";
private Supplier<AssembleComponent> component;
private Supplier<Map<String, String>> renderParameterBuild;
public NxInterceptRequestCallback(Supplier<Map<String, String>> renderParameterBuild) {
this.renderParameterBuild = renderParameterBuild;
}
public NxInterceptRequestCallback(Supplier<AssembleComponent> component,
Supplier<Map<String, String>> renderParameterBuild) {
this.component = component;
this.renderParameterBuild = renderParameterBuild;
}
/**
* 主要包括 atom 和 emb协议的文件链接处理,
* 去掉file文件协议的支持,因此jxbrowser 7之后不支持覆盖内置协议,详细见
* {@link com.teamdev.jxbrowser.net.internal.NonInterceptableScheme}
*
* @param params 参数
* @return 响应
*/
@Override
public Response on(Params params) {
UrlRequest urlRequest = params.urlRequest();
String path = urlRequest.url().replace(COLON_DECODE_ESCAPE, JxUIPane.COLON);
Optional<UrlRequestJob> urlRequestJobOptional;
if (path.startsWith(COMPONENT_TAG)) {
String text = htmlText(renderParameterBuild.get());
urlRequestJobOptional = generateBasicUrlRequestJob(params,
"text/html", text.getBytes(StandardCharsets.UTF_8));
} else {
urlRequestJobOptional = generateFileProtocolUrlRequestJob(params, path);
}
return urlRequestJobOptional
.map(Response::intercept)
.orElseGet(Response::proceed);
}
protected Optional<UrlRequestJob> generateFileProtocolUrlRequestJob(Params params, String path) {
try {
String resourcePath = getResourcePath(path);
InputStream inputStream = getResourceStream(resourcePath);
String mimeType = MimeType.parseMimeType(resourcePath);
byte[] bytes;
if (isHtml(mimeType)) {
String text = IOUtils.inputStream2String(inputStream, EncodeConstants.ENCODING_UTF_8);
text = TemplateUtils.renderParameter4Tpl(text, renderParameterBuild.get());
bytes = text.getBytes(StandardCharsets.UTF_8);
} else {
bytes = IOUtils.inputStream2Bytes(inputStream);
}
return generateBasicUrlRequestJob(params, mimeType, bytes);
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
return Optional.empty();
}
/**
* 获取资源文件流
*
* @param path 文件路径
* @return 输入流
* @throws Exception IO异常
*/
private InputStream getResourceStream(String path) {
return IOUtils.readResource(path);
}
private static String getResourcePath(String path) throws UnsupportedEncodingException {
int index = path.indexOf("=");
if (index > 0) {
path = path.substring(index + 1);
} else {
// jxbrowser 7之后,协议会自动补齐双斜杠//
int i = path.indexOf(SCHEME_SPLIT);
path = path.substring(i + SCHEME_SPLIT.length());
// 通过自定义协议之后的url会自动encode一些中文字符,这里做一个decode,否则会导致路径访问失败
path = URLDecoder.decode(path, StandardCharsets.UTF_8.name());
}
return path;
}
private boolean isHtml(String mimeType) {
return MimeType.HTML.getMimeType().equals(mimeType);
}
private Optional<UrlRequestJob> generateBasicUrlRequestJob(Params params, String mimeType, byte[] bytes) {
if (StringUtils.isEmpty(mimeType)) {
return Optional.empty();
}
UrlRequestJob.Options options = UrlRequestJob.Options
.newBuilder(HttpStatus.OK)
.addHttpHeader(HttpHeader.of("Content-Type", mimeType))
.build();
UrlRequestJob urlRequestJob = params.newUrlRequestJob(options);
urlRequestJob.write(bytes);
urlRequestJob.complete();
return Optional.of(urlRequestJob);
}
private String htmlText(Map<String, String> map) {
return component.get() == null ?
StringUtils.EMPTY :
parseComponent(component.get(), map);
}
@NotNull
private static String parseComponent(AssembleComponent component, Map<String, String> map) {
PathGroup pathGroup = AtomBuilder.create().buildAssembleFilePath(ModernRequestClient.KEY, component);
StylePath[] stylePaths = pathGroup.toStylePathGroup();
StringBuilder styleText = new StringBuilder();
for (StylePath path : stylePaths) {
if (StringUtils.isNotBlank(path.toFilePath())) {
styleText.append("<link rel=\"stylesheet\" href=\"emb://");
styleText.append(path.toFilePath());
styleText.append("\"/>");
}
}
String result = ModernUIConstants.HTML_TPL.replaceAll("##style##", styleText.toString());
ScriptPath[] scriptPaths = pathGroup.toScriptPathGroup();
StringBuilder scriptText = new StringBuilder();
for (ScriptPath path : scriptPaths) {
if (StringUtils.isNotBlank(path.toFilePath())) {
scriptText.append("<script src=\"emb://");
scriptText.append(path.toFilePath());
scriptText.append("\"></script>");
}
}
result = result.replaceAll("##script##", scriptText.toString());
if (map != null) {
for (Map.Entry<String, String> entry : map.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
result = result.replaceAll("\\$\\{" + key + "}", value);
}
}
return result;
}
}