feat: 数据查询接口类型优化

feat: 完善gitee、github登录异常逻辑
This commit is contained in:
qiufeng
2025-02-15 00:03:30 +08:00
parent ff91dbf114
commit ebb34184d4
21 changed files with 86 additions and 42 deletions
+6 -2
View File
@@ -11,7 +11,7 @@
## 架构图
![](https://oscimg.oschina.net/oscnet/up-7cb78605937aa402dbbdc8bdad8c2888b72.png)
![](https://mfish-pic.pages.dev/frame.png)
## 项目介绍
@@ -68,7 +68,7 @@
│ ├─数据源
│ ├─代码生成
│ ├─自助API
│ └─自助大屏(开发中...)
│ └─自助大屏
├─系统管理
│ ├─菜单管理
│ ├─组织管理
@@ -114,6 +114,10 @@
<td><img src="https://mfish-pic.pages.dev/login.png" /></td>
<td><img src="https://mfish-pic.pages.dev/menu.png" /></td>
</tr>
<tr>
<td><img src="https://mfish-pic.pages.dev/screen.png" /></td>
<td><img src="https://mfish-pic.pages.dev/screenConfig.png" /></td>
</tr>
<tr>
<td><img src="https://mfish-pic.pages.dev/api.png" /></td>
<td><img src="https://mfish-pic.pages.dev/flow.png" /></td>
@@ -60,6 +60,7 @@ public class DataConstant {
public static final String NUMBER = "NUMBER";
public static final String DATETIME = "DATETIME";
public static final String TIME = "TIME";
public static final String TIMETZ = "TIMETZ";
public static final String TIMESTAMP = "TIMESTAMP";
public static final String DATETIMEOFFSET = "DATETIMEOFFSET";
public static final String DATE = "DATE";
@@ -18,6 +18,7 @@ import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@@ -217,7 +218,7 @@ public class OkHttpUtils {
* @return 构建好的OkHttpClient实例
*/
private static OkHttpClient buildOkHttpClient(String url, TimeOut timeOut) {
OkHttpClient.Builder clientBuilder = new OkHttpClient().newBuilder();
OkHttpClient.Builder clientBuilder = new OkHttpClient().newBuilder().protocols(List.of(Protocol.HTTP_1_1));
if (timeOut != null) {
clientBuilder.connectTimeout(timeOut.getConnectTimeOut(), timeOut.getTimeUnit())
.readTimeout(timeOut.getReadTimeOut(), timeOut.getTimeUnit())
@@ -2,6 +2,7 @@ package cn.com.mfish.common.dblink.db;
import cn.com.mfish.common.core.utils.StringUtils;
import cn.com.mfish.common.dblink.entity.QueryParam;
import cn.com.mfish.common.dblink.enums.DBType;
import cn.com.mfish.common.dblink.page.BoundSql;
import java.text.MessageFormat;
@@ -39,6 +40,7 @@ public abstract class AbstractDBDialect implements DBDialect {
*/
protected BoundSql buildCondition(String sql, String dbName, String tableName) {
BoundSql boundSql = new BoundSql();
boundSql.setDbType(DBType.mysql);
if (!StringUtils.isEmpty(tableName)) {
sql += " and (table_name = ? or table_name = ?) ";
boundSql.getParams().add(new QueryParam().setValue(tableName.toUpperCase()));
@@ -2,6 +2,7 @@ package cn.com.mfish.common.dblink.db;
import cn.com.mfish.common.core.utils.StringUtils;
import cn.com.mfish.common.dblink.entity.QueryParam;
import cn.com.mfish.common.dblink.enums.DBType;
import cn.com.mfish.common.dblink.page.BoundSql;
import java.util.Locale;
@@ -56,6 +57,7 @@ public class OracleDBDialect implements DBDialect {
private BoundSql buildCondition(String sql, String tableName) {
BoundSql boundSql = new BoundSql();
boundSql.setDbType(DBType.oracle);
if (!StringUtils.isEmpty(tableName)) {
//这里虽然匹配大小写,但是建议oracle表名视图都创建大写名称,避免数据查询时无法查到
sql += " and (a.TABLE_NAME = ? or a.TABLE_NAME = ?)";
@@ -1,6 +1,7 @@
package cn.com.mfish.common.dblink.page;
import cn.com.mfish.common.dblink.entity.QueryParam;
import cn.com.mfish.common.dblink.enums.DBType;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -17,6 +18,8 @@ import java.util.List;
@Accessors(chain = true)
@Schema(description = "sql包装")
public class BoundSql {
@Schema(description = "数据库类型")
private DBType dbType;
@Schema(description = "查询SQL")
private String sql;
@Schema(description = "查询参数")
@@ -42,6 +45,11 @@ public class BoundSql {
* @param params 参数
*/
public BoundSql(String sql, List<QueryParam> params) {
this(DBType.mysql, sql, params);
}
public BoundSql(DBType dbType, String sql, List<QueryParam> params) {
this.dbType = dbType;
this.sql = sql;
if (params == null) {
params = new ArrayList<>();
@@ -1,21 +1,24 @@
package cn.com.mfish.common.dblink.query;
import cn.com.mfish.common.core.constants.DataConstant;
import cn.com.mfish.common.core.enums.DataType;
import cn.com.mfish.common.core.exception.MyRuntimeException;
import cn.com.mfish.common.core.utils.DataUtils;
import cn.com.mfish.common.core.utils.StringUtils;
import cn.com.mfish.common.core.utils.Utils;
import cn.com.mfish.common.core.utils.DataUtils;
import cn.com.mfish.common.dataset.datatable.MetaDataHeader;
import cn.com.mfish.common.dataset.datatable.MetaDataHeaders;
import cn.com.mfish.common.dataset.datatable.MetaDataRow;
import cn.com.mfish.common.dataset.datatable.MetaDataTable;
import cn.com.mfish.common.dataset.enums.TargetType;
import cn.com.mfish.common.core.constants.DataConstant;
import cn.com.mfish.common.dblink.entity.DataSourceOptions;
import cn.com.mfish.common.dblink.enums.DBType;
import cn.com.mfish.common.dblink.manger.PoolManager;
import cn.com.mfish.common.dblink.page.BoundSql;
import com.github.pagehelper.Page;
import lombok.extern.slf4j.Slf4j;
import oracle.sql.TIMESTAMP;
import oracle.sql.TIMESTAMPTZ;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@@ -54,7 +57,7 @@ public class BaseQuery {
public MetaDataTable query(BoundSql boundSql) {
return query(boundSql, rs -> {
try {
return getMetaDataTable(rs, getColHeaders(rs.getMetaData()));
return getMetaDataTable(rs, getColHeaders(rs.getMetaData()), boundSql.getDbType());
} catch (SQLException e) {
log.error("获取metaData异常:{}", boundSql.getSql(), e);
throw new MyRuntimeException(e);
@@ -269,7 +272,7 @@ public class BaseQuery {
* @return 返回元数据表格
* @throws SQLException 异常
*/
protected MetaDataTable getMetaDataTable(final ResultSet rs, final MetaDataHeaders headers) throws SQLException {
protected MetaDataTable getMetaDataTable(final ResultSet rs, final MetaDataHeaders headers, DBType dbType) throws SQLException {
final MetaDataTable table = new MetaDataTable(headers);
long start = System.currentTimeMillis();
while (rs.next()) {
@@ -279,10 +282,17 @@ public class BaseQuery {
while (iterator.hasNext()) {
String type = rs.getMetaData().getColumnTypeName(i).toUpperCase(Locale.ROOT);
Object value = formatValue(type, rs.getObject(i));
//MetaDataTable返回类型为日期时,强制格式为字符类型
if (value instanceof java.util.Date) {
//MetaDataTable返回类型日期强制格式为 yyyy-MM-dd HH:mm:ss
if (type.equals(DataConstant.DataType.DATE)) {
value = new SimpleDateFormat("yyyy-MM-dd").format(value);
//oracle没有dateTime,time等类型不进行转换
if (dbType != DBType.oracle) {
if (type.equals(DataConstant.DataType.DATE)) {
value = new SimpleDateFormat("yyyy-MM-dd").format(value);
} else if (type.equals(DataConstant.DataType.TIME) || type.equals(DataConstant.DataType.TIMETZ)) {
value = new SimpleDateFormat("HH:mm:ss").format(value);
} else {
value = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(value);
}
} else {
value = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(value);
}
@@ -304,7 +314,7 @@ public class BaseQuery {
* @param value 查询值
* @return 返回格式化后的值
*/
public Object formatValue(String columnTypeName, Object value) {
public Object formatValue(String columnTypeName, Object value) throws SQLException {
if (value == null) {
return null;
}
@@ -319,13 +329,10 @@ public class BaseQuery {
//LocalDateTime 转成Date类型
value = value instanceof LocalDateTime ? Date.from(((LocalDateTime) value).atZone(ZoneId.systemDefault()).toInstant()) : value;
} else if (columnTypeName.contains(DataConstant.DataType.TIMESTAMP)) {
String time = value.toString();
if (!StringUtils.isEmpty(time)) {
try {
value = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(time.substring(0, time.length() - 2));
} catch (ParseException e) {
log.error("错误:日期转换异常");
}
if (value instanceof TIMESTAMPTZ) {
value = Date.from(((TIMESTAMPTZ) value).toLocalDateTime().atZone(ZoneId.systemDefault()).toInstant());
} else if (value instanceof TIMESTAMP) {
value = Date.from(((TIMESTAMP) value).toLocalDateTime().atZone(ZoneId.systemDefault()).toInstant());
}
}
return value;
@@ -48,7 +48,7 @@ public class QueryHandler {
* @return 返回结果集
*/
public static MetaDataTable query(DataSourceOptions<?> dataSourceOptions, String strSql, List<QueryParam> params) {
return query(dataSourceOptions, new BoundSql(strSql, params), null);
return query(dataSourceOptions, new BoundSql(dataSourceOptions.getDbType(), strSql, params), null);
}
/**
@@ -75,7 +75,7 @@ public class QueryHandler {
* @return 返回结果集
*/
public static MetaDataTable query(DataSourceOptions<?> dataSourceOptions, String strSql, List<QueryParam> params, RowBounds rowBounds) {
return query(dataSourceOptions, new BoundSql(strSql, params), rowBounds);
return query(dataSourceOptions, new BoundSql(dataSourceOptions.getDbType(), strSql, params), rowBounds);
}
/**
@@ -109,7 +109,7 @@ public class QueryHandler {
* @return 返回翻页结果集
*/
public static <T> Page<T> queryT(DataSourceOptions<?> dataSourceOptions, String strSql, List<QueryParam> params, Class<T> cls) {
return queryT(dataSourceOptions, new BoundSql(strSql, params), null, cls);
return queryT(dataSourceOptions, new BoundSql(dataSourceOptions.getDbType(), strSql, params), null, cls);
}
/**
@@ -136,7 +136,7 @@ public class QueryHandler {
* @return 返回翻页结果集
*/
public static <T> Page<T> queryT(DataSourceOptions<?> dataSourceOptions, String strSql, List<QueryParam> params, RowBounds rowBounds, Class<T> cls) {
return queryT(dataSourceOptions, new BoundSql(strSql, params), rowBounds, cls);
return queryT(dataSourceOptions, new BoundSql(dataSourceOptions.getDbType(), strSql, params), rowBounds, cls);
}
/**
@@ -28,11 +28,14 @@ public interface SsoUserService extends IService<SsoUser> {
Result<SsoUser> updateUser(SsoUser user);
void validateUser(SsoUser user, String operate);
boolean removeUser(String id);
SsoUser getUserByAccount(String account);
SsoUser getUserByGitee(String gitee);
SsoUser getUserByGithub(String github);
UserInfo getUserByAccountNoPwd(String account);
@@ -66,7 +66,7 @@ public class GiteeController {
}
result = loginService.login(result.getData(), token, SerConstant.LoginType.Gitee, "system", "false");
if (!result.isSuccess()) {
return Result.fail("错误:登录失败");
return Result.fail(result.getMsg());
}
return Result.ok(0, "登录成功");
@@ -52,7 +52,7 @@ public class GithubController {
param.put("redirect_uri", redirectUri);
Map<String, String> header = new HashMap<>();
header.put("Accept", "application/json");
Result<String> result = OkHttpUtils.postJson("https://github.com/login/oauth/access_token", JSON.toJSONString(param));
Result<String> result = OkHttpUtils.postJson("https://github.com/login/oauth/access_token", JSON.toJSONString(param), header);
JSONObject jsonObject;
if (!result.isSuccess()) {
return Result.fail("错误:请求github token失败");
@@ -67,7 +67,7 @@ public class GithubController {
}
result = loginService.login(result.getData(), token, SerConstant.LoginType.Github, "system", "false");
if (!result.isSuccess()) {
return Result.fail("错误:登录失败");
return Result.fail(result.getMsg());
}
return Result.ok(0, "登录成功");
@@ -57,7 +57,7 @@ public class GitRealm extends AuthorizingRealm {
if (null != user) return user;
user = ssoUserService.getUserByAccount(username);
String account;
if (user == null) {
if (user == null && StringUtils.isMatch("^[a-zA-Z0-9]+$", username)) {
account = username;
} else {
account = IDBuild.getID("G");
@@ -65,7 +65,11 @@ public class GitRealm extends AuthorizingRealm {
SsoUser userInfo = new SsoUser();
userInfo.setId(Utils.uuid32());
userInfo.setAccount(account);
userInfo.setGitee(username);
if (myToken.getLoginType() == SerConstant.LoginType.Github) {
userInfo.setGithub(username);
} else {
userInfo.setGitee(username);
}
userInfo.setNickname(json.getString("name"));
userInfo.setEmail(json.getString("email"));
userInfo.setHeadImgUrl(json.getString("avatar_url"));
@@ -75,7 +75,7 @@ public class LoginServiceImpl implements LoginService {
* 本方法主要用于校验授权码(code)的有效性通过HTTP请求参数进行校验如果校验失败,
* 会将错误信息添加到模型中并返回false否则,返回true表示校验成功
*
* @param model 用于存储属性值,在发生错误时用于存储错误信息
* @param model 用于存储属性值,在发生错误时用于存储错误信息
* @param request HTTP请求对象,用于获取请求参数
* @return boolean 校验是否成功
*/
@@ -91,7 +91,7 @@ public class LoginServiceImpl implements LoginService {
/**
* web请求登录 构建model返回值
*
* @param model 用于存储属性值,在发生错误时用于存储错误信息
* @param model 用于存储属性值,在发生错误时用于存储错误信息
* @param request HTTP请求对象,用于获取请求参数
* @return boolean 校验是否成功
*/
@@ -124,8 +124,8 @@ public class LoginServiceImpl implements LoginService {
/**
* 登录用户验证逻辑
*
* @param username 账号
* @param password 密码
* @param username 账号
* @param password 密码
* @param loginType 登陆类型
* @return 返回登陆结果
*/
@@ -1,7 +1,6 @@
package cn.com.mfish.oauth.service.impl;
import cn.com.mfish.common.core.exception.MyRuntimeException;
import cn.com.mfish.common.core.exception.OAuthValidateException;
import cn.com.mfish.common.core.utils.AuthInfoUtils;
import cn.com.mfish.common.core.utils.StringUtils;
import cn.com.mfish.common.core.web.ReqPage;
@@ -9,7 +8,6 @@ import cn.com.mfish.common.core.web.Result;
import cn.com.mfish.common.oauth.api.entity.SsoOrg;
import cn.com.mfish.common.oauth.api.entity.SsoTenant;
import cn.com.mfish.common.oauth.api.vo.TenantVo;
import cn.com.mfish.common.oauth.common.SerConstant;
import cn.com.mfish.common.oauth.entity.SsoUser;
import cn.com.mfish.common.oauth.service.SsoOrgService;
import cn.com.mfish.common.oauth.service.SsoUserService;
@@ -24,6 +22,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -220,11 +219,17 @@ public class SsoTenantServiceImpl extends ServiceImpl<SsoTenantMapper, SsoTenant
}
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public void createTenantUser(SsoUser ssoUser) {
Result<SsoUser> result = ssoUserService.insertUser(ssoUser);
Result<SsoUser> result;
try {
result = ssoUserService.insertUser(ssoUser);
} catch (MyRuntimeException ex) {
//包装成shiro异常,便于shiro统一处理
throw new IncorrectCredentialsException(ex.getMessage());
}
if (!result.isSuccess()) {
throw new OAuthValidateException(SerConstant.INVALID_NEW_USER_DESCRIPTION);
throw new IncorrectCredentialsException(result.getMsg());
}
SsoTenant ssoTenant = new SsoTenant();
ssoTenant.setUserId(ssoUser.getId());
@@ -236,9 +241,14 @@ public class SsoTenantServiceImpl extends ServiceImpl<SsoTenantMapper, SsoTenant
ssoTenant.setStatus(0);
ssoTenant.setTenantType(0);
ssoTenant.setRoleIds(List.of(AuthInfoUtils.PERSON_ROLE_ID));
Result<SsoTenant> result1 = insertTenant(ssoTenant);
Result<SsoTenant> result1;
try {
result1 = insertTenant(ssoTenant);
} catch (MyRuntimeException ex) {
throw new IncorrectCredentialsException(ex.getMessage());
}
if (!result1.isSuccess()) {
throw new OAuthValidateException("错误:创建新租户失败");
throw new IncorrectCredentialsException("错误:创建新租户失败");
}
}
}
@@ -239,7 +239,8 @@ public class SsoUserServiceImpl extends ServiceImpl<SsoUserMapper, SsoUser> impl
* @param user 用户
* @param operate 操作
*/
private void validateUser(SsoUser user, String operate) {
@Override
public void validateUser(SsoUser user, String operate) {
if (isAccountExist(user.getAccount(), user.getId())) {
throw new MyRuntimeException("错误:帐号已存在-" + operate + "失败!");
}
@@ -15,8 +15,8 @@ let app = new Vue({
captchaKey: '',
captchaUrl: '',
phone: '',
username: 'mfish',
password: '!QAZ2wsx',
username: '',
password: '',
loginType: '',
loginTypeName: '帐号',
errorMsg: '',
@@ -47,6 +47,7 @@
<div class="card fat">
<div class="card-body">
<h4 class="card-title mb-3">{{loginTypeName}}登录</h4>
<h6 style="color: red">演示环境,请使用最下方gitee账号一键登录</h6>
<div v-show="userPasswordVisible">
<form id="login" method="POST" class="enter-x">
<div class="form-floating mb-3">
@@ -173,7 +174,7 @@
<div v-show="qrCodeVisible" class="enter-x">
<form id="qrCodeLogin" method="post">
<input type="hidden" v-model="qrCodeName" name="username"/>
<input type="hiddean" v-model="qrCodeSecret" name="password"/>
<input type="hidden" v-model="qrCodeSecret" name="password"/>
<input type="hidden" v-model="loginType" name="loginType"/>
</form>
<div class="qrcode-img mb-3">
Binary file not shown.
Binary file not shown.