org.springframework.boot.web.view.TemplateView Maven / Gradle / Ivy
package org.springframework.boot.web.view;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.expression.MapAccessor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.PropertyPlaceholderHelper;
import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
import org.springframework.web.servlet.View;
import org.springframework.web.util.HtmlUtils;
public class TemplateView implements View {
private final NonRecursivePropertyPlaceholderHelper helper;
private final String template;
private volatile Map expressions;
public TemplateView(String template) {
this.helper = new NonRecursivePropertyPlaceholderHelper("${", "}");
this.template = template;
}
@Override
public String getContentType() {
return "text/html";
}
@Override
public void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {
if (response.getContentType() == null) {
response.setContentType(getContentType());
}
String result = toString(model);
response.getWriter().append(result);
}
private Map getExpressions() {
if (this.expressions == null) {
synchronized (this) {
ExpressionCollector expressionCollector = new ExpressionCollector();
this.helper.replacePlaceholders(this.template, expressionCollector);
this.expressions = expressionCollector.getExpressions();
}
}
return this.expressions;
}
public String toString(Map model) {
Map map = new HashMap(model);
PlaceholderResolver resolver = new ExpressionResolver(getExpressions(), map);
return this.helper.replacePlaceholders(this.template, resolver);
}
}
class NonRecursivePropertyPlaceholderHelper extends PropertyPlaceholderHelper {
NonRecursivePropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix) {
super(placeholderPrefix, placeholderSuffix);
}
@Override
protected String parseStringValue(String strVal, PlaceholderResolver placeholderResolver, Set visitedPlaceholders) {
return super.parseStringValue(strVal, new NonRecursivePlaceholderResolver(placeholderResolver), visitedPlaceholders);
}
private static class NonRecursivePlaceholderResolver implements PlaceholderResolver {
private final PlaceholderResolver resolver;
NonRecursivePlaceholderResolver(PlaceholderResolver resolver) {
this.resolver = resolver;
}
@Override
public String resolvePlaceholder(String placeholderName) {
if (this.resolver instanceof NonRecursivePlaceholderResolver) {
return null;
}
return this.resolver.resolvePlaceholder(placeholderName);
}
}
}
class ExpressionResolver implements PlaceholderResolver {
private final Map expressions;
private final EvaluationContext context;
ExpressionResolver(Map expressions, Map map) {
this.expressions = expressions;
this.context = getContext(map);
}
private EvaluationContext getContext(Map map) {
StandardEvaluationContext context = new StandardEvaluationContext();
context.addPropertyAccessor(new MapAccessor());
context.setRootObject(map);
return context;
}
@Override
public String resolvePlaceholder(String placeholderName) {
Expression expression = this.expressions.get(placeholderName);
return escape(expression == null ? null : expression.getValue(this.context));
}
private String escape(Object value) {
return HtmlUtils.htmlEscape(value == null ? null : value.toString());
}
}
class ExpressionCollector implements PlaceholderResolver {
private final SpelExpressionParser parser = new SpelExpressionParser();
private final Map expressions = new HashMap();
@Override
public String resolvePlaceholder(String name) {
this.expressions.put(name, this.parser.parseExpression(name));
return null;
}
public Map getExpressions() {
return Collections.unmodifiableMap(this.expressions);
}
}