SpringBoot学习(九) ------访问静态web资源

SpringBoot可以通过3种方式来获取静态资源

方式一:访问所有webjars/**,访问静态资源的路径为META-INF/resources/webjars,可以在此路径中查找静态资源。

举个例子:

新建一个项目工程

并在pom.xml文件中引入webjars包,

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.2.1</version>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.7.RELEASE</version>
                <configuration>
                    <mainClass>com.example.demo.DemoApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

 核心代码:

 <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.2.1</version>
</dependency>

可以参考一下这个引入静态资源的网站https://www.webjars.org/

 然后我们通过浏览器访问一下web静态资源,路径为http://localhost:8080/webjars/jquery/3.2.1/jquery.js

为什么可以访问webjars目录下的所有静态资源,我们可以通过查看org.springframework.boot.autoconfigure.web包下面的WebMvcAutoConfiguration.class类的源代码分析其原因:

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
		        if (!this.resourceProperties.isAddMappings()) {
				logger.debug("Default resource handling disabled");
				return;
			}
			Integer cachePeriod = this.resourceProperties.getCachePeriod();
			if (!registry.hasMappingForPattern("/webjars/**")) {
				customizeResourceHandlerRegistration(
						registry.addResourceHandler("/webjars/**")
								.addResourceLocations(
										"classpath:/META-INF/resources/webjars/")
						.setCachePeriod(cachePeriod));
			}
			String staticPathPattern = this.mvcProperties.getStaticPathPattern();
			if (!registry.hasMappingForPattern(staticPathPattern)) {
				customizeResourceHandlerRegistration(
						registry.addResourceHandler(staticPathPattern)
								.addResourceLocations(
										this.resourceProperties.getStaticLocations())
						.setCachePeriod(cachePeriod));
			}
}

这里直接给staticPathPattern赋值,然后将该值赋给了资源访问路径方法。所以能够通过/webjars/**对静态资源进行访问。

方式二:./**访问当前项目的任何资源

 可以通过以下四种路径放置web静态资源,并访问web静态资源(静态资源的文件夹)

 

classpath:/META-INF/resources/* 
classpath:/resources/*
classpath:/static/*
classpath:/public/*
"/":当前项目的根路径

 

这里四个路径的优先级顺序分别从上到下依次递减。

举个例子:

在项目resource文件夹下建一个static静态文件夹,在image目录下放beautiful.jpeg文件

我们访问这个路径:localhost:8080/image/a.png,可以访问到a.png静态资源

为什么可以访问以上四个路径下的所有静态资源,我们可以通过查看org.springframework.boot.autoconfigure.web包下面的ResourceProperties.class类的源代码分析其原因

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.boot.autoconfigure.web;

import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.convert.DurationUnit;
import org.springframework.http.CacheControl;

@ConfigurationProperties(
    prefix = "spring.resources",
    ignoreUnknownFields = false
)
public class ResourceProperties {
    private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
    private String[] staticLocations;
    private boolean addMappings;
    private final ResourceProperties.Chain chain;
    private final ResourceProperties.Cache cache;

    public ResourceProperties() {
        this.staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
        this.addMappings = true;
        this.chain = new ResourceProperties.Chain();
        this.cache = new ResourceProperties.Cache();
    }

    public String[] getStaticLocations() {
        return this.staticLocations;
    }

    public void setStaticLocations(String[] staticLocations) {
        this.staticLocations = this.appendSlashIfNecessary(staticLocations);
    }

    private String[] appendSlashIfNecessary(String[] staticLocations) {
        String[] normalized = new String[staticLocations.length];

        for(int i = 0; i < staticLocations.length; ++i) {
            String location = staticLocations[i];
            normalized[i] = location.endsWith("/") ? location : location + "/";
        }

        return normalized;
    }

    public boolean isAddMappings() {
        return this.addMappings;
    }

    public void setAddMappings(boolean addMappings) {
        this.addMappings = addMappings;
    }

    public ResourceProperties.Chain getChain() {
        return this.chain;
    }

    public ResourceProperties.Cache getCache() {
        return this.cache;
    }

    public static class Cache {
        @DurationUnit(ChronoUnit.SECONDS)
        private Duration period;
        private final ResourceProperties.Cache.Cachecontrol cachecontrol = new ResourceProperties.Cache.Cachecontrol();

        public Cache() {
        }

        public Duration getPeriod() {
            return this.period;
        }

        public void setPeriod(Duration period) {
            this.period = period;
        }

        public ResourceProperties.Cache.Cachecontrol getCachecontrol() {
            return this.cachecontrol;
        }

        public static class Cachecontrol {
            @DurationUnit(ChronoUnit.SECONDS)
            private Duration maxAge;
            private Boolean noCache;
            private Boolean noStore;
            private Boolean mustRevalidate;
            private Boolean noTransform;
            private Boolean cachePublic;
            private Boolean cachePrivate;
            private Boolean proxyRevalidate;
            @DurationUnit(ChronoUnit.SECONDS)
            private Duration staleWhileRevalidate;
            @DurationUnit(ChronoUnit.SECONDS)
            private Duration staleIfError;
            @DurationUnit(ChronoUnit.SECONDS)
            private Duration sMaxAge;

            public Cachecontrol() {
            }

            public Duration getMaxAge() {
                return this.maxAge;
            }

            public void setMaxAge(Duration maxAge) {
                this.maxAge = maxAge;
            }

            public Boolean getNoCache() {
                return this.noCache;
            }

            public void setNoCache(Boolean noCache) {
                this.noCache = noCache;
            }

            public Boolean getNoStore() {
                return this.noStore;
            }

            public void setNoStore(Boolean noStore) {
                this.noStore = noStore;
            }

            public Boolean getMustRevalidate() {
                return this.mustRevalidate;
            }

            public void setMustRevalidate(Boolean mustRevalidate) {
                this.mustRevalidate = mustRevalidate;
            }

            public Boolean getNoTransform() {
                return this.noTransform;
            }

            public void setNoTransform(Boolean noTransform) {
                this.noTransform = noTransform;
            }

            public Boolean getCachePublic() {
                return this.cachePublic;
            }

            public void setCachePublic(Boolean cachePublic) {
                this.cachePublic = cachePublic;
            }

            public Boolean getCachePrivate() {
                return this.cachePrivate;
            }

            public void setCachePrivate(Boolean cachePrivate) {
                this.cachePrivate = cachePrivate;
            }

            public Boolean getProxyRevalidate() {
                return this.proxyRevalidate;
            }

            public void setProxyRevalidate(Boolean proxyRevalidate) {
                this.proxyRevalidate = proxyRevalidate;
            }

            public Duration getStaleWhileRevalidate() {
                return this.staleWhileRevalidate;
            }

            public void setStaleWhileRevalidate(Duration staleWhileRevalidate) {
                this.staleWhileRevalidate = staleWhileRevalidate;
            }

            public Duration getStaleIfError() {
                return this.staleIfError;
            }

            public void setStaleIfError(Duration staleIfError) {
                this.staleIfError = staleIfError;
            }

            public Duration getSMaxAge() {
                return this.sMaxAge;
            }

            public void setSMaxAge(Duration sMaxAge) {
                this.sMaxAge = sMaxAge;
            }

            public CacheControl toHttpCacheControl() {
                PropertyMapper map = PropertyMapper.get();
                CacheControl control = this.createCacheControl();
                map.from(this::getMustRevalidate).whenTrue().toCall(control::mustRevalidate);
                map.from(this::getNoTransform).whenTrue().toCall(control::noTransform);
                map.from(this::getCachePublic).whenTrue().toCall(control::cachePublic);
                map.from(this::getCachePrivate).whenTrue().toCall(control::cachePrivate);
                map.from(this::getProxyRevalidate).whenTrue().toCall(control::proxyRevalidate);
                map.from(this::getStaleWhileRevalidate).whenNonNull().to((duration) -> {
                    control.staleWhileRevalidate(duration.getSeconds(), TimeUnit.SECONDS);
                });
                map.from(this::getStaleIfError).whenNonNull().to((duration) -> {
                    control.staleIfError(duration.getSeconds(), TimeUnit.SECONDS);
                });
                map.from(this::getSMaxAge).whenNonNull().to((duration) -> {
                    control.sMaxAge(duration.getSeconds(), TimeUnit.SECONDS);
                });
                return control.getHeaderValue() == null ? null : control;
            }

            private CacheControl createCacheControl() {
                if (Boolean.TRUE.equals(this.noStore)) {
                    return CacheControl.noStore();
                } else if (Boolean.TRUE.equals(this.noCache)) {
                    return CacheControl.noCache();
                } else {
                    return this.maxAge != null ? CacheControl.maxAge(this.maxAge.getSeconds(), TimeUnit.SECONDS) : CacheControl.empty();
                }
            }
        }
    }

    public static class Fixed {
        private boolean enabled;
        private String[] paths = new String[]{"/**"};
        private String version;

        public Fixed() {
        }

        public boolean isEnabled() {
            return this.enabled;
        }

        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }

        public String[] getPaths() {
            return this.paths;
        }

        public void setPaths(String[] paths) {
            this.paths = paths;
        }

        public String getVersion() {
            return this.version;
        }

        public void setVersion(String version) {
            this.version = version;
        }
    }

    public static class Content {
        private boolean enabled;
        private String[] paths = new String[]{"/**"};

        public Content() {
        }

        public boolean isEnabled() {
            return this.enabled;
        }

        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }

        public String[] getPaths() {
            return this.paths;
        }

        public void setPaths(String[] paths) {
            this.paths = paths;
        }
    }

    public static class Strategy {
        private final ResourceProperties.Fixed fixed = new ResourceProperties.Fixed();
        private final ResourceProperties.Content content = new ResourceProperties.Content();

        public Strategy() {
        }

        public ResourceProperties.Fixed getFixed() {
            return this.fixed;
        }

        public ResourceProperties.Content getContent() {
            return this.content;
        }
    }

    public static class Chain {
        private Boolean enabled;
        private boolean cache = true;
        private boolean htmlApplicationCache = false;
        private boolean compressed = false;
        private final ResourceProperties.Strategy strategy = new ResourceProperties.Strategy();

        public Chain() {
        }

        public Boolean getEnabled() {
            return getEnabled(this.getStrategy().getFixed().isEnabled(), this.getStrategy().getContent().isEnabled(), this.enabled);
        }

        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }

        public boolean isCache() {
            return this.cache;
        }

        public void setCache(boolean cache) {
            this.cache = cache;
        }

        public ResourceProperties.Strategy getStrategy() {
            return this.strategy;
        }

        public boolean isHtmlApplicationCache() {
            return this.htmlApplicationCache;
        }

        public void setHtmlApplicationCache(boolean htmlApplicationCache) {
            this.htmlApplicationCache = htmlApplicationCache;
        }

        public boolean isCompressed() {
            return this.compressed;
        }

        public void setCompressed(boolean compressed) {
            this.compressed = compressed;
        }

        static Boolean getEnabled(boolean fixedEnabled, boolean contentEnabled, Boolean chainEnabled) {
            return !fixedEnabled && !contentEnabled ? chainEnabled : Boolean.TRUE;
        }
    }
}

 核心代码:

    private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};

 这里定义了我们的四个访问路径,因此,静态资源可以通过这四个访问路径进行访问。

配置欢迎页映射

@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern());
     welcomePageHandlerMapping.setInterceptors(this.getInterceptors(mvcConversionService, mvcResourceUrlProvider));
     welcomePageHandlerMapping.setCorsConfigurations(this.getCorsConfigurations());
     return welcomePageHandlerMapping;
}

 可以跟踪this.mvcProperties.getStaticPathPattern()看到页面被"/**"映射

private org.springframework.validation.DefaultMessageCodesResolver.Format messageCodesResolverFormat;
    private Locale locale;
    private WebMvcProperties.LocaleResolver localeResolver;
    private final WebMvcProperties.Format format;
    private boolean dispatchTraceRequest;
    private boolean dispatchOptionsRequest;
    private boolean ignoreDefaultModelOnRedirect;
    private boolean publishRequestHandledEvents;
    private boolean throwExceptionIfNoHandlerFound;
    private boolean logRequestDetails;
    private boolean logResolvedException;
    private String staticPathPattern;
    private final WebMvcProperties.Async async;
    private final WebMvcProperties.Servlet servlet;
    private final WebMvcProperties.View view;
    private final WebMvcProperties.Contentnegotiation contentnegotiation;
    private final WebMvcProperties.Pathmatch pathmatch;

    public WebMvcProperties() {
        this.localeResolver = WebMvcProperties.LocaleResolver.ACCEPT_HEADER;
        this.format = new WebMvcProperties.Format();
        this.dispatchTraceRequest = false;
        this.dispatchOptionsRequest = true;
        this.ignoreDefaultModelOnRedirect = true;
        this.publishRequestHandledEvents = true;
        this.throwExceptionIfNoHandlerFound = false;
        this.logResolvedException = false;
        this.staticPathPattern = "/**";
        this.async = new WebMvcProperties.Async();
        this.servlet = new WebMvcProperties.Servlet();
        this.view = new WebMvcProperties.View();
        this.contentnegotiation = new WebMvcProperties.Contentnegotiation();
        this.pathmatch = new WebMvcProperties.Pathmatch();
    }

当在/resources/public的目录下创建index.html文件之后,默认的访问首页为此index.html

index.html

<html>
<head>
    <meta charset="utf-8">
    <title>首页</title>
</head>
<body>
<h1 size="10px">首页</h1>
</body>
</html>  

运行SpringBoot程序,访问http://localhost:8080/

方式三:可以自定义静态资源进行访问

 新建一个MyWebMvcConfig.java,重写WebMvcConfigurer接口,这里我只重写了addResourceHandlers方法,定义了一个test文件夹。

package com.zk.Springboot;
import java.util.List;

import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
/**
 * 静态资源映射
 */
@Component
public class MyWebMvcConfig implements WebMvcConfigurer {
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/test/**")
                .addResourceLocations("classpath:/test/");
        }

	@Override
	public void addArgumentResolvers(List<HandlerMethodArgumentResolver> arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void addCorsMappings(CorsRegistry arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void addFormatters(FormatterRegistry arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void addInterceptors(InterceptorRegistry arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void addViewControllers(ViewControllerRegistry arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void configureAsyncSupport(AsyncSupportConfigurer arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void configureContentNegotiation(ContentNegotiationConfigurer arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void configurePathMatch(PathMatchConfigurer arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void configureViewResolvers(ViewResolverRegistry arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void extendMessageConverters(List<HttpMessageConverter<?>> arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public MessageCodesResolver getMessageCodesResolver() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Validator getValidator() {
		// TODO Auto-generated method stub
		return null;
	}
}

 

  访问刚才自定义路径http://localhost:8080/test/a.png

 同样能够访问我们的静态资源文件。

 方式四:可以在application.properties设置进行访问

spring.resources.static-locations=classpath:/hello,classpath:/atguigu/   

 当更改了静态资源的访问路径时,访问localhost:8080,此时无法访问到/resources/public/index.html文件

SpringBoot中引入thymeleaf

首先我们介绍一下什么是thymeleaf

thymeleaf是个XML/XHTML/HTML5模板引擎,可以用于Web与非Web应用。

我们现在需要使用thymeleaf,将thymeleaf引入springboot中。

在pom.xml文件中添加如下代码:

<dependency>
	    <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

加入thymeleaf依赖,引入jar包。

 thymeleaf的默认静态资源路径为classpath:/templates/,必须放置在此路径下,才能够访问到静态thymeleaf资源,否则无法访问。

项目结构如下:

 

 

HelloController.java

package com.example.demo;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @ResponseBody
    @RequestMapping("/hello")
    public String hello(){
        // 默认要去classpath:templates下查找success.html
        return "success";
    }
}

 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.2.1</version>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.7.RELEASE</version>
                <configuration>
                    <mainClass>com.example.demo.DemoApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

classpath:templates目录下的success.html文件

success.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>success</title>
</head>
<body>
<h1>success</h1>
</body>
</html>

 分析其原因可以查看源代码,访问spring-boot-autoconfigure-1.4.3.RELEASE.jar 包下的org.springframework.boot.autoconfigure.thymeleaf中的ThymeleafProperties.class文件

@ConfigurationProperties(
    prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {
    private static final Charset DEFAULT_ENCODING;
    public static final String DEFAULT_PREFIX = "classpath:/templates/";
    public static final String DEFAULT_SUFFIX = ".html";
    private boolean checkTemplate = true;
    private boolean checkTemplateLocation = true;
    private String prefix = "classpath:/templates/";
    private String suffix = ".html";
    private String mode = "HTML";
    private Charset encoding;
    private boolean cache;
    private Integer templateResolverOrder;
    private String[] viewNames;
    private String[] excludedViewNames;
    private boolean enableSpringElCompiler;
    private boolean renderHiddenMarkersBeforeCheckboxes;
    private boolean enabled;
    private final ThymeleafProperties.Servlet servlet;
    private final ThymeleafProperties.Reactive reactive;

 从该class文件中可以分析到,访问静态资源的路径必须为classpath:/templates/,且静态资源为.html。当html页面放在classpath:/templates目录下时,thymeleaf就可以自动渲染。

我们举个例子,

我们建个springboot项目,项目目录如下:

 

首先在classpath:/templates/构建success.html文件,文件内容如下:

success.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="utf-8" />
    <title>success.html</title>
    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
  </head>
  
  <body>
    success,helloworld <br/>
    <!-- 将div中的文本内容设置成自定义值 -->
    <h1 th:text="${hello}" th:id="${hello}" th:class="${hello}"></h1>
    <h1 th:utext="${hello}"></h1>
    <!-- 遍历user -->
    <div th:each="user:${users}">
    <span th:text="${user}"></span>
    </div>
    <table border="1">
        <thead>
            <th>学生id</th>
            <th>学生姓名</th>
            <th>学生年龄</th>
        </thead>
        <tbody>
            <tr th:each="entries:${resultList}">
                <td th:text="${entries['sid']}"></td>
                <td th:text="${entries['sname']}"></td>
                <td th:text="${entries['sage']}"></td>
            </tr>
        </tbody>
    </table>
  </body>
</html>

 如果想使用thymeleaf,则需要引入标签:

<html xmlns:th="http://www.thymeleaf.org">

th:text改变当前元素里面的文本内容,th:class th:id可以修改任意的html属性,替换原生class、id

thymeleaf官方文档中的标签,th官方文档 https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#attribute-precedence

thymeleaf的表达式语法 https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#standard-expression-syntax

Simple expressions:
Variable Expressions: ${...}
(1)获取对象的属性、调用方法
(2)使用内置的基本对象
#ctx: the context object.
#vars: the context variables.
#locale: the context locale.
#request: (only in Web Contexts) the HttpServletRequest object.
#response: (only in Web Contexts) the HttpServletResponse object.
#session: (only in Web Contexts) the HttpSession object.
#servletContext: (only in Web Contexts) the ServletContext object.
(3)内置一些工具对象
Selection Variable Expressions: *{...}选择表达式:和${}在功能上是一样的
补充:配合 th:object="${session.user}"
<div th:object="${session.user}">
Message Expressions: #{...} 获取国际化内容
Link URL Expressions: @{...}定义url链接
<!-- Will produce 'http://localhost:8080/gtvg/order/details?orderId=3' (plus rewriting) -->
<a href="details.html" 
th:href="@{http://localhost:8080/gtvg/order/details(orderId=${o.id})}">view</a>
<!-- Will produce '/gtvg/order/details?orderId=3' (plus rewriting) -->
<a href="details.html" th:href="@{/order/details(orderId=${o.id})}">view</a>
<!-- Will produce '/gtvg/order/3/details' (plus rewriting) -->
<a href="details.html" th:href="@{/order/{orderId}/details(orderId=${o.id})}">view</a>
Fragment Expressions: ~{...}:片段引用表达式
Literals(字面量)
Text literals: 'one text', 'Another one!',…
Number literals: 0, 34, 3.0, 12.3,…
Boolean literals: true, false
Null literal: null
Literal tokens: one, sometext, main,…
Text operations:(文本操作)
String concatenation: +
Literal substitutions: |The name is ${name}|
Arithmetic operations:(数学运算)
Binary operators: +, -, *, /, %
Minus sign (unary operator): -
Boolean operations:(布尔运算)
Binary operators: and, or
Boolean negation (unary operator): !, not
Comparisons and equality:(比较运算)
Comparators: >, <, >=, <= (gt, lt, ge, le)
Equality operators: ==, != (eq, ne)
Conditional operators:(条件运算)
If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)三元运算符
Default: (value) ?: (defaultvalue)
Special tokens:(特殊字符)
No-Operation: _

在success.html文件中访问了user参数列表和resultList,在HelloController后台封装代码如下:

package com.zk.Springboot;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {
	@ResponseBody
	@RequestMapping("/hello")
	public String hello() { 
		return "hello";
	}
	//插入一些数据在页面显示
	@RequestMapping("/success")
	public String successs(Map<String,Object> map) {
		map.put("hello", "你好");
		map.put("users", Arrays.asList("zhang","zhao","qian"));
		return "success";
	}
	
	@Controller
	@RequestMapping("studentMgmt")
	public class StudentController {
	    @RequestMapping("queryStudentInfo")
	    public String queryStudentInfo(Model model) {
	        List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
	        Map<String, Object> student = new HashMap<String, Object>(){{
	            put("sid", "101");
	            put("sname", "张三");
	            put("sage", "20");
	        }};
	        resultList.add(student);
	        student = new HashMap<String, Object>(){{
	            put("sid", "102");
	            put("sname", "李四");
	            put("sage", "30");
	        }};
	        resultList.add(student);
	        model.addAttribute("resultList", resultList);
	        return "success";
	    }
	}
}

同样设置启动项:

package com.zk.Springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootApplicationFirst {
	public static void main(String[]args){
        SpringApplication.run(SpringBootApplicationFirst.class, args);
    }
    public static void run(String...arg0) {
        System.out.println("Hello world from Command Line Runner");
    }
}

 application.properties配置文件内容:

spring.resources.static-locations=classpath\:/static,classpath\:/public,classpath\:/resources,classpath\:/META-INF/resources

  我们访问一下thymeleaf静态资源网页,访问效果如下:

 

 访问成功

 SpringBoot中引入freemark

首先在pom.xml文件中引入freemarker的依赖

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>myspringboot003</groupId>
  <artifactId>myspringboot003</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <parent>
  	<groupId>org.springframework.boot</groupId>
  	<artifactId>spring-boot-starter-parent</artifactId>
  	<version>1.3.3.RELEASE</version>
  </parent>
  <dependencies>
  	<dependency>
  		<groupId>org.springframework.boot</groupId>
  		<artifactId>spring-boot-starter-web</artifactId>
  	</dependency>
  	<dependency>
  		<groupId>org.springframework.boot</groupId>
  		<artifactId>spring-boot-starter-freemarker</artifactId>
  	</dependency>
  </dependencies>
</project>

 接着,写ftl页面文件

this is itmayiedu<br>
${name}
<#list userlist as user>
${user}
</#list>

 写业务controller文件

package com.zk.myspringboot003;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

//标识该接口全部返回json格式
@Controller
public class indexController {
	@RequestMapping("/indexController")
	public String indexController(Map<String,Object> result) {
		result.put("name", "zk");
		List<String> list=new ArrayList<String>();
		list.add("zhangkun");
		list.add("lisi");
		list.add("26");
		result.put("userlist", list);
		return "index";
	}
}

 最后写启动文件

package com.zk.myspringboot003;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@EnableAutoConfiguration
@SpringBootApplication
public class SpringBootApplicationThird {
	public static void main(String[]args){
        SpringApplication.run(SpringBootApplicationThird.class, args);
    }
    public static void run(String...arg0) {
        System.out.println("Hello world from Command Line Runner");
    }
}

  运行结果如下:

 SpringBoot中引入JSP

需要注意的是,在创建MAVEN工程项目的时候需要选择war,而不是我们平时选择的jar包

页面:index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
springboot 你好
</body>
</html>

  Controller类:IndexController.java

package com.zk.myspringboot004;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class IndexController {
	
	@RequestMapping("/index")
	public String index() {
		return "index";
	}
}

 application属性文件:application.properties

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

 依赖文件:pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.myspringboot004</groupId>
  <artifactId>myspringboot004</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  
  <parent>
  	<groupId>org.springframework.boot</groupId>
  	<artifactId>spring-boot-starter-parent</artifactId>
  	<version>1.3.3.RELEASE</version>
  </parent>
  <dependencies>
  	<dependency>
  		<groupId>org.springframework.boot</groupId>
  		<artifactId>spring-boot-starter-web</artifactId>
  	</dependency>
  	<dependency>
  		<groupId>org.springframework.boot</groupId>
  		<artifactId>spring-boot-starter-tomcat</artifactId>
  	</dependency>
  	<dependency>
  		<groupId>org.apache.tomcat.embed</groupId>
  		<artifactId>tomcat-embed-jasper</artifactId>
  	</dependency>
  </dependencies>
</project>

  启动程序:SpringBootApplicationTwice.java

package com.zk.myspringboot004;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@EnableAutoConfiguration
@SpringBootApplication
public class SpringBootApplicationTwice {
	public static void main(String[]args){
        SpringApplication.run(SpringBootApplicationTwice.class, args);
    }
    public static void run(String...arg0) {
        System.out.println("Hello world from Command Line Runner");
    }
}
posted @ 2020-04-14 15:11  leagueandlegends  阅读(954)  评论(0编辑  收藏  举报