MySQL数据权限的实现详情
知识点掌握了,还需要不断练习才能熟练运用。下面golang学习网给大家带来一个数据库开发实战,手把手教大家学习《MySQL数据权限的实现详情》,在实现功能的过程中也带大家重新温习相关知识点,温故而知新,回头看看说不定又有不一样的感悟!
数据权限模型
上篇文章的数据模型是基于传统的RBAC模型来设计的,由于我们这里的应用场景不一样,所以这里的数据权限模型并没有严格按照上篇文章的方案来设计,但是万变不离其宗,核心原理还是相同的。
首先我来介绍一下我们最终实现的效果
实现效果

一个组件(可以理解成菜单)可以绑定多个授权维度,当给角色授权组件时可以给这个授权组件赋予不同维度的权限。
关于数据权限的授权维度有以下几个关键点需要仔细体会:
- 给一个角色勾选授权维度实际上是在限制这个角色所能看到的数据范围
- 任何一个授权维度勾选了"全部",相当于不限制此维度的权限。
- 如果一个角色勾选了客户群的全部 + A产品线,那么最终生成的sql 会是
where 产品线 in ('A产品线')
- 如果一个角色勾选了客户群的全部 + A产品线,那么最终生成的sql 会是
- 如果一个角色勾选了多个维度,维度之间用 AND 拼接
- 如果一个角色勾选了A客户群 + B产品线,那么最终生成的sql 会是
where 客户群 in('A客户群')AND 产品线 in ('B产品线')
- 如果一个角色勾选了A客户群 + B产品线,那么最终生成的sql 会是
- 一个用户可能有多个角色,角色之间用 OR 拼接
- 一个用户有两个角色:客户群总监,产品线经理。其中客户群总监角色拥有A客户群和B客户群的权限,产品线经理角色拥有A产品线权限,那么最终生成的sql会是
where 客户群 in ('A客户群','B客户群') OR 产品线 in ('A产品线')
- 一个用户有两个角色:客户群总监,产品线经理。其中客户群总监角色拥有A客户群和B客户群的权限,产品线经理角色拥有A产品线权限,那么最终生成的sql会是
当然我们业务场景中数据规则比较单一,全部使用
in作为sql条件连接符,你们可以根据实际业务场景进行补充。
数据模型
最终的数据模型如下所示:

这里的组件大家完全可以理解成RBAC模型中的资源、菜单,只不过叫法不同而已。
数据权限表结构
下面是具体的表结构设计
授权维度表
CREATE TABLE `wb_dimension` ( `ID` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键', `DIMENSION_CODE` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '维度编码', `DIMENSION_NAME` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '维度名称', PRIMARY KEY (`ID`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='授权维度'
具体授权维度表(产品线)
CREATE TABLE `wb_dimension_proc_line` ( `ID` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键', `DIMENSION_CODE` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '维度编码', `PROC_LINE_CODE` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '产品线编码', `PROC_LINE_NAME` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '产品线名称', PRIMARY KEY (`ID`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='授权维度-产品线'
跟授权维度表实际是一个表继承的关系,由于每个授权维度的属性不一样,展现形式也不一样,所以分表存储。
组件路由表
CREATE TABLE `wb_route` ( `ID` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键ID', `COMPONENT_ID` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '组件ID', `ROUTE_URL` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '路由地址', `AUTHORIZATION_TYPE` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '授权方式:1 自定义,2 上下级授权, 3 范围授权', `AUTHORIZATION_DIMENSION` json DEFAULT NULL COMMENT '授权维度', PRIMARY KEY (`ID`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='组件路由' 复制代码
当组件属性授权方式为范围授权时在应用侧会强制要求选择具体的授权维度,如 产品线、客户群。
角色表
CREATE TABLE `wb_role` ( `ID` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键ID', `ROLE_CODE` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '角色CODE', `ROLE_NAME` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '角色名称', `IDENTITY_ID` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '身份ID' PRIMARY KEY (`ID`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='角色表'
角色上有一个身份属性,多个角色可以归属同一个身份,方便对角色进行分类管理。
角色组件绑定表
CREATE TABLE `role_component_relation` ( `ID` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键ID', `ROLE_ID` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色ID', `COMPONENT_ID` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '组件ID', PRIMARY KEY (`ID`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='角色授权组件'
角色组件授权规则表(核心)
CREATE TABLE `wb_role_component_rule` ( `ID` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键', `ROLE_ID` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '角色ID', `COMPONENT_ID` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '组件ID', `RULE_CODE` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '规则编码', `RULE_NAME` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '规则名称', `RULE_CONDITION` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '规则条件', `RULE_VALUE` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '规则值', PRIMARY KEY (`ID`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='角色组件维度规则表'
数据权限的核心表,规则条件的取值为IN,规则值存储具体的维度编码,当在数据维度中选择 全部 时我们将规则值存储为ALL这个特殊值,方便后续生成SQL语句。

实现过程
- 自定义一个数据权限的注解,比如叫
DataPermission - 在对应的资源请求方法,比如商机列表上添加自定义注解
@DataPermission - 利用AOP抓取到用户对应角色的所有数据规则并进行SQL拼接,最终在SQL层面实现数据过滤。
代码实现
自定义数据权限注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
@Documented
public @interface DataPermission {
/**
* 数据权限类型
* 1 上下级授权 2 数据范围授权
*/
String permissionType() default "2";
/**
* 配置菜单的组件路径,用于数据权限
*/
String componentRoute() default "";
}
定义数据权限处理切面
@Aspect
@Slf4j
public class DataPermissionAspect {
@Autowired
private RoleComponentRuleService roleComponentRuleService;
@Pointcut("@annotation(com.ifly.workbench.security.annotation.DataPermission)")
public void pointCut() {
}
@Around("pointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable{
HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
//获取请求token
String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
String userName = JwtUtil.getUsername(token);
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
DataPermission permissionData = method.getAnnotation(DataPermission.class);
//获取授权方式
String permissionType = permissionData.permissionType();
//获取组件路由
String componentRoute = permissionData.componentRoute();
if (StringUtils.isNotEmpty(componentRoute)){
// 查找当前用户此组件下的所有规则
List<rolecomponentruledto> componentRules = roleComponentRuleService.getRoleComponentRule(userName, componentRoute);
if(CollectionUtils.isNotEmpty(componentRules)){
DataPermissionUtils.installDataSearchConditon(request, componentRules);
SysUserCacheInfo userInfo = buildCacheUser(userName);
DataPermissionUtils.installUserInfo(request, userInfo);
}
}
return point.proceed();
}
private SysUserCacheInfo buildCacheUser(String userName) {
SysUserCacheInfo info = new SysUserCacheInfo();
info.setSysUserName(userName);
info.setOneDepart(true);
return info;
}
}</rolecomponentruledto>
在AOP中获取当前用户、需要访问的组件中所有的数据规则,参考wb_role_component_rule表设计,并将其放到Request作用域中。
数据权限工具类
public class DataPermissionUtils {
public static final String COMPONENT_DATA_RULES = "COMPONENT_DATA_RULES";
public static final String SYS_USER_INFO = "SYS_USER_INFO";
/**
* 往链接请求里面,传入数据查询条件
* @param request
* @param componentRules
*/
public static void installDataSearchConditon(HttpServletRequest request, List<rolecomponentruledto> componentRules) {
// 1.先从request获取MENU_DATA_AUTHOR_RULES,如果存则获取到LIST
List<rolecomponentruledto> list = loadDataSearchCondition();
if (list==null) {
// 2.如果不存在,则new一个list
list = Lists.newArrayList();
}
list.addAll(componentRules);
// 3.往list里面增量存指
request.setAttribute(COMPONENT_DATA_RULES, list);
}
/**
* 获取请求对应的数据权限规则
*
*/
@SuppressWarnings("unchecked")
public synchronized List<rolecomponentruledto> loadDataSearchCondition() {
return (List<rolecomponentruledto>) SpringContextUtils.getHttpServletRequest().getAttribute(COMPONENT_DATA_RULES);
}
public synchronized void installUserInfo(HttpServletRequest request, SysUserCacheInfo userinfo) {
request.setAttribute(SYS_USER_INFO, userinfo);
}
}</rolecomponentruledto></rolecomponentruledto></rolecomponentruledto></rolecomponentruledto>
在Request中存储数据规则。
查询组件规则
public interface RoleComponentRuleService extends IService<rolecomponentrule> {
/**
* 根据 用户域账户和组件编码 获取组件对应的关系
*
* @param userName 域账号
* @param componentCode 组件编码
* @return 用户的所有规则
*/
List<rolecomponentruledto> getRoleComponentRule(String userName, String componentCode);
}</rolecomponentruledto></rolecomponentrule>
@Service
public class RoleComponentRuleServiceImpl extends ServiceImpl<rolecomponentrulemapper rolecomponentrule> implements RoleComponentRuleService {
@Resource
private RoleComponentRuleMapper roleComponentRuleMapper;
/**
* 根据 用户域账户和组件编码 获取组件对应的关系
* @param userName 域账号
* @param componentCode 组件编码
* @return 用户的所有规则
*/
@Override
public List<rolecomponentruledto> getRoleComponentRule(String userName, String componentCode) {
return roleComponentRuleMapper.getRoleComponentRule(userName,componentCode);
}
}</rolecomponentruledto></rolecomponentrulemapper>
<select id="getRoleComponentRule" resulttype="com.ifly.vo.RoleComponentRuleDTO">
SELECT
tab1.id,
tab1.role_id,
tab4.role_code,
tab1.component_id,
tab1.rule_code,
tab1.rule_name,
tab1.rule_condition,
tab1.rule_value,
tab4.identity_id
FROM
wb_role_component_rule tab1
LEFT JOIN user_role_relation tab2 ON tab2.role_id = tab1.role_id
LEFT JOIN wb_component tab3 ON tab3.id = tab1.component_id
LEFT JOIN wb_role tab4 ON tab4.id = tab1.role_id
JOIN role_component_relation tab5 ON tab5.role_id = tab1.role_id
AND tab5.component_id = tab1.component_id
where
tab2.user_account = #{userName}
and tab3.component_code = #{componentCode}
</select>
Controller调用
@ApiOperation(value = "服务BU-领导-总览")
@GetMapping("opp/getLeaderOverviewSve")
@DataPermission(componentRoute = "020202")
public Result<salesprojoverviewsve> getLeaderOverviewSve(@RequestParam(name = "identityId") String identityId) {
String permissionSql = RuleQueryGenerator.getPermissionSql(identityId);
log.info("查服务BU-领导-总览-permissionSQL==" + permissionSql);
return Result.OK(overviewSveService.getLeaderOverviewSve(permissionSql));
}</salesprojoverviewsve>
在controller的请求方法上加上自定义注解@DataPermission并指定组件编码,然后通过工具类生成SQL条件,最后将SQL条件传入service层进行处理。
构建数据权限SQL
@Slf4j
@UtilityClass
public class RuleQueryGenerator {
private static final String SQL_AND = " and ";
private static final String SQL_OR = " or ";
private static final String SQL_JOINT = " (%s) ";
/**
* 获取带有数据权限的SQL
* @param identityId 身份ID
*/
public String getPermissionSql(String identityId) {
//------------------------获取当前身份的数据规则------------------------------------
List<rolecomponentruledto> conditionList = getCurrentIdentyPermission(identityId);
if (CollectionUtils.isEmpty(conditionList)) {
//没有权限
return "1 = 0";
}
//存在权限
//对当前身份根据规则编码分组-去除不同角色中相同编码且规则值为ALL的规则 并根据角色id分组
Map<string list>> ruleMap = getRuleMapByRoleId(conditionList);
StringBuilder sb = new StringBuilder();
String roleSql;
if (MapUtils.isNotEmpty(ruleMap)) {
//按角色拼接SQL
for (Map.Entry<string list>> entry : ruleMap.entrySet()) {
List<rolecomponentruledto> lists = entry.getValue();
// 同角色之间使用 AND
roleSql = buildRoleSql(lists);
//角色之间使用 OR
if (StringUtils.isNotEmpty(roleSql)) {
jointSqlByRoles(sb, roleSql);
}
}
}
return sb.toString();
}
private static List<rolecomponentruledto> getCurrentIdentyPermission(String identityId) {
//----------------------------获取所有数据规则-----------------------------
List<rolecomponentruledto> roleRuleList = DataPermissionUtils.loadDataSearchCondition();
if(CollectionUtils.isEmpty(roleRuleList)){
return null;
}
//-----------------------------过滤掉不属于当前身份的规则-----------------------------------
return roleRuleList.stream()
.filter(item -> item.getIdentityId().equals(identityId))
.collect(Collectors.toList());
}
/**
* 构建单角色SQL
*/
private static String buildRoleSql(List<rolecomponentruledto> lists) {
StringBuilder roleSql = new StringBuilder();
for (RoleComponentRuleDTO item : lists) {
//如果出现全选 则 代表全部,不需要限定范围
if ("ALL".equals(item.getRuleValue())) {
continue;
}
//将规则转换成SQL
String filedSql = convertRuleToSql(item);
roleSql.append(SQL_AND).append(filedSql);
}
return roleSql.toString();
}
/**
* 将单一规则转化成SQL,默认全部使用 In
* ruleCode : area_test
* ruleValue : 区域1,区域2,区域3
* @param rule 规则值
*/
private static String convertRuleToSql(RoleComponentRuleDTO rule) {
String whereCondition = " in ";
String ruleValueConvert = getInConditionValue(rule.getRuleValue());
return rule.getRuleCode() + whereCondition + ruleValueConvert;
}
/**
* IN字符串转换
* 区域1, 区域2, 区域3 --> ("区域1","区域2","区域3")
* 江西大区 --> ("江西大区")
*/
private static String getInConditionValue(String ruleValue) {
String[] temp = ruleValue.split(",");
StringBuilder res = new StringBuilder();
for (String string : temp) {
res.append(",'").append(string).append("'");
}
return "(" + res.substring(1) + ")";
}
/**
* 拼接单角色的SQL
* @param sqlBuilder 总的SQL
* @param roleSql 单角色SQL
*/
private static void jointSqlByRoles(StringBuilder sqlBuilder, String roleSql) {
roleSql = roleSql.replaceFirst(SQL_AND, "");
if (StringUtils.isEmpty(sqlBuilder.toString())) {
sqlBuilder.append(String.format(SQL_JOINT, roleSql));
} else {
sqlBuilder.append(SQL_OR).append(String.format(SQL_JOINT, roleSql));
}
}
/**
*
* 1. 对当前身份根据规则编码分组-去除不同角色中相同编码且规则值为ALL的规则
* 2. 对角色进行分组
* @param conditionList 数据规则
* @return 分组后的规则list
*/
private static Map<string list>> getRuleMapByRoleId(List<rolecomponentruledto> conditionList) {
//--------过滤掉不属于当前身份的规则,并对条件编码进行分组-----------------------------------
Map<string list>> conditionMap = conditionList.stream().collect(Collectors.groupingBy(RoleComponentRuleDTO::getRuleCode));
//--------相同编码分组中存在ALL的排除掉-----------------------------------------------
List<rolecomponentruledto> newRoleRuleList = new ArrayList();
if (MapUtils.isNotEmpty(conditionMap)) {
for (Map.Entry<string list>> entry : conditionMap.entrySet()) {
boolean flag = true;
List<rolecomponentruledto> lists = entry.getValue();
for (RoleComponentRuleDTO item : lists) {
if ("ALL".equals(item.getRuleValue())) {
flag = false;
break;
}
}
if (flag) {
newRoleRuleList.addAll(lists);
}
}
}
if (CollectionUtils.isNotEmpty(newRoleRuleList)) {
return newRoleRuleList.stream().collect(Collectors.groupingBy(RoleComponentRuleDTO::getRoleId));
}
return Maps.newHashMap();
}
}</rolecomponentruledto></string></rolecomponentruledto></string></rolecomponentruledto></string></rolecomponentruledto></rolecomponentruledto></rolecomponentruledto></rolecomponentruledto></string></string></rolecomponentruledto>
核心类,用于生成数据权限查询的SQL脚本。
Dao层实现
<select id="getLeaderOverviewSve" resulttype="com.ifly.center.entity.SalesProjOverviewSve">
SELECT <include refid="column_list"></include> FROM U_STD_ADS.LTC_SALES_PROJ_OVERVIEW_SVE
<where><if test="permissionSql != null and permissionSql != ''">
${permissionSql}
</if></where></select>
Dao层接受service层传入已经生成好的sql语句,作为查询条件直接拼接在业务语句之后。
小结
以上,就是数据权限的实现过程,其实代码实现并不复杂,主要还是得理解其中的实现原理。如果你也有数据权限的需求,不妨参考一下。
今天关于《MySQL数据权限的实现详情》的内容就介绍到这里了,是不是学起来一目了然!想要了解更多关于mysql的内容请关注golang学习网公众号!
MySQL数据库存储引擎介绍及数据库的操作详解
- 上一篇
- MySQL数据库存储引擎介绍及数据库的操作详解
- 下一篇
- Canal监听MySQL的实现步骤
-
- 数据库 · MySQL | 1天前 |
- MySQL数值函数大全及使用技巧
- 117浏览 收藏
-
- 数据库 · MySQL | 2天前 |
- 三种登录MySQL方法详解
- 411浏览 收藏
-
- 数据库 · MySQL | 3天前 |
- MySQL数据备份方法与工具推荐
- 420浏览 收藏
-
- 数据库 · MySQL | 3天前 |
- MySQL数据备份方法与工具推荐
- 264浏览 收藏
-
- 数据库 · MySQL | 4天前 |
- MySQL索引的作用是什么?
- 266浏览 收藏
-
- 数据库 · MySQL | 5天前 |
- MySQL排序原理与实战应用
- 392浏览 收藏
-
- 数据库 · MySQL | 1星期前 |
- MySQLwhere条件查询技巧
- 333浏览 收藏
-
- 数据库 · MySQL | 1星期前 |
- MySQL常用数据类型有哪些?怎么选更合适?
- 234浏览 收藏
-
- 数据库 · MySQL | 1星期前 |
- MySQL常用命令大全管理员必学30条
- 448浏览 收藏
-
- 数据库 · MySQL | 1星期前 |
- MySQL高效批量插入数据方法大全
- 416浏览 收藏
-
- 数据库 · MySQL | 1星期前 |
- MySQL性能优化技巧大全
- 225浏览 收藏
-
- 数据库 · MySQL | 1星期前 |
- MySQL数据备份4种方法保障安全
- 145浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ChatExcel酷表
- ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
- 3164次使用
-
- Any绘本
- 探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
- 3376次使用
-
- 可赞AI
- 可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
- 3405次使用
-
- 星月写作
- 星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
- 4509次使用
-
- MagicLight
- MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
- 3785次使用
-
- go-cqhttp权限管理系统的实现代码
- 2022-12-28 405浏览
-
- MySQL实现数据更新的示例详解
- 2023-02-25 176浏览
-
- Go 实现 WebSockets和什么是 WebSockets
- 2022-12-29 335浏览
-
- MySQL数据操作管理示例详解
- 2022-12-30 443浏览
-
- 详解MySQL中数据类型和字段类型
- 2023-02-23 311浏览

