Spring Boot2.x-09 基于Spring Boot 2.1.2 + Mybatis使用自定义注解实现数据库切换

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: Spring Boot2.x-09 基于Spring Boot 2.1.2 + Mybatis使用自定义注解实现数据库切换

概述


之前总结过一篇基于Spring的 数据库切换的文章:Spring-基于Spring使用自定义注解及Aspect实现数据库切换 ,新的项目一般都直接采用SpringBoot开发了,那我们也用Spring Boot来整一版吧。


用到的东西包含: Spring Boot + Mybatis + Druid + MySql8 + lombok 等


鉴于我们是整合了Spring Boot +Mybatis , 不清楚如何整合的可以先看下

Spring Boot2.x-07Spring Boot2.1.2整合Mybatis


场景说明:读写分离


简单说下适用场景【读写分离】:数据库切换通常情况是用在项目中存在主从数据库的情况,为了减轻主库的压力,因为主从是同步的,所以读的操作我们直接取从库的数据,主库只负责写的操作。从库可以使多个,当然了主库也可以是多个,看项目架构。 这个同多数据源还是有差别的,如何支持多数据源,后面单独开篇介绍下。


废话不多说,直接撸起来吧


操作步骤


核心还是重写Spring的AbstractRoutingDataSource抽象类的determineCurrentLookupKey方法。


工程结构


20190202002050252.png


Step1 自定义注解


这里我们先约定,自定义注解只能标注在方法上,如果需要也能标注在类上(因为后面的判断会有Aspect判断会所不同)请参考 Spring-基于Spring使用自定义注解及Aspect实现数据库切换

package com.artisan.annotation;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import com.artisan.config.DataSources;
/**
 * 
 *    自定义注解,用于切换数据源,默认MASTER_DB
 * @author yangshangwei
 *
 */
@Documented
@Retention(RUNTIME)
@Target({ METHOD })
public @interface RouteDataSource {
  String value() default DataSources.MASTER_DB;
}


Step2 数据源定义

为了方便能够注解引用,直接用接口吧

package com.artisan.config;
/**
 *   数据源列表
 * @author yangshangwei
 *
 */
public interface DataSources {
  String MASTER_DB = "masterDB";
    String SLAVE_DB = "slaveDB";
}


Step3 配置文件配置数据源

我们这里采用application.yml ,注意前缀,后面要用。

# datasource  Master   前缀为自定义的datasource-master
spring:
  datasource-master:
    driver-class-name: com.mysql.cj.jdbc.Driver # JDBC连接Mysql6以上com.mysql.cj.jdbc.Driver (服务端为Mysql8)
    url: jdbc:mysql://localhost:3306/master?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false
    username: root
    password: root
# datasource Replication 前缀为自定义的datasource-slave
  datasource-slave: 
    driver-class-name: com.mysql.cj.jdbc.Driver # JDBC连接Mysql6以上com.mysql.cj.jdbc.Driver  (服务端为Mysql8)
    url: jdbc:mysql://localhost:3306/slave?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false
    username: root
    password: root


Step4 数据源实例化DatasourceConfig


通过@Configuration标注为配置类。被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。


application.yml中定义的前缀,别搞错了。

package com.artisan.config;
import javax.sql.DataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.druid.pool.DruidDataSource;
@Configuration
public class DatasourceConfig {
  //destroy-method="close":当数据库连接不使用的时候,将该连接重新放到数据池中
    @Bean(name=DataSources.MASTER_DB,destroyMethod="close")
    @ConfigurationProperties(prefix = "spring.datasource-master")
    public DataSource dataSource() {
      // 创建数据源
        return DataSourceBuilder.create().type(DruidDataSource.class).build();
    }
    @Bean(name=DataSources.SLAVE_DB,destroyMethod="close")
    @ConfigurationProperties(prefix = "spring.datasource-slave")
    public DataSource dataSourceSlave() {
      // 创建数据源
        return DataSourceBuilder.create().type(DruidDataSource.class).build();
    }
}


Step5 Mybatis中配置成动态数据源


@Configuration 功能不多说了,如上。


@MapperScan 通过使用@MapperScan可以指定要扫描的Mapper类的包的路径,当然了也可以在Mapper接口上声明@Mapper , 当然是@MapperScan更方便了。


内部@Bean用到了DynamicDataSource 继承自AbstractRoutingDataSource,就是我们刚开始说的核心


20190202010417418.png

package com.artisan.config;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
@Configuration
@MapperScan(basePackages = { "com.artisan.dao" }) // 扫描的mybatis接口类的包名
public class MybatisConfig {
  @Autowired
  @Qualifier(DataSources.MASTER_DB)
  private DataSource masterDB;
  @Autowired
  @Qualifier(DataSources.SLAVE_DB)
  private DataSource slaveDB;
  /**
   * 动态数据源
   */
  @Bean(name = "dynamicDataSource")
  public DataSource dynamicDataSource() {
    DynamicDataSource dynamicDataSource = new DynamicDataSource();
    // 默认数据源
    dynamicDataSource.setDefaultTargetDataSource(masterDB);
    // 配置多数据源
    Map<Object, Object> dataSourceMap = new HashMap<Object, Object>();
    dataSourceMap.put(DataSources.MASTER_DB, masterDB);
    dataSourceMap.put(DataSources.SLAVE_DB, slaveDB);
    dynamicDataSource.setTargetDataSources(dataSourceMap);
    return dynamicDataSource;
  }
  @Bean
  @ConfigurationProperties(prefix = "mybatis")
  public SqlSessionFactoryBean sqlSessionFactoryBean() throws Exception {
    SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
    // 配置数据源,关键配置
    sqlSessionFactoryBean.setDataSource(dynamicDataSource());
    // 解决配置到配置文件中通过*配置找不到mapper文件的问题。 如果不设置这一行,在配置文件中,只能使用数组的方式一个个的罗列出来,并且要指定具体的文件名
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
    return sqlSessionFactoryBean;
  }
}

application.yml配置文件中新增mybatis的如下配置

# mybatis 
mybatis:
  # 映射文件的路径 , 这个切换数据源的场景下不能配置 * 通配符,有多个 逗号隔开,继续跟 classpath:mapper/XXX
  # mapper-locations: classpath:mapper/ArtisanMapper.xml  
  # 在MybatisConfig.java#sqlSessionFactoryBean方法中通过sqlSessionFactoryBean设置classpath:mapper/*.xml ,不然每次都要改这个地方,不好维护。
  # 类型别名包配置,只能指定具体的包,多个配置可以使用英文逗号隔开
  type-aliases-package: com.artisan.domain
  # Mybatis SQL语句控制台打印
  configuration: 
      log-impl: org.apache.ibatis.logging.stdout.StdOutImpl


Step6 ThreadLocal管理当前线程使用的数据源连接

package com.artisan.config;
import lombok.extern.slf4j.Slf4j;
/**
 * 
 * 使用ThreadLocal管理当前线程使用的数据源连接
 * 
 * @author yangshangwei
 *
 */
@Slf4j
public class DatasourceContextHolder {
  public static final String DEFAULT_DATASOURCE = DataSources.MASTER_DB;
  private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
  /**
   * 设置数据源
   * @param dbType
   */
  public static void setDB(String dbType) {
    contextHolder.set(dbType);
    log.info("切换到数据源{}", dbType);
  }
  /**
   * 获取数据源
   */
  public static String getDB() {
    return contextHolder.get();
  }
  /**
   * 清除数据源
   */
  public static void clearDB() {
    contextHolder.remove();
  }
}


Step7 切面

通过Aspect 来处理自定义注解的横切逻辑。

package com.artisan.aspect;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import com.artisan.annotation.RouteDataSource;
import com.artisan.config.DatasourceContextHolder;
import java.lang.reflect.Method;
/**
 * 通过切面对自定义切库注解的方法进行拦截,动态的选择数据源
 * 
 * @author yangshangwei
 *
 */
@Slf4j
@Aspect
@Component
public class DynamicDataSourceAspect {
  /**
   * 前置增强,方法执行前,通过JoinPoint访问连接点上下文的信息
   * 
   * @param joinPoint
   */
  @Before("@annotation(com.artisan.annotation.RouteDataSource)")
  public void beforeSwitchDataSource(JoinPoint joinPoint) {
    // 获取连接点的方法签名对象
    MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
    // 获取方法
    Method method = methodSignature.getMethod();
    // 设置默认的数据源为Master,防止切库出现异常执行失败的情况
    String dataSource = DatasourceContextHolder.DEFAULT_DATASOURCE;
    // 判断方法上是否标注了@RouteDataSource
    if (method.isAnnotationPresent(RouteDataSource.class)) {
      RouteDataSource routeDataSource = method.getDeclaredAnnotation(RouteDataSource.class);
      // 获取@RouteDataSource上的value的值
      dataSource = routeDataSource.value();
    }
    // 设置数据源
    DatasourceContextHolder.setDB(dataSource);
    log.info("setDB {}", dataSource);
  }
  /**
   * 后置增强,清空DatasourceContextHolder,防止threadLocal误用带来的内存泄露
   */
  @After("@annotation(com.artisan.annotation.RouteDataSource)")
  public void afterSwitchDataSource() {
    // 方法执行完成后,清除threadlocal中持有的database
    DatasourceContextHolder.clearDB();
    log.info("清空DatasourceContextHolder...");
  }
  /**
  @Before("@annotation(com.artisan.annotation.RouteDataSource)")
  public void beforeSwitchDataSource(JoinPoint point) {
    // 获得当前访问的class
    Class<?> className = point.getTarget().getClass();
    // 获得访问的方法名
    String methodName = point.getSignature().getName();
    // 得到方法的参数的类型
    Class[] argClass = ((MethodSignature) point.getSignature()).getParameterTypes();
    String dataSource = DatasourceContextHolder.DEFAULT_DATASOURCE;
    try {
      // 得到访问的方法对象
      Method method = className.getMethod(methodName, argClass);
      // 判断是否存在@DS注解
      if (method.isAnnotationPresent(RouteDataSource.class)) {
        RouteDataSource annotation = method.getAnnotation(RouteDataSource.class);
        // 取出注解中的数据源名
        dataSource = annotation.value();
      }
    } catch (Exception e) {
      log.error("routing datasource exception, " + methodName, e);
    }
    // 切换数据源
    DatasourceContextHolder.setDB(dataSource);
  }
  **/
}


Step 8 核心方法,重写AbstractRoutingDataSource#determineCurrentLookupKey


根据上面的AOP拦截,通过DatasourceContextHolder.getDB()动态的取出在切面里设置(DatasourceContextHolder.setDB(dataSource))的数据源即可。

package com.artisan.config;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource{
  @Override
    protected Object determineCurrentLookupKey() {
        log.info("数据源为{}", DatasourceContextHolder.getDB());
        return DatasourceContextHolder.getDB();
    }
}


测试

库表数据

Master:

-- ----------------------------
-- Table structure for artisan
-- ----------------------------
DROP TABLE IF EXISTS `artisan`;
CREATE TABLE `artisan` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `sex` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of artisan
-- ----------------------------
INSERT INTO `artisan` VALUES ('1', 'master', '女');
INSERT INTO `artisan` VALUES ('2', 'master2', '男');


Slave:

-- ----------------------------
-- Table structure for artisan
-- ----------------------------
DROP TABLE IF EXISTS `artisan`;
CREATE TABLE `artisan` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `sex` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of artisan
-- ----------------------------
INSERT INTO `artisan` VALUES ('1', 'replication1', '女');
INSERT INTO `artisan` VALUES ('2', 'replication2', '男');


Domain

package com.artisan.domain;
import lombok.Data;
@Data
public class Artisan {
  private Long  id ;
  private String name ;
  private String sex;
}


Dao

package com.artisan.dao;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import com.artisan.domain.Artisan;
/**
 * 
 * @author yangshangwei
 *  
 * 增加@Mapper这个注解之后,Spring 启动时会自动扫描该接口,这样就可以在需要使用时直接注入 Mapper 了
 * 
 * MybatisConfig中标注了@MapperScan , 所以这里的@Mapper不加也行
 */
@Mapper
public interface ArtisanMapper {
  Artisan selectArtisanById(@Param("id") int id );
}



对应的sql映射文件 ,当然了也可以使用@Select注解的方式,更简便。

<?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接口和XML文件关联的时候, namespace的值就需要配置成接口的全限定名称 -->
<mapper namespace="com.artisan.dao.ArtisanMapper">
  <select id="selectArtisanById"  resultType="Artisan"> 
    select id , name ,sex from artisan where id= #{id}
  </select>
</mapper>


Service

接口及实现类

忽略这个方法名,忘改了。。。。事实上是根据Id获取某个Artisan.

package com.artisan.service;
import com.artisan.domain.Artisan;
public interface ArtisanService {
  Artisan getArtisanListFromMaster(int id);
  Artisan getArtisanListFromSlave(int id);
}


实现类

通过自定义注解设置主从库 ,默认是主库,@RouteDataSource(DataSources.MASTER_DB)可以省略

package com.artisan.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.artisan.annotation.RouteDataSource;
import com.artisan.config.DataSources;
import com.artisan.dao.ArtisanMapper;
import com.artisan.domain.Artisan;
import com.artisan.service.ArtisanService;
@Service
public class ArtisanServiceImpl implements ArtisanService {
  @Autowired
  private ArtisanMapper artisanMapper;
  @Override
  @RouteDataSource(DataSources.MASTER_DB)
  public Artisan getArtisanListFromMaster(int id) {
    return artisanMapper.selectArtisanById(id);
  }
  @Override
  @RouteDataSource(DataSources.SLAVE_DB)
  public Artisan getArtisanListFromSlave(int id) {
    return artisanMapper.selectArtisanById(id);
  }
}


Controller

package com.artisan.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.artisan.domain.Artisan;
import com.artisan.service.ArtisanService;
@RestController
public class ArtisanController {
  @Autowired
  private ArtisanService artisanService ;
  @GetMapping("/getDataFromMaster")
  public Artisan getDataFromMaster(int id) {
    return artisanService.getArtisanListFromMaster(id);
  }
  @GetMapping("/getDataFromRep")
  public Artisan getDataFromRep(int id) {
    return artisanService.getArtisanListFromSlave(id);
  }
}


启动Spring Boot 工程


为了验证功能,我们从主从库均是查询操作吧。

访问主库:

http://localhost:8080/getDataFromMaster?id=1

20190202012741628.png

访问从库:

http://localhost:8080/getDataFromRep?id=2

20190202012808483.png

为了方便用application.properties的童鞋,代码如下,验证通过

#master
spring.datasource-master.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource-master.url=jdbc:mysql://localhost:3306/master?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false
spring.datasource-master.username=root
spring.datasource-master.password=root
spring.datasource-master.type=com.alibaba.druid.pool.DruidDataSource
#slave
spring.datasource-slave.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource-slave.url=jdbc:mysql://localhost:3306/slave?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false
spring.datasource-slave.username=root
spring.datasource-slave.password=root
spring.datasource-slave.type=com.alibaba.druid.pool.DruidDataSource
#mybatis 
#mybatis.mapper-locations=classpath:mapper/ArtisanMapper.xml
mybatis.type-aliases-package=com.artisan.domain


pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="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.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.2.RELEASE</version>
    <relativePath /> <!-- lookup parent from repository -->
  </parent>
  <groupId>com.artisan</groupId>
  <artifactId>RoutingDataSource</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>RoutingDataSource</name>
  <description>Artisan </description>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>1.3.2</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-configuration-processor</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid-spring-boot-starter</artifactId>
      <version>1.1.10</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <optional>true</optional>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>



代码

https://github.com/yangshangwei/RoutingDataSource


相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
打赏
0
0
0
0
99
分享
相关文章
Spring MVC常用的注解
@RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中 的所有响应请求的方法都是以该地址作为父路径。 @RequestBody:注解实现接收http请求的json数据,将json转换为java对象。 @ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。 @Controller:控制器的注解,表示是表现层,不能用用别的注解代替 @RestController : 组合注解 @Conntroller + @ResponseBody @GetMapping , @PostMapping , @Put
Spring Boot的核心注解是哪个?他由哪几个注解组成的?
Spring Boot的核心注解是@SpringBootApplication , 他由几个注解组成 : ● @SpringBootConfiguration: 组合了- @Configuration注解,实现配置文件的功能; ● @EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项 ● @ComponentScan:Spring组件扫描
SpringBoot+@Async注解一起用,速度提升
本文介绍了异步调用在高并发Web应用性能优化中的重要性,对比了同步与异步调用的区别。同步调用按顺序执行,每一步需等待上一步完成;而异步调用无需等待,可提升效率。通过Spring Boot示例,使用@Async注解实现异步任务,并借助Future对象处理异步回调,有效减少程序运行时间。
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于注解的整合
本文介绍了Spring Boot集成MyBatis的两种方式:基于XML和注解的形式。重点讲解了注解方式,包括@Select、@Insert、@Update、@Delete等常用注解的使用方法,以及多参数时@Param注解的应用。同时,针对字段映射不一致的问题,提供了@Results和@ResultMap的解决方案。文章还提到实际项目中常结合XML与注解的优点,灵活使用两者以提高开发效率,并附带课程源码供下载学习。
27 0
|
2月前
|
SpringBoot:SpringBoot通过注解监测Controller接口
本文详细介绍了如何通过Spring Boot注解监测Controller接口,包括自定义注解、AOP切面的创建和使用以及具体的示例代码。通过这种方式,可以方便地在Controller方法执行前后添加日志记录、性能监控和异常处理逻辑,而无需修改方法本身的代码。这种方法不仅提高了代码的可维护性,还增强了系统的监控能力。希望本文能帮助您更好地理解和应用Spring Boot中的注解监测技术。
75 16
Java后端开发-使用springboot进行Mybatis连接数据库步骤
本文介绍了使用Java和IDEA进行数据库操作的详细步骤,涵盖从数据库准备到测试类编写及运行的全过程。主要内容包括: 1. **数据库准备**:创建数据库和表。 2. **查询数据库**:验证数据库是否可用。 3. **IDEA代码配置**:构建实体类并配置数据库连接。 4. **测试类编写**:编写并运行测试类以确保一切正常。
117 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和MyBatis Generator,使用逆向工程来自动生成Java代码,包括实体类、Mapper文件和Example文件,以提高开发效率。
257 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
|
6月前
|
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
166 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
本文详细讲解了如何整合Apache Shiro与Spring Boot项目,包括数据库准备、项目配置、实体类、Mapper、Service、Controller的创建和配置,以及Shiro的配置和使用。
1238 1
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
Soring Boot的起步依赖、启动流程、自动装配、常用的注解、Spring MVC的执行流程、对MVC的理解、RestFull风格、为什么service层要写接口、MyBatis的缓存机制、$和#有什么区别、resultType和resultMap区别、cookie和session的区别是什么?session的工作原理

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等