简介
Doris 是一款数据库,本文介绍 Spring Boot 如何整合 Doris,关于 Doris 部署,参考这篇这篇博客
整合
以一个简单的 RBAC 项目为例,用 Spring Boot 实现,数据库初始化脚本如下:
sql
-- =============================================
-- Doris RBAC Demo 数据库初始化脚本
-- =============================================
CREATE DATABASE IF NOT EXISTS rbac_demo;
USE rbac_demo;
-- 用户表
DROP TABLE IF EXISTS sys_user;
CREATE TABLE IF NOT EXISTS sys_user (
id BIGINT NOT NULL COMMENT '主键ID',
username VARCHAR(50) NOT NULL COMMENT '用户名',
password VARCHAR(200) NOT NULL COMMENT '密码',
email VARCHAR(100) DEFAULT '' COMMENT '邮箱',
status TINYINT DEFAULT 1 COMMENT '状态:0-禁用,1-启用',
create_time DATETIME COMMENT '创建时间',
update_time DATETIME COMMENT '更新时间'
)
DUPLICATE KEY(id)
DISTRIBUTED BY HASH(id) BUCKETS 10
PROPERTIES (
"replication_num" = "1"
);
-- 角色表
DROP TABLE IF EXISTS sys_role;
CREATE TABLE IF NOT EXISTS sys_role (
id BIGINT NOT NULL COMMENT '主键ID',
role_name VARCHAR(50) NOT NULL COMMENT '角色名称',
role_code VARCHAR(50) NOT NULL COMMENT '角色编码',
description VARCHAR(200) DEFAULT '' COMMENT '角色描述',
status TINYINT DEFAULT 1 COMMENT '状态:0-禁用,1-启用',
create_time DATETIME COMMENT '创建时间',
update_time DATETIME COMMENT '更新时间'
)
DUPLICATE KEY(id)
DISTRIBUTED BY HASH(id) BUCKETS 10
PROPERTIES (
"replication_num" = "1"
);
-- 权限表
DROP TABLE IF EXISTS sys_permission;
CREATE TABLE IF NOT EXISTS sys_permission (
id BIGINT NOT NULL COMMENT '主键ID',
permission_name VARCHAR(50) NOT NULL COMMENT '权限名称',
permission_code VARCHAR(100) NOT NULL COMMENT '权限编码,如 user:add、role:delete',
description VARCHAR(200) DEFAULT '' COMMENT '权限描述',
status TINYINT DEFAULT 1 COMMENT '状态:0-禁用,1-启用',
create_time DATETIME COMMENT '创建时间',
update_time DATETIME COMMENT '更新时间'
)
DUPLICATE KEY(id)
DISTRIBUTED BY HASH(id) BUCKETS 10
PROPERTIES (
"replication_num" = "1"
);
-- 用户角色关联表
DROP TABLE IF EXISTS sys_user_role;
CREATE TABLE IF NOT EXISTS sys_user_role (
id BIGINT NOT NULL COMMENT '主键ID',
user_id BIGINT NOT NULL COMMENT '用户ID',
role_id BIGINT NOT NULL COMMENT '角色ID'
)
DUPLICATE KEY(id)
DISTRIBUTED BY HASH(id) BUCKETS 10
PROPERTIES (
"replication_num" = "1"
);
-- 角色权限关联表
DROP TABLE IF EXISTS sys_role_permission;
CREATE TABLE IF NOT EXISTS sys_role_permission (
id BIGINT NOT NULL COMMENT '主键ID',
role_id BIGINT NOT NULL COMMENT '角色ID',
permission_id BIGINT NOT NULL COMMENT '权限ID'
)
DUPLICATE KEY(id)
DISTRIBUTED BY HASH(id) BUCKETS 10
PROPERTIES (
"replication_num" = "1"
);
-- =============================================
-- 初始化测试数据
-- =============================================
-- 插入演示权限
INSERT INTO sys_permission(id, permission_name, permission_code, description, status, create_time, update_time)
VALUES
(1, '用户查询', 'user:list', '查看用户列表', 1, NOW(), NOW()),
(2, '用户新增', 'user:add', '新增用户', 1, NOW(), NOW()),
(3, '用户编辑', 'user:edit', '编辑用户信息', 1, NOW(), NOW()),
(4, '用户删除', 'user:delete', '删除用户', 1, NOW(), NOW()),
(5, '角色查询', 'role:list', '查看角色列表', 1, NOW(), NOW()),
(6, '角色新增', 'role:add', '新增角色', 1, NOW(), NOW()),
(7, '角色编辑', 'role:edit', '编辑角色信息', 1, NOW(), NOW()),
(8, '角色删除', 'role:delete', '删除角色', 1, NOW(), NOW());
-- 插入演示角色
INSERT INTO sys_role(id, role_name, role_code, description, status, create_time, update_time)
VALUES
(1, '超级管理员', 'ADMIN', '拥有所有权限', 1, NOW(), NOW()),
(2, '普通用户', 'USER', '普通用户权限', 1, NOW(), NOW()),
(3, '访客', 'GUEST', '仅有查看权限', 1, NOW(), NOW());
-- 给角色分配权限
-- 超级管理员拥有全部权限
INSERT INTO sys_role_permission(id, role_id, permission_id)
VALUES
(1, 1, 1), (2, 1, 2), (3, 1, 3), (4, 1, 4),
(5, 1, 5), (6, 1, 6), (7, 1, 7), (8, 1, 8);
-- 普通用户有用户管理和角色查看权限
INSERT INTO sys_role_permission(id, role_id, permission_id)
VALUES
(9, 2, 1), (10, 2, 2), (11, 2, 3), (12, 2, 5);
-- 访客只有查看权限
INSERT INTO sys_role_permission(id, role_id, permission_id)
VALUES
(13, 3, 1), (14, 3, 5);
-- 插入演示用户
INSERT INTO sys_user(id, username, password, email, status, create_time, update_time)
VALUES
(1, 'admin', '123456', 'admin@example.com', 1, NOW(), NOW()),
(2, 'zhangsan', '123456', 'zhangsan@example.com', 1, NOW(), NOW()),
(3, 'lisi', '123456', 'lisi@example.com', 1, NOW(), NOW());
-- 给用户分配角色
INSERT INTO sys_user_role(id, user_id, role_id)
VALUES
(1, 1, 1),
(2, 2, 2),
(3, 3, 3);
pom.xml 文件如下,其实整合 Doris,直接用 MySQL 的驱动和依赖就行,DAO 框架就用 MyBatis-Plus
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>
<!-- Spring Boot 父工程,统一管理依赖版本和插件配置 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.12</version>
<relativePath/>
</parent>
<!-- 项目坐标 -->
<groupId>com.hezy</groupId>
<artifactId>doris_rbac_demo</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 全局属性配置 -->
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- Spring Boot Web 启动器:内嵌 Tomcat,支持 Spring MVC RESTful 接口 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MySQL JDBC 驱动:连接后端数据库(运行时必需) -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Druid 连接池:数据库连接池管理,支持监控统计 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
<!-- Lombok:简化 Java POJO 代码(@Data/@Slf4j 等注解) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- MyBatis-Plus:增强版 ORM 框架,提供通用 CRUD、分页等功能 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.16</version>
</dependency>
<!-- Spring Boot 测试框架:单元测试和集成测试支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Hutool 工具包:提供丰富的 Java 工具类(字符串、日期、加密等) -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.6</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Spring Boot Maven 插件:打包可执行 jar,支持 spring-boot:run -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
配置文件如下,与 MySQL 不同的是 Doris 的端口,默认为 9030
yml
# ==================== 服务端口配置 ====================
server:
port: 8088
# ==================== 数据源 & 连接池配置 ====================
spring:
datasource:
# MySQL JDBC 驱动(使用 com.mysql.cj 新版本驱动类)
driver-class-name: com.mysql.cj.jdbc.Driver
# 数据库连接 URL(useUnicode/utf-8:支持中文,useSSL:关闭 SSL,serverTimezone:时区设为东八区)
url: jdbc:mysql://192.168.101.11:9030/rbac_demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
username: root
password:
# 使用 Druid 连接池
type: com.alibaba.druid.pool.DruidDataSource
druid:
# 连接池初始化大小
initial-size: 2
# 最小空闲连接数
min-idle: 2
# 最大活跃连接数
max-active: 10
# 连接有效性检测 SQL
validation-query: SELECT 1
# ==================== MyBatis-Plus 配置 ====================
mybatis-plus:
configuration:
# SQL 日志输出到控制台(开发调试用,生产环境建议关闭)
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 自动驼峰命名转换(数据库下划线字段 → Java 驼峰属性)
map-underscore-to-camel-case: true
# Mapper XML 文件路径
mapper-locations: classpath:mapper/*.xml
global-config:
db-config:
# 主键生成策略:使用雪花算法生成分布式 ID
id-type: assign_id
到这就整合好了,其实就将 Doris 当作 MySQL 就行,后面就是实现 RBAC,很简单,以 User 为例,其他代码不再赘述
User 实体类
java
package com.hezy.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 用户实体,映射 sys_user 表
*
* @author hezy
*/
@Data
@TableName("sys_user")
public class User {
/** 主键ID,使用 MyBatis-Plus 雪花算法自动生成 */
@TableId(type = IdType.ASSIGN_ID)
private Long id;
/** 用户名 */
private String username;
/** 密码 */
private String password;
/** 邮箱 */
private String email;
/** 状态:0-禁用,1-启用 */
private Integer status;
/** 创建时间 */
private LocalDateTime createTime;
/** 更新时间 */
private LocalDateTime updateTime;
}
UserMapper,继承 BaseMapper
java
package com.hezy.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hezy.entity.User;
import org.apache.ibatis.annotations.Mapper;
/**
* 用户表 Mapper
*
* @author hezy
*/
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
UserService,继承 IService
java
package com.hezy.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hezy.entity.User;
/**
* 用户 Service 接口
*
* @author hezy
*/
public interface UserService extends IService<User> {
}
UserServiceImpl,实现接口,Service 增强,MyBatis-Plus 的特性
java
package com.hezy.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hezy.entity.User;
import com.hezy.mapper.UserMapper;
import com.hezy.service.UserService;
import org.springframework.stereotype.Service;
/**
* 用户 Service 实现
*
* @author hezy
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
UserController,用户接口
java
package com.hezy.controller;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hezy.entity.Role;
import com.hezy.entity.User;
import com.hezy.entity.UserRole;
import com.hezy.mapper.RoleMapper;
import com.hezy.mapper.UserRoleMapper;
import com.hezy.service.UserService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 用户管理 Controller
* <p>
* 提供用户 CRUD 以及为用户分配/查询角色的接口。
* 角色分配采用"先删后插"策略,即每次分配都会清除旧的关联关系再写入新的。
* </p>
*
* @author hezy
*/
@RestController
@RequestMapping("/users")
public class UserController {
@Resource
private UserService userService;
@Resource
private UserRoleMapper userRoleMapper;
@Resource
private RoleMapper roleMapper;
/**
* 分页查询用户,支持按用户名/邮箱模糊搜索
*
* @param page 页码,默认 1
* @param size 每页条数,默认 10
* @param keyword 搜索关键字(可选),匹配用户名或邮箱
* @return total + records 分页结果
*/
@GetMapping
public Map<String, Object> page(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size,
@RequestParam(required = false) String keyword) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
if (StrUtil.isNotBlank(keyword)) {
wrapper.like(User::getUsername, keyword).or().like(User::getEmail, keyword);
}
wrapper.orderByDesc(User::getCreateTime);
Page<User> result = userService.page(new Page<>(page, size), wrapper);
return Map.of("total", result.getTotal(), "records", result.getRecords());
}
/**
* 新增用户
*
* @param user 用户信息,id 由雪花算法自动生成
*/
@PostMapping
public String create(@RequestBody User user) {
user.setCreateTime(LocalDateTime.now());
user.setUpdateTime(LocalDateTime.now());
userService.save(user);
return "ok";
}
/**
* 根据 ID 更新用户信息
*
* @param id 用户ID
* @param user 要更新的字段
*/
@PutMapping("/{id}")
public String update(@PathVariable Long id, @RequestBody User user) {
user.setId(id);
user.setUpdateTime(LocalDateTime.now());
userService.updateById(user);
return "ok";
}
/**
* 根据 ID 删除用户
*
* @param id 用户ID
*/
@DeleteMapping("/{id}")
public String delete(@PathVariable Long id) {
userService.removeById(id);
return "ok";
}
/**
* 为用户分配角色(先清除旧关联,再写入新关联)
*
* @param userId 用户ID
* @param roleIds 要分配的角色ID列表
*/
@PostMapping("/{userId}/roles")
public String assignRoles(@PathVariable Long userId, @RequestBody List<Long> roleIds) {
// 先删除用户原有的所有角色关联
userRoleMapper.delete(new QueryWrapper<UserRole>().eq("user_id", userId));
// 逐条插入新的角色关联
for (Long roleId : roleIds) {
UserRole ur = new UserRole();
ur.setUserId(userId);
ur.setRoleId(roleId);
userRoleMapper.insert(ur);
}
return "ok";
}
/**
* 查询用户当前拥有的角色列表
*
* @param userId 用户ID
* @return 角色列表
*/
@GetMapping("/{userId}/roles")
public List<Role> getUserRoles(@PathVariable Long userId) {
List<UserRole> userRoles = userRoleMapper.selectList(
new QueryWrapper<UserRole>().eq("user_id", userId));
if (userRoles.isEmpty()) {
return List.of();
}
List<Long> roleIds = userRoles.stream()
.map(UserRole::getRoleId)
.collect(Collectors.toList());
return roleMapper.selectBatchIds(roleIds);
}
}
测试
启动前,先在 Doris 数据库里,将初始化脚本执行了

启动测试,没有报错,如果 Doris 配置写歪了,或者初始化脚本没执行,没对应数据库,都会报错

调用接口,查询成功,没得问题
