Springboot笔记
SpringBoot学习笔记
1、通过Maven创建
pom文件中加入:
1 2 3 4 5 6 7 8 9 | <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><br> <plugins><br> <plugin><br> <groupId>org.springframework.boot</groupId><br> <artifactId>spring-boot-maven-plugin</artifactId><br> </plugin><br> </plugins><br></build> |
2、IDEA的脚手架创建(推荐)
SpringBoot的配置文件
1、application.properties格式
2、application.yml格式(层次清楚,推荐使用,但是缩进较为严格)
配置文件存放位置:
1、当前项目根目录中
2、当前项目根目录下的一个/config子目录中
3、项目resources根路径中
4、项目resources根路径下的/config子文件夹中
配置文件中的占位符:
1、语法:${}
2、占位符作用以及生成随机数:
BootStrap配置文件:
SpringBoot的HelloWorld:
1 2 3 4 5 6 7 8 9 | @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
1 2 3 4 5 6 7 8 9 10 11 12 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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目录,示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 | 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 } } |
配置文件中加上:
1 2 3 4 5 6 | server: port: 8888 spring: thymeleaf: prefix: classpath:/ static / suffix: .html |
热部署:
1、加入jar包
1 2 3 4 5 6 | <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的文件上传:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <!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> |
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 | 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" ; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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
1 2 3 4 5 | <!--整合freemarker--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> |
SpringBoot整合Mybatis:
1、添加pom:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <!--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、配置数据源
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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插件:
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 | <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> |
配置完成后双击下图中的选项即可生成:
配置资源拷贝插件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <!--配置资源拷贝插件--> <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文件夹时,需要使用
1 2 | mybatis: mapper-locations: classpath:/mapper/*.xml |
resultType起别名:
异常处理
1、自定义错误页面:如果我们需要将所有的异常统一跳到自定义的错误页面,需要在resources的templates目录下创建error.html,只能叫error,不能换名字!
2、通过@ExceptionHandler处理异常
3、通过@ControllerAdvice和@ExceptionHandler定义异常类处理
4、通过@SimpleMappingExceptionResolver处理,示例如下(错误页面存放与templates目录下):只能传递异常页面,无法传递异常信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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处理对象处理:可以传递异常页面和信息
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 | 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中开启校验规则
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 | 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" ; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <!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、注解中定义错误信息
1 2 3 4 5 6 7 | public class User { @NotBlank (message = "名字不能为空" ) private String name; @NotNull (message = "id不能为空" ) private Integer id; } |
2、配置文件中定义提示信息,配置文件名必须是ValidationMessages.properties
1 2 | userid.notnull=用户ID不能为空 1122 username.notnull=用户姓名不能为空 11 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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; } |
解决页面跳转异常:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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:
1 2 3 4 5 | <!--Actuator启动器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> |
2、配置文件添加:
使用可视化监控工具:SpringBoot Admin:
1、创建一个基于springboot的服务端项目
2、服务端添加依赖:
1 2 3 4 5 | <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-starter-server</artifactId> <version> 2.3 . 0 </version> </dependency> |
3、修改配置文件:
4、修改启动类
搭建客户端:
1、添加Pom
1 2 3 4 5 6 | <!-- 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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包:
1 2 3 4 5 6 7 8 9 10 11 | <!--开发定时任务--> <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、入门案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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
常用属性示例:
1 2 3 | 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
举例:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端