Spring Boot 初探

小随笔:

@RestController和@Controller区别:

1.@RestController:方法无法返回jsp页面,或者html
配置的视图解析器 InternalResourceViewResolver 不起作用,返回的内容就是Return 里的内容。

2.如果需要返回到指定页面,则需要用 @Controller配合视图解析器InternalResourceViewResolver 才行。
如果需要返回JSON,XML或自定义mediaType内容到页面,则需要在对应的方法上加上@ResponseBody注解。(@RestController 不用加 body 注解,但是无法返回到 jsp,html 页面)

报错o.s.b.d.LoggingFailureAnalysisReporter:

在启动类上加 exclude = {DataSourceAutoConfiguration.class}

注解作用:将DataSourceAutoConfiguration ,DataSourceTransactionManagerAutoConfiguration 排队在外
也就是不会自动配置 DataSource 与 DataSourceTransactionManager 。

maven 打包失败:

可能没有更新命令
先在 plugins 下的 spring-boot 下的 repackage 更新,然后再打包,就可以成功了

Spring Boot 入门:

微服务:

一种架构风格
一个应用应该是一组小型服务,可以通过 HTTP 的方式进行互通
单体应用:ALL IN ONE

每一个功能元素最终都是一个可独立替换和独立升级的软件单元(微服务)

Hello World:

主程序:(IDEA可以自动配置)

@SpringBootApplication
public class SpringBoot01HelloQuickApplication {

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

运行即可启动 spring boot

请求类:

浏览器发送 hello 请求,服务器接收请求并处理,响应 Hello World 字符串

直接用 RequestMapping 注解即可(value 为目录,返回的字符串为 文件名)

如果直接发送请求(不用文件,直接显示返回的字符串),则需要加 @ResponseBody 注解
(标识为 @RestController 则不需要加 body,但是无法跳转到目标页面)
(@ResponseBody 也可以加在类名上,表明该类的所有方法放回的字符串都是直接写在页面上的(返回的对象生成为一个JSON给页面))

简化部署:

maven 中加入依赖:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

功能:将这个应用打成 jar 包,直接在控制台使用 java -jar 的命令执行
(命令更新要先 repackage 再打包)
(命令提示符中可以用 Tab 自动补全名称)

POM.xml文件:

父项目:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

这个父项目spring-boot-starter-parent又依赖一个父项目

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.0.1.RELEASE</version>
    <relativePath>../../spring-boot-dependencies</relativePath>
</parent>

下面有个属性,定义了对应的版本号

<properties>
    <activemq.version>5.15.3</activemq.version>
    <antlr2.version>2.7.7</antlr2.version>
    <appengine-sdk.version>1.9.63</appengine-sdk.version>
    <artemis.version>2.4.0</artemis.version>
    <aspectj.version>1.8.13</aspectj.version>
    <assertj.version>3.9.1</assertj.version>
    <atomikos.version>4.0.6</atomikos.version>
    <bitronix.version>2.1.4</bitronix.version>
    <build-helper-maven-plugin.version>3.0.0</build-helper-maven-plugin.version>

Spring Boot 的版本仲裁中心 会自动导入对应的版本,不需要我们自己导入依赖
没有 dependencies 里面管理的依赖自己声明

启动器:

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

spring-boot-starter-web:帮我们导入web模块正常运行所依赖的组件

spring boot将所有的功能场景都抽取出来,做成一个个的starter(启动器),只需要在项目里引入这些starter相关场景的所有依赖都会被导入进来,要用什么功能就导入什么场景的启动器。

resources 目录解析:

resources文件夹目录结构:
● static:保存所有的静态文件如 js css images

● templates:保存所有的模板页面;
(Spring Boot 默认jar包使用嵌入式的 Tomcat,默认不支持JSP
可以使用模板引擎(freemarker.thymeleaf);

● application.properties:可以修改 Spring Boot 的默认配置
例如 server.port=8081(改 Tomcat 端口号)

配置文件:

Spring Boot使用全局配置文件,配置文件名是固定的;
● application.properties
● application.yml

配置文件作用:修改 Spring Boot 自动配置的默认值(在底层自动配置好的值)

YAML(YAML AIN’T Markup Language)
YAML a Markup Language:是一个标记语言
YAML isn’t Markup Language:不是一个标记语言

标记语言:
以前的配置文件,大多使用 xxx.xml 文件
YAML:以数据为中心,比 json、xml 等更适合做配置文件

以前的 XML 配置端口:

<server>
    <port>8081</port>
</server>

YAML:

server:
  port: 8081

YAML:

基本语法:

k:(空格)v: 表示一对键值对(空格必须有,在冒号后面)
以空格的缩进来表示层级关系
只要是左对齐的,都是同一个层级的

server: 
    port: 8081
    path: /hello

属性和值是大小写敏感的

值的写法:

字面量:普通的值(数字、字符串、布尔):

k: v: 字面量直接来写,字符串默认不用加引号
双引号:不会转义字符串里面的特殊字符,特殊字符会作为本身想表示的意思
(name: “hello \n” 输出为:hello 换行)
单引号:会转义特殊字符,特殊字符最终只是作为一个字符串输出
(name: “hello \n” 输出为:hello \n)

对象、Map(属性和值)(键值对):

k: v: 在下一行来写对象的属性和值的关系,注意缩进
对象还是 k: v 的方式
例如:

friends:
    lastName: zhangsan
    age: 20

还可以用行内写法:

friends: {lastName: zhangsan,age: 20}
数组(List、Set):

- 值 表示数组中的一个元素

pets: 
 - cat
 - dog
 - pig

行内写法:

pets: [cat,dog,pig]

例子:

配置:

person:
  lastName: zhangsan
  age: 20
  boss: false
  birth: 2018/01/01
  maps:
    k1: v1
    k2: 12
  lists:
    - lisi
    - zhaoliu
  dog:
    name: 小狗
    age: 2

(lastName 可以写为 last-name ,效果一样)

相应类上面要有
@Component 和 @ConfigurationProperties 注释:

/**
 * 将配置文件中配置的每一个属性的值,映射到这个组件中
 * @ConfigurationProperties: 告诉 spring boot 将本类中的所有属性和配置文件中相关的配置绑定
 * prefix="person" : 配置文件中哪个下面的所有属性进行一一映射
 *
 * 只有这个组件是容器中的组件才能使用容器提供的 @ConfigurationProperties 功能
 */
@Component
@ConfigurationProperties(prefix="person")

@Component (把普通pojo实例化到spring容器中,相当于配置文件中的
<bean id="" class=""/>

泛指各种组件,就是说当我们的类不属于各种归类的时候(不属于@Controller、@Services等的时候),我们就可以使用@Component来标注这个类。

@ConfigurationProperties:与配置文件关联
属性 prefix:与配置文件中的哪个属性绑定

可以自动注入对象:

@Controller
public class hello {

    @Autowired
    Person person;

    @ResponseBody
    @RequestMapping("/")
    private Person index(){
        return person;
    }
}

加入 @Autowired 自动注入对象

在 maven 中可以加:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
</dependency>

配置文件处理器,以后编写配置就有提示了

也可以用 properties 进行配置:

person.last-name=张三
person.age=20
person.birth=2018/01/01
person.boss=false
person.maps.k1=v1
person.maps.k2=14
person.lists=a,b,c
person.dog.name=dog
person.dog.age=15

但是有中文乱码问题,所以要在 IDEA 的设置里设置 properties 文件中文自动转为 ISCII 码值

可以用 @Value 代替 @ConfigurationProperties 注解:

@Value("${person.last-name}")
private String lastName;
@Value("#{11*2}")
private Integer age;
@Value("true")
private Boolean boss;

支持 Spring 语法
区别:

@ConfigurationProperties@Value
功能批量注入配置文件属性单个指定
松散绑定(语法)支持不支持
SpEL不支持支持
JSR303校验支持不支持
复杂类型封装支持不支持

松散绑定:比如 lastName 可以写成 last-name 或者 last_name
SpEL:表达式,如 #{10+3}
JSR303校验:加入 @Validated ,可以在属性上面加 @Email ,表明该属性只能填为邮箱格式
复杂类型封装:比如 map ,@Value 不支持

如果只是用配置文件中的某个值的时候,可以用 @Value:

@RestController
public class HelloController {

    @Value("${person.last-name}")
    private String name;

    @RequestMapping("/sayHello")
    public String sayHello() {
        return "Hello" + name;
    }
}

@PropertySource:

因为 @ConfigurationProperties 是加载全局配置的,如果所有配置都写在全局配置中就过于臃肿
用 @PropertySource 注解可以加载其他的配置文件:
比如有一个 person.properties 里面写着 person 的配置
则可以在 Person 上加入 @PropertySource(value = {“classpath:person.properties”}) 引入配置

@ImportResource:

导入 Spring 的配置文件,使配置文件里面的内容生效

Spring boot 里面没有 Spring 的配置文件,我们自己编写的配置文件也不能自动识别
想让 Spring 配置文件生效,加载进来,可以将 @ImportResource 标识在主启动类上
@ImportResource(locations = {“classpath:beans.xml”})
这样就导入了 Spring 的配置文件让其生效

但是太麻烦!

Spring Boot 推荐给容器添加组件的方式:

推荐使用全注解的方式

配置类 ======== Spring 配置文件

加入 @Configuration 注解,标明这是一个配置类,来替代 Spring 配置文件

在 xml 中用 <bean> 添加组件
而在 配置类 中,用 @Bean 添加组件:

@Bean
public HelloService helloService() {
    return new HelloService();
}

@Bean:将方法的返回值添加到容器中,容器中这个组件默认的 id 就是方法名

配置文件占位符:

  1. 配置文件可以使用随机数:
    ${random.value}、${random.int} 等

  2. 属性配置占位符:

app.name=MyApp
app.description=${app.name} is a Spring Boot application

可以在配置文件中引用前面配置过的属性
${app.name:默认值} 来指定找不到属性时的默认值

Profile:

Profile 是 Spring 对不同环境提供不同配置功能的支持,可以通过激活、指定参数等方式快速切换环境

多Profile文件:

我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml

  • application.properties
  • application-dev.properties
  • application-prod.properties

默认使用 application.properties

激活指定Profile:

application.properties 配置文件指定:

spring.profiles.active=dev

YAML支持多文档块:

server:
    port: 8081
spring:
    profiles:
        active: dev
---
server:
    port: 8082
spring:
    profiles: dev
---
server:
    port: 8083
spring:
    profiles: prod

分多个文档块,在最上层选择激活哪个:

spring:
    profiles:
        active: dev
激活:

1、在配置文件中激活:–spring.profiles.active=dev

2、命令行:

优先级大于配置文件

打包 成jar后

java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar –spring.profiles.active=dev
可以直接在测试的时候,配置传入命令行参数

3、虚拟机参数

-Dspring.profiles.active=dev

配置文件优先级:

SpringBoot启动扫描以下位置的 application.properties 或者 application.yml 文件作为 Spring boot的默认配置文件

file:./config/
file./
classpath:/config/
classpath:/
优先级从高到低顺序,高优先级会覆盖低优先级的相同配置
配置形成互补,如 server.servlet.context-path=/boot03
这样在低优先级配置后,输入 /boot03/项目名,会以高优先级的端口号运行低优先级的路径
(注:spring boot1x 是server.context.path=/boot02)

priority:

还可以通过spring.config.location来改变配置文件的位置

项目打包好了以后,可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置
指定配置文件和默认的配置文件会共同起作用,互补配置

java -jar spring-boot-config-02-0.0.1-SNAPSHOT.jar –spring.config.location=E:/work/application.properties

运维比较有用,从外部加载,不用修改别的文件

外部配置加载:

Spring Boot 也可以从以下位置加载配置:优先级从高到低,高优先级的配置会覆盖低优先级的配置,所有的配置会形成互补配置

1.命令行参数
java -jar spring-boot-config-02-0.0.1-SNAPSHOT.jar –server.port=8084 –server.context-path=/abc
中间一个空格
(和内部配置同时生效)

2.来自java:comp/env的JNDI属性

3.java系统属性(System.getProperties())

4.操作系统环境变量

5.RandomValuePropertySource配置的random.*属性值

由 jar 包外向 jar 包内寻找,高优先级覆盖低优先级
优先加载带 profile
6.jar包外部的 application-{profile}.properties 或 application.yml(带Spring.profile) 配置文件

7.jar包内部的 application-{profile}.properties 或 application.yml(带Spring.profile) 配置文件

再来加载不带 profile
8.jar包外部的 application.properties 或 application.yml(带Spring.profile) 配置文件

9.jar包内部的 application.properties 或 application.yml(不带spring.profile) 配置文件

10.@Configuration注解类的@PropertySource

11.通过SpringApplication.setDefaultProperties指定的默认属性

具体参考官方文档

Spring Boot 与 日志:(未完)

日志框架:

日志门面(日志的抽象层)日志实现
SLF4j Logback

左边选一个门面,右边选一个实现。
日志门面:SLF4j
日志实现:Logback

Spring Boot :底层是 Spring 框架,Spring 框架使用的是 JCL
Spring Boot 选用的是 SLF4j 和 Logback

SLF4j:(未完待续)

日志记录方法的调用不应该直接调用日志的实现类,要调用日志的抽象层里面的方法。

静态资源映射:

1.所有 /webjars/**,都去 classpath:/META-INF/resources/webjars 找资源;
webjars:以 jar 包的方式引入静态资源
https://www.webjars.org/

2.”/**” 访问当前项目的任意资源
如:localhost:8080/abc 去静态资源文件夹里找 abc

3.欢迎页,去静态资源文件夹里找 index.html(所有的 index 被 /** 映射)
如:localhost:8080/ 找 index

4.所有的 **/favicon.ico 都是在资源文件夹里找(网站小图标)

模板引擎:

作用:网页显示动态属性,如何将数据在网页上动态的显示出来。

Thymeleaf:

引入:

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

版本在 properties 里面设置:

<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>

Thymeleaf 前缀设置:templates/
后缀:.html

语法:

1.导入命名空间:
<html> 标签里加入 xmlns:th=”http://www.thymeleaf.org”

2.使用 thymeleaf 的语法:
在标签里加入 th:text,比如:
<div th:text=${hello}>
(将 div 里面的文本内容设置为传入的数据)

可以 th:任意 html 属性 来替换原来属性的值。

3.规则:

功能标签功能和jsp对比
1Fragment inclusionth:insert th:replaceinclude(片段包含)
2Fragment iterationth:eachc:forEach(遍历)
3Conditional evaluationth:if th:unless th:switch th:casec:if(条件判断)
4Local variable definitionth:object th:withc:set(声明变量)
5General attribute modificationth:attr th:attrprepend th:attrappend属性修改支持前面和后面追加内容
6Specific attribute modificationth:value th:href th:src …修改任意属性值
7Text (tag body modification)th:text th:utext修改标签体内容 utext:不转义字符
8Fragment specificationth:fragment声明片段

4.表达式语法:

Simple expressions:(表达式语法)
    Variable Expressions: ${...}
        1、获取对象属性、调用方法
        2、使用内置基本对象:
            #ctx : the context object.
            #vars: the context variables.
            #locale : the context locale.
            #request : (only in Web Contexts) the HttpServletRequest object.
            #response : (only in Web Contexts) the HttpServletResponse object.
            #session : (only in Web Contexts) the HttpSession object.
            #servletContext : (only in Web Contexts) the ServletContext object.
         3、内置一些工具对象
            #execInfo : information about the template being processed.
            #messages : methods for obtaining externalized messages inside variables expressions, in the same way as they
            would be obtained using #{…} syntax.
            #uris : methods for escaping parts of URLs/URIs
            #conversions : methods for executing the configured conversion service (if any).
            #dates : methods for java.util.Date objects: formatting, component extraction, etc.
            #calendars : analogous to #dates , but for java.util.Calendar objects.
            #numbers : methods for formatting numeric objects.
            #strings : methods for String objects: contains, startsWith, prepending/appending, etc.
            #objects : methods for objects in general.
            #bools : methods for boolean evaluation.
            #arrays : methods for arrays.
            #lists : methods for lists.
            #sets : methods for sets.
            #maps : methods for maps.
            #aggregates : methods for creating aggregates on arrays or collections.
            #ids : methods for dealing with id attributes that might be repeated (for example, as a result of an iteration).
    Selection Variable Expressions: *{...} //选择表达式:和${}功能一样,补充功能
   # 配合th:object使用,object=${object} 以后获取就可以使用*{a}  相当于${object.a}
        <div th:object="${session.user}">
            <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
            <p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
            <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
        </div>
    Message Expressions: #{...} //获取国际化内容
    Link URL Expressions: @{...} //定义URL链接
        #<a href="details.html" th:href="@{/order/details(orderId=${o.id})}">view</a>
    Fragment Expressions: ~{...}//片段文档

Literals(字面量)
    Text literals: 'one text' , 'Another one!' ,…
    Number literals: 0 , 34 , 3.0 , 12.3 ,…
    Boolean literals: true , false
    Null literal: null
    Literal tokens: one , sometext , main ,…
Text operations:(文本操作)
    String concatenation: +
    Literal substitutions: |The name is ${name}|
Arithmetic operations:(数学运算)
    Binary operators: + , - , * , / , %
    Minus sign (unary operator): -
Boolean operations:(布尔运算)
    Binary operators: and , or
    Boolean negation (unary operator): ! , not
Comparisons and equality:(比较运算)
    Comparators: > , < , >= , <= ( gt , lt , ge , le )
    Equality operators: == , != ( eq , ne )
Conditional operators:(条件运算)
    If-then: (if) ? (then)
    If-then-else: (if) ? (then) : (else)
    Default: (value) ?: (defaultvalue)
Special tokens:(空操作)
    No-Operation: _

5.行内写法:

[[]] -->th:text
[()] -->th:utext

如:

<span th:each="user:${users}">[[${user}]]</span>

CRUD:

自己配置 mvc 的视图解析跳转:

@Configuration
public class MyMvcConfig implements WebMvcConfigurer{

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/login.html").setViewName("login");
        registry.addViewController("/").setViewName("login");
    }
}

自己写一个类实现 WebMvcConfigurer 接口
重写 addViewControllers 方法,调用 addViewController.setViewName 方法
前面是地址,后面是跳转

Thymeleaf 运用:

<link href="asserts/css/bootstrap.min.css" th:href="@{/webjars/bootstrap/4.0.0/css/bootstrap.css}" rel="stylesheet">
        <!-- Custom styles for this template -->
<link href="asserts/css/signin.css" th:href="@{/asserts/css/signin.css}" rel="stylesheet">

加入 th:href=”@{url}” 可以指定访问动态的 url 地址
(假如地址改变,这里也会跟着改)

国际化:

1.编写国际化配置文件,抽取页面需要显示的国际化消息:

创建好三个文件后,任意打开一个文件,下面切换到 Resource Bundle 模式
可以增加属性,同时为三个文件赋值

(中文要用 ASCII 码表示,可以在 IDEA 的 File Encodings 设置里设置自动转换)

2.Spring Boot 自动配置好了管理国际化资源文件的组件:
(ResourceBundleMessageSource)

在 application 配置文件中配置:
spring.messages.basename=i18n.login

3.去页面获取国际化的值:
在页面标签中直接用 Thymeleaf 引用即可
(加入 th:text="#{login.**}"
input 标签不能加入 th,只能用行内表达式:
<input type="checkbox" value="remember-me" /> [[#{login.remember}]]

4.在页面中点击按钮切换:
Spring Boot 默认的区域信息转换器是根据请求头来定的
如果想在页面上点击按钮切换,可以自己配置信息转换器:

public class MyLocaleResolver implements LocaleResolver {

    @Override
    public Locale resolveLocale(HttpServletRequest httpServletRequest) {
        String l = httpServletRequest.getParameter("l");
        Locale locale = Locale.getDefault();
        if(!StringUtils.isEmpty(l)) {
            String[] split = l.split("_");
            locale = new Locale(split[0], split[1]);
        }

        return locale;
    }

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

    }
}

实现 LocaleResolver 接口,用 request 的 getParameter 方法获取
新 new 一个 Locale,默认为浏览器自带(getDefault)
用 StringUtils(引入的 framework 下的类)的 isEmpty 方法判断 l 是否为空
不为空的话,加入连接符 _ (String[] split = l.split(“_”);)
配置 locale = new Locale(split[0], split[1]);,返回

在 mvc 配置中加入容器:

@Bean
    public LocaleResolver localeResolver(){
        return new MyLocaleResolver();
    }

在页面显示:

<a class="btn btn-sm" th:href="@{/login.html(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/login.html(l='en_US')}">English</a>

登陆:

1.开发期间,模板引擎页面修改以后,要实时生效
(1)禁用模板引擎的缓存
spring.thymeleaf.cache=false

(2)页面修改完成以后 ctrl + F9 ,重新编译

用 th:action=@{url} 来跳转到登陆 controller
在 controller 中用 @RequestParam 传值(与 name 属性一致)
设置用户名密码相等才返回跳转
可以传一个 map<String, Object> 来保存错误信息:
map.put("msg", "用户名密码错误");

新设置一个标签,用 th:text="${msg}" 来取出错误信息
th:if="${not #strings.isEmpty(msg)}" 来判断:
<p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>

防止表单重复提交:
因为用的 post 请求,所以刷新表单会重复提交
重定向到指定成功页面即可解决

注意:不能直接重定向到 templates 文件夹里面的 html 页面
(因为 templates 文件夹是受保护的,不能直接 url 访问)
所以要重定向到一个其他的 url ,再由这个 url 转向指定的 html

衍生问题:如果重定向到一个其他的 url,那么直接访问这个 url 也可以跳转到成功页面,登陆就失去了意义
解决:拦截器进行登陆检查

如何定制错误页面:

原理:

ErrorMvcAutoConfiguration:错误处理的自动配置
容器中添加了以下组件:
1、DefaultErrorAttributes
(在页面共享信息)
2、BasicErrorController
(处理默认 /error 请求)
3、ErrorPageCustomizer
(系统出现错误后来到 /error 请求进行处理)
4、DefaultErrorViewResolver

步骤:
一旦系统出现4xx或者5xx之类的错误,ErrorPageCustomizer就会生效(定制错误的响应规则),来到 /error

如何定制错误响应:

1.有模板引擎的情况下, error/状态码,将错误页面命名为 错误状态码.html 放在模板引擎文件夹(templates 文件夹)里面的 error 文件夹下,发生此状态码错误就会来到该页面
(可以用 4xx 名称去匹配所有以 4 开头的错误状态码的错误,如果有精确的状态码页面,优先寻找精确的状态码页面,找不到才去 4xx 页面)

页面能获取的信息:
timestamp:时间戳
status:状态码
error:错误提示
exception:异常对象
message:异常消息
errors:JSR303数据校验的错误都在这里
(获得方式,用 thymeleaf 的行内写法:[[${status}]] 直接拿)

2.没模板引擎的情况下,静态资源文件夹下找(static)
3.模板引擎和静态资源文件夹下都没有,默认来到 Spring Boot 默认的错误页面

配置嵌入式 Servlet 容器:

Spring Boot 默认使用的是嵌入式的 Servlet 容器(Tomcat)

1.如何定制和修改 Servlet 容器的相关配置
1) 修改和 Servlet 有关的配置:(ServerProperties【也是 EmbeddedServletContainerCustomizer】)

server.port=8081
server.context‐path=/crud
server.tomcat.uri‐encoding=UTF‐8
//通用的Servlet容器设置
server.xxx
//Tomcat的设置
server.tomcat.xxx

2) 编写一个EmbeddedServletContainerCustomizer:嵌入式的Servlet容器的定制器;来修改Servlet容器的配置

   @Bean //一定要将这个定制器加入到容器中
    public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(){
        return new EmbeddedServletContainerCustomizer() {
            //定制嵌入式的Servlet容器相关的规则
            @Override
            public void customize(ConfigurableEmbeddedServletContainer container) {
                container.setPort(8083);
            }
        };
    }

注册 Servlet 三大组件 【Servlet、Filter、Listener】

由于 Spring Boot 默认是以 jar 包的方式启动嵌入式的 Servlet 容器来启动 web 应用,没有 web.xml 文件

注册三大组件用以下方式:
1) ServletRegistrationBean:

@Bean
    public ServletRegistrationBean myServlet() {
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(), "/servlet");

        return registrationBean;
    }

第一个是 Servlet 的 class 映射,第二个是地址映射

2)FilterRegistrationBean:
Filter:实现 Filter 接口(javax.servlet 包下的 Filter)
在过滤器中最后要执行 chain 的 doFilter 方法,将 request 和 response 传入

@Bean
    public FilterRegistrationBean myFilter() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();

        registrationBean.setFilter(new MyFilter());
        registrationBean.setUrlPatterns(Arrays.asList("/hello", "/myFilter"));

        return registrationBean;
    }

setFilter 设置 Filter 的 class
setUrlPatterns 设置访问路径
(Arrays.asList :将若干字符串集合,使其访问多重路径都可实现目的)

3)ServletListenerRegistrationBean:

Listener 要实现 ServletContextListener 接口

@Bean
    public ServletListenerRegistrationBean myListener() {
        ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener());

        return registrationBean;
    }

注意,返回的是 ServletListenerRegistrationBean
(因为其中是 web 启动和 web 停止时的处理,所以不需要 url )

Spring Boot 帮我们自动注册 Spring MVC 的前端控制器:DispatcherServlet

Docker:

Docker 是一个开源的应用容器引擎
Docker 支持将软件编译成一个镜像,然后在镜像中各种软件做好配置,将镜像发布出去,其他使用者可以使用这个镜像
运行中的镜像称为容器,容器启动时非常快速的

核心概念:

Docker 主机(Host):安装了 Docker 程序的机器(Docker 直接安装在操作系统之上)
Docker 客户端(Client):连接 Docker 主机进行操作
Docker 仓库(Registry):用来保存各种打包好的软件镜像
Docker 镜像(Images):软件打包好的镜像,放在 Docker 仓库中
Docker 容器(Container):镜像启动后的实例称为一个容器

使用 Docker 的步骤:
1. 安装 Docker
2. 去 Docker 仓库找到这个软件对应的镜像
3. 使用 Docker 运行这个镜像,这个镜像就会生成一个 Docker 容器
4. 对容器的启动停止就是对软件的启动停止

安装 Docker:

  1. 安装 Linux 虚拟机
  2. 在 Linux 虚拟机上安装 Docker

检查内核版本,必须是 3.10 及以上
uname -r
安装 Docker :
yum install docker
启动 Docker :
systemctl start docker
输入:docker -v ,如果出现版本号,说明启动成功
可以设置为开机启动:
systemctl enable docker

停止 Docker :
systemctl stop docker

镜像操作:

检索:docker search 关键字
拉取:docker pull 镜像名:tag(tag可选,多为软件的版本)
列表:docker images
删除:docker rmi image-id

Spring Boot 与数据访问:

配置:

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/jdbc?useSSL=true
    driver-class-name: com.mysql.jdbc.Driver
    schema:
     - classpath:department.sql

默认寻找文件 schema.sql 或者 schema-all.sql
可以使用:

    schema:
     - classpath:department.sql

来指定目标文件

Spring Boot 有自动配置的 JdbcTemplate 来操作数据库:

    @Autowired
    JdbcTemplate jdbcTemplate;

    @ResponseBody
    @GetMapping("/query")
    public Map<String, Object> map() {
        List<Map<String, Object>> list = jdbcTemplate.queryForList("SELECT * FROM department");
        return list.get(0);
    }

配置好 application 连接数据库,然后自动注入 JdbcTemplate,调用 query 返回查询语句,即可查询

整合 druid 数据源:

// 导入druid数据源
@Configuration
public class DruidConfig {

    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druid(){
       return  new DruidDataSource();
    }

在 yml 里配置 druid 数据源:

    type: com.alibaba.druid.pool.DruidDataSource

#   druid 初始化
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
#   配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

SSL 安全套接层:

SSL 协议分为两层:SSL 记录协议 和 SSL 握手协议
SSL 记录协议建立在可靠的传输协议上
SSL 握手协议建立在 SSL 记录协议之上

在基于 B/S 的 Web 应用中,是通过 HTTPS 来实现 SSL 的(B/S:browser/server ,浏览器与服务端模式),HTTPS 的安全基础是 SSL

使用 SSL 首先需要一个证书,在配置了 JAVA_HOME 的 bin 目录加入到 Path 后,可在控制台调用该命令:
keytool -genkey -alias tomcat
在当前目录下将生成一个 .keystore 文件

在 application.properties 中做出 SSL 的相关配置:

server.port = 8443
server.ssl.key-store = .keystore
server.ssl.key-store-password = 111111
server.ssl.keyStoreType = JKS
server.ssl.keyAlias: tomcat

关于 http 对于 https 的自动转向:

需要配置 TomcatEmbeddedServletContainerFactory,并且添加 Tomcat 的 connector 来实现
做如下配置(Configuration):

package com.example;

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.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class SpringBootHttpsApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootHttpsApplication.class, args);
    }
    @Bean
    public EmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint constraint = new SecurityConstraint();
                constraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                constraint.addCollection(collection);
                context.addConstraint(constraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(httpConnector());
        return tomcat;
    }

    @Bean
    public Connector httpConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        // Connector监听的http的端口号
        connector.setPort(8080);
        connector.setSecure(false);
        // 监听到http的端口号后转向到的https的端口号
        connector.setRedirectPort(8443);
        return connector;
    }

}

Spring data JPA 的综合运用:

小实战例子:

(开发使用 Oracle XE 数据库)
1. 对于 application.properties 的配置:

server.port=8888

spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.url=jdbc\:oracle\:thin\:@localhost\:1521\:xe
spring.datasource.username=boot
spring.datasource.password=boot

#1
spring.jpa.hibernate.ddl-auto=update
#2
spring.jpa.show-sql=true
#3
spring.jackson.serialization.indent-output=true

(因为 Oracle 管理端的端口占用8080,故使用端口8888)
连接用户名和密码为 boot 的数据库
spring.jpa.hibernate.ddl-auto=update:使实用类和数据库中的表单数据对应实时更新
spring.jpa.show-sql=true:控制台展示SQL语句
spring.jackson.serialization.indent-output=true:美观 json 数据

2. 实体类的构建:

package com.demo05.demo05.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.NamedQuery;

@Entity                         // 数据库中的实体类标注
// 给查询语句起名字
@NamedQuery(name = "Person.withNameAndAddressNamedQuery", query = "SELECT p FROM Person p where p.name=?1 and address=?2")
public class Person {
    @Id     // 表明这个属性映射为数据库的主键
    @GeneratedValue     // 默认使用主键生成方式为递增
    private Long id;

    private String name;

    private Integer age;

    private String address;

    public Person() {
        super();
    }

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

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

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

@Entity :标明实体类
@NamedQuery :为查询语句取一个名字(对应 Person 中相应的方法)
@Id :表明这个属性映射为数据库的主键
@GeneratedValue :默认使用主键生成方式为递增

3. 对于相应接口的构建:

package com.demo05.demo05.repository;

import com.demo05.demo05.model.Person;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

public interface PersonRepository extends JpaRepository<Person, Long> {
    List<Person> findByAddress(String name);

    Person findByNameAndAddress(String name, String address);

    /**
     *     @Param 注解注入参数,与 JPQL中的参数相对应
      */
    @Query("SELECT p FROM Person p where p.name= :name and p.address= :address")
    Person withNameAndAddressQuery(@Param("name")String name, @Param("address")String address);

    Person withNameAndAddressNamedQuery(String name, String address);
}

在接口中写相应方法,接口继承类 JpaRepository<Person, Long>

4. 最后构建路径对应:

package com.demo05.demo05.controller;

import com.demo05.demo05.model.Person;
import com.demo05.demo05.repository.PersonRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class DataController {

    @Autowired
    PersonRepository personRepository;

    @RequestMapping("/save")
    public Person save(String name, String address, Integer age) {

        Person p = personRepository.save(new Person(null, name, age, address));

        return p;

    }

    @RequestMapping("/q1")
    public List<Person> q1(String address) {
        List<Person> people = personRepository.findByAddress(address);

        return people;
    }

    @RequestMapping("/q2")
    public Person q2(String name, String address) {
        Person person = personRepository.findByNameAndAddress(name, address);
        return person;
    }

    @RequestMapping("/q3")
    public Person q3(String name, String address) {
        Person p = personRepository.withNameAndAddressQuery(name, address);
        return p;
    }

    @RequestMapping("/q4")
    public Person q4(String name, String address) {
        Person p = personRepository.withNameAndAddressNamedQuery(name, address);
        return p;
    }

    @RequestMapping("/sort")
    public List<Person> sort() {
        List<Person> people = personRepository.findAll(new Sort(Sort.Direction.ASC, "age"));

        return people;
    }

    @RequestMapping("/page")
    public Page<Person> page() {
        Page<Person> pagePeople = personRepository.findAll(new PageRequest(1, 2));
        return pagePeople;
    }


}

各个方法对应路径直接调用即可
(save 方法为传参后进行保存,sort 为排序,page 为分页)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值