Springboot(大总结)
Springboot
springboot优点
创建独立的spring应用
内嵌web服务器
自动starte依赖,简化构建配置
自动配置spring以及第三方功能
提供生产级别的监控、健康检查以及外部化检查
无代码生成、无需编写xml文件
缺点
版本迭代过快需要时刻关注
封装太深,内部原理复杂
第一个springboot程序
条件:maven3.3以上、JDK1.8
1在电脑终端输入mvn -v查看maven的版本
2在电脑终端输入java -version查看jdk版本
3使用idea创建一个maven工程
新建项目maven
打开pom.xml文件加入依赖(在springboot官网也有)
<!--springboot依赖-->
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.4.4</version>
</parent><!--web开发依赖springboot官网--><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies>
在java目录中创建一个主文件(MainApplication.java)
package com.springboot;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*
主程序类
@SpringBootApplication告诉springboot这是一个springboot应用*/
@SpringBootApplication
public class MainApplication {public static void main(String[] args) {/*主程序运行*/ SpringApplication.run(MainApplication.class,args);}
}
在创建一个Controller类
package com.springboot.controller;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;/*@ResponseBody
@Controller*/
@RestController//就是@ResponseBody和@Controller
public class HelloController {@RequestMapping("/hello")public String hello01(){return "hello Springboot2";}
}
直接运行主类就可以了
springboot主配置文件(官网链接: https://docs.spring.io/spring-boot/docs/2.4.4/reference/html/appendix-application-properties.html#common-application-properties)
导包插件(在pom.xml文件中引入插件)
<!--导包插件-->
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins>
</build>
运行结果
Springboot依赖管理
父项目做依赖管理(子项目继承父项目子项目无需版本号)
<!--springboot依赖-->
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.4.4</version>
</parent>
修改pom.xml里面jar包的版本
先找到父项目的版本
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.4.4</version>
</parent>
修改Mysql(<mysql.version>8.0.23</mysql.version>)这里mysql的版本号是8.0.23
在pom.xml里面修改
<properties><mysql.version>5.1.43</mysql.version>
</properties>
starter场景启动器
1.spring-boot-starter-*;星就代表的某种场景
2.只要引入spring-boot-starter-*,这个场景的所有需要的依赖和jar包都会引入进来
所有场景启动器最底层的依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><!--场景启动器--><artifactId>spring-boot-starter-web</artifactId></dependency>
</dependencies>
3.springboot所有支持的场景官方文档链接:https://docs.spring.io/spring-boot/docs/2.4.4/reference/html/using-spring-boot.html#using-boot-starter
*-spring-boot-starter(代表着第三方的starter)
自动配置
自动配好tomcat
引入tomcat依赖
配置tomcat
自动配好springmvc
引入springmvc全套组件
自动配置好springmvc常用组件
可以在主程序下用以下方法查看
public class MainApplication {public static void main(String[] args) {//1.返回一个ioc容器ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);//查看容器里面的组件String[] names = run.getBeanDefinitionNames();for (String name : names) {System.out.println(name);}}
自动配好web常见功能
springboot帮我们配置好了所有web开发的场景
默认的包结构
主程序所在包及其下面的所欲子包里面的组件都会被默认扫面进来
无需以前的包扫描配置
想要改变扫面路径,使用:
@SpringBootApplication(scanBasePackages = "com.springboot")
各种配置拥有默认值
默认配置最终都会映射到MultipartProperties
配置文件的值最终会绑定某个类上,这个类会在容器中创建对象
按需加载所有自动配置项
非常多的starter
引入了那些场景这个场景的自动配置才会开启
springboot所有的自动配置功能都在spring-boot-autoconfigure包里面
容器功能
组件添加
1.@Configuration
基本使用
Full模式与Lite模式
@Configuration(proxyBeanMethods =true)/*告诉springboot这是一个配置类配置类本身也是一个组件proxyBeanMethods =true 代理方法Full(proxyBeanMethods =true)、Lite(proxyBeanMethods =false)(每次访问都不一样)@Configuration(proxyBeanMethods =true)(每次访问都是IOC里面的配置)代理对象调用方法。springboot总会检查这个组件是否在容器中保持组件单实例*/
public class MyConfig {/*** 外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象* **/@Bean//给容器中添加组件,以方法名作为组件id 返回类型就是组件类型。 返回对象就是组件容器中的实例(默认为单例)public User user01(){User Zhangsan=new User("zhangsan",18);Zhangsan.setPet(tomcat());return Zhangsan;}@Bean("tom")//括号里面为自定义名字(默认名字是方法名)public Pet tomcat(){return new Pet("12"); }
}
在main方法测试(提前在User类里加入了Pet属性)
User user01=run.getBean("user01", User.class);
Pet tom= run.getBean("tom",Pet.class);user01.getPet();// Full(proxyBeanMethods =true)(配置类组件之间有依赖关系,方法会被调用得到之前单例组件)//Lite(proxyBeanMethods =false)(配置组件之间无依赖关系用Lite模式加速容器启动的过程,减少判断)System.out.println("用户宠物"+(user01.getPet()==tom));
Import注解(给容器中自动创建出这类型的组件)
/* @Import给容器中自动创建出这两个类型的组件
默认组件的名字就是全类名*/
@Import({User.class , DBHelper.class})
@Conditional条件装配
@Conditional的关系树(在满足某种条件或者不满足某种条件创建组件等方法 可以使用在类前面)
我们在main方法里面尝试拿取一下组件
运行结果
@ImportResource("classpath:beans.xml")可以导入以前xml的配置方式
我在spring.xml里面创建了一个组件如果直接拿那么结果是false因为springboot不知道它是是什么
如果在任何一个类上面加入@ImportResource(“classpath:beans.xml”)那么他会自动解析里面的组件放入springboot
<bean id="hh" class="com.springboot.bean.User"><property name="name" value="12"></property><property name="age" value="11"></property>
</bean>
@ImportResource("classpath:beans.xml")//可以导入以前xml的配置方式
配置绑定
第一种在实例类上加上
prefix是前缀代表着前缀里面的属性和car里面的属性一致
@Component加入ioc容器
Car实例类
package com.springboot.bean;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/*
* 只有在放在容器中才会生效
* */
@Component
@ConfigurationProperties(prefix = "mycard")
public class Car {private String brand;private Integer price;public String getBrand() {return brand;}public void setBrand(String brand) {this.brand = brand;}public Integer getPrice() {return price;}public void setPrice(Integer price) {this.price = price;}@Overridepublic String toString() {return "Car{" +"brand='" + brand + '\'' +", price=" + price +'}';}
}
主配置文件
mycard.brand=BM
mycard.price=10000
测试
HelloController
使用自动装配
package com.springboot.controller;import com.springboot.bean.Car;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*@ResponseBody(告诉springboot直接返回给浏览器)
@Controller*/
@RestController//就是@ResponseBody和@Controller
public class HelloController {@AutowiredCar car;@RequestMapping("/card")public Car car(){return car;}
}
测试结果
第二种方法:因为我们可能引入的car为第三方的无法加入@Component导致无法导入配置文件
使用@EnableConfigurationProperties+@ConfigurationProperties(开启car配置绑定功能
把car这个组件自动注册到容器中)@EnableConfigurationProperties在主配置文件类使用
@EnableConfigurationProperties(Car.class)
运行结果
自动配置原理
引导加载自动装配
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM,classes = {TypeExcludeFilter.class}
), @Filter(type = FilterType.CUSTOM,classes = {AutoConfigurationExcludeFilter.class}
)}
)
1.@SpringBootConfiguration:
Configuration代表这当前是一个配置类
2.@ComponentScan(指定扫面哪些注解)
3.@EnableAutoConfiguration
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
@AutoConfigurationPackage 自动配置包(指定了默认的包规则)
@Import({Registrar.class})
//利用Registrar给容器种导入一系列组件
//将指定的包下的所有组件导入进来MainApplication所在的报下
@Import({AutoConfigurationImportSelector.class})
1.利用this.getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件2. List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);获取到所有需要导入到容器中的配置类3.例如工厂加载List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader)得到组件4.从META-INF/spring.factories位置来加载一个文件默认扫面我们当前系统里所有MET-INF/spring.factories位置的文件
这些组件在xml中已经写死了
按需开启自动配置项
1.当我们导入相关的jar包才会开启相应的组件
2.springboot会预先加载配置类
3.每个自动配置类按照条件生效
4.生效的配置类就会给容器中装配很对组件
5.只要容器中有这些组件,就相当于这些功能有了
6.只要用户有自己配置的,就以用户的优先
xxxxAutoConfiguration–>组件–>xxxProperties里面拿值—>application.properties
实战
引入场景依赖
https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot
查看自动配置了那些
自己分析,引入场景对应的配置一般都会生效
配置文件中的debug=true开启自动配置报告 Negative(不生效)
是否修改配置项
参照文档修改配置项
https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#common-application-properties
自己查看分析xxxproperties绑定了配置文件的那些
自定义加入或替换组件
Lombok(javaben简化开发)
pom.xml中引入配置
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId>
</dependency>
再idea软件市场下载lombok插件
搜索插件里面搜索lombok
再javabean中删除set/get方法再类上加入lombok的Data的注解
如果需要定制全参构造自己写就好
package com.springboot.bean;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@NoArgsConstructor//无参构造
@Data//set/get方法
@AllArgsConstructor//全参构造
public class User {private String name;private int age;private Pet pet;public User(String name,Integer age){this.name=name;this.age=age;}}
controller类
package com.springboot.controller;import com.springboot.bean.Car;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*@ResponseBody(告诉springboot直接返回给浏览器)
@Controller*/
@RestController//就是@ResponseBody和@Controller
@Slf4j//(日志注解提供方法log.info)
public class HelloController {@AutowiredCar car;@RequestMapping("/card")public Car car(){log.info("请求");return car;}
}
运行结果
dev-tools(开发者工具)
作用:如果后台文件或者代码发生改变会重启如果是静态资源则不会重启
<!--devtools日更新 更改前端页面无需每次刷新ctrl+f9即可实时生效(自动重启)--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency>
spring Initailizr(项目初始化)
再创建新项目时选择spring Initailizr
导入了依赖
springBOOT核心功能
配置文件(yaml)
YAML是"YAML Ain’t Markup Language”(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)。
非常适合来做以数据为中心的配置文件
基本语法
key:value; kv 之间有空格
大小写敏感
使用缩进便是层级关系
缩进不允许使用tab,只允许空格
缩进的空格数不重要,只要同层级的元素左对齐即可
‘#’代表注释
"与"表示字符串内容 会被 转义/不转义
数据类型
字面量:单个的、不可在分值。date boolean string number null
k: v
对象:键值对的集合 map hash set object
Person类(再pom.xml中引入了lombok使用@Data和@ToString再用@Component放入容器)@ConfigurationProperties(prefix = “person”)(使用前缀引入配置文件)
package com.springinitailizr.boot01.bean;import lombok.Data;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;@ConfigurationProperties(prefix = "person")
@Component
@Data
@ToString
public class Person {private String userName;private boolean boss;private Date birth;private Integer age;private String[] interests;private List<String> animal;private Map<String,Object> score;private Set<Double> salarys;private Map<String , List<Pet>> allPets;
}
Pet
package com.springinitailizr.boot01.bean;import lombok.Data;
import lombok.ToString;@Data
@ToString
public class Pet {private String name;private Double weight;
}
application.yaml(后缀为yml也可以)
person:#字面量书写格式userName: "zs \n ls"#单引号会将\n作为字符串输出#双引号会将\n作为换行输出boss: truebirth: 2019/2/19age: 18#数组的两种书写格式#interests: [篮球,足球]interests:- 篮球- 足球- 18#List集合书写格式animal: [阿毛,阿狗]#Map集合书写的两种格式
# score:
# english: 80
# math: 90score: {english: 80,math: 90}#Set集合的书写方式(和数组书写方式一样)salarys:- 999- 9998#对象属性的书写格式pet:name: 阿狗weight: 99#Map<String,List<Pet>>v是集合 书写格式allPets:sick:- {name: 阿狗,weight: 99.99}- {name: 阿2,weight: 99.99}- name: 路weight: 75.1health:- {name: 阿黑,weight: 199}- {name: 啊, weight: 200}
双引号拿Person取值
单引号拿取Person名字的值
yaml配置提示功能以及排除processor被打包
添加依赖
<!--yaml依赖(配置yaml时有代码提示)-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional>
</dependency><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes> <!--打包插件不会把processor打包--><exclude><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId></exclude></excludes></configuration></plugin></plugins></build>
提示效果:
Web开发
静态资源访问
1.静态资源目录
只要静态资源放在类路径下/static(or
/publicor
/resourcesor
/META-INF/resources)
访问:当前项目的根路径/+静态资源名
原理:静态资源映射/**
请求进来先去controller处理,如不能处理则所有请求再交给静态资源。如果静态资源也找不到则404
2.静态资源访问前缀
默认无前缀
配置前缀后访问路径 项目名/res/静态资源名
再yaml下配置
#静态资源前缀
spring:mvc:static-path-pattern: /res/**#改变默认静态资源目录web:resources:static-locations: classpath:/bbb/
3.webjar(把一些常用的CSS、js的静态资源打成jar包只需要引用依赖则课访问它的静态资源)(官网链接:https://www.webjars.org/)
再pom.xml中引入依赖然后重启项目进行访问:
http://localhost:8080/webjars/jquery/3.6.0/jquery.js 后面的地址要按照包路径进行访问
运行结果
欢迎页面
1.给静态资源路径下方一个index.html
可以配置静态资源路径
但是不可以配置静态资源的访问前缀。否则导致index.html不能被默认访问
#静态资源前缀(会导致默认页面无法访问)
spring:mvc:static-path-pattern: /res/**#改变默认静态资源目录web:resources:static-locations: [classpath:/bbb/]
2.controller能处理/index
自定义Favicon
把图片名字改为favicon.ioc放入static静态资源即可
会使Favicon失效
spring:mvc:static-path-pattern: /res/**
静态资源配置管理
Springboot启动默认加载 xxxAutoConfiguration类(自动配置类)
springMvc功能的自动配置类WebMvcAutoConfiguration
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {}
给容器配置了什么
@Configuration(proxyBeanMethods = false)@Import(EnableWebMvcConfiguration.class)@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })@Order(0)public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {}
配置文件的相关属性和xxx进行了绑定。WebMvcProperties==spring.mvc、ResourceProperties==spring.resources
spring:
# mvc:
# static-path-pattern: /res/**resources:add-mappings: false 禁用所有静态资源规则
请求参数处理
请求映射
Rest风格支持(使用Http请求方式动词来表示对资源的操作)
*以前:/getUser 获取用户 /deleteUser 删除用户 /editUser 修改用户 /saveUser 保存用户
现在: /user GET-获取用户 DELETE-删除用户* PUT-修改用户 POST-保存用户
核心 Filter:HiddenHttpMethodFilter
用法:表单method=post,隐藏域_method=put
springboot中手动开启(默认是false)
Rest原理(表单提交要使用REST的时候)
表单提交会带上**_method=PUT**
请求过来被HiddenHttpMethodFilter拦截
- 请求是否正常,并且是POST
- 获取到**_method**的值。
- 兼容以下请求;PUT.DELETE.PATCH
- 原生request(post),包装模式requesWrapper重写了getMethod方法,返回的是传入的值。
- 过滤器链放行的时候用wrapper。以后的方法调用getMethod是调用requesWrapper的。
Rest使用客户端工具,
- 如PostMan直接发送Put、delete等方式请求,无需Filter。
@Bean@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false)public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {return new OrderedHiddenHttpMethodFilter();}
#开启Rest风格mvc:hiddenmethod:filter:enabled: true
HelloController
@RequestMapping(value = "/user",method = RequestMethod.GET)
public String getUser(){return "GET-张三";
}@RequestMapping(value = "/user",method = RequestMethod.POST)
public String saveUser(){return "POST-张三";
}@RequestMapping(value = "/user",method = RequestMethod.PUT)
public String putUser(){return "PUT-张三";
}@RequestMapping(value = "/user",method = RequestMethod.DELETE)
public String deleteUser(){return "DELETE-张三";
}
index.jsp
<form action="/user" method="get"><input value="Get提交" type="submit">
</form>
<form action="/user" method="post"><input value="post提交" type="submit">
</form>+
<form action="/user" method="post"><input name="_method" type="hidden" value="DELETE"><input value="DELETE" type="submit">
</form>
<form action="/user" method="post"><input name="_method" type="hidden" value="PUT"><input value="Put提交" type="submit">
</form>
自定义Rest风格的参数
package com.boot.web.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.HiddenHttpMethodFilter;@Configuration(proxyBeanMethods = false)
public class WebConfig {@Beanpublic HiddenHttpMethodFilter hiddenHttpMethodFilter(){HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();//修改成_m(那么请求参数就只能是_m _method就不可用)methodFilter.setMethodParam("_m");return methodFilter;}}
2、请求映射原理
SpringMVC功能分析都从 org.springframework.web.servlet.DispatcherServlet-》doDispatch()
RequestMappingHandlerMapping:保存了所有@RequestMapping 和handler的映射规则。
SpringBoot自动配置欢迎页的 WelcomePageHandlerMapping 。访问 /能访问到index.html;
SpringBoot自动配置了默认 的 RequestMappingHandlerMapping
请求进来,挨个尝试所有的HandlerMapping看是否有请求信息。
- 如果有就找到这个请求对应的handler
- 如果没有就是下一个 HandlerMapping
我们需要一些自定义的映射处理,我们也可以自己给容器中放HandlerMapping。自定义 HandlerMapping
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {if (this.handlerMappings != null) {for (HandlerMapping mapping : this.handlerMappings) {HandlerExecutionChain handler = mapping.getHandler(request);if (handler != null) {return handler;}}}return null;}
普通参数与基本注解
注解:
@PathVariable、@RequestHeader、@ModelAttribute、@RequestParam、@MatrixVariable、@CookieValue、@RequestBody
<ul><li>@PathVariable(路径变量)</li><li>@RequestHeader(获取请求头)</li><li>@RequestParam(获取请求参数)</li><li>@CookieValue(获取cookie值)</li><li>@RequestAttribute(获取request域属性)</li><li>@RequestBody(获取请求体)</li><li>@MatrixVariable(矩阵变量)</li></ul>
@RestController
public class ParameterTestController {@GetMapping("/car/{id}/owner/{username}")public Map<String,Object> getCar(@PathVariable("id") Integer id,@PathVariable("username") String name,@PathVariable Map<String,String> pv,@RequestHeader("Accept-Encoding") String Accept,@RequestHeader Map<String,String> header,@RequestParam("age") Integer age,@RequestParam("inters") List<String> inters,@RequestParam Map<String,String> params,@CookieValue("freePromorunningtmr") String _ga,@CookieValue("freePromorunningtmr") Cookie cookie){Map<String,Object> map = new HashMap<>();/* map.put("id",id);map.put("name",name);map.put("pv",pv);map.put("Accept-Encoding",Accept);map.put("headers",header);*/map.put("age",age);map.put("insters",inters);map.put("params",params);map.put("_ga",_ga);System.out.println(cookie.getName()+"==="+cookie.getValue());return map;}
2、POJO封装过程
ServletModelAttributeMethodProcessor
3、参数处理原理
- HandlerMapping中找到能处理请求的Handler(Controller.method())
- 为当前Handler 找一个适配器 HandlerAdapter; RequestMappingHandlerAdapter
- 适配器执行目标方法并确定方法参数的每一个值
1、HandlerAdapter
0 - 支持方法上标注@RequestMapping
1 - 支持函数式编程的
执行目标方法
// Actually invoke the handler.
//DispatcherServlet -- doDispatch
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
mav = invokeHandlerMethod(request, response, handlerMethod); //执行目标方法//ServletInvocableHandlerMethod
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
//获取方法的参数值
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
3、参数解析器-HandlerMethodArgumentResolver
确定将要执行的目标方法的每一个参数的值是什么;
SpringMVC目标方法能写多少种参数类型。取决于参数解析器。
当前解析器是否支持解析这种参数
支持就调用 resolveArgument
4、返回值处理器
=
Thymeleaf模板引擎
thymeleaf简介
现代化、服务端java模板引擎
引入
引入statr
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
2.springboot自动配置好了thymeleaf(在ThymeleafAutoConfiguration)
@Configuration(proxyBeanMethods = false
)
@EnableConfigurationProperties({ThymeleafProperties.class})
@ConditionalOnClass({TemplateMode.class, SpringTemplateEngine.class})
@AutoConfigureAfter({WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class})
自动配好的策略
所有的thymeleaf的配置都在ThymeleafProperties
配置好了Spring TrmplateEngine
配置好了ThymeleafViewResolver
默认后缀是.html
使用
新建html引入thymeleaf的命名空间
<html lang="en" xmlns:th="http://www.thymeleaf.org">
thymeleaf公用页面抽取
在thymeleaf公共页面 8 Template Layout
声明引用
<!--公共页面放在header里面用thymeleaf的fragment包裹-->
<head th:fragment="commonheader"><meta charset="UTF-8"><title>所有公共信息</title><!--common--><link href="css/style.css" th:href="@{/css/style.css}" rel="stylesheet"><link href="css/style-responsive.css" th:href="@{css/style-responsive.css}" rel="stylesheet"><!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries --><!--[if lt IE 9]>--><script src="js/html5shiv.js"></script><script src="js/respond.min.js"></script></head>
<!--或者用id的方式-->
<div id="commonscript">
<script th:src="@{/js/jquery-1.10.2.min.js}"></script>
<script th:src="@{/js/jquery-ui-1.9.2.custom.min.js}"></script>
<script th:src="@{/js/jquery-migrate-1.2.1.min.js}"></script>
<script th:src="@{/js/bootstrap.min.js}"></script>
<script th:src="@{/js/modernizr.min.js}"></script>
<script th:src="@{/js/jquery.nicescroll.js}"></script></div>
引用的使用
视图解析
视图解析:Springboot默认不支持JSP,需要引入第三方模板引擎技术实现页面渲染
视图解析原理流程
1.目标方法处理的过程中,所有数据都会放在ModelAndViewContainer里面。包括数据和视图地址
2.方法的参数是一个自定义类型对象(从请求参数中确定的,把他重新放在ModelAndViewContainer)
3.任何目标方法执行完成以后都会返回ModelAndView(数据和视图地址)
4.processDispatchResult处理派发结果(页面该如何响应)
1.render(mv,request,reponse);进行页面渲染逻辑
1.根据方法的String返回值得到view对象{定义了页面的渲染逻辑}
2.根据返回值得到了redirect:/xxx.html—> RedirectView
3.ContentNegotiationViewResolver里面包含了所有的视图解析器得到视图对象
视图解析:
返回值以forward(跳转):开始:newInternalResourceView(forwardUrl);
返回值以redirect(重定向):开始: new RedirectView()
拦截器
实现HandlerInterceptor接口以及重写三个方法
package com.springboot.admin.Interceptor;import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;/*
* 登录检查(拦截器的作用)
* */
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {/** 目标方法执行之前* 1.配置拦截器拦截那些请求* 2.把这些配置放入容器中* */@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String uri = request.getRequestURI();//请求显示log.info("拦截的请求是"+uri);//登录检查逻辑HttpSession session=request.getSession();Object user = session.getAttribute("user");if (user!=null){//放行return true;}//未登录进行跳转到登录页request.setAttribute("msg","请先登录");//response.sendRedirect("/");request.getRequestDispatcher("/").forward(request,response);return false;}/** 目标方法执行之后* */@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {log.info("postHandle方法执行{}"+modelAndView);}/** 页面渲染以后* */@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {log.info("afterCompletion执行异常{}"+ex);}
}
定制springMvc
package com.springboot.admin.config;import com.springboot.admin.Interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*定制Springmvc的功能
*必须实现WebMvcConfigurer
* 1.编写一个拦截器实现HandlerInterceptor接口
* 2.拦截器注册到容器中(实现WebMvcConfigurer的addInterceptor)
* 3.指定拦截规则
* */
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {//通过addInterceptor把拦截器注册到容器中registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**")//所有请求都会被拦截包括静态资源.excludePathPatterns("/","/login","/css/**","/fonts/**","/js/**","/images/**");//放行(静态资源放行的第一种方法)}
}
文件单个和多个文件上传
FormTestConfig(用来处理文件上传的请求)
package com.springboot.admin.controller;import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;import java.io.File;
import java.io.IOException;/*
* 文件上传
* */
@Slf4j
@Controller
public class FormTestController {@GetMapping("/form_layouts")public String form_layouts(){return "form/form_layouts";}/** MultipartFile会自动封装上传过来的文件* */@PostMapping("/upload")public String upload(@RequestParam("email")String email, @RequestParam("username") String username,@RequestPart("headerImg") MultipartFile headerImg,//单个文件上传参数获取@RequestPart("photos")MultipartFile[] photos) throws IOException {//多个文件上传参数获取log.info("上传信息:email={},username={},heanderimg={},photos={}",email,username,headerImg.getSize(),photos.length);if (!headerImg.isEmpty()){String filename = headerImg.getOriginalFilename();headerImg.transferTo(new File("E:\\"+filename));if (photos.length>0){for (MultipartFile photo:photos) {String MultipartFile = photo.getOriginalFilename();photo.transferTo(new File("E:\\"+MultipartFile));}}}return "main";}
}
html文件上传
<form role="form" th:action="@{/upload}" method="post" enctype="multipart/form-data"><div class="form-group"><label for="exampleInputEmail1">邮箱</label><input type="email" name="email" class="form-control" id="exampleInputEmail1" placeholder="Enter email"></div><div class="form-group"><label for="exampleInputPassword1">名字</label><input type="text" name="username" class="form-control" id="exampleInputPassword1" placeholder="name"></div><div class="form-group"><label for="exampleInputFile">头像</label><input type="file" id="exampleInputFile" name="headerImg"><p class="help-block">Example block-level help text here.</p></div><div class="form-group"><label for="exampleInputFile">生活照</label><input type="file" name="photos" multiple><!--multiple多文件上传--><p class="help-block">Example block-level help text here.</p></div><div class="checkbox"><label><input type="checkbox"> Check me out</label></div><button type="submit" class="btn btn-primary">提交</button>
</form>
错误处理
1、错误处理
1、默认规则
默认情况下,Spring Boot提供
/error
处理所有错误的映射对于机器客户端,它将生成JSON响应,其中包含错误,HTTP状态和异常消息的详细信息。对于浏览器客户端,响应一个“ whitelabel”错误视图,以HTML格式呈现相同的数据
自定义错误页面只需要在templates下面的error(目录名固定)下放入自定义页面即可(页面名字5xx是代表所有5开头的错误状态,404是指定错误页面消息)
异常处理自动配置原理
ErrorMvcAutoConfiguration 自动配置了异常处理规则
容器中的组件:组件的类型DefaultErrorAttributes—》组件的id:errorAttributes
public class DefaultErrorAttributes implements ErrorAttributes, HandlerExceptionResolver, Ordered
容器中组件的类型:BasicErrorController—》id:basicErrorController
默认处理/erro路径的请求:相应页面 new ModelAndView(“erro”,model)
容器中有组件:View->id:erro
全局异常处理@ControllerAdvice+ @ExceptionHandler
@ControllerAdvice//全局异常和处理注解
public class GlobalExceptionHander {@ExceptionHandler({ArithmeticException.class,NullPointerException.class})public String handlerArithException(Exception e){log.error("异常是:",e);System.out.println("123456");return "5xx";}}
自定义错误继承HandlerExceptionResolver和实现它的方法
package com.springboot.admin.exception;import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
public class CustomerHandlerExceptionResolver implements HandlerExceptionResolver {@Overridepublic ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {try {httpServletResponse.sendError(511,"我喜欢的错误");} catch (IOException ioException) {ioException.printStackTrace();}return new ModelAndView();}
原生组件
Filter(过滤器)
继承implements Filter和实现它的方法和注解@WebFilter(urlPatterns = {"/css/*"})
package com.springboot.admin.servlet;import lombok.extern.slf4j.Slf4j;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;@WebFilter(urlPatterns = {"/css/*"})
@Slf4j
public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {log.info("MyFilter初始化");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {log.info("MyFilter工作");filterChain.doFilter(servletRequest,servletResponse);}@Overridepublic void destroy() {log.info("MyFilter销毁");}
}
Servlet继承HttpServlet实现doget方法和注解@WebServlet(urlPatterns ="/my")
package com.springboot.admin.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(urlPatterns ="/my")
public class MyServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.getWriter().write(666);}}
Listener继承ServletContextListener和实现方法和注解@WebListener
package com.springboot.admin.servlet;import lombok.extern.slf4j.Slf4j;import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;@Slf4j
@WebListener
public class MyServletContextListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {log.info("监听到项目初始化");}@Overridepublic void contextDestroyed(ServletContextEvent sce) {log.info("监听到项目初销毁");}
}
在main方法里面写上@ServletComponentScan(basePackages = “com.springboot.admin”)来扫描上面的方法
package com.springboot.admin;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@ServletComponentScan(basePackages = "com.springboot.admin")
@SpringBootApplication
public class Boot05AdminApplication {public static void main(String[] args) {SpringApplication.run(Boot05AdminApplication.class, args);}}
方法二(单独写一个类把监听器,拦截器和servlet放入里面加上bean注解放入容器中)
package com.springboot.admin.servlet;import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.Arrays;@Configuration(proxyBeanMethods = true)
public class MyRegistConfig {@Beanpublic ServletRegistrationBean myServlet(){MyServlet myServlet = new MyServlet();return new ServletRegistrationBean(myServlet,"/my","/my02");}@Beanpublic FilterRegistrationBean myFilter(){MyFilter myFilter = new MyFilter();FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter);filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/css/*"));return filterRegistrationBean;}@Beanpublic ServletListenerRegistrationBean myListener(){MyServletContextListener myServletContextListener = new MyServletContextListener();return new ServletListenerRegistrationBean(myServletContextListener);}
}
1、切换嵌入式Servlet容器
默认支持的webServer
Tomcat
,Jetty
, orUndertow
ServletWebServerApplicationContext 容器启动寻找ServletWebServerFactory 并引导创建服务器
切换服务器
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions>
</dependency>
原理
- SpringBoot应用启动发现当前是Web应用。web场景包-导入tomcat
- web应用会创建一个web版的ioc容器
ServletWebServerApplicationContext
ServletWebServerApplicationContext
启动的时候寻找ServletWebServerFactory
(Servlet 的web服务器工厂---> Servlet 的web服务器)
- SpringBoot底层默认有很多的WebServer工厂;
TomcatServletWebServerFactory
,JettyServletWebServerFactory
, orUndertowServletWebServerFactory
底层直接会有一个自动配置类。ServletWebServerFactoryAutoConfiguration
ServletWebServerFactoryAutoConfiguration导入了ServletWebServerFactoryConfiguration(配置类)
ServletWebServerFactoryConfiguration 配置类 根据动态判断系统中到底导入了那个Web服务器的包。(默认是web-starter导入tomcat包),容器中就有 TomcatServletWebServerFactory
TomcatServletWebServerFactory 创建出Tomcat服务器并启动;TomcatWebServer 的构造器拥有初始化方法initialize---this.tomcat.start();
内嵌服务器,就是手动把启动服务器的代码调用(tomcat核心jar包存在
2、定制Servlet容器
实现 WebServerFactoryCustomizer
- 把配置文件的值和**
ServletWebServerFactory 进行绑定
**
- 把配置文件的值和**
修改配置文件 server.xxx
直接自定义 ConfigurableServletWebServerFactory
数据访问
SQL
数据源配置
导入JDBC场景
<!--数据库访问--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jdbc</artifactId></dependency>
</dependencies>
2.分析自动配置
数据库驱动
springboot仲裁了mysql驱动版本
<mysql.version>8.0.23</mysql.version>
数据库驱动
<!--修改版本方法一直接修改version使用maven的就近依赖原则-->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.49</version>
</dependency>
<!--第二个办法直接修改属性如父类也有此属性以我设置的为准--><properties><java.version>1.8</java.version><mysql.version>5.1.49</mysql.version></properties>
2、分析自动配置
1、自动配置的类
DataSourceAutoConfiguration : 数据源的自动配置
- 修改数据源相关的配置:spring.datasource
- 数据库连接池的配置,是自己容器中没有DataSource才自动配置的
- 底层配置好的连接池是:HikariDataSource
@Configuration(proxyBeanMethods = false)@Conditional(PooledDataSourceCondition.class)@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.OracleUcp.class,DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class })protected static class PooledDataSourceConfiguration
**
**
DataSourceTransactionManagerAutoConfiguration: 事务管理器的自动配置
JdbcTemplateAutoConfiguration: JdbcTemplate的自动配置,可以来对数据库进行crud
- 可以修改这个配置项@ConfigurationProperties(prefix = “spring.jdbc”) 来修改JdbcTemplate
- @Bean@Primary JdbcTemplate;容器中有这个组件
JndiDataSourceAutoConfiguration: jndi的自动配置
XADataSourceAutoConfiguration: 分布式事务相关的
测试
package com.springboot.admin;import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;@Slf4j
@SpringBootTest
class Boot05AdminApplicationTests {@AutowiredJdbcTemplate jdbcTemplate;@Testvoid contextLoads() {Long along=jdbcTemplate.queryForObject("select count(*) from student",Long.class);log.info("记录总数{}",along);}}
使用Druid数据源
整合第三方技术的两种方式
1、druid官方github地址
https://github.com/alibaba/druid
自定义
找starter
2.自定义方式
1.创建数据源
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version>
</dependency>
绑定配置文件以及监控页
package com.springboot.admin.config;import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import javax.sql.DataSource;
@Configuration
public class MyDataSourceConfig {//绑定配置文件(默认跟application.yaml绑定)@ConfigurationProperties("spring.datasource")@Beanpublic DataSource dataSource(){DruidDataSource druidDataSource = new DruidDataSource();
// druidDataSource.setUrl();
// druidDataSource.setUsername();
// druidDataSource.setPassword();
//加入监控功能druidDataSource.setFilters("stat");return druidDataSource;}/*配置监控页*/@Beanpublic ServletRegistrationBean statViewServlet(){StatViewServlet statViewServlet = new StatViewServlet();ServletRegistrationBean<StatViewServlet> registrationBean = new ServletRegistrationBean<>(statViewServlet, "/druid/*");return registrationBean;}
}
测试结果
写一个请求测试类来测试是否能监控到sql
//数据监控请求
@Autowired
JdbcTemplate jdbcTemplate;
@ResponseBody
@GetMapping("/sql")
public String queryFromDb(){Long along=jdbcTemplate.queryForObject("select count(*) from student",Long.class);return along.toString();
}
测试结果
开启web监控
通过官方文档可知要在web.xml里面放入filter
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aoWgfogb-1618298400523)(C:\Users\lbw\AppData\Roaming\Typora\typora-user-images\image-20210408215216881.png)]
/*监控web应用*/
@Bean
public FilterRegistrationBean webStatFilter(){WebStatFilter webStatFilter = new WebStatFilter();FilterRegistrationBean<WebStatFilter> webStatFilterFilterRegistrationBean = new FilterRegistrationBean<>(webStatFilter);webStatFilterFilterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));webStatFilterFilterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");return webStatFilterFilterRegistrationBean;
}
测试结果
配置监控页的登录
@Bean
public ServletRegistrationBean statViewServlet(){StatViewServlet statViewServlet = new StatViewServlet();ServletRegistrationBean<StatViewServlet> registrationBean = new ServletRegistrationBean<>(statViewServlet, "/druid/*");/*配置监控页面的登录账号密码*/registrationBean.addInitParameter("loginUsername","admin");registrationBean.addInitParameter("loginPassword","123456");return registrationBean;
}
StatViewServlet配置
根据官方文档引入druid-starter
<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.17</version>
</dependency>
分析自动配置
- 扩展配置项 spring.datasource.druid
- DruidSpringAopConfiguration.class, 监控SpringBean的;配置项:spring.datasource.druid.aop-patterns
- DruidStatViewServletConfiguration.class, 监控页的配置:spring.datasource.druid.stat-view-servlet;默认开启
- DruidWebStatFilterConfiguration.class, web监控配置;spring.datasource.druid.web-stat-filter;默认开启
- DruidFilterConfiguration.class}) 所有Druid自己filter的配置
spring:datasource:url: jdbc:mysql://localhost:3306/testusername: rootpassword: root# type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.jdbc.Driverdruid:aop-patterns: com.springboot.admin.* #监控springbeanfilters: stat,wall #底层功能开启,stat(sql监控),wall(防火墙)stat-view-servlet: # #监控页配置(账号密码)enabled: truelogin-username: adminlogin-password: 123465#web监控web-stat-filter:enabled: trueurl-pattern: '/*'exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'filter: #对上面stat和wall的详细配置stat:slow-sql-millis: 1000log-slow-sql: truewall:enabled: trueconfig:update-allow: truejdbc:template:query-timeout: 3
整合Mybatis操作
https://github.com/mybatis
starter(命名规范)
springBoot官网的Starter:spring-boot-starter-*
第三方: *-spring-boot-starter
引入statr
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.4</version>
</dependency>
配置模式
全局配置文件
SqlsessionFactory:以及自动配置好了
Sqlsession:自动配置了SqlsessionTemplate组合了Sqlsession
@import(AutoConfigredMapperScannerRegistrar.class)
Mapper:只要我们操作Mybatis的接口标准了@Mapper就会被扫描进来
@EnableConfigurationProperties({MybatisProperties.class})//Mybatis配置绑定类
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})public class MybatisProperties {public static final String MYBATIS_PREFIX = "mybatis";}
修改配置文件中mybatis开始的所有;
#配置mybatis规则
mybatis:config-location: classpath:mybatis/mybatis-config.xml #指定全局配置文件位置mapper-locations: classpath:mybatis/mapper/*.xml #sql映射文件位置
测试使用
Mapper接口绑定xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.springboot.admin.mapper.StudentMapper"><select id="getStudent" resultType="com.springboot.admin.bean.Student">select * from student where stuno=#{stuno}</select>
</mapper>
操作数据库
开启驼峰命名
所有配置都在MybatisProperties自动配置好了
写一个Mapepr接口(接口名要和StudentMapper.xml里面的namespace引用路径一致,方法名要和id一致注意要写@Mapper注解)
package com.springboot.admin.mapper;import com.springboot.admin.bean.Student;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface StudentMapper {public Student getStudentBystuno(Long stuno);
}
service
@Service
public class StudentService {@AutowiredStudentMapper studentMapper;public Student getStudentBystuno(Long stuno){return studentMapper.getStudentBystuno(stuno);}
}
controller
//整合mybatis测试
@Autowired
StudentService studentService;
@GetMapping("/acct")
@ResponseBody
public Student getBystuno(@RequestParam("stuno") Long stuno){return studentService.getStudentBystuno(stuno);
}
访问/acct并且给值结果
配置 private Configuration configuration; mybatis.configuration下面的所有,就是相当于改mybatis全局配置文件中的值
config-location configuration不能同时存在
#mybatis全局配置
mybatis:
# config-location: classpath:mybatis/mybatis-config.xml #指定mybatis-config.xmlmapper-locations: classpath:mybatis/mapper/*.xml #扫面mapper.xmlconfiguration:map-underscore-to-camel-case: true#可以不写全局;配置文件,所有全局配置文件的配置都放在configuration配置项中即可
导入mybatis官方starter
编写mapper接口。标准@Mapper注解
编写sql映射文件并绑定mapper接口
在application.yaml中指定Mapper配置文件的位置,以及指定全局配置文件的信息 (建议;配置在mybatis.configuration)
注解模式的mybatis配置
@Mapper
public interface CityMapper {@Select("select * from city where id=#{id}")public City getById(Long id);public void insert(City city);}
混合模式
@Mapper
public interface CityMapper {@Select("select * from city where id=#{id}")public City getById(Long id);public void insert(City city);}
最佳实战:
- 引入mybatis-starter
- 配置application.yaml中,指定mapper-location位置即可
- 编写Mapper接口并标注@Mapper注解
- 简单方法直接注解方式
- 复杂方法编写mapper.xml进行绑定映射
- @MapperScan(“com.atguigu.admin.mapper”) 简化,其他的接口就可以不用标注@Mapper注解
Mybatis-plus
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.1</version></dependency>
自动配置
- MybatisPlusAutoConfiguration 配置类,MybatisPlusProperties 配置项绑定。mybatis-plus:xxx 就是对****mybatis-plus的定制
- SqlSessionFactory 自动配置好。底层是容器中默认的数据源
- **mapperLocations 自动配置好的。有默认值。*classpath*:/mapper/*/*.xml;任意包的类路径下的所有mapper文件夹下任意路径下的所有xml都是sql映射文件。 建议以后sql映射文件,放在 mapper下
- 容器中也自动配置好了 SqlSessionTemplate
- @Mapper 标注的接口也会被自动扫描;建议直接 @MapperScan(“com.atguigu.admin.mapper”) 批量扫描就行
优点:
- 只需要我们的Mapper继承 BaseMapper 就可以拥有crud能力
实战:(创建一个user表)并且增加一些数据
CREATE TABLE user
(id BIGINT(20) NOT NULL COMMENT '主键ID',name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',age INT(11) NULL DEFAULT NULL COMMENT '年龄',email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',PRIMARY KEY (id)
);
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
创建一个实例类
package com.springboot.admin.bean;import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.context.annotation.Configuration;@AllArgsConstructor//lombok插件中的注解
@NoArgsConstructor
@Data
@ToString
//@TableName("user_tbl")//默认通过类去找名字一样的表名此注解是指定表名
public class User {/** 所有属性都应该在数据库中* */@TableField(exist = false)//表中不存在private String username;@TableField(exist = false)private String password;//数据库字段private Long id;private String name;private Integer age;private String email;}
mapper接口继承BaseMapper很多方法已经封装到BaseMapper
package com.springboot.admin.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.springboot.admin.bean.User;public interface UserMapper extends BaseMapper<User> {}
service接口(IService很多方法已经封装到Iservice里面无需再写)
package com.springboot.admin.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.springboot.admin.bean.User;public interface Userservice extends IService<User> {}
service实现类(虽然service中没有写方法但是Iservice中就有很多方法这些方法我们不能所有都实现继承ServiceImpl<操作的mapper对象,操作的实现类>就无需实现这些方法)
package com.springboot.admin.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.springboot.admin.bean.User;
import com.springboot.admin.mapper.UserMapper;
import com.springboot.admin.service.Userservice;
import org.springframework.stereotype.Service;@Service
public class UserServiceimpl extends ServiceImpl<UserMapper, User> implements Userservice {}
controller
@AutowiredUserservice userservice;@GetMapping("/dynamic_table")public String dynamic_table(Model model){//表格内容的遍历
// List<User> users = Arrays.asList(new User("zhangsan", "123456"), new User("ls", "456789"),
// new User("llkk", "555442"));// model.addAttribute("users",users);//查出user表中的数据进行展示mybatis-plusList<User> list = userservice.list();model.addAttribute("users",list);return "table/dynamic_table";}
前端使用Thymeleaf来进行拿值
<table class="display table table-bordered table-striped" id="dynamic-table">
<thead>
<tr><th>#</th><th>id</th><th>name</th><th>age</th><th class="hidden-phone">email</th><th class="hidden-phone">操作</th>
</tr>
</thead><tbody><tr class="gradeX" th:each="user,stat:${users}"><td th:text="${stat.count}">Trident</td><td th:text="${user.id}">id</td><td th:text="${user.name}"></td><td th:text="${user.age}">Win 95+</td><td class="center hidden-phone" >[[${user.email}]]</td><td class="center hidden-phone">X</td></tr>
效果
分页
mybatis-plus分页插件
创建一个comfig
package com.springboot.admin.config;import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MyBatisConfig {@Configuration@MapperScan("scan.your.mapper.package")public class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor paginationInterceptor() {MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false// paginationInterceptor.setOverflow(false);// 设置最大单页限制数量,默认 500 条,-1 不受限制// paginationInterceptor.setLimit(500);// 开启 count 的 join 优化,只针对部分 left join//分页拦截器PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();paginationInnerInterceptor.setOverflow(true);paginationInnerInterceptor.setMaxLimit(500L);mybatisPlusInterceptor.addInnerInterceptor(paginationInnerInterceptor);return mybatisPlusInterceptor;}}
}
controller(IPage里面包含了所有user类里面的数据所以去掉model.addAttribute(“users”,list)所有方法请参照IPage(Idea按两次shift输入IPage下载源码即可查看注解))
Userservice userservice;@GetMapping("/dynamic_table")public String dynamic_table(@RequestParam(value = "pn",defaultValue ="1")Integer pn,Model model){//表格内容的遍历
// List<User> users = Arrays.asList(new User("zhangsan", "123456"), new User("ls", "456789"),
// new User("llkk", "555442"));
// model.addAttribute("users",users);//查出user表中的数据进行展示mybatis-plusList<User> list = userservice.list();//model.addAttribute("users",list);//分页实现Page<User> userPage = new Page<>(pn, 2);//分页查询的结果Page<User> page = userservice.page(userPage, null);//当前第几页long current = page.getCurrent();//总记录数long pages = page.getPages();//所有数据List<User> records = page.getRecords();model.addAttribute("users",page);return "table/dynamic_table";}
分页条
<div class="row-fluid"><div class="span6"><div class="dataTables_info" id="dynamic-table_info">当前第[[${users.current}]]页 总计 [[${users.pages}]]页 共[[${users.total}]]条数据</div></div><div class="span6"><div class="dataTables_paginate paging_bootstrap pagination"><ul><li class="prev disabled"><a th:href="@{/dynamic_table(pn=${users.current}-1)}" >← 上一页</a></li><!--th:each="num:${#numbers.sequence(1,users.pages)}"参照thymeleaf numbers--><li th:class="${num == users.current?'active':''}"th:each="num:${#numbers.sequence(1,users.pages)}"><a th:href="@{/dynamic_table(pn=${num})}">[[${num}]]</a></li><li class="next"><a th:href="@{/dynamic_table(pn=${users.current}+1)}" >下一页 → </a></li></ul></div></div></div>
删除功能
html页面准备一个按钮参考thymeleaf官网文档4.4Link URLs可知**@{/order/{orderId}/details(orderId=${orderId})}动态带值**
<tr class="gradeX" th:each="user,stat:${users.records}"><td th:text="${stat.count}">Trident</td><td th:text="${user.id}">id</td><td th:text="${user.name}"></td><td th:text="${user.age}">Win 95+</td><td class="center hidden-phone" >[[${user.email}]]</td><td class="center hidden-phone"><a th:href="@{/user/delete/{id}(id=${user.id},pn=${users.current})}" class="btn btn-danger btn-sm" type="button">删除</a></td>
</tr>
controller
@GetMapping("/user/delete/{id}")
public String deleteUser(@PathVariable("id") Long id, @RequestParam(value = "pn",defaultValue = "1")Integer pn,RedirectAttributes ra){userservice.removeById(id);ra.addAttribute("pn",pn);return "redirect:/dynamic_table";
}
单元测试
JUnit5的变化
Spring Boot 2.2.0 版本开始引入 JUnit 5 作为单元测试默认库
作为最新版本的JUnit框架,JUnit5与之前版本的Junit框架有很大的不同。由三个不同子项目的几个不同模块组成。
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
JUnit Platform: Junit Platform是在JVM上启动测试框架的基础,不仅支持Junit自制的测试引擎,其他测试引擎也都可以接入。
JUnit Jupiter: JUnit Jupiter提供了JUnit5的新的编程模型,是JUnit5新特性的核心。内部 包含了一个测试引擎,用于在Junit Platform上运行。
JUnit Vintage: 由于JUint已经发展多年,为了照顾老的项目,JUnit Vintage提供了兼容JUnit4.x,Junit3.x的测试引擎。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xLUi1Fp2-1618298400533)(C:\Users\lbw\AppData\Roaming\Typora\typora-user-images\image-20210412011751745.png)]
注意:
SpringBoot 2.4 以上版本移除了默认对 Vintage 的依赖。如果需要兼容junit4需要自行引入(不能使用junit4的功能 @Test)
JUnit 5’s Vintage Engine Removed from spring-boot-starter-test,如果需要继续兼容junit4需要自行引入vintage
<dependency><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.hamcrest</groupId><artifactId>hamcrest-core</artifactId></exclusion></exclusions>
</dependency>
现在引用再springboot创建时就自动帮我们创建了一个测试类默认是Junit5 @SpringBootTest(此注解就是Junit的测试注解)
@SpringBootTest
class Boot05WebAdminApplicationTests {@Testvoid contextLoads() {}
}
以前:
@SpringBootTest + @RunWith(SpringTest.class)
SpringBoot整合Junit以后。
- 编写测试方法:@Test标注(注意需要使用junit5版本的注解)
- Junit类具有Spring的功能,@Autowired、比如 @Transactional 标注测试方法,测试完成后自动回滚
Junit5的常用注解
官网地址:https://junit.org/junit5/docs/current/user-guide/#writing-tests-annotations
- **@Test
Springboot(大总结)相关推荐
- springboot 大文件分片上传、断点续传和秒传
目录 前置说明 获取文件分片 项目流程简述 关键代码解读 表设计SQL 接口测试 测试项目获取地址 前置说明 目前没弄前端,搁置后续再说.前端若打算使用element-ui的el-upload改造分片 ...
- Java hdfs连接池_Java使用连接池管理Hdfs连接
记录一下Java API 连接hadoop操作hdfs的实现流程(使用连接池管理). 以前做过这方面的开发,本来以为不会有什么问题,但是做的还是坑坑巴巴,内心有些懊恼,记录下这烦人的过程,警示自己切莫 ...
- java书籍_还搞不定Java多线程和并发编程面试题?你可能需要这一份书单!
点击蓝色"程序员书单"关注我哟 加个"星标",每天带你读好书! 在介绍本书单之前,我想先问一下各位读者,你们之前对于Java并发编程的了解有多少呢.经过了1 ...
- redis深度历险:核心原理与应用实践_送你一份Redis书单,以后使用缓存的问题不用再问我啦!...
点击蓝色"程序员书单"关注我哟 加个"星标",每天带你读好书! 经过了10多年的发展,Java Web从开发框架到社区都已经非常成熟,很多程序员都可以通过使 ...
- 使用大华惠智双目半球网络摄像机DH-IPC-HD4140X-E2获取人流量统计数据
记录一下使用Java的SpringBoot+大华SDK在智慧公厕项目中使大华惠智双目半球网络摄像机DH-IPC-HD4140X-E2获取人流量统计数据 首先根据说明书登录摄像头,一般摄像头都有自己的账 ...
- Spring boot + sqlserver
参考: 1.狂神说SpringMVC05:整合SSM框架 狂神系列笔记:狂神说Springboot笔记 - 时移之人 - 博客园 SpringBoot Mybatis问题收集 SpringBoot ...
- 阿拉丁神灯点亮计划 之 500年打磨迭代
阿拉丁神灯点亮计划 之 500年打磨迭代 致敬多年以前,那些敢想敢拼敢闯敢干的年轻人. 2020年末总结 码农的角度-技术在精不在多,创业者的角度-技术无边界, 极客的角度-意念即一切, 产品的角度- ...
- 前端 + 后端 实现分片上传(断点续传/极速秒传)
先记录下,后面有时间再去实现 可参考链接:vue上传大文件/视频前后端(java)代码 前端 + 后端 实现分片上传(断点续传/极速秒传) 前端slice分片上传,后端用表记录分片索引和分片大小和分片 ...
- 2022年博客之星排行榜 日榜 2023-01-01 博客之星总榜
2022年博客之星排行榜 日榜 2023-01-01 博客之星总榜 备注: 数据来源 :https://pachong.vip/csdn/blogstar,如有侵权,联系秒删~ 博主链接: htt ...
- 2022年博客之星排行榜 日榜 2022-12-30博客之星总磅
2022年博客之星排行榜 日榜 2022-12-30 备注: 数据来源 :https://pachong.vip/csdn/blogstar,如有侵权,联系秒删~ 博主链接: http://t.c ...
最新文章
- mac curl命令下载文件
- 每日一皮:循环没写好,导致后面数据覆盖了前面的数据...
- 时下最流行前端构建工具Webpack 入门总结
- python设置一个初始为0的计数器_python中统计计数的几种方法
- API设计原则(觉得太合适,转发做记录)
- python根据频率画出词云_利用pandas+python制作100G亚马逊用户评论数据词云
- jQuery框架的ajax
- matlab中符号检验,配对符号秩和检验,配对资料的符号检验,符号
- 你想要的宏基因组-微生物组知识全在这(2021.12)
- ios键盘done中文_IOS_总结IOS中隐藏软键盘的三种方式,一、使用软键盘的 Done 键隐藏 - phpStudy...
- wincc安装信息服务器,常见WinCC安装问题及注意事项
- Pyflink系列之使用pyflink实现flink大数据引挚的经典案例wordcount
- OpenLayers之多源数据加载七:矢量地图
- 阿里云盘进场,安全星球凭什么成为云盘界的一股清流
- 4000字干货长文!从校招和社招的角度说说如何准备大厂面试?
- 一年级下册数学计算机应用题,【小学一年级数学练习题】小学生和机器人
- gateway-使用
- 标准库intrins.h中的循环指令在多种流水灯方式上的应用
- python爬取天猫商品数据
- 使用ajax访问腾讯地图api,腾讯地图ajax获取路线规划结果
热门文章
- 如何查看电脑操作系统及系统类型
- Codeforces 731C Socks By Assassin
- JavaEE Spring框架学习笔记(AOP Introductions介绍)
- 如何获取免费的数字货币历史数据
- TensorFlow 从入门到精通(8)—— 泰坦尼克号旅客生存预测
- pytorch3d代码解释:pytorch3d.structures.meshes之verts_list, verts_packed, verts_padded
- iWatermark Pro for Mac(水印制作软件)
- 滴滴章文嵩分享大数据在城市智慧交通领域探索实践
- 电脑通过网口共享网络(WIFI)给其他设备
- unity LineRender结合多点触摸 实现拖拽 重复画线
- springboot 大文件分片上传、断点续传和秒传