Commit 43d1d926 authored by Phillip Webb's avatar Phillip Webb

Rework ImageBanner Support

Refactor several aspects of the ImageBanner:

- Extract a few new classes and methods from the previous code
- Directly encode ANSI rather than using `${}` properties
- Rework the scaling algorithm to prefer a fixed width
- Allow ImageBanner and TextBanner to be used together
- Rename several of the `banner.image` properties
- Add support for a left hand margin
- Add property meta-data

See gh-4647
parent 60500aef
${Ansi.GREEN} :: Sample application build with Spring Boot${spring-boot.formatted-version} ::${Ansi.DEFAULT}
...@@ -38,7 +38,7 @@ import org.springframework.util.Assert; ...@@ -38,7 +38,7 @@ import org.springframework.util.Assert;
import org.springframework.util.StreamUtils; import org.springframework.util.StreamUtils;
/** /**
* Banner implementation that prints from a source {@link Resource}. * Banner implementation that prints from a source text {@link Resource}.
* *
* @author Phillip Webb * @author Phillip Webb
* @author Vedran Pavic * @author Vedran Pavic
......
...@@ -16,9 +16,6 @@ ...@@ -16,9 +16,6 @@
package org.springframework.boot; package org.springframework.boot;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.security.AccessControlException; import java.security.AccessControlException;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -41,6 +38,7 @@ import org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader; ...@@ -41,6 +38,7 @@ import org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.boot.Banner.Mode;
import org.springframework.boot.diagnostics.FailureAnalyzers; import org.springframework.boot.diagnostics.FailureAnalyzers;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ApplicationContextInitializer;
...@@ -167,19 +165,17 @@ public class SpringApplication { ...@@ -167,19 +165,17 @@ public class SpringApplication {
/** /**
* Default banner location. * Default banner location.
*/ */
public static final String BANNER_LOCATION_PROPERTY_VALUE = "banner.txt"; public static final String BANNER_LOCATION_PROPERTY_VALUE = SpringApplicationBannerPrinter.DEFAULT_BANNER_LOCATION;
/** /**
* Banner location property key. * Banner location property key.
*/ */
public static final String BANNER_LOCATION_PROPERTY = "banner.location"; public static final String BANNER_LOCATION_PROPERTY = SpringApplicationBannerPrinter.BANNER_LOCATION_PROPERTY;
private static final String CONFIGURABLE_WEB_ENVIRONMENT_CLASS = "org.springframework.web.context.ConfigurableWebEnvironment"; private static final String CONFIGURABLE_WEB_ENVIRONMENT_CLASS = "org.springframework.web.context.ConfigurableWebEnvironment";
private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless"; private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";
private static final Banner DEFAULT_BANNER = new SpringBootBanner();
private static final Set<String> SERVLET_ENVIRONMENT_SOURCE_NAMES; private static final Set<String> SERVLET_ENVIRONMENT_SOURCE_NAMES;
static { static {
...@@ -543,60 +539,16 @@ public class SpringApplication { ...@@ -543,60 +539,16 @@ public class SpringApplication {
* @see #setBannerMode * @see #setBannerMode
*/ */
protected void printBanner(Environment environment) { protected void printBanner(Environment environment) {
Banner selectedBanner = selectBanner(environment);
if (this.bannerMode == Banner.Mode.LOG) {
try {
logger.info(createStringFromBanner(selectedBanner, environment));
}
catch (UnsupportedEncodingException ex) {
logger.warn("Failed to create String for banner", ex);
}
}
else {
selectedBanner.printBanner(environment, this.mainApplicationClass,
System.out);
}
}
private Banner selectBanner(Environment environment) {
String location = environment.getProperty(BANNER_LOCATION_PROPERTY,
BANNER_LOCATION_PROPERTY_VALUE);
ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader
: new DefaultResourceLoader(getClassLoader()); : new DefaultResourceLoader(getClassLoader());
Resource resource = resourceLoader.getResource(location); SpringApplicationBannerPrinter banner = new SpringApplicationBannerPrinter(resourceLoader,
if (resource.exists()) { this.banner);
return new ResourceBanner(resource); if (this.bannerMode == Mode.LOG) {
} banner.print(environment, this.mainApplicationClass, logger);
if (this.banner != null) {
return this.banner;
} }
else {
Resource image = getBannerImage(environment, resourceLoader); banner.print(environment, this.mainApplicationClass, System.out);
if (image.exists()) {
return new ImageBanner(image);
}
return DEFAULT_BANNER;
}
private Resource getBannerImage(Environment environment, ResourceLoader resourceLoader) {
String imageLocation = environment.getProperty("banner.image", "banner.gif");
Resource image = resourceLoader.getResource(imageLocation);
if (!image.exists()) {
image = resourceLoader.getResource("banner.jpg");
}
if (!image.exists()) {
image = resourceLoader.getResource("banner.png");
} }
return image;
}
private String createStringFromBanner(Banner banner, Environment environment)
throws UnsupportedEncodingException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
banner.printBanner(environment, this.mainApplicationClass, new PrintStream(baos));
String charset = environment.getProperty("banner.charset", "UTF-8");
return baos.toString(charset);
} }
/** /**
......
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringUtils;
/**
* Class used by {@link SpringApplication} to print the application banner.
*
* @author Phillip Webb
*/
class SpringApplicationBannerPrinter {
static final String BANNER_LOCATION_PROPERTY = "banner.location";
static final String BANNER_IMAGE_LOCATION_PROPERTY = "banner.image.location";
static final String DEFAULT_BANNER_LOCATION = "banner.txt";
static final String[] IMAGE_EXTENSION = { "gif", "jpg", "png" };
private static final Banner DEFAULT_BANNER = new SpringBootBanner();
private final ResourceLoader resourceLoader;
private final Banner fallbackBanner;
SpringApplicationBannerPrinter(ResourceLoader resourceLoader, Banner fallbackBanner) {
this.resourceLoader = resourceLoader;
this.fallbackBanner = fallbackBanner;
}
public void print(Environment environment, Class<?> sourceClass, Log logger) {
Banner banner = getBanner(environment, this.fallbackBanner);
try {
logger.info(createStringFromBanner(banner, environment, sourceClass));
}
catch (UnsupportedEncodingException ex) {
logger.warn("Failed to create String for banner", ex);
}
}
public void print(Environment environment, Class<?> sourceClass, PrintStream out) {
Banner banner = getBanner(environment, this.fallbackBanner);
banner.printBanner(environment, sourceClass, out);
}
private Banner getBanner(Environment environment, Banner definedBanner) {
Banners banners = new Banners();
banners.addIfNotNull(getImageBanner(environment));
banners.addIfNotNull(getTextBanner(environment));
if (banners.hasAtLeastOneBanner()) {
return banners;
}
if (this.fallbackBanner != null) {
return this.fallbackBanner;
}
return DEFAULT_BANNER;
}
private Banner getTextBanner(Environment environment) {
String location = environment.getProperty(BANNER_LOCATION_PROPERTY,
DEFAULT_BANNER_LOCATION);
Resource resource = this.resourceLoader.getResource(location);
if (resource.exists()) {
return new ResourceBanner(resource);
}
return null;
}
private Banner getImageBanner(Environment environment) {
String location = environment.getProperty(BANNER_IMAGE_LOCATION_PROPERTY);
if (StringUtils.hasLength(location)) {
Resource resource = this.resourceLoader.getResource(location);
return (resource.exists() ? new ImageBanner(resource) : null);
}
for (String ext : IMAGE_EXTENSION) {
Resource resource = this.resourceLoader.getResource("banner." + ext);
if (resource.exists()) {
return new ImageBanner(resource);
}
}
return null;
}
private String createStringFromBanner(Banner banner, Environment environment,
Class<?> mainApplicationClass) throws UnsupportedEncodingException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
banner.printBanner(environment, mainApplicationClass, new PrintStream(baos));
String charset = environment.getProperty("banner.charset", "UTF-8");
return baos.toString(charset);
}
/**
* {@link Banner} comprised of other {@link Banner Banners}.
*/
private static class Banners implements Banner {
private final List<Banner> banners = new ArrayList<Banner>();
public void addIfNotNull(Banner banner) {
if (banner != null) {
this.banners.add(banner);
}
}
public boolean hasAtLeastOneBanner() {
return !this.banners.isEmpty();
}
@Override
public void printBanner(Environment environment, Class<?> sourceClass,
PrintStream out) {
for (Banner banner : this.banners) {
banner.printBanner(environment, sourceClass, out);
}
}
}
}
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.ansi;
import java.awt.Color;
import java.awt.color.ColorSpace;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.springframework.util.Assert;
/**
* Utility for working with {@link AnsiColor} in the context of {@link Color AWT Colors}.
*
* @author Craig Burke
* @author Ruben Dijkstra
* @author Phillip Webb
* @author Michael Simons
* @since 1.4.0
*/
public final class AnsiColors {
private static final Map<AnsiColor, LabColor> ANSI_COLOR_MAP;
static {
Map<AnsiColor, LabColor> colorMap = new LinkedHashMap<AnsiColor, LabColor>();
colorMap.put(AnsiColor.BLACK, new LabColor(0x000000));
colorMap.put(AnsiColor.RED, new LabColor(0xAA0000));
colorMap.put(AnsiColor.GREEN, new LabColor(0x00AA00));
colorMap.put(AnsiColor.YELLOW, new LabColor(0xAA5500));
colorMap.put(AnsiColor.BLUE, new LabColor(0x0000AA));
colorMap.put(AnsiColor.MAGENTA, new LabColor(0xAA00AA));
colorMap.put(AnsiColor.CYAN, new LabColor(0x00AAAA));
colorMap.put(AnsiColor.WHITE, new LabColor(0xAAAAAA));
colorMap.put(AnsiColor.BRIGHT_BLACK, new LabColor(0x555555));
colorMap.put(AnsiColor.BRIGHT_RED, new LabColor(0xFF5555));
colorMap.put(AnsiColor.BRIGHT_GREEN, new LabColor(0x55FF00));
colorMap.put(AnsiColor.BRIGHT_YELLOW, new LabColor(0xFFFF55));
colorMap.put(AnsiColor.BRIGHT_BLUE, new LabColor(0x5555FF));
colorMap.put(AnsiColor.BRIGHT_MAGENTA, new LabColor(0xFF55FF));
colorMap.put(AnsiColor.BRIGHT_CYAN, new LabColor(0x55FFFF));
colorMap.put(AnsiColor.BRIGHT_WHITE, new LabColor(0xFFFFFF));
ANSI_COLOR_MAP = Collections.unmodifiableMap(colorMap);
}
private AnsiColors() {
}
public static AnsiColor getClosest(Color color) {
return getClosest(new LabColor(color));
}
private static AnsiColor getClosest(LabColor color) {
AnsiColor result = null;
double resultDistance = Float.MAX_VALUE;
for (Entry<AnsiColor, LabColor> entry : ANSI_COLOR_MAP.entrySet()) {
double distance = color.getDistance(entry.getValue());
if (result == null || distance < resultDistance) {
resultDistance = distance;
result = entry.getKey();
}
}
return result;
}
/**
* Represents a color stored in LAB form.
*/
private static final class LabColor {
private static final ColorSpace XYZ_COLOR_SPACE = ColorSpace
.getInstance(ColorSpace.CS_CIEXYZ);
private final double l;
private final double a;
private final double b;
LabColor(Integer rgb) {
this(rgb == null ? (Color) null : new Color(rgb));
}
LabColor(Color color) {
Assert.notNull(color, "Color must not be null");
float[] lab = fromXyz(color.getColorComponents(XYZ_COLOR_SPACE, null));
this.l = lab[0];
this.a = lab[1];
this.b = lab[2];
}
private float[] fromXyz(float[] xyz) {
return fromXyz(xyz[0], xyz[1], xyz[2]);
}
private float[] fromXyz(float x, float y, float z) {
double l = (f(y) - 16.0) * 116.0;
double a = (f(x) - f(y)) * 500.0;
double b = (f(y) - f(z)) * 200.0;
return new float[] { (float) l, (float) a, (float) b };
}
private double f(double t) {
return (t > (216.0 / 24389.0) ? Math.cbrt(t)
: (1.0 / 3.0) * Math.pow(29.0 / 6.0, 2) * t + (4.0 / 29.0));
}
// See http://en.wikipedia.org/wiki/Color_difference#CIE94
public double getDistance(LabColor other) {
double c1 = Math.sqrt(this.a * this.a + this.b * this.b);
double deltaC = c1 - Math.sqrt(other.a * other.a + other.b * other.b);
double deltaA = this.a - other.a;
double deltaB = this.b - other.b;
double deltaH = Math.sqrt(
Math.max(0.0, deltaA * deltaA + deltaB * deltaB - deltaC * deltaC));
return Math.sqrt(Math.max(0.0,
Math.pow((this.l - other.l) / (1.0), 2)
+ Math.pow(deltaC / (1 + 0.045 * c1), 2)
+ Math.pow(deltaH / (1 + 0.015 * c1), 2.0)));
}
}
}
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.ansi;
import java.awt.Color;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link AnsiColors}.
*
* @author Phillip Webb
*/
public class AnsiColorsTests {
@Test
public void getClosestWhenExactMatchShouldReturnAnsiColor() throws Exception {
assertThat(getClosest(0x000000)).isEqualTo(AnsiColor.BLACK);
assertThat(getClosest(0xAA0000)).isEqualTo(AnsiColor.RED);
assertThat(getClosest(0x00AA00)).isEqualTo(AnsiColor.GREEN);
assertThat(getClosest(0xAA5500)).isEqualTo(AnsiColor.YELLOW);
assertThat(getClosest(0x0000AA)).isEqualTo(AnsiColor.BLUE);
assertThat(getClosest(0xAA00AA)).isEqualTo(AnsiColor.MAGENTA);
assertThat(getClosest(0x00AAAA)).isEqualTo(AnsiColor.CYAN);
assertThat(getClosest(0xAAAAAA)).isEqualTo(AnsiColor.WHITE);
assertThat(getClosest(0x555555)).isEqualTo(AnsiColor.BRIGHT_BLACK);
assertThat(getClosest(0xFF5555)).isEqualTo(AnsiColor.BRIGHT_RED);
assertThat(getClosest(0x55FF00)).isEqualTo(AnsiColor.BRIGHT_GREEN);
assertThat(getClosest(0xFFFF55)).isEqualTo(AnsiColor.BRIGHT_YELLOW);
assertThat(getClosest(0x5555FF)).isEqualTo(AnsiColor.BRIGHT_BLUE);
assertThat(getClosest(0xFF55FF)).isEqualTo(AnsiColor.BRIGHT_MAGENTA);
assertThat(getClosest(0x55FFFF)).isEqualTo(AnsiColor.BRIGHT_CYAN);
assertThat(getClosest(0xFFFFFF)).isEqualTo(AnsiColor.BRIGHT_WHITE);
}
@Test
public void getClosestWhenCloseShouldReturnAnsiColor() throws Exception {
assertThat(getClosest(0x292424)).isEqualTo(AnsiColor.BLACK);
assertThat(getClosest(0x8C1919)).isEqualTo(AnsiColor.RED);
assertThat(getClosest(0x0BA10B)).isEqualTo(AnsiColor.GREEN);
assertThat(getClosest(0xB55F09)).isEqualTo(AnsiColor.YELLOW);
assertThat(getClosest(0x0B0BA1)).isEqualTo(AnsiColor.BLUE);
assertThat(getClosest(0xA312A3)).isEqualTo(AnsiColor.MAGENTA);
assertThat(getClosest(0x0BB5B5)).isEqualTo(AnsiColor.CYAN);
assertThat(getClosest(0xBAB6B6)).isEqualTo(AnsiColor.WHITE);
assertThat(getClosest(0x615A5A)).isEqualTo(AnsiColor.BRIGHT_BLACK);
assertThat(getClosest(0xF23333)).isEqualTo(AnsiColor.BRIGHT_RED);
assertThat(getClosest(0x55E80C)).isEqualTo(AnsiColor.BRIGHT_GREEN);
assertThat(getClosest(0xF5F54C)).isEqualTo(AnsiColor.BRIGHT_YELLOW);
assertThat(getClosest(0x5656F0)).isEqualTo(AnsiColor.BRIGHT_BLUE);
assertThat(getClosest(0xFA50FA)).isEqualTo(AnsiColor.BRIGHT_MAGENTA);
assertThat(getClosest(0x56F5F5)).isEqualTo(AnsiColor.BRIGHT_CYAN);
assertThat(getClosest(0xEDF5F5)).isEqualTo(AnsiColor.BRIGHT_WHITE);
}
private AnsiColor getClosest(int rgb) {
return AnsiColors.getClosest(new Color(rgb));
}
}
...@@ -13,9 +13,36 @@ ...@@ -13,9 +13,36 @@
{ {
"name": "banner.location", "name": "banner.location",
"type": "org.springframework.core.io.Resource", "type": "org.springframework.core.io.Resource",
"description": "Banner file location.", "description": "Banner text resource location.",
"defaultValue": "classpath:banner.txt" "defaultValue": "classpath:banner.txt"
}, },
{
"name": "banner.image.location",
"type": "org.springframework.core.io.Resource",
"description": "Banner image file location.",
"defaultValue": "banner.gif"
},
{
"name": "banner.image.width",
"type": "java.lang.Integer",
"description": "Banner image width (in chars)."
},
{
"name": "banner.image.height",
"type": "java.lang.Integer",
"description": "Banner image height (in chars)."
},
{
"name": "banner.image.margin",
"type": "java.lang.Integer",
"description": "Left hand image height (in chars)."
},
{
"name": "banner.image.invert",
"type": "java.lang.Boolean",
"description": "Invert images for dark console themes.",
"defaultValue": false
},
{ {
"name": "debug", "name": "debug",
"type": "java.lang.Boolean", "type": "java.lang.Boolean",
......
...@@ -67,6 +67,7 @@ import org.springframework.core.env.Environment; ...@@ -67,6 +67,7 @@ import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource; import org.springframework.core.env.PropertySource;
import org.springframework.core.env.StandardEnvironment; import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.ResourceLoader;
...@@ -196,29 +197,26 @@ public class SpringApplicationTests { ...@@ -196,29 +197,26 @@ public class SpringApplicationTests {
} }
@Test @Test
public void textBannerTakesPrecedence() throws Exception { public void imageBannerAndTextBanner() throws Exception {
SpringApplication application = new SpringApplication(ExampleConfig.class); SpringApplication application = new SpringApplication(ExampleConfig.class);
BannerResourceLoaderStub resourceLoader = new BannerResourceLoaderStub(); MockResourceLoader resourceLoader = new MockResourceLoader();
resourceLoader.addResource("banner.gif", "banners/black-and-white.gif"); resourceLoader.addResource("banner.gif", "black-and-white.gif");
resourceLoader.addResource("banner.txt", "banners/foobar.txt"); resourceLoader.addResource("banner.txt", "foobar.txt");
application.setWebEnvironment(false); application.setWebEnvironment(false);
application.setResourceLoader(resourceLoader); application.setResourceLoader(resourceLoader);
application.run(); application.run();
assertThat(this.output.toString()).contains("@@@@").contains("Foo Bar");
assertThat(this.output.toString()).startsWith("Foo Bar");
} }
@Test @Test
public void imageBannerLoads() throws Exception { public void imageBannerLoads() throws Exception {
SpringApplication application = new SpringApplication(ExampleConfig.class); SpringApplication application = new SpringApplication(ExampleConfig.class);
BannerResourceLoaderStub resourceLoader = new BannerResourceLoaderStub(); MockResourceLoader resourceLoader = new MockResourceLoader();
resourceLoader.addResource("banner.gif", "banners/black-and-white.gif"); resourceLoader.addResource("banner.gif", "black-and-white.gif");
application.setWebEnvironment(false); application.setWebEnvironment(false);
application.setResourceLoader(resourceLoader); application.setResourceLoader(resourceLoader);
application.run(); application.run();
assertThat(this.output.toString()).contains("@@@@@@");
assertThat(this.output.toString()).startsWith("@");
} }
@Test @Test
...@@ -1120,28 +1118,23 @@ public class SpringApplicationTests { ...@@ -1120,28 +1118,23 @@ public class SpringApplicationTests {
} }
private static class BannerResourceLoaderStub extends DefaultResourceLoader { private static class MockResourceLoader implements ResourceLoader {
private Map<String, String> resources = new HashMap<String, String>(); private final Map<String, Resource> resources = new HashMap<String, Resource>();
Resource notFoundResource;
BannerResourceLoaderStub() { public void addResource(String source, String path) {
this.notFoundResource = super.getResource("classpath:foo/bar/foobar"); this.resources.put(source, new ClassPathResource(path, getClass()));
assert !this.notFoundResource.exists();
} }
public void addResource(String file, String realPath) { @Override
this.resources.put(file, realPath); public Resource getResource(String path) {
Resource resource = this.resources.get(path);
return (resource == null ? new ClassPathResource("doesnotexit") : resource);
} }
@Override @Override
public Resource getResource(String s) { public ClassLoader getClassLoader() {
if (this.resources.containsKey(s)) { return getClass().getClassLoader();
return super.getResource("classpath:" + this.resources.get(s));
}
else {
return this.notFoundResource;
}
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment