【SpringBoot2.x】-SpringBoot Web开发中Thymeleaf、Web、Tomcat以及Favicon

image.png

github:https://github.com/Ccww-lx/SpringBoot.git
模块:spring-boot-starter-base-web

  Web开发是开发中至关重要的一部分, Web开发的核心内容主要包括内嵌Servlet容器和Spring MVC。更重要的是,Spring Boot``为web开发提供了快捷便利的方式进行开发,使用依赖jar:spring-boot-starter-web,提供了嵌入式服务器Tomcat以及Spring MVC的依赖,且自动配置web相关配置,可查看org.springframework.boot.autoconfigure.web

Web相关的核心功能:

  • Thymeleaf模板引擎
  • Web相关配置
  • Tomcat配置
  • Favicon配置

1.模板配置

1.1原理以及源码分析

  Spring Boot提供了大量模板引擎, 包含括FreeMarkerGroovyThymeleafVelocity和MustacheSpring Boot中推荐
使用Thymeleaf作为模板引擎, 因为Thymeleaf提供了完美的Spring MVC的支持。

  在Spring Bootorg.springframework.boot.autoconfigure.thymeleaf包下实现自动配置,如下所示:

image.png

ThymeleafAutoConfiguration源码:

@Configuration
@EnableConfigurationProperties(ThymeleafProperties.class)
@ConditionalOnClass({ TemplateMode.class, SpringTemplateEngine.class })
@AutoConfigureAfter({ WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class })
public class ThymeleafAutoConfiguration {

        //配置TemplateResolver
    @Configuration
    @ConditionalOnMissingBean(name = "defaultTemplateResolver")
    static class DefaultTemplateResolverConfiguration {
            ...
    }
    
        //配置TemplateEngine
    @Configuration
    protected static class ThymeleafDefaultConfiguration {
            ...
    }
        //配置SpringWebFluxTemplateEngine
    @Configuration
    @ConditionalOnWebApplication(type = Type.SERVLET)
    @ConditionalOnProperty(name = "spring.thymeleaf.enabled", matchIfMissing = true)
    static class ThymeleafWebMvcConfiguration {
           ...
    }
    
        //配置thymeleafViewResolver
    @Configuration
    @ConditionalOnWebApplication(type = Type.REACTIVE)
    @ConditionalOnProperty(name = "spring.thymeleaf.enabled", matchIfMissing = true)
    static class ThymeleafWebFluxConfiguration {
           ...
    }
    ...
}

  ThymeleafAutoConfiguration自动加载Web所需的TemplateResolverTemplateEngineSpringWebFluxTemplateEngine以及thymeleafViewResolver,并通过ThymeleafProperties进行Thymeleaf属性配置。详细细节查看官方源码。

ThymeleafProperties源码:

//读取application.properties配置文件的属性
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {

    private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;

    public static final String DEFAULT_PREFIX = "classpath:/templates/";

    public static final String DEFAULT_SUFFIX = ".html";

    /**
     *Web模板文件前缀路径属性,Spring boot默认路径为classpath:/templates/
     */
    private String prefix = DEFAULT_PREFIX;

    /**
     * Web模板文件后缀属性,默认为html
     */
    private String suffix = DEFAULT_SUFFIX;

    /**
     * Web模板模式属性,默认为HTML
     */
    private String mode = "HTML";

    /**
     *  Web模板文件编码属性,默认为UTF_8
     */
    private Charset encoding = DEFAULT_ENCODING;

        ....
}

可以从ThymeleafProperties中看出,Thymeleaf的默认设置,以及可以通过前缀为spring.thymeleaf属性修改Thymeleaf默认配置。

1.2 示例

1).根据默认Thymeleaf配置,在src/main/resources/下,创建static文件夹存放脚本样式静态文件以及templates文件夹存放后缀为html的页面,如下所示:

image

2)index.html页面

<!DOCTYPE html>
<!-- 导入xmlns: th=http://www.thymeleaf.org命名空间 -->
<html xmlns:th="http://www.thymeleaf.org">
<html lang="en">
 <head>
     <meta charset="UTF-8">
    <title>首面详细</title>
 </head>
  <body>
    <div class="user" align="center"  width="400px" height="400px">
        message:<span th:text="${user.message}"/><br/>
       用户名:<span th:text="${user.username}"/><br/>
         密码:<span th:text="${user.password}"/>
    </div>
 </body>
</html>

3).controller配置:

@Controller
public class LoginController {
    @Autowired
    private LoginService loginService;
    
    /**
     * 将首页设置为登陆页面login.html
     * @return
     */
    @RequestMapping("/")
    public String startIndex() {
        return "login";
    }

    /**
     *  登陆验证
     * @param username
     * @param password
     * @param model
     * @return
     */
    @RequestMapping("/login")
    public String login(@RequestParam("username") String username, @RequestParam("password") String password, Model model) {
        UserDTO userDTO = loginService.login(username, password);
        model.addAttribute("user", userDTO);
        return "index";
    }
}

2. web相关配置

根据WebMvcAutoConfiguration以及WebMvcProperties理解Spring Boot提供的自动配置原理。

2.1 ViewResolver以及静态资源

Spring boot自动配置ViewResolver

  • ContentNegotiatingViewResolver(最高优先级Ordered.HIGHEST_PRECEDENCE
  • BeanNameViewResolver
  • InternalResourceViewResolver

静态资源
  addResourceHandlers 方法默认定义了/static/public/resources/METAINF/resources文件夹下的静态文件直接映射为/**

2.2 Formatter和Converter类型转换器

  addFormatters 方法会自动加载ConverterGenericConverter以及Formatter的实现类、并注册到Spring MVC中,因此自定义类型转换器只需继承其三个接口即可。

自定义Formatter:

/**
 * 将格式为 ccww:ccww88转为UserDTO
 *
 * @Auther: ccww
 * @Date: 2019/10/4 16:25
 * @Description:
 */
public class StringToUserConverter implements Converter<String, UserDTO> {
    @Nullable
    public UserDTO convert(String s) {
        UserDTO userDTO = new UserDTO();
        if (StringUtils.isEmpty(s))
            return userDTO;
        String[] item = s.split(":");
        userDTO.setUsername(item[0]);
        userDTO.setPassword(item[1]);
        return userDTO;
    }
}

2.3 HttpMessageConverters (HTTP request (请求)和response (响应)的转换器)

configureMessageConverters方法自动配置HttpMessageConverters:

public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            this.messageConvertersProvider.ifAvailable((customConverters) -> converters
                    .addAll(customConverters.getConverters()));
        }

通过加载由HttpMessageConvertersAutoConfiguration定义的HttpMessageConverters,会自动注册一系列HttpMessage Converter类,比如Spring MVC默认:

  • ByteArrayHttpMessageConverter
  • StringHttpMessageConverter
  • ResourceHttpMessageConverter
  • SourceHttpMessageConverter
  • AllEncompassingFormHttpMessageConverter

自定义HttpMessageConverters,只需要在自定义的HttpMessageConvertersBean注册自定义HttpMessageConverter即可。
如下:

注册自定义的HttpMessageConverter

@Configuration
public class CustomHttpMessageConverterConfig {
    @Bean
    public HttpMessageConverters converter(){
        HttpMessageConverter<?> userJsonHttpMessageConverter=new UserJsonHttpMessageConverter();
        return new HttpMessageConverters(userJsonHttpMessageConverter);
    }
}

自定义HttpMessageConverter

public class UserJsonHttpMessageConverter extends AbstractHttpMessageConverter<UserDTO> {
    private static Charset DEFUALT_ENCODE=Charset.forName("UTF-8");
    public UserJsonHttpMessageConverter(){
        super(new MediaType("application", "xxx-ccww", DEFUALT_ENCODE));
    }
    protected boolean supports(Class aClass) {
            return UserDTO.class == aClass;
    }

    protected UserDTO readInternal(Class aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {
        String message = StreamUtils.copyToString(httpInputMessage.getBody(), DEFUALT_ENCODE);
        String[] messages = message.split("-");
        UserDTO userDTO = new UserDTO();
        userDTO.setUsername(messages[0]);
        userDTO.setMessage(messages[1]);
        return userDTO;
    }

    protected void writeInternal(UserDTO userDTO, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {
        String out = "ccww: " + userDTO.getUsername() + "-" + userDTO.getMessage();
        httpOutputMessage.getBody().write(out.getBytes());
    }
}

同理,可以将Servlet、Filter以及Listener相对于的注册即可。

2.4 MVC相关配置

  自定义的MVC配置类上加@EnableWebMvc将废弃到Spring boot默认配置,完全由自己去控制MVC配置,但通常是Springboot默认配置+所需的额外MVC配置,只需要配置类继承WebMvcConfigurerAdapter即可

2.5 Tomcat配置

可以使用两种方式进行Tomcat配置属性

  1. application.properties配置属性即可,Tomcat是以"server.tomcat"为前缀的特有配置属性,通用的是以"server"作为前缀;
  2. 通过实现WebServerFactoryCustomizer接口自定义属性配置类即可,同理其他服务器实现对应的接口即可。

application.properties配置属性:

#通用Servlet容器配置
server.port=8888

#tomcat容器配置
#配置Tomcat编码, 默认为UTF-8
server.tomcat.uri-encoding = UTF-8
# Tomcat是否开启压缩, 默认为关闭off
server.tomcat.compression=off

实现WebServerFactoryCustomizer接口自定义:

/**
 * 配置tomcat属性
 * @Auther: ccww
 * @Date: 2019/10/5 23:22
 * @Description: 
 */
@Component
public class CustomTomcatServletContainer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
    public void customize(ConfigurableServletWebServerFactory configurableServletWebServerFactory) {
        ((TomcatServletWebServerFactory)configurableServletWebServerFactory).addConnectorCustomizers(new TomcatConnectorCustomizer() {
            public void customize(Connector connector) {
                Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
                protocol.setMaxConnections(200);
                protocol.setMaxThreads(200);
                protocol.setSelectorTimeout(3000);
                protocol.setSessionTimeout(3000);
                protocol.setConnectionTimeout(3000);
                protocol.setPort(8888);
            }
        });
    }
}

替换spring boot 默认Servlet容器tomcat,直接在依赖中排除,并导入相应的Servlet容器依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starterweb</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-startertomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starterjetty</artifactId>
</dependency

2.6 自定义Favicon

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



最后可关注公众号:【ccww笔记】 一起学习,每天会分享干货,还有学习视频领取!

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容