春季启动:覆盖图标


83

如何覆盖Spring Boot的图标?

注意:这是我的另一个问题,提供了不涉及任何编码的另一个解决方案:Spring Boot:是否可以在带有胖子的任意目录中使用外部application.properties文件?它用于application.properties,但也可以应用于收藏夹图标。实际上,我现在正在使用该方法来替换图标图标。

如果我实现的类具有@EnableWebMvc,则不会加载Spring Boot的WebMvcAutoConfiguration类,并且可以通过将其放置在静态内容的根目录中来提供自己的图标。

否则,WebMvcAutoConfiguration会注册faviconRequestHandler bean,(请参见源https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ web / WebMvcAutoConfiguration.java),并提供“绿叶”图标,该图标位于Spring Boot的主资源目录中。

如何在不实现自己具有@EnableWebMvc的类的情况下覆盖它,从而禁用Spring Boot的WebMvcAutoConfiguration类的整个默认配置功能?

另外,由于我希望在客户端(Web浏览器)端尽快更新图标文件,因此我想将收藏图标的缓存周期设置为0。(例如下面的代码,我将其用于更改文件后,必须尽快在客户端上更新“静态” webapp内容和脚本文件。)

public void addResourceHandlers(ResourceHandlerRegistry registry)
{
    registry.addResourceHandler("/**")
        .addResourceLocations("/")
        .setCachePeriod(0);
}

因此,仅找到保存Spring Boot的faviconRequestHandler认可的favicon.ico文件的位置可能不够。

更新

现在,我知道可以通过将图标图标放置到src / main / resources目录中来覆盖默认值。但是缓存期问题仍然存在。
此外,最好将收藏夹图标放置在放置静态Web文件的目录中,而不是资源目录中。

更新

好的,我设法覆盖了默认值。我所做的如下:

@Configuration
public class WebMvcConfiguration
{
    @Bean
    public WebMvcConfigurerAdapter faviconWebMvcConfiguration()
    {
        return new FaviconWebMvcConfiguration();
    }

    public class FaviconWebMvcConfiguration extends WebMvcConfigurerAdapter
    {
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry)
        {
            registry.setOrder(Integer.MIN_VALUE);
            registry.addResourceHandler("/favicon.ico")
                .addResourceLocations("/")
                .setCachePeriod(0);
        }
    }
}

基本上,我通过调用Registry.setOrder(Integer.MIN_VALUE)添加具有最高顺序的资源处理程序来覆盖默认的处理程序。

由于Spring Boot中的默认值具有顺序值(Integer.MIN_VALUE + 1),(请参阅https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/中的FaviconConfiguration类src / main / java / org / springframework / boot / autoconfigure / web / WebMvcAutoConfiguration.java),我的处理程序胜出。

这个可以吗?还有另一种方法(比我做的还要温柔)吗?

更新

不好 当我调用时registry.setOrder(Integer.MIN_VALUE),实际上我提高了所有资源处理程序的优先级。因此,当我将以下代码添加到另一个中时WebMvcConfigurerAdapter,实际上所有http请求都定向到该资源处理程序,从而防止Java代码进行任何动态处理。

public void addResourceHandlers(ResourceHandlerRegistry registry)
{
    registry.addResourceHandler("/**")
        .addResourceLocations("/")
        .setCachePeriod(0);
}

需要另一种解决方案。

更新

目前,我找不到覆盖Spring Boot提供的favicon功能的方法。
也许有一种添加我自己的HandlerMappingbean的方法,但是我不知道该怎么做。

现在,我可以选择以下选项之一:

  1. 有一个@EnableWebMvc因此禁用了Spring BootWebMvcAutoConfiguration类的类。(我可以复制WebMvcAutoConfiguration类的代码并删除favicon功能)
  2. 放弃将favicon文件放置在任意位置的自由,并根据Spring Boot的favicon功能的要求将其放置在资源目录中。并忽略缓存问题。

但是,两种选择都不令人满意。
我只想将favicon文件与我的静态Web文件(可以更改为目录的根目录,因为可以更改文档根目录)一起放置并解决缓存问题。
我想念什么吗?
任何建议将不胜感激。

更新

顺便说一句,我要更改图标图标和其他静态文件的位置的原因如下。目前主要是开发环境问题。

我正在构建一个单页Web应用程序(SPA)。

库/框架:

  • 对于服务器端,我使用Spring。(当然)
  • 对于客户端(Web浏览器),我使用AngularJS。

工具:

  • 对于服务器端,我使用Spring Tool Suite。
  • 对于客户端,我使用WebStorm。

主目录结构:

ProjectRoot\
    src\
    bin\
    build\
    webapp\
    build.gradle
  • src:我的Spring Java源文件所在的位置。
  • bin:Spring Tool Suite放置其构建输出的位置。
  • build:“ gradle build”放置其生成输出的位置。
  • webapp:我的客户端源文件(.js,.css,.htm和favicon)所在的位置。因此,这是WebStorm项目目录。(如有必要,我可以更改目录名称)

我想要的是:

  • 为了能够修改和测试我的客户端代码而无需重建/重新启动我的Spring服务器应用程序。因此,不得将客户端代码放入jar文件中。无论如何,Spring Tool Suite根本不会构建jar文件(至少对于当前配置而言)。
  • 为了能够使用客户端代码测试我的Spring服务器应用程序,请在Spring Tool Suite输出和gradle输出之间轻松切换。因此,必须可以从build子目录中的服务器应用程序(实际上是build\libs)和bin目录中的服务器应用程序访问客户端代码。
  • 当我修改客户端代码时,它必须立即可用于Web浏览器。因此,浏览器一定不能无限期地对其进行缓存,并且必须始终要求服务器进行更新。
  • 部署后,客户端代码必须可修改,而无需重建/重新启动服务器应用程序。因此,不得将客户端代码放入jar文件中。

关于缓存问题:

在addResourceHandlers()上没有setCachePeriod(0)的情况下,Google Chrome浏览器会无限期地缓存文件,而无需询问服务器是否有更新。它甚至不连接到服务器。(Google工程师说这种行为是正确的。)因此,我所能做的就是手动清除浏览器缓存。它在开发环境上令人沮丧,在生产环境上令人无法接受。

顺便说一句,Node.js上的express.js模块提供了合理的默认HTTP标头,以便Google Chrome浏览器要求服务器进行更新。当我回顾Spring和express.js使用Fiddler生成的HTTP标头时,它们是不同的。

任何改善我的环境的建议将不胜感激。
由于我是Spring的初学者,所以我可能会缺少一些东西。

更新

终于我有了工作代码。如下:

@Configuration
public static class FaviconConfiguration
{
    @Bean
    public SimpleUrlHandlerMapping myFaviconHandlerMapping()
    {
        SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
        mapping.setOrder(Integer.MIN_VALUE);
        mapping.setUrlMap(Collections.singletonMap("/favicon.ico",
            myFaviconRequestHandler()));
        return mapping;
    }

    @Autowired
    ApplicationContext applicationContext;

    @Bean
    protected ResourceHttpRequestHandler myFaviconRequestHandler()
    {
        ResourceHttpRequestHandler requestHandler =
            new ResourceHttpRequestHandler();
        requestHandler.setLocations(Arrays
            .<Resource> asList(applicationContext.getResource("/")));
        requestHandler.setCacheSeconds(0);
        return requestHandler;
    }
}

注意Bean名称。我添加了“我的”以避免名称冲突。
自动装配应用程序上下文本身看起来很尴尬,但是它是模仿中的代码所必需的org.springframework.web.servlet.config.annotation.ResourceHandlerRegistration.addResourceLocations()

现在,我有了一个没有缓存问题的favicon处理程序,并且可以将favicon文件放在我想要的任何位置。
谢谢。


1
您的方法看起来不错。但是,它不会代替默认的Spring MVC资源处理程序吗(因此将不再提供静态资源classpath:/static)。(这就是为什么Boot中的favicon支持在其自己的HandlerMapping中的原因。)
Dave Syer 2013年

@DaveSyer现在我意识到这还不行。我在上面写了第三次更新。也许HandlerMapping需要分开。
zeodtr

@DaveSyer请参阅上面的第四个更新。还有其他办法吗?例如,我可以注册自己的HandlerMapping吗?
zeodtr

是的,您可以添加一个HandlerMapping(只需从Boot中复制一个,并为其赋予更高的优先级)。我不太确定为什么您会关心的位置,favicon.ico file但是如果您愿意,我们可以将其配置为可配置的。所有浏览器也会缓存它,因此我怀疑缓存设置是否重要,但很高兴被证明是错误的。
Dave Syer 2013年

@DaveSyer请参阅更新后的问题,以了解为什么要将静态文件放置在其他位置的原因。还有缓存问题。
zeodtr 2013年

Answers:


53

您可以将自己的favicon.ico放在类路径的根目录或任何静态资源位置(例如classpath:/static)中。您也可以使用单个标志完全禁用Favicon分辨率spring.mvc.favicon.enabled=false

或者,要完全控制您,可以添加一个HandlerMapping(只需从Boot复制一个并赋予其更高的优先级),例如

@Configuration
public static class FaviconConfiguration {

@Bean
public SimpleUrlHandlerMapping faviconHandlerMapping() {
    SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
    mapping.setOrder(Integer.MIN_VALUE);
    mapping.setUrlMap(Collections.singletonMap("mylocation/favicon.ico",
            faviconRequestHandler()));
    return mapping;
}

@Bean
protected ResourceHttpRequestHandler faviconRequestHandler() {
    ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
    requestHandler.setLocations(Arrays
            .<Resource> asList(new ClassPathResource("/")));
    return requestHandler;
}
}

谢谢。我以为我已经尝试过了,但是现在我想到了,我错过了@Configuration注释。顺便说一句,我写了为什么要将静态文件放在问题的不同位置的原因。
zeodtr 2013年

顺便说一句,由于我必须使用ResourceLoader.gerResource(“ /”)在文档根目录中获取文件(对吗?),因此我必须@Autowire ApplicationContext。DI应用程序上下文可以吗?有人说这是坏事。
zeodtr 2013年

我正在尝试你的建议。需要注意的一件事:我的bean名称一定不能是'faviconHandlerMapping',因为它会导致bean名称与Spring Boot的faviconHandlerMapping bean发生冲突。org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIn includedAncestor‌s()调用的方法将仅选择2个bean中的一个,而org.springframework.web.servlet.initHandlerMappings()再次调用该方法。看来我的bean较早被加载,然后被名称冲突覆盖。
zeodtr

是注册的HandlerMapping豆的名称如下:{ faviconHandlerMappingrequestMappingHandlerMappingviewControllerHandlerMappingbeanNameHandlerMappingresourceHandlerMappingdefaultServletHandlerMappingendpointHandlerMapping}所以我必须避免这些名字。
zeodtr

2
您应该阅读更新的答案以及用户指南。如果您只想更改图标,那从来就不是一个非常困难的更改。我不知道为什么OP这么麻烦。
戴夫·瑟

75

这对我来说都不是必需的。

当您可以将资源与生成的JAR捆绑在一起时,为什么要覆盖默认值,而该JAR的优先级将高于默认值。

为了获得自定义favicon.ico文件,我src/main/resources为应用程序创建了一个目录,然后将favicon.ico文件复制到该目录中。此资源目录中的文件移动到了已编译JAR的根目录,因此favicon.ico在Spring提供该自定义文件之前就已经找到了您的自定义文件。

执行上述操作可获得与上述更新的解决方案相同的效果。

请注意,从v1.2.0开始,您还可以将文件放入src/main/resources/static


6
原因很简单。我不想将favicon文件放入JAR。
zeodtr 2014年

@zeodtr只是好奇为什么。对我来说,这似乎是最自然的。但是,我希望它会在src/main/resources/static/images
btiernay 2014年

1
@btiernay这是因为Web服务器是与Web客户端不同的实体。和收藏夹图标属于客户端。Web服务器的war文件没有理由包含属于客户端的文件,可以根据用户的需要对其进行更频繁地修改。
zeodtr 2014年

只是一个供参考,这是现在可能解决favicon.ico来自staticgithub.com/spring-projects/spring-boot/commit/...
btiernay

1
src / main / resources / static路径运作良好。这是最简单和常规的方法。
2015年

29

我真的很喜欢Springboot,因为总体上它充满了智能解决方案,但是我拒绝注册应用程序bean以提供favicon,因为那简直是愚蠢的。

我只是在html页面标题中添加了自己的收藏夹链接,就像这样。

<link rel="icon" type="image/png" href="images/fav.png">

然后,我将我的收藏夹重命名并放置在

<ProjFolder>/src/main/resources/static/images/fav.png

现在,我在Chrome和Firefox浏览器选项卡和Safari地址栏中都有一个图标,而不必使用Spring和Java,并且对于这种琐碎的功能,我不必在较新版本中追逐对Springboot的更改。


4
您无需再处理处理程序映射(只需将favicon.ico放入您的静态资源中)。
戴夫·塞尔

就是这么简单!谢谢。我将其添加到片段中。
Lay Leangsros,2016年

如果您仅将springboot用作API服务后端怎么办,那里没有任何html页面:/
Paramvir Singh Karwal,

@ParamvirSinghKarwal如果您只有一项服务,为什么还要一个favicon?
jeremyjjbrown

如果您直接从浏览器的地址访问api,它将显示spring应用程序的默认图标,就像绿叶一样。我希望它成为品牌的收藏夹。我能够做到。
Paramvir Singh Karwal

13

从Spring Boot 1.2.2和1.1.11开始,您可以使用spring.mvc.favicon.enabled = false属性轻松禁用默认图标。

有关更多信息,请访问:

更新:spring.mvc.favicon.enabled从Spring Boot 2.2.x开始,不再有属性


从spring boot 2.2中删除了spring.mvc.favicon.enabled。你知道用什么代替吗?
士兰

1
@Shilan它已被替换为空,因为不再有默认的图标。如果需要,则必须为自己的favicon配置映射。
Trynkiewicz Mariusz

1
是的,最后我发现我需要这样做:@Override public void addResourceHandlers(ResourceHandlerRegistry Registry){Registry.addResourceHandler(“ / favicon.ico”)。addResourceLocations(“ classpath:/ static /”); }
士兰

2

较新版本的Boot(可以肯定是1.2,但也可能是1.1.8)允许您将favicon.ico放入您的静态资源中。


2

我尝试了很多选项/变体,但是只有这个可行。(春季启动2.2.7)

Favicon.ico文件和robots.txt文件放在/ resources / static中

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
  protected void configure(HttpSecurity http) throws Exception { 
    http
      .authorizeRequests()
        .antMatchers("/favicon.ico").permitAll()
        .antMatchers("/robots.txt").permitAll()
        .antMatchers("/").permitAll()
        .anyRequest().authenticated();
    }
}

@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
@Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler(
      "/favicon.ico",
      "/robots.txt")
      .addResourceLocations(
        "classpath:/static/");
  }
}

如果有帮助,请喜欢;)


1

Registry.addResourceHandler(“ / robots.txt”)。addResourceLocations(“ /”);

Registry.addResourceHandler(“ / favicon.ico”)。addResourceLocations(“ /”);

robots.txt,favicon.ico文件位置:/ src / main / resources

我用弹簧靴1.2.1

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.