SpringBoot
1、SpringBoot简介
Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程。该框架使用了特定的方式进行配置,从而使开发人员不再需要定义样板化的配置。用我的话来理解,就是 Spring Boot 其实不是什么新的框架,它默认配置了很多框架的使用方式,就像 Maven 整合了所有的 Jar 包,Spring Boot 整合了所有的框架。
Spring Boot是一个快速的开发框架,能够帮助程序员快速整合第三方框架,内置了第三方容器(tomcat/jetty/undertom),完全简化编写xml,采用是注解方式。
优势:
- 快速构建项目
- 对主流开发框架的无配置集成
- 项目可独立运行,无须外部依赖Servlet容器
- 提供运行时的应用监控
- 极大的提高了开发、部署效率
- 与云计算的天然集成
2、第一个SpringBoot项目
2.1maven形式创建
2.1.1创建maven工程
选择maven,直接next
点击next,填写相应信息:
点击finish。
2.1.2导入依赖
<!-- 导入springboot版本和框架依赖 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.1</version>
<relativePath></relativePath>
</parent>
<!-- 导入动态web场景启动器 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<!--添加maven插件,项目的打包工具,打成jar包,否则在打包运行时报错 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
2.1.3创建springboot启动类
创建包com.tjetc,在包下创建启动类
创建启动类
package tjetc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 启动类
*/
@SpringBootApplication
public class HelloApplication {
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
}
}
2.1.4创建controller
创建com.tjetc.controller包,在包下创建controller类
package tjetc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class HelloController {
@RequestMapping("/hello")
@ResponseBody
public String hello() {
return "Hello Spring Boot!";
}
}
2.1.5启动springBoot
运行启动类的main方法
启动成功,端口号8080
2.1.6访问controller
在resources下创建配置文件,application.properties,springboot启动以后,默认读取该配置文件。配置端口号,contextpath
#配置web启动端口
server.port=8081
#配置web上下文路径
server.servlet.context-path=/first
访问:
2.1.7打包部署
Springboot工程被打包成jar包,通过package命令打成jar包。
将当前的工程打成jar包
放在target下面。
/usr/local >java -jar jar包名称
Dfsd> java -jar /usr/local/jar包的名称
在当前的路径下打开cmd窗口。运行jar包:
访问controller
2.2引导器快速创建
创建project
点击next:填写group和Artifact,确定打包方式,jdk版本,和package表示的启动类所在的包名,如果连接失败,可以使用Custom:阿里的镜像服务Custom:https://start.aliyun.com
没有问题,点击next。选择依赖:创建web工程,只要选择web依赖即可,选择springboot版本,选择当前稳定版本。点击next。
(1)官方
(2)阿里
确定module信息以后,点击finish
创建工程以后,可以删掉一些不用的(下面选中的):
- 自动创建了包:com.tjetc,并在包下创建了启动类和测试类。
- 同时在resources下创建了static,templates和springboot的主配置文件application.properties。
- 在启动类启动时,会自动读取主配置文件中的数据。Springboot内部集成了tomcat,默认端口号8080,可以在主配置文件中指定端口号。
- 在pom.xml中导入了parent,web依赖和单元测试,以及打包工具。
2.3理解Pom文件的依赖与starter启动器的作用
2.3.1Pom文件的依赖
Pom文件中的parent是Spring Boot的框架版本控制中心
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.1</version>
<relativePath></relativePath>
</parent>
spring-boot-starter-parent点进去看一下parent是如何控制版本的。点进去之后,也有一个父工程
父工程为spring-boot-dependencies,看到名字应该想到,是springboot的依赖。同时还有其他东西。再点进去,看到里面有<dependencyManagement>,管理各种依赖的版本。
到这里就理解了parent是如何控制版本的。我们创建的springboot工程是spring-boot-start-parent的子工程,spring-boot-starter-parent是spring-boot-denpendencies的子工程,父工程通过dependencyManagement控制了各种依赖的版本。所以当子工程导入依赖时,可以不写版本,自动使用父工程规定的版本。以此来进行版本的控制。
2.3.2spring-boot场景启动器
starter:spring-boot场景启动器,以web启动器为例:
<!-- 导入动态web场景启动器 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
点进去看到spring-boot-starter-web的内容:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.5.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
<version>2.5.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.5.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.8</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.8</version>
<scope>compile</scope>
</dependency>
</dependencies>
Spring-boot-starter-web导入了web环境所有的依赖,只需导入starter,可自动导入web模块正常运行所依赖的组件。其他的starter也是一样的。
springboot出厂默认就写好了很多starter,如:
spring-boot-starter-activemq,spring-boot-starter-aop,spring-boot-starter-data-redis,spring-boot-starter-data-solr等
重要提示:Spring Boot将所有的绝大部分框架整合场景都进行了抽取,做成一个个的starters(启动器),只需要在项目里面引入这些starter相关整合所需的依赖都会导入进来。
2.4理解主程序@SpringBootApplication
@SpringBootApplication 用于标识spring boot应用程序,代表该类是一个spring boot启动类
Spring boot运行这个类的main方法时启动SpringBoot应用。
@SpringBootConfiguration: Spring Boot的配置类。标注在类上表示是一个Spring Boot的配置类
@ComponentScan:根据定义的扫描路径,把符合扫描规则的类装配到spring容器中
虽然起启动类没有放在根包,可以通过ComponentScan注解重新定义扫描的包,不在使用springboot默认扫描启动类所在包和子包
@Configuration:配置类上来标注这个注解。配置类相当于配置文件。配置类也是容器中的一个组件。
@Component把组件实例化到spring容器中。
@EnableAutoConfiguration:开启自动配置功能;
当我们需要Spring Boot帮我们自动配置所需要的配置,@EnableAutoConfiguration告诉Spring Boot开启自动配置功能,这样Spring Boot会自动配置好并使之生效。
3SpringBoot配置文件
3.1学会Spring Boot全局配置和yaml的语法
Spring Boot全局配置文件(在src/main/resources目录或者类路径/config下),名称如下:
application.properties
application.yaml/yml
也许作者认为properties或json 的写法不爽,于是发明了yml这种以数据为中心写法的配置文件。
yml是YAML(YAML Ain't Markup Language)语言的文件,以数据为中心,比json、xml等更适合做配置文件。
3.1.1语法
参考语法规范:http://www.yaml.org
语法校验 : https://nodeca.github.io/js-yaml
YAML基本语法
A.使用缩进表示层级关系
B.缩进时不允许使用Tab键,只允许使用空格。
C.缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
D.大小写敏感
E.键与值之间一定要有空格
3.1.2yml支持的三种数据的结构
YAML 支持的三种数据结构
- 常见普通值:单个的、不可再分的值
- 对象:键值对的集合
- 数组:一组按次序排列的值
1.单个的,不能再分割的值
#单个值,不能再分割的值
name: rose
2.对象:键值对的集合
(1)第一种写法
#对象,键值对的集合
person:
#属性名: 属性值
name: kelly
age: 21
sex: female
(2)第二种写法(将对象写在一行上,键与值之间也要有空格)
user: {name: jack,age: 21,sex: male}
3.数组:一组按次序排列的值,-与值之间也要空格
(1)第一种写法
#数组或集合,一组按次序排列的值
names:
- kelly
- jack
- jim
(2)第二种写法(将对象写在一行上)
ages: [21,21,20]
4、数组中存的是对象
(1)第一种写法(name和age的左侧要对齐)
people:
- name: kelly
age: 21
sex: female
- name: marry
age: 20
sex: female
(2)第二种写法
users:
- {name: jack,age: 21,sex: male}
- {name: jim,age: 20,sex: male}
5、对象有数组
#对象有数组
student:
lists: [21,21,20]
abc:
- 20
- 20
- 20
3.2Spring Boot获取配置文件的值及配置文件编码设置
3.2.1创建实体类
package com.jetc.entity;
public class Book {
private String bookName;
private String author;
public String getBookName() {return bookName;}
public void setBookName(String bookName) {this.bookName = bookName;}
public String getAuthor() {return author;}
public void setAuthor(String author) {this.author = author;}
@Override
public String toString() {
return "Book{" +"bookName='" + bookName + '\'' + ", author='" + author + '\'' +'}';
}
}
package com.jetc.entity;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
/*将student对象放入容器
springboot容器创建student的bean对象并管理起来
*/
@Component
/*(1)读取主配置文件(application.properties或者
application.yaml或者application.yml)中的数据,
赋值给student对象(将数据注入到springboot管理的student对象的属性中)
(2)需要属性,指定主配置文件中的数据
prefix = "student1” 表示在配置中第一个层级是student1
*/
@ConfigurationProperties(prefix = "student1")
public class Student {
private String studentName;
private Integer age;
private Boolean sex;//男代表true
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate birth;
private Map<String, Object> maps;
private List<Object> lists;
private Book book;
public String getStudentName() {return studentName;}
public void setStudentName(String studentName) {this.studentName = studentName;}
public Integer getAge() {return age;}
public void setAge(Integer age) {this.age = age;}
public Boolean getSex() { return sex;}
public void setSex(Boolean sex) {this.sex = sex;}
public LocalDate getBirth() { return birth; }
public void setBirth(LocalDate birth) {this.birth = birth; }
public Map<String, Object> getMaps() {return maps;}
public void setMaps(Map<String, Object> maps) {this.maps = maps;}
public List<Object> getLists() { return lists; }
public void setLists(List<Object> lists) { this.lists = lists;}
public Book getBook() { return book; }
public void setBook(Book book) {this.book = book; }
@Override
public String toString() {
return "Student{" +
"studentName='" + studentName + '\'' +
", age=" + age +
", sex=" + sex +
", birth=" + birth +
", maps=" + maps +
", lists=" + lists +
", book=" + book +
'}';
}
}
3.2.2在主配置文件中配置student
#配置student
#@ConfigurationProperties studentName-->student-name或者studentName
student1:
studentName: 猪猪儿
age: 21
sex: false
birth: 2000-09-05
map1:
k1: v1
k2: v2
lists:
- zhangsan
- lisi
- wangwu
book:
bookName: 红岩
author: 罗广斌
3.2.3编写测试类
package com.jetc;
import com.jetc.entity.Student;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest//使用springboot环境测试
class ApplicationTests {
@Autowired
private Student student;
@Test
void contextLoads() { System.out.println(student);}
}
3.2.4执行结果
Student{studentName='猪猪儿', age=21, sex=false, birth=2000-09-05, maps=null, lists=[zhangsan, lisi, wangwu], book=Book{bookName='红岩', author='罗广斌'}}
启动springboot测试类,会自动加载主配置文件,@ConfigurationProperties负责将主配置文件中的数据赋值给student对象。Student对象已经通过@Component注解注册到容器中,所以在测试类中可以直接注入。
@ConfigurationProperties 映射实体的属性值
可以为实体对读入配置文件的值,支持所有类型值的读取;
前提是实体类需要提供一个setter或使用可变的值初始化它.
先把之前的application.yml放到别的包下
在application.properties中配置student1
#配置student1
student1.student-name=猪猪儿
student1.age=21
student1.sex=false
student1.birth=2000-09-05
student1.maps.k1=v1
student1.maps.k2=v2
student1.lists=zhangsan,lisi,wangwu
student1.book.bookName=红岩
student1.book.author=杨益言
最终执行结果:
Student{studentName='çªçªå¿', age=21, sex=false, birth=2000-09-05, maps={k1=v1, k2=v2}, lists=[zahngsan, lisi, wangwu], book=Book{bookName='红岩', author='æ¨çè¨'}} |
在使用properties文件的时候,中文乱码。如何解决?修改properties文件的编码,将所有编码类型都设置为utf-8
都改好以后,点击OK。
原来的application.properties就乱码了,修改乱码,重新运行,乱码问题解决了
Student{studentName='猪猪儿', age=21, sex=false, birth=2000-09-05, maps={k1=v1, k2=v2}, lists=[zhangsan, lisi, wangwu], book=Book{bookName='红岩', author='杨益言'}} |
3.3@ConfigurationProperties与@Value区别
松散语法属性名匹配规则:
- student.studentName:使用标准方式
- student.student-name:小写写用-
- student. STUDENT_NAME:大写用_
3.3.1功能不同
- @ConfigurationProperties是可以批量注入的,一次搞定
- @Value只能一个一个注入,如下:
3.3.1松散绑定
@ConfigurationProperties支持松散绑定studentName可以写为student-name都没有问题。
@Value不可以。@Value进行绑定时,名称只能与application.properties中属性的名称相同
3.3.2SpEL
@ConfigurationProperties不支持SpEL,比如:
Yml文件配置不支持SpEL
不会报错,但是不能注入到student的age中
@Value支持SpEL。比如:\
Age是可以正常注入的。
3.3.3复杂类型封装
@ConfigurationProperties支持复杂类型封装
@Value不支持复杂类型,只支持字符串,和基本数据类型及其包装类。
3.4 @PropertySource@Bean@Configuration@Import
3.4.1@PropertySource
- 读取指定的properties配置文件
- 如果我们将student的数据写在任意一个配置文件中,比如。student.properties文件中,如何读取配置中信息,注入到student中。可以使用该注解
- 复杂属性文件内部的属性的获取,如果不通过@PropertySource指定属性文件,默认读取的就是application.properties或者application.yml文件
3.4.2@Bean、@Configuration
Spring Boot 由于没有XML文件,所以所有的Bean管理都放入在一个配置类中实现。
配置类就是类上具有@Configuration的类。这个类就相当于之前的applicationContext.xml
配置类中的bean注入到容器
写一个config包,用来存放配置类:
package com.tjetc.service;
public class UserService {
public UserService() {
System.out.println("UserService的无参构造方法");
}
public void add() {
System.out.println("UserService的add方法");
}
}
创建配置类:
package com.tjetc.config;
import com.tjetc.service.UserService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/*
代表当前类是一个配置类,可以达到跟配置文件相同的效果
创建一个userService的对象,放在容器中
*/
@Configuration
public class MyConfig {
/*
springboot启动过程中调用有@Bean注解的方法,生成bean对象交给springboot容器管理
@Configuration+@Bean相当于spring.xml中<bean>标签的作用:
将方法的返回值存入spring容器,bean对象的id是方法名
*/
@Bean
public UserService userService() {
return new UserService();
}
}
测试:
package com.tjetc;
import com.tjetc.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ApplicationTests {
@Autowired
private UserService userService;
@Test
void contextLoads() {
userService.add();
}
}
结果:
如果@Bean对应的方法是非静态方法,那么只执行一次
package com.tjetc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
package com.tjetc.config;
import com.tjetc.service.UserService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
@Configuration
public class MyConfig {
@Bean
public UserService userService() {
return new UserService();
}
@Bean
public String abc() {
System.out.println("MyConfig的abc方法");
userService();
userService();
userService();
userService();
userService();
return "aaa";
}
}
如果是静态方法,执行多次,生成的bean是多例的
package com.tjetc.config;
import com.tjetc.service.UserService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
@Configuration
public class MyConfig {
@Bean
public static UserService userService() {
return new UserService();
}
@Bean
public static String abc() {
System.out.println("MyConfig的abc方法");
userService();
userService();
userService();
userService();
userService();
return "aaa";
}
}
package com.tjetc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
3.4.3@Import
@Import可以引入一个或多个类型,代表将该类实例化到IOC容器中。可以用在启动类上,或者配置类上,只能在程序启动的时候,能够读取该注解即可,这样该注解表示的类型就会被实例化到容器中。
创建db.properties属性文件
jdbc.driverName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=123456
创建DbConfiguration类,读取db.properties属性文件,并为属性赋值。
(1)使用@Value
package com.tjetc.common;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
/*
指定读取的属性文件,这里仅是读取属性文件,赋值,并不会把MyDataSource实例化到容器当中
*/
@PropertySource("classpath:db.properties")
public class DbConfiguration {
/*指定属性文件中的相应属性*/
@Value("${jdbc.driverName}")
private String driverName;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
public String getDriverName() {return driverName; }
public void setDriverName(String driverName) {this.driverName = driverName;}
public String getUrl() { return url; }
public void setUrl(String url) {this.url = url;}
public String getUsername() {return username;}
public void setUsername(String username) {this.username = username;}
public String getPassword() {return password;}
public void setPassword(String password) {this.password = password;}
@Override
public String toString() {
return "DbConfiguration{" +
"driverName='" + driverName + '\'' +
", url='" + url + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
(2)使用@ConfigurationProperties(prefix = "jdbc")
package com.tjetc.common;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
/*
指定读取的属性文件,这里仅是读取属性文件,赋值,并不会把MyDataSource实例化到容器当中
*/
@PropertySource("classpath:db.properties")
@ConfigurationProperties(prefix = "jdbc")
public class DbConfiguration {
private String driverName;
private String url;
private String username;
private String password;
public String getDriverName() {return driverName;}
public void setDriverName(String driverName) {this.driverName = driverName;}
public String getUrl() {return url;}
public void setUrl(String url) {this.url = url;}
public String getUsername() {return username;}
public void setUsername(String username) {this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) {this.password = password;}
@Override
public String toString() {
return "DbConfiguration{" +
"driverName='" + driverName + '\'' +
", url='" + url + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
在启动类上,通过@Import注解引入DbConfiguration,
package com.tjetc;
import com.tjetc.common.DbConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
@SpringBootApplication
/*
springboot启动容器过程中,创建配置import的对象,纳入springboot容器的管理
*/
@Import(value = {DbConfiguration.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
测试:
package com.tjetc;
import com.tjetc.common.DbConfiguration;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ApplicationTests {
@Autowired
private DbConfiguration dbConfiguration;
@Test
public void testDbConfiguration() {
System.out.println(dbConfiguration);
}
}
结果:
DbConfiguration{driverName='com.mysql.cj.jdbc.Driver', url='jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai', username='root', password='123456'} |
3.5多文件配置,加载顺序与位置
多文件配置:spring boot为了适应开发环境或生产环境的变化,专门打造profile通过指定参数来快速切换环境!
3.5.1.多文件的形式
格式: application-{profile}.properties 或 application-{profile}.yml
application-test.yml:
application-dev.yml:
application-prod.yml:
Spring boot提供几种的激活配置方式
3.5.2Spring boot提供几种的激活配置方式
一.JVM参数 -Dspring.profiles.active=prod
确定,启动springboot程序即可。
这时激活的是prod,端口号8083
二、配置文件(激活某个环境的配置)
在全局配置文件application.yml中激活相应的profile即可
此时,dev被激活,端口号为8082
三、命令行 : --spring.profiles.active=prod
先打包应用。
打开terminal,进入命令行,进入target目录:
运行jar包,激活profile
此时,prod被激活,端口号为8083
3.5.3加载顺序
SpringApplication将从以下位置加载application.yml文件, 并把它们添加到Spring环境上下文中:
优先级:当前目录下的/config子目录>当前目录>classpath下的/config包>classpath根路径
- 当前目录下的/config子目录
- 当前目录
- classpath下的/config包
- classpath根路径(项目root)
这个列表是按优先级排序的(列表中位置高的将覆盖位置低的),同时也可以使用properties文件替代YAML文件!
如果不希望使用默认的application.properties作为配置文件名,可以通过指定spring.config.name环境属性来切换其他的名称。 也可以使用spring.config.location环境属性来引用一个明确的路径(目录位置或文件路径列表以逗号分割)
java -jar myproject.jar --spring.config.location=c:/application.properties
Spring boot加载规则:优先级从高到低,高优先级的配置覆盖低优先级的配置,不同的配置混合一起使用。所有的配置由jar包外向jar内查找,优先加载带profile的,再加载不带profile的。
4SpringBoot整合MyBatis
4.1lombok
为了简化实体类的写法,可以使用lombok
4.1.1安装Lombok插件
4.1.2导入lombok依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
4.1.3使用lombok注解
package com.tjetc.entity;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
/*
@Data lombok插件生成getter和setter方法
@Setter lombok插件生成setter方法
@Getter lombok插件生成getter方法
*/
@Data
public class User {
private Long id;
/*@Setter*/
private String username;
/*@Getter*/
private String password;
}
在User上加上@Data注解,会自动拥有set方法,get方法,equals和hoshcode方法,toString方法。
4.2整合Mybatis注解开发
4.2.1导入依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
4.2.2创建user表
4.2.3创建实体类
package com.tjetc.entity;
import lombok.Data;
@Data
public class User {
private Long id;
private String username;
private String password;
}
4.2.4创建Mapper
package com.tjetc.dao;
import com.tjetc.entity.User;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface UserMapper {
@Select("select id,username,`password` from `user`")
List<User> selectAll();
}
4.2.5创建Service
package com.tjetc.service;
import com.tjetc.entity.User;
import java.util.List;
public interface UserService {
List<User> findAll();
}
4.2.6创建service实现类
package com.tjetc.service.impl;
import com.tjetc.dao.UserMapper;
import com.tjetc.entity.User;
import com.tjetc.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public List<User> findAll() {
return userMapper.selectAll();
}
}
4.2.7编写controller
package com.tjetc.controller;
import com.tjetc.entity.User;
import com.tjetc.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/*@Controller*/
@RestController
/*
@RestController 相当于 @Controller+@ResponseBody
*/
@RequestMapping("user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("all")
/*@ResponseBody//返回json*/
public List<User> findAll() {
return userService.findAll();
}
}
4.2.8添加mapper扫描
package com.tjetc;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
/*
扫描指定包下,mapper接口生代理对象,交给springboot容器管理
*/
@MapperScan(basePackages = {"com.tjetc.dao"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
如果在UserMapper接口上添加@Mapper注解,则不需要添加mapper扫描。二者用一种就可以。
4.2.9添加配置
在application.properties中配置datasource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
4.2.10测试
4.3基于xml整合mybatis
以查询所有用户为例。
4.3.1编写UserMapper
package com.tjetc.dao;
import com.tjetc.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/*@Mapper
mybatis会根据带有@Mapper注解的类生成代理对象,交给springboot容器管理
可以直接在Application中用 @MapperScan(basePackages = {"com.tjetc.dao"}) 替代
*/
public interface UserMapper {
/*@Select("select id,username,`password` from `user`")*/
List<User> selectAll();
}
4.3.2编写mapper映射
在resources下创建mapper目录,专门用来存放mybatis相关配置。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN "
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tjetc.dao.UserMapper">
<select id="selectAll" resultMap="userMap">
select id,username,`password` from `user`
</select>
<resultMap id="userMap" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="password" property="password"></result>
</resultMap>
</mapper>
4.3.3添加mybatis配置
在springboot的配置文件,接管mybatis核心配置:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
#配置mybatis映射文件的位置
mybatis.mapper-locations=classpath:mapper/*Mapper.xml
#配置mybatis使用别名
mybatis.type-aliases-package=com.tjetc.entity
4.3.4启动测试
实现跟注解相同的效果。
4.4整合PageHelper
PageHelper是一款犀利的Mybatis分页插件,使用了这个插件之后,分页开发起来更加简单容易。
Spring Boot整合PageHelper不需要做任何配置文件的配置,添加依赖后就可以直接使用。
4.4.1导入依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.3</version>
</dependency>
4.4.2准备数据
在service中实现分页,以查询所有用户为例:
4.4.3编写分页service
/** |
@Override
public PageInfo<User> findPage(int pageNum, int pageSize) {
PageHelper.startPage(pageNum,pageSize);
//查询所有用户
List<User> users = userMapper.selectAll();
//获取Page
PageInfo<User> userPageInfo = new PageInfo<>(users);
return userPageInfo;
}
4.4.4UserController
package com.tjetc.controller;
import com.github.pagehelper.PageInfo;
import com.tjetc.entity.User;
import com.tjetc.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/*@Controller*/
@RestController
/*
@RestController 相当于 @Controller+@ResponseBody
*/
@RequestMapping("user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("all")
/*@ResponseBody//返回json*/
public List<User> findAll() {
return userService.findAll();
}
@RequestMapping("page")
/*@ResponseBody//返回json*/
public PageInfo<User> page(@RequestParam(value = "pageNum",required = false,defaultValue = "3") int pageNum,
@RequestParam(value = "pageSize",required = false,defaultValue = "3") int pageSize) {
PageInfo<User> userPage = userService.findPage(pageNum, pageSize);
return userPage;
}
}
4.4.5结果
5SpringBoot整合logback
5.1日志框架设计思想
市面上存在的大量日志框架:
JUL、JCL、Jboss-logging、logback、log4j、log4j2、slf4j......
日志框架分为两类:
1、抽象类日志:
JCL、 slf4j、 Jboss-logging……
2、实现类日志
log4j、JUL、log4j2、logback……
Spring Boot使用的是SLF4j抽象和logback实现。
Logback是由log4j创始人设计的另一个开源日志组件,官方网站http://logback.qos.ch。
它当前分为下面几个模块:
logback-core:其它两个模块的基础模块
logback-classic:它是log4j的一个改良版本,同时它完整实现了slf4j API使你可以很方便地更换成其它日志系统如log4j或JDK14 Logging
logback-access:访问模块与Servlet容器集成提供通过Http来访问日志的功能。
5.2 Spring Boot日志依赖原理和日志级别
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
日志级别
在log4j2中, 共有8个级别,按照从低到高:
ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF。
- All:最低等级的,用于打开所有日志记录.
- Trace:是追踪,就是程序推进一下.
- Debug:指出细粒度信息事件对调试应用程序是非常有帮助的.
- Info:消息在粗粒度级别上突出强调应用程序的运行过程.
- Warn:输出警告及warn以下级别的日志.
- Error:输出错误信息日志.
- Fatal:输出每个严重的错误事件将会导致应用程序的退出的日志.
- OFF:最高等级的,用于关闭所有日志记录.
程序会打印高于或等于所设置级别的日志,设置的日志等级越高,打印出来的日志就越少 。
5.3Spring Boot日志默认配置
5.3.1日志级别配置
日志的默认级别是info,只有info级别,以及比info级别高的日志信息会打印。
Info,warn,error这三个级别的日志会打印。
在测试类中添加如下代码:
package com.tjetc;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ApplicationTests {
@Test
public void testLog() {
Logger logger = LoggerFactory.getLogger(ApplicationTests.class);
logger.trace("trace跟踪日志");
logger.debug("debug调试日志");
logger.info("info输出日志");
logger.warn("warn输出警告日志");
logger.error("error错误或异常日志");
}
}
2022-06-28 13:57:54.914 INFO 15024 --- [ main] com.tjetc.ApplicationTests : info输出日志 |
日志级别:logging.level.包名=级别
设置了日志的级别信息以后,大于等于该级别的日志信息都会打印,不是只打印当前级别,默认info级别
在application.properties文件中可以修改日志的级别,修改com.tjetc下面的类在执行的时候的日志级别为debug。
logging.level.com.tjetc=debug |
再次执行单元测试,debug级别的日志也会打印。
2022-06-28 14:00:44.403 DEBUG 11100 --- [ main] com.tjetc.ApplicationTests : debug调试日志 |
5.3.2日志文件与路径配置
Springboot的日志level来控制的,根据不同的level来显示。在哪里控制呢? Springboot默认的配置。
在application.properties中配置
logging.file.name= 文件完全名称
Springboot包下,logging包下的logback包下,有一个base.xml文件和defaults.xml文件。
Base.xml文件的内容:
|
Level:设置日志的级别为info。可以在控制台打印,也可以写入文件。
在全局配置文件application.properties中除了可以设置日志的级别:
#设置日志的级别 logging.level.com.tjetc=debug
|
还可以将日志写入文件中:
#将日志写入文件,在当前目录下生成一个logging.log文件
logging.file.name=logging.log
logging.file.name=C:/log/logging.log
上面的文件名可以是全路径名。比如C:/log/logging.log
如果不写盘符,直接写/log:在工程所在的盘符下创建一个log文件夹
应用一下:
@RequestMapping("abc")
public String abc(){
try {
int i = 1/0;
return "执行成功";
}catch (Exception e){
//控制台打印
e.printStackTrace();
//文件中输出错误信息
log.error(e.getMessage());
return "执行失败或者出现异常";
}
}
结果:
6SpringBoot整合JSP
6.1JSP简介
JSP全称Java Server Pages,是一种动态网页开发技术。它使用JSP标签在HTML网页中插入Java代码。标签通常以<%开头以%>结束。
JSP是一种Java servlet,主要用于实现Java web应用程序的用户界面部分。网页开发者们通过结合HTML代码、XHTML代码、XML元素以及嵌入JSP操作和命令来编写JSP。
JSP通过网页表单获取用户输入数据、访问数据库及其他数据源,然后动态地创建网页。
JSP标签有多种功能,比如访问数据库、记录用户选择信息、访问JavaBeans组件等,还可以在不同的网页中传递控制信息和共享信息。
6.2整合JSP
6.2.1创建工程
和之前建springboot项目一样
- 直接next:
- 填写相关信息:
- 点击next
- 导入web依赖,点击next,确定信息以后,finish。
6.2.2配置web.xml
在main下创建webapp/WEB-INF:
在IDEA窗口右上角点project constructor
添加web.xml
选择创建的WEB-INF目录,点击OK。最后在选中的WEB-INF路径后面添加web.xml,点击OK
Apply,OK。在WEB-INF中就有web.xml文件了。
6.2.3将webapp指定为web资源目录
webapp带蓝点,如下图,这样就可以了。
6.2.4添加jsp解析器依赖
<!--添加jsp解析器依赖-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<!-- 添加jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
6.2.5配置视图解析器
#配置查找页面的前缀
spring.mvc.view.prefix=/WEB-INF/views/
#配置查找页面的后缀
spring.mvc.view.suffix=.jsp
6.2.6编写controller
package com.tjetc.controller;
import com.github.pagehelper.PageInfo;
import com.tjetc.entity.User;
import com.tjetc.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@Controller/*返回页面*/
/*@RestController
相当于 @Controller+@ResponseBody 返回json
*/
@RequestMapping("user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("all")
/*@ResponseBody//返回json*/
public String findAll(Model model) {
List<User> users = userService.findAll();
model.addAttribute("users", users);
return "user-list";
}
}
6.2.7创建jsp
在WEB-INF下创建views文件夹,在views下创建user-list.jsp文件。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
<base href="<%=request.getContextPath()%>/">
</head>
<body>
<table border="1" cellspacing="0" cellpadding="1">
<tr>
<td>编号</td>
<td>用户名</td>
<td>密码</td>
</tr>
<c:forEach items="${users}" var="user">
<tr>
<td>${user.id}</td>
<td>${user.username}</td>
<td>${user.password}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
代码编写完成,这时启动服务,会看到端口号8080,默认contextpath为””。访问controller的路径为localhost:8080/user/all,这时很有可能会404。解决办法:打开project constructor
idea右上角。
选择artifacts,选中springboot-jsp,右键,将该工程下所有的jar包导到左边。点击put into output root即可。会看到右边所有的jar都到了lib下。
重启服务,如果这时是404的话。解决方法:
idea右上角,edit configurations
选择SpringBOotJSPApplication,点开Environment,选择Workingdirectory,在列表中选择ModuleFileDir,确定即可。重新启动服务。访问controller。会看到如下内容:
7SpringBoot异常处理
7.1异常显示的页面
7.1.1 spring-boot-starter-thymeleaf
Thymeleaf的使用非常简单,只需要把我们的html页面放在类路径下的templates下,thymeleaf就可以帮我们自动渲染了。
添加依赖()
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
加入依赖后,application.properties中有默认前缀和后缀
默认情况下,SpringBoot 项目错误页面如下:
当项目实际上线,如果给用户显示这个页面就不是很友好。当系统出现异常时应该给用户更加友好的错误页面
下面我们来看具体是如何实现的。
- 在templates/下新建error文件夹,在error中新建:状态.html的页面。例如当出现500时显示的页面为html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>500</title>
</head>
<body>
<h1>您的代码出现了内部错误,请检查!</h1>
</body>
</html>
- 创建controller
package com.tjetc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
@RequestMapping("hello")
public String hello() {
System.out.println(5 / 0);
return "hello";
}
}
我们知道,在运行上面代码的时候发生算术异常。错误码为500。
- 使用X进行模糊匹配
- 当出现5开头状态码的错误时,显示页面可以命名为html
- 如果html和5xx.html同时存在,则会精确匹配相应页面。
我们把刚才的500.html改为5xx.html,也是可以的。因为发生了5开头的异常,会走5xx.html。
执行结果:
如果500.html和5xx.html同时存在的话,可以会根据状态码精确匹配,如果没有相关状态码的html,则还是执行5xx.html
500.html和5xx.html同时存在,则会根据状态码精确匹配500.html。
- 统一错误页面显示
在templates下新建error.html。如果项目中不存在具体状态码的页面或没有使用x成功匹配的页面时,显示error.html作为错误显示页面。
比如我们在error下没有设置4xx相关的错误页面,当发生状态码为4xx的错误时,找不到相关的错误处理页面,这时会走一个统一的错误处理页面。一般会在templates下创建error.html,作为统一的错误处理页面。
在templates下创建error.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>error</title>
</head>
<body>
error
</body>
</html>
当发生404错误时,会自动走error.html
7.1.2 自定义异常显示的页面
package com.tjetc.controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
public class AdviceController {
@ExceptionHandler({Exception.class})
public String error() {
return "bbb/error.html";
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>error</title>
</head>
<body>
bbb/error
</body>
</html>
7.2异常处理
在Spring Boot项目中除了设置错误页面,还可以通过注解实现错误处理。
7.2.1局部异常
在Spring Boot项目中除了设置错误页面,还可以通过注解实现错误处理。
局部异常:
在控制器类中添加一个方法,结合@ExceptionHandler。但是只能对当前控制器中方法出现异常进行解决。
- 创建异常信息类
package com.tjetc.exception;
import lombok.Data;
@Data
public class ExceptionMessage {
private String code;
private String msg;
}
- 在controller中设置异常处理
package com.tjetc.controller;
import com.tjetc.exception.ExceptionMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
/*@Controller*/
@RestController
public class ErrorController {
@RequestMapping("hello")
public String hello() {
System.out.println(5 / 0);
return "hello";
}
/*局部异常处理*/
@ExceptionHandler(ArithmeticException.class)
public ExceptionMessage exception(Exception e) {
ExceptionMessage message = new ExceptionMessage();
message.setCode("500");
message.setMsg("出错了:" + e.getMessage());
return message;
}
}
@ExceptionHandler的参数为发生异常的类型。如果controller的方法中捕获到了这种异常,就会走@ExceptionHandler表示的方法arithmeticException(),在方法参数中,可以获取异常对象。
最终执行结果:
当访问test的controller方法时,会出现除0异常,就会走异常处理方法,封装异常信息,返回。
7.2.2全局异常
新建全局异常类,通过@ControllerAdvice结合@ExceptionHandler。当全局异常处理和局部处理同时存在时,局部生效(就近原则)
- 编写异常处理controller
package com.tjetc.controller;
import com.tjetc.exception.ExceptionMessage;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/*
全局异常处理的Controller
*/
@ControllerAdvice
public class GlobalExceptionHandleController {
//发生除0异常时,会执行该方法
@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public ExceptionMessage arithmeticException(Exception e) {
System.out.println("GlobalExceptionHandleController的全局异常处理");
ExceptionMessage message = new ExceptionMessage();
message.setCode("500");
message.setMsg("除0异常:" + e.getMessage());
return message;
}
//发生空指针异常时,会执行该方法
@ExceptionHandler(NullPointerException.class)
@ResponseBody
public ExceptionMessage nullPointerException(Exception e) {
ExceptionMessage message = new ExceptionMessage();
message.setCode("500");
message.setMsg("空指针异常:" + e.getMessage());
return message;
}
//发生其他异常时,会执行该方法
@ExceptionHandler(Exception.class)
@ResponseBody
public ExceptionMessage exception(Exception e) {
ExceptionMessage message = new ExceptionMessage();
message.setCode("500");
message.setMsg("非数字或空指针异常,未知异常");
return message;
}
}
- 编写controller(先局部处理,局部没有去全局)
package com.tjetc.controller;
import com.tjetc.exception.ExceptionMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
/*@Controller*/
@RestController
public class ErrorController {
@RequestMapping("hello")
public String hello() {
System.out.println(5 / 0);
return "hello";
}
@RequestMapping("aaa")
public String aaa() {
String str = null;
System.out.println(str.length());
return "aaa";
}
@RequestMapping("bbb")
public String bbb() {
int[] i = new int[3];
int num = i[3];//数组越界
return "bbb";
}
/*局部异常处理*/
@ExceptionHandler(ArithmeticException.class)
public ExceptionMessage exception(Exception e) {
System.out.println("ErrorController的局部异常处理");
ExceptionMessage message = new ExceptionMessage();
message.setCode("500");
message.setMsg("出错了:" + e.getMessage());
return message;
}
}
- 测试结果
(1)
(2)
(3)
8SpringBoot定时任务
8.1 Scheduled简介
Scheduled是Spring3.0后内置的定时任务器。通过Scheduled可以完成周期的执行一些功能。存在于spring-conext-support.jar中。
在SpringBoot中使用Scheduled非常简单,只需要在对应的方法上添加@Scheduled注解,再配置对应的参数就可以完成。
8.1.1创建工程
next,finish。
8.1.2添加依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
8.1.3在启动类上添加注解
package com.tjetc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling//启动调度
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
在启动类上添加@EnableScheduling注解
8.1.4创建定时任务
package com.tjetc.scheduled;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class ScheduledDemo {
//调度注解 cron填写表达式 每个参数之间有空格
@Scheduled(cron = "0/2 * * * * *")
public void test(){
//模拟业务逻辑
System.out.println("test scheduled");
}
}
8.1.5启动服务
启动spring服务,运行结果如下,每隔两秒执行一次任务。
8.2Cron表达式
在线Cron表达式生成器:https://cron.qqe2.com/
Cron表达式是一个字符串,分为6或7个域,每一个域代表一个含义
{秒数} {分钟} {小时} {日期} {月份} {星期} {年份(可为空)}
Cron有如下两种语法格式:
- Seconds Minutes Hours Day Month Week Year
- Seconds Minutes Hours Day Month Week
corn从左到右(用空格隔开):
秒 分 小时 月份中的日期 月份 星期中的日期 年份
位置 |
时间域名 |
允许值 |
允许的特殊字符 |
1 |
秒 |
0-59 |
, - * / |
2 |
分钟 |
0-59 |
, - * / |
3 |
小时 |
0-23 |
, - * / |
4 |
日 |
1-31 |
, - * / L W C |
5 |
月 |
1-12 |
, - * / |
6 |
星期 |
1-7(周日到周六) |
, - * ? / L C # |
7 |
年(可选) |
1970-2099 |
, - * / |
Cron表达式的时间字段除允许设置数值外,还可使用一些特殊的字符,提供列表、范围、通配符等功能,细说如下:
- 星号(*):可用在所有字段中,表示对应时间域的每一个时刻,例如,*在分钟字段时,表示“每分钟”;
- 问号(?) :该字符只在日期和星期字段中使用,它通常指定为“无意义的值”,相当于占位符;
- 减号(-):表达一个范围,如在小时字段中使用“10-12”,则表示从10到12点,即10,11,12;
- 逗号(,):表达一个列表值,如在星期字段中使用“MON,WED,FRI”,则表示星期一,星期三和星期五;
- 斜杠(/):x/y表达一个等步长序列,x为起始值,y为增量步长值。如在秒字段中使用0/15,则表示为0,15,30和45秒,而5/15在分钟字段中表示5,20,35,50,你也可以使用*/y,它等同于0/y;
- L:该字符只在日期和星期字段中使用,代表“Last”的意思,但它在两个字段中意思不同。L在日期字段中,表示这个月份的最后一天,如一月的31号,非闰年二月的28号;如果L用在星期中,则表示星期六,等同于7。但是,如果L出现在星期字段里,而且在前面有一个数值X,则表示“这个月的最后X天”,例如,6L表示该月的最后星期五;
- W:该字符只能出现在日期字段里,是对前导日期的修饰,表示离该日期最近的工作日。例如15W表示离该月15号最近的工作日,如果该月15号是星期六,则匹配14号星期五;如果15日是星期日,则匹配16号星期一;如果15号是星期二,那结果就是15号星期二。但必须注意关联的匹配日期不能够跨月,如你指定1W,如果1号是星期六,结果匹配的是3号星期一,而非上个月最后的那天。W字符串只能指定单一日期,而不能指定日期范围
- LW组合:在日期字段可以组合使用LW,它的意思是当月的最后一个工作日;
- 井号(#):该字符只能在星期字段中使用,表示当月某个工作日。如6#3表示当月的第三个星期五(6表示星期五,#3表示当前的第三个),而4#5表示当月的第五个星期三,假设当月没有第五个星期三,忽略不触发;
- C:该字符只在日期和星期字段中使用,代表“Calendar”的意思。它的意思是计划所关联的日期,如果日期没有被关联,则相当于日历中所有日期。例如5C在日期字段中就相当于日历5日以后的第一天。1C在星期字段中相当于星期日后的第一天。
Cron表达式对特殊字符的大小写不敏感,对代表星期的缩写英文大小写也不敏感。
例子:
- @Scheduled(cron = "0 0 1 1 1 ?")//每年一月的一号的1:00:00 执行一次
- @Scheduled(cron = "0 0 1 1 1,6 ?") //一月和六月的一号的1:00:00 执行一次
- @Scheduled(cron = "0 0 1 1 1,4,7,10 ?") //每个季度的第一个月的一号的1:00:00 执行一次
- @Scheduled(cron = “0 0 0 11 11 ?”) 11月11日0点执行
Cron表达式对特殊字符的大小写不敏感,对代表星期的缩写英文大小写也不敏感。
9SpringBoot与web开发
9.1静态资源映射规则
“/**” 访问当前项目任何资源,全部找静态资源的文件夹进行映射
静态资源的文件夹:
SpringBoot支持的目录映射包含(优先级从上到下,即若有相同文件资源时会先执行:
META-INF/resources/ > resource > static > public > / ,注意:自己指定静态资源路径时以上目录不起作用!):
- classpath:/META-INF/resources/
- classpath:/resources/
- classpath:/static/
- classpath:/public/
- /:当前项目的根路径
静态资源路径下的文件,可以通过地址栏直接访问
可以直接在地址栏中访问:
3.“/**” 访问静态资源文件夹下的所有index.html页面
在resources下创建index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>index</h1>
</body>
</html>
通过地址栏直接访问index.html
如果aaa.html的位置在/static/aaa/aaa.html,则相应的访问路径也要为/aaa/aaa.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>aaa</h1>
</body>
</html>
9.2自定义静态资源映射规则
自定义配置类
package com.tjetc.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyWebAppConfigurer implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").
addResourceLocations(
"classpath:/META-INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/",
"file:C:/image/img/");
}
}
完善上面的操作,动态处理路径
image.base.path=C:/image/img/
package com.tjetc.common;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
@Component
@PropertySource("classpath:user.properties")
public class CommonConstants {
@Value("${image.base.path}")
public String IMAGE_BASE_PATH;
}
package com.tjetc.config;
import com.tjetc.common.CommonConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/*
资源映射路径
*/
@Configuration
public class MyWebAppConfigurer implements WebMvcConfigurer {
@Autowired
private CommonConstants constants;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
/*
addResourceHandler 添加资源处理url路径
addResourceLocations 添加url对应的磁盘物理路径
*/
registry.addResourceHandler("/**").
addResourceLocations(
"classpath:/META-INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/",
/*"file:C:/image/img/");//添加自定义资源映射路径*/
"file:" + constants.IMAGE_BASE_PATH);/*动态处理*/
}
}
9.3登录拦截器
9.3.1编写controller
@Controller @RequestMapping("user") public class UserController { /** * 登录验证 * * @param username * @param password * @param session * @param model * @return */ @RequestMapping("login") public String login(@RequestParam("username") String username, @RequestParam("password") String password, HttpSession session, Model model) { //模拟数据库查询 if (username.equals("zhangsan") && password.equals("111")) { session.setAttribute("username", "zhangsan"); return "redirect:/user/welcome"; } else { model.addAttribute("msg", "用户名或者密码错误"); return "login"; } } /** * 登录的页面 * * @param model * @return */ @RequestMapping("login-html") public String loginHtml(Model model) { model.addAttribute("msg", ""); return "login"; } /** * 欢迎首页 * * @return */ @RequestMapping("welcome") public String welcome() { return "welcome"; } }
|
登录页面
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/user/login" method="post"> 用户名:<input type="text" name="username"><br> 密码:<input type="password" name="password"><br> <input type="submit" value="登录"><br> <span th:if="${msg}!=''" th:text="${msg}"></span> </form> </body> </html>
|
9.3.2编写登录拦截器
public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //获取session HttpSession session = request.getSession(); //判断session总是否存在用户名 String username = (String) session.getAttribute("username"); if (username == null) {//没有登录或者登录过期跳转登录页面 request.setAttribute("msg", ""); //重定向到请求/user/login-html response.sendRedirect("/user/login-html"); //返回false,不执行后面的拦截器和Controller对应的方法 return false; } //放行 return true; } }
|
9.3.3配置拦截器
@Configuration public class LoginInterceptorConfig implements WebMvcConfigurer { /** * 注册登录拦截器 * * @param registry */ @Override public void addInterceptors(InterceptorRegistry registry) { //注册拦截器 registry.addInterceptor(new LoginInterceptor()) //拦截器要拦截url .addPathPatterns("/**") //排除拦截器要拦截的url .excludePathPatterns("/user/login-html", "/user/login", "/css/**", "/js/**", "/img/**"); } }
|
9.4登录拦截器(JSON的应用)
9.4.1添加依赖,编写JsonResult
<!--json字符串与对象相互转换-->
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.74</version>
</dependency>
package com.tjetc.model;
public class JsonResult<T> {
//0 代表成功,1代表失败,-1代表登录过期
private int state;
//失败的提示信息
private String message;
//返回的数据
private T data;
public JsonResult(int state, String message, T data) {
this.state = state;
this.message = message;
this.data = data;
}
public int getState() {return state;}
public String getMessage() {return message;}
public T getData() {return data;}
}
9.4.2配置拦截器
package com.tjetc.config;
import com.tjetc.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class LoginWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor()).
//拦截器要拦截url
addPathPatterns("/**").
//排除拦截器要拦截的url
excludePathPatterns("/login", "/css/**",
"/js/**", "/img/**");
}
}
9.4.3编写controller
package com.tjetc.controller;
import com.tjetc.model.JsonResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpSession;
@RestController
public class LoginController {
@RequestMapping("login")
public JsonResult login(@RequestParam("username")String username,
@RequestParam("password")String password,
HttpSession session){
//数据库判断 todo
if("carat".equals(username)&&"17526".equals(password)){
session.setAttribute("username",username);
JsonResult<Object> jsonResult = new JsonResult<>(0, "登录成功", null);
return jsonResult;
}else{
JsonResult<Object> jsonResult = new JsonResult<>(1, "用户密码错误", null);
return jsonResult;
}
}
}
9.4.4编写登录拦截器
package com.tjetc.interceptor;
import com.alibaba.fastjson.JSONObject;
import com.tjetc.model.JsonResult;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
Object username = session.getAttribute("username");
if (username == null) {
response.setContentType("text/html;charset=utf-8");
JsonResult<Object> jsonResult = new JsonResult<>(-1, "未登录或登录过期", null);
String json = JSONObject.toJSONString(jsonResult);
response.getWriter().write(json);
return false;/*不放行*/
} else {
return true;
}
}
}
登陆成功前
登陆成功后