Эта статья поможет вам изучить SpringBoot

Java

1. Введение в SpringBoot

1. Что такое Spring Boot

Справочная информация: разработка Spring громоздка, существует много файлов конфигурации, сложный процесс развертывания и сложно интегрировать сторонние фреймворки. Это снижает эффективность разработки

SpringBoot — это фреймворк, упрощающий создание и разработку приложений Spring.

​ Интегрирует весь стек технологий Spring и является универсальным решением для разработки JavaEE.

2. Зачем использовать SpringBoot

преимущество:

  • Может быстро создавать проекты Spring и интегрироваться с основными платформами.
  • Встроенный контейнер сервлетов, нет необходимости вручную развертывать военный пакет
  • Используйте стартер для управления зависимостями и контроля версий
  • Множество автоматических настроек для упрощения разработки
  • Обеспечивает мониторинг во время выполнения для готовых к производству сред.
  • XML-файл не требуется

Во-вторых, первая программа SpringBoot

1. Шаги работы

шаг:

1.1 Создайте проект jar Maven

Традиционные приложения должны создать веб-проект, затем упаковать приложение в военный пакет, а затем развернуть его в контейнере.

И SpringBoot нужно только ввести в пакет jar, в котором есть встроенный tomcat

1.2 Импорт зависимостей, связанных с SpringBoot
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.ly</groupId>
    <artifactId>springboot01-helloworld</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.9.RELEASE</version>
    </parent>

    <name>springboot01-helloworld</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
    </build>
</project>
1.3 Создать контроллер
package com.ly.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * Author: LuYi
 * Date: 2019/10/27 11:05
 * Description: 描述
 */
@Controller
public class HelloController {

    @RequestMapping("/hello")
    @ResponseBody
    public String hello(){
        return "Hello World";
    }
}
1.4 Создайте стартовый класс
package com.ly;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Author: LuYi
 * Date: 2019/10/27 11:05
 * Description: 使用@SpringBootApplication将类标注成SpringBoot应用
 */
@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

сканирование по умолчанию@SpringBootApplicationТакже можно использовать пакет, в котором находится аннотация, и его подпакеты.@ComponentScan("com.ly.controller")Аннотация для указания

1.5 Упаковка
<!--该插件可以将应用打包成一个可执行的jar包-->
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

Добавьте этот плагин, упакуйте приложение в исполняемый jar-пакет и выполните:java -jar jar文件

2. Проанализируйте HelloWorld

2.1 POM-файл
  • родительский проект

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.9.RELEASE</version>
    </parent>
    
  • Родительский проект родительского проекта: используется для управления версиями зависимостей в приложении SPRINGBOOT для контроля версий

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.1.9.RELEASE</version>
        <relativePath>../../spring-boot-dependencies</relativePath>
    </parent>
    
  • Зависимость: пройтиstarterУкажите зависимости

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

    SpringBoot предоставляет множество пускателей (стартеров), которые соответствуют разным сценариям применения, при введении этих пускателей в проект будут импортированы зависимости соответствующих сценариев.

2.2 Стартовый класс
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
  • @SpringBootApplication

    Он отмечен на классе, указывая на то, что этот класс является классом запуска SpringBoot, и приложение SpringBoot запускается через метод Main этого класса.

  • @SpringBootConfiguration

    Аннотация к классу, указывающая, что этот класс является классом конфигурации SpringBoot.

    Иерархическая связь: SpringBootConfiguration——>@Configuration——>@Component

@Configuration: аннотация к классу, указывающая, что этот класс является классом конфигурации Spring, эквивалентным файлу конфигурации XML.

  • @EnableAutoConfiguration

    включиАвтоматическая конфигурацияФункция, упрощающая предыдущую громоздкую конфигурацию

    При запуске SpringBoot значения, указанные EnableAutoConfiguration в /META-INF/spring.factories, будут добавлены в контейнер как классы автоматической конфигурации.Эти значениякласс автоконфигурацииПоможет нам выполнить большую работу по настройке.

  • @ComponentScan

    Аннотируется к классу с указанием пакета и его подпакетов для сканирования.

3. Быстро создать проект SpringBoot

1. Введение

SpringBoot быстро построить проект, используя пружинный инициализатор

2. Основные операции

  • Файл pom и основной класс программы генерируются автоматически, а бизнес-логика может быть написана напрямую.

  • Структура каталогов папки ресурсов

    |-static	存放静态资源,如js,css,images
    |-template	存放模板引擎,如freemarker、thymeleaf等
    |-application.properties	SpringBoot应用的配置文件,可以修改默认设置
    

В-четвертых, файл конфигурации

1. Введение

Для SpringBoot существует два файла глобальной конфигурации по умолчанию:

  • application.properties
  • application.yml

Имя файла фиксировано и хранится в каталоге classpath:/ или classpath:/config/

Вы можете изменить конфигурацию Spring Boot по умолчанию, см.:docs.spring.IO/весенняя загрузка…

Примечание. Конфигурации SpringBoot 2.0 и 1.0 отличаются, и некоторые элементы конфигурации были удалены.

2. Использование YAML

2.1 Введение

YAML не является языком разметки. YAML специально используется для написания файлов конфигурации. Он ориентирован на данные и имеет мощное введение. Он больше подходит для файлов конфигурации, чем xml и свойства.

Файлы YAML имеют суффикс .yml или .yaml.

2.2 application.yml
server:
  port: 8081	#写法:key: value 冒号后面必须有空格
  servlet:
    context-path: /springboot03/
2.3 Грамматические правила
  • Деликатный случай
  • Используйте отступ для обозначения иерархии
  • Клавиша Tab не разрешена при отступе
  • Количество отступов не имеет значения, но он должен быть выровнен слева от соответствующего уровня.
  • #Указывает на примечание
2.4 Основное использование

YAML поддерживает три структуры данных:

  • Литерал: одно неделимое значение (строка, число, логическое значение)
  • Объект: набор пар ключ-значение.
  • массив: набор значений по порядку

Использование трех структур данных:

1. Литералы: обычные значения, такие как числа, строки, логические значения.

number: 12.5
str: hello
name: 'tom cruise' #如字符串包含空格及特殊字符需要使用 引号 引起来
name: 'tom \n cruise' #不会对特殊字符进行转义 结果为:tom 换行 cruise
name: "tom \n cruise" #对特殊字符进行转义,会作为普通字符输出, 结果为 tom \n cruise
  1. Объекты, также известные как Карты, содержат свойства и значения.

    # 写法1:换行写
    user:
      name: tom
      age: 20
      sex: male
      
    # 写法2:行内写法
    user: {name: tom, age: 20, sex: male}
    
    1. Массивы, такие как List, Set и т. д.
    # 写法1: 一组短横线开头的行
    names: 
      - tom
      - jack
      - alice
      
    # 写法2: 行内写法
    name: {tom,jack,alice}
    

3. Введите значения для свойств

Внедрить значения свойств в класс, загрузив файл конфигурации

3.1 Написание application.yml
user:
  username: admin
  age: 21
  status: true
  birthday: 2019/2/14
  address:
    province: 黑龙江省
    city: 哈尔滨市
  lists:
    - list1
    - list2
    - list3
  maps: {k1: v1,k2: v2}
3.2 Создание класса сущностей

User

package com.luyi.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Author: LuYi
 * Date: 2019/10/27 13:49
 * Description: 通过加载配置文件为当前类中的属性注入值
 */
// 必须将当前类加入到容器
@Component
// 默认读取全局配置文件获取值,当前类中的所有属性与 user 进行绑定
@ConfigurationProperties(value = "user")
public class User {

    private String username;
    private Integer age;
    private Boolean status;
    private Date birthday;
    private Address address;
    private List<String> lists;
    private Map<String, Object> maps;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getAge() {
        return age;
    }

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

    public Boolean getStatus() {
        return status;
    }

    public void setStatus(Boolean status) {
        this.status = status;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public Address getAddress() {
        return address;
    }

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

    public List<String> getLists() {
        return lists;
    }

    public void setLists(List<String> lists) {
        this.lists = lists;
    }

    public Map<String, Object> getMaps() {
        return maps;
    }

    public void setMaps(Map<String, Object> maps) {
        this.maps = maps;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", age=" + age +
                ", status=" + status +
                ", birthday=" + birthday +
                ", address=" + address +
                ", lists=" + lists +
                ", maps=" + maps +
                '}';
    }
}

Address

package com.luyi.bean;

/**
 * Author: LuYi
 * Date: 2019/10/27 13:50
 * Description: 描述
 */
public class Address {

    private String province;
    private String city;

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    @Override
    public String toString() {
        return "Address{" +
                "province='" + province + '\'' +
                ", city='" + city + '\'' +
                '}';
    }
}

3.3 Тестирование
package com.luyi.springboot03config;

import com.luyi.bean.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class Springboot03ConfigApplicationTests {

    @Autowired
    private User user;

    @Test
    void contextLoads() {
        System.out.println(user);
    }

}
3.4 Добавьте зависимости процессора файла конфигурации (необязательно)
<!--配置文件处理器,自动生成元数据信息,编写配置文件会有提示-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
3.5 Использование файла конфигурации свойств
user.username=alice
user.age=22
user.status=false
user.birthday=2019/10/27
user.address.province=黑龙江省
user.address.city=哈尔滨
user.lists=list1,list2,list3
user.maps.k1=v1
user.maps.k2=v2

Примечание. Кодировка UTF-8 используется по умолчанию в IDEA, а в файле свойств по умолчанию используется кодировка ASCII, поэтому есть искажения, которые можно устранить.

Приоритет: свойства> YML

3.6 Внедрение значений с помощью аннотации @Value
@Value("${user.username}")
private String username;
@Value("${user.age}")
private Integer age;
@Value("${user.status}")
private Boolean status;
@Value("${user.birthday}")
private Date birthday;
//@Value不支持复杂类型封装
private Address address;
@Value("${user.lists}")
private List<String> lists;
private Map<String, Object> maps;

Сравните @Value с @ConfigurationProperties:

  • Первый можно вводить только с одним значением, а второй можно вводить партиями.
  • Первый не поддерживает инкапсуляцию для сложных типов, второй поддерживает

4. Конфигурация многорекония

Различная информация о конфигурации может быть предоставлена ​​для различных сред, таких как среда разработки, тестовая среда, производственная среда и т. Д.

Два пути:

  • Создать несколько файлов свойств
  • определить блок документации yml
4.1 Создание нескольких файлов свойств

шаг:

​ 1. Создайте файлы свойств для разных сред

Имя файла должно соответствовать формату копия-xxx.properties

Application-dev.properties.

server.port=9991

приложение-test.properties

server.port=9992

приложение-prod.properties

server.port=9993

​ 2. Укажите конфигурацию, которую необходимо активировать в application.properties

#指定要激活的配置
spring.profiles.active=prod
4.2 Определение блока документации yml

​ 1. Используйте три тире, чтобы определить несколько блоков документов в yml

spring:
  profiles: dev
server:
  port: 9991
---
spring:
  profiles: test
server:
  port: 9992
---
spring:
  profiles: prod
server:
  port: 9993

​ 2. Укажите среду для активации в первом блоке документа

spring:
  profiles:
    active: test
---

5. Загрузите внешние файлы конфигурации

5.1 Загрузите файл свойств свойств

​ Вопрос: @ConfigurationProperties по умолчанию считывает значение из файла глобальной конфигурации.Что делать, если вы хотите получить значение из файла пользовательских свойств?

Решение: используйте аннотацию @PropertySource для загрузки внешних файлов свойств.

// 必须将当前类加入到容器
@Component
//加载外部的属性文件
@PropertySource({"classpath:user.properties"})
// 默认读取全局配置文件获取值,当前类中的所有属性与 user 进行绑定
@ConfigurationProperties(value = "user")
public class User{
5.2 Загрузите файл конфигурации Spring

​ Вопрос: Если есть информация, которую нужно записать в файл xml, что мне делать, если я хочу загрузить файл xml

Решение: используйте @ImportResource для загрузки внешних файлов конфигурации.

5.3 Добавление компонентов с помощью аннотаций

Рекомендуется использовать полную аннотацию для добавления компонентов в контейнер Spring, @Configuration и @Bean.

/**
 * Author: LuYi
 * Date: 2019/10/28 14:49
 * Description: 描述
 */
//添加在类上,表示这个类是一个配置类,相当于spring配置文件
@Configuration
public class SpringConfig {

    //标注在方法上,用来向容器中添加组件,将方法的返回值添加到容器中,方法名作为bean的id
    @Bean
    public Address address(){
        Address address = new Address();
        address.setProvince("山东");
        address.setCity("日照");
        return address;
    }
}

Пять, принцип автоматической настройки SpringBoot

1. Процесс исполнения

1. SpringBoot загружает основной класс конфигурации при запуске и использует @EnableAutoConfiguration для включения функции автоматической настройки.

​ 2. @Import({AutoConfigurationImportSelector.class}) используется в @EnableAutoConfiguration для добавления в контейнер некоторых компонентов (классов автоматической настройки).

Просмотрите метод selectImports в классе AutoConfigurationImportSelector, а затем щелкните метод `getCandidateConfigurations в методе getAutoConfigurationEntry.

Загружается в SpringFactory с помощью метода loadFactoryNames в getCandidateConfigurations,

Затем загрузите через classLoaderMETA-INF/spring.factoriesконфигурации, получите значение, соответствующее EnableAutoConfiguration (spring-boot-autoconfigure-2.1.9.RELEASE.jar) из конфигурации.

Добавьте эти классы автоконфигурации (xxxAutoConfiguration) в контейнер.

​ 3. Завершите функцию автоматической настройки через класс автоматической настройки.

2. Принципиальный анализ

Например, к httpenCodingautoconfigguration, ранее настроен в Web.xml HARDERENCODINGFILTER FILTER

//表示这是一个配置类,相当于以前编写的Spring配置文件
@Configuration
//启用HttpProperties类的ConfigurationProperties功能,通过配置文件为属性注入值,并将其添加到容器中
@EnableConfigurationProperties({HttpProperties.class})
//当该应用是web应用时才生效
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
//必须包含CharacterEncodingFilter类才生效
@ConditionalOnClass({CharacterEncodingFilter.class})
//如果配置文件中有spring.http.encoding选项则该配置生效,否则不生效。但是默认已经生效了
@ConditionalOnProperty(
    prefix = "spring.http.encoding",
    value = {"enabled"},
    matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
    private final Encoding properties;
	
    //将容器中的HttpProperties注入
    public HttpEncodingAutoConfiguration(HttpProperties properties) {
        this.properties = properties.getEncoding();
    }

    //将返回的filter添加到容器中,作为bean
    @Bean
    //如果容器中没有这个bean才会生效
    @ConditionalOnMissingBean
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
        return filter;
    }
//从配置文件中获取指定的值,然后绑定到指定的属性值
@ConfigurationProperties(
    prefix = "spring.http"
)
public class HttpProperties {
    private Charset charset;
    private Boolean force;
    private Boolean forceRequest;
    private Boolean forceResponse;
    private Map<Locale, Charset> mapping;

Уведомление:

  • Судя по текущей ситуации, решите, производится ли класс конфигурации или нет.Если условия не соблюдены, автоматическая конфигурация не вступит в силу.
  • Свойства класса автоматической настройки xxAutoConfiguration получаются из соответствующего класса xxProperties
  • Информация в классе xxProperties вводится и связывается через файл конфигурации, а значение атрибута может быть указано через файл конфигурации.

3. Резюме

  • SpringBoot загружает большое количество классов автоматической настройки при запуске
  • Добавление компонентов в контейнер через автоконфигурацию
  • Благодаря этим компонентам многие функции автоматизированы, что упрощает настройку.

Вы можете проверить соответствие классов автоконфигурации, включив режим отладки

#开启debug模式
debug=true

6. Веб-разработка

1. Введение

Шаги по разработке веб-приложений с помощью SpringBoot:

​ 1. Создайте проект SpringBoot и добавьте соответствующий стартер

​ 2. Укажите необходимый небольшой объем конфигурации в конфигурационном файле

3. Напишите бизнес-код

Класс автоматической настройки веб-разработки WebMvcAutoConfiguration

2. Картирование статических ресурсов

2.1 Статическое местоположение ресурсов

Просмотр WebMvcAutoConfiguration——> addResourceHandlers()——>getStaticLocations()——>staticLocations

Расположение по умолчанию для статических ресурсов

"classpath:/META-INF/resources/",
"classpath:/resources/", 
"classpath:/static/", 
"classpath:/public/"

Доступ к статическим ресурсам можно получить через указанную выше папку.

Вы также можете самостоятельно указать доступное местоположение в файле конфигурации.

# 指定静态资源的位置 存放在根目录下的public文件夹中
spring.resources.static-locations=classpath:/public
2.2 Страница приветствия

Просмотр WebMvcAutoConfiguration->welcomePageHandlerMapping() -> getWelcomePage()

Поместите страницу index.html в любую папку статических ресурсов.

2.3 Иконки веб-сайтов

Просмотр WebMvcAutoConfiguration—> Внутренний класс FaviconConfiguration—> faviconHandlerMapping

Поместите favicon.ico в любую папку статических ресурсов

Семь, шаблонизатор

1. Введение

В настоящее время рекомендуется использовать механизм шаблонов для веб-разработки на Java, и не рекомендуется использовать страницы jsp.

  • Недостатки jsp: По сути, сервлет необходимо компилировать в фоновом режиме, что менее эффективно.
  • Механизм шаблонов: не нужно компилировать, быстро

Часто используемые шаблонизаторы: Freemarker, Thymeleaf и т. д.

SpringBoot рекомендует Thymeleaf и по умолчанию не поддерживает jsp, потому что jsp должен быть упакован как военный пакет.

Дополнение: текущее Mainstream Web Development рекомендует разделение передних и задних концов, и передний конец использует MVVM Framework, Vue.js, угловые, реагирующие и т. Д.

2. Использование тимьяна

шаг:

​ 1. Добавьте зависимости Thymeleaf

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

​ 2. Поместите html-страницу под шаблоны

К HTML-коду в шаблонах нельзя получить прямой доступ. Вам нужно использовать контроллер, чтобы перейти и отобразить его с помощью Thymeleaf.

ThymeleaPautoconfiguration-> Thymeleafproperties.

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

Префикс SLICING по умолчанию и суффикс

3. Используйте тимьян

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h2>success</h2>
    <!--使用th:text属性设置元素中的文本,表达式:${}可以获取作用域中的数据-->
    <p th:text="${name}"></p>
</body>
</html>

4. После изменения страницы позвольте ему вступить в силу в режиме реального времени.

​ Поскольку тимелеаф по умолчанию включает кеширование, отключите кеширование

#禁用thymeleaf的缓存
spring.thymeleaf.cache=false

Дополнение: Также необходимо включить автоматическую компиляцию идеи, идея не будет компилироваться автоматически при сохранении по умолчанию.

3. Грамматические правила

3.1 Общие свойства
  • й:текст, й:uтекст

    Установите текстовое содержимое в элементе

    th:text экранирует специальные символы, эквивалентные встроенным [[${ }]]

    TH: otext не избежать специальных символов, эквивалентных встроенному [($ {})]]

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <!--th:text、th:utext-->
        <div th:text="${hello}">aaa</div>
        <div th:utext="${hello}">bbb</div>
    
        <!--使用内联方式,可以在文本前后添加内容-->
        <div>[[${hello}]]aaa</div>
        <div>[(${hello})]bbb</div>
    </body>
    </html>
    
  • TH: нативные свойства HTML

    Используется для замены значения указанного собственного атрибута html.

    @RequestMapping("/test2")
    public String test2(Model model){
        model.addAttribute("hello", "<mark>你好</mark>");
    
        model.addAttribute("id", "mydiv");
        model.addAttribute("title", "this is a div");
        return "result";
    }
    
    <!--th:html原生属性-->
    <div id="div1" title="这是一个div" th:id="${id}" th:title="${title}">div</div>
    
  • й:если, й:если, й:переключатель, й:случай

    Условное суждение, подобное if

    <!--th:if、th:unless、th:switch、th:case-->
    <div th:if="${age>=18}">成年</div>
    <p th:unless="${age<18}">成年</p>
    <p th:switch="${role}">
        <span th:case="student">学生</span>
        <span th:case="teacher">老师</span>
        <span th:case="*">其他</span>
    </p>
    <hr>
    
  • th:each

    петля, аналогичная для каждого

    <!--th:each-->
    <ul>
        <li th:each="name:${names}" th:text="${name}"></li>
    </ul>
    
  • th: объект, th: поле

    Для привязки объектов данных формы привяжите форму к параметру JavaBean контроллера, часто с th:field

    Используется вместе, его необходимо использовать в сочетании с выражением выбора * {}

    <!--th:object、th:field-->
    <h2>修改用户信息</h2>
    <!--th:object指定对象,th:field指定属性-->
    <form action="modify" method="post" th:object="${user}">
        编号:<input type="text" th:field="*{id}" readonly> <br>
        姓名:<input type="text" th:field="*{name}"> <br>
        年龄:<input type="text" th:field="*{age}"> <br>
        <input type="submit" value="修改">
    </form>
    
  • th:fragment

    Объявите фрагменты кода, часто используемые для представления верхнего и нижнего колонтитула страницы.

    <!--th:fragment-->
    <header th:fragment="head">
        这是页面的头部,导航
    </header>
    
  • й: включить, й: вставить, й: заменить

    Добавьте фрагменты кода, похожие на jsp:include.

    <!--th:include、th:insert、th:replace-->
    <!--引入templates/include下的header.html页面中的fragment为head的片段-->
    <div th:include="include/header::head"></div>
    

    разница между тремя

    th:include сохранит свои собственные теги, а не теги th:fragment (устарели после Thymeleaf 3.0)

    th:insert сохраняет свою собственную метку, а также сохраняет метку th:fragment

    th:relpace не сохраняет собственную метку, сохраните метку thfragment

3.2 выражения
  • ${} переменное выражение

    Получить свойства и методы объекта

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <!--获取对象的属性、方法-->
        <div th:text="${user.name}"></div>
        <div th:text="${user['age']}"></div>
        <div th:text="${users[1].name}"></div>
        <!--<div th:text="${users.size()}"></div>-->
        <div>[[${users.size()}]]个</div>
    </body>
    </html>
    

    Используйте встроенные базовые объекты, такие как сеанс и приложение.

    <!--使用内置基本对象-->
    <div th:text="${session.sex}"></div>
    <div th:text="${application.hobby}"></div>
    

    Используйте встроенные служебные объекты, такие как #strings, #dates, #arrays, #lists, #maps и т. д.

    <!--使用内置的工具对象-->
    <div th:text="${#strings.startsWith(user.name, 't')}"></div>
    <div th:text="${#strings.substring(user.name, 0, 2)}"></div>
    <div th:text="${#strings.length(user.name)}"></div>
    
    <div th:text="${#dates.createNow()}"></div>
    <div th:text="${#dates.create(2018, 10, 14)}"></div>
    <div th:text="${#dates.format(birthday, 'yyyy-MM-dd HH:mm:ss')}"></div>
    
  • } * {Выберите выражение (выражение звездочка)

    <!--*{}选择表达式-->
    <div th:object="${user}">
        <div th:text="*{id}"></div>
        <div th:text="*{name}"></div>
        <div th:text="*{age}"></div>
    </div>
    
  • @{} URL-выражение

    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <!--url表达式引入css文件-->
        <link rel="stylesheet" th:href="@{/css/style.css}">
    </head>
    <!--url表达式-->
    <a th:href="@{/findUser(name=${user.name})}">查询指定的用户信息</a>
    <a href="product/list.html" th:href="@{/product/list}">商品列表</a>
    <script th:src="@{/js/common.js}"></script>
    
  • оператор

    eq gt le == != тернарный оператор

4. Горячее развертывание

Используйте инструменты разработки, предоставляемые SpringBoot, для горячего развертывания.

Принцип: мониторинг изменений в файлах в пути к классам в режиме реального времени, автоматический перезапуск в случае изменений.

настроить: добавить зависимости devtools

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <!--该依赖不传递-->
    <optional>true</optional>
</dependency>

Восемь, расширьте функцию SpringMVC по умолчанию.

1. Введение

Ранее в SpringMVC переходы между представлениями и перехватчики можно было выполнять с помощью следующего кода:

<mvc:view-controller path="/showLogin" view-name="login"/>
<mvc:interceptors>
	<mvc:interceptor>
        <mvc:mapping path="/hello"/>
    	<bean class="com.luyi.interceptor.HelloInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

Конфигурация SpringBoot по умолчанию не предоставляет вышеуказанных функций по умолчанию, вам необходимо расширить ее самостоятельно, используя интерфейс WebMvcConfigurer

2. Основные операции

Шаги:

1. Определите класс конфигурации, реализующий интерфейс WebMvcConfigurer.

2. Реализовать требуемый метод

/**
 * Author: LuYi
 * Date: 2019/10/29 17:58
 * Description: 扩展默认的SpringMVC的功能
 * 要求:
 * 1.将该类标记为配置类
 * 2.实现WebMvcConfigurer接口
 * 3.根据需要实现接口中相应的方法
 *
 * 注意:这个接口中的方法都添加了jdk1.8中的default方法修饰,不强制实现所有方法(jdk1.8新特性)
 * 在SpringBoot1.0中是继承WebMvcConfigurerAdapter类,SpringBoot2.0是基于jdk1.8的,
 * 所以通过实现WebMvcConfigurer的方式
 */
//将该类设置为配置类
@Configuration
public class CustomMvcConfig implements WebMvcConfigurer {

    //添加ViewController
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //将访问login页面的url设置为showLogin
        registry.addViewController("/showLogin").setViewName("login");
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**")
                .excludePathPatterns("/test2");
    }
}

9. Глобальная обработка исключений

1. Введение

Когда в программе возникает исключение, выполняется глобальная обработка.Информация об исключении SpringBoot по умолчанию запрашивает:Whitelabel Error Page

Два пути:

  • Определить кодовую страницу ошибки
  • Определить уведомление об исключении

2. Определите кодовую страницу ошибки

Создать错误状态码.htmlстраницу, поместите ее в каталог templates/error, при возникновении ошибки он автоматически перейдет в этот каталог, чтобы найти соответствующую страницу ошибки

можно создать например4xx.htmlили5xx.htmlстраницу, чтобы сопоставить все ошибки этого типа (предпочтительнее будут точные совпадения

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h2>5xx错误</h2>
    <h3>状态码:[[${status}]]</h3>
    <h3>异常消息:[[${message}]]</h3>
    <h3>错误提示:[[${error}]]</h3>
    <h3>时间戳:[[${timestamp}]]</h3>
</body>
</html>

3. Определите уведомление об исключении

/**
 * Author: LuYi
 * Date: 2019/10/29 18:45
 * Description: 异常通知:用来处理全局异常
 */
@ControllerAdvice
public class ExceptionAdvice {

    @ExceptionHandler(ArithmeticException.class)
    public String arithmetic(Exception e){
        System.out.println("警报:程序出现异常,发短信:" + e.getMessage());
        return "error/5xx";
    }

    @ExceptionHandler(Exception.class)
    public String exception(Exception e){
        System.out.println("警报:程序出现异常,发邮件:" + e.getMessage());
        return "error/5xx";
    }
}

10. О контейнерах сервлетов

1. Введение

SpringBoot по умолчанию имеет встроенный сервлет: Tomcat

​ Вопрос: SpringBoot по умолчанию запускает встроенный контейнер Servlet как jar-пакет.Файла web.xml нет.Как зарегистрировать три компонента сервлета: Servlet, Filter, Listener

Решение: настроив конфигурацию сервлета, используйте ServletRegistrationBean, FilterRegistrationBean, ServletListenerRegistrationBean.

2. Зарегистрируйте компонент сервлета

Шаги:

​ 1. Определите класс конфигурации

2. Настройте способ зарегистрировать компонент

/**
 * Author: LuYi
 * Date: 2019/10/29 19:12
 * Description: 自定义Servlet配置
 */
//将该类声明为配置类
@Configuration
public class CustomServletConfig {

    //将方法返回值放到Spring容器
    @Bean
    public ServletRegistrationBean myServlet(){
        ServletRegistrationBean<Servlet> registrationBean = new ServletRegistrationBean<>();
        //对MyServlet进行注册
        registrationBean.setServlet(new MyServlet());
        ArrayList<String> urls = new ArrayList<>();
        urls.add("/myServlet");
        registrationBean.setUrlMappings(urls);

        return registrationBean;
    }

    //注册Filter
    @Bean
    public FilterRegistrationBean myFilter(){
        FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
        //注册filter
        registrationBean.setFilter(new MyFilter());
        registrationBean.addUrlPatterns("/showLogin", "/test1");
        return registrationBean;
    }

    //注册Listener
    @Bean
    public ServletListenerRegistrationBean myListener(){
        ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>();
        registrationBean.setListener(new MyListener());
        return registrationBean;
    }
}

3. Используйте внешний контейнер сервлета

3.1 Преимущества и недостатки

Используя встроенный контейнер сервлетов:

​ Преимущества: простота в использовании, упаковать приложение в пакет jar

​ Недостатки: не поддерживает jsp, низкая настраиваемость

Использование внешнего контейнера сервлета

​ Преимущества: поддержка jsp, широкие возможности настройки

​ Недостатки: нужно упаковать приложение в военный пакет

3.2 Этапы работы

Шаги:

​ 1. Создайте военный проект Maven

Есть следующие три изменения

​ 1. Способ упаковки становится войной

<packaging>war</packaging>

​ 2. Настройте встроенную область действия tomcat, как указано

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <scope>provided</scope>
</dependency>

3. Определяет подкласс SpringBootServletInitializer.

/**
 * 要求:
 * 1.必须继承SpringBootServletInitializer
 * 2.重写configure()方法
 * 3.调用SpringApplicationBuilder的sources()方法,传入主程序类的
 */
public class ServletInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Springboot05WarApplication.class);
    }

}

2. Создайте структуру веб-каталога

​ 3. Настройте префикс и суффикс

spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp

4. Настройте Tomcat

Чтобы использовать версию Tomcat, необходимую для SpringBoot

Одиннадцать, доступ к данным SpringBoot

1.JDBC

Шаги:

​ 1. Создайте проект и выберите следующие шаблоны: web, jdbc, mysql

​ 2. Настройте информацию о подключении к базе данных

#指定数据库连接参数
spring.datasource.driver-class-name= com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root

#指定数据源
spring.datasource.type=org.apache.commons.dbcp.BasicDataSource

3. Тест

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
class Springboot06JdbcApplicationTests {

    @Autowired
    private DataSource dataSource;

    @Test
    void contextLoads() throws SQLException {
        System.out.println("---------------------------");
        System.out.println("DataSource的类型: " + dataSource.getClass());
        System.out.println("Connection的连接: " + dataSource.getConnection());
    }

}

4. Настройте параметры пула соединений

spring.datasource.initialSize=10
spring.datasource.maxActive=100
spring.datasource.minIdle=5
spring.datasource.maxWait=50000

​ Проблема: Добавление вышеуказанных параметров не вступает в силу, так как SpringBoot не поддерживает эти параметры по умолчанию (DataSourceProperties)

Решение: Пользовательская конфигурация источника данных

/**
 * Author: LuYi
 * Date: 2019/10/30 16:09
 * Description: 描述
 */
@Configuration
public class DatasourceConfig {

    @Bean
    //从配置文件中读取spring.datasource属性,并注入给数据源的属性
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource(){
        return new BasicDataSource();
    }
}

​ 5. Используйте JdbcTemplate для работы с базой данных

/**
 * Author: LuYi
 * Date: 2019/10/30 16:17
 * Description: 描述
 */
@Controller
@RequestMapping("/user")
public class UserController {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @RequestMapping("/findAll")
    @ResponseBody
    public List<Map<String, Object>> findAll(){
        String sql = "select * from t_user";
        List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
        return list;
    }
}

2.MyBatis

2.1 Основные шаги

​ 1. Для создания проекта сначала выберите следующие модули: web, mybatis

​ 2. Настройте источник данных

#配置DataSource
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root
    initialSize: 5
    maxActive: 100
    minIdle: 3
    maxWait: 50000
#配置MyBatis
mybatis:
    type-aliases-package: com.luyi.pojo
    mapper-locations: classpath:mapper/*.xml

​ 3. Напишите Mapper, Service, Controller

​ 4. Настройте класс конфигурации MyBatisConfig

/**
 * Author: LuYi
 * Date: 2019/10/30 16:57
 * Description: 描述
 */
@Configuration
//扫描MyBatis接口所在的包
@MapperScan("com.luyi.mapper")
public class MyBatisConfig {

    @Bean
    //加载主配置文件,注入配置信息
    @ConfigurationProperties(prefix = "spring.datasource")
    public DruidDataSource druidDataSource(){
        return new DruidDataSource();
    }
}

2.2 Настройка плагина подкачки PageHelper

Шаги:

​ 1. Добавьте зависимость PageHelper

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.2.10</version>
</dependency>

​ 2. Настройте свойства PageHelper

#配置PageHelper
pagehelper:
  helper-dialect: mysql

​ 3. Используйте PageHelper

@Override
public PageInfo<User> findByPage(int pageNum, int pageSize) {

    //使用PageHelper设置分页
    PageHelper.startPage(pageNum, pageSize);

    List<User> users = userMapper.selectAll();

    PageInfo<User> pageInfo = new PageInfo<>(users);

    return pageInfo;
}
2.3 Использование MyBatis Plus

Ссылка:mp.baomidou.com/

Шаги:

​ 1. Добавьте зависимость MyBatis Plus

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.1.0</version>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.20</version>
</dependency>

2. Настройте глобальный файл конфигурации

#配置DataSource
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root
    initialSize: 5
    maxActive: 100
    minIdle: 3
    maxWait: 50000
#配置MyBatis Plus
mybatis-plus:
  mapper-locations: classpath:mapper/*Mapper.xml
  type-aliases-package: com.luyi.pojo
  global-config:
    db-config:
      #主键类型
      id-type: auto
      #字段策略
      field-strategy: not_empty
      #驼峰下划线转换
      table-underline: true
      #全局表前缀
      table-prefix: t_
      #刷新mapper神器
      refresh-mapper: true

​ 3 Настройка MyBatis Plus

/**
 * Author: LuYi
 * Date: 2019/10/31 9:59
 * Description: 描述
 */
@Configuration
@MapperScan("com.luyi.mapper")
public class MyBatisPlusConfig {

    /**
     * 分页插件,自动识别数据库类型
     * @return
     */
    @Bean
    public PaginationInterceptor paginationInterceptor(){
        return new PaginationInterceptor();
    }

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

4. Написать Mapper, унаследовать BaseMapper

/**
 * Author: LuYi
 * Date: 2019/10/31 10:07
 * Description: 继承BaseMapper接口
 */
public interface UserMapper extends BaseMapper<User> {
}

5. Тест

@RunWith(SpringRunner.class)
@SpringBootTest
class Springboot08MpApplicationTests {

    @Autowired
    private UserMapper userMapper;

    @Test
    void contextLoads() {
    }

    @Test
    public void add(){
        User user = new User();
        user.setUsername("xxx");
        user.setPassword("111");
        userMapper.insert(user);
        System.out.println("-------------" + user);
    }

    @Test
    public void removeById(){
        int i = userMapper.deleteById(3);
        System.out.println(i);
    }

    @Test
    public void modifyById(){
        User user = new User();
        user.setId(6);
        user.setUsername("zhangsan");
        user.setPassword("123");
        userMapper.updateById(user);
    }

    @Test
    public void findById(){
        User user = userMapper.selectById(1);
        System.out.println(user);
    }

    @Test
    public void findByCondition(){
        //定义条件构造器,用来封装查询条件
        QueryWrapper<User> wrapper = new QueryWrapper<>();
//        wrapper.eq("username", "tom");
        wrapper.like("username", "%a%");
        List<User> users = userMapper.selectList(wrapper);
        for (User user : users) {
            System.out.println(user);
        }
    }

    @Test
    public void findByPage(){
        Page<User> page = new Page<>(2, 2);
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        IPage<User> userIPage = userMapper.selectPage(page, wrapper.select("id", "username", "password"));
        assertThat(page).isSameAs(userIPage);
        System.out.println("总条数---->" + userIPage.getTotal());
        System.out.println("当前页数---->" + userIPage.getCurrent());
        System.out.println("当前每页显示数---->" + userIPage.getSize());
        System.out.println(userIPage.getRecords());
        System.out.println("----------自带分页----------");
    }

}

Добавлено: использование ломбока.

шаг:

​ 1. Добавьте зависимости

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.8</version>
    <scope>provided</scope>
</dependency>

​ 2. Используйте аннотации, предоставленные lombok

/**
 * Author: LuYi
 * Date: 2019/10/30 16:32
 * Description: Lombok的使用
 * Lombok提供了许多注解,标注在类上或者属性上
 */
@Getter
@Setter
@ToString
@Data   //相当于以上注解
@TableName(value = "t_user")    //指定当前数据库表的名称
public class User implements Serializable {

    private Integer id;
    private String username;
    private String password;
}

​ 3. Установите плагин lombok в Idea

Поскольку в исходном коде нет определения геттера/сеттера, Idea не может его распознать, вы можете установить плагин lombok, чтобы решить эту проблему.

12. SpringBoot интегрирует Redis

1. Введение

Redis — это база данных в памяти, которую можно использовать в качестве кэша, промежуточного программного обеспечения сообщений, базы данных «ключ-значение» и т. д.

2. Операция

Шаги:

​ 1. Добавьте зависимости

Примечание. Клиент Redis, используемый в SpringBoot1.0, — это Jedis, а Lettuce используется в SpringBoot2.0.

<!--整合Redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <!--SpringBoot2.0使用的Redis客户端时Lettuce-->
    <exclusions>
        <exclusion>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>

​ 2. Настройте Redis

#redis配置
spring.redis.host=192.168.52.128
spring.redis.port=6379
spring.redis.database=0
spring.redis.jedis.pool.max-active=100
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.min-idle=3

​ 3. Основное использование

Используйте классы инструментов, предоставляемые SpringDataRedis: StringRedisTemplate, RedisTemplate.

Инкапсулировать JsonUtils

/**
 * Author: LuYi
 * Date: 2019/10/31 17:37
 * Description: Json工具类,基于jackson
 */
public class JsonUtils {

    //获取jackson对象
    private static ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 将对象转换为Json字符串
     */
    public static String objectToJson(Object obj){
        try {
            //将对象转换为Json字符串
            String jsonStr = objectMapper.writeValueAsString(obj);
            return jsonStr;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将Json字符串转换为对象
     */
    public static <T> T jsonToObject(String jsonStr, Class<T> clazz){
        try {
            T t = objectMapper.readValue(jsonStr, clazz);
            return t;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
}

тест

@RunWith(SpringRunner.class)
@SpringBootTest
public class Springboot09RedisApplicationTests {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Test
    public void contextLoads() {
    }

    /**
     * 使用StringRedisTemplate
     * Redis数据类型:String、List、Set、ZSet、Hash
     */
    @Test
    public void test1(){
        /**
         * 操作redis
         */
//        ValueOperations<String, String> value = stringRedisTemplate.opsForValue();
//        ListOperations<String, String> list = stringRedisTemplate.opsForList();
//        SetOperations<String, String> set = stringRedisTemplate.opsForSet();
//        ZSetOperations<String, String> zset = stringRedisTemplate.opsForZSet();
//        HashOperations<String, Object, Object> hash = stringRedisTemplate.opsForHash();

        /**
         * 操作String
         */
//        stringRedisTemplate.opsForValue().set("username", "admin");
//        System.out.println(stringRedisTemplate.opsForValue().get("username"));

        /**
         * 操作List
         */
//        stringRedisTemplate.opsForList().leftPush("name", "tom");
//        stringRedisTemplate.opsForList().leftPushAll("name", "aaa", "bbb", "ccc");
//        System.out.println(stringRedisTemplate.opsForList().range("name", 0, -1));

        /**
         * 存储对象
         */
        User user = new User();
        user.setId(1001);
        user.setUsername("tom");
        user.setPassword("123");

        //将对象转换为json格式
        String jsonStr = JsonUtils.objectToJson(user);
        System.out.println(jsonStr);

        stringRedisTemplate.opsForValue().set("user", jsonStr);

        //获取jsonStr
        String str = stringRedisTemplate.opsForValue().get("user");

        //将str转换为对象
        User u = JsonUtils.jsonToObject(str, User.class);
        System.out.println(u);
    }

    /**
     * 使用redisTemplate
     */
    @Test
    public void test2(){
        redisTemplate.opsForValue().set("sex", "male");
        String sex = redisTemplate.opsForValue().get("sex");
        System.out.println(sex);
    }

}