SpringBoot-Mybatis框架使用与源码解析
2018-08-04 22:29
941 查看
大家可以关注一下公众号“Java架构师秘籍” 纯干货绿色天然无污染
欢迎大家加Q群:230419550 学习交流讨论架构师进阶知识
1.SpringBoot-Mybatis使用
1)添加maven依赖
spring:
datasource:
url: jdbc:mysql://localhost:3306/test
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
mybatis:
mapper-locations: classpath:mapper/*.xml #注意:一定要对应mapper映射xml文件的所在路径
type-aliases-package: com.example.demo.mybatis # 注意:对应实体类的路径
3)在mapper/User.xml中添加SQL
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mybatis.IUser">
<select id="getUser" parameterType="int"
resultType="com.example.demo.mybatis.User">
SELECT *
FROM USER
WHERE id = #{userId}
</select>
</mapper>
4)添加IUser接口
public interface IUser {
public User getUser(int id);
}
5)添加User实体类
@Data
public class User {
private int id;
private String name;
private String dept;
private String phone;
private String website;
}
6)在Application中添加最重要的一环(注意:@MapperScan对应IUser所在路径)
@SpringBootApplicationbr/>@MapperScan("com.example.demo.mybatis")
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(SpringbootstudyApplication.class);
springApplication.run(args);
}
}
7)添加测试
@RunWith(SpringRunner.class)[url=mailto:br/>@SpringBootTest(classes=SpringbootstudyApplication.class)
@SpringBootTest(classes=SpringbootstudyApplication.class)
测试成功
2.写在源码分析之前
3.分析mybatis-spring-boot-starter依赖
<project xmlns="[url=http://maven.apache.org/POM/4.0.0]http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot</artifactId>
<version>1.1.1</version>
</parent>
<artifactId>mybatis-spring-boot-starter</artifactId>
<name>mybatis-spring-boot-starter</name>
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-autoconfigure</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
</project>
可以看到,主要就是引入mybatis-spring-boot-autoconfigure,我们来看下这个jar包的结构
https://img-blog.csdn.net/20180803113940659?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI2MzIzMzIz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70
结构很简单,总共只有三个类,感觉MybatisAutoConfiguration应该是很重要的类。
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
又是熟悉的味道,MybatisAutoConfiguration被对应到EnableAutoConfiguration,那么MybatisAutoConfiguration类会在SpringBoot项目启动的时候被注入到Spring容器中。原因在这里不再赘述,读者可以看下笔者之前的博客,有详细介绍。
4.分析MybatisAutoConfiguration(SqlSessionFactory的创建)
@Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })[url=mailto:br/>@ConditionalOnBean(DataSource.class)
@ConditionalOnBean(DataSource.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@ConditionalOnMissingBean
@ConditionalOnMissingBean
// 同样还是通过SqlSessionFactoryBean来创建SqlSessionFactory
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setVfs(SpringBootVFS.class);
if (StringUtils.hasText(this.properties.getConfigLocation())) {
factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
}
factory.setConfiguration(properties.getConfiguration());
if (!ObjectUtils.isEmpty(this.interceptors)) {
factory.setPlugins(this.interceptors);
}
if (this.databaseIdProvider != null) {
factory.setDatabaseIdProvider(this.databaseIdProvider);
}
if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
}
if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
}
if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
// 就是我们在application.yml中配置的mybatis.mapper-locations: classpath:mapper/*.xml
factory.setMapperLocations(this.properties.resolveMapperLocations());
}
}
...
可知:当前类被添加了@Configuration注解,里面的所有被@Bean注解的方法返回值都会被注入到Spring容器中
5.DataSource在哪里被创建?
09:06:36.075 [main] DEBUG o.s.c.a.ConfigurationClassBeanDefinitionReader - Registered bean definition for imported class 'org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Tomcat'
09:06:36.075 [main] DEBUG o.s.c.a.ConfigurationClassBeanDefinitionReader - Registering bean definition for @Bean method org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Tomcat.dataSource()
看到在org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration中,有一个被注入了@Bean的方法dataSource(),感觉这个应该就是创建DataSource的方法了,我们进入该类看下:
abstract class DataSourceConfiguration {[url=mailto:br/>...
@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
...
@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
static class Tomcat extends DataSourceConfiguration {
6.@MapperScan()注解的分析(MapperFactoryBean的注入)
@Retention(RetentionPolicy.RUNTIME)[url=mailto:br/>@Target(ElementType.TYPE)
@Target(ElementType.TYPE)
@Import(MapperScannerRegistrar.class)//重点在这里,注入了MapperScannerRegistrar类
@Import(MapperScannerRegistrar.class)//重点在这里,注入了MapperScannerRegistrar类
1)MapperScannerRegistrar分析
// 注意当前类实现了ImportBeanDefinitionRegistrar接口,有关于ImportBeanDefinitionRegistrar的作用不再赘述,
// 读者可自行查看。
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
}
}
//ClassPathMapperScanner.doScan()
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
// 这个方法,会扫描包路径basePackages下的所有类,并生成BeanDefinitionHolder,注入到Spring中
// 在当前场景下,会扫描到IUser接口,并注入Spring中
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
}
//processBeanDefinitions()
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
// 1.获得IUser对应的BeanDefinitionHolder
definition = (GenericBeanDefinition) holder.getBeanDefinition();
}
[b]## 总结:[/b]通过上述分析,我们知道,ClassPathMapperScanner.doScan() 方法执行后,便会将IUser对应的BeanDefinitionHolder注入到Spring中;
前言:
现在微服务架构基本已经成为一种架构正确了,而SpringBoot技术也已经被应用在各个项目中。 SpringBoot不仅仅那些传统的好处,更多是可以与其他组件进行结合,使用户可以更方便的使用。比如SpringBoot-Kafka、SpringBoot-Mybatis、SpringBoot-RabbitMQ等等。 本文,分析一下SpringBoot-Mybatis的使用及其源码,让读者可以更深入的了解下SpringBoot是如何帮我们简化配置,节约开发时间的。
欢迎大家加Q群:230419550 学习交流讨论架构师进阶知识
1.SpringBoot-Mybatis使用
1)添加maven依赖
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.3.RELEASE</version> </parent> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.32</version> </dependency> **2)在application.yml中添加DataSource配置**
spring:
datasource:
url: jdbc:mysql://localhost:3306/test
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
mybatis:
mapper-locations: classpath:mapper/*.xml #注意:一定要对应mapper映射xml文件的所在路径
type-aliases-package: com.example.demo.mybatis # 注意:对应实体类的路径
3)在mapper/User.xml中添加SQL
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mybatis.IUser">
<select id="getUser" parameterType="int"
resultType="com.example.demo.mybatis.User">
SELECT *
FROM USER
WHERE id = #{userId}
</select>
</mapper>
4)添加IUser接口
public interface IUser {
public User getUser(int id);
}
5)添加User实体类
@Data
public class User {
private int id;
private String name;
private String dept;
private String phone;
private String website;
}
6)在Application中添加最重要的一环(注意:@MapperScan对应IUser所在路径)
@SpringBootApplicationbr/>@MapperScan("com.example.demo.mybatis")
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(SpringbootstudyApplication.class);
springApplication.run(args);
}
}
7)添加测试
@RunWith(SpringRunner.class)[url=mailto:br/>@SpringBootTest(classes=SpringbootstudyApplication.class)
@SpringBootTest(classes=SpringbootstudyApplication.class)
测试成功
2.写在源码分析之前
SpringBoot一般以配置居多,各种类之间的关系错综复杂。我们在分析SpringBoot的分析中,一定要抓住核心点。 比如当前Mybatis的分析,结合Spring-Mybatis来看,我们应该主动创建DataSource、SqlSessionFactoryBean、MapperFactoryBean,并且把这些bean添加到Spring容器中。但是从当前的使用配置来看,这些bean我们都没有显示声明,没有像Spring-Mybatis使用的时候那样显示声明在beans.xml中,所以一定是SpringBoot帮我们做了这些工作,我们的重点要放在SpringBoot如何帮我们声明这些bean。 仔细回想一下,SpringBoot需要我们做的的工作主要就是: * 添加mybatis-spring-boot-starter依赖 * 在Application上添加@MapperScan注解,并把IUser所在的包路径添加到注解中 所以,我们就主要从这两面入手,来剖析下SpringBoot-Mybatis框架
3.分析mybatis-spring-boot-starter依赖
我们在项目中引入该依赖,下面我们看下这个依赖的主要内容
<project xmlns="[url=http://maven.apache.org/POM/4.0.0]http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot</artifactId>
<version>1.1.1</version>
</parent>
<artifactId>mybatis-spring-boot-starter</artifactId>
<name>mybatis-spring-boot-starter</name>
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-autoconfigure</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
</project>
可以看到,主要就是引入mybatis-spring-boot-autoconfigure,我们来看下这个jar包的结构
https://img-blog.csdn.net/20180803113940659?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI2MzIzMzIz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70
结构很简单,总共只有三个类,感觉MybatisAutoConfiguration应该是很重要的类。
在META-INF中,我们又看到熟悉的配置spring.factories,我们在这里总能发现惊喜,打开这个文件,可以看到
Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
又是熟悉的味道,MybatisAutoConfiguration被对应到EnableAutoConfiguration,那么MybatisAutoConfiguration类会在SpringBoot项目启动的时候被注入到Spring容器中。原因在这里不再赘述,读者可以看下笔者之前的博客,有详细介绍。
那么下面我们就来看下MybatisAutoConfiguration这个类
4.分析MybatisAutoConfiguration(SqlSessionFactory的创建)
@Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })[url=mailto:br/>@ConditionalOnBean(DataSource.class)
@ConditionalOnBean(DataSource.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@ConditionalOnMissingBean
@ConditionalOnMissingBean
// 同样还是通过SqlSessionFactoryBean来创建SqlSessionFactory
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setVfs(SpringBootVFS.class);
if (StringUtils.hasText(this.properties.getConfigLocation())) {
factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
}
factory.setConfiguration(properties.getConfiguration());
if (!ObjectUtils.isEmpty(this.interceptors)) {
factory.setPlugins(this.interceptors);
}
if (this.databaseIdProvider != null) {
factory.setDatabaseIdProvider(this.databaseIdProvider);
}
if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
}
if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
}
if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
// 就是我们在application.yml中配置的mybatis.mapper-locations: classpath:mapper/*.xml
factory.setMapperLocations(this.properties.resolveMapperLocations());
}
return factory.getObject();
}
...
可知:当前类被添加了@Configuration注解,里面的所有被@Bean注解的方法返回值都会被注入到Spring容器中
在这里,我们可到熟悉的SqlSessionFactory,正是Mybatis需要的组件之一,同样还是通过SqlSessionFactoryBean来创建,具体创建过程笔者不再赘述,读者可参考上一篇 Spring-Mybatis文章 总结:在这里我们看到了SqlSessionFactory被注入到容器中。 疑问:可以看到,创建SqlSessionFactory的方法,入参为DataSource,那么在方法调用之前,DataSource应该已经被注入到容器中了,那么DataSource是在什么时候在哪里被注入的呢?
5.DataSource在哪里被创建?
我们没有主动创建DataSource的bean,那么应该也是SpringBoot帮我们主动创建了,那么究竟是在哪里创建的呢? 我们可以开启日志DEBUG模式,在bean创建的过程中,都会打印相应的日志,在日志中我们搜索DataSource,可以看到以下内容
09:06:36.075 [main] DEBUG o.s.c.a.ConfigurationClassBeanDefinitionReader - Registered bean definition for imported class 'org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Tomcat'
09:06:36.075 [main] DEBUG o.s.c.a.ConfigurationClassBeanDefinitionReader - Registering bean definition for @Bean method org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Tomcat.dataSource()
看到在org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration中,有一个被注入了@Bean的方法dataSource(),感觉这个应该就是创建DataSource的方法了,我们进入该类看下:
abstract class DataSourceConfiguration {[url=mailto:br/>...
@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
...
@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
static class Tomcat extends DataSourceConfiguration {
@Bean @ConfigurationProperties(prefix = "spring.datasource.tomcat") public org.apache.tomcat.jdbc.pool.DataSource dataSource( DataSourceProperties properties) { org.apache.tomcat.jdbc.pool.DataSource dataSource = createDataSource( properties, org.apache.tomcat.jdbc.pool.DataSource.class); DatabaseDriver databaseDriver = DatabaseDriver .fromJdbcUrl(properties.determineUrl()); String validationQuery = databaseDriver.getValidationQuery(); if (validationQuery != null) { dataSource.setTestOnBorrow(true); dataSource.setValidationQuery(validationQuery); } return dataSource; } } 在这里确实有关于 org.apache.tomcat.jdbc.pool.DataSource的创建,而且Tomcat类也符合上面的Condition条件 那么问题又来了,当前类DataSourceConfiguration只是一个抽象类,它是什么时候被引入的呢? 经过一番查找,我们看到在org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration类中有关于其创建,代码如下 @Configuration @Conditional(PooledDataSourceCondition.class) @ConditionalOnMissingBean({ DataSource.class, XADataSource.class }) @Import({ DataSourceConfiguration.Tomcat.class, DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Dbcp.class, DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class }) @SuppressWarnings("deprecation") protected static class PooledDataSourceConfiguration { } 直接使用@Import来引入DataSourceConfiguration.Tomcat 总结:到此为止,我们可以回答我们上文提出的问题了,DataSource是在DataSourceConfiguration类中被注入到Spring容器的;而DataSourceConfiguration是在DataSourceAutoConfiguration中被注入到Spring容器的。
6.@MapperScan()注解的分析(MapperFactoryBean的注入)
到目前为止,DataSource被注入到Spring中,SqlSessionFactory被注入到Spring中,还缺少MapperFactoryBean的注入 我们知道在@MapperScan()注解中,我们在注解value中添加了IUser所在的包路径,直觉上,MapperFactoryBean的注入应该跟该注解有关 **下面我们来看下该注解的内容:**
@Retention(RetentionPolicy.RUNTIME)[url=mailto:br/>@Target(ElementType.TYPE)
@Target(ElementType.TYPE)
@Import(MapperScannerRegistrar.class)//重点在这里,注入了MapperScannerRegistrar类
@Import(MapperScannerRegistrar.class)//重点在这里,注入了MapperScannerRegistrar类
1)MapperScannerRegistrar分析
// 注意当前类实现了ImportBeanDefinitionRegistrar接口,有关于ImportBeanDefinitionRegistrar的作用不再赘述,
// 读者可自行查看。
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName())); ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); ... scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef")); scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef")); List<String> basePackages = new ArrayList<String>(); for (String pkg : annoAttrs.getStringArray("value")) { if (StringUtils.hasText(pkg)) { basePackages.add(pkg); } } for (String pkg : annoAttrs.getStringArray("basePackages")) { if (StringUtils.hasText(pkg)) { basePackages.add(pkg); } } for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) { basePackages.add(ClassUtils.getPackageName(clazz)); } scanner.registerFilters(); // 重点看这里,实现在ClassPathMapperScanner.doScan() scanner.doScan(StringUtils.toStringArray(basePackages));
}
}
//ClassPathMapperScanner.doScan()
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
// 这个方法,会扫描包路径basePackages下的所有类,并生成BeanDefinitionHolder,注入到Spring中
// 在当前场景下,会扫描到IUser接口,并注入Spring中
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) { logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration."); } else { // 重要方法,下面继续观察 processBeanDefinitions(beanDefinitions); } return beanDefinitions;
}
//processBeanDefinitions()
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
// 1.获得IUser对应的BeanDefinitionHolder
definition = (GenericBeanDefinition) holder.getBeanDefinition();
... // 2.修改definition对应的Class // 看过Spring源码的都知道,getBean()返回的就是BeanDefinitionHolder中beanClass属性对应的实例 // 所以我们后面ac.getBean(IUser.class)的返回值也就是mapperFactoryBean的实例 definition.setBeanClass(this.mapperFactoryBean.getClass()); definition.getPropertyValues().add("addToConfig", this.addToConfig); ... if (!explicitFactoryUsed) { if (logger.isDebugEnabled()) { logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'."); } definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); } }
}
[b]## 总结:[/b]通过上述分析,我们知道,ClassPathMapperScanner.doScan() 方法执行后,便会将IUser对应的BeanDefinitionHolder注入到Spring中;
通过后续的processBeanDefinitions()方法,重新修改BeanDefinitionHolder的BeanClass属性值为mapperFactoryBean.class 又是熟悉的味道,MapperFactoryBean在这里被引入,然后在真正使用到的时候被创建对应的实例,而通过对Spring-Mybatis的分析可知,MapperFactoryBean真正返回的是IUser的代理类MapperProxy
总结:
1)DataSource在哪里被注入? 答:DataSourceAutoConfiguration类中被注入,默认值为org.apache.tomcat.jdbc.pool.DataSource 2)SqlSessionFactory在哪里被注入? 答:MybatisAutoConfiguration类中被注入 3)IUser等Mapper接口在哪里被注入? 答:@MapperScan注解引入的MapperScannerRegistrar中,会扫描用户给定的包路径,并将IUser对应的MapperFactoryBean注入到Spring中,真正使用IUser时,获取的MapperFactoryBean.getObject()返回值,也就是MapperProxy
相关文章推荐
- 使用myeclipse搭建SpringBoot框架,整合thymeleaf模板和mybatis
- 使用maven与MyEclipse整合ssm(Spring MVC、Spring、Mybatis)三大框架并实现用户注册(环境搭载+实例源码下载)
- (4)Spring Boot使用别的json解析框架【从零开始学Spring Boot】
- (3)spring boot如何使用第三方json解析框架
- springboot使用第三方的json解析框架fastjson
- mybatis源码解析-启动配置&使用spring启动配置(一)
- spring-boot+mybatis开发实战:如何在spring-boot中使用myabtis持久层框架
- 架构实战项目心得(七):使用SpringBoot+Dubbo+Mybatisplus+Oracle搭建后台项目框架(一)
- 架构实战项目心得(七):使用SpringBoot+Dubbo+Mybatisplus+Oracle搭建后台项目框架(二)
- 使用springboot+springsession实现分布式session以及源码解析
- SpringBoot 之 第三方Json解析框架FastJson的使用
- spring-boot+mybatis开发实战:如何在spring-boot中使用myabtis持久层框架
- spring boot 源码解析26-Liquibase使用及LiquibaseEndpoint解析
- 4. 使用别的json解析框架【从零开始学Spring Boot】
- 使用Spring Boot+MyBatis框架做查询操作
- 4. 使用别的json解析框架【从零开始学Spring Boot】
- springmvc mybatis 整合 框架源码 bootstrap html5 mysql oracle spring
- springmvc mybatis 整合 框架源码 bootstrap html5 mysql oracle spring
- zTree的调用设使用(跨两个系统,两类技术实现的项目案例SpringMVC+Spring+MyBatis和Struts2+Spring+ibatis框架组合)
- springmvc+mybatis+spring 整合 bootstrap html5 mysql oracle SSM框架源码 SSH maven