Springboot笔记
SpringBoot学习笔记
1、通过Maven创建
pom文件中加入:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
<relativePath/>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
2、IDEA的脚手架创建(推荐)
SpringBoot的配置文件
1、application.properties格式

2、application.yml格式(层次清楚,推荐使用,但是缩进较为严格)

配置文件存放位置:
1、当前项目根目录中
2、当前项目根目录下的一个/config子目录中
3、项目resources根路径中
4、项目resources根路径下的/config子文件夹中
配置文件中的占位符:
1、语法:${}
2、占位符作用以及生成随机数:

BootStrap配置文件:

SpringBoot的HelloWorld:
@RestController //等于@Controller+@Responsebody
public class HelloController {
@RequestMapping("/hello")
public String show() {
return "helloworld";
}
}
SpringBoot在Controller层中的常用注解:
1、@RestController:相当于@Controller+@ResponseBody注解的结合,使用后Controller无法返回页面,返回的就是return中的内容
2、@GetMapping:就是@RequestMapping(method=RequestMethod.GET)的缩写,@PostMapping、@PutMapping、@DeleteMapping效果类似
SpringBoot整合WEB层技术:
1、整合Servlet
方式一:
1.1通过注解扫描
1.1.1创建一个servlet
package comzhaojianhui.cn.springbootdemo.servlet;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(name = "first",urlPatterns = "/first")
public class MyServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response){
System.out.println("do GET");
}
}
1.1.2修改启动类:启动类上加上@ServletComponentScan注解
整合filter:
1、创建一个filter
package comzhaojianhui.cn.springbootdemo.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(filterName = "firstfilter",urlPatterns = "/firstfilter")
public class FirstFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("进入first filter");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("离开first filter");
}
}
2、启动类加上@ServletComponentScan注解
整合Listener
1、创建一个listener
package comzhaojianhui.cn.springbootdemo.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class FirstListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
2、启动类加上@ServletComponentScan注解
SpringBoot访问静态资源:static目录存放静态资源(例如css/html/js/jquery),templates目录存放Thymeleaf模板页面

如果Controller要实现static目录中html页面的视图跳转,不需要加上static目录,示例如下:
package comzhaojianhui.cn.springbootdemo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class IndexController {
@RequestMapping("/page")
public String hello() {
return "index.html";//直接返回要跳转到的页面即可,页面包含.html
}
}
配置文件中加上:
server:
port: 8888
spring:
thymeleaf:
prefix: classpath:/static/
suffix: .html
热部署:
1、加入jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
2、打开顶部工具栏 File -> Settings -> Default Settings -> Build -> Compiler 然后勾选 Build project automatically

3、同时按住 Ctrl + Shift + Alt + / 然后进入Registry ,勾选自动编译并调整延时参数

4、

静态资源存放的其他位置(classpath指的就是resources):

自定义静态资源位置:

SpringBoot的文件上传:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件上传</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="submit" value="上传"/>
</form>
</body>
</html>
package comzhaojianhui.cn.springbootdemo.controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
@RestController
public class FileLoad {
/**
* 文件上传
*/
@PostMapping("/upload")
public String fileup(MultipartFile file) throws IOException {
System.out.println(file.getOriginalFilename());
file.transferTo(new File("F:/" + file.getOriginalFilename()));
return "ok";
}
}
server:
port: 8888
spring:
thymeleaf:
prefix: classpath:/static/
suffix: .html
#配置单个文件大小限制
servlet:
multipart:
max-file-size: 50MB
#一次请求中上传文件总容量大小
max-request-size: 50MB
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatisstudy?serverTimezone=UTC&characterEncoding=utf8&useSSL=false
username: root
password: 1314520
type: com.alibaba.druid.pool.DruidDataSource
SpringBoot整合freemarker:
1、添加pom
<!--整合freemarker-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
SpringBoot整合Mybatis:
1、添加pom:
<!--Mybatis启动器-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<!--druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
2、配置数据源
server:
port: 8080
spring:
thymeleaf:
prefix: classpath:/templates/
suffix: .html
cache: false
mode: HTML
servlet:
multipart:
max-request-size: 50MB
max-file-size: 20MB
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatisstudy?serverTimezone=UTC&characterEncoding=utf8&useSSL=false
username: root
password: 1314520
type: com.alibaba.druid.pool.DruidDataSource
mybatis:
mapper-locations: classpath:/mapper/*.xml
3、pom中配置generator插件:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!--配置generator插件-->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.5</version>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
</dependencies>
<!--指定配置文件路径-->
<configuration>
<configurationFile>${project.basedir}/src/main/resources/mbg.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>
</plugins>
</build>

配置完成后双击下图中的选项即可生成:

配置资源拷贝插件:
<!--配置资源拷贝插件-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.yml</include>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
修改启动类添加@MapperScan注解完成mapper接口和映射文件的扫描,示例如下:

当mapper.xml映射配置文件放在resources目录下的mapper文件夹时,需要使用
mybatis: mapper-locations: classpath:/mapper/*.xml
resultType起别名:

异常处理
1、自定义错误页面:如果我们需要将所有的异常统一跳到自定义的错误页面,需要在resources的templates目录下创建error.html,只能叫error,不能换名字!
2、通过@ExceptionHandler处理异常
3、通过@ControllerAdvice和@ExceptionHandler定义异常类处理
4、通过@SimpleMappingExceptionResolver处理,示例如下(错误页面存放与templates目录下):只能传递异常页面,无法传递异常信息
package comzhaojianhui.cn.springbootdemo.Exception;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import java.util.Properties;
@Configuration
public class GlobalEx2 {
@Bean
public SimpleMappingExceptionResolver get() {
SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
Properties prop = new Properties();
/**
* 参数一:异常类型且是全名
* 参数二:视图名
*/
prop.put("java.lang.NullPointerException", "error2");
prop.put("java.lang.ArithmeticException", "error3");
resolver.setExceptionMappings(prop);
return resolver;
}
}
5、自定义HadlerExceptionResolver处理对象处理:可以传递异常页面和信息
package comzhaojianhui.cn.springbootdemo.Exception;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Configuration
public class Global3 implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
ModelAndView mv = new ModelAndView();
//判断异常类型进行视图跳转
if (e instanceof NullPointerException) {
mv.setViewName("error4");
}
if (e instanceof ArithmeticException) {
mv.setViewName("error5");
}
mv.addObject("error", e.toString());
return mv;
}
}
SpringBoot整合junit单元测试示例:


SpringBoot服务端数据校验:
1、对实体对象的校验
NotNull:多用于对Integer校验
NotBlank:对字符串做非空校验
NotEmpty:对集合类型做非空校验

2、在controller中开启校验规则
package comzhaojianhui.cn.springbootdemo.controller;
import comzhaojianhui.cn.springbootdemo.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/adduser")
public String add(@Validated User user, BindingResult result) {
if (result.hasErrors()) {
/* List<ObjectError> list = result.getAllErrors();
for (Object err : list) {
FieldError fieldError = (FieldError) err;
String fieldName = fieldError.getField();
String msg = fieldError.getDefaultMessage();
System.out.println(fieldName + "\t" + msg);
}*/
return "addUser";
}
System.out.println(user);
return "ok";
}
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form th:action="@{/user/adduser}" method="post">
<input type="text" name="name"/><span th:errors="${user.name}"/><br/>
<input type="text" name="id"/><span th:errors="${user.id}"/>
</form>
</body>
</html>
自定义错误提示信息:
1、注解中定义错误信息
public class User {
@NotBlank(message = "名字不能为空")
private String name;
@NotNull(message = "id不能为空")
private Integer id;
}
2、配置文件中定义提示信息,配置文件名必须是ValidationMessages.properties
userid.notnull=用户ID不能为空1122 username.notnull=用户姓名不能为空11
package comzhaojianhui.cn.springbootdemo.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@NotBlank(message = "{username.notnull}")
private String name;
@NotNull(message = "{userid.notnull}")
private Integer id;
}

解决页面跳转异常:
package comzhaojianhui.cn.springbootdemo.controller;
import comzhaojianhui.cn.springbootdemo.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 跳转页面的方法
* 解决异常的方式:在跳转页面方法中注入对应pojo对象
*/
@Controller
public class PageController {
@RequestMapping("/{page}")
public String showPage(@PathVariable String page, User user) {
return page;
}
}
修改参数key的名称:



其他校验规则:

SpringBoot中对controller中其他参数的校验示例:



全局异常中添加:

SpringBoot的度量指控与健康检查
1、引入pom:
<!--Actuator启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2、配置文件添加:

使用可视化监控工具:SpringBoot Admin:
1、创建一个基于springboot的服务端项目
2、服务端添加依赖:
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>2.3.0</version>
</dependency>
3、修改配置文件:

4、修改启动类

搭建客户端:
1、添加Pom
<!-- https://mvnrepository.com/artifact/de.codecentric/spring-boot-admin-starter-client -->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>2.3.0</version>
</dependency>
2、修改配置文件:

SpringBoot日志管理(默认是logback):
屏蔽指定包的日志输出:

SpringBoot的打包方式:双击install即可


运行:java -jar 文件名
SpringBoot多环境配置:


SpringBoot在Linux下的运行:


SpringBoot开发定时任务
示例:
1、启动类中加注解@EnableScheduling
package comzhaojianhui.cn.springbootdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling//开启定时任务
public class SpringbootdemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootdemoApplication.class, args);
}
}
2、编写的方法中添加@Scheduled(cron = "0/3 * * * * ?")注解,括号里写cron表达式,表示几秒钟执行一次(此例中3秒一次),cron表达式参考网站:https://cron.qqe2.com/
package comzhaojianhui.cn.springbootdemo.config;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component
public class OrderTask {
@Scheduled(cron = "0/3 * * * * ?")
public void autoCloseOrder() {
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
String nowtime = dateFormat.format(date);
System.out.println("执行定时任务,当前时间为:" + nowtime);
}
}
执行后效果图如下:

定时任务关闭超期未支付订单会存在的弊端:
- 1、会有时差,导致程序不严谨:例如10:39下单,11:00检查不足一小时;12点检查,超过1小时多余39分钟
- 2、不支持集群,单机使用无问题,使用集群后就会有多个定时任务。 解决方案:只用一台计算机节点,单独用来运行所有的定时任务
- 3、会对数据库全表搜索,影响数据库性能:select * from xxx
- 小结:定时任务仅仅适用于小型轻量级项目、传统项目。对于大型项目:可用消息队列如:MQ->RabbitMQ、kafka、ZeroMQ... 延时任务(队列) 例如:10:12下单的,未付款状态,11:12检查,如果状态还是未支付,则直接关闭
任务调度之Quartz:
常用api:

开发步骤:
1、导入quartz的jar包:
<!--开发定时任务-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.3.0</version>
</dependency>
2、入门案例:
package comzhaojianhui.cn.springbootdemo.config;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzMain {
public static void main(String[] args) throws Exception {
//1、调度器Scheduler,从工厂中获取调度实例
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
//2、任务实例JodDetail QuartzJob.class为加载任务类,与QuartzJob类完成绑定
JobDetail jobDetail = JobBuilder.newJob(QuartzJob.class).withIdentity("job1", "group1").build();//参数1:任务的名称(唯一实例) 参数2:任务组的名称
//3、触发器Trigger startNow为马上启动触发器
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").
startNow().withSchedule(SimpleScheduleBuilder
.simpleSchedule().repeatSecondlyForever(5)).build(); //每5秒重复执行一次
//让调度器关联任务和触发器,保证按照触发器定义的条件执行任务
scheduler.scheduleJob(jobDetail, trigger);
//启动调度
scheduler.start();
}
}
package comzhaojianhui.cn.springbootdemo.config;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class QuartzJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//自定义任务:比如输出当前时间
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = sf.format(date);
//工作内容
System.out.println("执行定时任务,当前时间为:" + dateString);
}
}
效果图:

Job和JobDetail介绍:
Job:工作任务调度的接口,任务类需要实现该接口。该接口中定义execute方法,在里面编写任务执行的业务逻辑。
Job实例在Quartz中的生命周期:每次调度器执行Job时,它在调用execute方法前会创建一个新Job实例,当调用完成后,关联的Job对象实例会被释放,释放的实例会被垃圾回收机制回收。
JobDetail:为Job实例提供了许多设置属性,调度器需要借助JobDetail对象来添加Job实例。
JobDetail的重要属性:name、group、jobClass、jobDataMap
常用属性示例:
System.out.println("name:" + jobDetail.getKey().getName());
System.out.println("group:" + jobDetail.getKey().getGroup());
System.out.println("class:" + jobDetail.getKey().getClass());
结果图:

JobExecutionContext介绍:
- 当Scheduler调用一个job,就会将JobExecutionContext传递给Job的execute()方法。
- Job能通过JobExecutionContext对象访问到Quartz运行时候的环境以及Job本身的明细数据。
JobDataMap介绍:
1、使用Map获取
- 在进行任务调度时,JobDataMap存储在JobExecutionContext中,非常方便获取
- JobDataMap可以用来装载任何可序列化的数据对象,当Job实例对象被执行时这些参数对象会传递给他。
- JobDataMap实现了JDK的Map接口,并且添加了非常方便的方法用来存取基本数据类型。
示例代码:



有状态的job(任务类上加@PersistJobDataAfterExecution)和无状态的job:
有状态的job可以理解为多次Job调用期间可以持有一些状态信息,这些状态信息存储在JobDataMap中,而默认的无状态的job每次调用时都会创建一个新的JobDataMap
举例:


浙公网安备 33010602011771号