SpringBoot可以通过3种方式来获取静态资源
方式一:访问所有webjars/**,访问静态资源的路径为META-INF/resources/webjars,可以在此路径中查找静态资源。
举个例子:
新建一个项目工程
并在pom.xml文件中引入webjars包,
<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 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zk.myspringboot_011</groupId> <artifactId>myspringboot_011</artifactId> <packaging>jar</packaging> <version>0.0.1-SNAPSHOT</version> <name>myspringboot_011 Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <!-- 继承父包 --> <dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.3.1-1</version> </dependency> </dependencies> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.3.RELEASE</version> </parent> <build> <finalName>myspringboot_011</finalName> </build> </project>
核心代码:
<dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.3.1-1</version> </dependency>
可以参考一下这个引入静态资源的网站https://www.webjars.org/
然后我们通过浏览器访问一下web静态资源,路径为http://localhost:8080/webjars/jquery/3.3.1-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目录下放a.png文件
我们访问这个路径:localhost:8080/image/a.png,可以访问到a.png静态资源
为什么可以访问以上四个路径下的所有静态资源,我们可以通过查看org.springframework.boot.autoconfigure.web包下面的ResourceProperties.class类的源代码分析其原因:
/* * 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.autoconfigure.web; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.NestedConfigurationProperty; import org.springframework.context.ResourceLoaderAware; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; /** * Properties used to configure resource handling. * * @author Phillip Webb * @author Brian Clozel * @author Dave Syer * @author Venil Noronha * @since 1.1.0 */ @ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false) public class ResourceProperties implements ResourceLoaderAware { private static final String[] SERVLET_RESOURCE_LOCATIONS = { "/" }; private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" }; private static final String[] RESOURCE_LOCATIONS; static { RESOURCE_LOCATIONS = new String[CLASSPATH_RESOURCE_LOCATIONS.length + SERVLET_RESOURCE_LOCATIONS.length]; System.arraycopy(SERVLET_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS, 0, SERVLET_RESOURCE_LOCATIONS.length); System.arraycopy(CLASSPATH_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS, SERVLET_RESOURCE_LOCATIONS.length, CLASSPATH_RESOURCE_LOCATIONS.length); } /** * Locations of static resources. Defaults to classpath:[/META-INF/resources/, * /resources/, /static/, /public/] plus context:/ (the root of the servlet context). */ private String[] staticLocations = RESOURCE_LOCATIONS; /** * Cache period for the resources served by the resource handler, in seconds. */ private Integer cachePeriod; /** * Enable default resource handling. */ private boolean addMappings = true; private final Chain chain = new Chain(); private ResourceLoader resourceLoader; @Override public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } public String[] getStaticLocations() { return this.staticLocations; } public void setStaticLocations(String[] staticLocations) { this.staticLocations = staticLocations; } public Resource getWelcomePage() { for (String location : getStaticWelcomePageLocations()) { Resource resource = this.resourceLoader.getResource(location); try { if (resource.exists()) { resource.getURL(); return resource; } } catch (Exception ex) { // Ignore } } return null; } private String[] getStaticWelcomePageLocations() { String[] result = new String[this.staticLocations.length]; for (int i = 0; i < result.length; i++) { String location = this.staticLocations[i]; if (!location.endsWith("/")) { location = location + "/"; } result[i] = location + "index.html"; } return result; } List<Resource> getFaviconLocations() { List<Resource> locations = new ArrayList<Resource>( this.staticLocations.length + 1); if (this.resourceLoader != null) { for (String location : this.staticLocations) { locations.add(this.resourceLoader.getResource(location)); } } locations.add(new ClassPathResource("/")); return Collections.unmodifiableList(locations); } public Integer getCachePeriod() { return this.cachePeriod; } public void setCachePeriod(Integer cachePeriod) { this.cachePeriod = cachePeriod; } public boolean isAddMappings() { return this.addMappings; } public void setAddMappings(boolean addMappings) { this.addMappings = addMappings; } public Chain getChain() { return this.chain; } /** * Configuration for the Spring Resource Handling chain. */ public static class Chain { /** * Enable the Spring Resource Handling chain. Disabled by default unless at least * one strategy has been enabled. */ private Boolean enabled; /** * Enable caching in the Resource chain. */ private boolean cache = true; /** * Enable HTML5 application cache manifest rewriting. */ private boolean htmlApplicationCache = false; /** * Enable resolution of already gzipped resources. Checks for a resource name * variant with the "*.gz" extension. */ private boolean gzipped = false; @NestedConfigurationProperty private final Strategy strategy = new Strategy(); /** * Return whether the resource chain is enabled. Return {@code null} if no * specific settings are present. * @return whether the resource chain is enabled or {@code null} if no specified * settings are present. */ public Boolean getEnabled() { Boolean strategyEnabled = getStrategy().getFixed().isEnabled() || getStrategy().getContent().isEnabled(); return (strategyEnabled ? Boolean.TRUE : 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 Strategy getStrategy() { return this.strategy; } public boolean isHtmlApplicationCache() { return this.htmlApplicationCache; } public void setHtmlApplicationCache(boolean htmlApplicationCache) { this.htmlApplicationCache = htmlApplicationCache; } public boolean isGzipped() { return this.gzipped; } public void setGzipped(boolean gzipped) { this.gzipped = gzipped; } } /** * Strategies for extracting and embedding a resource version in its URL path. */ public static class Strategy { @NestedConfigurationProperty private final Fixed fixed = new Fixed(); @NestedConfigurationProperty private final Content content = new Content(); public Fixed getFixed() { return this.fixed; } public Content getContent() { return this.content; } } /** * Version Strategy based on content hashing. */ public static class Content { /** * Enable the content Version Strategy. */ private boolean enabled; /** * Comma-separated list of patterns to apply to the Version Strategy. */ private String[] paths = new String[] { "/**" }; 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; } } /** * Version Strategy based on a fixed version string. */ public static class Fixed { /** * Enable the fixed Version Strategy. */ private boolean enabled; /** * Comma-separated list of patterns to apply to the Version Strategy. */ private String[] paths = new String[] { "/**" }; /** * Version string to use for the Version Strategy. */ private String version; 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; } } }
核心代码:
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" };
这里定义了我们的四个访问路径,因此,静态资源可以通过这四个访问路径进行访问。
方式三:可以自定义静态资源进行访问
新建一个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:/static,classpath:/public,classpath:/resources,classpath:/META-INF/resources
访问localhost:8080/static/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资源,否则无法访问。
分析其原因可以查看源代码,访问spring-boot-autoconfigure-1.4.3.RELEASE.jar 包下的org.springframework.boot.autoconfigure.thymeleaf中的ThymeleafProperties.class文件
@ConfigurationProperties("spring.thymeleaf") public class ThymeleafProperties { private static final Charset DEFAULT_ENCODING = Charset.forName("UTF-8"); private static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf("text/html"); public static final String DEFAULT_PREFIX = "classpath:/templates/"; public static final String DEFAULT_SUFFIX = ".html";
从该class文件中可以分析到,访问静态资源的路径必须为classpath:/templates/,且静态资源为.html
我们举个例子,
我们建个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">
在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"); } }