【Spring Boot】web开发

spring boot做web开发,十分方便,直接在pom.xml文件中引入web场景启动器依赖即可。省去了spring MVC的配置文件,这样我们就可以把重心放在编写我们的业务代码了。

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

spring boot其实就是spring框架,只是避免了spring框架整合其他框架搭建的许多配置文件,spring boot在底层都为我们做好了。

web模块自动配置原理主要关注WebMvcAutoConfiguration这个class文件。

一、静态资源引入方式

  • 1、webjar库,https://www.webjars.org/,主要以jar包的方式引入静态资源,从源码得知,所有的/webjars/**,都去 classpath:META-INF/resources/webjars/找资源
    图片.png
  • 2、/** 访问当前项目的任何资源(静态资源的文件夹)
    WebMvcAutoConfiguration.class中的addResourceHandlers方法跳到ResourceProperties中的getStaticLocations方法,得知如下的静态资源类路径数组,这里面文件夹里存放的静态资源都可以被访问到,只要没被拦截处理就到这4个路径下找静态资源。
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{
"classpath:/META-INF/resources/",
 "classpath:/resources/",
 "classpath:/static/", 
"classpath:/public/"
};
//项目结构中,main路径下的java和resource都是类根路径。
  • 3、欢迎页,其实就是当访问/**时自动映射到上面提到的4个静态资源文件夹下的index.html页面。
    图片.png

二、Thymeleaf模板引擎

引入thymeleaf,springboot默认不支持jsp,推荐使用thymeleaf模板引擎

<!--添加pom.xml依赖-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--修改属性版本值-->
<properties>
  <!--thymeleaf3版本的主程序则得适配layout2版本以上-->
  <springboot-thymeleaf.version>3.0.9.RELEASE</springboot-thymeleaf.version>
  <thymeleaf-layout-dialect.version>2.1.1</thymeleaf-layout-dialect.version>
</properties>

语法

推荐好文:thymeleaf3语法详析
记得在写thymeleaf页面的时候,要先声明名称空间 xmlns:th="http://www.thymeleaf.org,这样才能获得thymeleaf语法提示,thymeleaf是支持数据快速渲染的。

<!DOCTYPE html>
<!--名称空间-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
  <head>
      <meta charset="UTF-8">
      <title>Thymeleaf 开始</title>
  </head>
  <body>
    <p>基本跟jsp用法类似,在html中渲染传输数据,只是有自己的一套规则</p>
  </body>
</html>

附:IDEA写springboot时,当我们修改html等静态资源时不需要重启服务器才能看效果,实现热部署,参考文章:https://blog.csdn.net/qq_33172029/article/details/91412810

三、springboot对springMVC配置的解析

1、springboot对springMVC的自动配置原理

WebMvcAutoConfiguration.class文件中的viewResolver视图解析方法,跳进ContentNegotiatingViewResolver这个类中,得知其实就是组合容器中所有的视图解析器的,于是我们也可以自定义一个视图解析器然后被自动组合进来。

图片.png
编写自定义解析器后在DispatcherServlet.class文件中的doDispatch方法打断点,默认所有请求都会来到这个方法处理。
图片.png
总结:springboot在自动配置组件的时候,会先扫描容器中是否有用户自定义添加的组件(@Bean、@Component),如果有则优先使用用户自定义配置的组件,没有的话才使用默认自动配置。

2、扩展springMVC

新建配置类,加上注解@Configuration,继承WebMvcConfigurerAdapter类,不能标注@EnableWebMvc

图片.png
这样的话当我们发送test请求就会到test.html页面中去,这就是扩展配置springMVC,springboot对springMVC的自动配置和扩展配置都会生效。

3、全面接管springMVC

在配置类加上一个注解@EnableWebMvc,表示springboot不对springMVC做自动配置了,需求什么springMVC组件就都自己配置,比如视图解析器。

四、thymeleaf+bootstrap开发国际化登录页面

国际化:指的是页面根据浏览器的语言信息自动切换语言显示。

步骤:

1、创建一个i18n包,在里面放置3个国际化属性文件,分别是默认语言,中文,英文。
2、springboot自动配置好了管理国际化资源文件的组件了,我们只需要在配置文件中加入spring.messages.basename=i18n.login即可。
3、在页面使用thymeleaf的标签属性格式进行数据渲染,获取国际化的值。

注意:IDEA编写.properties属性文件的时候在运行时页面默认是会中文乱码的,得去other settings-->default setting(全局默认设置)-->file encoding里设置UTF-8编码并且自动转换为ASCALL码,这样页面就不会中文乱码了。

图片.png

从上图源码可以看出默认是在请求头中的区域信息获取Locale进行国际化的,我们可以通过自己编写一个MyLocaleResolver的bean注册到容器中,来从链接中解析获取Locale,然后把这个bean给注册到容器中生效,这样底层源码检测到容器中有这个bean就不会去默认请求头中获取Locale了。

实现点击链接的方式切换国际化功能,其实就是在点击链接时带上参数,以下贴源码

<!--没贴上css样式-->

<body class="body">
<!--

If we can only encounter each other rather than stay with each other,
then I wish we had never encountered.

如果只是遇见,不能停留,不如不遇见。

-->
<div class="container mask">
    <img th:src="@{/images/login_face.png}" style="margin-top: 50px">
    <h1 th:text="#{login.title}">项目管理系统</h1>
    <form action="/TBMS/login" method="post">
        <div class="form-group">
            <!--thymeleaf判断msg不为空再出现提示-->
            <span th:if="${not #strings.isEmpty(msg)}"><img th:src="@{/images/login_tip.png}" /></span>
            <label class="error" th:text="${msg}"></label>
        </div>

        <div class="form-group input-group">
            <span><img th:src="@{/images/nickname.png}" /></span>
            <input class="input" type="text" name="userId" th:placeholder="#{login.userid}"/>
        </div>

        <div class="form-group input-group">
            <span><img th:src="@{/images/locking.png}" /></span>
            <input class="input" type="password" name="password" th:placeholder="#{login.password}"/>
        </div>

        <button class="btn" th:text="#{login.btn}">登录</button>
    </form>

    <div style="margin-top: 20px;">
        <a th:href="@{/toLogin(l='zh_CN')}">中文</a>
        <a th:href="@{/toLogin(l='en_US')}" style="margin-left: 10px">English</a>
    </div>

</div>
</body>

编写自定义区域解析器MyLocaleResolver.java

/**
 * FileName: MyLocaleResolver
 * Author:   小江
 * Date:     2019/12/18 22:49
 * History:
 */
package com.zhbit.xiaojiang.component;

import org.springframework.web.servlet.LocaleResolver;
import org.thymeleaf.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;

/**
*@Author 小江  [com.zhbit]
*@Date 2019/12/22 16:37
*Description  自定义区域信息解析器
*/
public class MyLocaleResolver implements LocaleResolver {

    @Override
    public Locale resolveLocale(HttpServletRequest httpServletRequest) {

        String str = httpServletRequest.getParameter("l");
        //初始化先使用默认的区域信息
        Locale locale = Locale.getDefault();
        if(!StringUtils.isEmpty(str)){
            String[] split = str.split("_");
            //根据传来的区域信息创建一个locale对象
            locale = new Locale(split[0],split[1]);
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {

    }
}

注入自定义区域解析器bean

/**
 * FileName: WebConfig
 * Author:   小江
 * Date:     2019/12/18 21:20
 * History:
 */
package com.zhbit.xiaojiang.config;

import com.zhbit.xiaojiang.component.MyLocaleResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@ComponentScan
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    /**
    *@Author 小江  [com.zhbit]
    *@Date 2019/12/18 22:58
    *Description  注册自定义的区域信息解析bean到容器中
    */
    @Bean
    public LocaleResolver localeResolver(){
        return new MyLocaleResolver();
    }
}

最后配置声明国际化资源文件的基础名称以及编写国际化资源文件

image.png
image.png

经过以上步骤,登录页国际化功能就实现了。
image.png

注意:springboot项目中无法直接访问templates下的html文件时,可以添加如下配置即可直接访问templates下的页面:

图片.png
不过这是不推荐的,因为本身设定templates下仅存放模板页面,是没有开放直接访问权限的,要访问templates下的模板页面还是通过视图解析,服务器内部访问这个流程走比较好,即相当于Controller的方式,具体说明看这篇文章:https://blog.csdn.net/YTenderness/article/details/100164734
开发期间,IDEA修改thymeleaf模板引擎代码,页面是不会实时生效的,得在配置文件中先禁用模板引擎的缓存spring.thymeleaf.cache=false,之后IDEA修改完后按ctrl+f9重新编译即可实时生效了。

五、thymeleaf公共片段元素抽取

管理系统后台的每个页面一般都是有固定的顶部导航栏和侧边菜单栏,如果每次写页面都要复制粘贴这部分代码的话就显得页面代码很冗余,所以thymeleaf页面可以抽取出来页面固定的部分作为公共片段,然后其他页面如果需要就直接引入公共片段就好。

比如在index.html中抽取顶部导航栏,在nav标签里写上th:fragment="topbar",即定义抽取片段名

<nav class="navbar navbar-default top-navbar" role="navigation" th:fragment="topbar">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".sidebar-collapse">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" th:href="@{/admin/index}"><i class="fa fa-comments"></i> <strong>项目管理系统</strong></a>
            </div>
</nav>

然后在empty.html中引入顶部导航栏,th:replace="~{/admin/index::topbar}",即引入页面路径名::抽取片段名

<!--引入抽取出来的顶部导航栏-->
        <div th:replace="~{/admin/index::topbar}"></div>

关于thymeleaf引入抽取片段有3种方式,效果各有不同

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

推荐阅读更多精彩内容

  • 最近有点儿迷茫,喜欢画画的心空前高涨,却在彩铅上受挫。看到喜欢的素材都会保存下来,简笔画、黑白画、水彩画、彩铅每种...
    悠悠简笔画阅读 2,102评论 5 9
  • 正当升旗之时,忽闻天空隆隆之声。仰头瞧之,只见十余架飞机在西北之空。此机浑身迷彩,直升机型,略半隐形也。同学纷议之...
    子得阅读 268评论 1 3
  • a 网购时代,想象是必备技能。 想象这件双面呢大衣穿在我身上会是什么样子,想象这个发型是否适合我,想象这双靴子和我...
    素大夫包治百病阅读 224评论 0 2
  • 七月,带上我吧, 从绿荫葱葱的小道中 奔离! 离别之前, 从满园子的清芬中采一朵雏花, 从清冽的河水携走一滴水, ...
    疯尘子阅读 605评论 2 2
  • “啊~,终于回来了!!”林可欣拖着自己Hello Kitty的粉色行李箱,站在樱城机场张开了双手,用力的呼吸四周的...
    离妆阅读 199评论 0 1