7.springboot web开发

7.springboot web开发

  • xxxxAutoConfiguration:帮我们给容器中自动配置组件
  • xxxxProperties:配置类来封装配置文件的内容

7.1静态资源的映射规则

1.加载webjars目录下资源

我们springboot项目打包以<packaging>jar</packaging>包形式,以前我们是将静态资源保存在webapp目录下,现在我们以jar包方式如何引入静态资源呢?

public class WebMvcAutoConfiguration {
@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));
}
}
}

上述web自动配置源码可以看到所有 /webjars/** ,都去 classpath:/META-INF/resources/webjars/ 找资源;

webjars:以jar包的方式引入静态资源;webjars官网

作用:将前端框架以maven依赖的方式交给我们使用,比如引入jquery依赖,使用jquery内部定义好的资源。

<!--引入jquery-webjar-->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1</version>
</dependency>

我们请求localhost:8080/webjars/jquery/3.3.1/jquery.js 会从jquery中resources目录webjars/jquery/...访问具体的资源。在访问的时候只需要写webjars下面资源的名称即可。

2.访问当前项目任何资源

"/**" 访问当前项目的任何资源,都去(静态资源的文件夹)找映射

public class WebMvcAutoConfiguration {
@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));
}
}
}

this.mvcProperties.getStaticPathPattern()方法:

/**
* Path pattern used for static resources.
*/
private String staticPathPattern = "/**";

this.resourceProperties.getStaticLocations()方法:

@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;
public String[] getStaticLocations() {
return this.staticLocations;
}
}

查看上面两个方法源码可以看到,静态资源都放在这些文件夹中,只要没人处理,就从这些文件夹中找资源

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

优先级:resources > static(默认) > public

我们访问localhost:8080/abc,等同于去静态资源文件夹里面找abc,因为默认就是从这些静态资源目录中找资源,所以请求不用写静态资源目录名

3.欢迎页

静态资源文件夹下的所有index.html页面,被"/**"映射;

public class WebMvcAutoConfiguration {
// 配置欢迎页映射
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(
ResourceProperties resourceProperties) {
return new WelcomePageHandlerMapping(resourceProperties.getWelcomePage(),
// 静态资源路径 /**
this.mvcProperties.getStaticPathPattern());
}
}
@ConfigurationProperties(prefix = "spring.mvc")
public class WebMvcProperties {
/**
* Path pattern used for static resources.
*/
private String staticPathPattern = "/**";
public String getStaticPathPattern() {
return this.staticPathPattern;
}
}

访问localhost:8080/默认路径,请求 找index.html页面

为什么欢迎页是index.html在哪里配置的?上面源码中可以看到new WelcomePageHandlerMapping类实例。

它是WebMvcAutoConfiguration类中静态类,指定了视图名叫index.html

public class WebMvcAutoConfiguration {
static final class WelcomePageHandlerMapping extends AbstractUrlHandlerMapping {
private static final Log logger = LogFactory.getLog(WelcomePageHandlerMapping.class);
private WelcomePageHandlerMapping(Resource welcomePage,
String staticPathPattern) {
if (welcomePage != null && "/**".equals(staticPathPattern)) {
logger.info("Adding welcome page: " + welcomePage);
ParameterizableViewController controller = new ParameterizableViewController();
controller.setViewName("forward:index.html");
setRootHandler(controller);
setOrder(0);
}
}
}
}

4.网页图标

访问网页每个网站都会有这种属于自己的小图标。

所有的 **/favicon.ico 都是在静态资源文件下找;

public class WebMvcAutoConfiguration {
@Configuration
@ConditionalOnProperty(value = "spring.mvc.favicon.enabled", matchIfMissing = true)
public static class FaviconConfiguration {
private final ResourceProperties resourceProperties;
public FaviconConfiguration(ResourceProperties resourceProperties) {
this.resourceProperties = resourceProperties;
}
@Bean
public SimpleUrlHandlerMapping faviconHandlerMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
//所有 **/favicon.ico
mapping.setUrlMap(Collections.singletonMap("**/favicon.ico",
faviconRequestHandler()));
return mapping;
}
@Bean
public ResourceHttpRequestHandler faviconRequestHandler() {
ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
requestHandler.setLocations(this.resourceProperties.getFaviconLocations());
return requestHandler;
}
}
}

配置网页标题的图标:

#关闭默认图标,默认是打开的:matchIfMissing = true
spring.mvc.favicon.enabled=false

注意🔞:

springboot版本2.1.x版本中,在resources/public目录下放入favicon.ico图片

springboot版本1.x.x版本中,favicon.ico图片可以放在resources目录下的任意静态资源目录中,比如resources/static目录下

5.自定义静态资源存放路径

若自定义静态资源存放路径,可以在配置文件application.properties文件中指定路径:

# 多个路径以 , 逗号分隔
spring.resources.static-locations=classpath:/mystatic/,classpath:/myresources/
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties implements ResourceLoaderAware {
//可以设置和静态资源有关的参数,缓存时间等

7.2模板引擎

JSP、Velocity、Freemarker、Thymeleaf

SpringBoot推荐的Thymeleaf;语法更简单,功能更强大;

1、引入thymeleaf

前端交给我们的页面是html页面。如果是我们以前开发,我们需要把他们转成jsp页面,jsp好处就是当我们查出一些数据转发到JSP页面以后,我们可以用jsp轻松实现数据的显示及交互等。但是,我们现在的这种情况,SpringBoot这个项目首先是以jar的方式,不是war,第二,我们用的还是嵌入式的Tomcat,所以呢,他现在默认是不支持jsp的。

SpringBoot推荐你可以来使用模板引擎。模板引擎的作用就是我们来写一个页面模板,比如有些值呢,是动态的,我们写一些表达式。而这些值,从哪来呢,我们来组装一些数据,我们把这些数据找到。然后把这个模板和这个数据交给我们模板引擎,模板引擎按照我们这个数据帮你把这表达式解析、填充到我们指定的位置,然后把这个数据最终生成一个我们想要的内容给我们写出去,这就是我们这个模板引擎,不管是jsp还是其他模板引擎,都是这个思想。SpringBoot给我们推荐的Thymeleaf模板引擎。

第一步:引入thymeleaf springboot1.x.x版本 要用2.x.x版本的,springboot2.x.x 要用3.x.x的版本

<!--要切换thymeleaf版本,不适用springboot默认版本,在<properties>标签中进行指定要切换的版本,布局功能支持thymeleaf-layout-dialect.version要适配thymeleaf.version版本,thymeleaf.version 3版本适配2版本的布局功能-->
<properties>
<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
<!-- 布局功能的支持程序 thymeleaf3主程序 layout2以上版本 -->
<!-- thymeleaf 2 layout 1-->
<thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
</properties>
<!--thymeleaf模板-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

2、Thymeleaf使用

在templates目录下的所有页面,只能通过controller来跳转,需要模板引擎thymeleaf支持。

Thymeleaf的自动配置类源码

@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;
}

可以在其中看到默认的视图名称前缀prefix和后缀suffix,我们只需要把我们的html页面放在类路径下的templates目录下,返回需要的视图名称,thymeleaf就可以帮我们自动渲染了。

测试:

1、html文件导入thymeleaf的名称空间

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

2、controller

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller // 不能使用@RestController注解,html中msg报错
public class ThymeleafController {
@RequestMapping("/test")
public String thymeleafTest(Model model){
model.addAttribute("msg", "<h1>thymeleaf模板引擎</h1>");
return "test"; // 跳转的html页面名称
}
}

3、html文件

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<!--一定要写:xmlns:th="http://www.thymeleaf.org"否则 th:不能使用-->
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div th:text="${msg}"></div>
</body>
</html>
#关闭模板引擎缓存
spring.thymeleaf.cache=false

3、Thymeleaf语法

th:text;改变当前元素里面的文本内容;

th:任意html属性;来替换原生属性的值

表达式语法:

Simple expressions:(表达式语法)
Variable Expressions: ${...}:获取变量值;OGNL;
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.
eg:${session.foo}
3)、内置的一些工具对象:
#execInfo : information about the template being processed.
#messages : methods for obtaining externalized messages inside variables expressions, in the same way as they would be obtained using #{…} syntax.
#uris : methods for escaping parts of URLs/URIs
#conversions : methods for executing the configured conversion service (if any).
#dates : methods for java.util.Date objects: formatting, component extraction, etc.
#calendars : analogous to #dates , but for java.util.Calendar objects.
#numbers : methods for formatting numeric objects.
#strings : methods for String objects: contains, startsWith, prepending/appending, etc.
#objects : methods for objects in general.
#bools : methods for boolean evaluation.
#arrays : methods for arrays.
#lists : methods for lists.
#sets : methods for sets.
#maps : methods for maps.
#aggregates : methods for creating aggregates on arrays or collections.
#ids : methods for dealing with id attributes that might be repeated (for example, as a result of an iteration).
Selection Variable Expressions: *{...}:选择表达式:和${}在功能上是一样;配合 th:object="${session.user},这样之后如果使用th:object中的属性就不用${session.user.firstName}
示例:
<div th:object="${session.user}">
<p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
<p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
<p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
</div>
Message Expressions: #{...}:获取国际化内容
Link URL Expressions: @{...}:超链接定义URL;
@{/order/process(execId=${execId},execType='FAST')}
Fragment Expressions: ~{...}:片段引用表达式
<div th:insert="~{commons :: main}">...</div>
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: _

测试:

@Controller // 不能使用@RestController注解,html中msg报错
public class ThymeleafController {
@RequestMapping("/test")
public String thymeleafTest(Model model){
model.addAttribute("msg", "<h1>thymeleaf模板引擎</h1>");
model.addAttribute("job", Arrays.asList("简历", "工作")); // 数组转换为list
return "test"; // 返回视图名称
}
}

test.html:

<body>
<div th:text="${msg}"></div>
<!--th:utext将获取的内容进行转义(内容中有可以转义的标签)-->
<div th:utext="${msg}"></div>
<hr>
<!-- 将job取到的值赋给user, user取出循环的到的值-->
<div th:each="user:${job}" th:text="${user}"></div>
</body>
posted @   Lz_蚂蚱  阅读(47)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起