mirror of https://github.com/halo-dev/halo
Fix the problem of showing 500 error while containing special chars in excerpt (#5263)
#### What type of PR is this? /kind bug /area core /milestone 2.12.0 #### What this PR does / why we need it: This PR refactors building html meta by using `modelFactory#createStandaloneElementTag`. See https://github.com/halo-dev/halo/issues/4755 for more. #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/4755 #### Special notes for your reviewer: Validate via <https://github.com/halo-dev/halo/issues/4755#issuecomment-1776391345>. #### Does this PR introduce a user-facing change? ```release-note 修复摘要中包含特殊字符导致无法解析页面的问题 ```pull/5274/head^2
parent
9137d50a31
commit
47a1aa7631
|
@ -2,11 +2,13 @@ package run.halo.app.theme.dialect;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
|
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
|
||||||
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
|
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
|
||||||
|
import static org.thymeleaf.model.AttributeValueQuotes.DOUBLE;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
|
@ -15,6 +17,7 @@ import org.springframework.web.util.HtmlUtils;
|
||||||
import org.thymeleaf.context.ITemplateContext;
|
import org.thymeleaf.context.ITemplateContext;
|
||||||
import org.thymeleaf.model.IModel;
|
import org.thymeleaf.model.IModel;
|
||||||
import org.thymeleaf.model.IModelFactory;
|
import org.thymeleaf.model.IModelFactory;
|
||||||
|
import org.thymeleaf.model.ITemplateEvent;
|
||||||
import org.thymeleaf.processor.element.IElementModelStructureHandler;
|
import org.thymeleaf.processor.element.IElementModelStructureHandler;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import run.halo.app.theme.DefaultTemplateEnum;
|
import run.halo.app.theme.DefaultTemplateEnum;
|
||||||
|
@ -62,11 +65,9 @@ public class ContentTemplateHeadProcessor implements TemplateHeadProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
return htmlMetasMono
|
return htmlMetasMono
|
||||||
.doOnNext(htmlMetas -> {
|
.doOnNext(
|
||||||
String metaHtml = headMetaBuilder(htmlMetas);
|
htmlMetas -> buildMetas(context.getModelFactory(), htmlMetas).forEach(model::add)
|
||||||
IModelFactory modelFactory = context.getModelFactory();
|
)
|
||||||
model.add(modelFactory.createText(metaHtml));
|
|
||||||
})
|
|
||||||
.then();
|
.then();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,19 +98,12 @@ public class ContentTemplateHeadProcessor implements TemplateHeadProcessor {
|
||||||
String CONTENT = "content";
|
String CONTENT = "content";
|
||||||
}
|
}
|
||||||
|
|
||||||
private String headMetaBuilder(List<Map<String, String>> htmlMetas) {
|
private List<ITemplateEvent> buildMetas(IModelFactory modelFactory,
|
||||||
if (htmlMetas == null) {
|
List<Map<String, String>> metas) {
|
||||||
return StringUtils.EMPTY;
|
return metas.stream()
|
||||||
}
|
.map(metaMap ->
|
||||||
StringBuilder sb = new StringBuilder();
|
modelFactory.createStandaloneElementTag("meta", metaMap, DOUBLE, false, true)
|
||||||
for (Map<String, String> htmlMeta : htmlMetas) {
|
).collect(Collectors.toList());
|
||||||
sb.append("<meta");
|
|
||||||
htmlMeta.forEach((k, v) -> {
|
|
||||||
sb.append(" ").append(k).append("=\"").append(v).append("\"");
|
|
||||||
});
|
|
||||||
sb.append(" />\n");
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isPostTemplate(ITemplateContext context) {
|
private boolean isPostTemplate(ITemplateContext context) {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import org.springframework.core.annotation.Order;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.thymeleaf.context.ITemplateContext;
|
import org.thymeleaf.context.ITemplateContext;
|
||||||
import org.thymeleaf.model.IModel;
|
import org.thymeleaf.model.IModel;
|
||||||
|
import org.thymeleaf.model.IProcessableElementTag;
|
||||||
import org.thymeleaf.model.ITemplateEvent;
|
import org.thymeleaf.model.ITemplateEvent;
|
||||||
import org.thymeleaf.model.IText;
|
import org.thymeleaf.model.IText;
|
||||||
import org.thymeleaf.processor.element.IElementModelStructureHandler;
|
import org.thymeleaf.processor.element.IElementModelStructureHandler;
|
||||||
|
@ -59,9 +60,19 @@ public class DuplicateMetaTagProcessor implements TemplateHeadProcessor {
|
||||||
IText otherText = context.getModelFactory()
|
IText otherText = context.getModelFactory()
|
||||||
.createText(text);
|
.createText(text);
|
||||||
otherModel.add(new IndexedModel(i, otherText));
|
otherModel.add(new IndexedModel(i, otherText));
|
||||||
} else {
|
continue;
|
||||||
otherModel.add(new IndexedModel(i, templateEvent));
|
|
||||||
}
|
}
|
||||||
|
if (templateEvent instanceof IProcessableElementTag tag) {
|
||||||
|
var indexedModel = new IndexedModel(i, tag);
|
||||||
|
if ("meta".equals(tag.getElementCompleteName())) {
|
||||||
|
var attribute = tag.getAttribute("name");
|
||||||
|
if (attribute != null) {
|
||||||
|
uniqueMetaTags.put(attribute.getValue(), indexedModel);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
otherModel.add(new IndexedModel(i, templateEvent));
|
||||||
}
|
}
|
||||||
|
|
||||||
otherModel.addAll(uniqueMetaTags.values());
|
otherModel.addAll(uniqueMetaTags.values());
|
||||||
|
|
|
@ -146,8 +146,8 @@ class ContentTemplateHeadProcessorIntegrationTest {
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Post detail</title>
|
<title>Post detail</title>
|
||||||
<meta name="description" content="post-description">
|
|
||||||
<meta name="keyword" content="postK1,postK2">
|
<meta name="keyword" content="postK1,postK2">
|
||||||
|
<meta name="description" content="post-description">
|
||||||
<meta name="other" content="post-other-meta">
|
<meta name="other" content="post-other-meta">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -174,9 +174,9 @@ class HaloProcessorDialectTest {
|
||||||
<title>Post</title>
|
<title>Post</title>
|
||||||
<meta name="global-head-test" content="test" />
|
<meta name="global-head-test" content="test" />
|
||||||
<meta name="content-head-test" content="test" />
|
<meta name="content-head-test" content="test" />
|
||||||
<meta content="post-meta-V1" name="post-meta-V1" />
|
<meta content="post-meta-V1" name="post-meta-V1"/>\
|
||||||
<meta content="post-meta-V2" name="post-meta-V2" />
|
<meta content="post-meta-V2" name="post-meta-V2"/>\
|
||||||
<meta name="description" content="" />
|
<meta name="description" content=""/>\
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<p>post</p>
|
<p>post</p>
|
||||||
|
|
Loading…
Reference in New Issue