SpringBoot
2022-01-24 20:16:39 75 举报
AI智能生成
SpringBoot学习的大致流程
作者其他创作
大纲/内容
框架入门
前言
Spring优点:
1、使用Spring的IOC容器,将对象之间的依赖关系交给Spring,降低组件之间的耦合性,让我们更专注于应用逻辑。
2、提供众多服务、事务管理、WS等。
3、AOP的很好支持,方便面向切面编程。
4、对主流框架提供了很好的集成支持:如Hibernate、Struts2、JPA等
5、Spring DI机制降低了业务对象替换的复杂性。
6、Spring属于低侵入,代码污染极低。
7、Spring的高度可开放性,并不强制依赖于Spring,开发者可自由选择部分或全部。
1、使用Spring的IOC容器,将对象之间的依赖关系交给Spring,降低组件之间的耦合性,让我们更专注于应用逻辑。
2、提供众多服务、事务管理、WS等。
3、AOP的很好支持,方便面向切面编程。
4、对主流框架提供了很好的集成支持:如Hibernate、Struts2、JPA等
5、Spring DI机制降低了业务对象替换的复杂性。
6、Spring属于低侵入,代码污染极低。
7、Spring的高度可开放性,并不强制依赖于Spring,开发者可自由选择部分或全部。
Spring缺点:
虽然Spring的组件代码是轻量级的,但它的配置却是重量级的。一开始,Spring用XML配置,而且是很多XML配置。Spring 2.5引入了基于注解的组件扫描,这消除了大量针对应用程序自身组件的显式XML配置。Spring 3.0引入了基于Java的配置,这是一种类型安全的可重构配置方式,可以代替XML。(配置代表开发时损耗)
除此之外,项目的依赖管理也是一件耗时耗力的事情。在环境搭建时,需要分析要导入哪些库的坐标,而且还需要分析导入与之有依赖关系的其他库的坐标,一旦选错了依赖的版本,随之而来的不兼容问题就会严重阻碍项目的开发进度。
虽然Spring的组件代码是轻量级的,但它的配置却是重量级的。一开始,Spring用XML配置,而且是很多XML配置。Spring 2.5引入了基于注解的组件扫描,这消除了大量针对应用程序自身组件的显式XML配置。Spring 3.0引入了基于Java的配置,这是一种类型安全的可重构配置方式,可以代替XML。(配置代表开发时损耗)
除此之外,项目的依赖管理也是一件耗时耗力的事情。在环境搭建时,需要分析要导入哪些库的坐标,而且还需要分析导入与之有依赖关系的其他库的坐标,一旦选错了依赖的版本,随之而来的不兼容问题就会严重阻碍项目的开发进度。
概述
SpringBoot便是对上述Spring缺点进行的改善和优化,简化Spring应用程序的创建和开发过程,也可以说简化SSM框架进行开发的过程,基于约定优于配置的思想,可以让开发人员不必在配置与逻辑业务之间进行思维的切换。
在以往采用SSM框架进行开发时,搭建和整合三大框架,要配置web.xml、Spring、MyBatis还有整合等。现在SpringBoot框架对此开发过程进行了革命性颠覆,完全抛弃了繁琐的xml配置过程,采用大量默认配置简化开发过程。
所以采用SpringBoot可以容易和快速地创建基于Spring框架的应用程序,他让编码、配置、部署、监控变得简单。
在以往采用SSM框架进行开发时,搭建和整合三大框架,要配置web.xml、Spring、MyBatis还有整合等。现在SpringBoot框架对此开发过程进行了革命性颠覆,完全抛弃了繁琐的xml配置过程,采用大量默认配置简化开发过程。
所以采用SpringBoot可以容易和快速地创建基于Spring框架的应用程序,他让编码、配置、部署、监控变得简单。
特性
1、能快速创建基于Spring的应用程序。
2、能直接使用java main方法启动内嵌的Tomcat服务器运行SpringBoot程序,不需要部署war包文件。
3、提供约定的starter POM来简化Maven配置,让Maven配置变得简单。
4、自动化配置,根据项目的Maven依赖配置,SpringBoot自动配置Spring、SpringMVC等。
5、提供了一些大型项目中常见的非功能性特性,如嵌入式服务器、安全、指标,健康检测、外部配置等。
6、开箱即用,基本可以完全不使用XML配置文件,采用注解配置。同时也可以修改默认值来满足特定的需求。
四大核心功能
1、自动配置
Spring Boot的自动配置是一个运行时(更准确地说,是应用程序启动时)的过程,考虑了众多因素,才决定Spring配置应该用哪个,不该用哪个。该过程是Spring自动完成的。
Spring Boot的自动配置是一个运行时(更准确地说,是应用程序启动时)的过程,考虑了众多因素,才决定Spring配置应该用哪个,不该用哪个。该过程是Spring自动完成的。
2、起步依赖
起步依赖本质上是一个Maven项目对象模型(Project Object Model,POM),定义了对其他库的传递依赖,这些东西加在一起即支持某项功能。简单的说,起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能。
起步依赖本质上是一个Maven项目对象模型(Project Object Model,POM),定义了对其他库的传递依赖,这些东西加在一起即支持某项功能。简单的说,起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能。
3、Actuator(#)
4、命令行界面(#)
核心注解
@SpringBootApplication启动入口类
@SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。
@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。
@ComponentScan:Spring组件扫描。
当前工程GAV
<groupId>com.kx</groupId>
<artifactId>springboot002</artifactId>
<version>0.0.1-SNAPSHOT</version>
<artifactId>springboot002</artifactId>
<version>0.0.1-SNAPSHOT</version>
当前工程的父工程GAV
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
starter-parent的父工程
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.5.6</version>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.5.6</version>
spring-boot-starter-parent分类
1. Spring Boot应用类启动器
spring-boot-starter————包含自动配置、日志、YAML的支持。
spring-boot-starter-web———使用SpringMVC构建web工程,包含restful,默认使用Tomcat容器。。。
spring-boot-starter————包含自动配置、日志、YAML的支持。
spring-boot-starter-web———使用SpringMVC构建web工程,包含restful,默认使用Tomcat容器。。。
2. Spring Boot生产启动器
3. Spring Boot技术类启动器
spring-boot-starter-json————提供对JSON读写支持
spring-boot-starter-logging————默认的日志启动器Logback
spring-boot-starter-json————提供对JSON读写支持
spring-boot-starter-logging————默认的日志启动器Logback
4. 其他第三方启动器
入门案例
一、创建SpringBoot框架web项目
spring-boot-starter-web
SpringBoot-web项目起步依赖
<!--SpringBoot项目打包编译的插件-->
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
二、集成SpringMVC
常用注解
@Controller
@ResponseBody
@RestController=@Controller+@ResponseBody
@RequestMapping(method=get/post/delete/put/patch)
@Controller
public class IndexController {
@RequestMapping("/springboot/say")
@ResponseBody
public String say(){
return "hello,springboot!";
}
}
public class IndexController {
@RequestMapping("/springboot/say")
@ResponseBody
public String say(){
return "hello,springboot!";
}
}
三、核心配置文件
application-properties
#设置内嵌Tomcat端口号
server.port=9090
#设置上下文根
server.servlet.context-path=/springboot003
server.port=9090
#设置上下文根
server.servlet.context-path=/springboot003
application.yml
server:
port: 8081
servlet:
context-path: /springboot004
port: 8081
servlet:
context-path: /springboot004
application.yaml
若application.properties和application.yml或application.yaml同时存在,优先前者
多环境配置文件
后缀properties和yml配置大致相同
后缀properties和yml配置大致相同
application.properties
#SpringBoot主核心配置文件
#激活使用的配置文件
spring.profiles.active=dev
#激活使用的配置文件
spring.profiles.active=dev
application-dev.properties
#开发环境的配置文件
server.port=8080
server.servlet.context-path=/dev
server.port=8080
server.servlet.context-path=/dev
application-product.properties
#生产环境的配置文件
server.port=8083
server.servlet.context-path=/product
server.port=8083
server.servlet.context-path=/product
application-ready.properties
#准生产环境的配置文件
server.port=8082
server.servlet.context-path=/ready
server.port=8082
server.servlet.context-path=/ready
application-test.properties
#测试环境的配置文件
server.port=8081
server.servlet.context-path=/test
server.port=8081
server.servlet.context-path=/test
获取配置文件中自定义的值
${ property : default_value }
例:
#配置自定义属性
student.name=zkx
websit=www.kx25.com
—————————————
@Value("${student.name}")
private String stuName;
#配置自定义属性
student.name=zkx
websit=www.kx25.com
—————————————
@Value("${student.name}")
private String stuName;
#{ obj.property? :default_value }
将配置文件中的自定义值映射到对象
(注:得有前缀)
(注:得有前缀)
school.name=kxSchool
school.website=www.kx25.com
————————————————————
@Component
@ConfigurationProperties(prefix = "school")
public class School {
private String name;
private String website;
}
school.website=www.kx25.com
————————————————————
@Component
@ConfigurationProperties(prefix = "school")
public class School {
private String name;
private String website;
}
<!--解决使用@ConfigurationProperties注解出现警告-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
注:如果在SpringBoot核心配置文件中有中文信息,会出现乱码。一般在
配置文件中,不建议出现中文(注释除外)。如果有,可以先转化为ASCII码。
Idea操作:setting——editor——file encodings——UTF-8√
(注:拷贝配置是注意空格删干净)
配置文件中,不建议出现中文(注释除外)。如果有,可以先转化为ASCII码。
Idea操作:setting——editor——file encodings——UTF-8√
(注:拷贝配置是注意空格删干净)
四、集成jsp
依赖:
<!--web项目起步依赖-->
spring-boot-starter-web
<!--引入SpringBoot内嵌Tomcat对jsp的解析依赖,不添加解析不了jsp-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<!--web项目起步依赖-->
spring-boot-starter-web
<!--引入SpringBoot内嵌Tomcat对jsp的解析依赖,不添加解析不了jsp-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<!--
SpringBoot项目默认推荐使用Thymeleaf
现在要使用SpringBoot集成JSP,手动指定JSP最后编译的路径
而且SpringBoot集成JSP编译JSP的路径是SpringBoot规定好的位置
META-INF/resources
-->
<resources>
<resource>
<!--源文件夹-->
<directory>src/main/webapp</directory>
<!--指定编译到META-INF/resources-->
<targetPath>META-INF/resources</targetPath>
<!--指定源文件中的那个资源要编译进行-->
<includes>
<include>*.*</include>
</includes>
</resource>
</resources>
SpringBoot项目默认推荐使用Thymeleaf
现在要使用SpringBoot集成JSP,手动指定JSP最后编译的路径
而且SpringBoot集成JSP编译JSP的路径是SpringBoot规定好的位置
META-INF/resources
-->
<resources>
<resource>
<!--源文件夹-->
<directory>src/main/webapp</directory>
<!--指定编译到META-INF/resources-->
<targetPath>META-INF/resources</targetPath>
<!--指定源文件中的那个资源要编译进行-->
<includes>
<include>*.*</include>
</includes>
</resource>
</resources>
#配置视图解析器
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
五、logo的关闭和修改
关闭logo
//获取入口类
// SpringApplication springApplication = new SpringApplication(LogoApplication.class);
//设置它的属性
// springApplication.setBannerMode(Banner.Mode.OFF);
// springApplication.run(args);
// SpringApplication springApplication = new SpringApplication(LogoApplication.class);
//设置它的属性
// springApplication.setBannerMode(Banner.Mode.OFF);
// springApplication.run(args);
修改logo
//修改logo只需添加banner.txt
SpringApplication.run(LogoApplication.class, args);
SpringApplication.run(LogoApplication.class, args);
例:
${AnsiColor.RED}
.::::.
.::::::::.
:::::::::::
..:::::::::::'
'::::::::::::'
.::::::::::
'::::::::::::::..
..::::::::::::.
``::::::::::::::::
::::``:::::::::' .:::.
::::' ':::::' .::::::::.
.::::' :::: .:::::::'::::.
.:::' ::::: .:::::::::' ':::::.
.::' :::::.:::::::::' ':::::.
.::' ::::::::::::::' ``::::.
...::: ::::::::::::' ``::.
```` ':. ':::::::::' ::::..
'.:::::' ':'````..
:: Spring Boot :: (v2.6.2.RELEASE)
${AnsiColor.RED}
.::::.
.::::::::.
:::::::::::
..:::::::::::'
'::::::::::::'
.::::::::::
'::::::::::::::..
..::::::::::::.
``::::::::::::::::
::::``:::::::::' .:::.
::::' ':::::' .::::::::.
.::::' :::: .:::::::'::::.
.:::' ::::: .:::::::::' ':::::.
.::' :::::.:::::::::' ':::::.
.::' ::::::::::::::' ``::::.
...::: ::::::::::::' ``::.
```` ':. ':::::::::' ::::..
'.:::::' ':'````..
:: Spring Boot :: (v2.6.2.RELEASE)
集成MyBatis
依赖:
mybatis-spring-boot-starter、mysql-connector-java
mybatis-spring-boot-starter、mysql-connector-java
mybatis逆向工程
个人习惯在cmd中使用generator.xml自动生成(不会让项目看起来变的复杂)
springboot中mybatis-generator
配置完后双击maven中plugin中mybatis-generator
配置完后双击maven中plugin中mybatis-generator
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<overwrite>true</overwrite>
<configurationFile>GeneratorMapper.xml</configurationFile>
</configuration>
</plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<overwrite>true</overwrite>
<configurationFile>GeneratorMapper.xml</configurationFile>
</configuration>
</plugin>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- 数据库驱动:选择你的本地硬盘上面的数据库驱动包-->
<classPathEntry location="D:\generator/mysql-connector-java-8.0.16.jar"/>
<context id="DB2Tables" targetRuntime="MyBatis3">
<!-- JavaBean 实现 序列化 接口 -->
<!-- <plugin type="org.mybatis.generator.plugins.SerializablePlugin" />-->
<!-- 生成toString -->
<!-- <plugin type="org.mybatis.generator.plugins.ToStringPlugin" />-->
<!-- optional,旨在创建class时,对注释进行控制 -->
<commentGenerator>
<!-- <property name="suppressDate" value="true"/>-->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--数据库链接URL,用户名、密码 -->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://127.0.0.1:3306/springboot?serverTimezone=UTC"
userId="root"
password="123456">
</jdbcConnection>
<!-- 类型转换 -->
<javaTypeResolver>
<!-- 是否使用bigDecimal,
false: 把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer(默认)
true: 把JDBC DECIMAL 和 NUMERIC 类型解析为java.math.BigDecimal
-->
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- 生成模型的包名和位置-->
<javaModelGenerator targetPackage="com.kx.springboot.pojo" targetProject="src/main/java">
<!-- 默认false 是否允许子包 -->
<property name="enableSubPackages" value="true"/>
<!-- 默认false 是否对model添加 构造函数 -->
<property name="constructorBased" value="false"/>
<!-- 默认false 建立的Model对象是否 不可改变 即生成的Model对象不会有 setter方法,只有构造方法 -->
<property name="immutable" value="false"/>
<!-- 默认false 是否对类CHAR类型的列的数据进行trim操作 -->
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- 生成映射文件的包名和位置-->
<sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- 生成DAO的包名和位置-->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.kx.springboot.dao" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!-- 要生成的表 tableName是数据库中的表名或视图名 domainObjectName是实体类名-->
<!-- <table tableName="risk_model_order" domainObjectName="DSRiskModelOrder" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
<table tableName="tel_bill_record" domainObjectName="DSTelBillRecord" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>-->
<table tableName="student1"
enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"
enableSelectByExample="false" selectByExampleQueryId="false">
</table>
</context>
</generatorConfiguration>
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- 数据库驱动:选择你的本地硬盘上面的数据库驱动包-->
<classPathEntry location="D:\generator/mysql-connector-java-8.0.16.jar"/>
<context id="DB2Tables" targetRuntime="MyBatis3">
<!-- JavaBean 实现 序列化 接口 -->
<!-- <plugin type="org.mybatis.generator.plugins.SerializablePlugin" />-->
<!-- 生成toString -->
<!-- <plugin type="org.mybatis.generator.plugins.ToStringPlugin" />-->
<!-- optional,旨在创建class时,对注释进行控制 -->
<commentGenerator>
<!-- <property name="suppressDate" value="true"/>-->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--数据库链接URL,用户名、密码 -->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://127.0.0.1:3306/springboot?serverTimezone=UTC"
userId="root"
password="123456">
</jdbcConnection>
<!-- 类型转换 -->
<javaTypeResolver>
<!-- 是否使用bigDecimal,
false: 把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer(默认)
true: 把JDBC DECIMAL 和 NUMERIC 类型解析为java.math.BigDecimal
-->
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- 生成模型的包名和位置-->
<javaModelGenerator targetPackage="com.kx.springboot.pojo" targetProject="src/main/java">
<!-- 默认false 是否允许子包 -->
<property name="enableSubPackages" value="true"/>
<!-- 默认false 是否对model添加 构造函数 -->
<property name="constructorBased" value="false"/>
<!-- 默认false 建立的Model对象是否 不可改变 即生成的Model对象不会有 setter方法,只有构造方法 -->
<property name="immutable" value="false"/>
<!-- 默认false 是否对类CHAR类型的列的数据进行trim操作 -->
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- 生成映射文件的包名和位置-->
<sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- 生成DAO的包名和位置-->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.kx.springboot.dao" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!-- 要生成的表 tableName是数据库中的表名或视图名 domainObjectName是实体类名-->
<!-- <table tableName="risk_model_order" domainObjectName="DSRiskModelOrder" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
<table tableName="tel_bill_record" domainObjectName="DSTelBillRecord" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>-->
<table tableName="student1"
enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"
enableSelectByExample="false" selectByExampleQueryId="false">
</table>
</context>
</generatorConfiguration>
注解
@Mapper
需要在每个Mapper接口类上添加,作用扫描dao接口。(每个加麻烦,用下方@MapperScan)
@MapperScan
在SpringBoot启动入口类上添加的,basePackage="选择扫描的包"。
Mapper映射文件存放的位置
a)将Mapper接口和Mapper映射文件存放到src/main/java同一目录下,
还需要在pom文件中手动指定资源文件夹路径resources。
还需要在pom文件中手动指定资源文件夹路径resources。
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
b)将Mapper接口和Mapper映射文件分开存放,Mapper接口类存放到src/main/java目录下,Mapper映射文件存放到resource(类路径下)
还需要在配置文件中指定mapper映射文件
还需要在配置文件中指定mapper映射文件
#指定MyBatis映射文件的路径
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.mapper-locations=classpath:mapper/*.xml
使用事务
事务只跟什么SQL语句有关?事务只跟DML语句有关系:增删改
SQL语言:DML、DQL、DDL、TCL、DCL
SQL语言:DML、DQL、DDL、TCL、DCL
操作
在ServiceImpl类上添加@Transactional
例:
@Transactional
@Override
public int updateStudentById(Student student) {
int i = studentMapper.updateByPrimaryKeySelective(student);
int a = 10 / 0;
return i;
}
@Transactional
@Override
public int updateStudentById(Student student) {
int i = studentMapper.updateByPrimaryKeySelective(student);
int a = 10 / 0;
return i;
}
集成RESTFul
风格
传统风格
http://localhost:8080/boot/order?id=1&status=1
RestFul风格
http://localhost:8080/boot/order/1/1
路径
在RESTful架构中,每个网址代表一种资源(resource),所以网址中只能有名词(与数据库的表格名对应)。
@PathVariable:获取url中的数据
Restful API
简单的说即可联网设备利用HTTP协议通过get\post\delete\put\patch来操作具有URL标识的服务器资源,
返回统一格式的资源信息,包括JSON、XML、CSV、ProtoBuf等。
返回统一格式的资源信息,包括JSON、XML、CSV、ProtoBuf等。
HTTP常用的5个动词
GET(SELECT):从服务器取出资源
POST(CREATE):在服务器新建一个资源
PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)(整体更新)
PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)(局部更新)
DELETE(DALETE):在服务器删除资源
状态码:建议使用HTTP状态码
错误处理:返回指定错误
错误处理:返回指定错误
解决请求路径模糊
1、通常在RESTful风格中方法的请求方式会按增删改查的请求方式来区分。
2、修改请求路径。
3、RESTful请求风格要求路径中使用单词为名词。
4、分页、排序等操作,不需要使用斜杠
例:/book/orders?page=1&sort=desc一般传的参数不是数据库表的字段
例:/book/orders?page=1&sort=desc一般传的参数不是数据库表的字段
解决请求路径冲突
1、分配不同的请求方式@GetMapping和@PostMappering
2、改变路径位置
原路径:/stu/detail/{id}/{age}
改动后:/stu/{id}/detail/{status}
集成Redis
a)添加操作redis数据类型的依赖
spring-boot-starter-data-redis
b)配置文件中添加redis的配置
#设置redis配置信息
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.host=localhost
spring.redis.port=6379
注入RedisTemplate对象
@Autowired
private RedisTemplate<Object,Object> redisTemplate;
@Override
public void put(String key, String value) {
redisTemplate.opsForValue().set(key,value);
}
@Override
public void put1(String key, String value) {
RedisSerializer redisSerializer=new StringRedisSerializer();
redisTemplate.setKeySerializer(redisSerializer);
redisTemplate.setValueSerializer(redisSerializer);
redisTemplate.opsForValue().set(key,value);
}
@Override
public String get(String key) {
return (String) redisTemplate.opsForValue().get(key);
}
private RedisTemplate<Object,Object> redisTemplate;
@Override
public void put(String key, String value) {
redisTemplate.opsForValue().set(key,value);
}
@Override
public void put1(String key, String value) {
RedisSerializer redisSerializer=new StringRedisSerializer();
redisTemplate.setKeySerializer(redisSerializer);
redisTemplate.setValueSerializer(redisSerializer);
redisTemplate.opsForValue().set(key,value);
}
@Override
public String get(String key) {
return (String) redisTemplate.opsForValue().get(key);
}
SpringBoot下使用拦截器Intercept
a)定义一个拦截器
实现HandlerInterceptor接口,重写preHandler方法
public class UserInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("———————————进入用户登录拦截器——————————");
//编写拦截用户信息
//从session中获取用户信息
User user = (User) request.getSession().getAttribute("user");
//判断用户是否登录
if (null == user){
//未登录
response.sendRedirect(request.getContextPath()+"/user/error");
return false;
}
return true;
}
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("———————————进入用户登录拦截器——————————");
//编写拦截用户信息
//从session中获取用户信息
User user = (User) request.getSession().getAttribute("user");
//判断用户是否登录
if (null == user){
//未登录
response.sendRedirect(request.getContextPath()+"/user/error");
return false;
}
return true;
}
}
b)创建一个配置类
类似于在SpringMVC配置文件中使用mvc:interceptors标签
@Configuration //定义此类为配置文件(相当于之前的xml文件)
public class InterceptorConfig implements WebMvcConfigurer {
//mvc:interceptors
@Override
public void addInterceptors(InterceptorRegistry registry) {
String[] addPathPatterns = {
"/user/**"
};
String[] excludePathPatterns = {
"/user/login","/user/out","/user/error"
};
//mvc:interceptor bean class=""
registry.addInterceptor(new UserInterceptor()).addPathPatterns(addPathPatterns).excludePathPatterns(excludePathPatterns);
// WebMvcConfigurer.super.addInterceptors(registry);
}
}
public class InterceptorConfig implements WebMvcConfigurer {
//mvc:interceptors
@Override
public void addInterceptors(InterceptorRegistry registry) {
String[] addPathPatterns = {
"/user/**"
};
String[] excludePathPatterns = {
"/user/login","/user/out","/user/error"
};
//mvc:interceptor bean class=""
registry.addInterceptor(new UserInterceptor()).addPathPatterns(addPathPatterns).excludePathPatterns(excludePathPatterns);
// WebMvcConfigurer.super.addInterceptors(registry);
}
}
SpringBoot下使用Servlet(了解)
以前的配置
1、创建一个Servlet继承HTTPServlet
2、在web.xml配置文件中使用servlet servlet-mapping
方式
第一种方式:注解方式
@WebServlet、@ServletComponentScan
@WebServlet(urlPatterns = "/myservlet")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("MyServlet One");
resp.getWriter().flush();
resp.getWriter().close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("MyServlet One");
resp.getWriter().flush();
resp.getWriter().close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
@SpringBootApplication
@ServletComponentScan("com.kx.springboot.servlet")
public class Springboot031ServletApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot031ServletApplication.class, args);
}
}
@ServletComponentScan("com.kx.springboot.servlet")
public class Springboot031ServletApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot031ServletApplication.class, args);
}
}
第二种方式:通过配置类注册组件
和以前配置一样(创建一个Servlet继承HTTPServlet:)
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("MyServlet Two");
resp.getWriter().flush();
resp.getWriter().close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("MyServlet Two");
resp.getWriter().flush();
resp.getWriter().close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
@Configuration
public class ServletConfig {
/**
* @Bean是个方法级别的注解,主要用在配置类
* 相当于<beans><bean id="" class=""></bean></beans>
* @return
*/
@Bean
public ServletRegistrationBean myServletRegistrationBean(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new MyServlet(),"/myservlet2");
return servletRegistrationBean;
}
}
public class ServletConfig {
/**
* @Bean是个方法级别的注解,主要用在配置类
* 相当于<beans><bean id="" class=""></bean></beans>
* @return
*/
@Bean
public ServletRegistrationBean myServletRegistrationBean(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new MyServlet(),"/myservlet2");
return servletRegistrationBean;
}
}
SpringBoo下使用过滤器Filter(了解)
第一种方式:注解方式
@WebFilter、@ServletComponentScan
@WebFilter(urlPatterns = "/myfilter")
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("————————过滤器————————");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("————————过滤器————————");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
@SpringBootApplication
@ServletComponentScan(basePackages = "com.kx.springboot.filter")
public class Springboot033FilterApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot033FilterApplication.class, args);
}
}
@ServletComponentScan(basePackages = "com.kx.springboot.filter")
public class Springboot033FilterApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot033FilterApplication.class, args);
}
}
第二种方式:注册组件
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("————————过滤器————————");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("————————过滤器————————");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean myFilterRegistrationBean(){
//注册过滤器
FilterRegistrationBean filterRegistrationBean=new FilterRegistrationBean(new MyFilter());
//添加过滤路径
filterRegistrationBean.addUrlPatterns("/user/*");
return filterRegistrationBean;
}
}
public class FilterConfig {
@Bean
public FilterRegistrationBean myFilterRegistrationBean(){
//注册过滤器
FilterRegistrationBean filterRegistrationBean=new FilterRegistrationBean(new MyFilter());
//添加过滤路径
filterRegistrationBean.addUrlPatterns("/user/*");
return filterRegistrationBean;
}
}
SpringBoot配置字符编码
第一种方式
@WebServlet("/myservlet")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("世界您好 Hello World!");
//统一设置浏览器编码格式
resp.setContentType("text/html;character=utf-8");
resp.getWriter().flush();
resp.getWriter().close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("世界您好 Hello World!");
//统一设置浏览器编码格式
resp.setContentType("text/html;character=utf-8");
resp.getWriter().flush();
resp.getWriter().close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
@Configuration
public class SystemConfig {
@Bean
public FilterRegistrationBean myFilterRegistrationBean(){
//创建字符编码过滤器
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
//强制设置使用指定字符编码
characterEncodingFilter.setForceEncoding(true);
//并设置指定字符编码
characterEncodingFilter.setEncoding("utf-8");
FilterRegistrationBean filterRegistrationBean=new FilterRegistrationBean();
//设置字符编码过滤器
filterRegistrationBean.setFilter(characterEncodingFilter);
//设置字符编码过滤器路径
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
}
public class SystemConfig {
@Bean
public FilterRegistrationBean myFilterRegistrationBean(){
//创建字符编码过滤器
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
//强制设置使用指定字符编码
characterEncodingFilter.setForceEncoding(true);
//并设置指定字符编码
characterEncodingFilter.setEncoding("utf-8");
FilterRegistrationBean filterRegistrationBean=new FilterRegistrationBean();
//设置字符编码过滤器
filterRegistrationBean.setFilter(characterEncodingFilter);
//设置字符编码过滤器路径
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
}
@SpringBootApplication
@ServletComponentScan("com.kx.springboot.servlet")
public class Springboot035EncodingApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot035EncodingApplication.class, args);
}
}
@ServletComponentScan("com.kx.springboot.servlet")
public class Springboot035EncodingApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot035EncodingApplication.class, args);
}
}
#关闭SpringBoot的http字符编码支持
server.servlet.encoding.enabled=false
server.servlet.encoding.enabled=false
第二种方式
@WebServlet("/myservlet")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("世界你好 hello");
resp.setContentType("text/html;character=utf-8");
resp.getWriter().flush();
resp.getWriter().close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("世界你好 hello");
resp.setContentType("text/html;character=utf-8");
resp.getWriter().flush();
resp.getWriter().close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
@SpringBootApplication
@ServletComponentScan("com.kx.springboot.servlet")
public class Springboot035Encoding2Application {
public static void main(String[] args) {
SpringApplication.run(Springboot035Encoding2Application.class, args);
}
}
@ServletComponentScan("com.kx.springboot.servlet")
public class Springboot035Encoding2Application {
public static void main(String[] args) {
SpringApplication.run(Springboot035Encoding2Application.class, args);
}
}
#设置请求字符编码
server.http.encoding.enabled=true
server.servlet.encoding.force=true
server.servlet.encoding.charset=utf-8
server.http.encoding.enabled=true
server.servlet.encoding.force=true
server.servlet.encoding.charset=utf-8
打包与部署
打war包部署
<!--pom文件中修改打包方式-->
<packaging>war</packaging>
<!--pom文件中build下指定打包的war名称-->
<finalName>SpringBootWar</finalName>
<packaging>war</packaging>
<!--pom文件中build下指定打包的war名称-->
<finalName>SpringBootWar</finalName>
启动类变动:
@SpringBootApplication
public class Springboot037WarApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Springboot037WarApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
//构造新资源
return builder.sources(Springboot037WarApplication.class);
// return super.configure(builder);
}
}
@SpringBootApplication
public class Springboot037WarApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Springboot037WarApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
//构造新资源
return builder.sources(Springboot037WarApplication.class);
// return super.configure(builder);
}
}
在Tomcat的webapps目录下放上war包
启动Tomcat的bin目录下startup.bat
注:1、SpringBoot打war包,部署到tomcat中,之前在application.properties设置的端口号和上下文失效。
2、如果前端为jsp页面需要配置spring.mvc.view.prefix=/和spring.mvc.view.suffix=.jsp
2、如果前端为jsp页面需要配置spring.mvc.view.prefix=/和spring.mvc.view.suffix=.jsp
打jar包
<finalName>SpringBootJar</finalName>
<resources>
<resource>
<directory>src/main/webapp</directory>
<targetPath>META-INF/resources</targetPath>
<includes>
<include>*.*</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
<resources>
<resource>
<directory>src/main/webapp</directory>
<targetPath>META-INF/resources</targetPath>
<includes>
<include>*.*</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
pom文件build下plugins中打包插件加<version>1.4.2.RELEASE</version>
application.properties设置的端口号和上下文有效
java -jar xxx.jar
集成logback
logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,比如: 如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="10 seconds">
<contextName>logback</contextName>
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
<!-- <property name="log.path" value="/var/log/myapp"/>-->
<property name="log.path" value="D:/IdeaProject/log"/>
<!--0. 日志格式和颜色渲染 -->
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!--1. 输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!--2. 输出到文档-->
<!-- 2.1 level为 DEBUG 日志,时间滚动输出 -->
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/debug.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志归档 -->
<fileNamePattern>${log.path}/debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录debug级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>debug</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.2 level为 INFO 日志,时间滚动输出 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/info.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.3 level为 WARN 日志,时间滚动输出 -->
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/warn.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.4 level为 ERROR 日志,时间滚动输出 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/error.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.5 所有 除了DEBUG级别的其它高于DEBUG的 日志,记录到一个文件 -->
<appender name="ALL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/all.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/all-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档记录除了DEBUG级别的其它高于DEBUG的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
</appender>
<!--
<logger>用来设置某一个包或者具体的某一个类的日志打印级别、
以及指定<appender>。<logger>仅有一个name属性,
一个可选的level和一个可选的addtivity属性。
name:用来指定受此logger约束的某一个包或者具体的某一个类。
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
还有一个特殊值INHERITED或者同义词NULL,代表强制执行上级的级别。
如果未设置此属性,那么当前logger将会继承上级的级别。
addtivity:是否向上级logger传递打印信息。默认是true。
<logger name="org.springframework.web" level="info"/>
<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>
-->
<!--
使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别:
【logging.level.org.mybatis=debug logging.level.dao=debug】
-->
<!--
root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
不能设置为INHERITED或者同义词NULL。默认是DEBUG
可以包含零个或多个元素,标识这个appender将会添加到这个logger。
-->
<!-- 4 最终的策略:
基本策略(root级) + 根据profile在启动时, logger标签中定制化package日志级别(优先级高于上面的root级)-->
<!--多个或全部定义-->
<root level="info">
<appender-ref ref="CONSOLE" />
<!-- <appender-ref ref="DEBUG_FILE" />-->
<appender-ref ref="INFO_FILE" />
<!-- <appender-ref ref="WARN_FILE" />-->
<!-- <appender-ref ref="ERROR_FILE" />-->
<!-- <appender-ref ref="ALL_FILE" />-->
</root>
<!--单个定义-->
<logger name="com.kx.springboot" level="debug"/>
<!-- <springProfile name="dev">-->
<!-- <root level="info">-->
<!-- <appender-ref ref="CONSOLE" />-->
<!-- <appender-ref ref="DEBUG_FILE" />-->
<!-- <appender-ref ref="INFO_FILE" />-->
<!-- <appender-ref ref="WARN_FILE" />-->
<!-- <appender-ref ref="ERROR_FILE" />-->
<!-- <appender-ref ref="ALL_FILE" />-->
<!-- </root>-->
<!-- <logger name="com.kx.springboot" level="debug"/> <!– 开发环境, 指定某包日志为debug级 –>-->
<!-- </springProfile>-->
<!-- <springProfile name="test">-->
<!-- <root level="info">-->
<!-- <appender-ref ref="CONSOLE" />-->
<!-- <appender-ref ref="DEBUG_FILE" />-->
<!-- <appender-ref ref="INFO_FILE" />-->
<!-- <appender-ref ref="WARN_FILE" />-->
<!-- <appender-ref ref="ERROR_FILE" />-->
<!-- <appender-ref ref="ALL_FILE" />-->
<!-- </root>-->
<!-- <logger name="com.kx.springboot" level="info"/> <!– 测试环境, 指定某包日志为info级 –>-->
<!-- </springProfile>-->
<!-- <springProfile name="pro">-->
<!-- <root level="info">-->
<!-- <!– 生产环境最好不配置console写文件 –>-->
<!-- <appender-ref ref="DEBUG_FILE" />-->
<!-- <appender-ref ref="INFO_FILE" />-->
<!-- <appender-ref ref="WARN_FILE" />-->
<!-- <appender-ref ref="ERROR_FILE" />-->
<!-- <appender-ref ref="ALL_FILE" />-->
<!-- </root>-->
<!-- <logger name="com.kx.springboot" level="warn"/> <!– 生产环境, 指定某包日志为warn级 –>-->
<!-- <logger name="com.kx.springboot.Springboot039LogbackApplication" level="info"/> <!– 特定某个类打印info日志, 比如application启动成功后的提示语 –>-->
<!-- </springProfile>-->
</configuration>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,比如: 如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="10 seconds">
<contextName>logback</contextName>
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
<!-- <property name="log.path" value="/var/log/myapp"/>-->
<property name="log.path" value="D:/IdeaProject/log"/>
<!--0. 日志格式和颜色渲染 -->
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!--1. 输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!--2. 输出到文档-->
<!-- 2.1 level为 DEBUG 日志,时间滚动输出 -->
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/debug.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志归档 -->
<fileNamePattern>${log.path}/debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录debug级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>debug</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.2 level为 INFO 日志,时间滚动输出 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/info.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.3 level为 WARN 日志,时间滚动输出 -->
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/warn.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.4 level为 ERROR 日志,时间滚动输出 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/error.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.5 所有 除了DEBUG级别的其它高于DEBUG的 日志,记录到一个文件 -->
<appender name="ALL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/all.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/all-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档记录除了DEBUG级别的其它高于DEBUG的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
</appender>
<!--
<logger>用来设置某一个包或者具体的某一个类的日志打印级别、
以及指定<appender>。<logger>仅有一个name属性,
一个可选的level和一个可选的addtivity属性。
name:用来指定受此logger约束的某一个包或者具体的某一个类。
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
还有一个特殊值INHERITED或者同义词NULL,代表强制执行上级的级别。
如果未设置此属性,那么当前logger将会继承上级的级别。
addtivity:是否向上级logger传递打印信息。默认是true。
<logger name="org.springframework.web" level="info"/>
<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>
-->
<!--
使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别:
【logging.level.org.mybatis=debug logging.level.dao=debug】
-->
<!--
root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
不能设置为INHERITED或者同义词NULL。默认是DEBUG
可以包含零个或多个元素,标识这个appender将会添加到这个logger。
-->
<!-- 4 最终的策略:
基本策略(root级) + 根据profile在启动时, logger标签中定制化package日志级别(优先级高于上面的root级)-->
<!--多个或全部定义-->
<root level="info">
<appender-ref ref="CONSOLE" />
<!-- <appender-ref ref="DEBUG_FILE" />-->
<appender-ref ref="INFO_FILE" />
<!-- <appender-ref ref="WARN_FILE" />-->
<!-- <appender-ref ref="ERROR_FILE" />-->
<!-- <appender-ref ref="ALL_FILE" />-->
</root>
<!--单个定义-->
<logger name="com.kx.springboot" level="debug"/>
<!-- <springProfile name="dev">-->
<!-- <root level="info">-->
<!-- <appender-ref ref="CONSOLE" />-->
<!-- <appender-ref ref="DEBUG_FILE" />-->
<!-- <appender-ref ref="INFO_FILE" />-->
<!-- <appender-ref ref="WARN_FILE" />-->
<!-- <appender-ref ref="ERROR_FILE" />-->
<!-- <appender-ref ref="ALL_FILE" />-->
<!-- </root>-->
<!-- <logger name="com.kx.springboot" level="debug"/> <!– 开发环境, 指定某包日志为debug级 –>-->
<!-- </springProfile>-->
<!-- <springProfile name="test">-->
<!-- <root level="info">-->
<!-- <appender-ref ref="CONSOLE" />-->
<!-- <appender-ref ref="DEBUG_FILE" />-->
<!-- <appender-ref ref="INFO_FILE" />-->
<!-- <appender-ref ref="WARN_FILE" />-->
<!-- <appender-ref ref="ERROR_FILE" />-->
<!-- <appender-ref ref="ALL_FILE" />-->
<!-- </root>-->
<!-- <logger name="com.kx.springboot" level="info"/> <!– 测试环境, 指定某包日志为info级 –>-->
<!-- </springProfile>-->
<!-- <springProfile name="pro">-->
<!-- <root level="info">-->
<!-- <!– 生产环境最好不配置console写文件 –>-->
<!-- <appender-ref ref="DEBUG_FILE" />-->
<!-- <appender-ref ref="INFO_FILE" />-->
<!-- <appender-ref ref="WARN_FILE" />-->
<!-- <appender-ref ref="ERROR_FILE" />-->
<!-- <appender-ref ref="ALL_FILE" />-->
<!-- </root>-->
<!-- <logger name="com.kx.springboot" level="warn"/> <!– 生产环境, 指定某包日志为warn级 –>-->
<!-- <logger name="com.kx.springboot.Springboot039LogbackApplication" level="info"/> <!– 特定某个类打印info日志, 比如application启动成功后的提示语 –>-->
<!-- </springProfile>-->
</configuration>
添加lombok依赖
@Controller
@Slf4j
public class StudentController {
@Autowired
private StudentService studentService;
@RequestMapping("/student/count")
public @ResponseBody String studentCount() {
log.info("查询当前学生总人数");
Integer stuCount = studentService.queryStudentCount();
return "学生总人数为:" + stuCount;
}
}
@Slf4j
public class StudentController {
@Autowired
private StudentService studentService;
@RequestMapping("/student/count")
public @ResponseBody String studentCount() {
log.info("查询当前学生总人数");
Integer stuCount = studentService.queryStudentCount();
return "学生总人数为:" + stuCount;
}
}
集成Thymeleaf
Thymeleaf
简介
Thymeleaf是一个跟Velocity、FreeMarker类似的模板引擎,它可以完全代替JSP。
特点:
1、Thymeleaf在有无网络的情况下都能运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。
2、Thymeleaf开箱即用的特性。他提供标准和Spring标准两种方言,可直接套用模板实现JSTL、OGNL表达式效果,避免每天套模板、改jstl、改标签的困扰。同时也能自己拓展方言。
3、Thymeleaf提供Spring标准方言和一个与SpringMVC完美集成的可选模块、可以快速实现表单绑定、属性编辑器、国际化等功能。
特点:
1、Thymeleaf在有无网络的情况下都能运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。
2、Thymeleaf开箱即用的特性。他提供标准和Spring标准两种方言,可直接套用模板实现JSTL、OGNL表达式效果,避免每天套模板、改jstl、改标签的困扰。同时也能自己拓展方言。
3、Thymeleaf提供Spring标准方言和一个与SpringMVC完美集成的可选模块、可以快速实现表单绑定、属性编辑器、国际化等功能。
表达式
1、标准变量表达式(推荐):${...}
控制器:mo.addAttribute("city","上海");
表达式:<h1 th:text="${city}">hello</h1>(使用city变量的内容替换标记文本)
表达式:<h1 th:text="${city}">hello</h1>(使用city变量的内容替换标记文本)
2、选择变量表达式(不推荐):*{...}
意思是首先选择一个对象(通过属性th:object描述),
然后在选择(标记)的范围内,处理对象的属性。
然后在选择(标记)的范围内,处理对象的属性。
例:
*{}必须使用th:object属性来绑定此对象,在div子标签中用*来代替绑定的对象${stu}
控制器:
Student stu=new Student();
stu.setStuName("张飞");
stu.setStuId("s11");
stu.setGrade(67);
mo.addAttribute("stu",stu);
表达式:
<h1 th:object="${stu}">
用户姓名:<span th:text="*{stuName}"></span>
用户编号:<span th:text="*{stuId}"></span>
</h1>
*{}必须使用th:object属性来绑定此对象,在div子标签中用*来代替绑定的对象${stu}
控制器:
Student stu=new Student();
stu.setStuName("张飞");
stu.setStuId("s11");
stu.setGrade(67);
mo.addAttribute("stu",stu);
表达式:
<h1 th:object="${stu}">
用户姓名:<span th:text="*{stuName}"></span>
用户编号:<span th:text="*{stuId}"></span>
</h1>
3、消息表达式:#{...}
4、URL链接表达式:@{...}
导入文件
传统写法:<script type="text/javascript" src="js/jquery-3.5.1.min.js"></script>
路径表达式写法:<script type="text/javascript" th:src="@{/js/jquery-3.5.1.min.js}"></script>
注:@后面加上斜杠,以表示相对路径
注:@后面加上斜杠,以表示相对路径
导入图片
控制器:
Course cs=new Course();
cs.setCourseId("cs12");
cs.setCourseName("cpp");
mp.addAttribute("course",cs);
表达式:
<img src="1.jpg" th:src="@{images/getImg{courseId=${course.courseId}}}">
执行结果:<img src="images/getImg?courseId=cs12">
Course cs=new Course();
cs.setCourseId("cs12");
cs.setCourseName("cpp");
mp.addAttribute("course",cs);
表达式:
<img src="1.jpg" th:src="@{images/getImg{courseId=${course.courseId}}}">
执行结果:<img src="images/getImg?courseId=cs12">
路径表达式
a、无参数
绝对路径(不推荐,往往实际中不写绝对路径):
传统写法:<a href="http://www.baidu.com">百度一下</a>
路径表达式:<a th:href="@{http://www.baidu.com}">百度一下</a>
传统写法:<a href="http://localhost:8080/user">跳转至/user</a>
路径表达式:<a th:href="http://localhost:8080/user}">跳转至/user</a>
传统写法:<a href="http://www.baidu.com">百度一下</a>
路径表达式:<a th:href="@{http://www.baidu.com}">百度一下</a>
传统写法:<a href="http://localhost:8080/user">跳转至/user</a>
路径表达式:<a th:href="http://localhost:8080/user}">跳转至/user</a>
相对路径(推荐):
<a th :href="@{/user}">跳转至/user</a>
<a th :href="@{/user}">跳转至/user</a>
b、有参数
绝对路径(不推荐):
传统写法:<a href="http://localhost:8080/user?username='zhangsan'">跳转 至/user</a>
路径表达式:<a th:href="@{http://localhost:8080/user?username='zhangsan'}">跳转至/user</a>
传统写法:<a href="http://localhost:8080/user?username='zhangsan'">跳转 至/user</a>
路径表达式:<a th:href="@{http://localhost:8080/user?username='zhangsan'}">跳转至/user</a>
相对路径(推荐):
<a th :href="@{/user?username='zhangsan'}">带参数跳转至/user</a>
//后台获取动态参数(推荐)
<a th :href="@{'/user?username='+${username}}">动态参数值跳转</a>
//后台获取多个动态参数(推荐)
<a th :href="@{'/user?id=’+${id}+'&username='+${username}}">动态参数值跳转</a>
//后台获取多个动态参数(极力推荐)
<a th :href="@{/user(id=${id},username=${username})}">动态参数值跳转</a>
//RestFul风格不支持小括号(推荐)
<a th :href="@{'/user/'+${id}+'/'+${username}}">RestFul风格动态参数值跳转</a>
<a th :href="@{/user?username='zhangsan'}">带参数跳转至/user</a>
//后台获取动态参数(推荐)
<a th :href="@{'/user?username='+${username}}">动态参数值跳转</a>
//后台获取多个动态参数(推荐)
<a th :href="@{'/user?id=’+${id}+'&username='+${username}}">动态参数值跳转</a>
//后台获取多个动态参数(极力推荐)
<a th :href="@{/user(id=${id},username=${username})}">动态参数值跳转</a>
//RestFul风格不支持小括号(推荐)
<a th :href="@{'/user/'+${id}+'/'+${username}}">RestFul风格动态参数值跳转</a>
5、代码段表达式:~{...}
常用属性
th标签的基本含义:替换(th),解析:需要从后台取值需要加上th。
格式:th:需替换的部分="替换的值";
常用th标签
替换id: th:id
替换name:th:name
属性赋值 :th:value
替换文本 :th:text
textarea :th:utext
链接地址 :th:href
图片地址 :th:src
代入对象 :th:object
代入集合 :th:each
替换name:th:name
属性赋值 :th:value
替换文本 :th:text
textarea :th:utext
链接地址 :th:href
图片地址 :th:src
代入对象 :th:object
代入集合 :th:each
<!--
user:当前循环的对象变量名称(随意)
userStat:当前循环对象状态的变量(可省略,默认就是对象变量名称+Stat)
${userList}:当前循环的集合
-->
<div th:each="user,userStat:${userList}">
<span th:text="${userStat.index}"></span>
<span th:text="${userStat.count}"></span>
<span th:text="${user.id}"></span>
<span th:text="${user.nick}"></span>
<span th:text="${user.phone}"></span>
<span th:text="${user.address}"></span>
</div>
条件代入 :th:if
条件代入 :th:unless
<h2>th:if用法(th:unless与之相反)</h2>
<div th:if="${sex eq 1}">
男
</div>
<div th:if="${sex eq 0}">
女
</div>
选择结构 :th:switch
选择case :th:case
//*通配符表示无此产品
<div th:switch="${productType}">
<span th:case="0">产品0</span>
<span th:case="1">产品1</span>
<span th:case="*">无此产品</span>
</div>
内敛表达式:th:inline(三种取值(text文本、javascript脚本、none))
<h2>内敛文本:th:inline="text",通常在div标签中写</h2>
<div th:inline="text">
数据:[[${data}]]
</div>
//注意:JS中获取后台传过来的值得用th:inline
<h2>内敛脚本(在js获取后台传过来的值):th:inline="javascript"</h2>
<script type="text/javascript" th:inline="javascript">
function showData() {
// alter(${data}) //无效
alert([[${data}]])
}
</script>
<button type="button" onclick="showData()">showData</button>
设置样式 :th:style
th:onclick
user:当前循环的对象变量名称(随意)
userStat:当前循环对象状态的变量(可省略,默认就是对象变量名称+Stat)
${userList}:当前循环的集合
-->
<div th:each="user,userStat:${userList}">
<span th:text="${userStat.index}"></span>
<span th:text="${userStat.count}"></span>
<span th:text="${user.id}"></span>
<span th:text="${user.nick}"></span>
<span th:text="${user.phone}"></span>
<span th:text="${user.address}"></span>
</div>
条件代入 :th:if
条件代入 :th:unless
<h2>th:if用法(th:unless与之相反)</h2>
<div th:if="${sex eq 1}">
男
</div>
<div th:if="${sex eq 0}">
女
</div>
选择结构 :th:switch
选择case :th:case
//*通配符表示无此产品
<div th:switch="${productType}">
<span th:case="0">产品0</span>
<span th:case="1">产品1</span>
<span th:case="*">无此产品</span>
</div>
内敛表达式:th:inline(三种取值(text文本、javascript脚本、none))
<h2>内敛文本:th:inline="text",通常在div标签中写</h2>
<div th:inline="text">
数据:[[${data}]]
</div>
//注意:JS中获取后台传过来的值得用th:inline
<h2>内敛脚本(在js获取后台传过来的值):th:inline="javascript"</h2>
<script type="text/javascript" th:inline="javascript">
function showData() {
// alter(${data}) //无效
alert([[${data}]])
}
</script>
<button type="button" onclick="showData()">showData</button>
设置样式 :th:style
th:onclick
常量与运算符
常量
一般称之为字面量
文本:'one text,'another one!',...
数值:0,2,2.0
布尔类型:true、false
null
文本:'one text,'another one!',...
数值:0,2,2.0
布尔类型:true、false
null
运算符
1、算术运算:+,-,*,/,%
控制器:mp.addAttribute("num",50);
html:
<h1>hello<span th:text="${num}*2">spring</span></h1>
<h1>hello<span th:text="${num}/2">spring</span></h1>
<h1>hello<span th:text="${num}%2">spring</span></h1>
html:
<h1>hello<span th:text="${num}*2">spring</span></h1>
<h1>hello<span th:text="${num}/2">spring</span></h1>
<h1>hello<span th:text="${num}%2">spring</span></h1>
2、布尔操作:and,or二元操作符
!,not非(一元操作符)
!,not非(一元操作符)
3、关系操作符:>,<,>=,<=(gt,it,ge,le),==,!=(eq,ne)
控制器:mp.addAttrbute("grade",80);
html:<h1 th:utext="${course.courseGrade}>3?'<u>主课</u>':一般"></h1>
html:<h1 th:utext="${course.courseGrade}>3?'<u>主课</u>':一般"></h1>
4、条件运算
<span th:text="${grade} ge 90?'good':${grade}">spring</span>
配置:关闭自动缓存spring.thymeleaf.cache=false
引入th名称空间:<html xmlns:th="http://www.thymeleaf.org">
引入th名称空间:<html xmlns:th="http://www.thymeleaf.org">
循环遍历array、list、map
if、switch条件判断
inline内敛表达式
a、内敛文本:
<div th:inline="text">
数据:[[${data}]]
</div>
b、内敛脚本:
<script type="text/javascript" th:inline="javascript">
splice字符拼接,例:
<span th:text="|共${totalRows}条${totalPage}页,当前第${currentPage}页,首页 上一页 下一页 尾页|"></span>
<div th:inline="text">
数据:[[${data}]]
</div>
b、内敛脚本:
<script type="text/javascript" th:inline="javascript">
splice字符拼接,例:
<span th:text="|共${totalRows}条${totalPage}页,当前第${currentPage}页,首页 上一页 下一页 尾页|"></span>
literal字面量
operatal数学运算
基本表达式对象(内置功能对象前加#)
//获取协议名称
let scheme = [[${#request.getScheme()}]];
//获取服务器名称
let serverName = [[${#request.getServerName()}]];
//获取服务器端口号
let serverPort = [[${#request.getServerPort()}]];
//获取上下文路径
let contextPath = [[${#request.getContextPath()}]];
let allPath = scheme+"://"+serverName+":"+serverPort+contextPath;
// alert(allPath)
let requestUrl = [[${#httpServletRequest.requestURL}]];
let queryString = [[${#httpServletRequest.queryString}]];
let requestAddress = requestUrl + "?" + queryString;
alert(requestAddress)
let scheme = [[${#request.getScheme()}]];
//获取服务器名称
let serverName = [[${#request.getServerName()}]];
//获取服务器端口号
let serverPort = [[${#request.getServerPort()}]];
//获取上下文路径
let contextPath = [[${#request.getContextPath()}]];
let allPath = scheme+"://"+serverName+":"+serverPort+contextPath;
// alert(allPath)
let requestUrl = [[${#httpServletRequest.requestURL}]];
let queryString = [[${#httpServletRequest.queryString}]];
let requestAddress = requestUrl + "?" + queryString;
alert(requestAddress)
功能表达式对象
#dates
#calendars
#numbers
#strings:contains,startWith,appending等
#objects
#bools
#arrays
#lists
#maps
#aggregates
#calendars
#numbers
#strings:contains,startWith,appending等
#objects
#bools
#arrays
#lists
#maps
#aggregates
0 条评论
下一页