什么是 spring boot
-----简单的说, spring boot 就是整合了很多优秀的框架,不用我们自己手动的去写一堆 xml 来进行配置。
从本质上来说, Spring Boot 就是 Spring, 它做了那些没有它你也会去做的 Spring Bean 配置。它使用 “ 习惯优于配置 ” (项目中存在大量的配置,此外还内置了一个习惯性的配置,让你无需手动进行配置)的理念让你的项目快速运行起来。使用 Spring Boot 很容易创建一个独立运行
(运行 jar, 内嵌 Servlet 容器)、准生产级别的基于 Spring 框架的项目,使用 Spring Boot 你可以不用或者只需要很少的 Spring 配置。
框架特点:
1 :创建独立的 spring 应用。
2 :嵌入 Tomcat, Jetty, Undertow 而且不需要部署他们。
3 :提供的 “starters” 来简化 Maven 配置
4 :尽可能自动配置 spring 应用 , 绝对没有代码生成和 XML 配置要求。
5 :提供生产指标 , 健壮检查和外部化配置
微服务架构 :
将子系统拆成一个一个的 jar 包运行就是微服务。 Spring Boot算是微服务 开发的入门级 框架
2.spring boot 优缺点:
优点:
快速构建项目
对主流的开发框架的无配置集成
项目可以独立运行,无须外部依赖 servlet 容器
提供运行时的应用监控
极大的提高了开发、部署效率
与云计算的天然集成
缺点:
入门易,精通难,它没有增强 spring 的功能,只是帮助我们做了很多本需要我们自己
做的配置整合工作,本质还是我们以前学习的那些框架知识的应用。
SpringBoot的入门案例
- 创建一个并配置项目
1,创建一个Maven工程
处理中文乱码设置
2,进入官网,找到pom.xml配置文件
百度---搜索‘spring’---进入一个主页---project---spring boot,当前版本为3.x1(2023年1月)
maven配置,分别是启动器,web应用
4.0.0
cn.ybzy.spbtdemo
springbootdemo
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-parent
3.0.1
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-configuration-processor
true
8
8
org.springframework.boot
spring-boot-maven-plugin
有可能有如下错误:
java: 无法访问org.springframework.boot.SpringApplication
错误的类文件: /E:/JavaWeb/maven/local_repository35/org/springframework/boot/spring-boot/3.0.1/spring-boot-3.0.1.jar!/org/springframework/boot/SpringApplication.class
类文件具有错误的版本 61.0, 应为 52.0
请删除该文件或确保该文件位于正确的类路径子目录中。
该版本号与jdk版本号存在对应关系,61.0对应jdk17,52.0对应jdk8。
所以是某个依赖的版本太高,降低版本即可,具体是哪个依赖就需要自己排查了
我的项目中是
org.springframework.boot
spring-boot-starter-parent
3.0.0
改为2.0.0.RELEASE,再重新load [maven](就是点一下右上角的m字小按钮),就好了
org.springframework.boot
spring-boot-starter-parent
2.7.1
3,写一个启动入口,并启动之。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 这个注解就是告诉我们的springboot这个类就是我们主启动类
*/
@SpringBootApplication
public class ApplictionMain {
//main程序的主入口
public static void main(String[] args){
SpringApplication.run(ApplictionMain.class,args);
}
}
再在控制层写一个控制类IndexController.java
@Controller
public class IndexController {
@ResponseBody //这里没有做视图(index.html)模板,这里我们直接返json格式数据到浏览器
@RequestMapping(value={"/index.html","/"},method = RequestMethod.GET)
public String index(){
return "hello spring boot project";
}
}
4,启动
或打包复制到任何地方,再运行java -jar命令
cmd---输入如下命令,启动程序
E:\java>java -jar springbootdemo-1.0-SNAPSHOT.jar
浏览器中输入http://localhost:8080/index.html
如果端口号被占用,可用如下图所示处理
快速创建SpringBoot项目
在项目开发时候,我们不会自己创建一个maven项目,自己慢慢导入依
赖,有更方便的方法:
- idea快速创建spring boot项目:
使用Spring Initializr
注意1:需要联网
注意2:resources里的目录结构:
(1)static:是用来存放静态资源的,比如css,js,img....;
(2)templates:用来存放freemarker或者thymeleaf的模板
(3)application.properties: SpringBoot的配置文件,在这里可以修改SpringBoot的默认配置
注意:默认启动器为3.0.1(即现在最新稳定版2022/12/30),要匹配jdk15,但本人还用jdk 8,所以改一下pom.xml文件中的启动器为2.7.1版。
org.springframework.boot
spring-boot-starter-parent
2.7.1
8
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
-
sts(eclipse)快速创建spring boot项目
对SpringBoot入门案例的关键点
我们SpringBoot的入门案例中,即做了两个重要工作:配置pom.xml文件,写启动类
- pom.xml依赖配置文件,这里两个关键点:
①帮助我们进行版本控制的父模块
org.springframework.boot
spring-boot-starter-parent
2.7.1
在这个父模块的父模块里有spring boot的所有默认依赖的jar包的版本信息
②启动器的配置,这个启动器才是真正导入jar的配置
org.springframework.boot
spring-boot-starter-web
这种启动器, spring boot 有 44 个之多,每一个启动器就对应一个功能完整的应用场景所需要的一系列 jar
包:
spring-boot-starter-web :这个启动器就是与 web 应用有关的所有 jar 包, spring boot 配置了这个的启动器,
就会自动导入这个启动器对应 web 应用的所需要的所有 jar 包。
这两个核心配置,一个决定默认的jar包的版本,一个决定导入什么jar包!\
-
程序入口主类:ApplicationMain,这里也有两个注意的知识点:
①注解 @SpringBootApplication 声明有这个注解的类是主类,是spring boot的执行的入口,没有这个注解注解的类,就没有入口,没有入口,应用就启动不了
② SpringApplication.run( ApplicationMain .class, args); 的第一个参数的意义:让springboot知道 ApplicationMain 所在的包以及这个包下的所有子包,是spring的扫描组件范围,只有在这个范围的controller,service,dao里的组件类才能被spring扫描到,并且初始化对象,放入到spring的ioc容器里! 所以就意味着,主类所在的位置必须比controller,service,dao层的组件类所在的包结构的上层。
SpringBoot的配置文件
SpringBoot的有两种格式的全局配置文件,使用任何一个功能都是一样的, 注意:
SpringBoot的全局配置文件名都是固定的application.xxx
① application.properties, 这个是默认Spring initializr默认自动生成的配置文件,也是我们属性的文件格式
示例:在properties文件中写入对象值,通过model类关联,测试
server.port=8082
server.error.path=/error
server.servlet.session.timeout=30m
#server.srvlet.context-path=/chapter02 #这里是项目名称,没有则表示为'/',若写上,表示访问时要带上该名字。
server.tomcat.uri-encoding=utf-8
server.tomcat.max-threads=500
#server.tomcat.basedir=/home/sang/tmp
book.name=三国演义 //这里写第一篇或复帽粘贴过来时容易出现中文乱码,在已设置file encodings为utf-8后,还出现乱码,再重新输入一次中文。
book.author=罗贯中
book.price=30
Book.java
@Component
@ConfigurationProperties(prefix = "book")
public class book {
private String name;
private String author;
private Float price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
this.price = price;
}
@Override
public String toString() {
return "book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
'}';
}
}
BookController.java
@RestController
public class BookController {
@Autowired
book book;
@GetMapping("/book")
public String book1(){
return book.toString();
}
}
5--测试
https://localhost:8080/book回车
② application.yml,除了properties文件可以做为SpringBoot的配置文件以外,SpringBoot还支持一种我们以前没接触过的配置文件,这就是YAML配置文件
YAML文件的语法格式
① 基本格式: key: value 注意:键值对中的值前面必须有空格,多少个无所
谓,但必须有,这是语法
② 靠键左对齐来区分层级关系,也就是说凡是左对齐的键值对都是一个层次的
③ 大小写敏感,严格区分大小写的
④ 字符串默认不用引号引起来,在值里用 “不会转义特殊字符,\n会换行”,‘会转
义特殊字符,\n会输出’
⑤ 对象或Map集合的表示方法有两种,一种是用换行+缩进,另一种是利用大括号
----YAML简洁强大,是一种专门用来书写配置文件的语言,可以替代properties文件。spring-boot-starter-web依敇间接地引入了snakeyaml依赖,snakeyaml会实现对YAML配置的解析。YAML的使用非常简单,利用缩进来表示层级关系,并且大小写敏感。在springboot项目中使用YAML只需要在resources目录下创建一个xxx.yml文件即可。如:application.yml
server:
port: 80
# servlet:
# context-path: /springbootvue
tomcat:
uri-encoding: utf-8
my:
name: 江南一点雨
address: chian
User.java
@Component
@ConfigurationProperties(prefix = "my")
public class User{
private String name;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
}
这里会把 yml中定义的my对象注入到User属性中。
@RestController
public class UserController {
@Autowired
User user;
@GetMapping("/user")
public String user(){
return user.toString();
}
}
该控制类中,用做测试我们来显示对象的属性值。
http://localhost:80/user回车
示例2:配置Map,List变量,并且在测试类中测试打印对象的值
UserZhf.java
//alt+ins键,选择产生get,set,toString方法项
@Component //标记为组件,放到spring的IOC容器里
@ConfigurationProperties(prefix="user")
public class UserZhf {
private int id;
private String username;
private String password;
private Date birthday;
private boolean sex; //true表示男,false表示女
private List list; //这是测试,实际开发中没有意义
private Map map;
private Address address; //关联对象 Address
public Address getAddress() {
return address;
}
.......set方法,toString()方法
Address.java----该类上没有任何注解
public class Address {
private int id;
private String detail;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
@Override
public String toString() {
return "Address{" +
"id=" + id +
", detail='" + detail + '\'' +
'}';
}
}
application.yml
user:
id: 100
username: 张三
password: 123456
birthday: 2022/12/31
sex: true
list: {aaa,bbb,ccc,ddd}
map: {aa:cexoit,bb:xuhuifeng}
address:
id: 200
detail: 江西南昌
application.properties文件中的对象配置
打印结果:
userZhfUserZhf{id=100, username='张三', password='123456', birthday=Sat Dec 31 00:00:00 CST 2022, sex=true, list=null, map={aacexoit=, bbxuhuifeng=}, address=Address{id=200, detail='江西南昌'}}
通过注解@Vuale从全局配置文件中获取数据
-----除了通过注解@ConfigurationProperties让JavaBean的所有属性和全局配置文件中
配置项建立关联关系外,我们spring提供了一个@Value注解,获取全局配置文件中的某个配置项的数据,看例子:
@Component //标记为组件,放到spring的IOC容器里
//@ConfigurationProperties(prefix="user") //注释它,我们用@Value获取全局文件中配置的属性值
public class UserZhf {
@Value("#{11+22}")
private int id;
@Value(value="${user.username}")
private String username;
private String password;
private Date birthday;
@Value("true")
private boolean sex; //true表示男,false表示女
private List list; //这是测试,实际开发中没有意义
private Map map;
private Address address;
-------
接下来,我们重点说一下两个注解的的区别:
@ConfigurationProperties: 是和JavaBean的所有属性绑定
@Value: 是一个一个属性绑定
@ConfigurationProperties: 不支持spring表示式的写法
@Value: 支持spring的表达式的写法,#{12+13}
@ConfigurationProperties: 支持JSR303数据校验
@Value:不支持JSR303数据校验
@ConfigurationProperties: 支持复杂的类型绑定,比如Map,List
@Value:不 支持复杂的类型绑定,比如${user.map}是读不出数据的从区别中我们可以得到这样的结论或建议:
① 当我们有JavaBean与全局配置文件里的数据对应的时候,我们就用 @ConfigurationProperties 注解
② 当我们只是需要配置文件中某一个值的时候,就用 @Value 注解
三,注解@PropertiySource读取外部属性文件
首先:我们新建一个文件user.properties如下图位置。
其次:把UserZhf.java写成如下:
@Component //标记为组件,放到spring的IOC容器里
@ConfigurationProperties(prefix="user") //似乎不能注释它,要用它定到一个叫user的名字止。
@PropertySource({"classpath:user.properties"})
public class UserZhf {
private int id;
private String username;
private String password;
private Date birthday;
private boolean sex; //true表示男,false表示女
private List list; //这是测试,实际开发中没有意义
private Map map;
private Address address;
get/set/toString方法
}
UserController.java不变
最后:测试,启动启动类,打印结果如下
2023-01-08 05:58:49.012 INFO 1104 --- [ main] c.y.spbtdemo.SpbtdemoApplicationTests : Started SpbtdemoApplicationTests in 4.682 seconds (JVM running for 8.507)
userZhfUserZhf{id=111, username='aaa', password='123456', birthday=Mon Dec 13 00:00:00 CST 1999, sex=false, list=[aaaa, bbbb, cccc], map={gggg=tttt, uuu=kkkk}, address=Address{id=4000, detail='江西南昌市'}}
四,注解@ImportResource引入自定义spring的配置xml文件和配置类
首先:新建一个spring.xml文件,把类Address实例化放入IOC中。
然后:启动入口类中,加入如下
@ImportResource({"classpath:spring.xml"})
@SpringBootApplication
public class SpbtdemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpbtdemoApplication.class, args);
}
}
再然后:在控制类中或测试类中(写如下代码),本例是测试类中测试
@SpringBootTest
class SpbtdemoApplicationTests {
@Autowired
private Address address;
@Test
public void getAddress() {
System.out.println("address"+address);
}
}
最后:启动启动类,可以看到如下结果,虽然没结果,但表时Address实例化了。
addressAddress{id=0, detail='null'}
五,Spirng Boot里的配置类
-----上面是四一种做法,但是spring boot不推荐这样子做,它推荐尽可能全部用注解完成配置,所有它使用了一种我们以前没玩儿过的“配置类”来替代我们的上面的spring.xml这种xml配置文件,具体做法:
① 定义一个类做为配置类,用这个配置类代替spring.xml,所有他们之间存在一个一一对应的关系,这里我们把Addressbean配置到IOC容器中
@Configuration //表明是配置类,这里我们把Addressbean配置到IOC容器中
public class MyConfig {
@Bean
public Address address(){
return new Address();
}
}
②,删除四配置的spring.xml文件,删除启动类中的@ImportResource,再同样的测试单元里看看,配置类起做用没的?
六,配置文件中使用随机值和使用变量
1、配置文件中使用随机值,看个例子就ok:user.properties.
-------在配置文件使用引用变量,如果没定义还可以设置默认值,看例子:
user.id=${random.int}
user.username=${random.value}
user.password=${random.uuid}
user.birthday=1999/12/13
user.list=aaaa,bbbb,cccc
user.map.gggg=${user.username}
user.map.uuu=${abcdef:默认值}
user.address.id=${random.int(10)}
user.address.detail=江西南昌市
2,UserZhf.java
@Component //标记为组件,放到spring的IOC容器里
@ConfigurationProperties(prefix="user") //注释它,我们用@Value获取全局文件中配置的属性值
@PropertySource({"classpath:user.properties"})
public class UserZhf {
private int id;
--------
}
3,看效果,在测试类或控制类中都可以。
@SpringBootTest
class SpbtdemoApplicationTests {
@Autowired
private UserZhf user;
@Test
public void contextLoads() {
System.out.println("userZhf"+user);
}
}
在配置文件中使用Profile
----Profile ,译为“配置文件”,这种配置我们在讲Maven课程的时候,就已经遇到过了,回忆一下我们当初Maven里的配置:
myProfile
upload
myfirstRepository
http://124.222.48.147:8081/nexus/content/groups/public/
true
true
default
public
myPlugins
http://124.222.48.147:8081/nexus/content/groups/public/
true
true
jdk-1.8
true
jdk1.8
1.8
1.8
1.8
在这里的Spring Boot也是一样,我们可以配置很多个Profile,每个Profile都对应
一整个完整的全局配置,激活哪个,那个对应的全局配置就生效,具体的配置:
1,properties格式的全局配置文件的做法:
默认的application.properties文件还是不可少,但是我们可以多做几个配置文件,名字取为application-xxx.properties然后不做激活配置,默认就是使用application.properties,在application.properties做了激活配置,激活哪个,哪个生效:
我们可以在三个不同的文件中,设置不同的端口号,启动程序,看看端口号就可以看到效果了。
激活application-aaaa.properties的配置:
依次类推.....
2,yaml格式配置文件的做法,多文档块方式:
1.这样搞的话,好象现在过时了(2023年1月)但还能用。
2.这样搞还行。建了三个yml文件,分别进行了不同的配置。
application-prod.yml
# 需要部署上线的时候再用这个prod配置,记得把下面信息都改成你自己的
# 去application.yml里配置active: prod就可以运行本地prod环境
server:
port: 443 #https加密端口号 443
ssl: #SSL证书路径 一定要加上classpath:
key-store: classpath:xiongshaowen.club.jks
#SSL证书密码(密码在第一步的keystorePass.txt中)
key-store-password: b8iun3805c8h
#证书类型
key-store-type: JKS
servlet:
context-path: /diancan
# 记得把数据库账号密码改为你服务器里mysql的账号和密码
spring:
datasource:
url: jdbc:mysql://localhost/diancan?characterEncoding=utf-8&useSSL=false&serverTimeZone=UTC
&useOldAliasMetadataBehavior=true&allowPublicKeyRetrieval=true
username: root
password: xiong
hikari:
connection-init-sql: set names utf8mb4
tomcat:
init-s-q-l: SET NAMES utf8mb4 #这是最重要的一步
jpa:
show-sql: true
hibernate:
ddl-auto: update
application-test.yml
# 去application.yml里配置active: test就可以运行本地test环境
server:
port: 8081
servlet:
context-path: /diancan
spring:
datasource:
url: jdbc:mysql://124.222.48.147/diancan?characterEncoding=utf-8&useSSL=false&serverTimeZone=UTC
&useOldAliasMetadataBehavior=true&allowPublicKeyRetrieval=true
username: root
password: xiong
hikari:
connection-init-sql: set names utf8mb4
tomcat:
init-s-q-l: SET NAMES utf8mb4 #这是最重要的一
jpa:
show-sql: true
hibernate:
ddl-auto: update
3、除了在默认的配置文件里激活Profile以外,还可以用命令的方式激活,命令的方式激活时会忽略配置文件的激活配置
----① 在idea里配置命令行参数
[图片上传失败...(image-f4b7e2-1673822538435)]
----② 打成jar包后,启动是在启动命令后带激活命令参数
SpringBoot里的多配置文件优先级和运行时修改配置
在SpringBoot中默认会扫描好几个地方的默认配置文件:
项目的根目录/config/-----最高优先级
项目的根目录/-----第二优先级
类路径/config/-----第三优先级
类路径/-----第四优先级
如果这四个位置都有配置文件,那么四个配置文件都会生效,只不过四个配置文件中的相同配置项,生效的是高优先级的配置文件里的配置项!
----在项目已经打包运行后,我们有时候是需要修改配置的,这时还可以在jar的外面,新建一个配置文件,然后运行jar命令后面跟上 --spring.config.location=x:xxxx/application.properties,那么这个新配置文件会覆盖jar里的配置文件里的相同配置项的配置。 外面的这个配置文件优先级最最高!
SpringBoot全局配置文件里的配置项
---SpringBoot核心配置文件里可以配置的配置项,非常非常多!Spring BootReference Guide靠后的附件里看到所有配置项和说明
https://docs.spring.io/spring-boot/docs/2.7.7/reference/htmlsingle/----->https://docs.spring.io/spring-boot/docs/2.7.7/reference/htmlsingle/#appendix
① SpringBoot给我们做了很多默认配置,这些配置,具体配置在哪个文件里:
spring-boot-autoconfigure-2.0.5.RELEASE.jar里的META-INF/spring.factories/ EnableAutoConfiguration 属性里,在这个属性里指定了一大推的配置类 XxxxAutoConfiguration ,前面我们讲过,SpringBoot是用 配置类 来代替了我们在Spring中使用的xml格式的配置文件。
② 在这些配置类中都通过了一个注解 @EnableConfigurationProperties 指向了一个 XxxxxxProperties 的类,这个类又用注解 @ConfigurationProperties 关联上了我们SpringBoot的全局配置文件,从全局配置文件中读取数据!
③ SpringBoot默认写好的这些配置类是不是都在初始的状态下 已经生效?不
是 !SpringBoot里的默认的配置类里的配置项要生效都是有条件的,配置类中通过了一些列 @ConditionalXXX 注解进行判断,只有这些条件都返回true,这个配置才会起作用!
④ 我们在SpringBoot的全局配置文件中的具体配置项,其实就是前面介绍的 XxxxxxProperties 的类里的属性:
⑤ SpringBoot里有这么多默认的配置,那么那些是已经生效的,那些是没有生效的, 怎么查? 在全局配置文件application.properties/yml中设置 debug=true 运行主方法,会生成一份老长的默认配置生效的和没生效的报告:
============================
CONDITIONS EVALUATION REPORT
============================
Positive matches:
-----------------
AopAutoConfiguration matched:
- @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition)
AopAutoConfiguration.ClassProxyingConfiguration matched:
- @ConditionalOnMissingClass did not find unwanted class 'org.aspectj.weaver.Advice' (OnClassCondition)
- @ConditionalOnProperty (spring.aop.proxy-target-class=true) matched (OnPropertyCondition)
DispatcherServletAutoConfiguration matched:
- @ConditionalOnClass found required class 'org.springframework.web.servlet.DispatcherServlet' (OnClassCondition)
- found 'session' scope (OnWebApplicationCondition)
使用SpringBoot整合Servlet
SpringBoot和Servlet的整合,有两种玩法,第一种玩法是:
1、创建一个SpringBoot的web工程,在工程用创建一个Servlet,用注解 @WebServlet 配置Servlet映射
ALT+INSERT键去选择覆盖的方法,这里我用doGet方法。
@WebServlet(urlPatterns="/index.html")
public class IndexServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("IndexServlet....的doget的方法被调用了");
}
}
2、在SpringBoot的启动类上加注解@ServletComponentScan
@SpringBootApplication
@ServletComponentScan
public class SptdemoApplication {
public static void main(String[] args) {
SpringApplication.run(SptdemoApplication.class, args);
}
}
3,测试
localhost:8080/index.html
运行回车,空白没事,到控制台中我们可以看到
2023-01-19 11:01:36.557 INFO 7756 --- [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2023-01-19 11:01:36.557 INFO 7756 --- [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 0 ms
IndexServlet....的doget的方法被调用了
第二种玩法,在SpringBoot的启动类上也不用加注解 @ServletComponentScan, 而是在启动类文件中可以用一个方法来代替前面的两个注解的作用
SpringBootApplication
public class SptdemoApplication {
public static void main(String[] args) {
SpringApplication.run(SptdemoApplication.class, args);
}
@Bean //把IndexServlet注入到IOC容器中
public ServletRegistrationBean getMyServletBean(){
ServletRegistrationBean bean = new ServletRegistrationBean(new IndexServlet());
bean.addUrlMappings("/index.html");
return bean;
}
}
使用SpringBoot整合filter
SpringBoot整合filter,和整合servlet类似,也有两种玩儿法
一,第一种方法
1、创建一个SpringBoot工程,在工程中创建一个filter过滤器,然后用注解 @WebFilter
上图extedns改为implements,因为Filter是一个接口,ALT+INSERT键去选择要实现的方法,这里三个方法全选中。
@WebFilter(filterName = "myFilter",urlPatterns={"/index.html"}) //可以拦截很多内容,用逗号隔开,这里我只拦截index.html
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("MyFilter拦截器进来了。。。。");
filterChain.doFilter(servletRequest,servletResponse); //放行
System.out.println("MyFilter拦截器进来了.....");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
}
2、启动类还是使用 @ ServletComponentScan 注解来扫描拦截器 注解 @WebFilter
@SpringBootApplication
@ServletComponentScan
public class SptdemoApplication {
public static void main(String[] args) {
SpringApplication.run(SptdemoApplication.class, args);
}
}
3,localhost:8080/index.html
回车后,控制台显示,说明刚开始是拦截了,但又放行了。
MyFilter拦截器进来了。。。。
IndexServlet....的doget的方法被调用了
MyFilter拦截器进来了.....
二,另一种玩儿法,和Servlet一样也是做一个方法,来替代上面的两个注解的作用:
//拦截器类中没有@WebFilter注解
//@WebFilter(filterName = "myFilter",urlPatterns={"/index.html"}) //可以拦截很多内容,用逗号隔开,这里我只拦截index.html
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("MyFilter拦截器进来了。。。。");
filterChain.doFilter(servletRequest,servletResponse); //放行
System.out.println("MyFilter拦截器进来了.....");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
}
//启动类中,没有了@ServletComponentScan注解
@SpringBootApplication
public class SptdemoApplication {
public static void main(String[] args) {
SpringApplication.run(SptdemoApplication.class, args);
}
@Bean //把IndexServlet注入到IOC容器中
public ServletRegistrationBean getMyServletBean(){
ServletRegistrationBean bean = new ServletRegistrationBean(new IndexServlet());
bean.addUrlMappings("/index.html");
return bean;
}
@Bean
public FilterRegistrationBean getFilterBean(){
FilterRegistrationBean bean = new FilterRegistrationBean(new MyFilter());
bean.addUrlPatterns("/index.html");
return bean;
}
}
问题:有时,拦截器配置拦截有所url地址的时候/*
,会出现连续拦截两次的情况,原因是因为浏览器发出访问了图标favicon.ico的请求,本人还没遇到这种情部况
处理办法:
使用SpringBoot整合Listener监听器
常用的Web事件的监听接口如下:
ServletContextListener:用于监听Web的启动及关闭
ServletContextAttributeListener:用于监听ServletContext范围内属性的改变
ServletRequestListener:用于监听用户请求
ServletRequestAttributeListener:用于监听ServletRequest范围属性的改变
HttpSessionListener:用于监听用户session的开始及结束
HttpSessionAttributeListener:用于监听HttpSession范围内的属性改变
第一种方法,例:web系统初始化的监听
1.新建一个监听器
2.启动类中加@ServletComponentScan注解
3.测试效果
2023-01-19 12:17:18.509 INFO 7208 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 605 ms
系统初始化了!。。。。。
2023-01-19 12:17:18.703 INFO 7208 --- [
第二种方法
1.去掉第一种方法中的两个注解@WebListener和@ServletComponentScan.
2.启动类中,加一个方法,把监听器对象注入到IOC容器中。
SpringBoot访问web中的静态资源
总体来讲SpringBoot访问web中的静态资源,有两个方式:
- SpringBoot默认指定了一些固定的目录结构,静态资源放到这些目录中的某一个,
系统运行后浏览器就可以访问到
① 关键是SpringBoot默认指定的可以存放静态资源的目录有哪些?
a. classpath:/META-INF/resources/
b. classpath:/resources/
c. classpath:/static/ 这个是工具自动帮我们生成目录,用的最多的目录
d. classpath:/public/
e. / 当前项目的跟路径
f. src/main/webapp/
----当一个index.html是自建的话,放进/static/下后,启动系统时,只输入ip+端口号后,回车,会显示它。但当动态控制类中有返回的 index.html时,会优先访问。
----本人一般不会去改变这些目录,一般把静态资源放在static下。
② 这些默认的目录是可以在全局配置文件中修改,修改后,除配置的目录以外其他目录就不可以再访问静态资源了:
spring.resources.static-locations=classpath:resources,classpath:static
③ SpringBoot默认的首页是放在任一个静态资源目录下的index.html
------当然了,如果有动态index.html,则会显示它,不会显示静态的的index.html.
④ SpringBoot默认的web页面图标是放在任一静态资源目录下的favicon.ico
我们在这里目录下选两个放一个index.html和一张图片实验一下就ok!
ico图片我们可以在网上搜ico在线制作,即可找到相应的网站,我们制一个即可
2、把静态资源打成jar包引入系统后供访问
http://www.webjars.org 这个网站上提供了常用的静态资源的jar包的maven依赖:
把依赖配置到maven的pom.xml中,就可以在 网站根目
录/webjars/jquery/1.12.4/jquery.js 访问到资源!
http://localhost:8080/webjars/jquery/1.12.4/jquery.js
SpringBoot整合web中使用jsp
SpeingBoot官方是不推荐使用jsp这个引擎模板的,所有它的默认配置中是没有配置jsp支持的,但是jsp应该是我们学习JavaWeb技术以来最熟悉的视图引擎,依赖性还是很强,还是来讲讲怎么在SpringBoot中整合它:
1、在pom.xml文件中导入jsp依赖的jar包,一个是jstl标签,一个是jsp的引擎
org.springframework.boot
spring-boot-configuration-processor
true
org.apache.taglibs
taglibs-standard-spec
1.2.5
org.apache.taglibs
taglibs-standard-impl
1.2.5
org.apache.tomcat.embed
tomcat-embed-jasper
9.0.64
2、在SpringBoot的全局配置文件中修改SpringBoot的默认视图解析器的前缀和后缀。spring.mvc.view相当天src/main/webapp目录。webapp下有WEB-INF目录,它下面我们又建jsp目录,以便存放jsp视图。
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
注意:要把webapp目录添加到springboot的web服务中。
3,控制层中与jsp中的代码
IndexController.java
@Controller
public class IndexController {
@GetMapping("/index")
public String index(Model model){
model.addAttribute("aaa","jsp视图引擎!!");
return "index";
}
}
index.jsp----用到了jstl标签与EL
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
jsp测试
jsp首页 ${12+12}
aaa的值: ${aaa}
测试
http://localhost:8080/index
SpringBoot整合Freemarker(类似jsp视图)
Freemarker和jsp一样是一个视图的引擎模板,其实所有的模板引擎的工作原理都是类似的,如下图:
SpringBoot默认就支持这个模板,下面看看怎么把他们整合在一起:
中文在线手册
http://freemarker.foofun.cn/dgui_quickstart_basics.html
1、配置freemarker的启动器
org.springframework.boot
spring-boot-starter-parent
2.0.4.RELEASE
org.springframework.boot
spring-boot-starter-freemarker
2、编写controller类和Model类
User.java
public class User {
private int id;
private String username;
private String password;
public int getId() {
return id;
}
public User() {
}
public User(int id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
-------------
IndexController.java
@Controller
public class IndexController {
@RequestMapping(value="/index.html",method= RequestMethod.GET)
//@GetMapping("/index.html")
public String index(Model model){
List users = new ArrayList();
users.add(new User(1,"aaa","aaa123"));
users.add(new User(2,"bbb","bbb123"));
users.add(new User(3,"ccc","ccc123"));
model.addAttribute("users",users); //把users注入的视图中
return "users"; //返回到一个视图中
}
}
3,编写ftl模板文件,注意:模板文件必须放在src/resources/templates目录下
users.ftl
freemarker视图模板
<#list users as user>
用户id: ${user.id}
用户名: ${user.username}
用户密码: ${user.password}
#list>
4,测试 http://localhost:8080/index.html
----freemarker常用的标签语法
<1>freemarker的标签种类
${..}:FreeMarker will replace it in the output with the actual value of the thing in the
curly brackets. They are called interpolation s.
<#.. , 代表是 FTL tags ( FreeMarker Template Language tags ) , hey are instructions to
FreeMarker and will not be printed to the output
<#if ...>#if>
<#list totalList as elementObject>...#list>
<@ , 代表用户自定义的标签
<#-- --> 注释标签,注意不是
<2>一些特殊的指令:
r 代表原样输出: ${r"C:\foo\bar"}
<#list ["winter", "spring", "summer", "autumn"] as x>${x}#list>
?引出内置指令
String 处理指令:
html : 特殊的 html 字符将会被转义,比如 "<" ,处理后的结果是 <
cap_first 、 lower_case 、 upper_case
cap_first: 将字符串的第一个字符或者字母 ( 仅前几个字符是空格的情况 ) 大写 ( 如果第一个字符是字母 );
如果字符串的第一个字符不是字母 ( 空格除外 ) ,将按照原来字符串的格式返回 ; 若第一个字符是字母并且是大写的情况,结果同上。
trim : 除去字符串前后的空格
sequences 处理指令
size :可以用于返回 list 集合的元素个数
numbers 处理指令
int : number 的整数部分, (e.g. -1.9?int is -1)
举例:
1.r,#list的用法。
用户id: 1 用户名: aaa 用户密码: aaa123 用户id: 2 用户名: bbb 用户密码: bbb123 用户id: 3 用户名: ccc 用户密码: ccc123
c:\foo\bar
winter
spring
summer
autumn
2.?的用法,先用assign定义一个变量aaa,再显示。
<#assign aaa="xiongshaowen
"/>
${aaa}
${aaa?html}
${aaa?upper_case}
${users?size}
${125.3658?int}
结果:
<3>对于null,freemarker会报错处理
! :默认值操作符,语法结构为: unsafe_expr ! default_expr ,
比如 ${mouse!"No mouse."} 当 mouse 不存在时,返回 default value ;
(product.color)!"red" 这种方式,能够处理 product 或者 color 为 missvalue 的情况;
而 product.color!"red" 将只处理 color 为 miss value 的情况
?? : Missing value test operator , 测试是否为 missing value
unsafe_expr?? : product.color?? 将只测试 color 是否为 null
(unsafe_expr)?? : (product.color)?? 将测试 product 和color 是否存在 null
举例:
1.设默认值
${mouse!"xiongshaowen"}
2.判断是否为空
<#if mouse??>
Mouse found
<#else>
No mouse found
#if>
No mouse found
<#assign mouse="xiong">
<#if mouse??>
Mouse found
<#else>
No mouse found
#if>
mouse found
<3>分支语句
1.if分支
语法:
<#if condition>
...
<#elseif condition2>
...
<#elseif condition3>
...
<#else>
...
#if>
例子:
<#if x = 1>
x is 1
#if>
---------------------------------
<#if x = 1>
x is 1
<#else>
x is not 1
#if>
2.switch分支
语法:
<#switch value>
<#case refValue1>
...
<#break>
<#case refValue2>
...
<#break>
<#case refValueN>
...
<#break>
<#default>
...
#switch>
举例:
<#assign size="large"/>
<#switch size>
<#case "small">
This will be processed if it is small
<#break>
<#case "medium">
This will be processed if it is medium
<#break>
<#case "large">
This will be processed if it is large
<#break>
<#default>
This will be processed if it is neither
#switch>
<4>list循环,它可以用用if语句跳出循环。
<#list sequence as item>
...
<#if item = "spring"><#break>#if>
...
#list>
举例:
<#assign seq = ["winter", "spring", "summer", "autumn"]>
<#list seq as x>
${x_index + 1}. ${x}<#if x_has_next>,#if>
#list>
----------------------------------------------结果------------------------------------------------------------------------------------
1. winter,
2. spring,
3. summer,
4. autumn
关键字:item_index: 是 list 当前值的下标,从 0 开始 item_has_next: 判断 list 是否还有值
<5>macro, nested, return宏的应用
语法
<#macro name param1 param2 ... paramN>
...
<#nested loopvar1, loopvar2, ..., loopvarN> //有了这和标签:调用宏的时候,必须用双标签
...
<#return>
...
#macro>
宏举例应用:先定义宏,再调用宏,宏里面可以有html标签,这样的话我们可以把一系列标签放在一起重复利用。
<#macro test foo bar="Bar" baaz=-1>
Test text, and the params: ${foo}, ${bar}, ${baaz}
#macro>
<@test foo="a" bar="b" baaz=5*5-2/>
<@test foo="a" bar="b"/>
<@test foo="a" baaz=5*5-2/>
<@test foo="a"/>
---------------------------------------------------------------------结果----------------------------------------------------------------
Test text, and the params: a, b, 23
Test text, and the params: a, b, -1
Test text, and the params: a, Bar, 23
Test text, and the params: a, Bar, -1
循环的宏
<#macro list title items>
${title?cap_first}:
<#list items as x>
*${x?cap_first}
#list>
#macro>
<@list items=["mouse", "elephant", "python"] title="Animals"/>
---------------------------------------------------------------------结果----------------------------------------------------------------
Animals:
*Mouse
*Elephant
*Python
包含body 的宏
上图中的1..count as x表示从1到count(传来了值5)的循环,contant等是自定义的名字
<#macro repeat count>
<#list 1..count as x>
<#nested x, x/2, x==count>
#list>
#macro>
<@repeat count=5; contant,contant_half,is_last>
有一个有body的宏,宏里给我传来了三个值: ${contant},${contant_half},<#if is_last> 这是最后一个值#if>
@repeat>
----------------------------------------------------------------结果-----------------------------------------------
有一个有body的宏,宏里给我传来了三个值: 1, 0.5,
有一个有body的宏,宏里给我传来了三个值: 2, 1,
有一个有body的宏,宏里给我传来了三个值: 3, 1.5,
有一个有body的宏,宏里给我传来了三个值: 4, 2,
有一个有body的宏,宏里给我传来了三个值: 5, 2.5, 这是最后一个值
<#macro repeat count>
<#list 1..count as x>
<#nested x, x/2, x==count>
<#if x==3> <#return> #if>
#list>
#macro>
<@repeat count=5; contant,contant_half,is_last>
有一个有body的宏,宏里给我传来了三个值: ${contant}, ${contant_half},<#if is_last> 这是最后一个值#if>
@repeat>
----------------------------------------------------------------结果-----------------------------------------------
有一个有body的宏,宏里给我传来了三个值: 1, 0.5,
有一个有body的宏,宏里给我传来了三个值: 2, 1,
有一个有body的宏,宏里给我传来了三个值: 3, 1.5,
<6>include关键字
语法:
<#include filename options>
options包含两个属性:
encoding="GBK" 编码格式;
parse=true 是否作为ftl语法解析,默认是true,false就是以文本方式引入
举例:在user.ftl同目录下建一个copyright.ftl文件,内容如下
copyright.ftl
Copyright 2018-2023 ${me}
All rights reserved.
user.ftl加如下内容
include的应用
<#assign me="江西南昌市xxx公司"/>
<#include "./copyright.ftl" encoding="UTF-8"/>
----------------------------------------------------------------------------效果-------------------------------------------------------------
include的应用
Copyright 2018-2023 江西南昌市xxx公司
All rights reserved.
《7》Import关键字
语法
<#import path as hash>
类似于 java 里的 import, 它导入文件,然后就可以在当前文件里使用被导入文件里的宏组件
用例假设 mylib.ftl 里定义了宏 copyright 那么我们在其他模板页面里可以这样使用
<#import "/libs/mylib.ftl" as my>
<@my.copyright date="1999-2002"/>
<#-- "my"在freemarker里被称作namespace -->
举例:
-------先在mylib.ftl中定义如下内容(宏的定义,mmm为宏名,pp为它的一个参数用于传值)
<#macro mmm pp="abc">
mmm宏被调用了,传进来的参数pp的值是:${pp}
#macro>
-------然后在引入的文件中加入如下内容(users.ftl中)
import的引入mylib.ftl的定义的mmm宏
<#import "./mylib.ftl" as my/>
<@my.mmm pp="123"/>
----------------------------------------------------------------------结果-------------------------------------------------------------------
import的引入mylib.ftl的定义的mmm宏
mmm宏被调用了,传进来的参数pp的值是:123
《8》compress关键字
语法
<#compress>
...
#compress>
----用来压缩空白空间和空白的行,这里页面显示没有效果,但在源文件代码中可以看到效果。
《9》escape, noescape
语法
<#escape identifier as expression>
...
<#noescape>...#noescape>
...
#escape>
-------主要使用在相似的字符串变量输出,比如某一个模块的所有字符串输出都必须是 html 安全的,这个时候就可以使用,说白了 escape 包裹的内容,会被转义比如<>会编程 <> 而noescape noescape包裹的字符不会被转义,会被当成html代码执行
<#escape x as x?html>
First name: ${firstName}
<#noescape> Last name: ${lastName} #noescape>
Maiden name: ${maidenName}
#escape>
等同于:
First name: ${firstName?html}
Last name: ${lastName}
Maiden name: ${maidenName?html}
<10>assign语法
1.<#assign name=value>
2.<#assign name1=value1 name2=value2 ... nameN=valueN>
3.<#assign name>
capture this
#assign>
4.给aaa赋予序列值(数组一样)
<#assign aaa= ["winter", "spring", "summer", "autumn"]>
5.给变量 test 加 1
<#assign test = test + 1>
6.给 my namespace namespace 赋予一个变量 bgColor, 下面可以通过 my.bgColor 来访问这个变量
<#import "/mylib.ftl" as my>
<#assign bgColor="red" in my>
${my.bgcolor}
//这样输出的
举例:以3为例,将一段输出的文本量保存在 xx 变量里。
assign应用
<#assign xx>
Copyright 2018-2023 江西南昌市xxx公司
All rights reserved.
assign又标签定义局部变量的语法测试
assign双标签定义局部变量的语法测试大大点点滴滴
assign又标签定义局部变量的语法测试
#assign>
${xx}
《11》global语法,global可以跨越命名空间的。
1.<#global name=value>
2.<#global name1=value1 name2=value2 ... nameN=valueN>
3.<#global name>
capture this
#global>
全局赋值语法,利用这个语法给变量赋值,那么这个变量在所有的 namespace 中是可见的 , 如果这个变量被当前的 assign 语法覆盖
如 <#global x=2> <#assign x=1> 在当前页面里 x=2 将被隐藏,或者通过 ${.globals.x} 来访问
举例:在mylib.ftl中定义两个变理,aaa为assign变理,ggg为global变量(全局),在users.ftl中分别输出之,注意他们的用法,一个要用到命名空间的名。
<#assign aaa="aaa">
<#global ggg="ggg">
users.ftl
import的引入mylib.ftl的定义的mmm宏
<#import "./mylib.ftl" as my/>
${my.aaa}
${ggg}
---------------------------------------------------------------------------结果--------------------------------------------------------------
aaa ggg
<12>setting
语法
<#setting name=value>
用来设置整个系统的一个环境
locale
number_format
boolean_format
date_format , time_format , datetime_format
time_zone
classic_compatible, 默认值 false ,改成 true , ${aaa}
举例1:设置数字为百分比显示,如1显示100%,10显示1000%
setting的应用,下面的dd是由IndexController.java注入进来的--model.addAttribute("dd",new Date());?datetime告诉freemarker这个dd是时间日期变量
<#setting number_format="percent"/>
${1}
<#setting date_format="yyyy-MM-dd HH:mm:ss">
${dd?datetime}
---------------------------------------------------------------------------结果--------------------------------------------------------------
100% 2023-2-15 11:14:55
<13>t, lt, rt 只影响源码,不影响页面显示。
<#t> 去掉左右空白和回车换行
<#lt>去掉左边空白和回车换行
<#rt>去掉右边空白和回车换行
1 <#t>
2<#t>
3<#lt>
4
5<#rt>
6
------一些常用方法或注意事项
表达式转换类
${expression} 计算 expression 并输出
#{ expression } 数字计算 #{ expression ;format} 安格式输出数字 format 为 M 和 m
M 表示小数点后最多的位数 ,m 表示小数点后最少的位数如 #{121.2322;m2M2} 输出 121.23
数字循环
1..5 表示从 1 到 5 ,原型 number..number
给变量默认值
${var?default("hello world")?html} 如果 var is null 那么将会被 hello world 替代
解决输出中文乱码问题:
freemarker 乱码的原因:
没有使用正确的编码格式读取模版文件 , 表现为模版中的中文为乱码
解决方法:在 classpath 上放置一个文件 freemarker.properties ,在里面写上模版文件的
编码方式,比如default_encoding=UTF-8
locale=zh_CN
注意: eclipse 中除了 xml 文件、 java 文件外,默认的文件格式 iso8859-1
提高 freemarker 的性能
在 freemarker.properties 中设置:
template_update_delay=60000
避免每次请求都重新载入模版,即充分利用 cached 的模版
关于输出的一些问题
对于数值,会自动根据 local 确定格式,可以 "?c", 比如, Details..., 因此这里的 id 是? c 于数字转换为字符串,不会进行
格式化,注意 ?c 只对数值有效,
对于日期,会使用默认的日期格式转换,因此需要事先设置好默认的转换格式,包括
date_format , time_format , datetime_format
对于布尔值,不能输出,会报错并停止模版的执行,比如 ${a == 2} 会出错,但是 可
以 foo?string("yes","no") 来进行
SpringBoot中使用Thymeleaf模板引擎
和使用freemarker差不多的方式:
1、导入thymeleaf的启动器
org.springframework.boot
spring-boot-starter-thymeleaf
2、编写Controller类(IndexController.java)和模块类(User.java)
3、编写模板页面(扩展名为html), 注意:模板文件必须放在src/resources/templates目录下
①加上名称空间,加后就会有thymeleaf的代码提示
②使用thymeleaf标签实现显示数据
每一种视图引擎模板,都有最基本的功能,变量的输出
强调的知识点:
1.thymeleaf的输出和前面的freemarker,jsp都不一样,它们可在body中直接使用类似EL输出,但在这不能这样独立
使用${}输出,要么是依附在某一个标签上,写在标签属性位置上,要么写在双中括号中。
2.写thymeleaef标签时会暴红,这是没有代码提示与自动补全,这时我们要在标签中写上thymeleaf的命名空间网址
用户名id:
用户名称:
用户密码:
4、thymeleaf的常用标签语法总结:
①变量输出和字符串操作
th:text 在页面上输出值,会把特殊字符进行转义后输出,注意: [[ ]] 和 th:text 等价
th:utext 在页面上输出值,不会把特殊字符转义,注意: [()] 和 th:utext 等价
th:value 在 input 标签中显示数值 xiongshaowen");
---------------------------------------------------------------html页面---------------------------------------------------------------------
5,(符号),在thymeleaf中表示调用内置对象,dates,strings。。。。下面就通过内置对象stirngs对字符串的一些常用操作说明:
字符串的操作,利用控制层注入的str
判断是否为空
时间日期的格式化,利用制制层类IndexController.java注入到视图的时间对象dd
------------------------------------------------------------结果-------------------------------------------------
时间日期的格式化,利用制制层类IndexController.java注入到视图的时间对象dd
2023年2月15日 下午07时30分34秒
③条件分支标签
IndexController.java中注入两个变量sex,id
@Controller
public class IndexController {
// @RequestMapping(value="/index.html",method= RequestMethod.GET)
@GetMapping("/index.html")
public String index(Model model){
model.addAttribute("sex","女");
model.addAttribute("id",3);
return "users"; //返回到一个视图中
}
}
users.html
th:if
性别:女
th:switch
id 为 1
id 为 2
id 为 3
----------------------------------------------------------------结果---------------------------------------------
性别:女 th:switch
id 为 3
④迭代
普通迭代,即控制层注入对象到list集合中,遍历List集合。
IndexController.java
@GetMapping("/index.html")
public String index(Model model){
List users = new ArrayList();
users.add(new User(1,"aaa","aaa123"));
users.add(new User(2,"bbb","bbb123"));
users.add(new User(3,"ccc","ccc123"));
model.addAttribute("users",users); //把users注入的视图中
return "users";
}
users.html
用户ID
用户名
用户密码
结果:
用户ID 用户名 用户密码
1 aaa aaa123
2 bbb bbb123
3 ccc ccc123
状态变量属性
当前循环的索引,从0开始
当前循环的次数,从1开始
被循环的集合或数组的长度
布尔值,当前循环是偶数? 从0开始
布尔值,当前循环是奇数? 从0开始
布尔值,当前循环是不是第一条,是返回true
布尔值,当前循环是不是最后一条,是返回true
-------------------------------------------------------------------------------------------------------------------
1 aaa aaa123 0 1 3 false true true false
2 bbb bbb123 1 2 3 true false false false
3 ccc ccc123 2 3 3 false true false true
迭代Map型的集合
IndexController.java
@GetMapping("/index.html")
public String index(Model model){
Map maps = new HashMap();
maps.put("001",new User(1,"aaa","aaa123"));
maps.put("002",new User(2,"bbb","bbb123"));
maps.put("003",new User(3,"ccc","ccc123"));
model.addAttribute("maps",maps);
return "users"; //返回到一个视图中
}
}
users.html
用户ID
用户名
用户密码
⑤域对象操作
HttpServletRequet:
request.setAttribute("req", "HttpServletRequest")
Request:
HttpSession:
request.getSession().setAttribute("sess", "HttpSession");
Session:
ServletContext:
request.getSession().getServletContext().setAttribute("app","Applic
ation");
Application:
⑥URL 表达式
用在th:href标签或th:src标签上
url 表达式基本语法:@{}
URL 类型
a、绝对路径
绝对路径
b、相对路径
1)相对于当前项目的根,相对于项目的上下文的相对路径
相对路径
- 相对于服务器路径
相对于服务器的根
c、 在 url 中实现参数传递
相对路径-传参
d、 在 url 中通过 restful 风格进行参数
相 对 路径 - 传 参-restful
举例:
URL表达式的应用(用在th:href标签或th:src标签上)
绝对路径
绝对路径
相对路径
1)相对于当前项目的根,相对于项目的上下文的相对路径
相对路径
2) 相对于服务器路径
相对于服务器的根
传参数
相对路径传参
相对路径-传参-restful
若我们在全局配置文件中,在服务器根目录下加相对目录abc
http://localhost:8080/abc/index.html
回车
所以,我们推荐开发中使用thymeleaf视图模板,因为更改相对目录或转移服务器后,会自动给我们增加相应的目录,十分方便