文章目录
SpringBoot简单学习总结
前言
简单学习了SpringBoot,真的及其简化了spring的开发,省去了很多麻烦,感谢黑马程序员的课程,看的是黑马程序员SpringBoot2全套视频教程,讲的很好,在此总结一下,以便以后复习,
内容很多,请善用Ctrl+f
SpringBoot构建方式(以SpringMVC为例)
- idea使用官网(https://start.spring.io)构建(需要联网)
- idea新建项目,点击spring Initializr
- URL选项选择Default,点击next
- 设置自己的GAV信息,选择自己的java版本,(包名太长可以删除简化)
- 也可以更改工程类型与语种,默认为maven与java,点击next
- 这里选择你要导入的工具与选择SpringBoot的版本
- 选择工具勾选即可,也可搜索,然后点击next
- 直接访问官网(https://start.spring.io)构建(需要联网)
- 可以直接访问,也可以去spring官网->project->springboot->网页底端spring Initializr
- 操作同idea使用官网步骤3,4,5,Dependencies中添加需要的工具,GENERATE下载工程,EXPLORE预览生成的项目,SHARE分享链接共享当前配置。如果您想依赖我们的默认值,可以从 URL 中删除属性。
- 点击GENERATE下载项目,然后导入到idea进行开发.(阿里云没有这种方式)
- 使用阿里提供的网站(https://start.aliyun.com)构建(需要联网)
- idea新建项目,点击spring Initializr
- URL选项选择Custom,填入地址(https://start.aliyun.com),点击next
- 其他步骤同idea使用官网步骤3,4,5,6,不过中方式选择时候springboot版本较低,不过可以去项目的pom中修改即可,且阿里还提供了很多技术在导入工具是供我们选择
- 使用maven直接构建(无需联网,但需要原先boot项目)
- 直接创建一个maven项目,无需骨架,配置一个完整的maven项目
- 然后将缺少的东西补齐(东西是什么下面讲解)
- 缺少依赖,让项目继承spring-boot-starter-parent很重要的父工程
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
- 缺少依赖,添加项目所需SpringMVC依赖,使用springboot特点,添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
- 缺少引导类,添加一个类,名字、位置随便,类上添加注释@SpringBootApplication,类中有个main函数(理论上这个main方法在哪个类运行都可以,只不过idea不会识别为Service)
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
- 缺少依赖,让项目继承spring-boot-starter-parent很重要的父工程
- 添加controller,运行测试。(测试的那些东西也一样,如果原先有springboot的项目直接复制结构即可)
- SpringBoot构建总结
- 这四种方法都可以构建maven工程的boot项目,后面我们知道这些组件都是干什么的时候,就更容易构建
SpringBoot优点(以SpringMVC为例)
- 起步依赖(简化了依赖配置)
- parent
- 原理: boot将常用资源坐标与版本分离并管理,坐标设置成与当前boot版本最合适的版本,这样我们使用时就可以直接使用springboot的parent即可,使用其他组件也只需定义坐标即可,不用定义版本。
- 实现(从官网上与阿里云上构建的项目实现方式不同,不过都差不多):
- (官网构建)继承 spring-boot-starter-parent --> spring-boot-dependencies ==>里面有各组件及版本号
- (阿里云构建)直接导入spring-boot-dependencies,继承只能继承一次
- 都是利用了spring-boot-dependencies中定义的版本号与组件实现简化依赖配置
- starter
我们定义了parent,但是我们使用的时候一般不会直接使用组件,因为springboot还有starter,使用starter更能简化怎么的依赖配置。- 定义:包含若干个坐标定义的pom管理文件,即:一个starter定义了一个技术所有需要包的坐标及其版本,所以导入一个starter就相当于导入多个包,并且starter的版本号也由parent管理,使导入不需要关注版本。
- parent
- 自动配置(简化了常用工程的相关配置)
- 引导类
- 引导类的注解,点击
@SpringBootApplication
注解源码其实就可以看到(虽然没怎么看懂),直接映入眼帘的便是@ComponentScan
这个注解,即spring注解开发中配置注解配置类,不配置这个就默认扫描当前包及其子包,所以那些controller,service.mapper都要放在当前包及其子包及其子包中,上面还配置了@SpringBootConfiguration
,点击进去可知这个注解就配置了@Configuration
说明这就是个spring的配置类 - main方法中内容,也像spring注解开发中
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(SpringConfiguration.class);
,boot中SpringApplication.run(class,args)
将配置类的字节码文件传过去,所以像是spring注解开发,并把服务器也启动了起来, 它的返回值也是spring上下文类型ConfigurableApplicationContext,run方法有重载形式,不一定需要传入args,不传args表示不接受临时变量,可能更安全点.
- 引导类的注解,点击
- 引导类
- 辅助功能(内置服务器…)
- 内嵌tomcat
- 实现:boot中引入的依赖
spring-boot-starter-web
中包含spring-boot-starter-tomcat
,而tomcat的starter中又包含tomcat-embed-core
,即内嵌的tomcat代码,tomcat也是由java语言写的,boot就将tomcat运行过程封装成一个对象,并由spring管理,至于内部操作一定很复杂 - **替换服务器:**如果想更换web服务器,可以利用maven的排除依赖来排除掉tomcat
如果排除了tomcat,但没有添加其他服务器,web程序则无法启动
然后替代成其他web服务器(利用boot特点,导入相应starter即可)
springboot有三种web服务器starter- tomcat(默认) apache出品,应用面广,负载了若干较重的组件
- jetty 更轻量级,负载性能远不及tomcat
- undertow 负载性能勉强跑赢tomcat
实例 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions><!--排除tomcat--> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency>
- 实现:boot中引入的依赖
- 内嵌tomcat
SpringBoot中的配置文件
boot配置文件在maven中resource目录中,默认名称为application.properties
,idea中提供了强大的提示功能,且idea是根据你所导入的技术来提示,没导入的技术不会提示,你也可以从spring官网中查找相应的功能配置(需了解的是官网中为全部配置属性且格式为properties
配置格式),步骤为:
- 去https://spring.io/projects/spring-boot#learn 中Documentation中,绿色的表示现行的,点击 Reference Doc.
- 找到Application Properties选项,点进去就是所有配置及解释,可以使用Ctrl+f进行检索
配置文件的格式
配置文件格式分为三种
-
格式 server.port=8081 properties格式 传统格式/默认格式 server.port=8081 yml格式 主流模式 server:
port: 8081yaml格式 - 与yml格式一样 - 三种格式的优先级,如果有相同的配置,则优先级 properties>yml>yaml,如果存在不相同的配置,则全部都存在
配置文件名称
配置文件名称这个概念感觉比较重要,但是比较简单,后面也会用到,在这里简单介绍一下,配置文件名称默认为application,即boot项目运行时就会在resource中找名application
的配置文件,不管是什么格式的,内容合并依靠上面的优先级决定。
更专业的解释是,格式为:application-{profile}.properties,其中 {profile} 对应你的环境标识(后面解释)
而在实际开发中如果某开发人员离职,如果它知道配置文件名称,可能会导致不安全,所以给配置文件起别名会使项目更安全
方法1: 在运行时添加临时变量属性,即:–spring.config.name=ebank
不用后缀名,只要是这个名称的配置文件都可
方法2: 在运行时添加临时变量,配置文件路径(可多个,有逗号隔开,级别谁后定义谁级别高)
即:–spring.config.location=d://adc.properties[这是全路径名]
--spring.config.location=classpath:/abc.properties,classpath:/edank.yml[这是类路径]
boot启动时就会找相应的配置文件,在cmd中运行jar包时,传递参数也为–spring.config.name=ebank(还是两个减号,一个减号可能会识别命令行的参数,具体也不懂,知道的可以评论一下,蟹蟹)
yml配置详解
yml格式优点:
1.格式比较有层次感,
2.不会有太多的冗余
3.配置数组简单
数据前面要加空格与冒号隔开
元素数组定义
likes:
- book
- eat
- program
-122 #减号后面要用空格不然不识别
元素数组缩略版定义
likes2: [book,eat,program]
对象数组定义
users:
- name: tom
age: 15
- name: lucy
age: 16
users2:
-
name: tom
age: 15
-
name: lucy
age: 16
对象数组缩略版定义(json)
users3: [{name:tom,age=15},{name:lucy,age=16}]#name:tom中冒号不用加空格
配置文件读取,此后几乎都是使用yml配置格式
- 使用spring中@Value注解并结合SpEL进行加载
一个案例演示全了吧,读取users: [{name:tom,age=15},{name:lucy,age=16}]
@Value("${user[1].name}") ==> lucy - 使用spring的自动装配来进行读取,装配的数据为
Environment
类型
@Autowired
private Environment env
env.getProperty(“user[1].name”) - 定义相应组对象
实例- 配置文件中定义
user:
name: “张三”
age: 16
like:
- read
- eat
- program - //2.1.定义数据模型,封装yml中对应的数据
//2.2.定义为spring管控的bean
@Component
//2.3.指定加载的数据
@ConfigurationProperties(prefix = “user”)
@Data
public class User {
private String name;
private int age;
private String[] like;
} - 使用
@Autowired
User user; - 输出 User(name=张三,age=16,like=[read,eat,program])
- 配置文件中定义
- 上面为读取yml格式的,读取properties格式会出现各种问题
- 读取properties配置文件出现乱码,这是由于boot读取properties配置文件时默认为ISO-8859-1编码格式读取的,解决办法
- 读取的字符串使用ISO-8859-1解码,在使用utf-8进行编码,即:
new String(name.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8)
- 使用spring新注解
@PropertySource(value= "classpath:pro/application.properties", encoding="UTF-8")
,但是这样好像有点问题,试了多次,在此总结一下,如有错误,还请斧正。使用这个注解时如果直接是resource目录下的application.properties
,试了好多遍都不行,只能想到在加载这个配置文件时其他配置(注解)替代了@PropertySource的配置,但是换到其他目录上去或更改为其他名字便可以解决乱码 - properties配置文件中也可以定义数字,对象数组,读取时和yml一样,也可以封装到对应的对象中去,只不过将yml中配置完整写在properties中,只不过properties不支持yml中的缩略定义版
#案例 #properties这样定义对象数组 users[0].name="张三" users[0].age=16 users[1].name="王五" users[1].age=18 #properties定义对象,这样也可以封装成User对象 user.name=王五 user.age=17 user.like[0]=book user.like[1]=吃 user.like[2]=sleep #相比yml是不是很麻烦,所以主流为yml格式
- 读取的字符串使用ISO-8859-1解码,在使用utf-8进行编码,即:
- 读取properties配置文件出现乱码,这是由于boot读取properties配置文件时默认为ISO-8859-1编码格式读取的,解决办法
- yml与properties配置文件中都可以引用,与SpEL一样,即
# yml中可以这样配置 baseDir: c:\Windows tempDir: ${baseDir}\temp #这样tempDir实际上就是 c:\Windows\temp #properties中可以这样配置 baseDir=c:\Windows tempDir=${baseDir}\temp #与yml效果一样
- yml与properties配置文件的不同
- 他两个最大的不同就是引号问题,properties中等好后面的都是属性值,即使是引号也会当做字符串处理,注释符号也不例外,且那些转义字符是一定打开的,如果不想打开,则需要转义转义字符,即:\t => 制表符,\t => \t
- 而yml的最大特点是加引号与不加引号有两种解析方式,如果想让引号当做字符串需要转义一下,
- yml不加引号,不会识别转义字符,添加了引号才会识别转义字符,不管加不加引号都会识别SpEL属性
多环境开发多模块开发问题
多环境开发即多个环境分别为:生产环境Production,开发环境Development,测试环境Test, 在不同环境下配置也不尽相同,最明显的就是数据库配置、端口配置等,处理办法有如下
- 方法一:在一个配置文件中,配置多个环境(需要配置名称)
一个配置文件中配置多环境是以---
(三个减号)作为分隔线,可以配置若干个,但是不管配置几个环境,最下面一个没有定义环境名称的环境就是默认环境,配置的为公共配置(指定引用环境),在boot启动时会被加载,我们默认将最上面一个环境设置为默认环境,即:不设置环境名,只设置环境名,不设置引用哪个属性名,则不会执行任何环境,只会执行默认环境(properties配置文件不支持方法一)
其中设置环境名称好像有三种,1).spring: profiles: 名
,2).spring: config: activate: on-profile: 名
,这两种视频上讲了,第三种好像也可以(已试),3).profile:名
。
引用环境就一种spring: profile: active: 环境名
。# 默认环境(不定义则为最后一个环境) #配置公共配置 #使用哪个环境 spring: profiles: active: dev --- # 生产环境 spring: profiles: pro server: port: 80 --- # 开发环境 #spring: # profiles: dev #profiles: dev spring: config: activate: on-profile: dev server: port: 8001 --- # 测试环境 spring: profiles: test server: port: 8081
- 方法二:使用多个配置文件,然后在总配置文件中调用环境,调用就是
总配置名称-环境标识
的配置文件,不管格式(这里用到了上面配置文件名称知识)
在开发中默认还要分多个功能[模块],一般将每个功能[模块]的配置文件都分开书写,即application-devDB,application-devMVC,并且多环境开发时每个环境又有多个模块,可以使用两种方式解决
1). 通过spring=profile.include=${profile},${profile}
,**优点:**可以直接使用,不需要action启动相应的环境(没有多环境),include的配置直接被引用, **缺点:**不可以很好的与action相关联,切换环境时,即action改变时,必须手动改变相应的配置文件。
2). 通过spring.profile.group.*=${profile},${profile}
,**优点:**可以很好的与action关联,当action改变切换环境时,可以设定相对应的属性来指定配置文件,如总配置文件内容所示。**缺点:**只能联合action一起使用,不能在不引用action是导入配置文件
总结:当你有多环境时使用goroup方便,当你没有多环境时使用include快速
实例如下:
总配置文件内容
其他配置文件内容# 配置文件内容中不需要配置名称,只需要名称格式为:[此文件名-调用名称](properties也是这样) # 在开发中默认还要分多个功能[模块],一般将每个功能[模块]的配置文件都分开书写,即application-devDB,application-devMVC # 可以include/group引用其他配置文件 spring: profiles: active: dev # include每次切换环境都要手动改变配置文件名称 # include: devDB,devMVC # springBoot2.4开始使用group简化include group: "dev": devDB,devRedis,devMVC "pro": proDB,proRedis,proMVC "test": testDB,testRedis,testMVC
application-pro.yml内容 # 生产环境 server: port: 80 application-dev.yml内容 # 开发环境 server: port: 8001 application-test.yml内容 # 测试环境 server: port: 8081 application-devMVC.yml内容 # 开发环境中MVC相关配置 MVCdata: devMVC
- 多个配置文件时加载顺序问题,都坚持一个原则,后加载的配置覆盖先加载的
- 使用include加载时,先加载include的内容并顺序加载,最后加载
环境配置
配置: active: dev include: devMVC,devDB
输出: The following profiles are active: devDB,devMVC,dev
- 使用group加载时,先加载
环境配置
,在加载环境所对应的内容并顺序加载
配置: active: dev group: “dev”: devMVC,devDB
输出: The following profiles are active:dev
,devDB,devMVC - 如果include与group同时配置,则不管include与group配置先后顺序,先顺序加载include的,再加载
环境配置
,最后顺序加载group里的,相同的配置文件不会再次加载。
配置:active:dev
include: devMVC,devDB,devPojo
group: “dev”: devMVC,devRedis,devDB
输出:The following profiles are active: devMVC,devDB,devPojo,dev
,devRedis
- 使用include加载时,先加载include的内容并顺序加载,最后加载
- 多环境开发控制(maven与springBOOT都用多环境开发冲突)
当maven与springboot同时使用多环境进行控制室,以maven为主,
springBoot使用@.(maven属性名).@占位符获取maven对应的配置属性
基于springBoot读取maven配置文件属性的前提下,如果在Idea下测试工程时
pro.xml每次更改都需要手动compile方可生效
配置文件四级分类
在实际开发中,程序员开发时需要一套配置,而项目经理也需要一套配置,运维人员也需要一套配置,运维组长甚至也需要一套,如果相互的改动,不知道什么时候就乱了,于是boot就帮我们解决这一问题,他将配置文件分为四级,级别大的配置就替换级别小的配置,不同配置都会保留,这样也使各级人员互不干扰,减少冗余配置。
- 配置文件名称为统一的,默认为
application
,不管是什么格式(yml,properties,yaml)的配置文件,如果想设置其他名称可以参考上面的配置文件名称中的方法一,java -jar 包 --spring.config.name=ebank
- 一级配置:即:resource目录下的
名称.
配置文件,一般是程序员使用的配置 - 二级配置:在resource创建config目录,并创建
名称.
配置文件,一般为项目经理使用 - 三级配置:一般是指和项目jar包在同一目录下的
名称.
配置文件,不过使用idea工具时,和项目文件夹在同一目录下的名称.
配置文件也是三级配置,不过开发过程不会遇到 - 四级配置:一般是指和项目jar包在同一目录下创建config文件夹,并创建
名称.
配置文件, 和三级配置一样,使用idea工具项目文件夹就相当于项目jar包。
idea工具中配置文件不提示问题
idea具有强大的提示功能,但有时候我们自定义一些配置文件时,会出现编写配置不提示的问题,可以通过下面步骤来解决,**提醒: **这是设置只是让idea知道这是springboot的配置文件,来进行提示,项目中想引用配置文件还需要配置include或group。
步骤如下:1). 点击(1)处图标,或点击工具栏File → Project Structure 。2). 点击Facets。3). 选择项目。4)点击右侧的选项,是boot叶子图标变绿(表示可点击)。5). 点击boot标志叶子。6). 点击加号。7).找到你要提示的配置文件。8). 点击ok,
9).这里有特殊情况,情况一: 原先有配置文件,第(9)步位置处有值就不用了操作直点OK,情况二: 没有任何配置文件,你选择了配置文件,之后在第(9)步位置上输入名称(看图二),如果没有提示可能你将application.properties文件()没有删除而是移动到某个文件夹,你填application的相关配置文件就行,具体还是百度吧=_=
springboot集成各类技术
利用springboot的starter,可以很快的集成某项技术
springboot集成Junit
- 步骤:
1.导入测试相对应的starter,spring-boot-starter-test
2.测试类使用注解@SpringBootTest
3.使用自动装配添加测试对象 - 问题: 当测试类不在SpringBoot配置类(引导类)的包或子包时
执行测试文件会直接报错
Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=…) with your test - 原因: springboot测试类找不到@SpringBootConfiguration,即配置类(@SpringBootApplication有这个注解)
在spring整合Junit是需要配置两个注解
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(配置文件或者配置类)
在springboot中@SpringBootConfiguration的类就是spring配置类,而这个问题与springboot执行测试时找配置类机制有关 - 机制: springboot会从测试类的包下找配置类,如果没有则去上一层包去找,所以,当出现该问题是,需要手动定义配置类在哪
- 解决: 1.测试类添加注解@ContextConfiguration(class=Springboot0101quickstartApplication.class)
2.测试类@SpringBootTest添加属性(class=Springboot0101quickstartApplication.class)
springboot集成Mybatis
- 步骤
0.导入相应starter mysql -> mysql-connector-java , mybatis-spring-boot-starter(名字spring在后说明是第三方提供), mysql驱动包不要忘了
1.定义相应mapper,注解开发需要添加注解@Mapper
2.定义配置文件@Mapper//让容器识别到完成自动导入 public interface BookMapper { @Select("select * from book_tb where id = #{id}") public Book findById(int id); }
3.在测试类中测试spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/test username: root password: 1234
- 问题:这样配置
当springboot将至2.4.1时执行mybatis报错driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/test
The server time zone value '�й���ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the 'serverTimezone' configuration property) to use a more specific time zone value if you want to utilize time zone support.
- 解决: 好像是mysql的时区问题,要定义具体时区值 ,1.给mysql数据库直接设置上时区 , 2.在设置url设置
url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC
- 问题: 运行警告
Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
- 解决:意思是com.mysql.jdbc.Driver已废弃,要更改成com.mysql.cj.jdbc.Driver
重新配置: driver-class-name: com.mysql.cj.jdbc.Driver
springboot集成MybatisPlus
- 步骤
1.添加mybatisPlus的starter, springboot还没有收录MybatisPlus,所以创建项目时不能勾选,须去maven仓库查找然后手动添加,或者可以从阿里云官网构建项目,里面有mybatisPlus的选项
2.利用MP简化mapper<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
3.配置文件进行相关配置@Mapper//需要添加模块泛型 public interface BookMapper extends BaseMapper<Book> {}
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC username: root password: 1234
- 使用MybatisPlus的BaseMapper中方法.MP会将模型(pojo)与表自动映射,如果你的表与模型名称不一致,MP找不到相应的表
- 解决方法1: 在模型类上使用
@TableName("表名")
注解@Data @TableName("book_tb") public class Book { Integer id; String type; String name; String description; }
- 解决方法2: 如果你的模型类名与数据库表存在前缀关系,则可以在配置中配置表的前缀名,即: 表名:tbl_book,模型类名:Book,如果模型类配置了@TableName,则会按着这个注解找数据库表,不会走前缀
# 模型类不需要配置注解@TableName mybatis-plus: global-config: db-config: table-prefix: tbl_
@Autowired BookMapper bookMapper;//这里可能会 @Test void contextLoads() { System.out.println(bookMapper.selectById(1));//根据查询查询 System.out.println(bookMapper.selectList(null));//根据添加查询 }
- 结果集封装成对象是的驼峰命名法转换
驼峰命名法: 当变量名或函数名是由一个或多个单词连结在一起,而构成的唯一识别字时,第一个单词以小写字母开始;从第二个单词开始以后的每个单词的首字母都采用大写字母, 例如:myFirstName、myLastName 下划线命名法: 每个单词都为小写且单词之间以下划线作为分隔, 例如:my_first_ame、my_last_name
在使用MybatisPlus时默认为默认打开驼峰命名法转换的,简单看了下spring构建Bean的源码驼峰命名法转换(自己起的): 数据库字段使用下划线命名法,即:user_name, java实体类属性名使用驼峰命名法, CRUD时,数据库下划线字段与实体类驼峰字段相互转换 案例: 数据库字段: id,user_name 实体类属性: id,userName,user_name 操作: 从数据库读取数据 结果: 会把查询的结果集字段重命名为为userName,从而导致实体类user_name属性没有值 输出实体: id=1,userName=Tom,user_name=null
MybatisSqlSessionFactoryBean
,在buildSqlSessionFactory
方法中有个MybatisConfiguration
类型参数,在一开始会判断是否配置了configuration和configLocation,如果都没有(其他情况暂时不看)则直接使用空参构造创建MybatisConfiguration
,而空参构造方法中,mapUnderscoreToCamelCase
默认值为true;final MybatisConfiguration targetConfiguration; // TODO 使用 MybatisXmlConfigBuilder 而不是 XMLConfigBuilder MybatisXMLConfigBuilder xmlConfigBuilder = null; if (this.configuration != null) { targetConfiguration = this.configuration; if (targetConfiguration.getVariables() == null) { targetConfiguration.setVariables(this.configurationProperties); } else if (this.configurationProperties != null) { targetConfiguration.getVariables().putAll(this.configurationProperties); } } else if (this.configLocation != null) { // TODO 使用 MybatisXMLConfigBuilder xmlConfigBuilder = new MybatisXMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties); targetConfiguration = xmlConfigBuilder.getConfiguration(); } else { LOGGER.debug(() -> "Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration"); // TODO 使用 MybatisConfiguration targetConfiguration = new MybatisConfiguration(); Optional.ofNullable(this.configurationProperties).ifPresent(targetConfiguration::setVariables); }
- 怎样关闭驼峰命名法转换
虽然这个功能很好,但是可能原先项目换成mybatisPlus时会导致部分数据丢失核心文件中配置 <settings> <setting name="mapUnderscoreToCamelCase" value="false"/> </settings> spring中配置(直接使用MP同理): <bean id="mybatisConfiguration" class="com.baomidou.mybatisplus.core.MybatisConfiguration"> <property name="mapUnderscoreToCamelCase" value="false"/> </bean> <bean id="sessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="configuration" ref="mybatisConfiguration"/> </bean> springboot配置: mybatis-plus.configuration.map-underscore-to-camel-case=false
- 怎样部分开启,关闭之后可以在实体属性中配置注解
@TableField(下划线字段名)
,这个注解只有用MP时才会读取,即: 使用SqlSessionFactoryBuilder
构建时不会生效
例如:@TableField(value = "user_name") private String userName; //这个注解只有用MP时才会读取
@TableField
也可以解决实体类中某属性有值且在数据库不存在字段,可以使用@TableField(exist=false)
来解决,不使用此注解可能出现插入数据是报错.
- 怎样关闭驼峰命名法转换
-
MybatisPlus使用简解
-
继承
BaseMapper<泛型>
方法简解- 案例:
//Mapper接口 @Mapper//需要添加模块泛型 public interface BookMapper extends BaseMapper<Book> { } //模型类 @Data @TableName("book_tb") public class Book { private Integer id; private String type; private String name; private String description; }
- 调用方法:
- 插入方法
Book book = new Book(); bookMapper.insert(book);
- 插入时会报错,原因是由于MP使用自动生成Id为雪花算法生成,需要配置为自动生成id,也可以通过给id字段添加注解
@TableId(type = IdType.AUTO)
Caused by: org.apache.ibatis.reflection.ReflectionException: Could not set property 'id' of 'class com.muyu.pojo.Book' with value '1467064655366000642' Cause: java.lang.IllegalArgumentException: argument type mismatch
- 配置
mybatis-plus: global-config: db-config: id-type: auto
- 插入时会报错,原因是由于MP使用自动生成Id为雪花算法生成,需要配置为自动生成id,也可以通过给id字段添加注解
- 根据id删除方法
bookMapper.deleteById(15);
- 根据id修改,属性值为null的不修改
Book book = new Book(); book.setId(15); book.setName("mapper测试修改"); bookMapper.updateById(book);
- 根据id查询单个
Book book = bookMapper.selectById(12);
- 根据条件查询,
bookMapper.selectList(QueryWrapper);
参数为查询封装器类型- QueryWrapper类型,但是可能存在column出现拼错的问题,可以使用LambdaQueryWarpper
QueryWrapper<Book> qw = new QueryWrapper<Book>(); qw.like("name", "spring"); List<Book> books = bookMapper.selectList(qw); //查询所有 List<Book> books = bookMapper.selectList(null);
- LambdaQueryWarpper类型
String search = "spring"; LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>(); //如果search为空可以手动添加if进行判断 //if (Strings.isNotEmpty(search))qw.like(Book::getName, search); //也可是使用like方法的重载like(boolean, R , object) lqw.like(Strings.isNotEmpty(search),Book::getName, search);//org.apache.logging.log4j.util.Strings; bookMapper.selectList(lqw);
- QueryWrapper类型,但是可能存在column出现拼错的问题,可以使用LambdaQueryWarpper
- 分页条件查询,MP里有内置的分页工具,其原理应该是类似拦截器,或者像代理? 返回值其实就是那个参数Page类,和分页插件一样, 第二个参数也是QueryWarpper,同条件查询,要想分页生效需要配置拦截器
IPage page = new Page(1,5); bookMapper.selectPage(page,null); /*要想分页生效需要配置拦截器,*/ System.out.println(page.getRecords()); // 包含数据 System.out.println(page.getPages()); // 共几页 System.out.println(page.getTotal()); // 数据总数
- 配置拦截器
//此类要放在引导类的包及其子包下 //定义与Mp相关的一些配置 //方式一: @Configuration public class MPConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//这时候拦截器还是空的 interceptor.addInnerInterceptor(new PaginationInnerInterceptor());//配置内部拦截器 return interceptor; } }
//方式一: @Configuration public class MPConfig { @Bean public PaginationInnerInterceptor paginationInnerInterceptor() { return new PaginationInnerInterceptor();//直接配置分页 } }
- 配置拦截器
- 插入方法
- 案例:
-
使用MP简化Mapper层实现也可以通过注解或xml配置进行开发,mybatis与MP都可以这样配置
- 注解
@Select("SELECT * FROM user WHERE #{id}") List<User> findOne(int id);
- xml配置,条件查询我还是喜欢xml配置,属实小白,试了好久,还是没找到规律,先这样吧,简单总结一下
- 映射文件
*Mapper.xml
,springboot会自动加载mapper包及其子包下的xml映射文件,映射文件名称无所谓只要配置<mapper namespace="类全限定名">
,即使存在两个namespace一样的映射文件,也可以在boot配置文件中配置mybatis-plus.mapper-locations=classpath:*Mapper.xml
,mybatis.mapper-location好像不行。 - 配置核心文件一直配置不成功(成功了一半),在核心配置文件中配置
<typeAliases > <typeAlias type="com.muyu.pojo.User" alias="user"/> </typeAliases>
和<mappers> <mapper resource="aaa/UserMapper.xml"/> </mappers>
都可以,但是如果配置包那种如:<typeAliases > <package name="com.muyu.pojo" /> </typeAliases>
和<mappers> <package name="aaa"/> </mappers>
就会报错,Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in class path resource [com/baomidou/mybatisplus/autoconfigure/MybatisPlusAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.ibatis.session.SqlSessionFactory]: Factory method 'sqlSessionFactory' threw exception; nested exception is org.springframework.core.NestedIOException: Failed to parse config resource: class path resource [sqlMapConfig.xml]; nested exception is org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.lang.StringIndexOutOfBoundsException: String index out of range: -110 ... 70 more Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.ibatis.session.SqlSessionFactory]: Factory method 'sqlSessionFactory' threw exception; nested exception is org.springframework.core.NestedIOException: Failed to parse config resource: class path resource [sqlMapConfig.xml]; nested exception is org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.lang.StringIndexOutOfBoundsException: String index out of range: -110 at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ... 88 more Caused by: org.springframework.core.NestedIOException: Failed to parse config resource: class path resource [sqlMapConfig.xml]; nested exception is org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.lang.StringIndexOutOfBoundsException: String index out of range: -110 ... 89 more Caused by: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.lang.StringIndexOutOfBoundsException: String index out of range: -110 ... 102 more Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: -110
#mybatis:配置好像不行 mybatis-plus: configuration: map-underscore-to-camel-case: false mapper-locations: classpath:UserMapper.xm #配置Mybatis映射文件 type-aliases-package: com.muyu.pojo #给相应包起别名 # config-location: classpath:sqlMapConfig.xml #配置核心配置类 #mapperLocations:它表示我们的Mapper文件存放的位置,当我们的Mapper文件跟对应的Mapper接口处于同一位置的时候可以不用指定该属性的值 # configLocation:用于指定Mybatis的配置文件位置。如果指定了该属性,那么会以该配置文件的内容作为配置信息构建对应的SqlSessionFactoryBuilder,但是后续属性指定的内容会覆盖该配置文件里面指定的对应内容 # typeAliasesPackage:它一般对应我们的实体类所在的包,这个时候会自动取对应包中不包括包名的简单类名作为包括包名的别名。多个package之间可以用逗号或者分号等来进行分隔(value的值一定要是包的全) # typeAliases:数组类型,用来指定别名的。指定了这个属性后,Mybatis会把这个类型的短名称作为这个类型的别名,前提是该类上没有标注@Alias注解,否则将使用该注解对应的值作为此种类型的别名(value的值一定要是类的完全限定名) # plugins:数组类型,用来指定Mybatis的Interceptor # typeHandlersPackage:用来指定TypeHandler所在的包,如果指定了该属性,SqlSessionFactoryBean会自动把该包下面的类注册为对应的TypeHandler。多个package之间可以用逗号或者分号等来进行分隔 # typeHandlers:数组类型,表示TypeHandler # mapper: #不知道是什么,暂且挌下 # mappers: com.pinyu.miniprogram.mysql.mappers.BaseMapper # identity: mysql
- 映射文件
- 注解
-
使用MybatisPlus简化Service实现
- 步骤
- 给service接口继承Iservice<模型类>
//使用标准接口开发,前面加I public interface IBookService extends IService<Book> { //追加的操作与原始操作通过名称区分 IPage<Book> getPage(int currentPage, int pageSize,Book book); }
- 给service实现类继承ServiceImpl<引用的实现类,模型类>,service实现可以利用ServiceImpl现有的方法,减少代码编写量
/* ServiceImpl需要定义两个泛型,<引用的实现类,模型类> */ @Service public class BookServiceImpl extends ServiceImpl<BookMapper, Book> implements IBookService { @Autowired BookMapper bookMapper; @Override public IPage<Book> getPage(int currentPage, int pageSize,Book book) { IPage page = new Page(currentPage,pageSize); LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>(); lqw.like(Strings.isNotEmpty(book.getType()), Book::getType, book.getType()); lqw.like(Strings.isNotEmpty(book.getName()), Book::getName, book.getName()); lqw.like(Strings.isNotEmpty(book.getDescription()), Book::getDescription, book.getDescription()); bookMapper.selectPage(page, lqw); //如果查询完后当前页大于总页数(这样表明没有数据),就在执行一次,保证有数据, if (currentPage > page.getPages()) { page.setCurrent(page.getPages()); bookMapper.selectPage(page, lqw); } return page; }
- 给service接口继承Iservice<模型类>
- 步骤
- ServiceImpl<引用的实现类,模型类>方法简解,和上面一样的案例
- 插入方法,与实现Mapper层一样,也需要配置自动注解,详情看上面
Book book = new Book(); bookService.save(book);
- 根据id删除方法
bookService.removeById(17);
- 根据id修改方法
Book book = new Book(); book.setId(15); book.setName("Service测试数据123"); bookService.updateById(book);
- 根据id查询
Book byId = bookService.getById(12);
- 根据条件查询,与BaseMapper一样
LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>(); lqw.like(Book::getName, "spring"); List<Object> objects = bookService.listObjs(lqw); //查询所有,两种方法 List<Object> objects1 = bookService.listObjs(); List<Object> objects2 = bookService.list();
- 分页条件查询,与BaseMapper同理
IPage<Book> page = new Page<Book>(2,5); bookService.page(page); //分页条件查询 LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>(); bookService.page(page,lqw);
-
- MP实现Mapper与Service方法名称对比,使用几乎一模一样
功能 Mapper层 Service层 插入方法 insert(T)
save(T)
根据id删除 deleteById(Serializable)
removeById(Serializable)
根据id更改 updateById(T)
updateById(T)
根据id查询 selectById(Serializable)
getById(Serializable)
查询全部 selectList(null)
list()
,listObject()
,
不能listObject(null)
,需要强转类型条件查询 selectList(Warpper<T>)
listObjs(Warpper<T>)
分页查询 selectPage(E, null)
<E extends IPage<T>> page(E)
分页条件查询 selectPage(E, Warpper<T>)
<E extends IPage<T>> page(E , Wrapper<T>)
Boot整合Druid,总结整合过程
- 添加相应的Starter坐标,选中或手工添加
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.6</version> </dependency>
- 根据提供的配置格式,配置非默认值对应的配置项
通用方式
Druid整合专用配置spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC username: root password: 1234 type: com.alibaba.druid.pool.DruidDataSource #配置数据源类型
spring: datasource: druid: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC username: root password: 1234
Boot工程打包与运行
- 打包过程:直接使用maven的打包指令(过程包括所有测试,可以在idea中设置跳过测试,或者在测试方法中添加
@Ignore
表示不执行测试).打包是需要添加boot打包插件,才可以打包成一个可独立运行的jar包,运行通过java -jar
指令<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin>
- 打包插件: 如果没有打包插件使用maven打包指令,运行后会报
***.jar没有主清单属性
错误,- 对比,有boot-maven插件,打包时会打包更多的东西,如:项目所依赖的包,类加载器工具等
MANIFEST文件也配置有所不同,使用插件打包主要多配置了两个,配置了启动类与主运行类
- 对比,有boot-maven插件,打包时会打包更多的东西,如:项目所依赖的包,类加载器工具等