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
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; |
|
} |
|
} |