整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

关于 HTML5 你需要了解的基础知识

TML5 是第五个且是当前的 HTML 版本,它是用于在万维网上构建和呈现内容的标记语言。本文将帮助读者了解它。 -- Palak Shah

本文导航
  • -新标签和元素 …… 08%

  • -HTML5 的高级功能 …… 16%

  • -地理位置 …… 16%

  • -网络存储 …… 33%

  • -应用缓存(AppCache) …… 44%

  • -视频 …… 50%

  • -音频 …… 61%

  • -画布(Canvas) …… 71%

  • -HTML5 工具 …… 78%

编译自: http://opensourceforu.com/2017/06/introduction-to-html5/

作者: Palak Shah

译者: geekpi

HTML5 是第五个且是当前的 HTML 版本,它是用于在万维网上构建和呈现内容的标记语言。本文将帮助读者了解它。

HTML5 通过 W3C 和Web 超文本应用技术工作组Web Hypertext Application Technology Working Group之间的合作发展起来。它是一个更高版本的 HTML,它的许多新元素可以使你的页面更加语义化和动态。它是为所有人提供更好的 Web 体验而开发的。HTML5 提供了很多的功能,使 Web 更加动态和交互。

HTML5 的新功能是:

  • 新标签,如 <header> 和 <section>

  • 用于 2D 绘图的 <canvas> 元素

  • 本地存储

  • 新的表单控件,如日历、日期和时间

  • 新媒体功能

  • 地理位置

HTML5 还不是正式标准(LCTT 译注:HTML5 已于 2014 年成为“推荐标准”),因此,并不是所有的浏览器都支持它或其中一些功能。开发 HTML5 背后最重要的原因之一是防止用户下载并安装像 Silverlight 和 Flash 这样的多个插件。

新标签和元素

  • 语义化元素: 图 1 展示了一些有用的语义化元素。

  • 表单元素: HTML5 中的表单元素如图 2 所示。

  • 图形元素: HTML5 中的图形元素如图 3 所示。

  • 媒体元素: HTML5 中的新媒体元素如图 4 所示。

图 1:语义化元素

图 2:表单元素

图 3:图形元素

图 4:媒体元素

HTML5 的高级功能

地理位置

这是一个 HTML5 API,用于获取网站用户的地理位置,用户必须首先允许网站获取他或她的位置。这通常通过按钮和/或浏览器弹出窗口来实现。所有最新版本的 Chrome、Firefox、IE、Safari 和 Opera 都可以使用 HTML5 的地理位置功能。

地理位置的一些用途是:

  • 公共交通网站

  • 出租车及其他运输网站

  • 电子商务网站计算运费

  • 旅行社网站

  • 房地产网站

  • 在附近播放的电影的电影院网站

  • 在线游戏

  • 网站首页提供本地标题和天气

  • 工作职位可以自动计算通勤时间

工作原理: 地理位置通过扫描位置信息的常见源进行工作,其中包括以下:

  • 全球定位系统(GPS)是最准确的

  • 网络信号 - IP地址、RFID、Wi-Fi 和蓝牙 MAC地址

  • GSM/CDMA 蜂窝 ID

  • 用户输入

该 API 提供了非常方便的函数来检测浏览器中的地理位置支持:

if (navigator.geolocation) {

// do stuff

}

getCurrentPosition API 是使用地理位置的主要方法。它检索用户设备的当前地理位置。该位置被描述为一组地理坐标以及航向和速度。位置信息作为位置对象返回。

语法是:

getCurrentPosition(showLocation, ErrorHandler, options);
  • showLocation:定义了检索位置信息的回调方法。

  • ErrorHandler(可选):定义了在处理异步调用时发生错误时调用的回调方法。

  • options (可选): 定义了一组用于检索位置信息的选项。

我们可以通过两种方式向用户提供位置信息:测地和民用。

  1. 描述位置的测地方式直接指向纬度和经度。

  2. 位置信息的民用表示法是人类可读的且容易理解。

如下表 1 所示,每个属性/参数都具有测地和民用表示。

图 5 包含了一个位置对象返回的属性集。

图5:位置对象属性

网络存储

在 HTML 中,为了在本机存储用户数据,我们需要使用 JavaScript cookie。为了避免这种情况,HTML5 已经引入了 Web 存储,网站利用它在本机上存储用户数据。

与 Cookie 相比,Web 存储的优点是:

  • 更安全

  • 更快

  • 存储更多的数据

  • 存储的数据不会随每个服务器请求一起发送。只有在被要求时才包括在内。这是 HTML5 Web 存储超过 Cookie 的一大优势。

有两种类型的 Web 存储对象:

  1. 本地 - 存储没有到期日期的数据。

  2. 会话 - 仅存储一个会话的数据。

如何工作: localStorage 和 sessionStorage 对象创建一个 key=value 对。比如: key="Name", value="Palak"。

这些存储为字符串,但如果需要,可以使用 JavaScript 函数(如 parseInt() 和 parseFloat())进行转换。

下面给出了使用 Web 存储对象的语法:

  • 存储一个值:

  • localStorage.setItem("key1", "value1");

  • localStorage["key1"] = "value1";

  • 得到一个值:

  • alert(localStorage.getItem("key1"));

  • alert(localStorage["key1"]);

  • 删除一个值: -removeItem("key1");

  • 删除所有值:

  • localStorage.clear();

应用缓存(AppCache)

使用 HTML5 AppCache,我们可以使 Web 应用程序在没有 Internet 连接的情况下脱机工作。除 IE 之外,所有浏览器都可以使用 AppCache(截止至此时)。

应用缓存的优点是:

  • 网页浏览可以脱机

  • 页面加载速度更快

  • 服务器负载更小

cache manifest 是一个简单的文本文件,其中列出了浏览器应缓存的资源以进行脱机访问。 manifest 属性可以包含在文档的 HTML 标签中,如下所示:

<html manifest="test.appcache">

...

</html>

它应该在你要缓存的所有页面上。

缓存的应用程序页面将一直保留,除非:

  1. 用户清除它们

  2. manifest 被修改

  3. 缓存更新

视频

在 HTML5 发布之前,没有统一的标准来显示网页上的视频。大多数视频都是通过 Flash 等不同的插件显示的。但 HTML5 规定了使用 video 元素在网页上显示视频的标准方式。

目前,video 元素支持三种视频格式,如表 2 所示。

下面的例子展示了 video 元素的使用:

<! DOCTYPE HTML>

<html>

<body>

<video src=" vdeo.ogg" width="320" height="240" controls="controls">

This browser does not support the video element.

</video>

</body>

</html>

例子使用了 Ogg 文件,并且可以在 Firefox、Opera 和 Chrome 中使用。要使视频在 Safari 和未来版本的 Chrome 中工作,我们必须添加一个 MPEG4 和 WebM 文件。

video 元素允许多个 source 元素。source 元素可以链接到不同的视频文件。浏览器将使用第一个识别的格式,如下所示:

<video width="320" height="240" controls="controls">

<source src="vdeo.ogg" type="video/ogg" />

<source src=" vdeo.mp4" type="video/mp4" />

<source src=" vdeo.webm" type="video/webm" />

This browser does not support the video element.

</video>

图6:Canvas 的输出

音频

对于音频,情况类似于视频。在 HTML5 发布之前,在网页上播放音频没有统一的标准。大多数音频也通过 Flash 等不同的插件播放。但 HTML5 规定了通过使用音频元素在网页上播放音频的标准方式。音频元素用于播放声音文件和音频流。

目前,HTML5 audio 元素支持三种音频格式,如表 3 所示。

audio 元素的使用如下所示:

<! DOCTYPE HTML>

<html>

<body>

<audio src=" song.ogg" controls="controls">

This browser does not support the audio element.

</video>

</body>

</html>

此例使用 Ogg 文件,并且可以在 Firefox、Opera 和 Chrome 中使用。要在 Safari 和 Chrome 的未来版本中使 audio 工作,我们必须添加一个 MP3 和 Wav 文件。

audio 元素允许多个 source 元素,它可以链接到不同的音频文件。浏览器将使用第一个识别的格式,如下所示:

<audio controls="controls">

<source src="song.ogg" type="audio/ogg" />

<source src="song.mp3" type="audio/mpeg" />

This browser does not support the audio element.

</audio>

画布(Canvas)

要在网页上创建图形,HTML5 使用 画布 API。我们可以用它绘制任何东西,并且它使用 JavaScript。它通过避免从网络下载图像而提高网站性能。使用画布,我们可以绘制形状和线条、弧线和文本、渐变和图案。此外,画布可以让我们操作图像中甚至视频中的像素。你可以将 canvas 元素添加到 HTML 页面,如下所示:

<canvas id="myCanvas" width="200" height="100"></canvas>

画布元素不具有绘制元素的功能。我们可以通过使用 JavaScript 来实现绘制。所有绘画应在 JavaScript 中。

<script type="text/javascript">

var c=document.getElementById("myCanvas");

var cxt=c.getContext("2d");

cxt.fillStyle="blue";

cxt.storkeStyle = "red";

cxt.fillRect(10,10,100,100);

cxt.storkeRect(10,10,100,100);

</script>

以上脚本的输出如图 6 所示。

你可以绘制许多对象,如弧、圆、线/垂直梯度等。

HTML5 工具

为了有效操作,所有熟练的或业余的 Web 开发人员/设计人员都应该使用 HTML5 工具,当需要设置工作流/网站或执行重复任务时,这些工具非常有帮助。它们提高了网页设计的可用性。

以下是一些帮助创建很棒的网站的必要工具。

  • HTML5 Maker: 用来在 HTML、JavaScript 和 CSS 的帮助下与网站内容交互。非常容易使用。它还允许我们开发幻灯片、滑块、HTML5 动画等。

  • Liveweave: 用来测试代码。它减少了保存代码并将其加载到屏幕上所花费的时间。在编辑器中粘贴代码即可得到结果。它非常易于使用,并为一些代码提供自动完成功能,这使得开发和测试更快更容易。

  • Font dragr: 在浏览器中预览定制的 Web 字体。它会直接载入该字体,以便你可以知道看起来是否正确。也提供了拖放界面,允许你拖动字形、Web 开放字体和矢量图形来马上测试。

  • HTML5 Please: 可以让我们找到与 HTML5 相关的任何内容。如果你想知道如何使用任何一个功能,你可以在 HTML Please 中搜索。它提供了支持的浏览器和设备的有用资源的列表,语法,以及如何使用元素的一般建议等。

  • Modernizr: 这是一个开源工具,用于给访问者浏览器提供最佳体验。使用此工具,你可以检测访问者的浏览器是否支持 HTML5 功能,并加载相应的脚本。

  • Adobe Edge Animate: 这是必须处理交互式 HTML 动画的 HTML5 开发人员的有用工具。它用于数字出版、网络和广告领域。此工具允许用户创建无瑕疵的动画,可以跨多个设备运行。

  • Video.js: 这是一款基于 JavaScript 的 HTML5 视频播放器。如果要将视频添加到你的网站,你应该使用此工具。它使视频看起来不错,并且是网站的一部分。

  • The W3 Validator: W3 验证工具测试 HTML、XHTML、SMIL、MathML 等中的网站标记的有效性。要测试任何网站的标记有效性,你必须选择文档类型为 HTML5 并输入你网页的 URL。这样做之后,你的代码将被检查,并将提供所有错误和警告。

  • HTML5 Reset: 此工具允许开发人员在 HTML5 中重写旧网站的代码。你可以使用这些工具为你网站的访问者提供一个良好的网络体验。


Palak Shah

作者是高级软件工程师。她喜欢探索新技术,学习创新概念。她也喜欢哲学。你可以通过 palak311@gmail.com[1] 联系她。


via: http://opensourceforu.com/2017/06/introduction-to-html5/

作者:Palak Shah[2] 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

点击“了解更多”可访问文内链接

SpringBoot的Web开发支持

在Spring Boot的Web开发中,有许多支持类和配置文件可以帮助我们快速搭建和配置Web应用程序。其中一些重要的支持类和配置文件包括:

1.1 ServerPropertiesAutoConfiguration和ServerProperties

这两个类用于配置服务器的相关属性,比如监听端口、上下文路径等。

ServerPropertiesAutoConfiguration定义服务器配置参数加载工具Bean serverProperties ServerPropertiesAutoConfiguration是Springboot的另外一个自动配置类,位于包

package org.springframework.boot.autoconfigure.web

它定义了bean serverProperties,对应实现类ServerProperties,这是负责加载服务器配置参数的工具类。

// 该代码引用略去与本主题无关部分
@Configuration
@EnableConfigurationProperties
@ConditionalOnWebApplication
public class ServerPropertiesAutoConfiguration {

    // 定义加载服务器配置参数的工具bean
    @Bean
    @ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
    public ServerProperties serverProperties() {
        return new ServerProperties();
    }
}

ServerProperties读取服务器配置参数 ServerProperties是springboot的自动配置autoconfigure工具,位于包

org.springframework.boot.autoconfigure.web

该类用于提供服务器的端口,路径,SSL等参数设置,它实现了接口EmbeddedServletContainerCustomizer,是专门设计给EmbeddedServletContainerCustomizerBeanPostProcessor用来定制EmbeddedServletContainerFactory实例的。

ServerProperties在容器启动时会被作为bean定义注册到容器,在容器启动过程中应用EmbeddedServletContainerCustomizerBeanPostProcessor的阶段,ServerProperties bean会被实例化,此时配置文件会被该bean读取。

1.2 HttpEncodingAutoConfiguration和HttpEncodingProperties

这两个类用于配置HTTP请求和响应的字符编码方式。

HttpEncodingAutoConfiguration源码如下:

@AutoConfiguration
@EnableConfigurationProperties(ServerProperties.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {

    private final Encoding properties;

    public HttpEncodingAutoConfiguration(ServerProperties properties) {
        this.properties = properties.getServlet().getEncoding();
    }

    @Bean
    @ConditionalOnMissingBean
    public CharacterEncodingFilter characterEncodingFilter() {
        //  。。。
    }

    @Bean
    public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
        // 。。。
    }
    
    // ...
}
  • @AutoConfiguration : 该类是一个自动配置类,Spring Boot 会根据项目中的依赖自动配置这个类的实例。
  • @EnableConfigurationProperties(ServerProperties.class) :启用 ServerProperties 类的配置属性,这样在配置文件中就可以使用 server.servlet.encoding 属性来配置字符编码。
  • @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) :该配置类只有在基于 servlet 的 web 应用程序中才会被实例化。
  • @ConditionalOnClass(CharacterEncodingFilter.class) :只有在项目中存在 CharacterEncodingFilter 类时才会生效。
  • @ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true) :只有在配置文件中 server.servlet.encoding 属性的值为 "enabled" 时才会生效;当然如果配置文件中没有这个属性,也默认会生效。
  • @Bean :用于声明一个方法创建的对象是一个 Spring 管理的 Bean。Spring 容器会自动管理这个 Bean 的生命周期,包括依赖注入、初始化和销毁等。
  • @ConditionalOnMissingBean :只有在当前 Spring 容器中不存在指定类型的 Bean 时,才会执行被注解的方法。这样可以用于确保在需要的时候才创建某个 Bean,避免重复创建。

其中 ServerProperties 类的属性值对应着 application.yml 或 application.properties 中的配置,通过注解@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) 实现的属性注入。

有关属性注入来看看ServerProperties 类相关的部分源码 和 对应的配置参数:

@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
    // 。。。
    private final Servlet servlet = new Servlet();
    // 。。。
    public static class Servlet {
        // 。。。
        @NestedConfigurationProperty
        private final Encoding encoding = new Encoding();
        // 。。。
    }
    // 。。。
}

public class Encoding {
    // 默认的HTTP编码,用于Servlet应用程序。
    public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;

    // HTTP请求和响应的字符集。如果未显式设置,将添加到"Content-Type"头中
    private Charset charset = DEFAULT_CHARSET;

    // 是否强制在HTTP请求和响应上使用配置的字符集的标志
    private Boolean force;

    // 是否强制在HTTP请求上使用配置的字符集的标志。当"force"未指定时,默认为true。
    private Boolean forceRequest;

    // 是否强制在HTTP响应上使用配置的字符集的标志。
    private Boolean forceResponse;

    // 将区域设置映射到字符集以进行响应编码的映射。
    private Map<Locale, Charset> mapping;
    // 。。。
}

当然在 application.properties 中,我们就可以添加如下的配置:

server.servlet.encoding.force=true
server.servlet.encoding.charset=UTF-8
# server.servlet.encoding.force-request=true 
# ...其他配置省略

注意: server.servlet.encoding.force=true 和 server.servlet.encoding.force-request=true 这两个配置项实际上具有相同的功能,它们都决定是否强制对客户端请求进行字符编码。当这些配置项设置为 true时,服务器将要求客户端发送的请求内容使用指定的字符集进行编码。 另外,从 Spring Boot 2.3.5 版本开始,server.servlet.encoding.enabled 配置项已被弃用。因此,推荐的做法是直接设置 server.servlet.encoding.charset 来指定字符集,然后通过设置server.servlet.encoding.force=true 来开启对请求/响应的编码集强制控制。

1.3 MultipartAutoConfiguration和MultipartProperties

这两个类用于配置文件上传功能。

MultipartAutoConfiguration和MultipartProperties源码如下:

@Configuration(proxyBeanMethods = false)
//类路径下存在类Servlet, StandardServletMultipartResolver, MultipartConfigElement
@ConditionalOnClass({ Servlet.class, StandardServletMultipartResolver.class, MultipartConfigElement.class })
//文件上传开关,默认开启
@ConditionalOnProperty(prefix = "spring.servlet.multipart", name = "enabled", matchIfMissing = true)
//servlet web应用环境
@ConditionalOnWebApplication(type = Type.SERVLET)
//文件上传配置信息MultipartProperties
@EnableConfigurationProperties(MultipartProperties.class)
public class MultipartAutoConfiguration {

    private final MultipartProperties multipartProperties;

    public MultipartAutoConfiguration(MultipartProperties multipartProperties) {
        this.multipartProperties = multipartProperties;
    }
    //不存在MultipartConfigElement、CommonsMultipartResolver时创建MultipartConfigElement 
    @Bean
    @ConditionalOnMissingBean({ MultipartConfigElement.class, CommonsMultipartResolver.class })
    public MultipartConfigElement multipartConfigElement() {
        return this.multipartProperties.createMultipartConfig();
    }
    
    //不存在时创建MultipartResolver
    @Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
    @ConditionalOnMissingBean(MultipartResolver.class)
    public StandardServletMultipartResolver multipartResolver() {
        StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();
        multipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily());
        return multipartResolver;
    }

}

MultipartProperties源码:

@ConfigurationProperties(prefix = "spring.servlet.multipart", ignoreUnknownFields = false)
public class MultipartProperties {

    /**
     * Whether to enable support of multipart uploads.
     */
     //文件上传开关
    private boolean enabled = true;

    /**
     * Intermediate location of uploaded files.
     */
     //文件上传中间路径
    private String location;

    /**
     * Max file size.
     */
     //文件最大大小
    private DataSize maxFileSize = DataSize.ofMegabytes(1);

    /**
     * Max request size.
     */
     //最大请求文件大小
    private DataSize maxRequestSize = DataSize.ofMegabytes(10);

    /**
     * Threshold after which files are written to disk.
     */
     //阈值,超过后文件将被写入磁盘
    private DataSize fileSizeThreshold = DataSize.ofBytes(0);

    /**
     * Whether to resolve the multipart request lazily at the time of file or parameter
     * access.
     */
     //延迟解析
    private boolean resolveLazily = false;

    /**
     * Create a new {@link MultipartConfigElement} using the properties.
     * @return a new {@link MultipartConfigElement} configured using there properties
     */
     //根据默认或自定义配置项创建MultipartConfigElement 
    public MultipartConfigElement createMultipartConfig() {
        MultipartConfigFactory factory = new MultipartConfigFactory();
        PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
        map.from(this.fileSizeThreshold).to(factory::setFileSizeThreshold);
        map.from(this.location).whenHasText().to(factory::setLocation);
        map.from(this.maxRequestSize).to(factory::setMaxRequestSize);
        map.from(this.maxFileSize).to(factory::setMaxFileSize);
        return factory.createMultipartConfig();
    }

}

常用配置如下

spring.servlet.multipart.enabled=true
spring.servlet.multipart.max-file-size=10485760000
spring.servlet.multipart.max-request-size=52428800000
spring.servlet.multipart.location=d:/tmp

1.4 JacksonHttpMessageConvertersConfiguration

这个类用于配置JSON转换器,方便在Web应用中处理JSON数据。

JacksonHttpMessageConvertersConfiguration源码:

@Configuration(
        proxyBeanMethods = false
)
class JacksonHttpMessageConvertersConfiguration {
    JacksonHttpMessageConvertersConfiguration() {
    }
 
    @Configuration(
            proxyBeanMethods = false
    )
    @ConditionalOnClass({XmlMapper.class})
    @ConditionalOnBean({Jackson2ObjectMapperBuilder.class})
    protected static class MappingJackson2XmlHttpMessageConverterConfiguration {
        protected MappingJackson2XmlHttpMessageConverterConfiguration() {
        }
 
        @Bean
        @ConditionalOnMissingBean
        public MappingJackson2XmlHttpMessageConverter mappingJackson2XmlHttpMessageConverter(Jackson2ObjectMapperBuilder builder) {
            return new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build());
        }
    }
 
    /**
     * @Configuration - 配置类注解
     * @ConditionalOnXxx
     *      - 为条件注解,当添加了Jackson依赖,就有了ObjectMapper.class和属性,后面的配置就会生效
     */
    @Configuration(
            proxyBeanMethods = false
    )
    @ConditionalOnClass({ObjectMapper.class})
    @ConditionalOnBean({ObjectMapper.class})
    @ConditionalOnProperty(
            name = {"spring.mvc.converters.preferred-json-mapper"},
            havingValue = "jackson",
            matchIfMissing = true
    )
    static class MappingJackson2HttpMessageConverterConfiguration {
        MappingJackson2HttpMessageConverterConfiguration() {
        }
 
        /**
         * MappingJackson2HttpMessageConverter就是Jackson的消息转换工具类
         * @ConditionalOnMissingBean
         *   - 表示如果我们没有配置这个Bean,就自动创建一个默认的,当我们配置了就使用我们自定义的Bean。
         *
         * @param objectMapper
         * @return
         */
        @Bean
        @ConditionalOnMissingBean(
                value = {MappingJackson2HttpMessageConverter.class},
                ignoredType = {"org.springframework.hateoas.server.mvc.TypeConstrainedMappingJackson2HttpMessageConverter", "org.springframework.data.rest.webmvc.alps.AlpsJsonHttpMessageConverter"}
        )
        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
            // JSON中序列化对象主要用ObjectMapper工具类
            return new MappingJackson2HttpMessageConverter(objectMapper);
        }
    }

通过查看上面源码,可以知道我们修改生成的JSON的全局格式有以下两种方式:

1)自定义MappingJackson2HttpMessageConverter类

自己创建一个Bean,取代JacksonHttpMessageConvertersConfiguration中项目自带的。

例如:删除 @JsonFormat注解,新建一个配置类,内容如下:

@Configuration
public class WebMVCConfig {
 
    @Bean
    MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
        converter.setObjectMapper(objectMapper);
        return converter;
    }
}

2)自定义ObjectMapper类

通过上面的类可以看到类中主要起作用的是ObjectMapping,ObjectMapping是直接注入的。它是在配置类JacksonAutoConfiguration 类中提供的。

例如:在WebMVCConfig配置类中,注入自定义的ObjectMapping,内容如下:

@Configuration
public class WebMVCConfig {
 
    @Bean
    ObjectMapper objectMapper(){
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
        return objectMapper;
    }
}

1.5 WebMvcAutoConfiguration和WebMvcProperties

这两个类用于配置Spring MVC的相关属性,比如视图解析器、拦截器等。

WebMvcAutoConfiguration源码:

// 我的自动配置类在这些自动配置之后配置
@AutoConfiguration(
	after = { 
		DispatcherServletAutoConfiguration.class, 
		TaskExecutionAutoConfiguration.class,
		ValidationAutoConfiguration.class 
	}) 
	
// 如果是web应用就生效,类型SERVLET、REACTIVE 响应式web
@ConditionalOnWebApplication(type = Type.SERVLET)

// 容器中没有这个Bean,才生效。默认就是没有
@ConditionalOnClass({ 
	Servlet.class, 
	DispatcherServlet.class,
	WebMvcConfigurer.class 
	})
// 容器中没有WebMvcConfigurationSupport类,才生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class) 

// 优先级
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)

// 导入运行时的指标统计
@ImportRuntimeHints(WebResourcesRuntimeHints.class)
public class WebMvcAutoConfiguration { 
}

给容器中放了WebMvcConfigurer组件;给SpringMVC添加各种定制功能

所有的功能最终会和配置文件进行绑定 WebMvcProperties: spring.mvc配置文件 WebProperties: spring.web配置文件

@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class) // 额外导入了其他配置
@EnableConfigurationProperties({ WebMvcProperties.class, WebProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware{

}

2 Thymeleaf模版引擎

2.1 Thymeleaf基础知识

Thymeleaf是适用于Web和独立环境的现代服务器端Java引擎模板

(1)模板引擎介绍 模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的html文档。从字面上理解模板引擎,最重要的就是模板二字,这个意思就是做好一个模板后套入对应位置的数据,最终以html的格式展示出来,这就是模板引擎的作用。 对于模板引擎的理解,可以这样形象的做一个类比:开会! 相信你在上学初高中时候每次开会都要提前布置场地、拿小板凳、收拾场地。而你上了大学之后每次开会再也不去大操场了,每次开会都去学校的大会议室,桌子板凳音响主席台齐全,来个人即可,还可复用……。

模板引擎的功能就类似我们的会议室开会一样开箱即用,将模板设计好之后直接填充数据即可而不需要重新设计整个页面。提高页面、代码的复用性。 不仅如此,在Java中模板引擎还有很多,模板引擎是动态网页发展进步的产物,在最初并且流传度最广的jsp它就是一个模板引擎。jsp是官方标准的模板,但是由于jsp的缺点比较多也挺严重的,所以很多人弃用jsp选用第三方的模板引擎,市面上开源的第三方的模板引擎也比较多,有Thymeleaf、FreeMaker、Velocity等模板引擎受众较广。

(2)Thymeleaf介绍 Thymeleaf是众多模板引擎的一种,从官方的介绍来看,Thymeleaf的目标很明确:

Thymeleaf的主要目标是为开发工作流程带来优雅自然的模板-HTML可以在浏览器中正确显示,也可以作为静态原型工作,从而可以在开发团队中加强协作。 Thymeleaf拥有适用于Spring Framework的模块,与开发者喜欢的工具的大量集成以及插入开发者自己的功能的能力,对于现代HTML5 JVM Web开发而言,Thymeleaf是理想的选择——尽管它还有很多工作要做。 并且随着市场使用的验证Thymeleaf也达到的它的目标和大家对他的期望,在实际开发有着广泛的应用。Thymeleaf作为被Springboot官方推荐的模板引擎,一定有很多过人和不寻同之处:

  • 动静分离: Thymeleaf选用html作为模板页,这是任何一款其他模板引擎做不到的!Thymeleaf使用html通过一些特定标签语法代表其含义,但并未破坏html结构,即使无网络、不通过后端渲染也能在浏览器成功打开,大大方便界面的测试和修改。
  • 开箱即用: Thymeleaf提供标准和Spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、改JSTL、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。

Springboot官方大力推荐和支持,Springboot官方做了很多默认配置,开发者只需编写对应html即可,大大减轻了上手难度和配置复杂度。

2.2 引入 Thymeleaf 依赖

(1)pml引用

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

(2)配置文件

全局配置文件application.properties配置Thymeleaf模板的一些参数。如设置模板缓存、模板编码、模板样式、指定模板页面存放路径、指定模板页面名称的后缀

spring.thymeleaf.cache=true
spring.thymeleaf.encoding=UTF-8   
spring.thymeleaf.mode=HTML5   
spring.thymeleaf.prefix=classpath:/templates/  
spring.thymeleaf.suffix=.html   

(3)Thymeleaf命名空间的声明

<!DOCTYPE html>  
<html xmlns:th="http://www.thymeleaf.org">  
<head>  
    <title>My Thymeleaf Template</title>  
    <!-- 其他head元素,如meta, link, script等 -->  
</head>  
<body>  
    <!-- 页面内容 -->  
</body>  
</html>

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

xmlns:th声明了Thymeleaf的命名空间。这个命名空间允许你在HTML标签中使用Thymeleaf特定的属性,如th:text、th:each等。Thymeleaf引擎在处理模板时会识别这些属性,并根据它们的值动态地生成或修改HTML内容。

2.3 常用配置

虽然Springboot官方对Thymeleaf做了很多默认配置,但引入Thymeleaf的jar包依赖后很可能需要根据开发者特定需求进行更细化的配置,例如页面缓存、字体格式设置等等。

Springboot官方提供的配置内容有以下:

# 是否启用模板缓存,默认为true。启用后,模板在第一次编译后会被缓存,提高渲染效率。
spring.thymeleaf.cache=true 

# 在渲染模板之前是否检查模板是否存在,默认为false。
spring.thymeleaf.check-template=true 

# 是否检查模板位置是否存在,默认为true。
spring.thymeleaf.check-template-location=true 

# 是否启用Thymeleaf视图解析,适用于Web框架,默认为true。
spring.thymeleaf.enabled=true 

# 是否在SpringEL表达式中启用SpringEL编译器,默认为false。启用后可以提高表达式的执行效率。
spring.thymeleaf.enable-spring-el-compiler=false 

# 模板文件的编码方式,默认为"UTF-8"。
spring.thymeleaf.encoding=UTF-8 

# 逗号分隔的视图名称列表(允许使用模式),这些视图将被排除在解析之外。
spring.thymeleaf.excluded-view-names= 

# 应用于模板的模板模式,默认为"HTML"。也可以参考Thymeleaf的TemplateMode枚举了解其他模式。
spring.thymeleaf.mode=HTML 

# 构建URL时,视图名称前缀,默认为"classpath:/templates/"。
spring.thymeleaf.prefix=classpath:/templates/ 

# 当设置了最大块大小时,只有这些视图名称(允许使用模式)会以CHUNKED模式执行。
spring.thymeleaf.reactive.chunked-mode-view-names= 

# 即使设置了最大块大小,这些视图名称(允许使用模式)也会以FULL模式执行。
spring.thymeleaf.reactive.full-mode-view-names= 

# 用于写入响应的数据缓冲区的最大大小,以字节为单位,默认为0。
spring.thymeleaf.reactive.max-chunk-size=0 

# 视图技术支持的媒体类型。
spring.thymeleaf.reactive.media-types= 

# 写入HTTP响应的Content-Type值,默认为"text/html"。
spring.thymeleaf.servlet.content-type=text/html 

# 构建URL时,视图名称的后缀,默认为".html"。
spring.thymeleaf.suffix=.html 

# 模板解析器在链中的顺序。
spring.thymeleaf.template-resolver-order= 

# 逗号分隔的视图名称列表(允许使用模式),这些视图可以被解析。
spring.thymeleaf.view-names= 

2.4 常用语法

Thymeleaf 作为一种模板引擎,它拥有自己的语法规则。Thymeleaf 语法分为以下 2 类:

  • th属性
  • 标准表达式语法

2.4.1 th属性



  • th:eache:status中,有count(获取循环的次数,从1开始)、first(判断是否为第一次循环)、index(获取循环的索引号,从0开始)、event(判断count是否为偶数)、last(判断是否是最后一次循环)、odd(判断count是否为奇数)、size(获取集合的长度)
<tr th:each="employee,status : ${employees}">
	<td th:text="${status.count}"></td>
</tr>
1
  • th:field:获取域对象的属性值,后台不能用reques.setAttribute()来传值,可以用model.addAttribute()来传值;而这两种方式th:value都可以接收;在单选框中,当th:field中的属性值与value的值一样,单选框就会被选中

2.4.2 标准表达式语法

Thymeleaf 模板引擎支持多种表达式:

  • 变量表达式:${...}
  • 选择变量表达式:*{...}
  • 链接表达式:@{...}
  • 国际化表达式:#{...}
  • 片段引用表达式:~{...}

变量表达式和国际化表达式都属于OGNL(Objects-Graph Navigation Language,对象导航图语言)是应用于Java中的一个开源的表达式语言

2.4.2.1 变量表达式

变量表达式(Variable Expressions):用于在模板中引用和显示变量的值。例如,${variable}表示引用名为variable的变量

使用 ${} 包裹的表达式被称为变量表达式,该表达式具有以下功能:

  • 获取对象的属性或方法
  • 获取内置的基本对象并使用
  • 获取内置的工具对象并使用

${对象.属性/方法名}:获取对象的属性或方法

//获取对象的方法
${book.getName()}

${#内置的基本对象}:获取内置的基本对象并使用

  • ctx :上下文对象
  • vars :上下文变量
  • locale:上下文的语言环境
  • request:HttpServletRequest 对象(仅在 Web 应用中可用)
  • response:HttpServletResponse 对象(仅在 Web 应用中可用)
  • session:HttpSession 对象(仅在 Web 应用中可用)
  • servletContext:ServletContext 对象(仅在 Web 应用中可用)
//获取Session域对象中存储的List集合对象
//方式一:
${#session.getAttribute('books')
//方式二:
${session.books}

${#内置的工具对象}:获取内置的工具对象并使用

  • strings:字符串工具对象,常用方法有:equals、equalsIgnoreCase、length、trim、toUpperCase、toLowerCase、indexOf、substring、replace、startsWith、endsWith,contains 和 containsIgnoreCase 等
  • numbers:数字工具对象,常用的方法有:formatDecimal 等
  • bools:布尔工具对象,常用的方法有:isTrue 和 isFalse 等
  • arrays:数组工具对象,常用的方法有:toArray、length、isEmpty、contains 和 containsAll 等
  • lists/sets:List/Set 集合工具对象,常用的方法有:toList、size、isEmpty、contains、containsAll 和 sort 等
  • maps:Map 集合工具对象,常用的方法有:size、isEmpty、containsKey 和 containsValue 等
  • dates:日期工具对象,常用的方法有:format、year、month、hour 和 createNow 等
//使用内置工具对象 strings 的 equals 方法,来判断字符串与对象的某个属性是否相等
${#strings.equals('张三',name)}

2.4.2.2 选择表达式

选择表达式(Selection Expressions):用于从对象中选择属性或方法。例如,*{user.name}表示选择user对象的name属性。

选择变量也可以称为星号表达式,表达式与变量表达式功能基本一致,只是在变量表达式的基础上增加了与 th:object 的配合使用。当使用 th:object 存储一个对象后,我们可以在其后代中使用选择变量表达式{...}获取该对象中的属性,其中,即代表该对象

<div th:object="${session.user}" >
    <!--直接获取user对象中的userName属性的值-->
    <p th:text="*{userName}">firstname</p>
</div>

2.4.2.3 URL表达式

URL表达式(URL Expressions):用于生成动态URL链接。例如,@{/path}会生成相对于当前上下文路径的URL。

链接表达式的形式结构如下:

  • 无参请求:@{/xxx}
  • 有参请求:@{/xxx(k1=v1,k2=v2)}

2.4.2.4 链接表达式

链接表达式(Link Expressions):类似于URL表达式,用于生成页面内部的锚点链接。例如,#fragmentId会生成一个指向具有相应片段标识符的位置的链接。

链接表达式是用于生成页面内部的锚点链接(即片段标识符)。它们使用#符号作为前缀,后跟片段标识符。例如,#fragmentId会生成一个指向具有相应片段标识符的位置的链接。链接表达式主要用于在同一页面内部进行导航和定位。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Link and URL Expression Demo</title>
</head>
<body>
    <h1>Link and URL Expression Demo</h1>
    
    <p>Link Expression:</p>
    <a th:href="#section1">Go to Section 1</a>
    <a th:href="#section2">Go to Section 2</a>
    
    <p>URL Expression:</p>
    <a th:href="@{/path1}">Link to Path 1</a>
    <a th:href="@{/path2}">Link to Path 2</a>

    <!-- Assume there are corresponding sections and paths in the application -->
    <section id="section1">
        <h2>Section 1</h2>
        <p>This is section 1 content.</p>
    </section>
    <section id="section2">
        <h2>Section 2</h2>
        <p>This is section 2 content.</p>
    </section>
</body>
</html>

在上面的示例中,我们使用Thymeleaf的链接表达式和URL表达式创建了一些链接。

链接表达式使用#符号,并通过th:href属性生成到相应片段标识符的锚点链接。例如,<a th:href="#section1">Go to Section 1</a>会生成一个链接,点击后将滚动至具有section1片段标识符的位置。

URL表达式使用@符号,并通过th:href属性生成动态的URL链接。例如,<a th:href="@{/path1}">Link to Path 1</a>会生成相对于当前上下文路径的URL,点击后将导航到/path1。

4.2.2.5 国际化表达式

国际表达式使用的基本步骤:

配置国际化资源文件:首先,在项目中配置对应的国际化资源文件,按照不同语言创建不同的属性文件,如messages_en.properties(英语)、messages_zh_CN.properties(中文)等。每个属性文件中包含了对应语言的键值对,用于表示不同语言下的文本信息。

设置 Locale 解析器:在 Spring MVC 中,需要配置 LocaleResolver 来解析用户的语言偏好,并将其应用到 Thymeleaf 视图中。常见的 LocaleResolver 有 CookieLocaleResolver、SessionLocaleResolver等,你可以根据需求选择合适的LocaleResolver。

在 Thymeleaf 模板中使用国际化表达式:在 Thymeleaf 模板中,可以使用国际化表达式来获取对应语言的文本信息。通过#{}来包裹键名,Thymeleaf 会根据当前 Locale 自动寻找对应的属性值。例如,<span th:text="#{welcome.message}"></span> 表示从国际化资源文件中获取键为 “welcome.message” 的文本信息并显示在HTML中。

4.2.2.6 片段引用表达式

Thymeleaf的片段引用表达式(Fragment Expression)是一种在模板中引用和渲染片段的方式。它允许将一个或多个片段从其他模板中提取出来并在当前模板中进行引用和渲染。

Thymeleaf的片段引用表达式使用~{}包裹片段名称,并可以传递参数。以下是使用片段引用表达式的基本语法:

<div th:insert="~{templateName :: fragmentName(parameter1='value1', parameter2='value2')}"></div>

其中,templateName表示模板文件名,fragmentName表示片段名称。通过::符号来连接模板文件名和片段名称。在片段引用表达式中,还可以传递参数给被引用的片段。参数以键值对的形式传递,使用逗号分隔。

示例中的parameter1和parameter2是片段中定义的参数名称,value1和value2是要传递的实际值。

使用片段引用表达式可以将片段从其他模板中提取出来并插入到当前模板的指定位置。这有助于模块化开发和代码复用,可以将通用的部分抽离出来,减少重复代码的编写。

需要注意的是,被引用的片段必须在对应的模板文件中存在,并且在片段定义处使用th:fragment属性进行标记。例如,在templateName.html模板文件中定义一个片段:

<div th:fragment="fragmentName">
    <!-- 片段内容 -->
</div>

然后在另一个模板中使用片段引用表达式来引用和渲染该片段:

<div th:insert="~{templateName :: fragmentName}"></div>

通过使用Thymeleaf的片段引用表达式,我们可以方便地将模板中的特定部分提取出来并在其他模板中重复使用,提高了代码的可维护性和重用性。

3 Web相关配置

3.1 SpringBoot提供的自动配置

3.1.1 自动配置的ViewResolver

(1)ContentNegotiatingViewResolver

  • ContentNegotiatingViewResolver支持在Spring MVC下输出不同的格式
  • ContentNegotiatingViewResolver是ViewResolver的一个实现
  • ContentNegotiatingViewResolver使用request的媒体类型,根据扩展名选择不同的view输出不同的格式
  • ContentNegotiatingViewResolver不是自己处理view,而是代理给不同的ViewResolver来处理不同的view;

Spring在解析视图的时候有两个重要的接口:ViewResolverView

ViewResolver 中只有一个方法 resolveViewName ,提供 view name 和 实际 view的映射; View 中两个方法 getContentTyperender ,解析请求中的参数并把这个请求处理成某一种 View.

对于一个请求,应该返回什么样的视图是 ViewResolver 来决定的,spring3.0提供的 ViewResolver 包括 AbstractCachingViewResolver,XmlViewResolver,ResourceBundleViewResolver,UrlBasedViewResolver,InternalResourceViewResolver,VelocityViewResolver/FreeMarkerViewResolver,ContentNegotiatingViewResolver等

ContentNegotiatingViewResolver

根据官方文档:The ContentNegotiatingViewResolver does not resolve views itself but rather delegates to other view resolvers,就是说ContentNegotiatingViewResolver 本身并不自己去解析,只是分配给其他的ViewResolver 去解析。并选择一个看起来像是客户端请求需要返回的一种 View 返回。

  • spring检查setFavorPathExtension(boolean) ,如果这个属性为true(默认为true),检查请求的后缀名,来返回一种 mediaType ,而后缀名和mediaType是通过ContentNegotiatingViewResolver 配置中的mediaTypes指定的
  • spring检查 setFavorParameter(boolean) 这个属性是否为true(默认为false),而如果你打开这个属性,那么默认的参数名应为 format_
  • 没有找到合适的mediaType,并且 ignoreAcceptHeader 这个属性为false(默认为false),spring则根据 你请求头里面设置的 ContentType 来找适合的 mediaType

要想返回JSON数据所代表的MappingJacksonJsonView ,要么在请求头中设置contentType为application/json,要么使用 .json 或者 ?format=json

例子:

/user/showUserListMix.html     //返回一个html的页面显示用户列表
/user/showUserListMix.html ?content=xml   //返回一个xml的页面显示用户列表
/user/showUserListMix.html ?content=json   //返回一个json的页面显示用户列表

(2)BeanNameViewResolver

1)BeanNameViewResolver概述

BeanNameViewResolver是Spring MVC框架提供的一个视图解析器,它根据视图名称直接查找Spring容器中的同名Bean作为视图对象。这种方式的好处在于简单直观,当视图名称与Bean名称一一对应时,可以快速地解析出视图对象。

2)BeanNameViewResolver工作原理

  • 查找视图Bean 当Spring MVC接收到一个请求并需要解析视图时,它会调用BeanNameViewResolver的resolveViewName方法。该方法会根据请求的视图名称,在Spring容器中查找与之同名的Bean。如果找到了匹配的Bean,就将其返回作为视图对象;如果没有找到,则继续尝试其他视图解析器。
  • 视图Bean的创建与管理 在Spring容器中,视图Bean的创建和管理与其他Bean没有本质区别。可以通过XML配置或注解的方式定义视图Bean,并指定其生命周期和依赖关系。Spring容器会负责这些Bean的创建、初始化和销毁等过程。
  • 视图Bean的调用 当BeanNameViewResolver解析出视图Bean后,Spring MVC会调用该Bean的相应方法(通常是render方法)来渲染视图。这取决于视图Bean的具体实现和配置。

3)BeanNameViewResolver的适用场景

BeanNameViewResolver适用于视图名称与Bean名称一一对应的情况,特别是当视图实现较为简单且数量不多时。在这种情况下,使用BeanNameViewResolver可以简化配置和代码,提高开发效率。

然而,当视图实现较为复杂或数量较多时,使用BeanNameViewResolver可能会导致Spring容器中的Bean数量过多,增加管理难度。此时,可以考虑使用其他更灵活的视图解析器,如InternalResourceViewResolver或自定义的视图解析器。

4)总结

BeanNameViewResolver作为Spring MVC框架中的一种视图解析器,具有简单直观的特点。它通过直接查找Spring容器中的同名Bean来解析视图对象,适用于视图名称与Bean名称一一对应的情况。然而,在复杂或大规模的项目中,可能需要考虑使用其他更灵活的视图解析器来满足需求。

在使用BeanNameViewResolver时,需要注意以下几点:

  • 确保视图名称与Spring容器中的Bean名称一致;
  • 合理管理视图Bean的生命周期和依赖关系;
  • 根据项目实际情况选择合适的视图解析器。
  • 通过对BeanNameViewResolver原理的解析,我们可以更好地理解和使用这一视图解析器,为Spring MVC项目的开发提供便利。

(3)InteranlResourceViewResolver

InternalResourceViewResolver 是 Spring MVC 中的一个视图解析器,用于解析视图名称并将其解析为服务器上的实际资源。它主要用于将逻辑视图名称(例如 “index”)解析为实际的视图资源路径(例如 “/WEB-INF/views/index.jsp”)。

InternalResourceViewResolver 可以配置在 Spring MVC 的配置文件中,并用于处理控制器方法返回的逻辑视图名称。当控制器方法返回一个字符串作为视图名称时,InternalResourceViewResolver 会将这个逻辑视图名称解析为实际的视图资源路径,然后将该路径返回给客户端进行展示。

通过配置 InternalResourceViewResolver,可以简化控制器方法的返回处理逻辑,并提供一种方便的方式来管理视图资源的路径。

@Bean
public ViewResolver viewResolver() {
    InternalResourceViewResolver irv = new InternalResourceViewResolver();
    irv.setPrefix("/WEB-INF/");
    irv.setSuffix(".jsp");

    return irv;

}

3.1.2 自动配置的静态资源

一般客户端发送请求到web服务器,web服务器从内存在取到相应的文件,返回给客户端,客户端解析并渲染显示出来。

例如:css,js等文件。

(1)使用webjar实现

SpringBoot中,SpringMVC的web配置都在 WebMvcAutoConfiguration 这个配置类里面,默认为我们提供了静态资源处理。

我们进入WebMvcAutoConfigurationAdapter源码里面进行查看,发现有这么一个方法: addResourceHandlers 添加资源处理;

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
        if (!this.resourceProperties.isAddMappings()) {
// 已禁用默认资源处理
        logger.debug("Default resource handling disabled");
        return;
        }
// 缓存控制
        Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
        CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
// webjars 配置
        if (!registry.hasMappingForPattern("/webjars/**")) {
        customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
        .addResourceLocations("classpath:/META-INF/resources/webjars/")
        .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
        }
// 静态资源配置
        String staticPathPattern = this.mvcProperties.getStaticPathPattern();
        if (!registry.hasMappingForPattern(staticPathPattern)) {
        customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
        .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
        .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
        }
        }

所有的 /webjars/** , 都需要去 classpath:/META-INF/resources/webjars/ 找对应的资源; 什么是webjars 呢?

Webjars本质就是以jar包的方式引入我们的静态资源 。

  • 显而易见,因为简单。但不仅是依赖这么简单:
  • 清晰的管理 web 依赖
  • 通过 Maven, Gradle 等项目管理工具就可以下载 web 依赖
  • 解决 web 组件中传递依赖的问题以及版本问题

页面依赖的版本自动检测功能

WebJars是将这些通用的Web前端资源打包成Java的Jar包,然后借助Maven工具对其管理,保证这些Web资源版本唯一性,升级也比较容易。关于webjars资源,有一个专门的网站https://www.webjars.org/,我们可以到这个网站上找到自己需要的资源,在自己的工程中添加入maven依赖,即可直接使用这些资源了。

1)pom中引入依赖

我们可以从WebJars官方查看maven依赖,如下图


例如:将bootstrap和jquery引入pom文件中

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

<dependency>
   <groupId>org.webjars</groupId>
   <artifactId>bootstrap</artifactId>
   <version>4.5.0</version>
</dependency>

2)访问引入的js文件

在html内访问静态资源可以使用如下方式:

<script src="/webjars/jquery/3.5.1/jquery.min.js "></script>

<script src="/webjars/bootstrap/4.5.0/js/bootstrap.min.js"></script>

(2)将静态资源文件放至静态资源文件夹

ResourceProperties类部分源码

@ConfigurationProperties(
  prefix = "spring.resources",
  ignoreUnknownFields = false
)
public class ResourceProperties {
  //springboot默认的加载路径
  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;

映射规则总结

在springboot静态资源加载规则中,除了”标准“静态资源位置之外,还有一个较为特殊的WebJars “标准”静态资源映射规则。 所有的“/**”的请求,如果没有对应的处理,那么就去默认映射的静态资源目录下去找,如下所示:

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

(3)SpringBoot配置静态资源

1)通过配置文件配置

配置节点:spring.web.resources.static-locations

值为要配置的静态资源存放目录

spring:
    web:     
        resources:
            static-locations: classpath:/test/

以上配置中,设置静态资源目录为src/main/resources/test/目录。

假如在test目录下存放文件test.txt,程序启动后,便能通过浏览器访问ip:port/test.txt访问文件。

2) 通过config类配置

新建WebMvcConfig类,继承WebMvcConfigurationSupport类,并添加注解@Configuration。

重写WebMvcConfigurationSupport类的addResourceHandlers方法。

通过参数ResourceHandlerRegistry的addResourceHandler方法和addResourceLocations添加访问路径与资源目录的映射。

@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/test/**").addResourceLocations("classpath:/test/");
    }
}

上述配置代码中,添加了路径/test/**对资源目录src/main/resources/test/的映射。

假如在test目录下存放文件test.txt,程序启动后,便能在浏览器访问ip:port/test/test.txt访问文件内容

区别:

  • 通过配置文件配置时,只能覆盖默认配置设置一个静态资源目录(默认目录为static),但无需添加根目录名即可访问。如“一”中访问test.txt时,并没有/test/路径,而是直接访问test.txt。
  • 通过代码配置时,可以配置多对访问路径和资源目录的映射,但访问路径需要包含根目录名。如“二”中,访问test.txt时,需要添加/test/路径。

共同点:

  • 以上两种方法,一旦选择其一进行配置,默认配置(static)目录即失效。
  • 当同时使用两种方法时,配置文件方法失效,仅代通过配置类配置的方法生效。

3.1.3 自动配置的Formatter和Conventer

只要我们定义了Converter,GenericConverter和Formatter接口的实现类的Bean,这些Bean就会自动注册到SpringMVC中。 参考一下源码(位于WebMvcAutoConfiguration类中)

@Override
public void addFormatters(FormatterRegistry registry) {
	for (Converter<?, ?> converter : getBeansOfType(Converter.class)) {
		registry.addConverter(converter);
	}
	for (GenericConverter converter : getBeansOfType(GenericConverter.class)) {
		registry.addConverter(converter);
	}
	for (Formatter<?> formatter : getBeansOfType(Formatter.class)) {
		registry.addFormatter(formatter);
	}
}

private <T> Collection<T> getBeansOfType(Class<T> type) {
	return this.beanFactory.getBeansOfType(type).values();
}

3.1.4 自动配置的HttpMessageConverters

在WebMvcAutoConfiguration中,注册了messageConverters:

private final HttpMessageConverters messageConverters;
@Override
        public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            converters.addAll(this.messageConverters.getConverters());
        }

在Spring Boot中,如果要新增自定义的HttpMessageVoncerter,需要定义一个自己的HttpMessageConverters的Bean,然后在这个Bean中注册自定义的HttpMessageConverter即可。 例如:

@Bean
public HttpMessageConverters customConverters() {
    HttpMessageConverter<?> customConverter1 = new CustomConverter1();
    HttpMessageConverter<?> customConverter2 = new CustomConverter2();
    return new HttpMessageConverters(customConverter1, customConverter2);
}

3.1.5 静态首页的支持

将静态首页index.html文件放置在如下目录:

  • classpath:/META-INF/resources/index.html
  • classpath:/resources/index.html
  • classpath:/static/index.html
  • classpath:/public/index.html 当访问应用根目录http://localhost:8080/时,会直接映射。

3.2 接管SpringBoot的Web配置

  • 可以通过一个配置类(注解有@Configuration的类)加上@EnableWebMvc注解来实现自己控制的MVC配置。
  • 可以定义一个配置类并继承WebMvcConfigurationAdapter,无需使用@EnableWebMvc注解,然后按照Spring MVC的配制方法来添加Spring Boot
@Configuration
public class WebMvcConfig extends WebMvcConfigurationAdapter{
    @Override
    public void addViewControllers(ViewCOntrolllerRegistery residtry) {
        registery.addViewController("/xx").setViewName("/xx");
    }
}

注意,这里重写的addViewControllers方法,并不会覆盖WebMvcAutoConfiguration中的addViewControllers方法,即自己配置和Spring Boot的自动配置同时有效。

3.3 注册Servlet,Filter,Listener

当使用嵌入式Servlet容器(Tomcat,Jetty等)时,通过将Servlet,Filter,Listener生命为Spring Bean来达到注册的效果,或者注册ServletRegistrationBean、FilterRegistrationBean、ServletListenerRigistrationBean的Bean。

(1) 直接注册Bean:

@Bean
pubilc XxServlet xxServlet (){
    return new XxServlet();
}

@Bean
public YyFilter yyFilter() {
    return new YyServlet();
}

@Bean
public ZzListener zzListener() {
    return new ZzListener();
}

(2) 通过RegistrationBean

@Bean
public ServletRegistrationBean serletRegistrationBean() {
    return new ServletRegistrationBean(new XxServlet(), "/xx/*");
}

@Bean 
public FilterRegistrationBean filterRegistrationBean() {
    FilterRegistrationBean  registrationBean = new FilterRegistrationBean();
    registrationBean.setFilter( new YyFilter());
    registrationBean.setOrder(2);
    return registrationBean;
}

@Bean
public ServletListenerRegistrationBean<ZzListener> zzListenerRegistrationBean() {
    return new ServletListenerRegistrationBean<ZzListener> (new ZzListener())
}

4 Tomcat配置

4.1 配置Tomcat

SpringBoot 项目中,可以内置 TomcatJettyUndertowNetty 等服务器容器。当我们添加了 spring-boot-starter-web 依赖后,默认会使用 Tomcat 作为 Web 容器。

在SpringBoot框架的自动配置类中,Web项目中不显式更换其他服务依赖时,默认提供了对Tomcat服务的管理;

@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class})
public class ServletWebServerFactoryAutoConfiguration {

	@Bean
	@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
	public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
			ServerProperties serverProperties) {
		return new TomcatServletWebServerFactoryCustomizer(serverProperties);
	}
}

4.2 常用配置

4.2.1 基本配置

在配置文件中,对Tomcat做一些基础性的设置,查看下面的配置类可以知道,这些属性存在默认值;

server:
  port: 8082                # 端口号
  tomcat:                   # Tomcat组件
    uri-encoding: UTF-8     # URI编码
    max-threads: 100        # 最大工作线程
    min-spare-threads: 10   # 最小工作线程

4.2.2 常用配置

#端口号,默认8080
server.port = 80
 
#服务器绑定的网络地址,默认0.0.0.0,允许通过所有IPv4地址进行连接
server.address = yourIp
 
#标准错误网页,Whitelabel。它默认启用,可以关闭
server.error.whitelabel.enabled = false
 
#Whitelabel默认路径是/error,可以通过设置server.error.path参数来自定义它
server.error.path = /user-error
 
#设置属性,以确定显示有关错误的信息。可以包含错误消息和堆栈跟踪
server.error.include-exception= true
server.error.include-stacktrace= always
 
#工作线程的最大数量
server.tomcat.max-threads= 200
 
#设置服务器连接超时时间
server.connection-timeout= 5s
 
#定义请求头的最大大小
server.max-http-header-size= 8KB
 
#请求正文的最大大小
server.tomcat.max-swallow-size= 2MB
 
#整个POST请求的最大大小
server.tomcat.max-http-post-size= 2MB
 
#启用SSL支持,定义SSL协议
server.ssl.enabled = true
server.ssl.protocol = TLS
 
#配置保存证书密钥库的密码,类型和路径
server.ssl.key-store-password=my_password
server.ssl.key-store-type=keystore_type
server.ssl.key-store=keystore-path
 
#定义标识密钥库中密钥的别名
server.ssl.key-alias=tomcat
 
#启用访问日志
server.tomcat.accesslog.enabled = true
 
#配置参数,如附加到日志文件的目录名,前缀,后缀和日期格式
server.tomcat.accesslog.directory=logs
server.tomcat.accesslog.file-date-format=yyyy-MM-dd
server.tomcat.accesslog.prefix=access_log
server.tomcat.accesslog.suffix=.log

4.3 替换Tomcat

4.3.2 替换为Jetty

(1)改Maven依赖

排除Tomcat依赖:首先,你需要在pom.xml文件中的spring-boot-starter-web依赖里排除Tomcat。这可以通过<exclusions>标签实现。

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

添加Jetty依赖:接下来,在pom.xml中添加Jetty的起步依赖。

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

配置文件调整(可选) 虽然通常情况下仅上述步骤就足够了,但如果你需要对Jetty进行额外的配置,可以在application.properties中添加相应的配置项。例如,调整端口:

# 端口配置
server.port=8081

# 启动线程数
server.jetty.acceptors=2

# Selector线程数
server.jetty.selectors=4

# 访问日志配置
server.jetty.accesslog.enabled=true
server.jetty.accesslog.filename=access.log
server.jetty.accesslog.file-date-format=.yyyy-MM-dd

# SSL/TLS配置
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-type=PKCS12
server.ssl.key-store-password=changeit
server.ssl.keyAlias=tomcat

# 请求和响应缓冲区大小
server.jetty.max-http-header-size=10KB
server.jetty.max-http-form-post-size=20MB

4.3.2 替换为Undertow

(1)依赖处理

先排除Tomcat依赖 ,然后引入undertow依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
	<exclusions>
		<exclusion>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
		</exclusion>
	</exclusions>
</dependency>
 <dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

(2)yml的配置项

server:
  # 服务器的HTTP端口,默认为80
  port: 80
  servlet:
    # 应用的访问路径
    context-path: /
  # undertow 配置
  undertow:
    # HTTP post内容的最大大小。当值为-1时,默认值为大小是无限的
    max-http-post-size: -1
    # 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
    # 每块buffer的空间大小,越小的空间被利用越充分
    buffer-size: 512
    # 是否分配的直接内存
    direct-buffers: true
    threads:
      # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
      io: 8
      # 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
      worker: 256

4.4 SSL配置

通过HTTP协议传输数据,并不会对数据进行加密,所以存在着一定的风险,容易被抓包破解数据,而且现在各种浏览器对使用HTTP协议的网站也会提示不安全。

通过将HTTP协议升级为HTTPS协议可以提高安全系数。使用HTTPS协议就需要了解一下SSL协议。

SSL(Secure Sockets Layer 安全套接字协议),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。

TLS与SSL在传输层与应用层之间对网络连接进行加密。

SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。

SSL协议可分为两层:

  • SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。
  • SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。

服务器认证阶段:

1)客户端向服务器发送一个开始信息“Hello”以便开始一个新的会话连接;

2)服务器根据客户的信息确定是否需要生成新的主密钥,如需要则服务器在响应客户的“Hello”信息时将包含生成主密钥所需的信息;

3)客户根据收到的服务器响应信息,产生一个主密钥,并用服务器的公开密钥加密后传给服务器;

4)服务器恢复该主密钥,并返回给客户一个用主密钥认证的信息,以此让客户认证服务器。

用户认证阶段:

  • 在此之前,服务器已经通过了客户认证,这一阶段主要完成对客户的认证。
  • 经认证的服务器发送一个提问给客户,客户则返回(数字)签名后的提问和其公开密钥,从而向服务器提供认证。

SSL协议提供的安全通道有以下三个特性:

  • 机密性:SSL协议使用密钥加密通信数据。
  • 可靠性:服务器和客户都会被认证,客户的认证是可选的。
  • 完整性:SSL协议会对传送的数据进行完整性检查。

从SSL 协议所提供的服务及其工作流程可以看出,SSL协议运行的基础是商家对消费者信息保密的承诺,这就有利于商家而不利于消费者。

4.4.1 配置证书

keytool -genkeypair -alias tomcat -keyalg RSA -keystore tomcat.key

依次填入以下内容:

mcat.key
输入密钥库口令:
再次输入新口令:
您的名字与姓氏是什么?
  [Unknown]:  localhost
您的组织单位名称是什么?
  [Unknown]:  localhost
您的组织名称是什么?
  [Unknown]:  xxx Co,.Ltd
您所在的城市或区域名称是什么?
  [Unknown]:  KunShan
您所在的省/市/自治区名称是什么?
  [Unknown]:  SuZhou
该单位的双字母国家/地区代码是什么?
  [Unknown]:  China
CN=localhost, OU=localhost, O="xxxCo,.Ltd", L=KunShan, ST=SuZhou, C=Chin
a是否正确?
  [否]:y

输入 <tomcat> 的密钥口令
        (如果和密钥库口令相同, 按回车):
再次输入新口令:

把生成的证书放入 resources目录

4.4.2 SpringBoot配置SSL

配置application.yml

server:
  port: 8110
  tomcat:
    max-threads: 800
    accept-count: 30000
    min-spare-threads: 20
    max-connections: 30000
  ssl:
    key-store: classpath:tomcat.key
    key-store-type: JKS
    key-alias: tomcat
    #证书密码
    key-store-password: xxxx

新增一个组件类

@Component
public class CustomContainer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {

    @Value("${server.port}")
    int serverPort;

    @Override
    public void customize(ConfigurableServletWebServerFactory factory) {
        factory.setPort(serverPort);
    }
}

4.4.3 http转向https

当用户使用http访问的时候,将http协议重定向到https端口

(1)修改配置文件

custom:  # 自定义http启动端口
  http-port: 8089
配置
server:
  port: 8090 #端口配置  
  ssl: #ssl配置
    enabled: true  # 默认为true
    #key-alias: alias-key # 别名(可以不进行配置)
    # 保存SSL证书的秘钥库的路径
    key-store: classpath:ssl/service.一级域名.jks
    key-password: 私钥密码
    #key-store-password: 证书密码
    key-store-type: JKS

(2)添加配置类

package cn.zlc.servicehttps.config;

import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * https配置,将http请求全部转发到https
 * @author Jacob
 */
@Configuration
public class HttpsConfig {

    @Value("${custom.http-port: 8080}")
    private Integer httpPort;

    @Value("${server.port}")
    private Integer port;

    @Bean
    public TomcatServletWebServerFactory servletContainer() {
        // 将http请求转换为https请求
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint constraint = new SecurityConstraint();
                // 默认为NONE
                constraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                // 所有的东西都https
                collection.addPattern("/*");
                constraint.addCollection(collection);
                context.addConstraint(constraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(httpConnector());
        return tomcat;
    }

    /**
     * 强制将所有的http请求转发到https
     * @return httpConnector
     */
    @Bean
    public Connector httpConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        // connector监听的http端口号
        connector.setPort(httpPort);
        connector.setSecure(false);
        // 监听到http的端口号后转向到的https的端口号
        connector.setRedirectPort(port);
        return connector;
    }
}

4.5 Favicon配置

4.5.1 默认的Favicon

Spring Boot提供了一个默认的Favicon,每次访问应用的时候都能看到,如图所示。



4.5.2 关闭Favicon

我们可以在application.properties中设置关闭Favicon,默认为开启。

spring.mvc.favicon.enabled=false

4.5.3 设置自己的Favicon

若需要设置自己的Favicon,则只需将自己的favicon.ico(文件名不能变动)文件放置在类路径根目录、类路径META-INF/resources/下、类路径resources/下、类路径static/下或类路径public/下。这里将favicon.ico放置在src/main/resources/static下。

注意:配置文件不要配置spring.mvc.static-path-pattern参数,否则不能看到Favicon图标

4.6 WebSocket

4.6.1 什么是WebSocket?

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,它允许在浏览器和服务器之间进行实时的、双向的通信。相对于传统的基于请求和响应的 HTTP 协议,WebSocket 提供了一种更有效、更实时的通信方式,适用于需要实时更新、实时通知和实时交互的应用。

WebSocket 的一些关键特点包括:

  1. 全双工通信: WebSocket 允许服务器和客户端在同一连接上同时进行双向通信。这意味着服务器可以随时向客户端推送数据,而不必等待客户端发送请求。
  2. 持久连接: WebSocket 连接一旦建立,会一直保持打开状态,不会像传统的 HTTP 连接那样在每次请求和响应之后关闭。这减少了每次连接建立和关闭的开销,使通信更加高效。
  3. 低延迟: 由于连接保持打开状态,WebSocket 通信具有较低的延迟,适用于实时性要求较高的应用,如实时聊天、实时数据更新等。
  4. 少量的数据交换: 与 HTTP 请求和响应相比,WebSocket 数据交换的开销较小。WebSocket 的帧头相对较小,因此有效载荷的比例更高。
  5. 兼容性: 现代浏览器和大多数服务器支持 WebSocket。此外,WebSocket 协议还定义了一个子协议 STOMP(Streaming Text Oriented Messaging Protocol),用于更高级的消息传递和订阅功能。
  6. 安全性: 与其他网络通信协议一样,WebSocket 通信也需要一些安全性的考虑。可以使用加密协议(如 TLS)来保护数据在网络传输中的安全性。

4.6.2 代码实战

(1)SpringBoot导入依赖

在pom.xml中导入以下依赖,版本由SpringBoot管理

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

(2)创建配置类

创建WebSocketConfig配置类,并将其注入到Bean容器中

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
 
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

(3)创建WebSocketServer类

创建WebSocketServer类,并将其注入到Bean容器中

注意:@ServerEndpoint("/WebSocket"),该注解用于配置建立WebSocket连接的路径,可以按需修改。

该类一般拥有以下功能:

  1. WebSocket 端点注册: WebSocket 服务器需要注册一个或多个 WebSocket 端点(Endpoints)。每个端点对应一种处理逻辑,可以处理客户端发送过来的消息,以及向客户端发送消息。这些端点通过注解或配置来定义。
  2. 建立和维护连接: WebSocket 服务器负责监听客户端的连接请求,一旦有客户端连接,服务器会创建一个 WebSocket 会话(Session)来管理这个连接。服务器需要能够维护这些连接,包括打开、关闭、保持心跳等操作。
  3. 消息处理: 一旦客户端连接成功,WebSocket 服务器需要处理客户端发送过来的消息。这可以在 WebSocket 端点中的方法上定义处理逻辑。服务器可以根据不同的业务需求处理不同类型的消息。
  4. 处理异常: 与任何网络通信一样,WebSocket 连接可能会面临各种异常情况,如断开连接、网络问题等。WebSocket 服务器需要能够处理这些异常情况,进行适当的清理和处理。

可以将该类理解为WebSocket生命周期中会调用的方法。

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
 
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
 
@Slf4j
@Component
@ServerEndpoint("/WebSocket")
public class WebSocketServer {
 
    private Session session;
 
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        WebSocketManager.sentToUser(session, "WebSocket is connected!");
        WebSocketManager.addWebSocketServer(this);
        log.info("与SessionId:{}建立连接", session.getId());
    }
 
    @OnClose
    public void onClose() {
        WebSocketManager.removeWebSocketServer(this);
        log.info("WebSocket连接关闭");
    }
 
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("来自SessionId:{}的消息:{}", session.getId(), message);
    }
 
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("Session:{}的WebSocket发生错误", session.getId(), error);
    }
 
    public Session getSession() {
        return session;
    }
 
    public String getSessionId() {
        return session.getId();
    }
}

(4)创建WebSocketServer管理类

该类用于管理WebSocketServer(其实主要是管理Session),如果不需要发送消息给特定用户,那么无需创建该类,在WebSocketServer类中维护一个类变量即可。

import lombok.extern.slf4j.Slf4j;
 
import javax.websocket.Session;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
 
@Slf4j
public class WebSocketManager {
 
    private final static CopyOnWriteArraySet<WebSocketServer> webSocketServerSet = new CopyOnWriteArraySet<>();
 
    private final static ConcurrentHashMap<String, WebSocketServer> webSocketServerMap = new ConcurrentHashMap<>();
 
    public static void addWebSocketServer(WebSocketServer webSocketServer){
        if (webSocketServer != null){
            webSocketServerSet.add(webSocketServer);
            webSocketServerMap.put(webSocketServer.getSessionId(), webSocketServer);
        }
    }
 
    public static void removeWebSocketServer(WebSocketServer webSocketServer){
        webSocketServerSet.remove(webSocketServer);
        webSocketServerMap.remove(webSocketServer.getSessionId());
    }
 
    /**
     * 通过SessionId发送消息给特定用户
     * @param
     * @param msg
     */
    public static void sentToUser(String sessionId, String msg){
        Session session = webSocketServerMap.get(sessionId).getSession();
        sentToUser(session, msg);
    }
 
    /**
     * 通过Session发送消息给特定用户
     * @param session
     * @param msg
     */
    public static void sentToUser(Session session, String msg){
        if (session == null){
            log.error("不存在该Session,无法发送消息");
            return;
        }
        session.getAsyncRemote().sendText(msg);
    }
 
    /**
     * 发送消息给所有用户
     * @param msg
     */
    public static void sentToAllUser(String msg){
        for (WebSocketServer webSocketServer : webSocketServerSet) {
            sentToUser(webSocketServer.getSession(), msg);
        }
        log.info("向所有用户发送WebSocket消息完毕,消息:{}", msg);
    }
}

(5)前端代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>websocket通讯</title>
</head>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
    let socket;
    function openSocket() {
 
        const socketUrl = "ws://localhost:9091/WebSocket/";
        console.log(socketUrl);
        if(socket!=null){
            socket.close();
            socket=null;
        }
        socket = new WebSocket(socketUrl);
        //打开事件
        socket.onopen = function() {
            console.log("websocket已打开");
        };
        //获得消息事件
        socket.onmessage = function(msg) {
            console.log(msg.data);
            //发现消息进入,开始处理前端触发逻辑
        };
        //关闭事件
        socket.onclose = function() {
            console.log("websocket已关闭");
        };
        //发生了错误事件
        socket.onerror = function() {
            console.log("websocket发生了错误");
        }
    }
    function sendMessage() {
 
        socket.send('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}');
        console.log('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}');
    }
</script>
<body>
<p>【socket开启者的ID信息】:<div><input id="userId" name="userId" type="text" value="10"></div>
<p>【客户端向服务器发送的内容】:<div><input id="toUserId" name="toUserId" type="text" value="20">
    <input id="contentText" name="contentText" type="text" value="hello websocket"></div>
<p>【操作】:<div><a onclick="openSocket()">开启socket</a></div>
<p>【操作】:<div><a onclick="sendMessage()">发送消息</a></div>
</body>
 
</html>

5 基于Bootstarp和AngularJS的现代Web应用

现代的B/S系统软件有下面几个特色。

1.单页面应用 单页面应用(single-page application,简称SPA)指的是一种类似于原生客户端软件的更流畅的用户体验的页面。在单页面的应用中,所有的资源(HTML、Javascript、CSS)都是按需动态加载到页面上的,且不需要服务端控制页面的转向。

2.响应式设计 响应式设计(Responsive web design,简称RWD)指的是不同的设备(电脑、平板、手机)访问相同的页面的时候,得到不同的页面视图,而得到的视图是适应当前屏幕的。当然就算在电脑上,我们通过拖动浏览器窗口的大小, 也通用得到合适的视图。

3.数据导向 数据导向是对于页面导向而言的,页面上的数据获得是通过消费后台的REST服务来实现的,而不是通过服务器渲染的动态页面(如JSP)来实现的,一般数据交换使用的格式是JSON。 本节将针对Bootstrap 和 AngularJS 进行快速入门式的引导,如需深入学习,请参考官网或相关专题书籍。

5.1 Bootstrap

1.什么是Bootstrap Bootstrap官方定义:Bootstrap是开发响应式和移动优先的Web应用的最流行的HTML、CSS、JavaScript框架。

2.下载并引入Bootstrap 下载地址:http://getbootstrap.com/getting-started/, 如图

下载的压缩包的目录结构如图

css
fonts
js

最简单的Bootstrap页面模板如下:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1">
<!-- 上面3个meta标签必须是head 的头三个标签,其余的head内标签在此3个之后 -->
<title>Bootstrap基本模板</title>

<!-- Bootstrap的CSS -->
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">

<!-- HTML5 shim and Respond.js 用来让IE 8 支持 HTML 5 元素和媒体查询 -->
	<!-- [if lt IE 9]>
		<script src="js/html5shiv.min.js"></script>
		<script src="js/respond.min.js"></script>
	<[endif]-->
</head>
<body>
	<h1>你好,Bootstrap</h1>
	
	<!-- Jquery是Bootstrap脚本插件必需的 -->
	<script src=js/jquery.min.js></script>
	<!-- 包含所有编译的插件 -->
	<script src="bootstrap/js/bootstrap.min.js"></script>
</body>
</html>

3.CSS支持 Bootstrap的CSS样式为基础的HTML元素提供了美观的样式,此外还提供了一个高级的网格系统用来做页面布局。

(1)布局网格 在Bootstrap里,行使用的样式为row,列使用col-md-数字,此数字范围为1~12,所有列加起来的和也是12,代码如下:

<div class="row">
	<div class="col-md-1">。col-md-1</div>
	<div class="col-md-1">。col-md-1</div>
	<div class="col-md-1">。col-md-1</div>
	<div class="col-md-1">。col-md-1</div>
	<div class="col-md-1">。col-md-1</div>
	<div class="col-md-1">。col-md-1</div>
	<div class="col-md-1">。col-md-1</div>
	<div class="col-md-1">。col-md-1</div>
	<div class="col-md-1">。col-md-1</div>
	<div class="col-md-1">。col-md-1</div>
	<div class="col-md-1">。col-md-1</div>
	<div class="col-md-1">。col-md-1</div>
</div>
<div class="row">
	<div class="col-md-8">.col-md-8</div>
	<div class="col-md-4">.col-md-4</div>
</div>
<div>
	<div class="col-md-4">.col-md-4</div>
	<div class="col-md-4">.col-md-4</div>
	<div class="col-md-4">.col-md-4</div>
</div>
<div>
	<div class="col-md-6">.col-md-6</div>
	<div class="col-md-6">.col-md-6</div>
</div>

(2)html元素

Bootsrtap为html元素提供了大量的样式,如表单元素、按钮、图标等。更多内容请查看:http://getbootstrap.com/css/。

4.页面组件支持 Bootstrap为我们提供了大量的页面组件,包括字体图标、下拉框、导航条、进度条、缩略图等,更多请阅读http://getboostrap.com/components/。

5.javascript支持 Bootstrap为我们提供了大量的JavaScript插件,包含模式对话框、标签页、提示、警告等,更多内容请查看http://getbootstrap.com/javascript/。

5.2 AngularJS

1.什么是AngularJS AugularJS官方定义:AngularJS是HTML开发本应该的样子,它是用来设计开发Web应用的。 AngularJS使用声明式模板+数据绑定(类似于JSP、Thymeleaf)、MVW(Model-View——Whatever)、MVVM(Model-View-ViewModel)、MVC(Model-View-Controller)、依赖注入和测试,但是这一切的实现却只借助纯客户端的JavaScript。 HTML一般是用来声明静态页面的,但是通常情况下我们希望页面是基于数据动态生成的,这也是我们很多服务端模板引擎出现的原因;而AngularJS可以只通过前端技术就能实现动态的页面。

2.下载并引入AngularJS AngularJS下载地址:https://code.angularjs.org/ 最简单的AngularJS页面

<!DOCTYPE html>
<html ng-app> <!-- ng-app所作用的范围是AngularJS起效的范围,本例是整个页面有效。 -->
<head>
<sctipt src="js/angular.min.js"></sctipt>  <!-- 载入AngularJS的 脚本 -->
</head>
<body>
<div>
	<label>名字:</label>
	<input type="text" ng-model="yourName" placeholder="输入你的名字"> <!-- ng-model定义整个AngularJS的前端数据模型,模型的名称为yourName,模型的值来自你输入的值若输入的值改变,则数据模型值也会变 -->
	<hr>
	<h1>你好{{yourName}}!</h1><!-- 使用{{模型名}}来读取模型中的值。 -->
</div>
</body>
</html>

3.模块、控制器和数据绑定

我们对MVC的概念已经烂熟于心了,但是平时的MVC都是服务端的MVC,这里用AngularJS实现了纯页面端MVC,即实现了视图模板、数据模型、代码控制的分离。 再来看看数据绑定,数据绑定是将视图和数据模型绑定在一起。如果视图变了,则模型的值就变了;如果模型值变了,则视图也会跟着改变。 AngularJS为了分离代码达到复用的效果,提供了一个module(模块)。定义一个模块需使用下面的代码。

无依赖模块:

angular.module('firstModule',[]);

有依赖模块

angular.module('firstModule',['moduleA','moduleB']);

我们看到了V就是我们的页面元素,M就是我们的ng-model,那C呢?我们可以通过下面的代码来定义控制器,页面使用ng-controller来和其关联:

augular.module('firstModule',[])
	.controller('firstController',funtion(){
	...
	};
);

<div ng-controller="firstController">
...
</div>

4.Scope和Event

(1)Scope Scope是AngularJS的内置对象,用$Scope来获得。在Scope中定义的数据是数据模型,可以通过{{模型名}}在视图上获得。Scope主要是在编码中需要对数据模型进行处理的时候使用,Scope的作用范围与在页面声明的范围一致(如在controller内使用,scope的作用范围是页面声明ng-controller标签元素的作用范围)。

定义:

$scope.greeting='Hello'

获取

{{greeting}}

(2)Event

因为Scope的作用范围不同,所以不同的Scope之间若要交互的话需要通过事件(Event)来完成。 1)冒泡事件(Emit)冒泡事件负责从子Scope向上发送事件,示例如下。 子Scope发送:

$scope.$emit('EVENT_NAME_EMIT','message');

父Scope接受:

$scope.$on(''EVENT_NAME_EMIT',function(event,data){
	....
})

2)广播事件(Broadcast)。广播事件负责从父Scope向下发送事件,示例如下。 父Scope发送:

$scope.$broadcast('EVENT_NAME_BROAD','message');

子scope接受

$scope.$on(''EVENT_NAME_BROAD',function(event,data){
...
})

5.多视图和路由

多视图和路由是AngularJS实现单页面应用的技术关键,AngularJS内置了一个$routeProvider对象来负责页面加载和页面路由转向。 需要注意的是,1.2.0之后的AngularJS将路由功能移出,所以使用路由功能要另外引入angular-route.js 例如

angular.module('firstModule').config(function($routeProvider){
$routeProvider.when('/view1,{  //此处定义的是某个页面的路由名称
	controller:'Controller1',   //此处定义的是当前页面使用的控制器。
	templateUrl:'view1.html',  //此处定义的要加载的真实页面
}).when('/view2',{
	controller:'Controller2',
	templateUrl:'view2.html',
	});
})

在页面上可以用下面代码来使用我们定义的路由

<ul>
	<li><a href="#/view1">view1</a></li>
	<li><a href="#/view2">view2</a></li>
</ul>
<ng-view></ng-view>  <!--此处为加载进来的页面显示的位置  -->

依赖注入 依赖注入是AngularJS的一大酷炫功能。可以实现对代码的解耦,在代码里可以注入AngularJS的对象或者我们自定义的对象。下面示例是在控制器中注入$scope,注意使用依赖注入的代码格式。

angular.module('firstModule')
	.controller("diController",['$scope',
		function($scope){
				...
			}]);

7.Service和Factory

AngularJS为我们内置了一些服务,如$location、$time、$rootScope 。很多时候我们需要自己定制一些服务,AngularJS为我们提供了Service和Factory。 Service和Factory的区别是:使用Service的话,AngularJS会使用new来初始化对象;而使用Factory会直接获得对象。 (1)Service

定义:

angular.module('firstModule').service('helloService',function(){
	this.sayHello=function(name){
		alert('Hello '+name);
	}
});

注入调用:

angular.module('firstModule'
	.controller("diController",['$scope','helloService',
		function($scope,helloService){
			helloService.sayHello('lmz');
	}]);

(2)Factory

定义:

angular.module('firstModule').service('helloFactory',function(){
	return{
	sayHello:function(name){
		alert('Hello ' + name);
		}
	}
});

注入调用:

angular.module('firstModule')
	.controller("diController",['$scope', 'helloFactory',
		function($scope , helloFactory) {
		 	helloFactory.sayHelle('lmz');
		 }]);

8.http操作

AngularJS内置了$http对象用来进行Ajax的操作:

$http.get(url)
$http.post(url,data)
$http.put(url,data)
$http.delete(url)
$http.head(url)

9.自定义指令

AngularJS内置了大量的指令(directive),如ng-repeat、ng-show、ng-model等。即使用一个简短的指令可实现一个前端组件。 比方说,有一个日期的js/jQuery插件,使用AngularJS封装后,在页面上调用此插件可以通过指令来实现,例如:

元素指令:<date-picker></date-picker>
属性指令:<input type="text" date-picker/>
样式指令:<input type="text" class="date-picker"/>
注释指令:<!--directive:date-picker -->

定义指令:

angular.module('myApp',[]).directive('helloWorld',function(){
return {
	restrict:'AE',  //支持使用属性、元素
	replace:true,
	template:'<h3>Hello,World!</h3>
};
});

调用指令,元素标签:

<hello-world/>

<hello:world/>

或者属性方式

<div hello-world />

5.3 实战

在前面两节我们快速介绍了Bootstrap和AngularJS,本节我人将它们和Spring Boot串起来做个例子。 在例子中,我们使用Bootstrap制作导航使用AngularJS实现导航切换页面的路由功能,并演示AngularJS通过$http服务和Spring Boot提供的REST服务,最后演示用指令封装jQuery UI的日期选择器。

1.新建Spring Boot项目

初始化一个Spring Boot项目,依赖只需选择Web 。

准备Bootstrap、AngularJS、jQuery、jQueryUI相关的资源到 src/main/resources/static 下,结构如图



另外要说明的是,本例的页面都是静态页面,所以全部放置在/static目录下。

2.制作导航

页面位置:src/main/resources/static/action.html:

<!DOCTYPE html>
<html lang="zh-cn" ng-app="actionApp">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>实战</title>

<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="jqueryui/jquery-ui.min.css" rel="sylesheet">
<style type="text/css">

.content{
	padding:100px 15px;
	text-align: center;
}
</style>

<!--[if lt IE 9]>
	<script src="js/html5shiv.min.js"></script>
	<script src="js/respond.min.js"></scripte>
	<![endif]-->
</head>
<body>
<!-- 使用Bootstrap定义的导航,并配合AngularJS的路由,通过路由名称#/oper和#/directive切换视图 -->
	<nav class="navbar navbar-inverse navbar-fixed-top">
		<div class="container">
			<div id="navbar" class="collapse navbar-collapse">
				<ul class=nav navbar-nav>
					<li><a href="#/oper">后台交互</a>
					<li><a href="#/directive">自定义指令</a></li>
				</ul>
			</div>
		</div>
	</nav>
	
	<!-- 通过<ng-view></ng-view>展示载入的页面 -->
	<div class="content">
		<ng-view></ng-view>
	</div>
	
	<!-- 加载本例所需的脚本,其中jquery-ui.min.js的脚本是为我们定制指令所用;app.js定义AngularJS的模块和路由;directives.js为自定义的指令;controllers.js是控制器定义之处 -->
	<script src="js/jquery.min.js"></script>
	<script src="jqueryui/jquery-ui.min.js"></script>
	<script src="bootstrap/js/bootstrap.min.js"></script>
	<script src="js/angular.min.js"></script>
	<script src="js/angular-route.min.js"></script>
	<script src="js-action/app.js"></script>
	<script src="js-action/directives.js"></script>
	<script src="js-action/controllers.js"></script>
</body>
</html>

3.模块和路由定义

页面位置: src/main/resources/static/js-action/app.js:

var actionApp = angular.module('actionApp',['ngRoute']);  //定义模块actionApp,并依赖于路由模块ngRout。

actionApp.config(['$routeProvider'] , function($routeProvider){  //配置路由,并注入$routeProvider来配置
	$routeProvider.when('/oper',{        //  /oper为路由名称
		controller:'View1Controller',     //controller定义的是路由的控制器名称
		templateUrl:'views/view1.html',    //templateUrl定义的是视图的真正地址
	}).when('/directive',{
		controller:'View2Controller',
		templateUrl:'views/view.html',
	});
});

控制器定义 脚本位置: src/main/resources/static/js-action/controllers.js

//定义控制器View1Controller,并注入$rootScope、$scope和$http。
actionApp.controller('View1Controller',['$rootScope','$scope','$http',
function($rootScope,$scope,$http){
	//使用$scope.$on监听$viewContentLoaded事件,可以在页面内容加载完成后进行一些操作。
	$scope.$on('$viewContentLoaded',function(){
		console.log('页面加载完成');
	});
	//这段代码是核心 代码,请结合下面的View1的界面一起理解
	$scope.search=function(){  //在scope内定义一个方法search,在页面上通过ng-click调用。
		personName = $scope.personName;        //通过$scope.personName获取页面定义的ng-model = "personName" 的值。
		$http.get('search',{                 //使用$http.get向服务器地址search发送get请求。
			  		params:{personName:personName}   //使用params增加请求参数
		}).success(function(data){                   //用success方法作为请求成功后的回调。
			$scope.person=data;                     //将服务端返回的数据data通过$scope.person赋给模型person,这样页面视图上可以通过{{person.name}}、{{person.age}}、{{person.address}}来调用,且模型person值改变后,视图是自动更新的
		});
	};
}]);

actionApp.controller('View2Controller',['$rootScope','$scope',function($rootScope,$scope){
	$scope.$on('$viewContentLoaded',function(){
		console.log('页面加载完成');
	});
}]);

5.View1的界面(演示与服务端交互) 页面位置 src/main/resources/static/views/view1.html

<div class="row">
	<label for="attr" class="col-md-2 control-label">名称</label>
	<div class="col-md-2">
		<!-- 定义数据模型 ng-model="personName" -->
		<input type="text" class="form-control" ng-model="personName">
	</div>
	<div class="col-md-1">
	<!-- 通过ng-click="search()"调用控制器中定义的方法 -->
	<button class="btn btn-primary" ng-click="search()">查询</button>
	</div>
</div>

<div class="row">
	<div class="col-md-4">
		<ul class="list-group">
			<li class="list-group-item">名字:{{person.name}}
			<li class="list-group-item">年龄:{{person.age}}
			<li class="list-group-item">地址:{{person.address}}
		</ul>
	</div>
</div>

6.服务端代码

传值对象Javabean:

public class Person {
	private String name;
	private Integer age;
	private String address;
	
	public Person() {
		super();
	}
	
	public Person(String name,Integer age,String address) {
		super();
		this.name=name;
		this.age=age;
		this.address=address;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}
	
	

}

控制器:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@SpringBootApplication
public class Ch77Application {
	
	@RequestMapping(value="/search",produces= {MediaType.APPLICATION_JSON_VALUE})
	public Person search(String personName) {
		return new Person(personName,32,"shenzhen");
	}

	public static void main(String[] args) {
		SpringApplication.run(Ch77Application.class, args);
	}

}

7.自定义指令

脚本位置: src/main/resources/static/js-action/directives.js:

actionApp.directive('datePicker',function(){  //定义一个指令名为datePicker。
	return{
		restrict:'AC',   //限制为属性指令和样式指令。
		link:function(scope,elem,attrs){   //使用link方法来定义指令,在Link方法内可使用当前scope、当前元素及元素属性。
			elem.datepicher();				//初始化jqueryui的datePicker(jquery的写法是$('#id').datePicker()).
		}
	};
});

通过上面的代码我们就定制了一个封装jqueryui的datePicker的指令,本例只是为了演示的目的,主流的脚本框架已经被很多人封装过了,有兴趣的读者可以访问http://ngmodules.org/网站,这个网站包含了大量的AngularJS的第三方模块、插件和指令。

8.View2的页面(演示自定义指令)

页面地址: src/main/resources/static/views/view2.html:

<div class="row">
    <label for="arrt" class="col-md-2 control-label">属性形式</label>
    <div class="col-md-2">
        <!-- 使用属性形式调用指令 -->
        <input type="text" class="form-control" date-picker>
    </div>
</div>

<div class="row">
    <label for="style" class="col-md-2 control-label">样式形式</label>
    <div class="col-md-2">
        <!-- 使用样式形式调用指令 -->
        <input type="text" class="form-control date-picker"
    </div>
</div>

9.运行

菜单及路由切换如图



与后台交互如图

自定义指定如图

TML5大前端是由新的标记引进的新元素形式和为现有元素新增的某些属性,与新的JavaScript APIs的结合体。那么HTML5新增加了哪些新标签与JavaScript API结合体以及具体作用有哪些呢?以下是最常用的几种:

1、Canvas API是一个具有完整功能的JavaScript API并伴随产生了新HTML5元素。通过Canvas API,利用它和WebGL在浏览器中创建一个2 D或3 D绘图场景;

2、Contacts API主要应用在移动设备上,为浏览器提供对用户通用通讯录的访问。它在浏览器内建立一个本地存储库,来存储联系人信息。Contacts API将允许您有本地存储库,网站可以通过本地存储库访问存储的联系人信息。现在的主流浏览器都支持Contacts API;

3、通过File API 浏览器可以直接访问用户计算机的沙箱区域,将数据存储到文件系统;

4、在HTML5中Forms API得到了发展,内置了验证功能;

5、允许浏览器请求用户的位置信息,一旦获权,浏览器通过许多不同的方法来确定计算机或设备的实际位置,它将会有一个比例尺来确认精确的地点位置。通过该API能获取经纬度等数据,非常适合应用程序定位;

6、Media Capture的功能是将本地设备通过JavaScript将与浏览器相连接;

7、Messaging API被用来与其他API一起使用;

8、选择(Selection)API的就像jQuery库一样,运用非常广泛;

9、 Server-Sent Events API:一个网页获取新的数据通常需要发送一个请求到服务器,也就是向服务器请求的页面。使用Server-Sent Events API,服务器可以在任何时刻向Web页面推送数据和信息,这些被推送进来的信息可以在这个页面上作为事件/数据来处理;

10、 Web Notifications API即Web消息提醒,它可以使页面发出通知,通知将被显示在页面之外的系统层面上(通常使用操作系统的标准通知机制,但是在不同的平台和浏览器上的表现会有差异);

11、Web Sockets API:Web Sockets是一种基ws协议的技术,它使得建立全双工连接成为可能。Websocket常见于浏览器中,但是这个协议不受使用平台的限制,允许收发信息到服务器端。

以上是HTML5大前端中新加入的一些比较常用的功能API,如果想要系统的了解以及学习HTML5的新功能,可以选择千锋重庆校区的HTML5大前端课程。其课程将一线互联网企业前沿技术迁移课堂,让学员通过深度学习,切实掌握实战技术,助力学员开启成功职场生涯。