Spring Boot 的 Web 开发

web 开发是开发中至关重要的一环,web 开发的核心内容包括内嵌 servlet 容器和 spring MVC。
1.springboot 的 web 开发支持

    springboot 提供了 spring-boot-starter-web 为 web 开发予以支持,spring-boot-starter-web 为我们提供了嵌入的 Tomcat 以及 Spring MVC 的依赖。而 web 相关的自动配置存储在 spring-boot-autoconfigure.jar 和 org.springframework.boot.web 下。

2.Thymeleaf 模板引擎

    尽可能的少用 JSP,因为在内嵌 Servlet 容器上 JSP 运行有点问题(内嵌 Tomcat、jetty 不支持以 jar 形式运行的 JSP,Undertow 不支持 JSP)。

    springboot 提供了大量的模板引擎,包括 FreeMark、Groovy、Thymeleaf、Velocity 和 Mustache,Spring Boot  中推荐使用 Thymeleaf 作为模板引擎,因为 Thymeleaf 提供了完美的 Spring MVC  的支持。

2.1 Thymeleaf 基础知识

    Thymeleaf 是一个 Java 类库,它是一个 xml/xhtml/html5 的模板引擎,可以作为 MVC 的 Web 应用的 VIEW 层。

    Thymeleaf 还提供了额外的模块与 Spring MVC  集成,所以我们可以使用 Thymeleaf 完全的替代 JSP。

    详见:http://www.thymeleaf.org

2.2 与 Spring MVC 集成

    在 springmvc 中,若我们需要集成一个模板引擎的话,需要定义 ViewResolver,而 ViewResolver 需要定义一个 View ,定义前缀后缀。Thymeleaf 为我们提供的相关的驱动。

    

以上为默认提供的配置。

下面示例一个简单的例子:

package com.pangu.demo;

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

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import com.pangu.demo.web.entity.Person;

@Controller
@SpringBootApplication
public class WebApplication {
	public static void main(String[] args) {
		SpringApplication.run(WebApplication.class, args);
	}
	@RequestMapping("/thy")
	public String thymeleaf(Model model){
		Person person = new Person("etfox", 22);
		
		List<Person> people = new ArrayList<Person>();
		Person person1 = new Person("etfox1", 22);
		Person person2 = new Person("etfox2", 22);
		Person person3 = new Person("etfox3", 22);
		
		people.add(person1);
		people.add(person2);
		people.add(person3);
		
		model.addAttribute("singlePerson", person);
		model.addAttribute("people", people);
		
		return "index";
	}
	
	@RequestMapping(value = "/json",produces={MediaType.APPLICATION_JSON_VALUE})
	public String json(Model model) {
		Person single = new Person("aa",11);
		model.addAttribute("single", single);
		return "jsonView";
	}
	
	@Bean
	public MappingJackson2JsonView jsonView() {
		MappingJackson2JsonView jsonView = new MappingJackson2JsonView();
		return jsonView;
	}
	
}

index.jsp:

<html xmlns:th="http://www.thymeleaf.org">
  <head>
  	 <meta content="text/html;charset=UTF-8"/>
  	 <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
     <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <link th:href="@{bootstrap/css/bootstrap.min.css}" rel="stylesheet"/> 
    <link th:href="@{bootstrap/css/bootstrap-theme.min.css}" rel="stylesheet"/>
  </head>
  <body>
  
  <div class="panel panel-primary">
    <div class="panel-heading">
        <h3 class="panel-title">访问model</h3>
    </div>
    <div class="panel-body">
        	<span th:text="${singlePerson.name}"></span> 
    </div>
  </div>
  
  <div th:if="${not #lists.isEmpty(people)}">
	  <div class="panel panel-primary">
	    <div class="panel-heading">
	        <h3 class="panel-title">列表</h3>
	    </div>
	    <div class="panel-body">
	        <ul class="list-group">
				<li class="list-group-item" th:each="person:${people}">
				    <span th:text="${person.name}"></span>
				   	<span th:text="${person.age}"></span>
				   	<button class="btn" th:οnclick="'getName(\'' + ${person.name} + '\');'">获得名字</button>
				</li>
	        </ul>
	    </div>
	 </div>
 </div>
  
  <script th:src="@{jquery.min.js}" type="text/javascript"></script><!-- 2 -->
  <script th:src="@{bootstrap/js/bootstrap.min.js}"></script><!-- 2 -->
  
  <script th:inline="javascript">
  	var single = [[${singlePerson}]];
  	console.log(single.name+"/"+single.age)
  	
  	function getName(name){
  		console.log(name);
  	}
  </script>
  
  </body>
 </html>

项目结构:



run。。。。。。。。。。。。。。。。



后记:SB 在自定义拦截器之后,之前的默认配置将不再生效,也就是说你配置的默认的静态路径啥的,刚碰到的坑!!!!!


3.Web 相关配置
3.1:Spring Boot 提供的自动配置

    通过查看 WebMvcAutoConfiguration  及 WebMvcProperties 的源码,可以发现 Spring Boot  为我们提供了如下的自动配置。

3.1.1 自动配置的 ViewResolver

    (1).ContentNegotiating ViewResolver

    这是 spring MVC 提供的一个特殊的 ViewResolver,ContentNegotiatingViewResolver 不是自己处理 view,而是代理给不同的 ViewResolver 来处理不同的 View,所以它有最高的优先级。

    (2).BeanNameViewResolver

    在控制器(@Controller)中的一个方法的返回值的字符串(视图名)会根据 BeanNameViewResolver 去查找 Bean 的名称为返回字符串的 View  来渲染视图。是不是不好理解,下面举个栗子。

    定义 BeanNameViewResolver 的 Bean: 

@Bean
	public BeanNameViewResolver beanNameViewResolver(){
		BeanNameViewResolver resolver = new BeanNameViewResolver();
		return resolver;
	}

定义一个 View 的 Bean ,名称为 jsonView:

@Bean
	public MappingJackson2JsonView jsonView() {
		MappingJackson2JsonView jsonView = new MappingJackson2JsonView();
		return jsonView;
	}
在控制器中,返回值为字符串 jsonView, 它会找 Bean 的名称为 jsonView 的视图来渲染:
@RequestMapping(value = "/json",produces={MediaType.APPLICATION_JSON_VALUE})
	public String json(Model model) {
		Person single = new Person("aa",11);
		model.addAttribute("single", single);
		return "jsonView";
	}

(3).InternalResourceViewResolver

这个是一个极为常用的 ViewResolver,主要通过设置前缀后缀,以及控制器中方法来返回视图名的字符串,以的到实际的页面,springboot 的源码如下:

@Bean
@ConditionalOnMissingBean(InternalResourceViewResolver.class)
public InternalResourceViewResolver defaultViewResolver(){
    InternalResourceViewResolver resolver = new InternalResourceViewResolver();
    resolver.setPrefix(this.prefix);//前缀
    resolver.setSuffix(this.suffix);//后缀
    return resolver;
}
3.1.2 自动配置的静态资源

在自动配置类的 addResourceHandlers 方法中定义了以下静态资源自动配置。

(1)类路径文件

把类路径下的/static、/public、/resources 和 /META-INF/resources 文件夹下的静态文件直接映射为 /**,可以通过 http://localhost:xxxx/** 直接访问。

(2)webjar

何谓 webjar,webjar 就是我们常用的脚本框架封装的 jar 包中的 jar 包

把 webjar 的 META-INF/resources/webjar/ 下的静态文件映射为 /webjar/**,可以通过 http://localhost:8080/webjar/** 来访问。

3.1.3 自动配置的 Formatter 和 Converter

关于自动配置 Formatter 和 Converter,我们可以看一下 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();
		}
从代码中可以看出,只要我们定义了 Converter GenericConverter Formatter 接口类的实现 bean ,这些 bean 就会自动注册到 spring MVC 中。
3.1.4 自动配置的 HttpMessageConverters

在 WebMvcAutoConfiguration 中,我们注册了 messageConverters,代码如下:

public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties,
				WebMvcProperties mvcProperties, ListableBeanFactory beanFactory,
				@Lazy HttpMessageConverters messageConverters,
				ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider) {
			this.resourceProperties = resourceProperties;
			this.mvcProperties = mvcProperties;
			this.beanFactory = beanFactory;
			this.messageConverters = messageConverters;
			this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider
					.getIfAvailable();
		}


private final HttpMessageConverters messageConverters;
@Override
		public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
			converters.addAll(this.messageConverters.getConverters());
		}
在 springboot 中如果要新增自定义的 HttpMessageConverter , 则只需定义一个你自己的 HttpMessageConverters  的 Bean,然后在此 bean 中注册自定义 HttpMessageConverter  即可。
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:xxxx/ 时,会直接映射。

4.接管 Spring Boot 的 Web 配置

如果 Spring Boot 提供的 Spring MVC 默认配置不符合你的需求,则可以通过一个配置类(注解有@Configuration 的类)加上 @EnableWebMvc 注解来实现完全自己控制的 MVC 配置。

当然通常情况下可以满足绝大多数的需求。在既需要保留 Spring Boot 提供的便利,又需要增加自己的额外配置的时候,可以定义一个配置类继承 WebMvcConfigurerAdapter,无需使用 @EnableWebMvc 注解:

 

package com.pangu.config;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**

 * @ClassName: WebMvcConfig

 * @Description: TODO 接管 SpringBoot 的 Web 配置,并不会覆盖 WebMvcAutoConfiguration 中的 addViewControllers

 * @author etfox

 * @date 2018年7月1日 下午3:06:16

 *

 * @Copyright: 2018 www.etfox.com Inc. All rights reserved.

 */

@Configuration

public class WebMvcConfig implements WebMvcConfigurer {

    

    /**

     * <p>Title: addViewControllers</p>   

     * <p>Description:http://127.0.0.1:8080/xx </p>   

     * @param registry   

     * @see org.springframework.web.servlet.config.annotation.WebMvcConfigurer#addViewControllers(org.springframework.web.servlet.config.annotation.ViewControllerRegistry)

     */

    @Override

    public void addViewControllers(ViewControllerRegistry registry) {

        registry.addViewController("/xx").setViewName("test");

    }

    

}

值得注意的是,在这里重写 addViewControllers 方法,并不会覆盖 WebMvcAutoConfiguration 中的 addViewControllers( 此方法中,SpringBoot 将”/“映射至 index.html),这也就意味着我们自己的配置和 springboot 的配置同时生效,这也是我们推荐的添加自己的 MVC 配置的方式。


5. 注册 servlet、filter、listener

    当使用嵌入式的 servlet 容器时,我们通过将 servlet、filter 和 listener 声明为 spring bean 而达到注册的效果:或者注册 ServletRegistrationBean、FilterRegistrationBean  和 ServletListenerRegistrationBean  的 Bean.




6.Tomcat 配置

    servlet 容器的配置,Spring Boot 默认内嵌的 Tomcat 为 servlet 容器。

    6.1 配置 Tomcat

        关于 Tomcat 的所有属性都在 org.springframework.boot.autoconfigure.web.ServerProperties 配置类中做了定义,我们只需在 application.properties 配置属性做配置即可。通用的 servlet 容器配置都以 server 作为前缀,而Tomcat 特有配置都以 server 作为前缀,而 Tomcat 特有配置都以 server.tomcat 作为前缀。示例:




7.Favicon 配置

    将 ico 文件配置在静态路径下即可,通常根目录。

8.WebSocket
    8.1 什么是 WebSocket

        WebScoket 为浏览器和服务端提供了双向异步通信的功能,即浏览器可以向服务端发送消息,服务端也可以向浏览器端发送消息。WebSocket 需浏览器的支持,如 IE 10+、Chrome 13+, Firefox 6+, 这对我们现在的浏览器来说都不是问题。

        WebScoket 是通过一个 socket 来实现双工异步通信能力。但是直接使用 WebSocket( 或 SockJS:WebSocket  协议的模拟,增加了当浏览器不支持的时候兼容支持)协议开发程序显得特别繁琐,我们使用它的子协议 STOMP ,它是一个更高级别的协议, STOMP 协议使用一个基于帧的格式来定义消息,与 HTTP 的 request 和 response 类似(具有类似于 @RequestMapping 的 @MessageMapping),我们会在后面实战内容中观察 STOMP 的帧。

    8.2 Spring Boot  提供的自动配置

        Spring Boot 对内嵌的 Tomcat(7/8)、Jetty9 和 Undertow 使用 websocket 提供了支持,配置源码存在 autoconfigure.websocket 下。


Spring Boot 为 WebSocket 提供的 stater pom 是 spring-boot-starter-websocket。







  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值