库函数增加修改日志记录,增加函数修改授权,展示优化

This commit is contained in:
暮光:城中城
2021-04-27 23:24:21 +08:00
parent 744e877309
commit 58976dc829
22 changed files with 517 additions and 57 deletions

View File

@@ -91,6 +91,11 @@ public class DbDataSourceAuthController {
UserAuth userAuth = this.createUserAuth(sourceId, currentUser.getUserId(), authVo.getUserId(), authId);
userAuthList.add(userAuth);
}
if (Objects.equals(authVo.getProcEditAuth(), 1)) {
Long authId = authInfoMap.get(DbAuthType.PROC_EDIT.getName());
UserAuth userAuth = this.createUserAuth(sourceId, currentUser.getUserId(), authVo.getUserId(), authId);
userAuthList.add(userAuth);
}
if (userAuthList.size() <= 0) {
continue;
}
@@ -121,7 +126,6 @@ public class DbDataSourceAuthController {
userAuthGroup.forEach((key, value) -> {
Set<String> authNameSet = value.stream().map(auth -> authInfoMap.get(auth.getAuthId())).collect(Collectors.toSet());
UserDbAuthVo authVo = new UserDbAuthVo();
authVo.setExecuteAuth(0);
if (this.haveAuth(authNameSet, DbAuthType.UPDATE) == 1) {
authVo.setExecuteAuth(3);
} else if (this.haveAuth(authNameSet, DbAuthType.SELECT) == 1) {
@@ -130,6 +134,7 @@ public class DbDataSourceAuthController {
authVo.setExecuteAuth(1);
}
authVo.setDescEditAuth(this.haveAuth(authNameSet, DbAuthType.DESC_EDIT));
authVo.setProcEditAuth(this.haveAuth(authNameSet, DbAuthType.PROC_EDIT));
authVo.setUserId(key);
authVo.setUserName(userInfoMap.get(key));
authVoList.add(authVo);

View File

@@ -15,6 +15,7 @@ import com.zyplayer.doc.db.framework.configuration.DatasourceUtil;
import com.zyplayer.doc.db.framework.db.bean.DatabaseFactoryBean;
import com.zyplayer.doc.db.framework.db.bean.DatabaseRegistrationBean;
import com.zyplayer.doc.db.framework.json.DocDbResponseJson;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.springframework.web.bind.annotation.PostMapping;
@@ -59,8 +60,13 @@ public class DbDatasourceController {
public ResponseJson groups() {
QueryWrapper<DbDatasource> wrapper = new QueryWrapper<>();
wrapper.eq("yn", 1);
wrapper.isNotNull("group_name");
wrapper.select("group_name");
wrapper.groupBy("group_name");
List<DbDatasource> datasourceList = dbDatasourceService.list(wrapper);
if (CollectionUtils.isEmpty(datasourceList)) {
return DocDbResponseJson.ok();
}
Set<String> groupNameSet = datasourceList.stream().map(DbDatasource::getGroupName).filter(StringUtils::isNotBlank).collect(Collectors.toSet());
return DocDbResponseJson.ok(groupNameSet);
}

View File

@@ -1,10 +1,20 @@
package com.zyplayer.doc.db.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException;
import com.zyplayer.doc.core.annotation.AuthMan;
import com.zyplayer.doc.core.exception.ConfirmException;
import com.zyplayer.doc.core.json.ResponseJson;
import com.zyplayer.doc.data.config.security.DocUserDetails;
import com.zyplayer.doc.data.config.security.DocUserUtil;
import com.zyplayer.doc.data.repository.manage.entity.DbDatasource;
import com.zyplayer.doc.data.repository.manage.entity.DbProcLog;
import com.zyplayer.doc.data.repository.support.consts.DocAuthConst;
import com.zyplayer.doc.data.service.manage.DbProcLogService;
import com.zyplayer.doc.db.controller.param.ProcedureListParam;
import com.zyplayer.doc.db.framework.consts.DbAuthType;
import com.zyplayer.doc.db.framework.db.dto.ProcedureDto;
import com.zyplayer.doc.db.framework.db.mapper.base.ExecuteResult;
import com.zyplayer.doc.db.framework.json.DocDbResponseJson;
@@ -18,6 +28,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
/**
@@ -34,6 +45,8 @@ public class DbProcedureController {
@Resource
DbBaseFactory dbBaseFactory;
@Resource
DbProcLogService dbProcLogService;
/**
* 存储过程列表
@@ -43,18 +56,19 @@ public class DbProcedureController {
*/
@PostMapping(value = "/list")
public ResponseJson list(ProcedureListParam procedureParam) {
boolean manageAuth = DocUserUtil.haveAuth(DocAuthConst.DB_DATASOURCE_MANAGE);
if (!manageAuth) {
return DocDbResponseJson.warn("没有该数据源的管理权限");
try {
DbBaseService dbBaseService = dbBaseFactory.getDbBaseService(procedureParam.getSourceId());
procedureParam.setOffset((procedureParam.getPageNum() - 1) * procedureParam.getPageSize());
List<ProcedureDto> procedureDtoList = dbBaseService.getProcedureList(procedureParam);
DocDbResponseJson responseJson = DocDbResponseJson.ok(procedureDtoList);
if (procedureParam.getPageNum() == 1) {
responseJson.setTotal(dbBaseService.getProcedureCount(procedureParam));
}
return responseJson;
} catch (Exception e) {
// 一般是数据库的帐号没权限查存储过程
return DocDbResponseJson.error(e.getMessage());
}
DbBaseService dbBaseService = dbBaseFactory.getDbBaseService(procedureParam.getSourceId());
procedureParam.setOffset((procedureParam.getPageNum() - 1) * procedureParam.getPageSize());
List<ProcedureDto> procedureDtoList = dbBaseService.getProcedureList(procedureParam);
DocDbResponseJson responseJson = DocDbResponseJson.ok(procedureDtoList);
if (procedureParam.getPageNum() == 1) {
responseJson.setTotal(dbBaseService.getProcedureCount(procedureParam));
}
return responseJson;
}
/**
@@ -68,13 +82,14 @@ public class DbProcedureController {
*/
@PostMapping(value = "/detail")
public ResponseJson detail(Long sourceId, String dbName, String typeName, String procName) {
boolean manageAuth = DocUserUtil.haveAuth(DocAuthConst.DB_DATASOURCE_MANAGE);
if (!manageAuth) {
return DocDbResponseJson.warn("没有该数据源的管理权限");
}
DbBaseService dbBaseService = dbBaseFactory.getDbBaseService(sourceId);
ProcedureDto procedureDto = dbBaseService.getProcedureDetail(sourceId, dbName, typeName, procName);
return DocDbResponseJson.ok(procedureDto);
try {
ProcedureDto procedureDto = dbBaseService.getProcedureDetail(sourceId, dbName, typeName, procName);
return DocDbResponseJson.ok(procedureDto);
} catch (Exception e) {
// 一般是数据库的帐号没权限查存储过程
return DocDbResponseJson.error(e.getMessage());
}
}
/**
@@ -88,13 +103,19 @@ public class DbProcedureController {
*/
@PostMapping(value = "/delete")
public ResponseJson delete(Long sourceId, String dbName, String typeName, String procName) {
boolean manageAuth = DocUserUtil.haveAuth(DocAuthConst.DB_DATASOURCE_MANAGE);
if (!manageAuth) {
return DocDbResponseJson.warn("没有该数据源的管理权限");
this.judgeAuth(sourceId, DbAuthType.PROC_EDIT.getName(), "没有修改该库函数的权限");
DbProcLog dbProcLog = this.createDbProcLog(sourceId, dbName, typeName, procName, "删除函数操作");
try {
DbBaseService dbBaseService = dbBaseFactory.getDbBaseService(sourceId);
dbBaseService.deleteProcedure(sourceId, dbName, typeName, procName);
return DocDbResponseJson.ok();
} catch (Exception e) {
dbProcLog.setStatus(2);
// 一般是数据库的帐号没权限查存储过程
return DocDbResponseJson.error(e.getMessage());
} finally {
dbProcLogService.save(dbProcLog);
}
DbBaseService dbBaseService = dbBaseFactory.getDbBaseService(sourceId);
dbBaseService.deleteProcedure(sourceId, dbName, typeName, procName);
return DocDbResponseJson.ok();
}
/**
@@ -109,14 +130,93 @@ public class DbProcedureController {
*/
@PostMapping(value = "/save")
public ResponseJson save(Long sourceId, String dbName, String typeName, String procName, String procSql) {
boolean manageAuth = DocUserUtil.haveAuth(DocAuthConst.DB_DATASOURCE_MANAGE);
if (!manageAuth) {
return DocDbResponseJson.warn("没有该数据源的管理权限");
this.judgeAuth(sourceId, DbAuthType.PROC_EDIT.getName(), "没有修改该库函数的权限");
DbProcLog dbProcLog = this.createDbProcLog(sourceId, dbName, typeName, procName, procSql);
try {
DbBaseService dbBaseService = dbBaseFactory.getDbBaseService(sourceId);
ExecuteResult executeResult = dbBaseService.saveProcedure(sourceId, dbName, typeName, procName, procSql);
if (StringUtils.isNotBlank(executeResult.getErrMsg())) {
dbProcLog.setStatus(2);
}
return DocDbResponseJson.ok(executeResult);
} catch (Exception e) {
dbProcLog.setStatus(2);
// 一般是数据库的帐号没权限查存储过程
return DocDbResponseJson.error(e.getMessage());
} finally {
dbProcLogService.save(dbProcLog);
}
DbBaseService dbBaseService = dbBaseFactory.getDbBaseService(sourceId);
ExecuteResult executeResult = dbBaseService.saveProcedure(sourceId, dbName, typeName, procName, procSql);
return DocDbResponseJson.ok(executeResult);
}
/**
* 存储过程修改日志列表
*
* @param sourceId 数据源ID
* @param dbName 数据库名
* @param typeName 类型名
* @param procName 函数名
* @return 列表
*/
@PostMapping(value = "/log/list")
public ResponseJson logList(Integer pageNum, Integer pageSize, Long sourceId, String dbName, String typeName, String procName) {
QueryWrapper<DbProcLog> wrapper = new QueryWrapper<>();
wrapper.eq("datasource_id", sourceId);
wrapper.eq("proc_db", dbName);
wrapper.eq("proc_name", procName);
wrapper.eq("proc_type", typeName);
wrapper.orderByDesc("id");
wrapper.select("id", "proc_body", "create_user_name", "create_time", "status");
IPage<DbProcLog> page = new Page<>(pageNum, pageSize, pageNum == 1);
dbProcLogService.page(page, wrapper);
return DocDbResponseJson.ok(page);
}
/**
* 存储过程修改日志详情
*
* @param logId 日志ID
* @return 详情
*/
@PostMapping(value = "/log/detail")
public ResponseJson logDetail(Long logId) {
DbProcLog dbProcLog = dbProcLogService.getById(logId);
return DocDbResponseJson.ok(dbProcLog);
}
/**
* 权限判断
*
* @author 暮光:城中城
*/
private void judgeAuth(Long sourceId, String authName, String noAuthInfo) {
if (!DocUserUtil.haveAuth(DocAuthConst.DB_DATASOURCE_MANAGE)
&& !DocUserUtil.haveCustomAuth(authName, DocAuthConst.DB + sourceId)) {
throw new ConfirmException(noAuthInfo);
}
}
/**
* 创建日志对象
* @param sourceId
* @param dbName
* @param typeName
* @param procName
* @param procSql
* @return
*/
public DbProcLog createDbProcLog(Long sourceId, String dbName, String typeName, String procName, String procSql) {
DocUserDetails currentUser = DocUserUtil.getCurrentUser();
DbProcLog dbProcLog = new DbProcLog();
dbProcLog.setDatasourceId(sourceId);
dbProcLog.setCreateTime(new Date());
dbProcLog.setCreateUserId(currentUser.getUserId());
dbProcLog.setCreateUserName(currentUser.getUsername());
dbProcLog.setProcDb(dbName);
dbProcLog.setProcName(procName);
dbProcLog.setProcType(typeName);
dbProcLog.setProcBody(procSql);
dbProcLog.setStatus(1);
return dbProcLog;
}
}

View File

@@ -5,6 +5,7 @@ public class UserDbAuthVo {
private Long userId;
private Integer executeAuth;
private Integer descEditAuth;
private Integer procEditAuth;
public String getUserName() {
return userName;
@@ -37,4 +38,12 @@ public class UserDbAuthVo {
public void setDescEditAuth(Integer descEditAuth) {
this.descEditAuth = descEditAuth;
}
public Integer getProcEditAuth() {
return procEditAuth;
}
public void setProcEditAuth(Integer procEditAuth) {
this.procEditAuth = procEditAuth;
}
}

View File

@@ -5,7 +5,8 @@ public enum DbAuthType {
VIEW(1, "DB_VIEW_"),
SELECT(2, "DB_SELECT_"),
UPDATE(3, "DB_UPDATE_"),
DESC_EDIT(3, "DB_DESC_EDIT_"),
DESC_EDIT(4, "DB_DESC_EDIT_"),
PROC_EDIT(5, "DB_PROC_EDIT_"),
;
private Integer type;
private String name;

View File

@@ -66,13 +66,13 @@ public class MysqlServiceImpl extends DbBaseService {
// 新建的时候
ProcedureDto procedureDetailNew = new ProcedureDto();
if (Objects.equals(typeName, "FUNCTION")) {
procedureDetailNew.setBody("CREATE DEFINER = CURRENT_USER " + typeName + " `" + procName + "`() RETURNS integer\n" +
procedureDetailNew.setBody("CREATE DEFINER = CURRENT_USER " + typeName + " `" + dbName + "`.`" + procName + "`() RETURNS integer\n" +
"BEGIN\n" +
"\t#Routine body goes here...\n" +
"\tRETURN 0;\n" +
"END;");
} else {
procedureDetailNew.setBody("CREATE DEFINER = CURRENT_USER " + typeName + " `" + procName + "`()\n" +
procedureDetailNew.setBody("CREATE DEFINER = CURRENT_USER " + typeName + " `" + dbName + "`.`" + procName + "`()\n" +
"BEGIN\n" +
"\t#Routine body goes here...\n" +
"END;");
@@ -85,9 +85,10 @@ public class MysqlServiceImpl extends DbBaseService {
// 组装好SQL
String type = procedureDetail.getType();
String name = procedureDetail.getName();
String db = procedureDetail.getDb();
String paramList = StringUtils.defaultIfBlank(procedureDetail.getParamList(), "");
String[] definerArr = procedureDetail.getDefiner().split("@");
String createStr = String.format("CREATE DEFINER=`%s`@`%s` %s `%s`(%s)", definerArr[0], definerArr[1], type, name, paramList);
String createStr = String.format("CREATE DEFINER=`%s`@`%s` %s `%s`.`%s`(%s)", definerArr[0], definerArr[1], type, db, name, paramList);
if (Objects.equals(procedureDetail.getType(), "FUNCTION")) {
createStr += " RETURNS " + procedureDetail.getReturns();
}
@@ -99,7 +100,7 @@ public class MysqlServiceImpl extends DbBaseService {
public ExecuteResult saveProcedure(Long sourceId, String dbName, String typeName, String procName, String procSql) {
String firstLine = procSql.split("\n")[0];
// 看函数名是否被修改了,修改会导致函数名的不确定,有认知上的成本,明确的先删再建吧
if (!firstLine.contains(" `" + procName + "`(") && !firstLine.contains(" " + procName + "(")) {
if (!firstLine.contains("`" + procName + "`(") && !firstLine.contains(" " + procName + "(") && !firstLine.contains("." + procName + "(")) {
return ExecuteResult.error("在编辑页面不允许修改函数名,如需新建或修改,请到列表页删除后再新建函数", procSql);
}
ProcedureDto procedureDetail = this.getProcedureDetail(sourceId, dbName, typeName, procName);
@@ -121,7 +122,7 @@ public class MysqlServiceImpl extends DbBaseService {
executeParam.setSql(procedureDetail.getBody());
sqlExecutor.execute(executeParam);
} catch (Exception e1) {
return ExecuteResult.error("执行和恢复函数均失败请先备份您的SQL以防丢失", procSql);
return ExecuteResult.error("执行和恢复函数均失败请先备份您的SQL以防丢失\n" + e.getMessage(), procSql);
}
return ExecuteResult.error(e.getMessage(), procSql);
}