This commit is contained in:
2025-11-28 16:17:55 +08:00
commit 3b097b5f63
480 changed files with 117778 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
package org.springblade;
import org.mybatis.spring.annotation.MapperScan;
import org.springblade.common.constant.CommonConstant;
import org.springblade.core.launch.BladeApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
/**
* 启动器
*
* @author Chill
*/
@EnableScheduling
@EnableRedisHttpSession
@SpringBootApplication
public class Application {
public static void main(String[] args) {
BladeApplication.run(CommonConstant.APPLICATION_NAME, Application.class, args);
}
}

View File

@@ -0,0 +1,46 @@
package org.springblade.common.cache;
import org.springblade.core.tool.utils.StringPool;
/**
* 缓存名
*
* @author Chill
*/
public interface CacheNames {
/**
* 返回拼接后的key
*
* @param cacheKey 缓存key
* @param cacheKeyValue 缓存key值
* @return tenantKey
*/
static String cacheKey(String cacheKey, String cacheKeyValue) {
return cacheKey.concat(cacheKeyValue);
}
/**
* 返回租户格式的key
*
* @param tenantId 租户编号
* @param cacheKey 缓存key
* @param cacheKeyValue 缓存key值
* @return tenantKey
*/
static String tenantKey(String tenantId, String cacheKey, String cacheKeyValue) {
return tenantId.concat(StringPool.COLON).concat(cacheKey).concat(cacheKeyValue);
}
/**
* 验证码key
*/
String CAPTCHA_KEY = "blade:auth::blade:captcha:";
/**
* 登录失败key
*/
String USER_FAIL_KEY = "blade:user::blade:fail:";
}

View File

@@ -0,0 +1,101 @@
package org.springblade.common.cache;
import org.springblade.common.enums.DictBizEnum;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.utils.SpringUtil;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.modules.system.pojo.entity.DictBiz;
import org.springblade.modules.system.service.IDictBizService;
import java.util.List;
import static org.springblade.core.cache.constant.CacheConstant.DICT_CACHE;
/**
* 业务字典缓存工具类
*
* @author Chill
*/
public class DictBizCache {
private static final String DICT_ID = "dictBiz:id";
private static final String DICT_VALUE = "dictBiz:value";
private static final String DICT_LIST = "dictBiz:list";
private static final IDictBizService dictService;
static {
dictService = SpringUtil.getBean(IDictBizService.class);
}
/**
* 获取字典实体
*
* @param id 主键
* @return DictBiz
*/
public static DictBiz getById(Long id) {
String keyPrefix = DICT_ID.concat(StringPool.DASH).concat(AuthUtil.getTenantId()).concat(StringPool.COLON);
return CacheUtil.get(DICT_CACHE, keyPrefix, id, () -> dictService.getById(id));
}
/**
* 获取字典值
*
* @param code 字典编号枚举
* @param dictKey Integer型字典键
* @return String
*/
public static String getValue(DictBizEnum code, Integer dictKey) {
return getValue(code.getName(), dictKey);
}
/**
* 获取字典值
*
* @param code 字典编号
* @param dictKey Integer型字典键
* @return String
*/
public static String getValue(String code, Integer dictKey) {
String keyPrefix = DICT_VALUE.concat(StringPool.DASH).concat(AuthUtil.getTenantId()).concat(StringPool.COLON);
return CacheUtil.get(DICT_CACHE, keyPrefix + code + StringPool.COLON, String.valueOf(dictKey), () -> dictService.getValue(code, String.valueOf(dictKey)));
}
/**
* 获取字典值
*
* @param code 字典编号枚举
* @param dictKey String型字典键
* @return String
*/
public static String getValue(DictBizEnum code, String dictKey) {
return getValue(code.getName(), dictKey);
}
/**
* 获取字典值
*
* @param code 字典编号
* @param dictKey String型字典键
* @return String
*/
public static String getValue(String code, String dictKey) {
String keyPrefix = DICT_VALUE.concat(StringPool.DASH).concat(AuthUtil.getTenantId()).concat(StringPool.COLON);
return CacheUtil.get(DICT_CACHE, keyPrefix + code + StringPool.COLON, dictKey, () -> dictService.getValue(code, dictKey));
}
/**
* 获取字典集合
*
* @param code 字典编号
* @return List<DictBiz>
*/
public static List<DictBiz> getList(String code) {
String keyPrefix = DICT_LIST.concat(StringPool.DASH).concat(AuthUtil.getTenantId()).concat(StringPool.COLON);
return CacheUtil.get(DICT_CACHE, keyPrefix, code, () -> dictService.getList(code));
}
}

View File

@@ -0,0 +1,128 @@
package org.springblade.common.cache;
import org.springblade.common.enums.DictEnum;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.tool.utils.SpringUtil;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.modules.system.pojo.entity.Dict;
import org.springblade.modules.system.service.IDictService;
import java.util.List;
import java.util.Optional;
import static org.springblade.core.cache.constant.CacheConstant.DICT_CACHE;
/**
* 字典缓存工具类
*
* @author Chill
*/
public class DictCache {
private static final String DICT_ID = "dict:id:";
private static final String DICT_KEY = "dict:key:";
private static final String DICT_VALUE = "dict:value:";
private static final String DICT_LIST = "dict:list:";
private static final Boolean TENANT_MODE = Boolean.FALSE;
private static final IDictService dictService;
static {
dictService = SpringUtil.getBean(IDictService.class);
}
/**
* 获取字典实体
*
* @param id 主键
* @return Dict
*/
public static Dict getById(Long id) {
return CacheUtil.get(DICT_CACHE, DICT_ID, id, () -> dictService.getById(id), TENANT_MODE);
}
/**
* 获取字典值
*
* @param code 字典编号枚举
* @param dictValue 字典值
* @return String
*/
public static String getKey(DictEnum code, String dictValue) {
return getKey(code.getName(), dictValue);
}
/**
* 获取字典键
*
* @param code 字典编号
* @param dictValue 字典值
* @return String
*/
public static String getKey(String code, String dictValue) {
return CacheUtil.get(DICT_CACHE, DICT_KEY + code + StringPool.COLON, dictValue, () -> {
List<Dict> list = getList(code);
Optional<String> key = list.stream().filter(
dict -> dict.getDictValue().equalsIgnoreCase(dictValue)
).map(Dict::getDictKey).findFirst();
return key.orElse(StringPool.EMPTY);
}, TENANT_MODE);
}
/**
* 获取字典值
*
* @param code 字典编号枚举
* @param dictKey Integer型字典键
* @return String
*/
public static String getValue(DictEnum code, Integer dictKey) {
return getValue(code.getName(), dictKey);
}
/**
* 获取字典值
*
* @param code 字典编号
* @param dictKey Integer型字典键
* @return String
*/
public static String getValue(String code, Integer dictKey) {
return CacheUtil.get(DICT_CACHE, DICT_VALUE + code + StringPool.COLON, String.valueOf(dictKey), () -> dictService.getValue(code, String.valueOf(dictKey)), TENANT_MODE);
}
/**
* 获取字典值
*
* @param code 字典编号枚举
* @param dictKey String型字典键
* @return String
*/
public static String getValue(DictEnum code, String dictKey) {
return getValue(code.getName(), dictKey);
}
/**
* 获取字典值
*
* @param code 字典编号
* @param dictKey String型字典键
* @return String
*/
public static String getValue(String code, String dictKey) {
return CacheUtil.get(DICT_CACHE, DICT_VALUE + code + StringPool.COLON, dictKey, () -> dictService.getValue(code, dictKey), TENANT_MODE);
}
/**
* 获取字典集合
*
* @param code 字典编号
* @return List<Dict>
*/
public static List<Dict> getList(String code) {
return CacheUtil.get(DICT_CACHE, DICT_LIST, code, () -> dictService.getList(code), TENANT_MODE);
}
}

View File

@@ -0,0 +1,47 @@
package org.springblade.common.cache;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.tool.utils.SpringUtil;
import org.springblade.modules.system.pojo.entity.Param;
import org.springblade.modules.system.service.IParamService;
import static org.springblade.core.cache.constant.CacheConstant.PARAM_CACHE;
/**
* 参数缓存工具类
*
* @author Chill
*/
public class ParamCache {
private static final String PARAM_ID = "param:id:";
private static final String PARAM_VALUE = "param:value:";
private static final IParamService paramService;
static {
paramService = SpringUtil.getBean(IParamService.class);
}
/**
* 获取参数实体
*
* @param id 主键
* @return Param
*/
public static Param getById(Long id) {
return CacheUtil.get(PARAM_CACHE, PARAM_ID, id, () -> paramService.getById(id));
}
/**
* 获取参数配置
*
* @param paramKey 参数值
* @return String
*/
public static String getValue(String paramKey) {
return CacheUtil.get(PARAM_CACHE, PARAM_VALUE, paramKey, () -> paramService.getValue(paramKey));
}
}

View File

@@ -0,0 +1,42 @@
package org.springblade.common.cache;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.tool.utils.SpringUtil;
import org.springblade.modules.system.pojo.entity.Region;
import org.springblade.modules.system.service.IRegionService;
import static org.springblade.core.cache.constant.CacheConstant.SYS_CACHE;
/**
* 行政区划缓存工具类
*
* @author Chill
*/
public class RegionCache {
public static final String MAIN_CODE = "00";
public static final int PROVINCE_LEVEL = 1;
public static final int CITY_LEVEL = 2;
public static final int DISTRICT_LEVEL = 3;
public static final int TOWN_LEVEL = 4;
public static final int VILLAGE_LEVEL = 5;
private static final String REGION_CODE = "region:code:";
private static final IRegionService regionService;
static {
regionService = SpringUtil.getBean(IRegionService.class);
}
/**
* 获取行政区划实体
*
* @param code 区划编号
* @return Param
*/
public static Region getByCode(String code) {
return CacheUtil.get(SYS_CACHE, REGION_CODE, code, () -> regionService.getById(code));
}
}

View File

@@ -0,0 +1,302 @@
package org.springblade.common.cache;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.tool.utils.SpringUtil;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.modules.system.pojo.entity.*;
import org.springblade.modules.system.service.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import static org.springblade.core.cache.constant.CacheConstant.SYS_CACHE;
/**
* 系统缓存
*
* @author Chill
*/
public class SysCache {
private static final String MENU_ID = "menu:id:";
private static final String DEPT_ID = "dept:id:";
private static final String DEPT_NAME = "dept:name:";
private static final String DEPT_NAME_FUZZY = "dept:nameFuzzy:";
private static final String DEPT_NAME_ID = "deptName:id:";
private static final String DEPT_NAMES_ID = "deptNames:id:";
private static final String DEPT_CHILD_ID = "deptChild:id:";
private static final String DEPT_CHILDIDS_ID = "deptChildIds:id:";
private static final String POST_ID = "post:id:";
private static final String POST_NAME = "post:name:";
private static final String POST_NAME_FUZZY = "post:nameFuzzy:";
private static final String POST_NAME_ID = "postName:id:";
private static final String POST_NAMES_ID = "postNames:id:";
private static final String ROLE_ID = "role:id:";
private static final String ROLE_NAME = "role:name:";
private static final String ROLE_NAME_ID = "roleName:id:";
private static final String ROLE_NAMES_ID = "roleNames:id:";
private static final String ROLE_ALIAS_ID = "roleAlias:id:";
private static final String ROLE_ALIASES_ID = "roleAliases:id:";
public static final String TENANT_ID = "tenant:id:";
public static final String TENANT_TENANT_ID = "tenant:tenantId:";
public static final String TENANT_PACKAGE_ID = "tenant:packageId:";
private static final IMenuService menuService;
private static final IDeptService deptService;
private static final IPostService postService;
private static final IRoleService roleService;
private static final ITenantService tenantService;
private static final ITenantPackageService tenantPackageService;
static {
menuService = SpringUtil.getBean(IMenuService.class);
deptService = SpringUtil.getBean(IDeptService.class);
postService = SpringUtil.getBean(IPostService.class);
roleService = SpringUtil.getBean(IRoleService.class);
tenantService = SpringUtil.getBean(ITenantService.class);
tenantPackageService = SpringUtil.getBean(ITenantPackageService.class);
}
/**
* 获取菜单
*
* @param id 主键
* @return 菜单
*/
public static Menu getMenu(Long id) {
return CacheUtil.get(SYS_CACHE, MENU_ID, id, () -> menuService.getById(id));
}
/**
* 获取部门
*
* @param id 主键
* @return 部门
*/
public static Dept getDept(Long id) {
return CacheUtil.get(SYS_CACHE, DEPT_ID, id, () -> deptService.getById(id));
}
/**
* 获取部门id
*
* @param tenantId 租户id
* @param deptNames 部门名
* @return 部门id
*/
public static String getDeptIds(String tenantId, String deptNames) {
return CacheUtil.get(SYS_CACHE, DEPT_NAME, tenantId + StringPool.DASH + deptNames, () -> deptService.getDeptIds(tenantId, deptNames));
}
/**
* 获取部门id
*
* @param tenantId 租户id
* @param deptNames 部门名模糊查询
* @return 部门id
*/
public static String getDeptIdsByFuzzy(String tenantId, String deptNames) {
return CacheUtil.get(SYS_CACHE, DEPT_NAME_FUZZY, tenantId + StringPool.DASH + deptNames, () -> deptService.getDeptIdsByFuzzy(tenantId, deptNames));
}
/**
* 获取部门名
*
* @param id 主键
* @return 部门名
*/
public static String getDeptName(Long id) {
return CacheUtil.get(SYS_CACHE, DEPT_NAME_ID, id, () -> deptService.getById(id).getDeptName());
}
/**
* 获取部门名集合
*
* @param deptIds 主键集合
* @return 部门名
*/
public static List<String> getDeptNames(String deptIds) {
return CacheUtil.get(SYS_CACHE, DEPT_NAMES_ID, deptIds, () -> deptService.getDeptNames(deptIds));
}
/**
* 获取子部门集合
*
* @param deptId 主键
* @return 子部门
*/
public static List<Dept> getDeptChild(Long deptId) {
return CacheUtil.get(SYS_CACHE, DEPT_CHILD_ID, deptId, () -> deptService.getDeptChild(deptId));
}
/**
* 获取子部门ID集合
*
* @param deptId 主键
* @return 子部门ID
*/
public static List<Long> getDeptChildIds(Long deptId) {
if (deptId == null) {
return null;
}
List<Long> deptIdList = CacheUtil.get(SYS_CACHE, DEPT_CHILDIDS_ID, deptId, List.class);
if (deptIdList == null) {
deptIdList = new ArrayList<>();
List<Dept> deptChild = getDeptChild(deptId);
if (deptChild != null) {
List<Long> collect = deptChild.stream().map(Dept::getId).collect(Collectors.toList());
deptIdList.addAll(collect);
}
deptIdList.add(deptId);
CacheUtil.put(SYS_CACHE, DEPT_CHILDIDS_ID, deptId, deptIdList);
}
return deptIdList;
}
/**
* 获取岗位
*
* @param id 主键
* @return
*/
public static Post getPost(Long id) {
return CacheUtil.get(SYS_CACHE, POST_ID, id, () -> postService.getById(id));
}
/**
* 获取岗位id
*
* @param tenantId 租户id
* @param postNames 岗位名
* @return
*/
public static String getPostIds(String tenantId, String postNames) {
return CacheUtil.get(SYS_CACHE, POST_NAME, tenantId + StringPool.DASH + postNames, () -> postService.getPostIds(tenantId, postNames));
}
/**
* 获取岗位id
*
* @param tenantId 租户id
* @param postNames 岗位名模糊查询
* @return
*/
public static String getPostIdsByFuzzy(String tenantId, String postNames) {
return CacheUtil.get(SYS_CACHE, POST_NAME_FUZZY, tenantId + StringPool.DASH + postNames, () -> postService.getPostIdsByFuzzy(tenantId, postNames));
}
/**
* 获取岗位名
*
* @param id 主键
* @return 岗位名
*/
public static String getPostName(Long id) {
return CacheUtil.get(SYS_CACHE, POST_NAME_ID, id, () -> postService.getById(id).getPostName());
}
/**
* 获取岗位名集合
*
* @param postIds 主键集合
* @return 岗位名
*/
public static List<String> getPostNames(String postIds) {
return CacheUtil.get(SYS_CACHE, POST_NAMES_ID, postIds, () -> postService.getPostNames(postIds));
}
/**
* 获取角色
*
* @param id 主键
* @return Role
*/
public static Role getRole(Long id) {
return CacheUtil.get(SYS_CACHE, ROLE_ID, id, () -> roleService.getById(id));
}
/**
* 获取角色id
*
* @param tenantId 租户id
* @param roleNames 角色名
* @return
*/
public static String getRoleIds(String tenantId, String roleNames) {
return CacheUtil.get(SYS_CACHE, ROLE_NAME, tenantId + StringPool.DASH + roleNames, () -> roleService.getRoleIds(tenantId, roleNames));
}
/**
* 获取角色名
*
* @param id 主键
* @return 角色名
*/
public static String getRoleName(Long id) {
return CacheUtil.get(SYS_CACHE, ROLE_NAME_ID, id, () -> roleService.getById(id).getRoleName());
}
/**
* 获取角色名集合
*
* @param roleIds 主键集合
* @return 角色名
*/
public static List<String> getRoleNames(String roleIds) {
return CacheUtil.get(SYS_CACHE, ROLE_NAMES_ID, roleIds, () -> roleService.getRoleNames(roleIds));
}
/**
* 获取角色别名
*
* @param id 主键
* @return 角色别名
*/
public static String getRoleAlias(Long id) {
return CacheUtil.get(SYS_CACHE, ROLE_ALIAS_ID, id, () -> roleService.getById(id).getRoleAlias());
}
/**
* 获取角色别名集合
*
* @param roleIds 主键集合
* @return 角色别名
*/
public static List<String> getRoleAliases(String roleIds) {
return CacheUtil.get(SYS_CACHE, ROLE_ALIASES_ID, roleIds, () -> roleService.getRoleAliases(roleIds));
}
/**
* 获取租户
*
* @param id 主键
* @return Tenant
*/
public static Tenant getTenant(Long id) {
return CacheUtil.get(SYS_CACHE, TENANT_ID, id, () -> tenantService.getById(id), Boolean.FALSE);
}
/**
* 获取租户
*
* @param tenantId 租户id
* @return Tenant
*/
public static Tenant getTenant(String tenantId) {
return CacheUtil.get(SYS_CACHE, TENANT_TENANT_ID, tenantId, () -> tenantService.getByTenantId(tenantId), Boolean.FALSE);
}
/**
* 获取租户产品包
*
* @param tenantId 租户id
* @return Tenant
*/
public static TenantPackage getTenantPackage(String tenantId) {
Tenant tenant = getTenant(tenantId);
return CacheUtil.get(SYS_CACHE, TENANT_PACKAGE_ID, tenantId, () -> tenantPackageService.getById(tenant.getPackageId()), Boolean.FALSE);
}
}

View File

@@ -0,0 +1,62 @@
package org.springblade.common.cache;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.SpringUtil;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.system.pojo.entity.User;
import org.springblade.modules.system.service.IUserService;
import static org.springblade.core.cache.constant.CacheConstant.USER_CACHE;
import static org.springblade.core.launch.constant.FlowConstant.TASK_USR_PREFIX;
/**
* 系统缓存
*
* @author Chill
*/
public class UserCache {
private static final String USER_CACHE_ID = "user:id:";
private static final String USER_CACHE_ACCOUNT = "user:account:";
private static final IUserService userService;
static {
userService = SpringUtil.getBean(IUserService.class);
}
/**
* 根据任务用户id获取用户信息
*
* @param taskUserId 任务用户id
* @return
*/
public static User getUserByTaskUser(String taskUserId) {
Long userId = Func.toLong(StringUtil.removePrefix(taskUserId, TASK_USR_PREFIX));
return getUser(userId);
}
/**
* 获取用户
*
* @param userId 用户id
* @return
*/
public static User getUser(Long userId) {
return CacheUtil.get(USER_CACHE, USER_CACHE_ID, userId, () -> userService.getById(userId));
}
/**
* 获取用户
*
* @param tenantId 租户id
* @param account 账号名
* @return
*/
public static User getUser(String tenantId, String account) {
return CacheUtil.get(USER_CACHE, USER_CACHE_ACCOUNT, tenantId + StringPool.DASH + account, () -> userService.userByAccount(tenantId, account));
}
}

View File

@@ -0,0 +1,70 @@
package org.springblade.common.config;
import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.oauth2.endpoint.OAuth2SocialEndpoint;
import org.springblade.core.oauth2.endpoint.OAuth2TokenEndPoint;
import org.springblade.core.secure.registry.SecureRegistry;
import org.springblade.core.tool.utils.StringPool;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Blade配置
*
* @author Chill
*/
@Configuration(proxyBeanMethods = false)
public class BladeConfiguration implements WebMvcConfigurer {
/**
* 安全框架配置
*/
@Bean
public SecureRegistry secureRegistry() {
SecureRegistry secureRegistry = new SecureRegistry();
secureRegistry.setEnabled(true);
secureRegistry.excludePathPatterns("/blade-auth/**");
secureRegistry.excludePathPatterns("/blade-system/tenant/info");
secureRegistry.excludePathPatterns("/blade-flow/process/resource-view");
secureRegistry.excludePathPatterns("/blade-flow/process/diagram-view");
secureRegistry.excludePathPatterns("/blade-flow/manager/check-upload");
secureRegistry.excludePathPatterns("/doc.html");
secureRegistry.excludePathPatterns("/swagger-ui.html");
secureRegistry.excludePathPatterns("/static/**");
secureRegistry.excludePathPatterns("/webjars/**");
secureRegistry.excludePathPatterns("/swagger-resources/**");
secureRegistry.excludePathPatterns("/druid/**");
return secureRegistry;
}
/**
* 跨域配置
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/cors/**")
.allowedOriginPatterns("*")
.allowedHeaders("*")
.allowedMethods("*")
.maxAge(3600)
.allowCredentials(true);
}
/**
* 给OAuth2服务端添加前缀
*/
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.addPathPrefix(StringPool.SLASH + AppConstant.APPLICATION_AUTH_NAME,
c -> c.isAnnotationPresent(RestController.class) && (
OAuth2TokenEndPoint.class.equals(c) || OAuth2SocialEndpoint.class.equals(c))
);
}
}

View File

@@ -0,0 +1,28 @@
package org.springblade.common.config;
import lombok.AllArgsConstructor;
import org.springblade.common.handler.BladeScopeModelHandler;
import org.springblade.core.datascope.handler.ScopeModelHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* Blade处理器自动配置
*
* @author Chill
*/
@Configuration(proxyBeanMethods = false)
@AllArgsConstructor
public class BladeHandlerConfiguration {
private final JdbcTemplate jdbcTemplate;
@Bean
public ScopeModelHandler scopeModelHandler() {
return new BladeScopeModelHandler(jdbcTemplate);
}
}

View File

@@ -0,0 +1,43 @@
package org.springblade.common.config;
import lombok.AllArgsConstructor;
import org.springblade.common.event.ApiLogListener;
import org.springblade.common.event.ErrorLogListener;
import org.springblade.common.event.UsualLogListener;
import org.springblade.core.launch.props.BladeProperties;
import org.springblade.core.launch.server.ServerInfo;
import org.springblade.modules.system.service.ILogService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 日志工具自动配置
*
* @author Chill
*/
@Configuration(proxyBeanMethods = false)
@AllArgsConstructor
public class BladeLogConfiguration {
private final ILogService logService;
private final ServerInfo serverInfo;
private final BladeProperties bladeProperties;
@Bean(name = "apiLogListener")
public ApiLogListener apiLogListener() {
return new ApiLogListener(logService, serverInfo, bladeProperties);
}
@Bean(name = "errorEventListener")
public ErrorLogListener errorEventListener() {
return new ErrorLogListener(logService, serverInfo, bladeProperties);
}
@Bean(name = "usualEventListener")
public UsualLogListener usualEventListener() {
return new UsualLogListener(logService, serverInfo, bladeProperties);
}
}

View File

@@ -0,0 +1,26 @@
package org.springblade.common.config;
import org.springblade.common.filter.PreviewFilter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 演示配置类
*
* @author Chill
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "blade.preview.enabled", havingValue = "true")
public class BladePreviewConfiguration {
/**
* 演示模式配置
*/
@Bean
public PreviewFilter previewFilter() {
return new PreviewFilter();
}
}

View File

@@ -0,0 +1,28 @@
package org.springblade.common.config;
import org.springblade.core.report.datasource.ReportDataSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
/**
* 报表配置类
*
* @author Chill
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "report.enabled", havingValue = "true", matchIfMissing = true)
public class BladeReportConfiguration {
/**
* 自定义报表可选数据源
*/
@Bean
public ReportDataSource reportDataSource(DataSource dataSource) {
return new ReportDataSource(dataSource);
}
}

View File

@@ -0,0 +1,46 @@
package org.springblade.common.config;
import lombok.AllArgsConstructor;
import org.springblade.core.launch.constant.AppConstant;
import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Swagger配置类
*
* @author Chill
*/
@Configuration(proxyBeanMethods = false)
@AllArgsConstructor
@ConditionalOnProperty(value = "swagger.enabled", havingValue = "true", matchIfMissing = true)
public class SwaggerConfiguration {
@Bean
public GroupedOpenApi authApi() {
return GroupedOpenApi.builder()
.group("授权模块")
.packagesToScan(AppConstant.BASE_PACKAGES + ".core.oauth2", AppConstant.BASE_PACKAGES + ".modules.auth")
.build();
}
@Bean
public GroupedOpenApi sysApi() {
return GroupedOpenApi.builder()
.group("系统模块")
.packagesToScan(AppConstant.BASE_PACKAGES + ".modules.system", AppConstant.BASE_PACKAGES + ".modules.resource")
.build();
}
@Bean
public GroupedOpenApi flowApi() {
// 创建并返回GroupedOpenApi对象
return GroupedOpenApi.builder()
.group("工作流模块")
.packagesToScan(AppConstant.BASE_PACKAGES + ".flow")
.build();
}
}

View File

@@ -0,0 +1,69 @@
package org.springblade.common.constant;
import org.springblade.core.launch.constant.AppConstant;
/**
* 通用常量
*
* @author Chill
*/
public interface CommonConstant {
/**
* app name
*/
String APPLICATION_NAME = AppConstant.APPLICATION_NAME_PREFIX + "api";
/**
* sword 系统名
*/
String SWORD_NAME = "sword";
/**
* saber 系统名
*/
String SABER_NAME = "saber";
/**
* 顶级父节点id
*/
Long TOP_PARENT_ID = 0L;
/**
* 顶级父节点名称
*/
String TOP_PARENT_NAME = "顶级";
/**
* 未封存状态值
*/
Integer NOT_SEALED_ID = 0;
/**
* 默认密码
*/
String DEFAULT_PASSWORD = "123456";
/**
* 默认密码参数值
*/
String DEFAULT_PARAM_PASSWORD = "account.initPassword";
/**
* 默认排序字段
*/
String SORT_FIELD = "sort";
/**
* 数据权限类型
*/
Integer DATA_SCOPE_CATEGORY = 1;
/**
* 接口权限类型
*/
Integer API_SCOPE_CATEGORY = 2;
}

View File

@@ -0,0 +1,166 @@
package org.springblade.common.constant;
import io.jsonwebtoken.Claims;
/**
* 通用常量信息
*
* @author ruoyi
*/
public class Constants {
/**
* UTF-8 字符集
*/
public static final String UTF8 = "UTF-8";
/**
* GBK 字符集
*/
public static final String GBK = "GBK";
/**
* http请求
*/
public static final String HTTP = "http://";
/**
* https请求
*/
public static final String HTTPS = "https://";
/**
* 通用成功标识
*/
public static final String SUCCESS = "0";
/**
* 通用失败标识
*/
public static final String FAIL = "1";
/**
* 登录成功
*/
public static final String LOGIN_SUCCESS = "Success";
/**
* 注销
*/
public static final String LOGOUT = "Logout";
/**
* 注册
*/
public static final String REGISTER = "Register";
/**
* 登录失败
*/
public static final String LOGIN_FAIL = "Error";
/**
* 验证码 redis key
*/
public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
/**
* 登录用户 redis key
*/
public static final String LOGIN_TOKEN_KEY = "login_tokens:";
/**
* 防重提交 redis key
*/
public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
/**
* 限流 redis key
*/
public static final String RATE_LIMIT_KEY = "rate_limit:";
/**
* 验证码有效期(分钟)
*/
public static final Integer CAPTCHA_EXPIRATION = 2;
/**
* 令牌
*/
public static final String TOKEN = "token";
/**
* 令牌前缀
*/
public static final String TOKEN_PREFIX = "Bearer ";
/**
* 令牌前缀
*/
public static final String LOGIN_USER_KEY = "login_user_key";
/**
* 用户ID
*/
public static final String JWT_USERID = "userid";
/**
* 用户名称
*/
public static final String JWT_USERNAME = Claims.SUBJECT;
/**
* 用户头像
*/
public static final String JWT_AVATAR = "avatar";
/**
* 创建时间
*/
public static final String JWT_CREATED = "created";
/**
* 用户权限
*/
public static final String JWT_AUTHORITIES = "authorities";
/**
* 参数管理 cache key
*/
public static final String SYS_CONFIG_KEY = "sys_config:";
/**
* 字典管理 cache key
*/
public static final String SYS_DICT_KEY = "sys_dict:";
/**
* 资源映射路径 前缀
*/
public static final String RESOURCE_PREFIX = "/profile";
/**
* RMI 远程方法调用
*/
public static final String LOOKUP_RMI = "rmi:";
/**
* LDAP 远程方法调用
*/
public static final String LOOKUP_LDAP = "ldap:";
/**
* LDAPS 远程方法调用
*/
public static final String LOOKUP_LDAPS = "ldaps:";
/**
* 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
*/
public static final String[] JOB_WHITELIST_STR = {"com.ruoyi"};
/**
* 定时任务违规的字符
*/
public static final String[] JOB_ERROR_STR = {"java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
"org.springframework", "org.apache", "com.ruoyi.common.utils.file"};
}

View File

@@ -0,0 +1,23 @@
package org.springblade.common.constant;
/**
* 字典常量.
*
* @author zhuangqian
*/
public interface DictConstant {
String SEX_CODE = "sex";
String NOTICE_CODE = "notice";
String MENU_CATEGORY_CODE = "menu_category";
String BUTTON_FUNC_CODE = "button_func";
String YES_NO_CODE = "yes_no";
String FLOW_CATEGORY_CODE = "flow_category";
}

View File

@@ -0,0 +1,78 @@
package org.springblade.common.constant;
import org.springblade.core.launch.constant.AppConstant;
/**
* 启动常量
*
* @author Chill
*/
public interface LauncherConstant {
/**
* sentinel dev 地址
*/
String SENTINEL_DEV_ADDR = "127.0.0.1:8858";
/**
* sentinel prod 地址
*/
String SENTINEL_PROD_ADDR = "10.211.55.5:8858";
/**
* sentinel test 地址
*/
String SENTINEL_TEST_ADDR = "172.30.0.58:8858";
/**
* elk dev 地址
*/
String ELK_DEV_ADDR = "127.0.0.1:9000";
/**
* elk prod 地址
*/
String ELK_PROD_ADDR = "172.30.0.58:9000";
/**
* elk test 地址
*/
String ELK_TEST_ADDR = "172.30.0.58:9000";
/**
* 动态获取sentinel地址
*
* @param profile 环境变量
* @return addr
*/
static String sentinelAddr(String profile) {
switch (profile) {
case (AppConstant.PROD_CODE):
return SENTINEL_PROD_ADDR;
case (AppConstant.TEST_CODE):
return SENTINEL_TEST_ADDR;
default:
return SENTINEL_DEV_ADDR;
}
}
/**
* 动态获取elk地址
*
* @param profile 环境变量
* @return addr
*/
static String elkAddr(String profile) {
switch (profile) {
case (AppConstant.PROD_CODE):
return ELK_PROD_ADDR;
case (AppConstant.TEST_CODE):
return ELK_TEST_ADDR;
default:
return ELK_DEV_ADDR;
}
}
}

View File

@@ -0,0 +1,51 @@
package org.springblade.common.constant;
import java.util.Arrays;
import java.util.List;
/**
* 租户常量
*
* @author Chill
*/
public interface TenantConstant {
/**
* 租户默认密码KEY
*/
String PASSWORD_KEY = "tenant.default.password";
/**
* 租户默认账号额度KEY
*/
String ACCOUNT_NUMBER_KEY = "tenant.default.accountNumber";
/**
* 租户默认菜单集合KEY
*/
String ACCOUNT_MENU_CODE_KEY = "tenant.default.menuCode";
/**
* 租户默认密码
*/
String DEFAULT_PASSWORD = "123456";
/**
* 租户授权码默认16位密钥
*/
String DES_KEY = "0000000000000000";
/**
* 租户默认账号额度
*/
Integer DEFAULT_ACCOUNT_NUMBER = -1;
/**
* 租户默认菜单集合
*/
List<String> MENU_CODES = Arrays.asList(
"desk", "flow", "work", "monitor", "resource", "role", "user", "dept", "dictbiz", "topmenu"
);
}

View File

@@ -0,0 +1,249 @@
package org.springblade.common.constant;
/**
* 用户常量信息
*
* @author ruoyi
*/
public class UserConstants
{
/**
* 平台内系统用户的唯一标志
*/
public static final String SYS_USER = "SYS_USER";
/** 正常状态 */
public static final String NORMAL = "0";
/** 异常状态 */
public static final String EXCEPTION = "1";
/** 用户封禁状态 */
public static final String USER_DISABLE = "1";
/** 角色封禁状态 */
public static final String ROLE_DISABLE = "1";
/** 部门正常状态 */
public static final String DEPT_NORMAL = "0";
/** 部门停用状态 */
public static final String DEPT_DISABLE = "1";
/** 字典正常状态 */
public static final String DICT_NORMAL = "0";
/** 是否为系统默认(是) */
public static final String YES = "Y";
public static final String NO = "N";
/** 是否菜单外链(是) */
public static final String YES_FRAME = "0";
/** 是否菜单外链(否) */
public static final String NO_FRAME = "1";
/** 菜单类型(目录) */
public static final String TYPE_DIR = "M";
/** 菜单类型(菜单) */
public static final String TYPE_MENU = "C";
/** 菜单类型(按钮) */
public static final String TYPE_BUTTON = "F";
/** Layout组件标识 */
public final static String LAYOUT = "Layout";
/** ParentView组件标识 */
public final static String PARENT_VIEW = "ParentView";
/** InnerLink组件标识 */
public final static String INNER_LINK = "InnerLink";
public final static String WEBSOCKET_HEARTBEAT = "-heartbeat-";
/** 校验返回结果码 */
public final static String UNIQUE = "0";
public final static String NOT_UNIQUE = "1";
/**
* 用户名长度限制
*/
public static final int USERNAME_MIN_LENGTH = 2;
public static final int USERNAME_MAX_LENGTH = 20;
/**
* 密码长度限制
*/
public static final int PASSWORD_MIN_LENGTH = 5;
public static final int PASSWORD_MAX_LENGTH = 20;
/**
* 各种业务单据的内定自动编码规则标识
*/
public static final String ITEM_TYPE_CODE ="ITEM_TYPE_CODE";
public static final String ITEM_CODE ="ITEM_CODE";
public static final String MACHINERY_TYPE_CODE="MACHINERY_TYPE_CODE";
public static final String TASK_CODE="TASK_CODE";
public static final String DEFECT_CODE = "DEFECT_CODE";
public static final String SN_CODE = "SN_CODE";
public static final String TRANS_ORDER_CODE ="TRANS_ORDER_CODE";
public static final String ITEMRECPT_CODE ="ITEMRECPT_CODE"; //物料采购入库
public static final String WM_RTVENDOR_CODE ="WM_RTVENDOR_CODE";//退回供应商
public static final String ISSUE_CODE ="ISSUE_CODE"; //生产领料
public static final String RTISSUE_CODE ="RTISSUE_CODE"; //生产退料
public static final String PRODUCTRECPT_CODE ="PRODUCTRECPT_CODE"; //产品入库
public static final String PRODUCTSALSE_CODE ="PRODUCTSALSE_CODE"; //销售出库
public static final String RTSALSE_CODE ="RTSALSE_CODE"; //销售退货
public static final String TRANSFER_CODE ="TRANSFER_CODE"; //移库
public static final String STOCKTAKING_CODE ="STOCKTAKING_CODE"; //盘库单
public static final String FEEDBACK_CODE ="FEEDBACK_CODE"; //报工单
/**
* 单据的状态类型
*/
public static final String ORDER_STATUS_PREPARE="PREPARE";
public static final String ORDER_STATUS_CONFIRMED="CONFIRMED";
public static final String ORDER_STATUS_APPROVING="APPROVING";
public static final String ORDER_STATUS_APPROVED="APPROVED";
public static final String ORDER_STATUS_FINISHED="FINISHED";
/**
* 维护类型
*/
public static final String MAINTEN_TYPE_REGULAR="REGULAR";
public static final String MAINTEN_TYPE_USAGE="USAGE";
/**
* 甘特图中的TASK类型
*/
public static final String GANTT_TASK_TYPE_TASK="task";
public static final String GANTT_TASK_TYPE_PROJECT="project";
/**
* 报表相关
*/
public static final String REPORT_PRINT_TYPE ="print";
public static final String REPORT_PDF_TYPE ="pdf";
public static final String REPORT_EXCEL_TYPE ="excel";
public static final String REPORT_WORD_TYPE ="word";
public static final String REPORT_JASPER_PATH="reports/jasper/";
/**
* 库存事务类型
*/
public static final String TRANSACTION_TYPE_ITEM_RECPT = "ITEM_RECPT"; //原材料接收入库
public static final String TRANSACTION_TYPE_ITEM_RTV = "ITEM_RTV"; //原材料退回供应商
public static final String TRANSACTION_TYPE_ITEM_ISSUE_OUT = "ITEM_ISSUE_OUT"; //生产领用-出库事务
public static final String TRANSACTION_TYPE_ITEM_ISSUE_IN = "ITEM_ISSUE_IN"; //生产领用-入库事务
public static final String TRANSACTION_TYPE_OUTSOURCE_ISSUE_OUT ="OUTSOURCE_ISSUE_OUT"; //外协领用-出库事务
public static final String TRANSACTION_TYPE_OUTSOURCE_RECPT_IN ="OUTSOURCE_RECPT_IN"; //外协入库-入库事务
public static final String TRANSACTION_TYPE_ITEM_RT_ISSUE_OUT = "ITEM_RT_ISSUE_OUT"; //生产退料-出库事务
public static final String TRANSACTION_TYPE_ITEM_RT_ISSUE_IN = "ITEM_RT_ISSUE_IN"; //生产退料-入库事务
public static final String TRANSACTION_TYPE_WAREHOUSE_TRANS_OUT = "TRANS_OUT"; //移库,移出
public static final String TRANSACTION_TYPE_WAREHOUSE_TRANS_IN = "TRANS_IN"; //移库,移入
public static final String TRANSACTION_TYPE_ITEM_CONSUME = "ITEM_CONSUME";//物料生产消耗
public static final String TRANSACTION_TYPE_PRODUCT_PRODUCE = "PRODUCT_PRODUCE";//产品生产
public static final String TRANSACTION_TYPE_PRODUCT_RECPT_OUT = "PRODUCT_RECPT_OUT"; //产品入库-出库事务
public static final String TRANSACTION_TYPE_PRODUCT_RECPT_IN = "PRODUCT_RECPT_IN"; //产品入库-入库事务
public static final String TRANSACTION_TYPE_PRODUCT_ISSUE = "PRODUCT_SALSE"; //销售出库
public static final String TRANSACTION_TYPE_PRODUCT_RS = "PRODUCT_RT"; //销售退货
/**
* 轮班方式
*/
public static final String CAL_SHIFT_TYPE_SINGLE="SINGLE";
public static final String CAL_SHIFT_TYPE_TWO="SHIFT_TWO";
public static final String CAL_SHIFT_TYPE_THREE="SHIFT_THREE";
public static final String CAL_SHIFT_NAME_DAY="白班";
public static final String CAL_SHIFT_NAME_NIGHT="夜班";
public static final String CAL_SHIFT_NAME_MID="中班";
public static final String CAL_SHIFT_METHOD_QUARTER="QUARTER";
public static final String CAL_SHIFT_METHOD_MONTH="MONTH";
public static final String CAL_SHIFT_METHOD_WEEK="WEEK";
public static final String CAL_SHIFT_METHOD_DAY="DAY";
/**
* 排班日历的查询方式
*/
public static final String CAL_QUERY_BY_TYPE="TYPE";
public static final String CAL_QUERY_BY_TEAM="TEAM";
public static final String CAL_QUERY_BY_USER="USER";
/**
* 生产投料单据的类型
*/
public static final String TASK_ISSUE_DOC_TYPE_ISSUE="ISSUE"; //领料单
public static final String TASK_ISSUE_DOC_TYPE_TRANS="TRANS"; //流转单
/**
* 检测单类型,这里的类型是大类
* 首检、末检等等是过程检验中的子分类
*/
public static final String QC_TYPE_IQC = "IQC"; //来料检验单
public static final String QC_TYPE_IPQC = "IPQC"; //过程检验单
public static final String QC_TYPE_OQC = "OQC"; //出货检验
/**
* 默认线边库对应的仓库、库区、库位编码
*/
public static final String VIRTUAL_WH ="XBK_VIRTUAL";
public static final String VIRTUAL_WS ="XBKKQ_VIRTUAL";
public static final String VIRTUAL_WA ="XBKKW_VIRTUAL";
/**
* 条码格式
*/
public static final String QR_CODE = "QR_CODE";
public static final String EAN_CODE = "EAN_CODE";
public static final String UPC_CODE = "UPC_CODE";
public static final String CODE39_CODE = "CODE39_CODE";
/**
* 条码类型
*/
public static final String BARCODE_TYPE_ITEM = "ITEM"; //物料
public static final String BARCODE_TYPE_PACKAGE = "PACKAGE"; //装箱单
public static final String BARCODE_TYPE_STOCK = "STOCK"; //库存
public static final String BARCODE_TYPE_MACHINERY = "MACHINERY"; //设备
public static final String BARCODE_TYPE_WORKSTATION = "WORKSTATION"; //工作站
public static final String BARCODE_TYPE_WAREHOUSE = "WAREHOUSE"; //仓库
public static final String BARCODE_TYPE_STORAGELOCATION = "LOCATION"; //库区
public static final String BARCODE_TYPE_STORAGEAREA = "AREA"; //库位
public static final String BARCODE_TYPE_TRANSORDER = "TRANSORDER"; //流转单
public static final String BARCODE_TYPE_CLIENT = "CLIENT"; //客户
public static final String BARCODE_TYPE_VENDOR = "VENDOR"; //供应商
public static final String BARCODE_TYPE_SN = "SN";
/**
* 消息状态
*/
public static final String MESSAGE_STATUS_UNREAD = "UNREAD"; //未读
public static final String MESSAGE_STATUS_READ = "READ";//已读
public static final String MESSAGE_STATUS_PROCEED = "PROCEED";//已处理
/**
* 库存盘点方式
*/
public static final String WM_STOCK_TAKING_TYPE_BLIND = "BLIND"; //盲盘
public static final String WM_STOCK_TAKING_TYPE_OPEN = "OPEN"; //明盘
/**
* 库存盘点结果
*/
public static final String WM_STOCK_TAKING_STATUS_LOSS = "LOSS";// 盘亏
public static final String WM_STOCK_TAKING_STATUS_PROFIT = "PROFIT"; //盘盈
public static final String WM_STOCK_TAKING_STATUS_NORMAL = "NORMAL"; //正常
}

View File

@@ -0,0 +1,44 @@
package org.springblade.common.enums;
public enum CycleMethodMnum {
CYCLE_METHOD_YEAR("YEAR", "按年"),
CYCLE_METHOD_MONTH("MONTH", "按月"),
CYCLE_METHOD_DAY("DAY", "按日"),
CYCLE_METHOD_HOUR("HOUR", "按小时"),
CYCLE_METHOD_MINUTE("MINUTE", "按分钟"),
CYCLE_METHOD_OTHER("OTHER", "其他");
private String code;
private String name;
CycleMethodMnum(String code, String name) {
this.code = code;
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static CycleMethodMnum getByCode(String code) {
for (CycleMethodMnum value : CycleMethodMnum.values()) {
if (value.getCode().equals(code)) {
return value;
}
}
return CYCLE_METHOD_OTHER;
}
}

View File

@@ -0,0 +1,24 @@
package org.springblade.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 业务字典枚举类
*
* @author Chill
*/
@Getter
@AllArgsConstructor
public enum DictBizEnum {
/**
* 测试
*/
TEST("test"),
;
final String name;
}

View File

@@ -0,0 +1,80 @@
package org.springblade.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 系统字典枚举类
*
* @author Chill
*/
@Getter
@AllArgsConstructor
public enum DictEnum {
/**
* 性别
*/
SEX("sex"),
/**
* 通知类型
*/
NOTICE("notice"),
/**
* 菜单类型
*/
MENU_CATEGORY("menu_category"),
/**
* 按钮功能
*/
BUTTON_FUNC("button_func"),
/**
* 是否
*/
YES_NO("yes_no"),
/**
* 流程类型
*/
FLOW("flow"),
/**
* 机构类型
*/
ORG_CATEGORY("org_category"),
/**
* 数据权限
*/
DATA_SCOPE_TYPE("data_scope_type"),
/**
* 接口权限
*/
API_SCOPE_TYPE("api_scope_type"),
/**
* 权限类型
*/
SCOPE_CATEGORY("scope_category"),
/**
* 对象存储类型
*/
OSS("oss"),
/**
* 短信服务类型
*/
SMS("sms"),
/**
* 岗位类型
*/
POST_CATEGORY("post_category"),
/**
* 行政区划
*/
REGION("region"),
/**
* 用户平台
*/
USER_TYPE("user_type"),
;
final String name;
}

View File

@@ -0,0 +1,42 @@
package org.springblade.common.enums;
public enum PartTypeEnum {
PART_TYPE_INPUTCHAR("INPUTCHAR", "传入字符", 0),
PART_TYPE_NOWDATE("NOWDATE", "当前日期", 1),
PART_TYPE_FIXCHAR("FIXCHAR", "固定字符", 2),
PART_TYPE_SERIALNO("SERIALNO", "流水号", 3),
PART_TYPE_OTHER("OTHER", "其他", 99);
private final String code;
private final String name;
private final Integer beanIndex;
PartTypeEnum(String code, String name, Integer beanIndex) {
this.code = code;
this.name = name;
this.beanIndex = beanIndex;
}
public String getCode() {
return code;
}
public String getName() {
return name;
}
public Integer getBeanIndex() {
return beanIndex;
}
public static PartTypeEnum getByCode(String code) {
for (PartTypeEnum value : PartTypeEnum.values()) {
if (value.getCode().equals(code)) {
return value;
}
}
return PART_TYPE_OTHER;
}
}

View File

@@ -0,0 +1,45 @@
package org.springblade.common.event;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.launch.props.BladeProperties;
import org.springblade.core.launch.server.ServerInfo;
import org.springblade.core.log.constant.EventConstant;
import org.springblade.core.log.event.ApiLogEvent;
import org.springblade.core.log.model.LogApi;
import org.springblade.core.log.utils.LogAbstractUtil;
import org.springblade.modules.system.service.ILogService;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import java.util.Map;
/**
* 异步监听日志事件
*
* @author Chill
*/
@Slf4j
@AllArgsConstructor
public class ApiLogListener {
private final ILogService logService;
private final ServerInfo serverInfo;
private final BladeProperties bladeProperties;
@Async
@Order
@EventListener(ApiLogEvent.class)
public void saveApiLog(ApiLogEvent event) {
Map<String, Object> source = (Map<String, Object>) event.getSource();
LogApi logApi = (LogApi) source.get(EventConstant.EVENT_LOG);
LogAbstractUtil.addOtherInfoToLog(logApi, bladeProperties, serverInfo);
logService.saveApiLog(logApi);
}
}

View File

@@ -0,0 +1,47 @@
package org.springblade.common.event;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.launch.props.BladeProperties;
import org.springblade.core.launch.server.ServerInfo;
import org.springblade.core.log.constant.EventConstant;
import org.springblade.core.log.event.ErrorLogEvent;
import org.springblade.core.log.model.LogError;
import org.springblade.core.log.utils.LogAbstractUtil;
import org.springblade.modules.system.service.ILogService;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import java.util.Map;
/**
* 异步监听错误日志事件
*
* @author Chill
*/
@Slf4j
@AllArgsConstructor
public class ErrorLogListener {
private final ILogService logService;
private final ServerInfo serverInfo;
private final BladeProperties bladeProperties;
@Async
@Order
@EventListener(ErrorLogEvent.class)
public void saveErrorLog(ErrorLogEvent event) {
try {
Map<String, Object> source = (Map<String, Object>) event.getSource();
LogError logError = (LogError) source.get(EventConstant.EVENT_LOG);
LogAbstractUtil.addOtherInfoToLog(logError, bladeProperties, serverInfo);
logService.saveErrorLog(logError);
} catch (Exception e) {
// 可以根据需要进行更多的异常处理,例如发送警报等
log.error("保存错误日志时发生异常", e);
}
}
}

View File

@@ -0,0 +1,43 @@
package org.springblade.common.event;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.launch.props.BladeProperties;
import org.springblade.core.launch.server.ServerInfo;
import org.springblade.core.log.constant.EventConstant;
import org.springblade.core.log.event.UsualLogEvent;
import org.springblade.core.log.model.LogUsual;
import org.springblade.core.log.utils.LogAbstractUtil;
import org.springblade.modules.system.service.ILogService;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import java.util.Map;
/**
* 异步监听日志事件
*
* @author Chill
*/
@Slf4j
@AllArgsConstructor
public class UsualLogListener {
private final ILogService logService;
private final ServerInfo serverInfo;
private final BladeProperties bladeProperties;
@Async
@Order
@EventListener(UsualLogEvent.class)
public void saveUsualLog(UsualLogEvent event) {
Map<String, Object> source = (Map<String, Object>) event.getSource();
LogUsual logUsual = (LogUsual) source.get(EventConstant.EVENT_LOG);
LogAbstractUtil.addOtherInfoToLog(logUsual, bladeProperties, serverInfo);
logService.saveUsualLog(logUsual);
}
}

View File

@@ -0,0 +1,52 @@
package org.springblade.common.filter;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* 演示过滤器
*
* @author Chill
*/
public class PreviewFilter implements Filter {
private static final List<String> KEYS = new ArrayList<>();
static {
KEYS.add("notice");
KEYS.add("process");
KEYS.add("work");
KEYS.add("token");
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String path = httpServletRequest.getServletPath();
String method = httpServletRequest.getMethod();
String get = "GET";
if (method.equals(get) || KEYS.stream().anyMatch(path::contains)) {
filterChain.doFilter(servletRequest, servletResponse);
} else {
throw new RuntimeException("演示环境暂时无法操作!");
}
}
@Override
public void destroy() {
}
}

View File

@@ -0,0 +1,106 @@
package org.springblade.common.handler;
import lombok.RequiredArgsConstructor;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.datascope.constant.DataScopeConstant;
import org.springblade.core.datascope.handler.ScopeModelHandler;
import org.springblade.core.datascope.model.DataScopeModel;
import org.springblade.core.tool.utils.CollectionUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.springblade.core.cache.constant.CacheConstant.SYS_CACHE;
/**
* BladeScopeModelHandler
*
* @author Chill
*/
//若开启动态数据源功能,则加上@Master注解指定权限数据库为主库
//@Master
@RequiredArgsConstructor
public class BladeScopeModelHandler implements ScopeModelHandler {
private static final String SCOPE_CACHE_CODE = "dataScope:code:";
private static final String SCOPE_CACHE_CLASS = "dataScope:class:";
private static final String DEPT_CACHE_ANCESTORS = "dept:ancestors:";
private static final DataScopeModel SEARCHED_DATA_SCOPE_MODEL = new DataScopeModel(Boolean.TRUE);
private final JdbcTemplate jdbcTemplate;
/**
* 获取数据权限
*
* @param mapperId 数据权限mapperId
* @param roleId 用户角色集合
* @return DataScopeModel
*/
@Override
public DataScopeModel getDataScopeByMapper(String mapperId, String roleId) {
List<Object> args = new ArrayList<>(Collections.singletonList(mapperId));
List<Long> roleIds = Func.toLongList(roleId);
args.addAll(roleIds);
// 增加searched字段防止未配置的参数重复读库导致缓存击穿
// 后续若有新增配置则会清空缓存重新加载
DataScopeModel dataScope = CacheUtil.get(SYS_CACHE, SCOPE_CACHE_CLASS, mapperId + StringPool.COLON + roleId, DataScopeModel.class, Boolean.FALSE);
if (dataScope == null || !dataScope.getSearched()) {
List<DataScopeModel> list = jdbcTemplate.query(DataScopeConstant.dataByMapper(roleIds.size()), args.toArray(), new BeanPropertyRowMapper<>(DataScopeModel.class));
if (CollectionUtil.isNotEmpty(list)) {
dataScope = list.iterator().next();
dataScope.setSearched(Boolean.TRUE);
} else {
dataScope = SEARCHED_DATA_SCOPE_MODEL;
}
CacheUtil.put(SYS_CACHE, SCOPE_CACHE_CLASS, mapperId + StringPool.COLON + roleId, dataScope, Boolean.FALSE);
}
return StringUtil.isNotBlank(dataScope.getResourceCode()) ? dataScope : null;
}
/**
* 获取数据权限
*
* @param code 数据权限资源编号
* @return DataScopeModel
*/
@Override
public DataScopeModel getDataScopeByCode(String code) {
DataScopeModel dataScope = CacheUtil.get(SYS_CACHE, SCOPE_CACHE_CODE, code, DataScopeModel.class, Boolean.FALSE);
// 增加searched字段防止未配置的参数重复读库导致缓存击穿
// 后续若有新增配置则会清空缓存重新加载
if (dataScope == null || !dataScope.getSearched()) {
List<DataScopeModel> list = jdbcTemplate.query(DataScopeConstant.DATA_BY_CODE, new Object[]{code}, new BeanPropertyRowMapper<>(DataScopeModel.class));
if (CollectionUtil.isNotEmpty(list)) {
dataScope = list.iterator().next();
dataScope.setSearched(Boolean.TRUE);
} else {
dataScope = SEARCHED_DATA_SCOPE_MODEL;
}
CacheUtil.put(SYS_CACHE, SCOPE_CACHE_CODE, code, dataScope, Boolean.FALSE);
}
return StringUtil.isNotBlank(dataScope.getResourceCode()) ? dataScope : null;
}
/**
* 获取部门子级
*
* @param deptId 部门id
* @return deptIds
*/
@Override
public List<Long> getDeptAncestors(Long deptId) {
List ancestors = CacheUtil.get(SYS_CACHE, DEPT_CACHE_ANCESTORS, deptId, List.class);
if (CollectionUtil.isEmpty(ancestors)) {
ancestors = jdbcTemplate.queryForList(DataScopeConstant.DATA_BY_DEPT, new Object[]{deptId}, Long.class);
CacheUtil.put(SYS_CACHE, DEPT_CACHE_ANCESTORS, deptId, ancestors);
}
return ancestors;
}
}

View File

@@ -0,0 +1,29 @@
package org.springblade.common.launch;
import org.springblade.common.constant.LauncherConstant;
import org.springblade.core.auto.service.AutoService;
import org.springblade.core.launch.service.LauncherService;
import org.springblade.core.launch.utils.PropsUtil;
import org.springframework.boot.builder.SpringApplicationBuilder;
import java.util.Properties;
/**
* 启动参数拓展
*
* @author smallchil
*/
@AutoService(LauncherService.class)
public class LauncherServiceImpl implements LauncherService {
@Override
public void launcher(SpringApplicationBuilder builder, String appName, String profile, boolean isLocalDev) {
Properties props = System.getProperties();
PropsUtil.setProperty(props, "spring.cloud.sentinel.transport.dashboard", LauncherConstant.sentinelAddr(profile));
PropsUtil.setProperty(props, "spring.datasource.dynamic.enabled", "false");
// 开启elk日志
//PropsUtil.setProperty(props, "blade.log.elk.destination", LauncherConstant.elkAddr(profile));
}
}

View File

@@ -0,0 +1,11 @@
package org.springblade.common.utils;
/**
* 通用工具类
*
* @author Chill
*/
public class CommonUtil {
}

View File

@@ -0,0 +1,187 @@
package org.springblade.common.utils;
import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;
import org.apache.commons.lang3.time.DateFormatUtils;
/**
* 时间工具类
*
* @author ruoyi
*/
public class DateUtils extends org.apache.commons.lang3.time.DateUtils
{
public static String YYYY = "yyyy";
public static String YYYY_MM = "yyyy-MM";
public static String YYYY_MM_DD = "yyyy-MM-dd";
public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
private static String[] parsePatterns = {
"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
/**
* 获取当前Date型日期
*
* @return Date() 当前日期
*/
public static Date getNowDate()
{
return new Date();
}
/**
* 获取当前日期, 默认格式为yyyy-MM-dd
*
* @return String
*/
public static String getDate()
{
return dateTimeNow(YYYY_MM_DD);
}
public static final String getTime()
{
return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
}
public static final String dateTimeNow()
{
return dateTimeNow(YYYYMMDDHHMMSS);
}
public static final String dateTimeNow(final String format)
{
return parseDateToStr(format, new Date());
}
public static final String dateTime(final Date date)
{
return parseDateToStr(YYYY_MM_DD, date);
}
public static final String parseDateToStr(final String format, final Date date)
{
return new SimpleDateFormat(format).format(date);
}
public static final Date dateTime(final String format, final String ts)
{
try
{
return new SimpleDateFormat(format).parse(ts);
}
catch (ParseException e)
{
throw new RuntimeException(e);
}
}
/**
* 日期路径 即年/月/日 如2018/08/08
*/
public static final String datePath()
{
Date now = new Date();
return DateFormatUtils.format(now, "yyyy/MM/dd");
}
/**
* 日期路径 即年/月/日 如20180808
*/
public static final String dateTime()
{
Date now = new Date();
return DateFormatUtils.format(now, "yyyyMMdd");
}
/**
* 日期型字符串转化为日期 格式
*/
public static Date parseDate(Object str)
{
if (str == null)
{
return null;
}
try
{
return parseDate(str.toString(), parsePatterns);
}
catch (ParseException e)
{
return null;
}
}
/**
* 获取服务器启动时间
*/
public static Date getServerStartDate()
{
long time = ManagementFactory.getRuntimeMXBean().getStartTime();
return new Date(time);
}
/**
* 计算相差天数
*/
public static int differentDaysByMillisecond(Date date1, Date date2)
{
return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
}
/**
* 计算两个时间差
*/
public static String getDatePoor(Date endDate, Date nowDate)
{
long nd = 1000 * 24 * 60 * 60;
long nh = 1000 * 60 * 60;
long nm = 1000 * 60;
// long ns = 1000;
// 获得两个时间的毫秒时间差异
long diff = endDate.getTime() - nowDate.getTime();
// 计算差多少天
long day = diff / nd;
// 计算差多少小时
long hour = diff % nd / nh;
// 计算差多少分钟
long min = diff % nd % nh / nm;
// 计算差多少秒//输出结果
// long sec = diff % nd % nh % nm / ns;
return day + "" + hour + "小时" + min + "分钟";
}
/**
* 增加 LocalDateTime ==> Date
*/
public static Date toDate(LocalDateTime temporalAccessor)
{
ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
return Date.from(zdt.toInstant());
}
/**
* 增加 LocalDate ==> Date
*/
public static Date toDate(LocalDate temporalAccessor)
{
LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
return Date.from(zdt.toInstant());
}
}

View File

@@ -0,0 +1,584 @@
package org.springblade.common.utils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import cn.hutool.core.text.StrFormatter;
import org.springblade.common.constant.Constants;
import org.springframework.util.AntPathMatcher;
/**
* 字符串工具类
*
* @author ruoyi
*/
public class StringUtils extends org.apache.commons.lang3.StringUtils
{
/** 空字符串 */
private static final String NULLSTR = "";
/** 下划线 */
private static final char SEPARATOR = '_';
/**
* 获取参数不为空值
*
* @param value defaultValue 要判断的value
* @return value 返回值
*/
public static <T> T nvl(T value, T defaultValue)
{
return value != null ? value : defaultValue;
}
/**
* * 判断一个Collection是否为空 包含ListSetQueue
*
* @param coll 要判断的Collection
* @return true为空 false非空
*/
public static boolean isEmpty(Collection<?> coll)
{
return isNull(coll) || coll.isEmpty();
}
/**
* * 判断一个Collection是否非空包含ListSetQueue
*
* @param coll 要判断的Collection
* @return true非空 false
*/
public static boolean isNotEmpty(Collection<?> coll)
{
return !isEmpty(coll);
}
/**
* * 判断一个对象数组是否为空
*
* @param objects 要判断的对象数组
** @return true为空 false非空
*/
public static boolean isEmpty(Object[] objects)
{
return isNull(objects) || (objects.length == 0);
}
/**
* * 判断一个对象数组是否非空
*
* @param objects 要判断的对象数组
* @return true非空 false
*/
public static boolean isNotEmpty(Object[] objects)
{
return !isEmpty(objects);
}
/**
* * 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true为空 false非空
*/
public static boolean isEmpty(Map<?, ?> map)
{
return isNull(map) || map.isEmpty();
}
/**
* * 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true非空 false
*/
public static boolean isNotEmpty(Map<?, ?> map)
{
return !isEmpty(map);
}
/**
* * 判断一个字符串是否为空串
*
* @param str String
* @return true为空 false非空
*/
public static boolean isEmpty(String str)
{
return isNull(str) || NULLSTR.equals(str.trim());
}
/**
* * 判断一个字符串是否为非空串
*
* @param str String
* @return true非空串 false空串
*/
public static boolean isNotEmpty(String str)
{
return !isEmpty(str);
}
/**
* * 判断一个对象是否为空
*
* @param object Object
* @return true为空 false非空
*/
public static boolean isNull(Object object)
{
return object == null;
}
/**
* * 判断一个对象是否非空
*
* @param object Object
* @return true非空 false
*/
public static boolean isNotNull(Object object)
{
return !isNull(object);
}
/**
* * 判断一个对象是否是数组类型Java基本型别的数组
*
* @param object 对象
* @return true是数组 false不是数组
*/
public static boolean isArray(Object object)
{
return isNotNull(object) && object.getClass().isArray();
}
/**
* 去空格
*/
public static String trim(String str)
{
return (str == null ? "" : str.trim());
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @return 结果
*/
public static String substring(final String str, int start)
{
if (str == null)
{
return NULLSTR;
}
if (start < 0)
{
start = str.length() + start;
}
if (start < 0)
{
start = 0;
}
if (start > str.length())
{
return NULLSTR;
}
return str.substring(start);
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @param end 结束
* @return 结果
*/
public static String substring(final String str, int start, int end)
{
if (str == null)
{
return NULLSTR;
}
if (end < 0)
{
end = str.length() + end;
}
if (start < 0)
{
start = str.length() + start;
}
if (end > str.length())
{
end = str.length();
}
if (start > end)
{
return NULLSTR;
}
if (start < 0)
{
start = 0;
}
if (end < 0)
{
end = 0;
}
return str.substring(start, end);
}
/**
* 格式化文本, {} 表示占位符<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
* 例:<br>
* 通常使用format("this is {} for {}", "a", "b") -> this is a for b<br>
* 转义{} format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
* 转义\ format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
*
* @param template 文本模板,被替换的部分用 {} 表示
* @param params 参数值
* @return 格式化后的文本
*/
public static String format(String template, Object... params)
{
if (isEmpty(params) || isEmpty(template))
{
return template;
}
return StrFormatter.format(template, params);
}
/**
* 是否为http(s)://开头
*
* @param link 链接
* @return 结果
*/
public static boolean ishttp(String link)
{
return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS);
}
/**
* 字符串转set
*
* @param str 字符串
* @param sep 分隔符
* @return set集合
*/
public static final Set<String> str2Set(String str, String sep)
{
return new HashSet<String>(str2List(str, sep, true, false));
}
/**
* 字符串转list
*
* @param str 字符串
* @param sep 分隔符
* @param filterBlank 过滤纯空白
* @param trim 去掉首尾空白
* @return list集合
*/
public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim)
{
List<String> list = new ArrayList<String>();
if (StringUtils.isEmpty(str))
{
return list;
}
// 过滤空白字符串
if (filterBlank && StringUtils.isBlank(str))
{
return list;
}
String[] split = str.split(sep);
for (String string : split)
{
if (filterBlank && StringUtils.isBlank(string))
{
continue;
}
if (trim)
{
string = string.trim();
}
list.add(string);
}
return list;
}
/**
* 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写
*
* @param cs 指定字符串
* @param searchCharSequences 需要检查的字符串数组
* @return 是否包含任意一个字符串
*/
public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences)
{
if (isEmpty(cs) || isEmpty(searchCharSequences))
{
return false;
}
for (CharSequence testStr : searchCharSequences)
{
if (containsIgnoreCase(cs, testStr))
{
return true;
}
}
return false;
}
/**
* 驼峰转下划线命名
*/
public static String toUnderScoreCase(String str)
{
if (str == null)
{
return null;
}
StringBuilder sb = new StringBuilder();
// 前置字符是否大写
boolean preCharIsUpperCase = true;
// 当前字符是否大写
boolean curreCharIsUpperCase = true;
// 下一字符是否大写
boolean nexteCharIsUpperCase = true;
for (int i = 0; i < str.length(); i++)
{
char c = str.charAt(i);
if (i > 0)
{
preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
}
else
{
preCharIsUpperCase = false;
}
curreCharIsUpperCase = Character.isUpperCase(c);
if (i < (str.length() - 1))
{
nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
}
if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase)
{
sb.append(SEPARATOR);
}
else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase)
{
sb.append(SEPARATOR);
}
sb.append(Character.toLowerCase(c));
}
return sb.toString();
}
/**
* 是否包含字符串
*
* @param str 验证字符串
* @param strs 字符串组
* @return 包含返回true
*/
public static boolean inStringIgnoreCase(String str, String... strs)
{
if (str != null && strs != null)
{
for (String s : strs)
{
if (str.equalsIgnoreCase(trim(s)))
{
return true;
}
}
}
return false;
}
/**
* 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如HELLO_WORLD->HelloWorld
*
* @param name 转换前的下划线大写方式命名的字符串
* @return 转换后的驼峰式命名的字符串
*/
public static String convertToCamelCase(String name)
{
StringBuilder result = new StringBuilder();
// 快速检查
if (name == null || name.isEmpty())
{
// 没必要转换
return "";
}
else if (!name.contains("_"))
{
// 不含下划线,仅将首字母大写
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
// 用下划线将原始字符串分割
String[] camels = name.split("_");
for (String camel : camels)
{
// 跳过原始字符串中开头、结尾的下换线或双重下划线
if (camel.isEmpty())
{
continue;
}
// 首字母大写
result.append(camel.substring(0, 1).toUpperCase());
result.append(camel.substring(1).toLowerCase());
}
return result.toString();
}
/**
* 驼峰式命名法 例如user_name->userName
*/
public static String toCamelCase(String s)
{
if (s == null)
{
return null;
}
s = s.toLowerCase();
StringBuilder sb = new StringBuilder(s.length());
boolean upperCase = false;
for (int i = 0; i < s.length(); i++)
{
char c = s.charAt(i);
if (c == SEPARATOR)
{
upperCase = true;
}
else if (upperCase)
{
sb.append(Character.toUpperCase(c));
upperCase = false;
}
else
{
sb.append(c);
}
}
return sb.toString();
}
/**
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
*
* @param str 指定字符串
* @param strs 需要检查的字符串数组
* @return 是否匹配
*/
public static boolean matches(String str, List<String> strs)
{
if (isEmpty(str) || isEmpty(strs))
{
return false;
}
for (String pattern : strs)
{
if (isMatch(pattern, str))
{
return true;
}
}
return false;
}
/**
* 判断url是否与规则配置:
* ? 表示单个字符;
* * 表示一层路径内的任意字符串,不可跨层级;
* ** 表示任意层路径;
*
* @param pattern 匹配规则
* @param url 需要匹配的url
* @return
*/
public static boolean isMatch(String pattern, String url)
{
AntPathMatcher matcher = new AntPathMatcher();
return matcher.match(pattern, url);
}
@SuppressWarnings("unchecked")
public static <T> T cast(Object obj)
{
return (T) obj;
}
/**
* 数字左边补齐0使之达到指定长度。注意如果数字转换为字符串后长度大于size则只保留 最后size个字符。
*
* @param num 数字对象
* @param size 字符串指定长度
* @return 返回数字的字符串格式,该字符串为指定长度。
*/
public static final String padl(final Number num, final int size)
{
return padl(num.toString(), size, '0');
}
/**
* 字符串左补齐。如果原始字符串s长度大于size则只保留最后size个字符。
*
* @param s 原始字符串
* @param size 字符串指定长度
* @param c 用于补齐的字符
* @return 返回指定长度的字符串,由原字符串左补齐或截取得到。
*/
public static final String padl(final String s, final int size, final char c)
{
final StringBuilder sb = new StringBuilder(size);
if (s != null)
{
final int len = s.length();
if (s.length() <= size)
{
for (int i = size - len; i > 0; i--)
{
sb.append(c);
}
sb.append(s);
}
else
{
return s.substring(len - size, len);
}
}
else
{
for (int i = size; i > 0; i--)
{
sb.append(c);
}
}
return sb.toString();
}
}

View File

@@ -0,0 +1,141 @@
package org.springblade.job.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.job.pojo.entity.JobInfo;
import org.springblade.job.service.IJobInfoService;
import org.springblade.job.pojo.vo.JobInfoVO;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* 任务信息表 控制器
*
* @author BladeX
*/
@RestController
@AllArgsConstructor
@RequestMapping(AppConstant.APPLICATION_JOB_NAME + "/job-info")
@Tag(name = "任务信息表", description = "任务信息表接口")
public class JobInfoController extends BladeController {
private final IJobInfoService jobInfoService;
/**
* 任务信息表 详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@Operation(summary = "详情", description = "传入jobInfo")
public R<JobInfo> detail(JobInfo jobInfo) {
JobInfo detail = jobInfoService.getOne(Condition.getQueryWrapper(jobInfo));
return R.data(detail);
}
/**
* 任务信息表 分页
*/
@GetMapping("/list")
@ApiOperationSupport(order = 2)
@Operation(summary = "分页", description = "传入jobInfo")
public R<IPage<JobInfo>> list(@Parameter(hidden = true) @RequestParam Map<String, Object> jobInfo, Query query) {
IPage<JobInfo> pages = jobInfoService.page(Condition.getPage(query), Condition.getQueryWrapper(jobInfo, JobInfo.class));
return R.data(pages);
}
/**
* 任务信息表 自定义分页
*/
@GetMapping("/page")
@ApiOperationSupport(order = 3)
@Operation(summary = "分页", description = "传入jobInfo")
public R<IPage<JobInfoVO>> page(JobInfoVO jobInfo, Query query) {
IPage<JobInfoVO> pages = jobInfoService.selectJobInfoPage(Condition.getPage(query), jobInfo);
return R.data(pages);
}
/**
* 任务信息表 新增
*/
@PostMapping("/save")
@ApiOperationSupport(order = 4)
@Operation(summary = "新增", description = "传入jobInfo")
public R save(@Valid @RequestBody JobInfo jobInfo) {
return R.status(jobInfoService.save(jobInfo));
}
/**
* 任务信息表 修改
*/
@PostMapping("/update")
@ApiOperationSupport(order = 5)
@Operation(summary = "修改", description = "传入jobInfo")
public R update(@Valid @RequestBody JobInfo jobInfo) {
return R.status(jobInfoService.updateById(jobInfo));
}
/**
* 任务信息表 新增或修改
*/
@PostMapping("/submit")
@ApiOperationSupport(order = 6)
@Operation(summary = "新增或修改", description = "传入jobInfo")
public R submit(@Valid @RequestBody JobInfo jobInfo) {
return R.status(jobInfoService.submitAndSync(jobInfo));
}
/**
* 任务信息表 删除
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 7)
@Operation(summary = "删除", description = "传入ids")
public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status(jobInfoService.removeAndSync(Func.toLongList(ids)));
}
/**
* 任务信息表 变更状态
*/
@PostMapping("/change")
@ApiOperationSupport(order = 8)
@Operation(summary = "变更状态", description = "传入id与status")
public R change(@Parameter(description = "主键", required = true) @RequestParam Long id, @Parameter(description = "是否启用", required = true) @RequestParam Integer enable) {
return R.status(jobInfoService.changeServerJob(id, enable));
}
/**
* 运行服务
*/
@PostMapping("run")
@ApiOperationSupport(order = 9)
@Operation(summary = "运行服务", description = "传入jobInfoId")
public R run(@Parameter(description = "主键", required = true) @RequestParam Long id) {
return R.status(jobInfoService.runServerJob(id));
}
/**
* 任务信息数据同步
*/
@PostMapping("sync")
@ApiOperationSupport(order = 10)
@Operation(summary = "任务信息数据同步", description = "任务信息数据同步")
public R sync() {
return R.status(jobInfoService.sync());
}
}

View File

@@ -0,0 +1,139 @@
package org.springblade.job.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.job.pojo.entity.JobServer;
import org.springblade.job.service.IJobServerService;
import org.springblade.job.pojo.vo.JobServerVO;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* 任务服务表 控制器
*
* @author BladeX
*/
@RestController
@AllArgsConstructor
@RequestMapping(AppConstant.APPLICATION_JOB_NAME + "/job-server")
@Tag(name = "任务服务表", description = "任务服务表接口")
public class JobServerController extends BladeController {
private final IJobServerService jobServerService;
/**
* 任务服务表 详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@Operation(summary = "详情", description = "传入jobServer")
public R<JobServer> detail(JobServer jobServer) {
JobServer detail = jobServerService.getOne(Condition.getQueryWrapper(jobServer));
return R.data(detail);
}
/**
* 任务服务表 分页
*/
@GetMapping("/list")
@ApiOperationSupport(order = 2)
@Operation(summary = "分页", description = "传入jobServer")
public R<IPage<JobServer>> list(@Parameter(hidden = true) @RequestParam Map<String, Object> jobServer, Query query) {
IPage<JobServer> pages = jobServerService.page(Condition.getPage(query), Condition.getQueryWrapper(jobServer, JobServer.class));
return R.data(pages);
}
/**
* 任务服务表 自定义分页
*/
@GetMapping("/page")
@ApiOperationSupport(order = 3)
@Operation(summary = "分页", description = "传入jobServer")
public R<IPage<JobServerVO>> page(JobServerVO jobServer, Query query) {
IPage<JobServerVO> pages = jobServerService.selectJobServerPage(Condition.getPage(query), jobServer);
return R.data(pages);
}
/**
* 任务服务表 新增
*/
@PostMapping("/save")
@ApiOperationSupport(order = 4)
@Operation(summary = "新增", description = "传入jobServer")
public R save(@Valid @RequestBody JobServer jobServer) {
return R.status(jobServerService.save(jobServer));
}
/**
* 任务服务表 修改
*/
@PostMapping("/update")
@ApiOperationSupport(order = 5)
@Operation(summary = "修改", description = "传入jobServer")
public R update(@Valid @RequestBody JobServer jobServer) {
return R.status(jobServerService.updateById(jobServer));
}
/**
* 任务服务表 新增或修改
*/
@PostMapping("/submit")
@ApiOperationSupport(order = 6)
@Operation(summary = "新增或修改", description = "传入jobServer")
public R submit(@Valid @RequestBody JobServer jobServer) {
return R.status(jobServerService.submitAndSync(jobServer));
}
/**
* 任务服务表 删除
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 7)
@Operation(summary = "逻辑删除", description = "传入ids")
public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status(jobServerService.deleteLogic(Func.toLongList(ids)));
}
/**
* 应用服务信息 列表
*/
@GetMapping("/select")
@ApiOperationSupport(order = 8)
@Operation(summary = "应用服务信息", description = "应用服务信息")
public R select() {
List<JobServer> list = jobServerService.list();
list.forEach(jobServer -> jobServer.setJobAppName(
jobServer.getJobAppName() + StringPool.COLON + StringPool.SPACE + StringPool.LEFT_BRACKET +
jobServer.getJobServerName() + StringPool.SPACE + StringPool.DASH + StringPool.SPACE + jobServer.getJobServerUrl() + StringPool.RIGHT_BRACKET)
);
return R.data(list);
}
/**
* 任务服务数据同步
*/
@PostMapping("sync")
@ApiOperationSupport(order = 9)
@Operation(summary = "任务服务数据同步", description = "任务服务数据同步")
public R sync() {
jobServerService.list().forEach(jobServerService::sync);
return R.success("同步完毕");
}
}

View File

@@ -0,0 +1,27 @@
package org.springblade.job.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.job.pojo.entity.JobInfo;
import org.springblade.job.pojo.vo.JobInfoVO;
import java.util.List;
/**
* 任务信息表 Mapper 接口
*
* @author BladeX
*/
public interface JobInfoMapper extends BaseMapper<JobInfo> {
/**
* 自定义分页
*
* @param page
* @param jobInfo
* @return
*/
List<JobInfoVO> selectJobInfoPage(IPage page, JobInfoVO jobInfo);
}

View File

@@ -0,0 +1,52 @@
<?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 namespace="org.springblade.job.mapper.JobInfoMapper">
<!-- 通用查询映射结果 -->
<resultMap id="jobInfoResultMap" type="org.springblade.job.pojo.entity.JobInfo">
<result column="id" property="id"/>
<result column="job_server_id" property="jobServerId"/>
<result column="job_id" property="jobId"/>
<result column="job_name" property="jobName"/>
<result column="job_description" property="jobDescription"/>
<result column="job_params" property="jobParams"/>
<result column="time_expression_type" property="timeExpressionType"/>
<result column="time_expression" property="timeExpression"/>
<result column="execute_type" property="executeType"/>
<result column="processor_type" property="processorType"/>
<result column="processor_info" property="processorInfo"/>
<result column="max_instance_num" property="maxInstanceNum"/>
<result column="concurrency" property="concurrency"/>
<result column="instance_time_limit" property="instanceTimeLimit"/>
<result column="instance_retry_num" property="instanceRetryNum"/>
<result column="task_retry_num" property="taskRetryNum"/>
<result column="min_cpu_cores" property="minCpuCores"/>
<result column="min_memory_space" property="minMemorySpace"/>
<result column="min_disk_space" property="minDiskSpace"/>
<result column="designated_workers" property="designatedWorkers"/>
<result column="max_worker_count" property="maxWorkerCount"/>
<result column="notify_user_ids" property="notifyUserIds"/>
<result column="enable" property="enable"/>
<result column="dispatch_strategy" property="dispatchStrategy"/>
<result column="lifecycle" property="lifecycle"/>
<result column="alert_threshold" property="alertThreshold"/>
<result column="statistic_window_len" property="statisticWindowLen"/>
<result column="silence_window_len" property="silenceWindowLen"/>
<result column="log_type" property="logType"/>
<result column="log_level" property="logLevel"/>
<result column="extra" property="extra"/>
<result column="create_user" property="createUser"/>
<result column="create_dept" property="createDept"/>
<result column="create_time" property="createTime"/>
<result column="update_user" property="updateUser"/>
<result column="update_time" property="updateTime"/>
<result column="status" property="status"/>
<result column="is_deleted" property="isDeleted"/>
</resultMap>
<select id="selectJobInfoPage" resultMap="jobInfoResultMap">
select * from blade_job_info where is_deleted = 0
</select>
</mapper>

View File

@@ -0,0 +1,27 @@
package org.springblade.job.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.job.pojo.entity.JobServer;
import org.springblade.job.pojo.vo.JobServerVO;
import java.util.List;
/**
* 任务服务表 Mapper 接口
*
* @author BladeX
*/
public interface JobServerMapper extends BaseMapper<JobServer> {
/**
* 自定义分页
*
* @param page
* @param jobServer
* @return
*/
List<JobServerVO> selectJobServerPage(IPage page, JobServerVO jobServer);
}

View File

@@ -0,0 +1,27 @@
<?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 namespace="org.springblade.job.mapper.JobServerMapper">
<!-- 通用查询映射结果 -->
<resultMap id="jobServerResultMap" type="org.springblade.job.pojo.entity.JobServer">
<result column="id" property="id"/>
<result column="job_server_name" property="jobServerName"/>
<result column="job_server_url" property="jobServerUrl"/>
<result column="job_app_name" property="jobAppName"/>
<result column="job_app_password" property="jobAppPassword"/>
<result column="job_remark" property="jobRemark"/>
<result column="create_user" property="createUser"/>
<result column="create_dept" property="createDept"/>
<result column="create_time" property="createTime"/>
<result column="update_user" property="updateUser"/>
<result column="update_time" property="updateTime"/>
<result column="status" property="status"/>
<result column="is_deleted" property="isDeleted"/>
</resultMap>
<select id="selectJobServerPage" resultMap="jobServerResultMap">
select * from blade_job_server where is_deleted = 0
</select>
</mapper>

View File

@@ -0,0 +1,32 @@
package org.springblade.job.pojo.dto;
import lombok.Data;
import org.springblade.job.pojo.entity.JobInfo;
import org.springblade.job.pojo.entity.JobServer;
import tech.powerjob.client.PowerJobClient;
/**
* 任务数据DTO
*
* @author Chill
*/
@Data
public class JobDTO {
/**
* 任务信息类
*/
private JobInfo jobInfo;
/**
* 任务服务类
*/
private JobServer jobServer;
/**
* 任务客户端类
*/
private PowerJobClient powerJobClient;
}

View File

@@ -0,0 +1,178 @@
package org.springblade.job.pojo.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.mp.base.BaseEntity;
import java.io.Serial;
import java.math.BigDecimal;
/**
* 任务信息表 实体类
*
* @author BladeX
*/
@Data
@TableName("blade_job_info")
@EqualsAndHashCode(callSuper = true)
@Schema(description = "任务信息表")
public class JobInfo extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 任务服务ID
*/
@Schema(description = "任务服务ID")
private Long jobServerId;
/**
* 任务 ID可选null 代表创建任务,否则填写需要修改的任务 ID
*/
@Schema(description = "任务 ID可选null 代表创建任务,否则填写需要修改的任务 ID")
private Long jobId;
/**
* 任务名称
*/
@Schema(description = "任务名称")
private String jobName;
/**
* 任务描述
*/
@Schema(description = "任务描述")
private String jobDescription;
/**
* 任务参数Processor#process 方法入参 TaskContext 对象的 jobParams 字段
*/
@Schema(description = "任务参数Processor#process 方法入参 TaskContext 对象的 jobParams 字段")
private String jobParams;
/**
* 时间表达式类型,枚举值
*/
@Schema(description = "时间表达式类型,枚举值")
private Integer timeExpressionType;
/**
* 时间表达式,填写类型由 timeExpressionType 决定,比如 CRON 需要填写 CRON 表达式
*/
@Schema(description = "时间表达式,填写类型由 timeExpressionType 决定,比如 CRON 需要填写 CRON 表达式")
private String timeExpression;
/**
* 执行类型,枚举值
*/
@Schema(description = "执行类型,枚举值")
private Integer executeType;
/**
* 处理器类型,枚举值
*/
@Schema(description = "处理器类型,枚举值")
private Integer processorType;
/**
* 处理器参数,填写类型由 processorType 决定如Java 处理器需要填写全限定类名com.github.kfcfans.oms.processors.demo.MapReduceProcessorDemo
*/
@Schema(description = "处理器参数,填写类型由 processorType 决定如Java 处理器需要填写全限定类名com.github.kfcfans.oms.processors.demo.MapReduceProcessorDemo")
private String processorInfo;
/**
* 最大实例数,该任务同时执行的数量(任务和实例就像是类和对象的关系,任务被调度执行后被称为实例)
*/
@Schema(description = "最大实例数,该任务同时执行的数量(任务和实例就像是类和对象的关系,任务被调度执行后被称为实例)")
private Integer maxInstanceNum;
/**
* 单机线程并发数表示该实例执行过程中每个Worker 使用的线程数量
*/
@Schema(description = "单机线程并发数表示该实例执行过程中每个Worker 使用的线程数量")
private Integer concurrency;
/**
* 任务实例运行时间限制0 代表无任何限制,超时会被打断并判定为执行失败
*/
@Schema(description = "任务实例运行时间限制0 代表无任何限制,超时会被打断并判定为执行失败")
private Long instanceTimeLimit;
/**
* instanceRetryNum 任务实例重试次数,整个任务失败时重试,代价大,不推荐使用
*/
@Schema(description = "instanceRetryNum 任务实例重试次数,整个任务失败时重试,代价大,不推荐使用")
private Integer instanceRetryNum;
/**
* taskRetryNum Task 重试次数,每个子 Task 失败后单独重试,代价小,推荐使用
*/
@Schema(description = "taskRetryNum Task 重试次数,每个子 Task 失败后单独重试,代价小,推荐使用")
private Integer taskRetryNum;
/**
* minCpuCores 最小可用 CPU 核心数CPU 可用核心数小于该值的 Worker 将不会执行该任务0 代表无任何限制
*/
@Schema(description = "minCpuCores 最小可用 CPU 核心数CPU 可用核心数小于该值的 Worker 将不会执行该任务0 代表无任何限制")
private BigDecimal minCpuCores;
/**
* 最小内存大小GB可用内存小于该值的Worker 将不会执行该任务0 代表无任何限制
*/
@Schema(description = "最小内存大小GB可用内存小于该值的Worker 将不会执行该任务0 代表无任何限制")
private BigDecimal minMemorySpace;
/**
* 最小磁盘大小GB可用磁盘空间小于该值的Worker 将不会执行该任务0 代表无任何限制
*/
@Schema(description = "最小磁盘大小GB可用磁盘空间小于该值的Worker 将不会执行该任务0 代表无任何限制")
private BigDecimal minDiskSpace;
/**
* 指定机器执行,设置该参数后只有列表中的机器允许执行该任务,空代表不指定机器
*/
@Schema(description = "指定机器执行,设置该参数后只有列表中的机器允许执行该任务,空代表不指定机器")
private String designatedWorkers;
/**
* 最大执行机器数量限定调动执行的机器数量0代表无限制
*/
@Schema(description = "最大执行机器数量限定调动执行的机器数量0代表无限制")
private Integer maxWorkerCount;
/**
* 接收报警的用户 ID 列表
*/
@Schema(description = "接收报警的用户 ID 列表")
private String notifyUserIds;
/**
* 是否启用该任务,未启用的任务不会被调度
*/
@Schema(description = "是否启用该任务,未启用的任务不会被调度")
private Integer enable;
/**
* 调度策略枚举目前支持随机RANDOM和 健康度优先HEALTH_FIRST
*/
@Schema(description = "调度策略枚举目前支持随机RANDOM和 健康度优先HEALTH_FIRST")
private Integer dispatchStrategy;
/**
* lifecycle 生命周期(预留,用于指定定时调度任务的生效时间范围)
*/
@Schema(description = "lifecycle 生命周期(预留,用于指定定时调度任务的生效时间范围)")
private String lifecycle;
/**
* 错误阈值0代表不限制
*/
@Schema(description = "错误阈值0代表不限制")
private Integer alertThreshold;
/**
* 统计的窗口长度(s)0代表不限制
*/
@Schema(description = "统计的窗口长度(s)0代表不限制")
private Integer statisticWindowLen;
/**
* 沉默时间窗口(s)0代表不限制
*/
@Schema(description = "沉默时间窗口(s)0代表不限制")
private Integer silenceWindowLen;
/**
* 日志配置
*/
@Schema(description = "日志配置")
private Integer logType;
/**
* 日志配置
*/
@Schema(description = "日志级别")
private Integer logLevel;
/**
* 扩展字段供开发者使用用于功能扩展powerjob 自身不会使用该字段)
*/
@Schema(description = "扩展字段供开发者使用用于功能扩展powerjob 自身不会使用该字段)")
private String extra;
}

View File

@@ -0,0 +1,52 @@
package org.springblade.job.pojo.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.mp.base.BaseEntity;
import java.io.Serial;
/**
* 任务服务表 实体类
*
* @author BladeX
*/
@Data
@TableName("blade_job_server")
@EqualsAndHashCode(callSuper = true)
@Schema(description = "任务服务表")
public class JobServer extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 任务服务名称
*/
@Schema(description = "任务服务名称")
private String jobServerName;
/**
* 任务服务器地址
*/
@Schema(description = "任务服务器地址")
private String jobServerUrl;
/**
* 任务应用名称
*/
@Schema(description = "任务应用名称")
private String jobAppName;
/**
* 任务应用密码
*/
@Schema(description = "任务应用密码")
private String jobAppPassword;
/**
* 任务备注
*/
@Schema(description = "任务备注")
private String jobRemark;
}

View File

@@ -0,0 +1,21 @@
package org.springblade.job.pojo.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.job.pojo.entity.JobInfo;
import java.io.Serial;
/**
* 任务信息表 视图实体类
*
* @author BladeX
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class JobInfoVO extends JobInfo {
@Serial
private static final long serialVersionUID = 1L;
}

View File

@@ -0,0 +1,21 @@
package org.springblade.job.pojo.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.job.pojo.entity.JobServer;
import java.io.Serial;
/**
* 任务服务表 视图实体类
*
* @author BladeX
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class JobServerVO extends JobServer {
@Serial
private static final long serialVersionUID = 1L;
}

View File

@@ -0,0 +1,35 @@
package org.springblade.job.processor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import tech.powerjob.worker.core.processor.ProcessResult;
import tech.powerjob.worker.core.processor.TaskContext;
import tech.powerjob.worker.core.processor.sdk.BasicProcessor;
import tech.powerjob.worker.log.OmsLogger;
// 支持 SpringBean 的形式
@Slf4j
@Component
public class ProcessorDemo implements BasicProcessor {
@Override
public ProcessResult process(TaskContext context) {
// 在线日志功能,可以直接在控制台查看任务日志,非常便捷
OmsLogger omsLogger = context.getOmsLogger();
omsLogger.info("BasicProcessorDemo start to process, current JobParams is {}.", context.getJobParams());
// TaskContext为任务的上下文信息包含了在控制台录入的任务元数据常用字段为
// jobParams任务参数在控制台录入instanceParams任务实例参数通过 OpenAPI 触发的任务实例才可能存在该参数)
// 进行实际处理...
log.info("============== ProcessorDemo#process ==============");
log.info("hello blade");
log.info("============== ProcessorDemo#process ==============");
// 返回结果,该结果会被持久化到数据库,在前端页面直接查看,极为方便
return new ProcessResult(true, "result is success");
}
}

View File

@@ -0,0 +1,64 @@
package org.springblade.job.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseService;
import org.springblade.job.pojo.entity.JobInfo;
import org.springblade.job.pojo.vo.JobInfoVO;
import java.util.List;
/**
* 任务信息表 服务类
*
* @author BladeX
*/
public interface IJobInfoService extends BaseService<JobInfo> {
/**
* 自定义分页
*
* @param page
* @param jobInfo
* @return
*/
IPage<JobInfoVO> selectJobInfoPage(IPage<JobInfoVO> page, JobInfoVO jobInfo);
/**
* 保存并同步
*
* @return
*/
Boolean submitAndSync(JobInfo jobInfo);
/**
* 删除并同步
*
* @return
*/
Boolean removeAndSync(List<Long> ids);
/**
* 启用禁用服务
*
* @param id 任务服务ID
* @param enable 是否启用
* @return
*/
Boolean changeServerJob(Long id, Integer enable);
/**
* 运行服务
*
* @param id 任务服务ID
* @return
*/
Boolean runServerJob(Long id);
/**
* 数据同步
*
* @return
*/
Boolean sync();
}

View File

@@ -0,0 +1,40 @@
package org.springblade.job.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseService;
import org.springblade.job.pojo.entity.JobServer;
import org.springblade.job.pojo.vo.JobServerVO;
/**
* 任务服务表 服务类
*
* @author BladeX
*/
public interface IJobServerService extends BaseService<JobServer> {
/**
* 自定义分页
*
* @param page
* @param jobServer
* @return
*/
IPage<JobServerVO> selectJobServerPage(IPage<JobServerVO> page, JobServerVO jobServer);
/**
* 保存并同步
*
* @param jobServer
* @return
*/
Boolean submitAndSync(JobServer jobServer);
/**
* 同步数据
*
* @param jobServer
* @return
*/
Boolean sync(JobServer jobServer);
}

View File

@@ -0,0 +1,320 @@
package org.springblade.job.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.powerjob.constant.PowerJobConstant;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.utils.ConvertUtil;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.job.pojo.dto.JobDTO;
import org.springblade.job.pojo.entity.JobInfo;
import org.springblade.job.pojo.entity.JobServer;
import org.springblade.job.mapper.JobInfoMapper;
import org.springblade.job.service.IJobInfoService;
import org.springblade.job.service.IJobServerService;
import org.springblade.job.pojo.vo.JobInfoVO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tech.powerjob.client.PowerJobClient;
import tech.powerjob.common.enums.DispatchStrategy;
import tech.powerjob.common.enums.ExecuteType;
import tech.powerjob.common.enums.ProcessorType;
import tech.powerjob.common.enums.TimeExpressionType;
import tech.powerjob.common.model.AlarmConfig;
import tech.powerjob.common.model.LifeCycle;
import tech.powerjob.common.model.LogConfig;
import tech.powerjob.common.request.http.SaveJobInfoRequest;
import tech.powerjob.common.response.JobInfoDTO;
import tech.powerjob.common.response.ResultDTO;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
/**
* 任务信息表 服务实现类
*
* @author BladeX
*/
@Service
@AllArgsConstructor
public class JobInfoServiceImpl extends BaseServiceImpl<JobInfoMapper, JobInfo> implements IJobInfoService {
private final IJobServerService jobServerService;
@Override
public IPage<JobInfoVO> selectJobInfoPage(IPage<JobInfoVO> page, JobInfoVO jobInfo) {
return page.setRecords(baseMapper.selectJobInfoPage(page, jobInfo));
}
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean submitAndSync(JobInfo jobInfo) {
//获取应用分组服务端信息
JobServer jobServer = jobServerService.getById(jobInfo.getJobServerId());
//构建Job客户端
PowerJobClient client = new PowerJobClient(jobServer.getJobServerUrl(), jobServer.getJobAppName(), jobServer.getJobAppPassword());
SaveJobInfoRequest request = convertToServer(jobInfo);
//获取上传结果
ResultDTO<Long> result = client.saveJob(request);
if (result.isSuccess()) {
jobInfo.setJobId(result.getData());
return this.saveOrUpdate(jobInfo);
} else {
throw new ServiceException(result.getMessage());
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean removeAndSync(List<Long> ids) {
ids.forEach(id -> {
JobDTO jobDTO = JobData(id);
if (Func.isNotEmpty(jobDTO)) {
JobInfo jobInfo = jobDTO.getJobInfo();
PowerJobClient powerJobClient = jobDTO.getPowerJobClient();
//删除服务数据
ResultDTO<Void> result = powerJobClient.deleteJob(jobInfo.getJobId());
if (result.isSuccess()) {
this.removeById(id);
} else {
throw new ServiceException(result.getMessage());
}
}
});
return true;
}
@Override
public Boolean changeServerJob(Long id, Integer enable) {
JobDTO jobDTO = JobData(id);
if (Func.isNotEmpty(jobDTO)) {
JobInfo jobInfo = jobDTO.getJobInfo();
PowerJobClient powerJobClient = jobDTO.getPowerJobClient();
//更换服务端状态
ResultDTO<Void> result = (enable == PowerJobConstant.JOB_ENABLED) ?
powerJobClient.enableJob(jobInfo.getJobId()) :
powerJobClient.disableJob(jobInfo.getJobId());
//删除客户端数据
if (result.isSuccess()) {
return this.update(Wrappers.<JobInfo>update().lambda().set(JobInfo::getEnable, enable).eq(JobInfo::getId, id));
} else {
throw new ServiceException(result.getMessage());
}
}
return false;
}
@Override
public Boolean runServerJob(Long id) {
JobDTO jobDTO = JobData(id);
if (Func.isNotEmpty(jobDTO)) {
JobInfo jobInfo = jobDTO.getJobInfo();
PowerJobClient powerJobClient = jobDTO.getPowerJobClient();
ResultDTO<Long> result = powerJobClient.runJob(jobInfo.getJobId());
return result.isSuccess();
}
return false;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean sync() {
//任务信息列表
List<JobInfo> jobInfos = this.list();
//任务服务列表
List<JobServer> jobServers = jobServerService.list();
//按应用分组
Map<Long, List<JobInfo>> jobGroups = jobInfos.stream().collect(Collectors.groupingBy(JobInfo::getJobServerId));
//处理服务端数据下载
jobServers.forEach(jobServer -> {
//构建Job客户端
PowerJobClient client = new PowerJobClient(jobServer.getJobServerUrl(), jobServer.getJobAppName(), jobServer.getJobAppPassword());
//从服务端获取数据
List<JobInfoDTO> serverInfoList = Optional.ofNullable(client.fetchAllJob())
.filter(ResultDTO::isSuccess)
.map(ResultDTO::getData)
.orElseGet(ArrayList::new);
//获取客户端数据
List<JobInfo> localInfoList = jobGroups.get(jobServer.getId());
//处理需要从服务端下载的数据
List<JobInfoDTO> jobInfoDTOList = serverInfoList.stream()
.filter(serverData -> serverData.getStatus() != PowerJobConstant.JOB_DELETED)
.filter(serverData -> Func.isEmpty(localInfoList) || localInfoList.stream().noneMatch(localData -> Func.equalsSafe(localData.getJobId(), serverData.getId())))
.collect(Collectors.toList());
List<JobInfo> dataToDownload = convertToLocalList(jobInfoDTOList, jobServer.getId());
//调用本地Service保存数据
this.saveBatch(dataToDownload);
});
//处理客户端数据上传
jobGroups.forEach((jobServerId, localInfoList) -> {
//获取应用分组服务端信息
JobServer jobServer = jobServers.stream().filter(js -> Func.equalsSafe(js.getId(), jobServerId))
.findFirst().orElseThrow(() -> new ServiceException(PowerJobConstant.JOB_SYNC_ALERT));
//构建Job客户端
PowerJobClient client = new PowerJobClient(jobServer.getJobServerUrl(), jobServer.getJobAppName(), jobServer.getJobAppPassword());
//处理需要上传到服务端的数据
localInfoList.forEach(localData -> {
//转换数据格式
SaveJobInfoRequest data = convertToServer(localData);
//调用OpenAPI接口上传数据
ResultDTO<Long> saveResult = client.saveJob(data);
if (saveResult.isSuccess()) {
//更新服务端JobId至客户端
this.update(Wrappers.<JobInfo>update().lambda().set(JobInfo::getJobId, saveResult.getData()).eq(JobInfo::getId, localData.getId()));
} else {
throw new RuntimeException(saveResult.getMessage());
}
});
});
return true;
}
/**
* 获取Job数据集合
*
* @param jobInfoId 服务信息ID
* @return PowerJobClient
*/
public JobDTO JobData(Long jobInfoId) {
//构建DTO类
JobDTO jobDTO = new JobDTO();
//获取任务信息
JobInfo jobInfo = this.getById(jobInfoId);
jobDTO.setJobInfo(jobInfo);
if (Func.isEmpty(jobInfo.getJobId())) {
throw new ServiceException(PowerJobConstant.JOB_SYNC_ALERT);
}
if (Func.isNotEmpty(jobInfo.getJobServerId())) {
//获取应用分组服务端信息
JobServer jobServer = jobServerService.getById(jobInfo.getJobServerId());
jobDTO.setJobServer(jobServer);
//构建Job客户端
PowerJobClient powerJobClient = new PowerJobClient(jobServer.getJobServerUrl(), jobServer.getJobAppName(), jobServer.getJobAppPassword());
jobDTO.setPowerJobClient(powerJobClient);
return jobDTO;
}
return null;
}
/**
* 服务端Job列表转换
*
* @param jobInfoList 本地任务信息列表
* @return List<SaveJobInfoRequest>
*/
public List<SaveJobInfoRequest> convertToServerList(List<JobInfo> jobInfoList) {
return jobInfoList.stream().map(this::convertToServer).collect(Collectors.toList());
}
/**
* 本地Job列表转换
*
* @param jobInfoDTOList 服务端任务信息列表
* @return List<JobInfo>
*/
public List<JobInfo> convertToLocalList(List<JobInfoDTO> jobInfoDTOList, Long jobServerId) {
return jobInfoDTOList.stream().map(jobInfoDTO -> convertToLocal(jobInfoDTO, jobServerId)).collect(Collectors.toList());
}
/**
* 服务端Job单个转换
*
* @param jobInfo 本地任务信息
* @return SaveJobInfoRequest
*/
public SaveJobInfoRequest convertToServer(JobInfo jobInfo) {
SaveJobInfoRequest saveJobInfoRequest = new SaveJobInfoRequest();
if (Func.toLong(jobInfo.getJobId()) > 0L) {
saveJobInfoRequest.setId(jobInfo.getJobId());
}
saveJobInfoRequest.setJobName(jobInfo.getJobName());
saveJobInfoRequest.setJobDescription(jobInfo.getJobDescription());
saveJobInfoRequest.setJobParams(jobInfo.getJobParams());
saveJobInfoRequest.setTimeExpressionType(TimeExpressionType.of(jobInfo.getTimeExpressionType()));
saveJobInfoRequest.setTimeExpression(jobInfo.getTimeExpression());
saveJobInfoRequest.setExecuteType(ExecuteType.of(jobInfo.getExecuteType()));
saveJobInfoRequest.setProcessorType(ProcessorType.of(jobInfo.getProcessorType()));
saveJobInfoRequest.setProcessorInfo(jobInfo.getProcessorInfo());
saveJobInfoRequest.setMaxInstanceNum(jobInfo.getMaxInstanceNum());
saveJobInfoRequest.setConcurrency(jobInfo.getConcurrency());
saveJobInfoRequest.setInstanceTimeLimit(jobInfo.getInstanceTimeLimit());
saveJobInfoRequest.setInstanceRetryNum(jobInfo.getInstanceRetryNum());
saveJobInfoRequest.setTaskRetryNum(jobInfo.getTaskRetryNum());
saveJobInfoRequest.setMinCpuCores(jobInfo.getMinCpuCores().doubleValue());
saveJobInfoRequest.setMinMemorySpace(jobInfo.getMinMemorySpace().doubleValue());
saveJobInfoRequest.setMinDiskSpace(jobInfo.getMinDiskSpace().doubleValue());
saveJobInfoRequest.setDesignatedWorkers(jobInfo.getDesignatedWorkers());
saveJobInfoRequest.setMaxWorkerCount(jobInfo.getMaxWorkerCount());
saveJobInfoRequest.setNotifyUserIds(Func.toLongList(jobInfo.getNotifyUserIds()));
saveJobInfoRequest.setEnable(jobInfo.getEnable() == 1);
saveJobInfoRequest.setDispatchStrategy(DispatchStrategy.of(jobInfo.getDispatchStrategy()));
saveJobInfoRequest.setAlarmConfig(new AlarmConfig(jobInfo.getAlertThreshold(), jobInfo.getStatisticWindowLen(), jobInfo.getSilenceWindowLen()));
saveJobInfoRequest.setLogConfig(new LogConfig().setLevel(jobInfo.getLogLevel()).setType(jobInfo.getLogType()));
if (Func.isNotEmpty(jobInfo.getLifecycle())) {
LifeCycle lifeCycle = new LifeCycle();
String[] lifeCycleArr = Func.toStrArray(jobInfo.getLifecycle());
lifeCycle.setStart(DateUtil.parse(lifeCycleArr[0], DateUtil.PATTERN_DATETIME).getTime());
lifeCycle.setEnd(DateUtil.parse(lifeCycleArr[1], DateUtil.PATTERN_DATETIME).getTime());
saveJobInfoRequest.setLifeCycle(lifeCycle);
}
saveJobInfoRequest.setExtra(jobInfo.getExtra());
return saveJobInfoRequest;
}
/**
* 本地Job单个转换
*
* @param jobInfoDTO 服务端任务信息
* @return SaveJobInfoRequest
*/
public JobInfo convertToLocal(JobInfoDTO jobInfoDTO, Long jobServerId) {
JobInfo jobInfo = new JobInfo();
jobInfo.setJobServerId(jobServerId);
jobInfo.setJobId(jobInfoDTO.getId());
jobInfo.setJobName(jobInfoDTO.getJobName());
jobInfo.setJobDescription(jobInfoDTO.getJobDescription());
jobInfo.setJobParams(jobInfoDTO.getJobParams());
jobInfo.setTimeExpressionType(jobInfoDTO.getTimeExpressionType());
jobInfo.setTimeExpression(jobInfoDTO.getTimeExpression());
jobInfo.setExecuteType(jobInfoDTO.getExecuteType());
jobInfo.setProcessorType(jobInfoDTO.getProcessorType());
jobInfo.setProcessorInfo(jobInfoDTO.getProcessorInfo());
jobInfo.setMaxInstanceNum(jobInfoDTO.getMaxInstanceNum());
jobInfo.setConcurrency(jobInfoDTO.getConcurrency());
jobInfo.setInstanceTimeLimit(jobInfoDTO.getInstanceTimeLimit());
jobInfo.setInstanceRetryNum(jobInfoDTO.getInstanceRetryNum());
jobInfo.setTaskRetryNum(jobInfoDTO.getTaskRetryNum());
jobInfo.setMinCpuCores(ConvertUtil.convert(jobInfoDTO.getMinCpuCores(), BigDecimal.class));
jobInfo.setMinMemorySpace(ConvertUtil.convert(jobInfoDTO.getMinMemorySpace(), BigDecimal.class));
jobInfo.setMinDiskSpace(ConvertUtil.convert(jobInfoDTO.getMinDiskSpace(), BigDecimal.class));
jobInfo.setDesignatedWorkers(jobInfoDTO.getDesignatedWorkers());
jobInfo.setMaxWorkerCount(jobInfoDTO.getMaxWorkerCount());
jobInfo.setNotifyUserIds(jobInfoDTO.getNotifyUserIds());
jobInfo.setEnable(jobInfoDTO.getStatus());
jobInfo.setDispatchStrategy(jobInfoDTO.getDispatchStrategy());
if (Func.isNotEmpty(jobInfoDTO.getLifecycle()) && !Func.equalsSafe(jobInfoDTO.getLifecycle(), StringPool.EMPTY_JSON)) {
LifeCycle lifeCycle = JsonUtil.parse(jobInfoDTO.getLifecycle(), LifeCycle.class);
String start = DateUtil.format(new Date(lifeCycle.getStart()), DateUtil.PATTERN_DATETIME);
String end = DateUtil.format(new Date(lifeCycle.getEnd()), DateUtil.PATTERN_DATETIME);
jobInfo.setLifecycle(start + StringPool.COMMA + end);
}
if (Func.isNotEmpty(jobInfoDTO.getAlarmConfig())) {
jobInfo.setAlertThreshold(jobInfoDTO.getAlarmConfig().getAlertThreshold());
jobInfo.setStatisticWindowLen(jobInfoDTO.getAlarmConfig().getStatisticWindowLen());
jobInfo.setSilenceWindowLen(jobInfoDTO.getAlarmConfig().getSilenceWindowLen());
}
if (Func.isNotEmpty(jobInfoDTO.getLogConfig())) {
jobInfo.setLogType(jobInfoDTO.getLogConfig().getType());
jobInfo.setLogLevel(jobInfoDTO.getLogConfig().getLevel());
}
jobInfo.setExtra(jobInfoDTO.getExtra());
return jobInfo;
}
}

View File

@@ -0,0 +1,47 @@
package org.springblade.job.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.core.type.TypeReference;
import org.springblade.core.http.util.HttpUtil;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.support.Kv;
import org.springblade.core.tool.utils.Func;
import org.springblade.job.pojo.entity.JobServer;
import org.springblade.job.mapper.JobServerMapper;
import org.springblade.job.service.IJobServerService;
import org.springblade.job.pojo.vo.JobServerVO;
import org.springframework.stereotype.Service;
import tech.powerjob.common.response.ResultDTO;
/**
* 任务服务表 服务实现类
*
* @author BladeX
*/
@Service
public class JobServerServiceImpl extends BaseServiceImpl<JobServerMapper, JobServer> implements IJobServerService {
@Override
public IPage<JobServerVO> selectJobServerPage(IPage<JobServerVO> page, JobServerVO jobServer) {
return page.setRecords(baseMapper.selectJobServerPage(page, jobServer));
}
@Override
public Boolean submitAndSync(JobServer jobServer) {
if (Func.isEmpty(jobServer.getId())) {
this.sync(jobServer);
}
return this.saveOrUpdate(jobServer);
}
@Override
public Boolean sync(JobServer jobServer) {
Kv appInfo = Kv.create().set("appName", jobServer.getJobAppName()).set("password", jobServer.getJobAppPassword());
String data = HttpUtil.postJson(jobServer.getJobServerUrl() + "/appInfo/save", JsonUtil.toJson(appInfo));
ResultDTO<Void> result = JsonUtil.parse(data, new TypeReference<ResultDTO<Void>>() {});
return result.isSuccess();
}
}

View File

@@ -0,0 +1,56 @@
package org.springblade.modules.auth.config;
import org.springblade.core.jwt.props.JwtProperties;
import org.springblade.core.oauth2.config.OAuth2AutoConfiguration;
import org.springblade.core.oauth2.handler.AuthorizationHandler;
import org.springblade.core.oauth2.handler.PasswordHandler;
import org.springblade.core.oauth2.handler.TokenHandler;
import org.springblade.core.oauth2.service.OAuth2ClientService;
import org.springblade.core.oauth2.service.OAuth2UserService;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.tenant.BladeTenantProperties;
import org.springblade.modules.auth.handler.BladeAuthorizationHandler;
import org.springblade.modules.auth.handler.BladePasswordHandler;
import org.springblade.modules.auth.handler.BladeTokenHandler;
import org.springblade.modules.auth.service.BladeClientDetailService;
import org.springblade.modules.auth.service.BladeUserDetailService;
import org.springblade.modules.system.service.IUserService;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* BladeAuthConfiguration
*
* @author Chill
*/
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(OAuth2AutoConfiguration.class)
public class BladeAuthConfiguration {
@Bean
public AuthorizationHandler authorizationHandler(BladeRedis bladeRedis, BladeTenantProperties tenantProperties) {
return new BladeAuthorizationHandler(bladeRedis, tenantProperties);
}
@Bean
public PasswordHandler passwordHandler() {
return new BladePasswordHandler();
}
@Bean
public TokenHandler tokenHandler(JwtProperties jwtProperties) {
return new BladeTokenHandler(jwtProperties);
}
@Bean
public OAuth2ClientService oAuth2ClientService(JdbcTemplate jdbcTemplate) {
return new BladeClientDetailService(jdbcTemplate);
}
@Bean
public OAuth2UserService oAuth2UserService(IUserService userService) {
return new BladeUserDetailService(userService);
}
}

View File

@@ -0,0 +1,22 @@
package org.springblade.modules.auth.constant;
/**
* AuthorizationConstant
*
* @author Chill
*/
public interface BladeAuthConstant {
/**
* 是否开启注册参数key
*/
String REGISTER_USER_VALUE = "account.registerUser";
/**
* 账号锁定错误次数参数key
*/
String FAIL_COUNT_VALUE = "account.failCount";
/**
* 账号锁定默认错误次数
*/
Integer FAIL_COUNT = 5;
}

View File

@@ -0,0 +1,49 @@
package org.springblade.modules.auth.granter;
import org.springblade.core.oauth2.constant.OAuth2TokenConstant;
import org.springblade.core.oauth2.exception.UserInvalidException;
import org.springblade.core.oauth2.granter.PasswordTokenGranter;
import org.springblade.core.oauth2.handler.PasswordHandler;
import org.springblade.core.oauth2.provider.OAuth2Request;
import org.springblade.core.oauth2.service.OAuth2ClientService;
import org.springblade.core.oauth2.service.OAuth2User;
import org.springblade.core.oauth2.service.OAuth2UserService;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.stereotype.Component;
/**
* CaptchaTokenGranter
*
* @author BladeX
*/
@Component
public class CaptchaTokenGranter extends PasswordTokenGranter {
private final BladeRedis bladeRedis;
public CaptchaTokenGranter(OAuth2ClientService clientService, OAuth2UserService userService, PasswordHandler passwordHandler, BladeRedis bladeRedis) {
super(clientService, userService, passwordHandler);
this.bladeRedis = bladeRedis;
}
@Override
public String type() {
return CAPTCHA;
}
@Override
public OAuth2User user(OAuth2Request request) {
// 获取验证码信息
String key = request.getCaptchaKey();
String code = request.getCaptchaCode();
// 获取验证码
String redisCode = bladeRedis.get(OAuth2TokenConstant.CAPTCHA_CACHE_KEY + key);
// 判断验证码
if (code == null || !StringUtil.equalsIgnoreCase(redisCode, code)) {
throw new UserInvalidException(OAuth2TokenConstant.CAPTCHA_NOT_CORRECT);
}
return super.user(request);
}
}

View File

@@ -0,0 +1,115 @@
package org.springblade.modules.auth.granter;
import org.jetbrains.annotations.NotNull;
import org.springblade.common.cache.ParamCache;
import org.springblade.core.oauth2.exception.ExceptionCode;
import org.springblade.core.oauth2.exception.UserInvalidException;
import org.springblade.core.oauth2.granter.AbstractTokenGranter;
import org.springblade.core.oauth2.handler.PasswordHandler;
import org.springblade.core.oauth2.provider.OAuth2Request;
import org.springblade.core.oauth2.service.OAuth2Client;
import org.springblade.core.oauth2.service.OAuth2ClientService;
import org.springblade.core.oauth2.service.OAuth2User;
import org.springblade.core.oauth2.service.OAuth2UserService;
import org.springblade.core.oauth2.service.impl.OAuth2UserDetail;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.auth.provider.UserType;
import org.springblade.modules.system.pojo.entity.User;
import org.springblade.modules.system.service.IUserService;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.function.Predicate;
import static org.springblade.modules.auth.constant.BladeAuthConstant.REGISTER_USER_VALUE;
/**
* RegisterTokenGranter
*
* @author BladeX
*/
@Component
public class RegisterTokenGranter extends AbstractTokenGranter {
private final IUserService service;
public RegisterTokenGranter(OAuth2ClientService clientService, OAuth2UserService userService, PasswordHandler passwordHandler, IUserService service) {
super(clientService, userService, passwordHandler);
this.service = service;
}
@Override
public String type() {
return REGISTER;
}
@Override
public OAuth2User user(OAuth2Request request) {
// 校验注册功能是否开启
Boolean registerOpen = Func.toBoolean(ParamCache.getValue(REGISTER_USER_VALUE), false);
if (!registerOpen) {
throw new UserInvalidException("注册功能暂未开启,请联系管理员");
}
// 用户注册信息
User user = new User();
user.setUserType(UserType.WEB.getCategory());
user.setTenantId(request.getTenantId());
user.setAccount(request.getUsername());
user.setPassword(request.getPassword());
user.setName(request.getName());
user.setRealName(request.getName());
user.setPhone(request.getPhone());
user.setEmail(request.getEmail());
// 校验用户格式
validateUser(user);
// 执行用户注册
if (service.registerUser(user)) {
// 构建oauth2所需用户信息
return convertOAuth2UserDetail(user, client(request));
}
throw new UserInvalidException(ExceptionCode.INVALID_USER.getMessage());
}
private void validateUser(User user) {
Predicate<String> isNameValid = name -> name.matches("^([\\u4e00-\\u9fa5]{2,20}|[a-zA-Z]{2,10})$");
Predicate<String> isUsernameValid = username -> username.matches("^(?=.*[a-zA-Z])[a-zA-Z0-9_\\-@]{3,20}$");
Predicate<String> isPasswordValid = password -> password.matches("^(?=.*[0-9])(?=.*[a-zA-Z])[\\w@-]{6,45}$");
Predicate<String> isPhoneValid = phone -> phone.matches("^1[3-9]\\d{9}$");
Predicate<String> isEmailValid = email -> email.matches("^[A-Za-z0-9+_.-]+@(.+)$");
if (!isNameValid.test(user.getName())) {
throw new UserInvalidException("用户姓名长度必须在2-10之间且仅能设置纯中文或纯英文");
}
if (!isUsernameValid.test(user.getAccount())) {
throw new UserInvalidException("用户账号长度必须在3-20之间且需要包含英文可额外携带数字、下划线、横杠、@");
}
if (!isPhoneValid.test(user.getPhone())) {
throw new UserInvalidException("手机号格式不正确");
}
if (!isEmailValid.test(user.getEmail())) {
throw new UserInvalidException("邮箱格式不正确");
}
if (!isPasswordValid.test(user.getPassword())) {
throw new UserInvalidException("密码长度格式不符合要求");
}
}
@NotNull
private OAuth2UserDetail convertOAuth2UserDetail(User user, OAuth2Client client) {
OAuth2UserDetail userDetail = new OAuth2UserDetail();
userDetail.setUserId(String.valueOf(user.getId()));
userDetail.setTenantId(user.getTenantId());
userDetail.setName(user.getName());
userDetail.setRealName(user.getName());
userDetail.setAccount(user.getAccount());
userDetail.setPassword(user.getPassword());
userDetail.setPhone(user.getPhone());
userDetail.setEmail(user.getEmail());
userDetail.setAuthorities(Collections.singletonList(REGISTER));
userDetail.setClient(client);
return userDetail;
}
}

View File

@@ -0,0 +1,87 @@
package org.springblade.modules.auth.granter;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import org.springblade.core.oauth2.exception.OAuth2ErrorCode;
import org.springblade.core.oauth2.granter.AbstractTokenGranter;
import org.springblade.core.oauth2.handler.PasswordHandler;
import org.springblade.core.oauth2.provider.OAuth2Request;
import org.springblade.core.oauth2.service.OAuth2ClientService;
import org.springblade.core.oauth2.service.OAuth2User;
import org.springblade.core.oauth2.service.OAuth2UserService;
import org.springblade.core.oauth2.utils.OAuth2ExceptionUtil;
import org.springblade.core.social.props.SocialProperties;
import org.springblade.core.social.utils.SocialUtil;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.modules.auth.utils.TokenUtil;
import org.springblade.modules.system.pojo.entity.UserInfo;
import org.springblade.modules.system.pojo.entity.UserOauth;
import org.springblade.modules.system.service.IUserService;
import org.springframework.stereotype.Component;
import java.util.Objects;
/**
* SocialTokenGranter
*
* @author Chill
*/
@Component
public class SocialTokenGranter extends AbstractTokenGranter {
private static final Integer AUTH_SUCCESS_CODE = 2000;
private final IUserService userService;
private final SocialProperties socialProperties;
public SocialTokenGranter(OAuth2ClientService clientService, OAuth2UserService oAuth2UserService, PasswordHandler passwordHandler, IUserService userService, SocialProperties socialProperties) {
super(clientService, oAuth2UserService, passwordHandler);
this.userService = userService;
this.socialProperties = socialProperties;
}
@Override
public String type() {
return SOCIAL;
}
@Override
public OAuth2User user(OAuth2Request request) {
String tenantId = request.getTenantId();
// 开放平台来源
String sourceParameter = request.getSource();
// 匹配是否有别名定义
String source = socialProperties.getAlias().getOrDefault(sourceParameter, sourceParameter);
// 开放平台授权码
String code = request.getCode();
// 开放平台状态吗
String state = request.getState();
// 获取开放平台授权数据
AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
AuthCallback authCallback = new AuthCallback();
authCallback.setCode(code);
authCallback.setState(state);
AuthResponse<?> authResponse = authRequest.login(authCallback);
AuthUser authUser = null;
if (authResponse.getCode() == AUTH_SUCCESS_CODE) {
authUser = (AuthUser) authResponse.getData();
} else {
OAuth2ExceptionUtil.throwFromCode(OAuth2ErrorCode.INVALID_USER);
}
// 组装数据
UserOauth userOauth = Objects.requireNonNull(BeanUtil.copyProperties(authUser, UserOauth.class));
userOauth.setSource(authUser.getSource());
userOauth.setTenantId(tenantId);
userOauth.setUuid(authUser.getUuid());
UserInfo userInfo = userService.userInfo(userOauth);
return TokenUtil.convertUser(userInfo, request);
}
}

View File

@@ -0,0 +1,176 @@
package org.springblade.modules.auth.handler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.cache.CacheNames;
import org.springblade.common.cache.ParamCache;
import org.springblade.common.cache.SysCache;
import org.springblade.common.constant.TenantConstant;
import org.springblade.core.oauth2.exception.ExceptionCode;
import org.springblade.core.oauth2.handler.AbstractAuthorizationHandler;
import org.springblade.core.oauth2.provider.OAuth2Request;
import org.springblade.core.oauth2.provider.OAuth2Validation;
import org.springblade.core.oauth2.service.OAuth2User;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.tenant.BladeTenantProperties;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.tool.utils.DesUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.system.pojo.entity.Tenant;
import java.time.Duration;
import java.util.Date;
import static org.springblade.modules.auth.constant.BladeAuthConstant.FAIL_COUNT;
import static org.springblade.modules.auth.constant.BladeAuthConstant.FAIL_COUNT_VALUE;
/**
* AbstractAuthorizationHandler
*
* @author BladeX
*/
@Slf4j
@RequiredArgsConstructor
public class BladeAuthorizationHandler extends AbstractAuthorizationHandler {
private final BladeRedis bladeRedis;
private final BladeTenantProperties tenantProperties;
/**
* 认证校验
*
* @param user 用户信息
* @param request 请求信息
* @return boolean
*/
@Override
public OAuth2Validation authValidation(OAuth2User user, OAuth2Request request) {
// 密码模式、刷新token模式、验证码模式需要校验租户状态
if (request.isPassword() || request.isRefreshToken() || request.isCaptchaCode()) {
// 租户校验
OAuth2Validation tenantValidation = validateTenant(user.getTenantId());
if (!tenantValidation.isSuccess()) {
return tenantValidation;
}
// 判断登录是否锁定
OAuth2Validation failCountValidation = validateFailCount(user.getTenantId(), user.getAccount());
if (!failCountValidation.isSuccess()) {
return failCountValidation;
}
}
return super.authValidation(user, request);
}
/**
* 认证成功回调
*
* @param user 用户信息
*/
@Override
public void authSuccessful(OAuth2User user, OAuth2Request request) {
// 清空错误锁定次数
delFailCount(user.getTenantId(), user.getAccount());
log.info("用户:{},认证成功", user.getAccount());
}
/**
* 认证失败回调
*
* @param user 用户信息
* @param validation 失败信息
*/
@Override
public void authFailure(OAuth2User user, OAuth2Request request, OAuth2Validation validation) {
// 增加错误锁定次数
addFailCount(user.getTenantId(), user.getAccount());
log.error("用户:{},认证失败,失败原因:{}", user.getAccount(), validation.getMessage());
}
/**
* 租户授权校验
*
* @param tenantId 租户id
* @return OAuth2Validation
*/
private OAuth2Validation validateTenant(String tenantId) {
// 租户校验
Tenant tenant = SysCache.getTenant(tenantId);
if (tenant == null) {
return buildValidationFailure(ExceptionCode.USER_TENANT_NOT_FOUND);
}
// 租户授权时间校验
Date expireTime = tenant.getExpireTime();
if (tenantProperties.getLicense()) {
String licenseKey = tenant.getLicenseKey();
String decrypt = DesUtil.decryptFormHex(licenseKey, TenantConstant.DES_KEY);
expireTime = JsonUtil.parse(decrypt, Tenant.class).getExpireTime();
}
if (expireTime != null && expireTime.before(DateUtil.now())) {
return buildValidationFailure(ExceptionCode.UNAUTHORIZED_USER_TENANT);
}
return new OAuth2Validation();
}
/**
* 判断登录是否锁定
*
* @param tenantId 租户id
* @param account 账号
* @return OAuth2Validation
*/
private OAuth2Validation validateFailCount(String tenantId, String account) {
int cnt = getFailCount(tenantId, account);
int failCount = Func.toInt(ParamCache.getValue(FAIL_COUNT_VALUE), FAIL_COUNT);
if (cnt >= failCount) {
return buildValidationFailure(ExceptionCode.USER_TOO_MANY_FAILS);
}
return new OAuth2Validation();
}
/**
* 获取账号错误次数
*
* @param tenantId 租户id
* @param username 账号
* @return int
*/
private int getFailCount(String tenantId, String username) {
return Func.toInt(bladeRedis.get(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, username)), 0);
}
/**
* 设置账号错误次数
*
* @param tenantId 租户id
* @param username 账号
*/
private void addFailCount(String tenantId, String username) {
int count = getFailCount(tenantId, username);
bladeRedis.setEx(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, username), count + 1, Duration.ofMinutes(30));
}
/**
* 设置账号错误次数
*
* @param tenantId 租户id
* @param username 账号
* @param count 次数
*/
private void setFailCount(String tenantId, String username, int count) {
bladeRedis.setEx(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, username), count + 1, Duration.ofMinutes(30));
}
/**
* 清空账号错误次数
*
* @param tenantId 租户id
* @param username 账号
*/
private void delFailCount(String tenantId, String username) {
bladeRedis.del(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, username));
}
}

View File

@@ -0,0 +1,35 @@
package org.springblade.modules.auth.handler;
import org.springblade.core.oauth2.handler.OAuth2PasswordHandler;
/**
* BladePasswordHandler
*
* @author BladeX
*/
public class BladePasswordHandler extends OAuth2PasswordHandler {
/**
* 判断密码是否匹配
*
* @param rawPassword 请求时提交的原密码
* @param encodedPassword 数据库加密后的密码
* @return boolean
*/
@Override
public boolean matches(String rawPassword, String encodedPassword) {
return super.matches(rawPassword, encodedPassword);
}
/**
* 加密密码规则
*
* @param rawPassword 密码
* @return 加密后的密码
*/
@Override
public String encode(String rawPassword) {
return super.encode(rawPassword);
}
}

View File

@@ -0,0 +1,34 @@
package org.springblade.modules.auth.handler;
import org.springblade.core.jwt.props.JwtProperties;
import org.springblade.core.launch.constant.TokenConstant;
import org.springblade.core.oauth2.handler.OAuth2TokenHandler;
import org.springblade.core.oauth2.provider.OAuth2Request;
import org.springblade.core.oauth2.provider.OAuth2Token;
import org.springblade.core.oauth2.service.OAuth2User;
import org.springblade.core.tool.support.Kv;
/**
* BladeTokenHandler
*
* @author BladeX
*/
public class BladeTokenHandler extends OAuth2TokenHandler {
public BladeTokenHandler(JwtProperties properties) {
super(properties);
}
@Override
public OAuth2Token enhance(OAuth2User user, OAuth2Token token, OAuth2Request request) {
// 父类令牌状态配置
OAuth2Token enhanceToken = super.enhance(user, token, request);
// 令牌统一处理,增加或删减字段
Kv args = enhanceToken.getArgs();
args.set(TokenConstant.USER_NAME, user.getAccount());
// 返回令牌
return enhanceToken;
}
}

View File

@@ -0,0 +1,43 @@
package org.springblade.modules.auth.provider;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 用户类型枚举
*
* @author Chill
*/
@Getter
@AllArgsConstructor
public enum UserType {
/**
* web
*/
WEB("web", 1),
/**
* app
*/
APP("app", 2),
/**
* other
*/
OTHER("other", 3),
;
final String name;
final int category;
public static UserType of(String name) {
return Arrays.stream(UserType.values())
.filter(userEnum -> userEnum.getName().equalsIgnoreCase(name != null ? name : "web"))
.findFirst()
.orElse(UserType.WEB); // 在没有找到匹配项时返回默认值
}
}

View File

@@ -0,0 +1,37 @@
package org.springblade.modules.auth.service;
import org.springblade.core.oauth2.provider.OAuth2Request;
import org.springblade.core.oauth2.service.OAuth2Client;
import org.springblade.core.oauth2.service.impl.OAuth2ClientDetailService;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* BladeClientDetailService
*
* @author Chill
*/
public class BladeClientDetailService extends OAuth2ClientDetailService {
public BladeClientDetailService(JdbcTemplate jdbcTemplate) {
super(jdbcTemplate);
}
@Override
public OAuth2Client loadByClientId(String clientId) {
return super.loadByClientId(clientId);
}
@Override
public OAuth2Client loadByClientId(String clientId, OAuth2Request request) {
return super.loadByClientId(clientId, request);
}
@Override
public boolean validateClient(OAuth2Client client, String clientId, String clientSecret) {
return super.validateClient(client, clientId, clientSecret);
}
@Override
public boolean validateGranter(OAuth2Client client, String grantType) {
return super.validateGranter(client, grantType);
}
}

View File

@@ -0,0 +1,62 @@
package org.springblade.modules.auth.service;
import lombok.RequiredArgsConstructor;
import org.springblade.core.oauth2.provider.OAuth2Request;
import org.springblade.core.oauth2.service.OAuth2User;
import org.springblade.core.oauth2.service.OAuth2UserService;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.auth.provider.UserType;
import org.springblade.modules.auth.utils.TokenUtil;
import org.springblade.modules.system.pojo.entity.UserInfo;
import org.springblade.modules.system.service.IUserService;
import java.util.Optional;
/**
* BladeUserDetailService
*
* @author Chill
*/
@RequiredArgsConstructor
public class BladeUserDetailService implements OAuth2UserService {
private final IUserService userService;
@Override
public OAuth2User loadByUserId(String userId, OAuth2Request request) {
// 获取用户参数
String userType = Optional.ofNullable(request.getUserType())
.filter(s -> !StringUtil.isBlank(s))
.orElse(UserType.WEB.getName());
// 获取用户信息
UserInfo userInfo = userService.userInfo(Func.toLong(userId), UserType.of(userType));
// 构建oauth2用户信息
return TokenUtil.convertUser(userInfo, request);
}
@Override
public OAuth2User loadByUsername(String username, OAuth2Request request) {
// 获取用户参数
String userType = Optional.ofNullable(request.getUserType())
.filter(s -> !StringUtil.isBlank(s))
.orElse(UserType.WEB.getName());
String tenantId = request.getTenantId();
// 获取用户信息
UserInfo userInfo = userService.userInfo(tenantId, username, UserType.of(userType));
// 构建oauth2用户信息
return TokenUtil.convertUser(userInfo, request);
}
@Override
public boolean validateUser(OAuth2User user) {
return Optional.ofNullable(user)
.filter(u -> u.getUserId() != null && !u.getUserId().isEmpty()) // 检查userId不为空
.filter(u -> u.getAuthorities() != null && !u.getAuthorities().isEmpty()) // 检查authorities不为空
.isPresent(); // 如果上述条件都满足则返回true否则返回false
}
}

View File

@@ -0,0 +1,59 @@
package org.springblade.modules.auth.utils;
import org.springblade.core.oauth2.provider.OAuth2Request;
import org.springblade.core.oauth2.service.OAuth2User;
import org.springblade.core.oauth2.service.impl.OAuth2UserDetail;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.system.pojo.entity.User;
import org.springblade.modules.system.pojo.entity.UserInfo;
/**
* 认证工具类
*
* @author Chill
*/
public class TokenUtil {
/**
* 系统用户转换为OAuth2标准用户
*
* @param userInfo 用户信息
* @param request 请求信息
* @return OAuth2User
*/
public static OAuth2User convertUser(UserInfo userInfo, OAuth2Request request) {
// 为空则返回null
if (userInfo == null) {
return null;
}
User user = userInfo.getUser();
String userDept = request.getUserDept();
String userRole = request.getUserRole();
// 多部门情况下指定单部门
if (Func.isNotEmpty(userDept) && user.getDeptId().contains(userDept)) {
user.setDeptId(userDept);
}
// 多角色情况下指定单角色
if (Func.isNotEmpty(userRole) && user.getRoleId().contains(userRole)) {
user.setRoleId(userRole);
}
// 构建oauth2所需用户信息
OAuth2UserDetail userDetail = new OAuth2UserDetail();
userDetail.setUserId(String.valueOf(user.getId()));
userDetail.setTenantId(user.getTenantId());
userDetail.setName(user.getName());
userDetail.setRealName(user.getRealName());
userDetail.setAccount(user.getAccount());
userDetail.setPassword(user.getPassword());
userDetail.setDeptId(user.getDeptId());
userDetail.setPostId(user.getPostId());
userDetail.setRoleId(user.getRoleId());
userDetail.setRoleName(Func.join(userInfo.getRoles()));
userDetail.setAvatar(user.getAvatar());
userDetail.setAuthorities(userInfo.getRoles());
userDetail.setDetail(userInfo.getDetail());
return userDetail;
}
}

View File

@@ -0,0 +1,212 @@
package org.springblade.modules.desk.controller;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.tenant.annotation.NonDS;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.support.Kv;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 首页
*
* @author Chill
*/
@NonDS
@Hidden
@RestController
@RequestMapping(AppConstant.APPLICATION_DESK_NAME)
@AllArgsConstructor
@Tag(name = "首页", description = "首页")
public class DashBoardController {
/**
* 活跃用户
*/
@GetMapping("/dashboard/activities")
@ApiOperationSupport(order = 1)
@Operation(summary = "活跃用户", description = "活跃用户")
public R activities() {
List<Map<String, Object>> list = new ArrayList<>();
Map<String, Object> map1 = new HashMap<>(16);
map1.put("id", "trend-1");
map1.put("updatedAt", "2019-01-01");
map1.put("user", Kv.create().set("name", "曲丽丽").set("avatar", "https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png"));
map1.put("group", Kv.create().set("name", "高逼格设计天团").set("link", "http://github.com/"));
map1.put("project", Kv.create().set("name", "六月迭代").set("link", "http://github.com/"));
map1.put("template", "在 @{group} 新建项目 @{project}");
list.add(map1);
Map<String, Object> map2 = new HashMap<>(16);
map2.put("id", "trend-2");
map2.put("updatedAt", "2019-01-01");
map2.put("user", Kv.create().set("name", "付小小").set("avatar", "https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png"));
map2.put("group", Kv.create().set("name", "高逼格设计天团").set("link", "http://github.com/"));
map2.put("project", Kv.create().set("name", "七月月迭代").set("link", "http://github.com/"));
map2.put("template", "在 @{group} 新建项目 @{project}");
list.add(map2);
return R.data(list);
}
/**
* 用户信息
*/
@GetMapping("/dashboard/info")
@ApiOperationSupport(order = 2)
@Operation(summary = "用户信息", description = "用户信息")
public R info() {
Map<String, Object> map = new HashMap<>(16);
map.put("id", "trend-1");
map.put("updatedAt", "2019-01-01");
map.put("user", Kv.create().set("name", "曲丽丽").set("avatar", "https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png"));
map.put("group", Kv.create().set("name", "高逼格设计天团").set("link", "http://github.com/"));
map.put("project", Kv.create().set("name", "六月迭代").set("link", "http://github.com/"));
map.put("template", "在 @{group} 新建项目 @{project}");
return R.data(map);
}
/**
* 签名信息
*/
@PostMapping("/dashboard/sign")
@ApiOperationSupport(order = 3)
@Operation(summary = "签名信息", description = "签名信息")
public R sign() {
Map<String, Object> map = new HashMap<>(16);
map.put("user", Kv.create().set("name", "曲丽丽").set("avatar", "https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png"));
return R.data(map);
}
/**
* 获取消息
*/
@GetMapping("/notice/notices")
@ApiOperationSupport(order = 4)
@Operation(summary = "消息", description = "消息")
public R notices() {
List<Map<String, String>> list = new ArrayList<>();
Map<String, String> map1 = new HashMap<>(16);
map1.put("logo", "https://spring.io/img/homepage/icon-spring-framework.svg");
map1.put("title", "SpringBoot");
map1.put("description", "现在的web项目几乎都会用到spring框架而要使用spring难免需要配置大量的xml配置文件而 springboot的出现解 决了这一问题一个项目甚至不用部署到服务器上直接开跑真像springboot所说“just run”。");
map1.put("member", "Chill");
map1.put("href", "http://spring.io/projects/spring-boot");
list.add(map1);
Map<String, String> map2 = new HashMap<>(16);
map2.put("logo", "https://spring.io/img/homepage/icon-spring-cloud.svg");
map2.put("title", "SpringCloud");
map2.put("description", "SpringCloud是基于SpringBoot的一整套实现微服务的框架。他提供了微服务开发所需的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等组件。");
map2.put("member", "Chill");
map2.put("href", "http://spring.io/projects/spring-cloud");
list.add(map2);
Map<String, String> map3 = new HashMap<>(16);
map3.put("logo", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1546359961068&di=05ff9406e6675ca9a58a525a7e7950b9&imgtype=jpg&src=http%3A%2F%2Fimg0.imgtn.bdimg.com%2Fit%2Fu%3D575314515%2C4268715674%26fm%3D214%26gp%3D0.jpg");
map3.put("title", "Mybatis");
map3.put("description", "MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。");
map3.put("member", "Chill");
map3.put("href", "http://www.mybatis.org/mybatis-3/getting-started.html");
list.add(map3);
Map<String, String> map4 = new HashMap<>(16);
map4.put("logo", "https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png");
map4.put("title", "React");
map4.put("description", "React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架都不满意就决定自己写一套用来架设Instagram 的网站。做出来以后发现这套东西很好用就在2013年5月开源了。");
map4.put("member", "Chill");
map4.put("href", "https://reactjs.org/");
list.add(map4);
Map<String, String> map5 = new HashMap<>(16);
map5.put("logo", "https://gw.alipayobjects.com/zos/rmsportal/dURIMkkrRFpPgTuzkwnB.png");
map5.put("title", "Ant Design");
map5.put("description", "蚂蚁金服体验技术部经过大量的项目实践和总结,沉淀出设计语言 Ant Design这可不单纯只是设计原则、控件规范和视觉尺寸还配套有前端代码实现方案。也就是说采用Ant Design后UI设计和前端界面研发可同步完成效率大大提升。");
map5.put("member", "Chill");
map5.put("href", "https://ant.design/docs/spec/introduce-cn");
list.add(map5);
Map<String, String> map6 = new HashMap<>(16);
map6.put("logo", "https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png");
map6.put("title", "Ant Design Pro");
map6.put("description", "Ant Design Pro 是一个企业级开箱即用的中后台前端/设计解决方案。符合阿里追求的'敏捷的前端+强大的中台'的思想。");
map6.put("member", "Chill");
map6.put("href", "https://pro.ant.design");
list.add(map6);
return R.data(list);
}
/**
* 获取我的消息
*/
@GetMapping("/notice/my-notices")
@ApiOperationSupport(order = 5)
@Operation(summary = "消息", description = "消息")
public R myNotices() {
List<Map<String, String>> list = new ArrayList<>();
Map<String, String> map1 = new HashMap<>(16);
map1.put("id", "000000001");
map1.put("avatar", "https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png");
map1.put("title", "你收到了 14 份新周报");
map1.put("datetime", "2018-08-09");
map1.put("type", "notification");
list.add(map1);
Map<String, String> map2 = new HashMap<>(16);
map2.put("id", "000000002");
map2.put("avatar", "https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png");
map2.put("title", "你推荐的 曲妮妮 已通过第三轮面试");
map2.put("datetime", "2018-08-08");
map2.put("type", "notification");
list.add(map2);
Map<String, String> map3 = new HashMap<>(16);
map3.put("id", "000000003");
map3.put("avatar", "https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg");
map3.put("title", "曲丽丽 评论了你");
map3.put("description", "描述信息描述信息描述信息");
map3.put("datetime", "2018-08-07");
map3.put("type", "message");
map3.put("clickClose", "true");
list.add(map3);
Map<String, String> map4 = new HashMap<>(16);
map4.put("id", "000000004");
map4.put("avatar", "https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg");
map4.put("title", "朱偏右 回复了你");
map4.put("description", "这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像");
map4.put("type", "message");
map4.put("datetime", "2018-08-07");
map4.put("clickClose", "true");
list.add(map4);
Map<String, String> map5 = new HashMap<>(16);
map5.put("id", "000000005");
map5.put("title", "任务名称");
map5.put("description", "任务需要在 2018-01-12 20:00 前启动");
map5.put("extra", "未开始");
map5.put("status", "todo");
map5.put("type", "event");
list.add(map5);
return R.data(list);
}
}

View File

@@ -0,0 +1,127 @@
package org.springblade.modules.desk.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSort;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tenant.annotation.TenantDS;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.desk.pojo.entity.Notice;
import org.springblade.modules.desk.service.INoticeService;
import org.springblade.modules.desk.pojo.vo.NoticeVO;
import org.springblade.modules.desk.wrapper.NoticeWrapper;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* 控制器
*
* @author Chill
*/
@TenantDS
@RestController
@RequestMapping(AppConstant.APPLICATION_DESK_NAME + "/notice")
@AllArgsConstructor
@ApiSort(2)
@Tag(name = "用户博客", description = "博客接口")
public class NoticeController extends BladeController {
private final INoticeService noticeService;
/**
* 详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@Operation(summary = "详情", description = "传入notice")
public R<NoticeVO> detail(Notice notice) {
Notice detail = noticeService.getOne(Condition.getQueryWrapper(notice));
return R.data(NoticeWrapper.build().entityVO(detail));
}
/**
* 分页
*/
@GetMapping("/list")
@Parameters({
@Parameter(name = "category", description = "公告类型", in = ParameterIn.QUERY, schema = @Schema(type = "integer")),
@Parameter(name = "title", description = "公告标题", in = ParameterIn.QUERY, schema = @Schema(type = "string"))
})
@ApiOperationSupport(order = 2)
@Operation(summary = "分页", description = "传入notice")
public R<IPage<NoticeVO>> list(@Parameter(hidden = true) @RequestParam Map<String, Object> notice, Query query) {
NoticeWrapper.build().noticeQuery(notice);
IPage<Notice> pages = noticeService.page(Condition.getPage(query), Condition.getQueryWrapper(notice, Notice.class));
return R.data(NoticeWrapper.build().pageVO(pages));
}
/**
* 多表联合查询自定义分页
*/
@GetMapping("/page")
@Parameters({
@Parameter(name = "category", description = "公告类型", in = ParameterIn.QUERY, schema = @Schema(type = "integer")),
@Parameter(name = "title", description = "公告标题", in = ParameterIn.QUERY, schema = @Schema(type = "string"))
})
@ApiOperationSupport(order = 3)
@Operation(summary = "分页", description = "传入notice")
public R<IPage<NoticeVO>> page(@Parameter(hidden = true) NoticeVO notice, Query query) {
IPage<NoticeVO> pages = noticeService.selectNoticePage(Condition.getPage(query), notice);
return R.data(pages);
}
/**
* 新增
*/
@PostMapping("/save")
@ApiOperationSupport(order = 4)
@Operation(summary = "新增", description = "传入notice")
public R save(@RequestBody Notice notice) {
return R.status(noticeService.save(notice));
}
/**
* 修改
*/
@PostMapping("/update")
@ApiOperationSupport(order = 5)
@Operation(summary = "修改", description = "传入notice")
public R update(@RequestBody Notice notice) {
return R.status(noticeService.updateById(notice));
}
/**
* 新增或修改
*/
@PostMapping("/submit")
@ApiOperationSupport(order = 6)
@Operation(summary = "新增或修改", description = "传入notice")
public R submit(@RequestBody Notice notice) {
return R.status(noticeService.saveOrUpdate(notice));
}
/**
* 删除
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 7)
@Operation(summary = "逻辑删除", description = "传入notice")
public R remove(@Parameter(description = "主键集合") @RequestParam String ids) {
boolean temp = noticeService.deleteLogic(Func.toLongList(ids));
return R.status(temp);
}
}

View File

@@ -0,0 +1,35 @@
package org.springblade.modules.desk.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.modules.desk.pojo.entity.Notice;
import org.springblade.modules.desk.pojo.vo.NoticeVO;
import java.util.List;
/**
* Mapper 接口
*
* @author Chill
*/
public interface NoticeMapper extends BaseMapper<Notice> {
/**
* 前N条数据
*
* @param number 数量
* @return List<Notice>
*/
List<Notice> topList(Integer number);
/**
* 自定义分页
*
* @param page 分页
* @param notice 实体
* @return List<NoticeVO>
*/
List<NoticeVO> selectNoticePage(IPage page, NoticeVO notice);
}

View File

@@ -0,0 +1,53 @@
<?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 namespace="org.springblade.modules.desk.mapper.NoticeMapper">
<!-- 通用查询映射结果 -->
<resultMap id="noticeResultMap" type="org.springblade.modules.desk.pojo.entity.Notice">
<result column="id" property="id"/>
<result column="create_user" property="createUser"/>
<result column="create_time" property="createTime"/>
<result column="update_user" property="updateUser"/>
<result column="update_time" property="updateTime"/>
<result column="status" property="status"/>
<result column="is_deleted" property="isDeleted"/>
<result column="release_time" property="releaseTime"/>
<result column="title" property="title"/>
<result column="content" property="content"/>
</resultMap>
<!-- 通用查询映射结果 -->
<resultMap id="noticeVOResultMap" type="org.springblade.modules.desk.pojo.vo.NoticeVO">
<result column="id" property="id"/>
<result column="create_user" property="createUser"/>
<result column="create_time" property="createTime"/>
<result column="update_user" property="updateUser"/>
<result column="update_time" property="updateTime"/>
<result column="status" property="status"/>
<result column="is_deleted" property="isDeleted"/>
<result column="release_time" property="releaseTime"/>
<result column="title" property="title"/>
<result column="content" property="content"/>
</resultMap>
<select id="topList" resultMap="noticeResultMap">
select * from blade_notice limit #{number}
</select>
<select id="selectNoticePage" resultMap="noticeVOResultMap">
SELECT
n.*,
d.dict_value AS categoryName
FROM
blade_notice n
LEFT JOIN ( SELECT * FROM blade_dict WHERE CODE = 'notice' ) d ON n.category = d.dict_key
WHERE
n.is_deleted = 0 and n.tenant_id = #{notice.tenantId}
<if test="notice.title!=null">
and n.title like concat(concat('%', #{notice.title}), '%')
</if>
<if test="notice.category!=null">
and n.category = #{notice.category}
</if>
</select>
</mapper>

View File

@@ -0,0 +1,52 @@
package org.springblade.modules.desk.pojo.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tenant.mp.TenantEntity;
import java.io.Serial;
import java.util.Date;
/**
* 实体类
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("blade_notice")
@Schema(description = "公告实体类")
public class Notice extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 标题
*/
@Schema(description = "标题")
private String title;
/**
* 通知类型
*/
@Schema(description = "通知类型")
private Integer category;
/**
* 发布日期
*/
@Schema(description = "发布日期")
private Date releaseTime;
/**
* 内容
*/
@Schema(description = "内容")
private String content;
}

View File

@@ -0,0 +1,24 @@
package org.springblade.modules.desk.pojo.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.modules.desk.pojo.entity.Notice;
/**
* 通知公告视图类
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(description = "公告实体VO")
public class NoticeVO extends Notice {
@Schema(description = "通知类型名")
private String categoryName;
@Schema(description = "租户编号")
private String tenantId;
}

View File

@@ -0,0 +1,24 @@
package org.springblade.modules.desk.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseService;
import org.springblade.modules.desk.pojo.entity.Notice;
import org.springblade.modules.desk.pojo.vo.NoticeVO;
/**
* 服务类
*
* @author Chill
*/
public interface INoticeService extends BaseService<Notice> {
/**
* 自定义分页
* @param page
* @param notice
* @return
*/
IPage<NoticeVO> selectNoticePage(IPage<NoticeVO> page, NoticeVO notice);
}

View File

@@ -0,0 +1,28 @@
package org.springblade.modules.desk.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.modules.desk.pojo.entity.Notice;
import org.springblade.modules.desk.mapper.NoticeMapper;
import org.springblade.modules.desk.service.INoticeService;
import org.springblade.modules.desk.pojo.vo.NoticeVO;
import org.springframework.stereotype.Service;
/**
* 服务实现类
*
* @author Chill
*/
@Service
public class NoticeServiceImpl extends BaseServiceImpl<NoticeMapper, Notice> implements INoticeService {
@Override
public IPage<NoticeVO> selectNoticePage(IPage<NoticeVO> page, NoticeVO notice) {
// 若不使用mybatis-plus自带的分页方法则不会自动带入tenantId所以我们需要自行注入
notice.setTenantId(AuthUtil.getTenantId());
return page.setRecords(baseMapper.selectNoticePage(page, notice));
}
}

View File

@@ -0,0 +1,49 @@
package org.springblade.modules.desk.wrapper;
import org.springblade.common.cache.DictCache;
import org.springblade.common.enums.DictEnum;
import org.springblade.core.mp.support.BaseEntityWrapper;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.desk.pojo.entity.Notice;
import org.springblade.modules.desk.pojo.vo.NoticeVO;
import java.util.Map;
import java.util.Objects;
/**
* Notice包装类,返回视图层所需的字段
*
* @author Chill
*/
public class NoticeWrapper extends BaseEntityWrapper<Notice, NoticeVO> {
public static NoticeWrapper build() {
return new NoticeWrapper();
}
@Override
public NoticeVO entityVO(Notice notice) {
NoticeVO noticeVO = Objects.requireNonNull(BeanUtil.copyProperties(notice, NoticeVO.class));
String dictValue = DictCache.getValue(DictEnum.NOTICE, noticeVO.getCategory());
noticeVO.setCategoryName(dictValue);
return noticeVO;
}
/**
* 查询条件处理
*/
public void noticeQuery(Map<String, Object> notice) {
// 此场景仅在 pg数据库 map类型传参的情况下需要处理entity传参已经包含数据类型则无需关心
// 针对 pg数据库 int类型字段查询需要强转的处理示例
String searchKey = "category";
if (Func.isNotEmpty(notice.get(searchKey))) {
// 数据库字段为int类型设置"="查询,具体查询参数请见 @org.springblade.core.mp.support.SqlKeyword
notice.put(searchKey.concat("_equal"), Func.toInt(notice.get(searchKey)));
// 默认"like"查询pg数据库 场景会报错,所以将其删除
notice.remove(searchKey);
}
}
}

View File

@@ -0,0 +1,183 @@
package org.springblade.modules.develop.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.annotation.PreAuth;
import org.springblade.core.tenant.annotation.NonDS;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.constant.RoleConstant;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.develop.constant.DevelopConstant;
import org.springblade.develop.support.BladeCodeGenerator;
import org.springblade.modules.develop.pojo.entity.Code;
import org.springblade.modules.develop.pojo.entity.Datasource;
import org.springblade.modules.develop.pojo.entity.Model;
import org.springblade.modules.develop.pojo.entity.ModelPrototype;
import org.springblade.modules.develop.service.ICodeService;
import org.springblade.modules.develop.service.IDatasourceService;
import org.springblade.modules.develop.service.IModelPrototypeService;
import org.springblade.modules.develop.service.IModelService;
import org.springframework.web.bind.annotation.*;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 控制器
*
* @author Chill
*/
@NonDS
@Hidden
@RestController
@AllArgsConstructor
@RequestMapping(AppConstant.APPLICATION_DEVELOP_NAME + "/code")
@Tag(name = "代码生成", description = "代码生成")
@PreAuth(RoleConstant.HAS_ROLE_ADMINISTRATOR)
public class CodeController extends BladeController {
private final ICodeService codeService;
private final IDatasourceService datasourceService;
private final IModelService modelService;
private final IModelPrototypeService modelPrototypeService;
/**
* 详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@Operation(summary = "详情", description = "传入code")
public R<Code> detail(Code code) {
Code detail = codeService.getOne(Condition.getQueryWrapper(code));
return R.data(detail);
}
/**
* 分页
*/
@GetMapping("/list")
@Parameters({
@Parameter(name = "codeName", description = "模块名", in = ParameterIn.QUERY, schema = @Schema(type = "string")),
@Parameter(name = "tableName", description = "表名", in = ParameterIn.QUERY, schema = @Schema(type = "string")),
@Parameter(name = "modelName", description = "实体名", in = ParameterIn.QUERY, schema = @Schema(type = "string"))
})
@ApiOperationSupport(order = 2)
@Operation(summary = "分页", description = "传入code")
public R<IPage<Code>> list(@Parameter(hidden = true) @RequestParam Map<String, Object> code, Query query) {
IPage<Code> pages = codeService.page(Condition.getPage(query), Condition.getQueryWrapper(code, Code.class));
return R.data(pages);
}
/**
* 新增或修改
*/
@PostMapping("/submit")
@ApiOperationSupport(order = 3)
@Operation(summary = "新增或修改", description = "传入code")
public R submit(@Valid @RequestBody Code code) {
return R.status(codeService.submit(code));
}
/**
* 删除
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 4)
@Operation(summary = "删除", description = "传入ids")
public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status(codeService.removeByIds(Func.toLongList(ids)));
}
/**
* 复制
*/
@PostMapping("/copy")
@ApiOperationSupport(order = 5)
@Operation(summary = "复制", description = "传入id")
public R copy(@Parameter(description = "主键", required = true) @RequestParam Long id) {
Code code = codeService.getById(id);
code.setId(null);
code.setCodeName(code.getCodeName() + "-copy");
return R.status(codeService.save(code));
}
/**
* 代码生成
*/
@PostMapping("/gen-code")
@ApiOperationSupport(order = 6)
@Operation(summary = "代码生成", description = "传入ids")
public R genCode(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
Collection<Code> codes = codeService.listByIds(Func.toLongList(ids));
codes.forEach(code -> {
BladeCodeGenerator generator = new BladeCodeGenerator();
// 设置基础模型
Model model = modelService.getById(code.getModelId());
generator.setModelCode(model.getModelCode());
generator.setModelClass(model.getModelClass());
// 设置模型集合
List<ModelPrototype> prototypes = modelPrototypeService.prototypeList(model.getId());
generator.setModel(JsonUtil.readMap(JsonUtil.toJson(model)));
generator.setPrototypes(JsonUtil.readListMap(JsonUtil.toJson(prototypes)));
if (StringUtil.isNotBlank(code.getSubModelId()) && StringUtil.equals(code.getTemplateType(), DevelopConstant.TEMPLATE_SUB)) {
Model subModel = modelService.getById(Func.toLong(code.getSubModelId()));
List<ModelPrototype> subPrototypes = modelPrototypeService.prototypeList(subModel.getId());
generator.setSubModel(JsonUtil.readMap(JsonUtil.toJson(subModel)));
generator.setSubPrototypes(JsonUtil.readListMap(JsonUtil.toJson(subPrototypes)));
}
// 设置数据源
Datasource datasource = datasourceService.getById(model.getDatasourceId());
generator.setDriverName(datasource.getDriverClass());
generator.setUrl(datasource.getUrl());
generator.setUsername(datasource.getUsername());
generator.setPassword(datasource.getPassword());
// 设置基础配置
generator.setCodeStyle(code.getCodeStyle());
generator.setCodeName(code.getCodeName());
generator.setServiceName(code.getServiceName());
generator.setPackageName(code.getPackageName());
generator.setPackageDir(code.getApiPath());
generator.setPackageWebDir(code.getWebPath());
generator.setTablePrefix(Func.toStrArray(code.getTablePrefix()));
generator.setIncludeTables(Func.toStrArray(code.getTableName()));
// 设置模版信息
generator.setTemplateType(code.getTemplateType());
generator.setAuthor(code.getAuthor());
generator.setSubModelId(code.getSubModelId());
generator.setSubFkId(code.getSubFkId());
generator.setTreeId(code.getTreeId());
generator.setTreePid(code.getTreePid());
generator.setTreeName(code.getTreeName());
// 设置是否继承基础业务字段
generator.setHasSuperEntity(code.getBaseMode() == 2);
// 设置是否开启包装器模式
generator.setHasWrapper(code.getWrapMode() == 2);
// 设置是否开启远程调用模式
generator.setHasFeign(code.getFeignMode() == 2);
// 设置控制器服务名前缀
generator.setHasServiceName(Boolean.TRUE);
// 启动代码生成
generator.run();
});
return R.success("代码生成成功");
}
}

View File

@@ -0,0 +1,116 @@
package org.springblade.modules.develop.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tenant.annotation.NonDS;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.develop.pojo.entity.Datasource;
import org.springblade.modules.develop.service.IDatasourceService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 数据源配置表 控制器
*
* @author Chill
*/
@NonDS
@RestController
@AllArgsConstructor
@RequestMapping(AppConstant.APPLICATION_DEVELOP_NAME + "/datasource")
@Tag(name = "数据源配置表", description = "数据源配置表接口")
public class DatasourceController extends BladeController {
private final IDatasourceService datasourceService;
/**
* 详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@Operation(summary = "详情", description = "传入datasource")
public R<Datasource> detail(Datasource datasource) {
Datasource detail = datasourceService.getOne(Condition.getQueryWrapper(datasource));
return R.data(detail);
}
/**
* 分页 数据源配置表
*/
@GetMapping("/list")
@ApiOperationSupport(order = 2)
@Operation(summary = "分页", description = "传入datasource")
public R<IPage<Datasource>> list(Datasource datasource, Query query) {
IPage<Datasource> pages = datasourceService.page(Condition.getPage(query), Condition.getQueryWrapper(datasource));
return R.data(pages);
}
/**
* 新增 数据源配置表
*/
@PostMapping("/save")
@ApiOperationSupport(order = 4)
@Operation(summary = "新增", description = "传入datasource")
public R save(@Valid @RequestBody Datasource datasource) {
return R.status(datasourceService.save(datasource));
}
/**
* 修改 数据源配置表
*/
@PostMapping("/update")
@ApiOperationSupport(order = 5)
@Operation(summary = "修改", description = "传入datasource")
public R update(@Valid @RequestBody Datasource datasource) {
return R.status(datasourceService.updateById(datasource));
}
/**
* 新增或修改 数据源配置表
*/
@PostMapping("/submit")
@ApiOperationSupport(order = 6)
@Operation(summary = "新增或修改", description = "传入datasource")
public R submit(@Valid @RequestBody Datasource datasource) {
if (StringUtil.isNotBlank(datasource.getUrl())) {
datasource.setUrl(datasource.getUrl().replace("&amp;", "&"));
}
return R.status(datasourceService.saveOrUpdate(datasource));
}
/**
* 删除 数据源配置表
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 7)
@Operation(summary = "逻辑删除", description = "传入ids")
public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status(datasourceService.deleteLogic(Func.toLongList(ids)));
}
/**
* 数据源列表
*/
@GetMapping("/select")
@ApiOperationSupport(order = 8)
@Operation(summary = "下拉数据源", description = "查询列表")
public R<List<Datasource>> select() {
List<Datasource> list = datasourceService.list();
return R.data(list);
}
}

View File

@@ -0,0 +1,236 @@
package org.springblade.modules.develop.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.develop.pojo.entity.Datasource;
import org.springblade.modules.develop.pojo.entity.Model;
import org.springblade.modules.develop.pojo.entity.ModelPrototype;
import org.springblade.modules.develop.service.IDatasourceService;
import org.springblade.modules.develop.service.IModelPrototypeService;
import org.springblade.modules.develop.service.IModelService;
import org.springframework.web.bind.annotation.*;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
/**
* 数据模型表 控制器
*
* @author Chill
*/
@RestController
@AllArgsConstructor
@RequestMapping(AppConstant.APPLICATION_DEVELOP_NAME + "/model")
@Tag(name = "数据模型表", description = "数据模型表接口")
public class ModelController extends BladeController {
private final IModelService modelService;
private final IModelPrototypeService modelPrototypeService;
private final IDatasourceService datasourceService;
/**
* 详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@Operation(summary = "详情", description = "传入model")
public R<Model> detail(Model model) {
Model detail = modelService.getOne(Condition.getQueryWrapper(model));
return R.data(detail);
}
/**
* 分页 数据模型表
*/
@GetMapping("/list")
@ApiOperationSupport(order = 2)
@Operation(summary = "分页", description = "传入model")
public R<IPage<Model>> list(Model model, Query query) {
IPage<Model> pages = modelService.page(Condition.getPage(query), Condition.getQueryWrapper(model));
return R.data(pages);
}
/**
* 新增 数据模型表
*/
@PostMapping("/save")
@ApiOperationSupport(order = 3)
@Operation(summary = "新增", description = "传入model")
public R save(@Valid @RequestBody Model model) {
return R.status(modelService.save(model));
}
/**
* 修改 数据模型表
*/
@PostMapping("/update")
@ApiOperationSupport(order = 4)
@Operation(summary = "修改", description = "传入model")
public R update(@Valid @RequestBody Model model) {
return R.status(modelService.updateById(model));
}
/**
* 新增或修改 数据模型表
*/
@PostMapping("/submit")
@ApiOperationSupport(order = 5)
@Operation(summary = "新增或修改", description = "传入model")
public R submit(@Valid @RequestBody Model model) {
boolean temp = modelService.saveOrUpdate(model);
if (temp) {
return R.data(model);
} else {
return R.status(Boolean.FALSE);
}
}
/**
* 删除 数据模型表
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 6)
@Operation(summary = "逻辑删除", description = "传入ids")
public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status(modelService.delete(Func.toLongList(ids)));
}
/**
* 模型列表
*/
@GetMapping("/select")
@ApiOperationSupport(order = 7)
@Operation(summary = "模型列表", description = "模型列表")
public R<List<Model>> select() {
List<Model> list = modelService.list();
list.forEach(model -> model.setModelName(model.getModelTable() + StringPool.COLON + StringPool.SPACE + model.getModelName()));
return R.data(list);
}
/**
* 获取物理表列表
*/
@GetMapping("/table-list")
@ApiOperationSupport(order = 8)
@Operation(summary = "物理表列表", description = "传入datasourceId")
public R<List<TableInfo>> tableList(Long datasourceId) {
Datasource datasource = datasourceService.getById(datasourceId);
ConfigBuilder config = getConfigBuilder(datasource);
List<TableInfo> tableInfoList = config.getTableInfoList().stream()
.filter(tableInfo -> !StringUtil.startsWithIgnoreCase(tableInfo.getName(), "ACT_"))
.map(tableInfo -> tableInfo.setComment(tableInfo.getName() + StringPool.COLON + tableInfo.getComment()))
.collect(Collectors.toList());
return R.data(tableInfoList);
}
/**
* 获取物理表信息
*/
@GetMapping("/table-info")
@ApiOperationSupport(order = 9)
@Operation(summary = "物理表信息", description = "传入model信息")
public R<TableInfo> tableInfo(Long modelId, String tableName, Long datasourceId) {
if (StringUtil.isBlank(tableName)) {
Model model = modelService.getById(modelId);
tableName = model.getModelTable();
}
TableInfo tableInfo = getTableInfo(tableName, datasourceId);
return R.data(tableInfo);
}
/**
* 获取字段信息
*/
@GetMapping("/model-prototype")
@ApiOperationSupport(order = 10)
@Operation(summary = "物理表字段信息", description = "传入modelId与datasourceId")
public R modelPrototype(Long modelId, Long datasourceId) {
List<ModelPrototype> modelPrototypeList = modelPrototypeService.list(Wrappers.<ModelPrototype>query().lambda().eq(ModelPrototype::getModelId, modelId));
if (modelPrototypeList.size() > 0) {
return R.data(modelPrototypeList);
}
Model model = modelService.getById(modelId);
String tableName = model.getModelTable();
TableInfo tableInfo = getTableInfo(tableName, datasourceId);
if (tableInfo != null) {
return R.data(tableInfo.getFields());
} else {
return R.fail("未获得相关表信息");
}
}
/**
* 获取表信息
*
* @param tableName 表名
* @param datasourceId 数据源主键
*/
private TableInfo getTableInfo(String tableName, Long datasourceId) {
Datasource datasource = datasourceService.getById(datasourceId);
ConfigBuilder config = getConfigBuilder(datasource, tableName);
List<TableInfo> tableInfoList = config.getTableInfoList();
TableInfo tableInfo = null;
Iterator<TableInfo> iterator = tableInfoList.stream().filter(table -> table.getName().equals(tableName)).collect(Collectors.toList()).iterator();
if (iterator.hasNext()) {
tableInfo = iterator.next();
if (tableName.contains(StringPool.UNDERSCORE)) {
tableInfo.setEntityName(tableInfo.getEntityName().replace(StringUtil.firstCharToUpper(tableName.split(StringPool.UNDERSCORE)[0]), StringPool.EMPTY));
} else {
tableInfo.setEntityName(StringUtil.firstCharToUpper(tableName));
}
}
return tableInfo;
}
/**
* 获取表配置信息
*
* @param datasource 数据源信息
*/
private ConfigBuilder getConfigBuilder(Datasource datasource) {
return getConfigBuilder(datasource, null);
}
/**
* 获取表配置信息
*
* @param datasource 数据源信息
* @param tableName 表名
*/
private ConfigBuilder getConfigBuilder(Datasource datasource, String tableName) {
StrategyConfig.Builder builder = new StrategyConfig.Builder();
if (StringUtil.isNotBlank(tableName)) {
builder.addInclude(tableName);
}
StrategyConfig strategyConfig = builder.entityBuilder()
.naming(NamingStrategy.underline_to_camel)
.columnNaming(NamingStrategy.underline_to_camel).build();
DataSourceConfig datasourceConfig = new DataSourceConfig.Builder(
datasource.getUrl(), datasource.getUsername(), datasource.getPassword()
).build();
return new ConfigBuilder(null, datasourceConfig, strategyConfig, null, null, null);
}
}

View File

@@ -0,0 +1,122 @@
package org.springblade.modules.develop.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.modules.develop.pojo.entity.ModelPrototype;
import org.springblade.modules.develop.service.IModelPrototypeService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 数据原型表 控制器
*
* @author Chill
*/
@RestController
@AllArgsConstructor
@RequestMapping(AppConstant.APPLICATION_DEVELOP_NAME + "/model-prototype")
@Tag(name = "数据原型表", description = "数据原型表接口")
public class ModelPrototypeController extends BladeController {
private final IModelPrototypeService modelPrototypeService;
/**
* 详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@Operation(summary = "详情", description = "传入modelPrototype")
public R<ModelPrototype> detail(ModelPrototype modelPrototype) {
ModelPrototype detail = modelPrototypeService.getOne(Condition.getQueryWrapper(modelPrototype));
return R.data(detail);
}
/**
* 分页 数据原型表
*/
@GetMapping("/list")
@ApiOperationSupport(order = 2)
@Operation(summary = "分页", description = "传入modelPrototype")
public R<IPage<ModelPrototype>> list(ModelPrototype modelPrototype, Query query) {
IPage<ModelPrototype> pages = modelPrototypeService.page(Condition.getPage(query), Condition.getQueryWrapper(modelPrototype));
return R.data(pages);
}
/**
* 新增 数据原型表
*/
@PostMapping("/save")
@ApiOperationSupport(order = 4)
@Operation(summary = "新增", description = "传入modelPrototype")
public R save(@Valid @RequestBody ModelPrototype modelPrototype) {
return R.status(modelPrototypeService.save(modelPrototype));
}
/**
* 修改 数据原型表
*/
@PostMapping("/update")
@ApiOperationSupport(order = 5)
@Operation(summary = "修改", description = "传入modelPrototype")
public R update(@Valid @RequestBody ModelPrototype modelPrototype) {
return R.status(modelPrototypeService.updateById(modelPrototype));
}
/**
* 新增或修改 数据原型表
*/
@PostMapping("/submit")
@ApiOperationSupport(order = 6)
@Operation(summary = "新增或修改", description = "传入modelPrototype")
public R submit(@Valid @RequestBody ModelPrototype modelPrototype) {
return R.status(modelPrototypeService.saveOrUpdate(modelPrototype));
}
/**
* 批量新增或修改 数据原型表
*/
@PostMapping("/submit-list")
@ApiOperationSupport(order = 7)
@Operation(summary = "批量新增或修改", description = "传入modelPrototype集合")
public R submitList(@Valid @RequestBody List<ModelPrototype> modelPrototypes) {
return R.status(modelPrototypeService.submitList(modelPrototypes));
}
/**
* 删除 数据原型表
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 8)
@Operation(summary = "逻辑删除", description = "传入ids")
public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status(modelPrototypeService.deleteLogic(Func.toLongList(ids)));
}
/**
* 数据原型列表
*/
@GetMapping("/select")
@ApiOperationSupport(order = 9)
@Operation(summary = "数据原型列表", description = "数据原型列表")
public R<List<ModelPrototype>> select(@Parameter(description = "数据模型Id", required = true) @RequestParam Long modelId) {
List<ModelPrototype> list = modelPrototypeService.list(Wrappers.<ModelPrototype>query().lambda().eq(ModelPrototype::getModelId, modelId));
list.forEach(prototype -> prototype.setJdbcComment(prototype.getJdbcName() + StringPool.COLON + StringPool.SPACE + prototype.getJdbcComment()));
return R.data(list);
}
}

View File

@@ -0,0 +1,14 @@
package org.springblade.modules.develop.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springblade.modules.develop.pojo.entity.Code;
/**
* Mapper 接口
*
* @author Chill
*/
public interface CodeMapper extends BaseMapper<Code> {
}

View File

@@ -0,0 +1,22 @@
<?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 namespace="org.springblade.modules.develop.mapper.CodeMapper">
<!-- 通用查询映射结果 -->
<resultMap id="codeResultMap" type="org.springblade.modules.develop.pojo.entity.Code">
<id column="id" property="id"/>
<result column="datasource_id" property="datasourceId"/>
<result column="service_name" property="serviceName"/>
<result column="code_name" property="codeName"/>
<result column="table_name" property="tableName"/>
<result column="pk_name" property="pkName"/>
<result column="base_mode" property="baseMode"/>
<result column="wrap_mode" property="wrapMode"/>
<result column="table_prefix" property="tablePrefix"/>
<result column="package_name" property="packageName"/>
<result column="api_path" property="apiPath"/>
<result column="web_path" property="webPath"/>
<result column="is_deleted" property="isDeleted"/>
</resultMap>
</mapper>

View File

@@ -0,0 +1,14 @@
package org.springblade.modules.develop.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springblade.modules.develop.pojo.entity.Datasource;
/**
* 数据源配置表 Mapper 接口
*
* @author Chill
*/
public interface DatasourceMapper extends BaseMapper<Datasource> {
}

View File

@@ -0,0 +1,22 @@
<?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 namespace="org.springblade.modules.develop.mapper.DatasourceMapper">
<!-- 通用查询映射结果 -->
<resultMap id="datasourceResultMap" type="org.springblade.modules.develop.pojo.entity.Datasource">
<result column="id" property="id"/>
<result column="create_user" property="createUser"/>
<result column="create_dept" property="createDept"/>
<result column="create_time" property="createTime"/>
<result column="update_user" property="updateUser"/>
<result column="update_time" property="updateTime"/>
<result column="status" property="status"/>
<result column="is_deleted" property="isDeleted"/>
<result column="driver_class" property="driverClass"/>
<result column="url" property="url"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="remark" property="remark"/>
</resultMap>
</mapper>

View File

@@ -0,0 +1,14 @@
package org.springblade.modules.develop.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springblade.modules.develop.pojo.entity.Model;
/**
* 数据模型表 Mapper 接口
*
* @author Chill
*/
public interface ModelMapper extends BaseMapper<Model> {
}

View File

@@ -0,0 +1,27 @@
<?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 namespace="org.springblade.modules.develop.mapper.ModelMapper">
<!-- 通用查询映射结果 -->
<resultMap id="modelResultMap" type="org.springblade.modules.develop.pojo.entity.Model">
<id column="id" property="id"/>
<result column="create_user" property="createUser"/>
<result column="create_time" property="createTime"/>
<result column="update_user" property="updateUser"/>
<result column="update_time" property="updateTime"/>
<result column="status" property="status"/>
<result column="is_deleted" property="isDeleted"/>
<result column="datasource_id" property="datasourceId"/>
<result column="model_name" property="modelName"/>
<result column="model_code" property="modelCode"/>
<result column="model_table" property="modelTable"/>
<result column="model_class" property="modelClass"/>
<result column="model_remark" property="modelRemark"/>
</resultMap>
<select id="selectModelPage" resultMap="modelResultMap">
select * from blade_model where is_deleted = 0
</select>
</mapper>

View File

@@ -0,0 +1,14 @@
package org.springblade.modules.develop.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springblade.modules.develop.pojo.entity.ModelPrototype;
/**
* 数据原型表 Mapper 接口
*
* @author Chill
*/
public interface ModelPrototypeMapper extends BaseMapper<ModelPrototype> {
}

View File

@@ -0,0 +1,35 @@
<?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 namespace="org.springblade.modules.develop.mapper.ModelPrototypeMapper">
<!-- 通用查询映射结果 -->
<resultMap id="modelPrototypeResultMap" type="org.springblade.modules.develop.pojo.entity.ModelPrototype">
<id column="id" property="id"/>
<result column="create_user" property="createUser"/>
<result column="create_time" property="createTime"/>
<result column="update_user" property="updateUser"/>
<result column="update_time" property="updateTime"/>
<result column="status" property="status"/>
<result column="is_deleted" property="isDeleted"/>
<result column="jdbc_name" property="jdbcName"/>
<result column="jdbc_type" property="jdbcType"/>
<result column="jdbc_comment" property="jdbcComment"/>
<result column="property_type" property="propertyType"/>
<result column="property_entity" property="propertyEntity"/>
<result column="property_name" property="propertyName"/>
<result column="is_form" property="isForm"/>
<result column="is_row" property="isRow"/>
<result column="component_type" property="componentType"/>
<result column="dict_code" property="dictCode"/>
<result column="is_required" property="isRequired"/>
<result column="is_list" property="isList"/>
<result column="is_query" property="isQuery"/>
<result column="query_type" property="queryType"/>
</resultMap>
<select id="selectModelPrototypePage" resultMap="modelPrototypeResultMap">
select * from blade_model_prototype where is_deleted = 0
</select>
</mapper>

View File

@@ -0,0 +1,29 @@
package org.springblade.modules.develop.pojo.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.modules.develop.pojo.entity.Model;
import org.springblade.modules.develop.pojo.entity.ModelPrototype;
import java.io.Serial;
import java.util.List;
/**
* 代码模型DTO
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class ModelDTO extends Model {
@Serial
private static final long serialVersionUID = 1L;
/**
* 代码建模原型
*/
private List<ModelPrototype> prototypes;
}

View File

@@ -0,0 +1,166 @@
package org.springblade.modules.develop.pojo.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 实体类
*
* @author Chill
*/
@Data
@TableName("blade_code")
@Schema(description = "Code对象")
public class Code implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@JsonSerialize(using = ToStringSerializer.class)
@Schema(description = "主键")
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
/**
* 数据模型主键
*/
@JsonSerialize(using = ToStringSerializer.class)
@Schema(description = "数据模型主键")
private Long modelId;
/**
* 模块名称
*/
@Schema(description = "服务名称")
private String serviceName;
/**
* 模块名称
*/
@Schema(description = "模块名称")
private String codeName;
/**
* 表名
*/
@Schema(description = "表名")
private String tableName;
/**
* 实体名
*/
@Schema(description = "表前缀")
private String tablePrefix;
/**
* 主键名
*/
@Schema(description = "主键名")
private String pkName;
/**
* 后端包名
*/
@Schema(description = "后端包名")
private String packageName;
/**
* 模版类型
*/
@Schema(description = "模版类型")
private String templateType;
/**
* 作者信息
*/
@Schema(description = "作者信息")
private String author;
/**
* 子表模型主键
*/
@Schema(description = "子表模型主键")
private String subModelId;
/**
* 子表绑定外键
*/
@Schema(description = "子表绑定外键")
private String subFkId;
/**
* 树主键字段
*/
@Schema(description = "树主键字段")
private String treeId;
/**
* 树父主键字段
*/
@Schema(description = "树父主键字段")
private String treePid;
/**
* 树名称字段
*/
@Schema(description = "树名称字段")
private String treeName;
/**
* 基础业务模式
*/
@Schema(description = "基础业务模式")
private Integer baseMode;
/**
* 包装器模式
*/
@Schema(description = "包装器模式")
private Integer wrapMode;
/**
* 远程调用模式
*/
@Schema(description = "远程调用模式")
private Integer feignMode;
/**
* 代码风格
*/
@Schema(description = "代码风格")
private String codeStyle;
/**
* 后端路径
*/
@Schema(description = "后端路径")
private String apiPath;
/**
* 前端路径
*/
@Schema(description = "前端路径")
private String webPath;
/**
* 是否已删除
*/
@TableLogic
@Schema(description = "是否已删除")
private Integer isDeleted;
}

View File

@@ -0,0 +1,68 @@
package org.springblade.modules.develop.pojo.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.mp.base.BaseEntity;
import java.io.Serial;
/**
* 数据源配置表实体类
*
* @author Chill
*/
@Data
@TableName("blade_datasource")
@EqualsAndHashCode(callSuper = true)
@Schema(description = "数据源配置表")
public class Datasource extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 数据源类型
*/
@Schema(description = "数据源类型")
private Integer category;
/**
* 名称
*/
@Schema(description = "名称")
private String name;
/**
* 驱动类
*/
@Schema(description = "驱动类")
private String driverClass;
/**
* 连接地址
*/
@Schema(description = "连接地址")
private String url;
/**
* 用户名
*/
@Schema(description = "用户名")
private String username;
/**
* 密码
*/
@Schema(description = "密码")
private String password;
/**
* 分库分表配置
*/
@Schema(description = "分库分表配置")
private String shardingConfig;
/**
* 备注
*/
@Schema(description = "备注")
private String remark;
}

View File

@@ -0,0 +1,61 @@
package org.springblade.modules.develop.pojo.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.mp.base.BaseEntity;
import java.io.Serial;
/**
* 数据模型表实体类
*
* @author Chill
*/
@Data
@TableName("blade_model")
@EqualsAndHashCode(callSuper = true)
@Schema(description = "数据模型表")
public class Model extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 数据源主键
*/
@Schema(description = "数据源主键")
@JsonSerialize(using = ToStringSerializer.class)
private Long datasourceId;
/**
* 模型名称
*/
@Schema(description = "模型名称")
private String modelName;
/**
* 模型编号
*/
@Schema(description = "模型编号")
private String modelCode;
/**
* 物理表名
*/
@Schema(description = "物理表名")
private String modelTable;
/**
* 模型类名
*/
@Schema(description = "模型类名")
private String modelClass;
/**
* 模型备注
*/
@Schema(description = "模型备注")
private String modelRemark;
}

View File

@@ -0,0 +1,106 @@
package org.springblade.modules.develop.pojo.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.mp.base.BaseEntity;
import java.io.Serial;
/**
* 数据原型表实体类
*
* @author Chill
*/
@Data
@TableName("blade_model_prototype")
@EqualsAndHashCode(callSuper = true)
@Schema(description = "数据原型表")
public class ModelPrototype extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 模型主键
*/
@Schema(description = "模型主键")
@JsonSerialize(using = ToStringSerializer.class)
private Long modelId;
/**
* 物理列名
*/
@Schema(description = "物理列名")
private String jdbcName;
/**
* 物理类型
*/
@Schema(description = "物理类型")
private String jdbcType;
/**
* 注释说明
*/
@Schema(description = "注释说明")
private String jdbcComment;
/**
* 实体列名
*/
@Schema(description = "实体列名")
private String propertyName;
/**
* 实体类型
*/
@Schema(description = "实体类型")
private String propertyType;
/**
* 实体类型引用
*/
@Schema(description = "实体类型引用")
private String propertyEntity;
/**
* 列表显示
*/
@Schema(description = "列表显示")
private Integer isList;
/**
* 表单显示
*/
@Schema(description = "表单显示")
private Integer isForm;
/**
* 独占一行
*/
@Schema(description = "独占一行")
private Integer isRow;
/**
* 组件类型
*/
@Schema(description = "组件类型")
private String componentType;
/**
* 字典编码
*/
@Schema(description = "字典编码")
private String dictCode;
/**
* 是否必填
*/
@Schema(description = "是否必填")
private Integer isRequired;
/**
* 查询配置
*/
@Schema(description = "查询配置")
private Integer isQuery;
/**
* 查询类型
*/
@Schema(description = "查询类型")
private String queryType;
}

View File

@@ -0,0 +1,23 @@
package org.springblade.modules.develop.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springblade.modules.develop.pojo.entity.Code;
/**
* 服务类
*
* @author Chill
*/
public interface ICodeService extends IService<Code> {
/**
* 提交
*
* @param code
* @return
*/
boolean submit(Code code);
}

View File

@@ -0,0 +1,14 @@
package org.springblade.modules.develop.service;
import org.springblade.core.mp.base.BaseService;
import org.springblade.modules.develop.pojo.entity.Datasource;
/**
* 数据源配置表 服务类
*
* @author Chill
*/
public interface IDatasourceService extends BaseService<Datasource> {
}

View File

@@ -0,0 +1,32 @@
package org.springblade.modules.develop.service;
import org.springblade.core.mp.base.BaseService;
import org.springblade.modules.develop.pojo.entity.ModelPrototype;
import java.util.List;
/**
* 数据原型表 服务类
*
* @author Chill
*/
public interface IModelPrototypeService extends BaseService<ModelPrototype> {
/**
* 批量提交
*
* @param modelPrototypes 原型集合
* @return boolean
*/
boolean submitList(List<ModelPrototype> modelPrototypes);
/**
* 原型列表
*
* @param modelId 模型ID
* @return List<ModelPrototype>
*/
List<ModelPrototype> prototypeList(Long modelId);
}

View File

@@ -0,0 +1,24 @@
package org.springblade.modules.develop.service;
import org.springblade.core.mp.base.BaseService;
import org.springblade.modules.develop.pojo.entity.Model;
import java.util.List;
/**
* 数据模型表 服务类
*
* @author Chill
*/
public interface IModelService extends BaseService<Model> {
/**
* 删除模型
*
* @param ids 主键集合
* @return boolean
*/
boolean delete(List<Long> ids);
}

View File

@@ -0,0 +1,25 @@
package org.springblade.modules.develop.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.modules.develop.pojo.entity.Code;
import org.springblade.modules.develop.mapper.CodeMapper;
import org.springblade.modules.develop.service.ICodeService;
import org.springframework.stereotype.Service;
/**
* 服务实现类
*
* @author Chill
*/
@Service
public class CodeServiceImpl extends ServiceImpl<CodeMapper, Code> implements ICodeService {
@Override
public boolean submit(Code code) {
code.setIsDeleted(BladeConstant.DB_NOT_DELETED);
return saveOrUpdate(code);
}
}

View File

@@ -0,0 +1,18 @@
package org.springblade.modules.develop.service.impl;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.modules.develop.pojo.entity.Datasource;
import org.springblade.modules.develop.mapper.DatasourceMapper;
import org.springblade.modules.develop.service.IDatasourceService;
import org.springframework.stereotype.Service;
/**
* 数据源配置表 服务实现类
*
* @author Chill
*/
@Service
public class DatasourceServiceImpl extends BaseServiceImpl<DatasourceMapper, Datasource> implements IDatasourceService {
}

View File

@@ -0,0 +1,40 @@
package org.springblade.modules.develop.service.impl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.modules.develop.pojo.entity.ModelPrototype;
import org.springblade.modules.develop.mapper.ModelPrototypeMapper;
import org.springblade.modules.develop.service.IModelPrototypeService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* 数据原型表 服务实现类
*
* @author Chill
*/
@Service
public class ModelPrototypeServiceImpl extends BaseServiceImpl<ModelPrototypeMapper, ModelPrototype> implements IModelPrototypeService {
@Override
@Transactional(rollbackFor = Exception.class)
public boolean submitList(List<ModelPrototype> modelPrototypes) {
modelPrototypes.forEach(modelPrototype -> {
if (modelPrototype.getId() == null) {
this.save(modelPrototype);
} else {
this.updateById(modelPrototype);
}
});
return true;
}
@Override
public List<ModelPrototype> prototypeList(Long modelId) {
return this.list(Wrappers.<ModelPrototype>lambdaQuery().eq(ModelPrototype::getModelId, modelId));
}
}

View File

@@ -0,0 +1,52 @@
package org.springblade.modules.develop.service.impl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.modules.develop.pojo.entity.Code;
import org.springblade.modules.develop.pojo.entity.Model;
import org.springblade.modules.develop.pojo.entity.ModelPrototype;
import org.springblade.modules.develop.mapper.ModelMapper;
import org.springblade.modules.develop.service.ICodeService;
import org.springblade.modules.develop.service.IModelPrototypeService;
import org.springblade.modules.develop.service.IModelService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* 数据模型表 服务实现类
*
* @author Chill
*/
@Service
@RequiredArgsConstructor
public class ModelServiceImpl extends BaseServiceImpl<ModelMapper, Model> implements IModelService {
private final IModelPrototypeService modelPrototypeService;
private final ICodeService codeService;
@Override
@Transactional(rollbackFor = Exception.class)
public boolean delete(List<Long> ids) {
boolean modelTemp = this.deleteLogic(ids);
if (modelTemp) {
if (modelPrototypeService.count(Wrappers.<ModelPrototype>lambdaQuery().in(ModelPrototype::getModelId, ids)) > 0) {
boolean prototypeTemp = modelPrototypeService.remove(Wrappers.<ModelPrototype>lambdaQuery().in(ModelPrototype::getModelId, ids));
if (!prototypeTemp) {
throw new ServiceException("删除数据模型成功,关联数据原型删除失败");
}
}
if (codeService.count(Wrappers.<Code>lambdaQuery().in(Code::getModelId, ids)) > 0) {
boolean codeTemp = codeService.remove(Wrappers.<Code>lambdaQuery().in(Code::getModelId, ids));
if (!codeTemp) {
throw new ServiceException("删除数据模型成功,关联代码生成配置删除失败");
}
}
}
return true;
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.modules.martial.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tenant.annotation.TenantDS;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.martial.pojo.entity.Athlete;
import org.springblade.modules.martial.service.IAthleteService;
import org.springblade.modules.martial.pojo.vo.AthleteVO;
import org.springframework.web.bind.annotation.*;
/**
* 运动员控制器
*
* @author BladeX
*/
@TenantDS
@RestController
@RequestMapping("/api/martial/athlete")
@AllArgsConstructor
@Tag(name = "运动员管理", description = "运动员管理接口")
public class AthleteController extends BladeController {
private final IAthleteService athleteService;
/**
* 详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@Operation(summary = "详情", description = "传入athlete")
public R<Athlete> detail(@Parameter(description = "主键", required = true) @RequestParam Long id) {
Athlete detail = athleteService.getById(id);
return R.data(detail);
}
/**
* 分页查询
*/
@GetMapping("/list")
@ApiOperationSupport(order = 2)
@Operation(summary = "分页查询", description = "传入athlete")
public R<IPage<Athlete>> list(Athlete athlete, Query query) {
IPage<Athlete> pages = athleteService.page(Condition.getPage(query), Condition.getQueryWrapper(athlete));
return R.data(pages);
}
/**
* 自定义分页查询
*/
@GetMapping("/page")
@ApiOperationSupport(order = 3)
@Operation(summary = "自定义分页", description = "传入athlete")
public R<IPage<AthleteVO>> page(AthleteVO athlete, Query query) {
IPage<AthleteVO> pages = athleteService.selectAthletePage(Condition.getPage(query), athlete);
return R.data(pages);
}
/**
* 新增
*/
@PostMapping("/save")
@ApiOperationSupport(order = 4)
@Operation(summary = "新增", description = "传入athlete")
public R save(@RequestBody Athlete athlete) {
return R.status(athleteService.save(athlete));
}
/**
* 修改
*/
@PostMapping("/update")
@ApiOperationSupport(order = 5)
@Operation(summary = "修改", description = "传入athlete")
public R update(@RequestBody Athlete athlete) {
return R.status(athleteService.updateById(athlete));
}
/**
* 新增或修改
*/
@PostMapping("/submit")
@ApiOperationSupport(order = 6)
@Operation(summary = "新增或修改", description = "传入athlete")
public R submit(@RequestBody Athlete athlete) {
return R.status(athleteService.saveOrUpdate(athlete));
}
/**
* 删除
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 7)
@Operation(summary = "逻辑删除", description = "传入主键集合")
public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status(athleteService.deleteLogic(Func.toLongList(ids)));
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.modules.martial.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tenant.annotation.TenantDS;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.martial.pojo.entity.Competition;
import org.springblade.modules.martial.service.ICompetitionService;
import org.springblade.modules.martial.pojo.vo.CompetitionVO;
import org.springframework.web.bind.annotation.*;
/**
* 赛事控制器
*
* @author BladeX
*/
@TenantDS
@RestController
@RequestMapping("/api/martial/competition")
@AllArgsConstructor
@Tag(name = "赛事管理", description = "赛事管理接口")
public class CompetitionController extends BladeController {
private final ICompetitionService competitionService;
/**
* 详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@Operation(summary = "详情", description = "传入competition")
public R<Competition> detail(@Parameter(description = "主键", required = true) @RequestParam Long id) {
Competition detail = competitionService.getById(id);
return R.data(detail);
}
/**
* 分页查询
*/
@GetMapping("/list")
@ApiOperationSupport(order = 2)
@Operation(summary = "分页查询", description = "传入competition")
public R<IPage<Competition>> list(Competition competition, Query query) {
IPage<Competition> pages = competitionService.page(Condition.getPage(query), Condition.getQueryWrapper(competition));
return R.data(pages);
}
/**
* 自定义分页查询
*/
@GetMapping("/page")
@ApiOperationSupport(order = 3)
@Operation(summary = "自定义分页", description = "传入competition")
public R<IPage<CompetitionVO>> page(CompetitionVO competition, Query query) {
IPage<CompetitionVO> pages = competitionService.selectCompetitionPage(Condition.getPage(query), competition);
return R.data(pages);
}
/**
* 新增
*/
@PostMapping("/save")
@ApiOperationSupport(order = 4)
@Operation(summary = "新增", description = "传入competition")
public R save(@RequestBody Competition competition) {
return R.status(competitionService.save(competition));
}
/**
* 修改
*/
@PostMapping("/update")
@ApiOperationSupport(order = 5)
@Operation(summary = "修改", description = "传入competition")
public R update(@RequestBody Competition competition) {
return R.status(competitionService.updateById(competition));
}
/**
* 新增或修改
*/
@PostMapping("/submit")
@ApiOperationSupport(order = 6)
@Operation(summary = "新增或修改", description = "传入competition")
public R submit(@RequestBody Competition competition) {
return R.status(competitionService.saveOrUpdate(competition));
}
/**
* 删除
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 7)
@Operation(summary = "逻辑删除", description = "传入主键集合")
public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status(competitionService.deleteLogic(Func.toLongList(ids)));
}
}

View File

@@ -0,0 +1,113 @@
package org.springblade.modules.martial.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.modules.martial.pojo.entity.Judge;
import org.springblade.modules.martial.service.IJudgeService;
import org.springblade.modules.martial.pojo.vo.JudgeVO;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 裁判控制器
*
* @author Blade
* @since 2025-01-01
*/
@RestController
@AllArgsConstructor
@RequestMapping("/api/martial/judge")
@Tag(name = "裁判管理", description = "裁判管理接口")
public class JudgeController extends BladeController {
private final IJudgeService judgeService;
/**
* 详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@Operation(summary = "详情", description = "传入judge")
public R<JudgeVO> detail(@Parameter(description = "主键", required = true) @RequestParam Long id) {
JudgeVO detail = judgeService.getJudgeById(id);
return R.data(detail);
}
/**
* 分页查询
*/
@GetMapping("/list")
@ApiOperationSupport(order = 2)
@Operation(summary = "分页查询", description = "传入judge")
public R<IPage<JudgeVO>> list(JudgeVO judge, Query query) {
IPage<JudgeVO> pages = judgeService.selectJudgePage(Condition.getPage(query), judge);
return R.data(pages);
}
/**
* 新增
*/
@PostMapping("/save")
@ApiOperationSupport(order = 3)
@Operation(summary = "新增", description = "传入judge")
public R save(@Valid @RequestBody Judge judge) {
return R.status(judgeService.save(judge));
}
/**
* 修改
*/
@PostMapping("/update")
@ApiOperationSupport(order = 4)
@Operation(summary = "修改", description = "传入judge")
public R update(@Valid @RequestBody Judge judge) {
return R.status(judgeService.updateById(judge));
}
/**
* 删除
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 5)
@Operation(summary = "删除", description = "传入ids")
public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status(judgeService.removeByIds(org.springblade.core.tool.utils.Func.toLongList(ids)));
}
/**
* 裁判登录认证
*/
@PostMapping("/login")
@ApiOperationSupport(order = 6)
@Operation(summary = "裁判登录认证", description = "传入赛事编码和邀请码")
public R<JudgeVO> login(@Parameter(description = "赛事编码", required = true) @RequestParam String competitionCode,
@Parameter(description = "邀请码", required = true) @RequestParam String inviteCode) {
JudgeVO judge = judgeService.judgeLogin(competitionCode, inviteCode);
if (judge == null) {
return R.fail("赛事编码或邀请码错误");
}
return R.data(judge);
}
/**
* 根据赛事ID查询裁判列表
*/
@GetMapping("/listByCompetition")
@ApiOperationSupport(order = 7)
@Operation(summary = "根据赛事ID查询裁判列表", description = "传入competitionId")
public R<List<JudgeVO>> listByCompetition(@Parameter(description = "赛事ID", required = true) @RequestParam Long competitionId) {
List<JudgeVO> list = judgeService.getJudgeByCompetitionId(competitionId);
return R.data(list);
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.modules.martial.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tenant.annotation.TenantDS;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.martial.pojo.entity.Project;
import org.springblade.modules.martial.service.IProjectService;
import org.springblade.modules.martial.pojo.vo.ProjectVO;
import org.springframework.web.bind.annotation.*;
/**
* 项目控制器
*
* @author BladeX
*/
@TenantDS
@RestController
@RequestMapping("/api/martial/project")
@AllArgsConstructor
@Tag(name = "项目管理", description = "项目管理接口")
public class ProjectController extends BladeController {
private final IProjectService projectService;
/**
* 详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@Operation(summary = "详情", description = "传入project")
public R<Project> detail(@Parameter(description = "主键", required = true) @RequestParam Long id) {
Project detail = projectService.getById(id);
return R.data(detail);
}
/**
* 分页查询
*/
@GetMapping("/list")
@ApiOperationSupport(order = 2)
@Operation(summary = "分页查询", description = "传入project")
public R<IPage<Project>> list(Project project, Query query) {
IPage<Project> pages = projectService.page(Condition.getPage(query), Condition.getQueryWrapper(project));
return R.data(pages);
}
/**
* 自定义分页查询
*/
@GetMapping("/page")
@ApiOperationSupport(order = 3)
@Operation(summary = "自定义分页", description = "传入project")
public R<IPage<ProjectVO>> page(ProjectVO project, Query query) {
IPage<ProjectVO> pages = projectService.selectProjectPage(Condition.getPage(query), project);
return R.data(pages);
}
/**
* 新增
*/
@PostMapping("/save")
@ApiOperationSupport(order = 4)
@Operation(summary = "新增", description = "传入project")
public R save(@RequestBody Project project) {
return R.status(projectService.save(project));
}
/**
* 修改
*/
@PostMapping("/update")
@ApiOperationSupport(order = 5)
@Operation(summary = "修改", description = "传入project")
public R update(@RequestBody Project project) {
return R.status(projectService.updateById(project));
}
/**
* 新增或修改
*/
@PostMapping("/submit")
@ApiOperationSupport(order = 6)
@Operation(summary = "新增或修改", description = "传入project")
public R submit(@RequestBody Project project) {
return R.status(projectService.saveOrUpdate(project));
}
/**
* 删除
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 7)
@Operation(summary = "逻辑删除", description = "传入主键集合")
public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status(projectService.deleteLogic(Func.toLongList(ids)));
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.modules.martial.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tenant.annotation.TenantDS;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.martial.pojo.entity.RegistrationOrder;
import org.springblade.modules.martial.service.IRegistrationOrderService;
import org.springblade.modules.martial.pojo.vo.RegistrationOrderVO;
import org.springframework.web.bind.annotation.*;
/**
* 报名订单控制器
*
* @author BladeX
*/
@TenantDS
@RestController
@RequestMapping("/api/martial/registrationorder")
@AllArgsConstructor
@Tag(name = "报名订单管理", description = "报名订单管理接口")
public class RegistrationOrderController extends BladeController {
private final IRegistrationOrderService registrationOrderService;
/**
* 详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@Operation(summary = "详情", description = "传入registrationOrder")
public R<RegistrationOrder> detail(@Parameter(description = "主键", required = true) @RequestParam Long id) {
RegistrationOrder detail = registrationOrderService.getById(id);
return R.data(detail);
}
/**
* 分页查询
*/
@GetMapping("/list")
@ApiOperationSupport(order = 2)
@Operation(summary = "分页查询", description = "传入registrationOrder")
public R<IPage<RegistrationOrder>> list(RegistrationOrder registrationOrder, Query query) {
IPage<RegistrationOrder> pages = registrationOrderService.page(Condition.getPage(query), Condition.getQueryWrapper(registrationOrder));
return R.data(pages);
}
/**
* 自定义分页查询
*/
@GetMapping("/page")
@ApiOperationSupport(order = 3)
@Operation(summary = "自定义分页", description = "传入registrationOrder")
public R<IPage<RegistrationOrderVO>> page(RegistrationOrderVO registrationOrder, Query query) {
IPage<RegistrationOrderVO> pages = registrationOrderService.selectRegistrationOrderPage(Condition.getPage(query), registrationOrder);
return R.data(pages);
}
/**
* 新增
*/
@PostMapping("/save")
@ApiOperationSupport(order = 4)
@Operation(summary = "新增", description = "传入registrationOrder")
public R save(@RequestBody RegistrationOrder registrationOrder) {
return R.status(registrationOrderService.save(registrationOrder));
}
/**
* 修改
*/
@PostMapping("/update")
@ApiOperationSupport(order = 5)
@Operation(summary = "修改", description = "传入registrationOrder")
public R update(@RequestBody RegistrationOrder registrationOrder) {
return R.status(registrationOrderService.updateById(registrationOrder));
}
/**
* 新增或修改
*/
@PostMapping("/submit")
@ApiOperationSupport(order = 6)
@Operation(summary = "新增或修改", description = "传入registrationOrder")
public R submit(@RequestBody RegistrationOrder registrationOrder) {
return R.status(registrationOrderService.saveOrUpdate(registrationOrder));
}
/**
* 删除
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 7)
@Operation(summary = "逻辑删除", description = "传入主键集合")
public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status(registrationOrderService.deleteLogic(Func.toLongList(ids)));
}
}

Some files were not shown because too many files have changed in this diff Show More