掘金手册:https://juejin.cn/book/6844733814560784397

工程热部署

我们在开发中反复修改类、页面等资源,每次修改后都是需要重新启动才生效,这样每次启动都很麻烦,浪费了大的时间,我们可以在修改代码后不重启就能生效,在 pom.xml 中添加如下配置就可以实现这样的功能,我们称之为热部署。

1
2
3
4
5
<!--热部署配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>

IDEA设置自动热部署
seting —> 搜索compiler —> 勾选Build project automatically

然后 Shift+Ctrl+Alt+/,选择Registry回车

勾选compiler.automake.allow.when.app.running

配置文件

SpringBoot是基于约定的,所以很多配置都有默认值,但如果想使用自己的配置替换默认配置的话,就可以使用application.properties或者application.yml(application.yaml)进行配置。(YML文件的扩展名可以使用.yml或者.yaml。)

yml配置文件的语法

(1)配置普通数据

1
2
3
语法: key: value
示例代码:name: haohao
注意:value之前有一个空格

(2) 配置对象数据

1
2
3
4
语法:
key:
key1: value1
key2: value2

示例代码:

1
2
3
4
5
6
7
person:
name: haohao
age: 31
addr: beijing
#或者
person: {name: haohao,age: 31,addr: beijing}
注意:key1前面的空格个数不限定,在yml语法中,相同缩进代表同一个级别

(3) 配置Map数据–同上面的对象写法

1
2
3
4
5
6
person:
name: haohao
age: 31
addr: beijing
#或者
person: {name: haohao,age: 31,addr: beijing}

(4) 配置数组(List、Set)数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 key:
- value1
- value2
或者:key: [value1,value2]
#示例代码:
city:
- Beijing
- Tianjin

city: [Guangzhou, Shenzhen]
#数组对象
person:
- name: accp
age: 20
- name: zhangsan
age: 21
person: [{name:accp, age:20}, {name:zhangsan, age:21}]

多环境配置

为每个环境创建一个配置文件,命名必须以 application-环境 标识.properties|yml

SpringBoot 总配置文件: application.yml application.properties

开发环境配置文件: application-dev.yml application-dev.properties

测试环境配置文件: application-test.yml application-test.properties

生产环境配置文件: application-product.yml application-product.properties

在总配置文件 application.properties /application.ym中进行环境的激活

等号右边的值和配置文件的环境标识名一致, 可以更改总配置 文件的配置, 重新运行 Application,查看启动的端口及上下文根。

在总的配置文件application.properties中激活配置文件

1
2
3
4
5
6
7
#SpringBoot 的总配置文件
#激活开发环境
#spring.profiles.active=dev
#激活测试环境
#spring.profiles.active=test
#激活生产环境
spring.profiles.active=product

配置文件与配置类的属性映射方式

Spring Boot 自定义配置 在 SpringBoot 的核心配置文件中,除了使用内置的配置项之外, 我们还可以在自定义配置,然后采用如下注解去读取配置的属性值

  1. 使用注解@Value映射
    我们可以通过@Value注解将配置文件中的值映射到一个Spring管理的Bean的字段上例如:
    application.yml配置如下:
1
2
3
person:
name: zhangsan
age: 18

实体Bean代码如下:

1
2
3
4
5
6
7
8
9
10
11
@Controller
public class QuickStartController {
@Value("${person.name}")
private String name;
@Value("${person.age}")
private Integer age;
@RequestMapping("/quick")
@ResponseBody
public String quick(){
return "springboot 访问成功! name="+name+",age="+age; }
}

(2) @ConfigurationProperties 将整个文件映射成一个对象,用于自定义配置项比较多的情况

通过注解@ConfigurationProperties(prefix=”配置文件中的key的前缀”)可以将配置文件中的配置自动与实体进行映射,需要定义get/set方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Controller
@ConfigurationProperties(prefix = "person")
public class QuickStartController {
private String name;
private Integer age;
@RequestMapping("/quick")
@ResponseBody
public String quick(){
return "springboot 访问成功! name="+name+",age="+age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
}

(3)解决警告问题

1
2
3
4
5
6
<!--解决使用@ConfigurationProperties 注解出现警告问题-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

前端使用 JSP(不推荐)

springboot官方推荐使用Thymeleaf
笔记:https://pengyirui.gitee.io/posts/2d22.html

在pom.xml文件中配置以下依赖项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!--引入 Spring Boot 内嵌的 Tomcat 对 JSP 的解析包,不加解析不了 jsp 页面-->
<!--如果只是使用 JSP 页面,可以只添加该依赖-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<!--如果要使用 servlet 必须添加该以下两个依赖-->
<!-- servlet 依赖的 jar 包-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
</dependency>
<!--如果使用 JSTL 必须添加该依赖-->
<!--jstl 标签依赖的 jar 包 start-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>

在 pom.xml 的 build 标签中要配置编译信息。

SpringBoot 要求 jsp 文件必须编译到指定的 META-INF/resources 目 录下才能访问,否则访问不到。因为Spring Boot默认是使用“Thymeleaf”视图模板的,而非“JSP”视图模板,因此JSP的支持并不在刚才加入的starter组件中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!--
SpringBoot 要求 jsp 文件必须编译到指定的 META-INF/resources 目录下才能访问,否则访问
不到。其它官方已经建议使用模版技术(后面会课程会单独讲解模版技术)
-->
<resources>
<resource>
<!--源文件位置-->
<directory>src/main/webapp</directory>
<!--指定编译到 META-INF/resources,该目录不能随便写-->
<targetPath>META-INF/resources</targetPath>
<!--指定要把哪些文件编译进去, **表示 webapp 目录及子目录, *.*表示所有文件-->
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>

配置 Spring MVC 的视图 展示为 jsp

1
2
3
4
5
6
7
#SpringBoot 核心配置文件
#指定内嵌 Tomcat 端口号
server.port=8090
#配置 SpringMVC 视图解析器
#其中: / 表示目录为 src/main/webapp
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp

application.yml 格式的配置文件

1
2
3
4
5
spring:
mvc:
view:
prefix: /WEB-INF/jsp/
suffix: .jsp

5.4在 src/main 下创建一个 webapp 目录

然后在该目录 下新建 index.jsp 页面 如果在 webapp 目录下右键,如果没有创建 jsp 的选项,可以在 Project Structure 中指定 webapp 为 Web Resource Directory

5.5添加静态资源

客户端资源的默认路径为resources-static,本项目中添加如下静态资源

集成mybatis

添加起步依赖和驱动包

1
2
3
4
5
6
7
8
9
10
11
<!--MyBatis 整合 SpringBoot 的起步依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<!--MySQL 的驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>

添加数据源配置信息

在 Springboot 的核心配置文件 application.properties 中配 置数据源

1
2
3
4
5
6
7
8
9
10
11
12
#数据库连接信息
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/myCinema?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=
#spring集成Mybatis环境
#实体别名扫描包
mybatis.type-aliases-package=io.peng.model
#加载Mybatis映射文件
mybatis.mapper-locations=classpath:mapper/*Mapper.xml
#配置日志,打印sql
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

在 Mybatis 反向工程生成的 StudentMapper 接口上加一个 Mapper 注解 @Mapper

作用: mybatis 自动扫描数据持久层的映射文件及 DAO 接口的关系

在 Mybatis 反向工程生成的 StudentMapper 接口上加一个 Mapper 注解 @Mapper 作用: mybatis 自动扫描数据持久层的映射文件及 DAO 接口的关系

在 运 行 的 主 类 上 添 加 注 解 包 扫 描 @MapperScan(“com.abc.springboot.mapper”) 注释掉 Mapper 接口上的@Mapper 注解

1
2
3
4
5
6
7
8
9
10
11
@SpringBootApplication
//Mybatis 提供的注解:扫描数据持久层的 mapper 映谢配置文件,DAO 接口上就不用加@Mapper
//basePackages 通常指定到数据持久层包即可
@SpringBootApplication
@MapperScan("io.peng.mycinema.mapper")//批量设置扫描包
public class MycinemaApplication {

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

在application.properties文件设置mapper文件的路径

1
mybatis.mapper-locations=classpath:/mapper/*Mapper.xml

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// @SpringBootTest(classes = BookUserApplication.class)
// 旧版本需要指定启动类 springframework 2.25
@SpringBootTest
// @RunWith(SpringRunner.class)
// 旧版本需要指定启动方法 springframework 2.25
public class BookUserApplicationTest {

@Autowired
private UsersMapper usersMapper;

@Test
public void aaa(){
usersMapper.selectByCode("sam");
}
}

事务支持

Spring Boot 使用事务非常简单,底层依然采用的是 Spring 本身提 供的事务管理

➢ 在入口类中使用注解 @EnableTransactionManagement 开启 事务支持

➢ 在访问数据库的 Service 方法上添加注解 @Transactional 即可

1
2
3
4
5
6
7
//启动类开启事务支持
@SpringBootApplication
@MapperScan(basePackages = "com.powernode.mapper")
@EnableTransactionManagement //开启事务支持(可选项,但@Transactional 必须添加)
public class Application {

}

Spring MVC 注解

注解 作用
@Controller 控制器
@RestController @Controller 与@ResponseBody 的组合注解 如果一个 Controller 类添加了@RestController,那么该 Controller 类下的所有方法都相当于添加了@ResponseBody 注解 用于返回字符串或 json 数据
@RequestMapping 支持Get请求和Post请求
@GetMapping 支持Get请求,用于查询数据
@PostMapping 只支持Post请求,用于增加数据
@PutMapping 只支持Put请求,用于修改数据
@DeleteMapping 只支持Delete请求,删除数据

RESTful

REST(英文: Representational 表述性State Transfer,简称 REST)一种互联网软件架构设计的风格,但它并不是标准,它只是提出了一组客户端和服务器交互时的架构理念和设计原则,基于这种理念和原则设计的接口可以更简洁,更有层次, REST这个词,是Roy ThomasFielding 在他 2000 年的博士论文中提出的。任何的技术都可以实现这种理念,如果一个架构符合 REST 原则,

Spring Boot 开发 RESTFul Spring boot

开发 RESTFul 主要是几个注解实现

  • @PathVariable 获取 url 中的数据 该注解是实现 RESTFul 最主要的一个注解

  • @PostMapping 接收和处理 Post 方式的请求

  • @DeleteMapping 接收 delete 方式的请求,可以使用 GetMapping 代替

  • @PutMapping 接收 put 方式的请求,可以用 PostMapping 代替

  • @GetMapping 接收 get 方式的请求

RESTful 的优点

➢ 轻量,直接基于 http,不再需要任何别的诸如消息协议 get/post/put/delete 为 CRUD 操作

➢ 面向资源,一目了然,具有自解释性。

➢ 数据描述简单,一般以 xml, json 做数据交换。

➢ 无状态,在调用一个接口(访问、操作资源)的时候,可以不 用考虑上下文,不用考虑当前状态,极大的降低了复杂度。

➢ 简单、低耦合

RESTful 原则

➢ 增 post 请求、删 delete 请求、改 put 请求、查 get 请求

➢ 请求路径不要出现动词

​ 例如:查询订单接口 /boot/order/1021/1(推荐) /boot/queryOrder/1021/1(不推荐)

➢ 分页、排序等操作,不需要使用斜杠传参数

​ 例如:订单列表接口 /boot/orders?page=1&sort=desc 一般传的参数不是数据库表的字段,可以不采用斜杠

拦截器

直接上例子:地址拦截

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Login.java
// 功能类
// 实现HandlerInterceptor接口

@Component
public class Login implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){

// 如果user不等于空,就不拦截,否则就跳去XXX地址
if (user != null) {
return true;

}else {
response.sendRedirect("XXX");
return false;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 实现方法类
// 实现WebMvcConfigurer接口
// Login功能类交给spring创建
// 重写addInterceptors方法

// 应用功能类XXX
// registry.addInterceptor(XXX)
// 需要拦截的地址
// .addPathPatterns("/loan/loanInfo/**");
// 需要放开的地址
// .excludePathPatterns("/money/loan/page/login");


@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private Login login;

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(login)
.addPathPatterns("/");
.excludePathPatterns("/money/");
}
}

定时任务

在日常的项目开发中,往往会涉及到一些需要做到定时执行的代码,例如自动将超过24小时的未付款的单改为取消状态,自动将超过14天客户未签收的订单改为已签收状态等等, Java项目中常使用的定时器有JDK Timer、Quartz、Spring Task等三种。Quartz的功能强大,配置也比较复杂,适合大型、多定时任务的项目使用。Spring Task配置较为简单轻量,需要Spring框架支持。JDK自带的定时器Timer使用灵活,配置简单,适合中小型项目。

Timer

这是java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务。使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行。一般用的较少。

1
2
3
4
5
6
7
8
TimerTask task=new TimerTask() {
@Override
public void run() {
System.out.println("hello,world...."+new Date());
}
};
Timer timer=new Timer();
timer.schedule(task,1000,3000);

ScheduledExecutorService

jdk自带的一个类;是基于线程池设计的定时任务类,每个调度任务都会分配到线程池中的一个线程去执行,也就是说,任务是并发执行,互不影响 。

1
2
3
4
5
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
// 参数:1、任务体 2、首次执行的延时时间
// 3、任务执行间隔 4、间隔时间单位
service.scheduleAtFixedRate(
()->System.out.println("ScheduledExecutorService定时任务 "+new Date()), 0, 3, TimeUnit.SECONDS);

Spring Task

Spring3.0以后自带的task,可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多 .在SpringBoot中已经内置集成了SpringTask,使用非常的方便快捷。

在类上@EnableScheduling,在方法@Scheduled

1
2
3
4
5
6
7
8
9
<!-- 导包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Component
@EnableScheduling
public class SpringTaskDemo {

@Scheduled(cron = "3/15 * * * * *")
public void start(){
System.out.println("----间隔计划任务----"+new Date());
}

@Scheduled(initialDelay = 2000,fixedDelay = 10000)
public void stop(){
System.out.println("----延迟计划任务----"+new Date());
}

@Scheduled(fixedRate = 10000)
public void delay(){
System.out.println("----固定计划任务----"+new Date());
}
}

@Scheduled有三种定时任务的执行方式,包括fixedDelay、fixedRate、corn表达式,下面就分别讲讲这三种执行方式的不同。

fixedDelay:指定两次任务执行的时间间隔(毫秒),此时间间隔指的是,前一次任务结束与下一个任务开始的间隔。如:@Scheduled(fixedDelay = 5*1000 ),表示第一个任务结束后,过5秒后,开始第二个任务。

fixedRate:指定两次任务执行的时间间隔(毫秒),此时间间隔指的是,前一个任务开始与下一个任务开始的间隔。如:@Scheduled(fixedRate= 5*1000 ),表示第一个任务开始后(第一个任务执行时间小于5秒),第一个任务开始后的第6秒,开始第二个任务。如果第一个任务执行时间大于5秒,第一个任务结束后,直接开始第二个任务。

cron表达式(常用)

使用cron表达式进行任务的执行
cron一般是六个或七个字段,分别是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
1. Seconds (秒) 
2. Minutes (分)
3. Hours (时)
4. Day (每月的第几天,day-of-month)
5. Month (月)
6. Day (每周的第几天,day-of-week)
7. Year (年 可选字段)


说明
秒 :范围:0-59
分 :范围:0-59
时 :范围:0-23
天(月) :范围:1-31,但要注意一些特别的月份2月份没有只能1-28,有些月份没有31
月 :用0-11 或用字符串 “JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC” 表示
天(周):用1-7表示(1 = 星期日)或用字符口串“SUN, MON, TUE, WED, THU, FRI and SAT”表示
年:范围:1970-2099

“/”:表示为“每”,如“0/10”表示每隔10分钟执行一次,“0”表示为从“0”分开始, “3/20”表示表示每隔20分钟执行一次
“?”:只用于月与周,表示不指定值
“L”:只用于月与周,5L用在月表示为每月的最后第五天;1L用在周表示每周的最后一天;
“W”::表示有效工作日(周一到周五),只能出现在day-of-month,系统将在离指定日期的最近的有效工作日触发事件。例如:在 DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份
“#”:用于确定每个月第几个星期几,只能出现在DayofMonth域。例如在4#2,表示某月的第二个星期三。
“*” 代表整个时间段。


例子
0 0 10,14,16 * * ? 每天上午10点,下午2点,4点
0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
0 0 12 ? * WED 表示每个星期三中午12点
0 0 12 * * ? 每天中午12点
0 15 10 ? * * ? 每天上午10:15
0 15 10 * * ? 每天上午10:15
0 15 10 * * ? * 每天上午10:15
0 15 10 * * ? 2005 2005年的每天上午10:15
0 * 14 * * ? 在每天下午2点到下午2:59期间的每1分钟
0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟
0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟
0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟
0 10,44 14 ? 3 WED 每年三月的星期三的下午2:10和2:44
0 15 10 ? * MON-FRI 周一至周五的上午10:15
0 15 10 15 * ? 每月15日上午10:15
0 15 10 L * ? 每月最后一日的上午10:15
0 15 10 ? * 6L 每月的最后一个星期五上午10:15
0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15
0 15 10 ? * 6#3" 每月的第三个星期五上午10:15

@ConfigurationProperties

根据配置文件自动配置属性

1
2
3
4
5
6
@ConfigurationProperties(prefix = "jwt.config")
@Component
public class JwtUtil {
private String signKey;
private int expireMinutes;
}
1
2
jwt.config.signKey=peng
jwt.config.expireMinutes=0

配置类

一般@Configuration注释放在类上,与@Ben搭配使用

表示启动spring立即加载

web注释

路径变量

1
2
3
4
@DeleteMapping("/{id}")
public String delete(@PathVariable ("id") Integer id){
xxxxx
}

入参是json

1
2
3
4
@PostMapping("/login")
public String login(@RequestBody User user){

}

请求参数

1
2
@PostMapping
String check(@RequestParam("userCoed") String userCoed);

返回的是json

ResponseResult
自定义ResponseResult在controller响应信息主体和自定义全局及局部异常中的实现