发布 v2.5.0

This commit is contained in:
疯狂的狮子li
2021-07-12 11:36:37 +08:00
parent 7e3bbb4aab
commit 007a6d0c88
82 changed files with 2952 additions and 785 deletions

View File

@ -2,7 +2,7 @@ package com.ruoyi.common.constant;
/**
* 用户常量信息
*
*
* @author ruoyi
*/
public class UserConstants
@ -57,6 +57,9 @@ public class UserConstants
/** ParentView组件标识 */
public final static String PARENT_VIEW = "ParentView";
/** InnerLink组件标识 */
public final static String INNER_LINK = "InnerLink";
/** 校验返回结果码 */
public final static String UNIQUE = "0";
public final static String NOT_UNIQUE = "1";

View File

@ -148,6 +148,10 @@ public class SysUser implements Serializable
@TableField(exist = false)
private Long[] postIds;
/** 角色ID */
@TableField(exist = false)
private Long roleId;
public SysUser(Long userId)
{
this.userId = userId;

View File

@ -15,6 +15,9 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* mybatis-redis 二级缓存
*
* 使用方法 配置文件开启 mybatis-plus 二级缓存
* 在 XxxMapper.java 类上添加注解 @CacheNamespace(implementation = MybatisPlusRedisCache.class, eviction = MybatisPlusRedisCache.class)
*
* @author Lion Li
*/
@Slf4j

View File

@ -1,13 +1,17 @@
package com.ruoyi.common.core.mybatisplus.methods;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
/**
* 单sql批量插入
*
@ -20,9 +24,28 @@ public class InsertAll extends AbstractMethod {
final String sql = "<script>insert into %s %s values %s</script>";
final String fieldSql = prepareFieldSql(tableInfo);
final String valueSql = prepareValuesSqlForMysqlBatch(tableInfo);
KeyGenerator keyGenerator = new NoKeyGenerator();
SqlMethod sqlMethod = SqlMethod.INSERT_ONE;
String keyProperty = null;
String keyColumn = null;
// 表包含主键处理逻辑,如果不包含主键当普通字段处理
if (StrUtil.isNotBlank(tableInfo.getKeyProperty())) {
if (tableInfo.getIdType() == IdType.AUTO) {
/** 自增主键 */
keyGenerator = new Jdbc3KeyGenerator();
keyProperty = tableInfo.getKeyProperty();
keyColumn = tableInfo.getKeyColumn();
} else {
if (null != tableInfo.getKeySequence()) {
keyGenerator = TableInfoHelper.genKeyGenerator(getMethod(sqlMethod), tableInfo, builderAssistant);
keyProperty = tableInfo.getKeyProperty();
keyColumn = tableInfo.getKeyColumn();
}
}
}
final String sqlResult = String.format(sql, tableInfo.getTableName(), fieldSql, valueSql);
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);
return this.addInsertMappedStatement(mapperClass, modelClass, "insertAll", sqlSource, new NoKeyGenerator(), null, null);
return this.addInsertMappedStatement(mapperClass, modelClass, "insertAll", sqlSource, keyGenerator, keyProperty, keyColumn);
}
private String prepareFieldSql(TableInfo tableInfo) {

View File

@ -205,9 +205,9 @@ public class RedisCache {
* @param hKeys Hash键集合
* @return Hash对象集合
*/
public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
RListMultimap rListMultimap = redissonClient.getListMultimap(key);
return rListMultimap.getAll(hKeys);
public <K,V> Map<K,V> getMultiCacheMapValue(final String key, final Set<K> hKeys) {
RMap<K,V> rMap = redissonClient.getMap(key);
return rMap.getAll(hKeys);
}
/**

View File

@ -88,7 +88,7 @@ public class DictUtils
StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType);
if (StrUtil.containsAny(separator, dictValue) && CollUtil.isNotEmpty(datas))
if (StrUtil.containsAny(dictValue, separator) && CollUtil.isNotEmpty(datas))
{
for (SysDictData dict : datas)
{
@ -128,7 +128,7 @@ public class DictUtils
StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType);
if (StrUtil.containsAny(separator, dictLabel) && CollUtil.isNotEmpty(datas))
if (StrUtil.containsAny(dictLabel, separator) && CollUtil.isNotEmpty(datas))
{
for (SysDictData dict : datas)
{

View File

@ -0,0 +1,28 @@
package com.ruoyi.common.utils;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.constant.Constants;
/**
* 字符串工具类
*
* @author ruoyi
*/
public class StringUtils extends org.apache.commons.lang3.StringUtils {
/** 空字符串 */
private static final String NULLSTR = "";
/** 下划线 */
private static final char SEPARATOR = '_';
/**
* 是否为http(s)://开头
*
* @param link 链接
* @return 结果
*/
public static boolean ishttp(String link) {
return StrUtil.startWithAny(link, Constants.HTTP, Constants.HTTPS);
}
}

View File

@ -32,7 +32,7 @@ import java.util.stream.Collectors;
/**
* Excel相关处理
*
*
* @author ruoyi
*/
public class ExcelUtil<T>
@ -88,12 +88,12 @@ public class ExcelUtil<T>
* 统计列表
*/
private Map<Integer, Double> statistics = new HashMap<Integer, Double>();
/**
* 数字格式
*/
private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00");
/**
* 实体对象
*/
@ -119,7 +119,7 @@ public class ExcelUtil<T>
/**
* 对excel表单默认第一个索引名转换成list
*
*
* @param is 输入流
* @return 转换后集合
*/
@ -130,7 +130,7 @@ public class ExcelUtil<T>
/**
* 对excel表单指定表格索引名转换成list
*
*
* @param sheetName 表格索引名
* @param is 输入流
* @return 转换后集合
@ -298,7 +298,7 @@ public class ExcelUtil<T>
/**
* 对list数据源将其里面的数据导入到excel表单
*
*
* @param list 导出数据集合
* @param sheetName 工作表的名称
* @return 结果
@ -311,7 +311,7 @@ public class ExcelUtil<T>
/**
* 对list数据源将其里面的数据导入到excel表单
*
*
* @param sheetName 工作表的名称
* @return 结果
*/
@ -323,7 +323,7 @@ public class ExcelUtil<T>
/**
* 对list数据源将其里面的数据导入到excel表单
*
*
* @return 结果
*/
public AjaxResult exportExcel()
@ -391,7 +391,7 @@ public class ExcelUtil<T>
/**
* 填充excel数据
*
*
* @param index 序号
* @param row 单元格行
*/
@ -418,7 +418,7 @@ public class ExcelUtil<T>
/**
* 创建表格样式
*
*
* @param wb 工作薄对象
* @return 样式列表
*/
@ -456,7 +456,7 @@ public class ExcelUtil<T>
headerFont.setColor(IndexedColors.WHITE.getIndex());
style.setFont(headerFont);
styles.put("header", style);
style = wb.createCellStyle();
style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(VerticalAlignment.CENTER);
@ -500,7 +500,7 @@ public class ExcelUtil<T>
/**
* 设置单元格信息
*
*
* @param value 单元格值
* @param attr 注解相关
* @param cell 单元格信息
@ -531,7 +531,7 @@ public class ExcelUtil<T>
}
}
}
/**
* 获取画布
*/
@ -646,7 +646,7 @@ public class ExcelUtil<T>
/**
* 设置 POI XSSFSheet 单元格提示
*
*
* @param sheet 表单
* @param promptTitle 提示标题
* @param promptContent 提示内容
@ -669,7 +669,7 @@ public class ExcelUtil<T>
/**
* 设置某些列的值只能输入预制的数据,显示下拉框.
*
*
* @param sheet 要设置的sheet.
* @param textlist 下拉框显示的内容
* @param firstRow 开始行
@ -703,7 +703,7 @@ public class ExcelUtil<T>
/**
* 解析导出值 0=男,1=女,2=未知
*
*
* @param propertyValue 参数值
* @param converterExp 翻译注解
* @param separator 分隔符
@ -716,7 +716,7 @@ public class ExcelUtil<T>
for (String item : convertSource)
{
String[] itemArray = item.split("=");
if (StrUtil.containsAny(separator, propertyValue))
if (StrUtil.containsAny(propertyValue, separator))
{
for (String value : propertyValue.split(separator))
{
@ -740,7 +740,7 @@ public class ExcelUtil<T>
/**
* 反向解析值 男=0,女=1,未知=2
*
*
* @param propertyValue 参数值
* @param converterExp 翻译注解
* @param separator 分隔符
@ -753,7 +753,7 @@ public class ExcelUtil<T>
for (String item : convertSource)
{
String[] itemArray = item.split("=");
if (StrUtil.containsAny(separator, propertyValue))
if (StrUtil.containsAny(propertyValue, separator))
{
for (String value : propertyValue.split(separator))
{
@ -774,10 +774,10 @@ public class ExcelUtil<T>
}
return StrUtil.strip(propertyString.toString(), null,separator);
}
/**
* 解析字典值
*
*
* @param dictValue 字典值
* @param dictType 字典类型
* @param separator 分隔符
@ -790,7 +790,7 @@ public class ExcelUtil<T>
/**
* 反向解析值字典值
*
*
* @param dictLabel 字典标签
* @param dictType 字典类型
* @param separator 分隔符
@ -800,7 +800,7 @@ public class ExcelUtil<T>
{
return DictUtils.getDictValue(dictType, dictLabel, separator);
}
/**
* 合计统计信息
*/
@ -837,7 +837,7 @@ public class ExcelUtil<T>
cell = row.createCell(0);
cell.setCellStyle(styles.get("total"));
cell.setCellValue("合计");
for (Integer key : keys)
{
cell = row.createCell(key);
@ -859,7 +859,7 @@ public class ExcelUtil<T>
/**
* 获取下载路径
*
*
* @param filename 文件名称
*/
public String getAbsoluteFile(String filename)
@ -875,7 +875,7 @@ public class ExcelUtil<T>
/**
* 获取bean中的属性值
*
*
* @param vo 实体对象
* @param field 字段
* @param excel 注解
@ -906,7 +906,7 @@ public class ExcelUtil<T>
/**
* 以类的属性的get方法方法形式获取值
*
*
* @param o
* @param name
* @return value
@ -955,7 +955,7 @@ public class ExcelUtil<T>
this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());
this.maxHeight = getRowHeight();
}
/**
* 根据注解获取最大行高
*/
@ -991,7 +991,7 @@ public class ExcelUtil<T>
/**
* 创建工作表
*
*
* @param sheetNo sheet数量
* @param index 序号
*/
@ -1012,7 +1012,7 @@ public class ExcelUtil<T>
/**
* 获取单元格值
*
*
* @param row 获取的行
* @param column 获取单元格列号
* @return 单元格值
@ -1069,4 +1069,4 @@ public class ExcelUtil<T>
}
return val;
}
}
}

View File

@ -0,0 +1,70 @@
package com.ruoyi.demo.controller;
import com.ruoyi.common.core.domain.AjaxResult;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* spring-cache 演示案例
*
* @author Lion Li
*/
// 类级别 缓存统一配置
//@CacheConfig(cacheNames = "redissonCacheMap")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
@RequestMapping("/demo/cache")
public class RedisCacheController {
/**
* 测试 @Cacheable
*
* 表示这个方法有了缓存的功能,方法的返回值会被缓存下来
* 下一次调用该方法前,会去检查是否缓存中已经有值
* 如果有就直接返回,不调用方法
* 如果没有,就调用方法,然后把结果缓存起来
* 这个注解「一般用在查询方法上」
*
* cacheNames 为配置文件内 groupId
*/
@Cacheable(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null")
@GetMapping("/test1")
public AjaxResult<String> test1(String key, String value){
return AjaxResult.success("操作成功", value);
}
/**
* 测试 @CachePut
*
* 加了@CachePut注解的方法,会把方法的返回值put到缓存里面缓存起来,供其它地方使用
* 它「通常用在新增方法上」
*
* cacheNames 为 配置文件内 groupId
*/
@CachePut(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null")
@GetMapping("/test2")
public AjaxResult<String> test2(String key, String value){
return AjaxResult.success("操作成功", value);
}
/**
* 测试 @CacheEvict
*
* 使用了CacheEvict注解的方法,会清空指定缓存
* 「一般用在更新或者删除的方法上」
*
* cacheNames 为 配置文件内 groupId
*/
@CacheEvict(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null")
@GetMapping("/test3")
public AjaxResult<String> test3(String key, String value){
return AjaxResult.success("操作成功", value);
}
}

View File

@ -7,7 +7,10 @@ import org.springframework.stereotype.Component;
/**
* feign测试fallback
* 自定义封装结构体熔断
* 需重写解码器 根据自定义实体 自行解析熔断
*
* @see {com.ruoyi.framework.config.FeignConfig#errorDecoder()}
* @author Lion Li
*/
@Slf4j

View File

@ -1,63 +0,0 @@
package com.ruoyi.framework.config;
import de.codecentric.boot.admin.server.config.EnableAdminServer;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;
import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties;
import org.springframework.boot.task.TaskExecutorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.thymeleaf.dialect.IDialect;
import org.thymeleaf.spring5.ISpringTemplateEngine;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.templateresolver.ITemplateResolver;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
/**
* springboot-admin server配置类
*
* @author Lion Li
*/
@Configuration
@EnableAdminServer
public class AdminServerConfig {
@Lazy
@Bean(name = TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)
@ConditionalOnMissingBean(Executor.class)
public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) {
return builder.build();
}
/**
* 解决 admin 与 项目 页面的交叉引用 将 admin 的路由放到最后
* @param properties
* @param templateResolvers
* @param dialects
* @return
*/
@Bean
@ConditionalOnMissingBean(ISpringTemplateEngine.class)
SpringTemplateEngine templateEngine(ThymeleafProperties properties,
ObjectProvider<ITemplateResolver> templateResolvers, ObjectProvider<IDialect> dialects) {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setEnableSpringELCompiler(properties.isEnableSpringElCompiler());
engine.setRenderHiddenMarkersBeforeCheckboxes(properties.isRenderHiddenMarkersBeforeCheckboxes());
templateResolvers.orderedStream().forEach(engine::addTemplateResolver);
dialects.orderedStream().forEach(engine::addDialect);
Set<ITemplateResolver> templateResolvers1 = engine.getTemplateResolvers();
templateResolvers1 = templateResolvers1.stream()
.sorted(Comparator.comparing(ITemplateResolver::getOrder))
.collect(Collectors.toCollection(LinkedHashSet::new));
engine.setTemplateResolvers(templateResolvers1);
return engine;
}
}

View File

@ -54,4 +54,40 @@ public class FeignConfig {
return new Retryer.Default();
}
// /**
// * 自定义异常解码器
// * 用于自定义返回体异常熔断
// */
// @Bean
// public ErrorDecoder errorDecoder() {
// return new CustomErrorDecoder();
// }
//
//
// /**
// * 自定义返回体解码器
// */
// @Slf4j
// public static class CustomErrorDecoder implements ErrorDecoder {
//
// @Override
// public Exception decode(String methodKey, Response response) {
// Exception exception = null;
// try {
// // 获取原始的返回内容
// String json = JsonUtils.toJsonString(response.body().asReader(StandardCharsets.UTF_8));
// exception = new RuntimeException(json);
// // 将返回内容反序列化为Result这里应根据自身项目作修改
// AjaxResult result = JsonUtils.parseObject(json, AjaxResult.class);
// // 业务异常抛出简单的 RuntimeException保留原来错误信息
// if (result.getCode() != 200) {
// exception = new RuntimeException(result.getMsg());
// }
// } catch (IOException e) {
// log.error(e.getMessage(), e);
// }
// return exception;
// }
// }
}

View File

@ -19,6 +19,7 @@ import org.springframework.context.annotation.Configuration;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
@ -78,8 +79,13 @@ public class RedisConfig extends CachingConfigurerSupport {
*/
@Bean
public CacheManager cacheManager(RedissonClient redissonClient) {
List<RedissonProperties.CacheGroup> cacheGroup = redissonProperties.getCacheGroup();
Map<String, CacheConfig> config = new HashMap<>();
config.put("redissonCacheMap", new CacheConfig(30*60*1000, 10*60*1000));
for (RedissonProperties.CacheGroup group : cacheGroup) {
CacheConfig cacheConfig = new CacheConfig(group.getTtl(), group.getMaxIdleTime());
cacheConfig.setMaxSize(group.getMaxSize());
config.put(group.getGroupId(), cacheConfig);
}
return new RedissonSpringCacheManager(redissonClient, config, JsonJacksonCodec.INSTANCE);
}

View File

@ -3,7 +3,6 @@ package com.ruoyi.framework.config;
import com.ruoyi.framework.security.filter.JwtAuthenticationTokenFilter;
import com.ruoyi.framework.security.handle.AuthenticationEntryPointImpl;
import com.ruoyi.framework.security.handle.LogoutSuccessHandlerImpl;
import de.codecentric.boot.admin.server.config.AdminServerProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
@ -57,9 +56,6 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
@Autowired
private CorsFilter corsFilter;
@Autowired
private AdminServerProperties adminServerProperties;
/**
* 解决 无法直接注入 AuthenticationManager
*
@ -104,12 +100,13 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
.antMatchers("/login", "/captchaImage").anonymous()
.antMatchers(
HttpMethod.GET,
"/",
"/*.html",
"/**/*.html",
"/**/*.css",
"/**/*.js"
"/**/*.js",
"/profile/**"
).permitAll()
.antMatchers("/profile/**").anonymous()
.antMatchers("/common/download**").anonymous()
.antMatchers("/common/download/resource**").anonymous()
.antMatchers("/doc.html").anonymous()
@ -117,9 +114,6 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
.antMatchers("/webjars/**").anonymous()
.antMatchers("/*/api-docs").anonymous()
.antMatchers("/druid/**").anonymous()
// Spring Boot Admin Server 的安全配置
.antMatchers(adminServerProperties.getContextPath()).anonymous()
.antMatchers(adminServerProperties.getContextPath() + "/**").anonymous()
// Spring Boot Actuator 的安全配置
.antMatchers("/actuator").anonymous()
.antMatchers("/actuator/**").anonymous()

View File

@ -2,11 +2,12 @@ package com.ruoyi.framework.config.properties;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.redisson.client.codec.Codec;
import org.redisson.config.TransportMode;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* Redisson 配置属性
*
@ -37,6 +38,11 @@ public class RedissonProperties {
*/
private SingleServerConfig singleServerConfig;
/**
* 缓存组
*/
private List<CacheGroup> cacheGroup;
@Data
@NoArgsConstructor
public static class SingleServerConfig {
@ -98,4 +104,30 @@ public class RedissonProperties {
}
@Data
@NoArgsConstructor
public static class CacheGroup {
/**
* 组id
*/
private String groupId;
/**
* 组过期时间
*/
private long ttl;
/**
* 组最大空闲时间
*/
private long maxIdleTime;
/**
* 组最大长度
*/
private int maxSize;
}
}

View File

@ -1,6 +1,8 @@
package com.ruoyi.framework.mybatisplus;
import cn.hutool.http.HttpStatus;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.utils.SecurityUtils;
import org.apache.ibatis.reflection.MetaObject;
@ -8,6 +10,7 @@ import java.util.Date;
/**
* MP注入处理器
*
* @author Lion Li
* @date 2021/4/25
*/
@ -15,30 +18,38 @@ public class CreateAndUpdateMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
//根据属性名字设置要填充的值
if (metaObject.hasGetter("createTime")) {
if (metaObject.getValue("createTime") == null) {
this.setFieldValByName("createTime", new Date(), metaObject);
try {
//根据属性名字设置要填充的值
if (metaObject.hasGetter("createTime")) {
if (metaObject.getValue("createTime") == null) {
this.setFieldValByName("createTime", new Date(), metaObject);
}
}
}
if (metaObject.hasGetter("createBy")) {
if (metaObject.getValue("createBy") == null) {
this.setFieldValByName("createBy", SecurityUtils.getUsername(), metaObject);
if (metaObject.hasGetter("createBy")) {
if (metaObject.getValue("createBy") == null) {
this.setFieldValByName("createBy", SecurityUtils.getUsername(), metaObject);
}
}
} catch (Exception e) {
throw new CustomException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
}
}
@Override
public void updateFill(MetaObject metaObject) {
if (metaObject.hasGetter("updateBy")) {
if (metaObject.getValue("updateBy") == null) {
this.setFieldValByName("updateBy", SecurityUtils.getUsername(), metaObject);
try {
if (metaObject.hasGetter("updateBy")) {
if (metaObject.getValue("updateBy") == null) {
this.setFieldValByName("updateBy", SecurityUtils.getUsername(), metaObject);
}
}
}
if (metaObject.hasGetter("updateTime")) {
if (metaObject.getValue("updateTime") == null) {
this.setFieldValByName("updateTime", new Date(), metaObject);
if (metaObject.hasGetter("updateTime")) {
if (metaObject.getValue("updateTime") == null) {
this.setFieldValByName("updateTime", new Date(), metaObject);
}
}
} catch (Exception e) {
throw new CustomException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
}
}

View File

@ -182,9 +182,9 @@ public class GenTableServiceImpl extends ServicePlusImpl<GenTableMapper, GenTabl
List<GenTableColumn> genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
for (GenTableColumn column : genTableColumns) {
GenUtils.initColumnField(column, table);
genTableColumnMapper.insert(column);
}
}
genTableColumnMapper.insertAll(genTableColumns);
}
}
} catch (Exception e) {
throw new CustomException("导入失败:" + e.getMessage());
@ -258,7 +258,7 @@ public class GenTableServiceImpl extends ServicePlusImpl<GenTableMapper, GenTabl
// 获取模板列表
List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
for (String template : templates) {
if (!StrUtil.containsAny(template, "sql.vm", "api.js.vm", "index.vue.vm", "index-tree.vue.vm")) {
if (!StrUtil.containsAny("sql.vm", "api.js.vm", "index.vue.vm", "index-tree.vue.vm", template)) {
// 渲染模板
StringWriter sw = new StringWriter();
Template tpl = Velocity.getTemplate(template, Constants.UTF8);
@ -290,9 +290,9 @@ public class GenTableServiceImpl extends ServicePlusImpl<GenTableMapper, GenTabl
dbTableColumns.forEach(column -> {
if (!tableColumnNames.contains(column.getColumnName())) {
GenUtils.initColumnField(column, table);
genTableColumnMapper.insert(column);
}
});
}
});
genTableColumnMapper.insertAll(tableColumns);
List<GenTableColumn> delColumns = tableColumns.stream().filter(column -> !dbTableColumnNames.contains(column.getColumnName())).collect(Collectors.toList());
if (CollUtil.isNotEmpty(delColumns)) {

View File

@ -1,6 +1,8 @@
package com.ruoyi.system.domain.vo;
import lombok.*;
import com.ruoyi.common.utils.StringUtils;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
@ -28,6 +30,11 @@ public class MetaVo {
*/
private boolean noCache;
/**
* 内链地址http(s)://开头)
*/
private String link;
public MetaVo(String title, String icon) {
this.title = title;
this.icon = icon;
@ -39,4 +46,19 @@ public class MetaVo {
this.noCache = noCache;
}
public MetaVo(String title, String icon, String link) {
this.title = title;
this.icon = icon;
this.link = link;
}
public MetaVo(String title, String icon, boolean noCache, String link) {
this.title = title;
this.icon = icon;
this.noCache = noCache;
if (StringUtils.ishttp(link)) {
this.link = link;
}
}
}

View File

@ -24,6 +24,22 @@ public interface SysUserMapper extends BaseMapperPlus<SysUser> {
*/
public List<SysUser> selectUserList(SysUser sysUser);
/**
* 根据条件分页查询未已配用户角色列表
*
* @param user 用户信息
* @return 用户信息集合信息
*/
public Page<SysUser> selectAllocatedList(@Param("page") Page<SysUser> page, @Param("user") SysUser user);
/**
* 根据条件分页查询未分配用户角色列表
*
* @param user 用户信息
* @return 用户信息集合信息
*/
public Page<SysUser> selectUnallocatedList(@Param("page") Page<SysUser> page, @Param("user") SysUser user);
/**
* 通过用户名查询用户
*

View File

@ -3,6 +3,8 @@ package com.ruoyi.system.service;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.mybatisplus.core.IServicePlus;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.system.domain.SysUserRole;
import java.util.List;
import java.util.Set;
@ -26,7 +28,15 @@ public interface ISysRoleService extends IServicePlus<SysRole> {
public List<SysRole> selectRoleList(SysRole role);
/**
* 根据用户ID查询角色
* 根据用户ID查询角色列表
*
* @param userId 用户ID
* @return 角色列表
*/
public List<SysRole> selectRolesByUserId(Long userId);
/**
* 根据用户ID查询角色权限
*
* @param userId 用户ID
* @return 权限列表
@ -134,4 +144,30 @@ public interface ISysRoleService extends IServicePlus<SysRole> {
* @return 结果
*/
public int deleteRoleByIds(Long[] roleIds);
/**
* 取消授权用户角色
*
* @param userRole 用户和角色关联信息
* @return 结果
*/
public int deleteAuthUser(SysUserRole userRole);
/**
* 批量取消授权用户角色
*
* @param roleId 角色ID
* @param userIds 需要取消授权的用户数据ID
* @return 结果
*/
public int deleteAuthUsers(Long roleId, Long[] userIds);
/**
* 批量选择授权用户角色
*
* @param roleId 角色ID
* @param userIds 需要删除的用户数据ID
* @return 结果
*/
public int insertAuthUsers(Long roleId, Long[] userIds);
}

View File

@ -24,6 +24,22 @@ public interface ISysUserService extends IServicePlus<SysUser> {
*/
public List<SysUser> selectUserList(SysUser user);
/**
* 根据条件分页查询已分配用户角色列表
*
* @param user 用户信息
* @return 用户信息集合信息
*/
public TableDataInfo<SysUser> selectAllocatedList(SysUser user);
/**
* 根据条件分页查询未分配用户角色列表
*
* @param user 用户信息
* @return 用户信息集合信息
*/
public TableDataInfo<SysUser> selectUnallocatedList(SysUser user);
/**
* 通过用户名查询用户
*
@ -103,6 +119,14 @@ public interface ISysUserService extends IServicePlus<SysUser> {
*/
public int updateUser(SysUser user);
/**
* 用户授权角色
*
* @param userId 用户ID
* @param roleIds 角色组
*/
public void insertUserAuth(Long userId, Long[] roleIds);
/**
* 修改用户状态
*
@ -123,7 +147,7 @@ public interface ISysUserService extends IServicePlus<SysUser> {
* 修改用户头像
*
* @param userName 用户名
* @param avatar 头像地址
* @param avatar 头像地址
* @return 结果
*/
public boolean updateUserAvatar(String userName, String avatar);
@ -164,9 +188,9 @@ public interface ISysUserService extends IServicePlus<SysUser> {
/**
* 导入用户数据
*
* @param userList 用户数据列表
* @param userList 用户数据列表
* @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据
* @param operName 操作用户
* @param operName 操作用户
* @return 结果
*/
public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName);

View File

@ -3,6 +3,7 @@ package com.ruoyi.system.service.impl;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.TreeSelect;
import com.ruoyi.common.core.domain.entity.SysMenu;
@ -10,6 +11,7 @@ import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysRoleMenu;
import com.ruoyi.system.domain.vo.MetaVo;
import com.ruoyi.system.domain.vo.RouterVo;
@ -135,7 +137,7 @@ public class SysMenuServiceImpl extends ServicePlusImpl<SysMenuMapper, SysMenu>
router.setName(getRouteName(menu));
router.setPath(getRouterPath(menu));
router.setComponent(getComponent(menu));
router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StrUtil.equals("1", menu.getIsCache())));
router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StrUtil.equals("1", menu.getIsCache()), menu.getPath()));
List<SysMenu> cMenus = menu.getChildren();
if (!cMenus.isEmpty() && UserConstants.TYPE_DIR.equals(menu.getMenuType())) {
router.setAlwaysShow(true);
@ -148,7 +150,19 @@ public class SysMenuServiceImpl extends ServicePlusImpl<SysMenuMapper, SysMenu>
children.setPath(menu.getPath());
children.setComponent(menu.getComponent());
children.setName(StrUtil.upperFirst(menu.getPath()));
children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StrUtil.equals("1", menu.getIsCache())));
children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StrUtil.equals("1", menu.getIsCache()), menu.getPath()));
childrenList.add(children);
router.setChildren(childrenList);
} else if (menu.getParentId().intValue() == 0 && isInnerLink(menu)) {
router.setMeta(null);
router.setPath("/inner");
List<RouterVo> childrenList = new ArrayList<RouterVo>();
RouterVo children = new RouterVo();
String routerPath = StringUtils.replaceEach(menu.getPath(), new String[] { Constants.HTTP, Constants.HTTPS }, new String[] { "", "" });
children.setPath(routerPath);
children.setComponent(UserConstants.INNER_LINK);
children.setName(StringUtils.capitalize(routerPath));
children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath()));
childrenList.add(children);
router.setChildren(childrenList);
}
@ -305,6 +319,10 @@ public class SysMenuServiceImpl extends ServicePlusImpl<SysMenuMapper, SysMenu>
*/
public String getRouterPath(SysMenu menu) {
String routerPath = menu.getPath();
// 内链打开外网方式
if (menu.getParentId().intValue() != 0 && isInnerLink(menu)) {
routerPath = StringUtils.replaceEach(routerPath, new String[] { Constants.HTTP, Constants.HTTPS }, new String[] { "", "" });
}
// 非外链并且是一级目录(类型为目录)
if (0 == menu.getParentId().intValue() && UserConstants.TYPE_DIR.equals(menu.getMenuType())
&& UserConstants.NO_FRAME.equals(menu.getIsFrame())) {
@ -327,7 +345,9 @@ public class SysMenuServiceImpl extends ServicePlusImpl<SysMenuMapper, SysMenu>
String component = UserConstants.LAYOUT;
if (StrUtil.isNotEmpty(menu.getComponent()) && !isMenuFrame(menu)) {
component = menu.getComponent();
} else if (StrUtil.isEmpty(menu.getComponent()) && isParentView(menu)) {
} else if (StrUtil.isEmpty(menu.getComponent()) && menu.getParentId().intValue() != 0 && isInnerLink(menu)) {
component = UserConstants.INNER_LINK;
} else if (StrUtil.isEmpty(menu.getComponent()) && isParentView(menu)) {
component = UserConstants.PARENT_VIEW;
}
return component;
@ -344,6 +364,16 @@ public class SysMenuServiceImpl extends ServicePlusImpl<SysMenuMapper, SysMenu>
&& menu.getIsFrame().equals(UserConstants.NO_FRAME);
}
/**
* 是否为内链组件
*
* @param menu 菜单信息
* @return 结果
*/
public boolean isInnerLink(SysMenu menu) {
return menu.getIsFrame().equals(UserConstants.NO_FRAME) && StringUtils.ishttp(menu.getPath());
}
/**
* 是否为parent_view组件
*
@ -357,7 +387,7 @@ public class SysMenuServiceImpl extends ServicePlusImpl<SysMenuMapper, SysMenu>
/**
* 根据父节点的ID获取所有子节点
*
* @param list 分类表
* @param list 分类表
* @param parentId 传入的父节点ID
* @return String
*/

View File

@ -59,6 +59,27 @@ public class SysRoleServiceImpl extends ServicePlusImpl<SysRoleMapper, SysRole>
return baseMapper.selectRoleList(role);
}
/**
* 根据用户ID查询角色
*
* @param userId 用户ID
* @return 角色列表
*/
@Override
public List<SysRole> selectRolesByUserId(Long userId) {
List<SysRole> userRoles = baseMapper.selectRolePermissionByUserId(userId);
List<SysRole> roles = selectRoleAll();
for (SysRole role : roles) {
for (SysRole userRole : userRoles) {
if (role.getRoleId().longValue() == userRole.getRoleId().longValue()) {
role.setFlag(true);
break;
}
}
}
return roles;
}
/**
* 根据用户ID查询权限
*
@ -305,4 +326,51 @@ public class SysRoleServiceImpl extends ServicePlusImpl<SysRoleMapper, SysRole>
roleDeptMapper.delete(new LambdaQueryWrapper<SysRoleDept>().in(SysRoleDept::getRoleId, ids));
return baseMapper.deleteBatchIds(ids);
}
/**
* 取消授权用户角色
*
* @param userRole 用户和角色关联信息
* @return 结果
*/
@Override
public int deleteAuthUser(SysUserRole userRole) {
return userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
.eq(SysUserRole::getRoleId, userRole.getRoleId())
.eq(SysUserRole::getUserId, userRole.getUserId()));
}
/**
* 批量取消授权用户角色
*
* @param roleId 角色ID
* @param userIds 需要取消授权的用户数据ID
* @return 结果
*/
@Override
public int deleteAuthUsers(Long roleId, Long[] userIds) {
return userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
.eq(SysUserRole::getRoleId, roleId)
.in(SysUserRole::getUserId, Arrays.asList(userIds)));
}
/**
* 批量选择授权用户角色
*
* @param roleId 角色ID
* @param userIds 需要删除的用户数据ID
* @return 结果
*/
@Override
public int insertAuthUsers(Long roleId, Long[] userIds) {
// 新增用户与角色管理
List<SysUserRole> list = new ArrayList<SysUserRole>();
for (Long userId : userIds) {
SysUserRole ur = new SysUserRole();
ur.setUserId(userId);
ur.setRoleId(roleId);
list.add(ur);
}
return userRoleMapper.insertAll(list);
}
}

View File

@ -69,6 +69,30 @@ public class SysUserServiceImpl extends ServicePlusImpl<SysUserMapper, SysUser>
return baseMapper.selectUserList(user);
}
/**
* 根据条件分页查询已分配用户角色列表
*
* @param user 用户信息
* @return 用户信息集合信息
*/
@Override
@DataScope(deptAlias = "d", userAlias = "u", isUser = true)
public TableDataInfo<SysUser> selectAllocatedList(SysUser user) {
return PageUtils.buildDataInfo(baseMapper.selectAllocatedList(PageUtils.buildPage(), user));
}
/**
* 根据条件分页查询未分配用户角色列表
*
* @param user 用户信息
* @return 用户信息集合信息
*/
@Override
@DataScope(deptAlias = "d", userAlias = "u", isUser = true)
public TableDataInfo<SysUser> selectUnallocatedList(SysUser user) {
return PageUtils.buildDataInfo(baseMapper.selectUnallocatedList(PageUtils.buildPage(), user));
}
/**
* 通过用户名查询用户
*
@ -231,6 +255,21 @@ public class SysUserServiceImpl extends ServicePlusImpl<SysUserMapper, SysUser>
return baseMapper.updateById(user);
}
/**
* 用户授权角色
*
* @param userId 用户ID
* @param roleIds 角色组
*/
@Override
@Transactional
public void insertUserAuth(Long userId, Long[] roleIds)
{
userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
.eq(SysUserRole::getUserId, userId));
insertUserRole(userId, roleIds);
}
/**
* 修改用户状态
*
@ -257,7 +296,7 @@ public class SysUserServiceImpl extends ServicePlusImpl<SysUserMapper, SysUser>
* 修改用户头像
*
* @param userName 用户名
* @param avatar 头像地址
* @param avatar 头像地址
* @return 结果
*/
@Override
@ -338,6 +377,28 @@ public class SysUserServiceImpl extends ServicePlusImpl<SysUserMapper, SysUser>
}
}
/**
* 新增用户角色信息
*
* @param userId 用户ID
* @param roleIds 角色组
*/
public void insertUserRole(Long userId, Long[] roleIds) {
if (Validator.isNotNull(roleIds)) {
// 新增用户与角色管理
List<SysUserRole> list = new ArrayList<SysUserRole>();
for (Long roleId : roleIds) {
SysUserRole ur = new SysUserRole();
ur.setUserId(userId);
ur.setRoleId(roleId);
list.add(ur);
}
if (list.size() > 0) {
userRoleMapper.insertAll(list);
}
}
}
/**
* 通过用户ID删除用户
*
@ -377,9 +438,9 @@ public class SysUserServiceImpl extends ServicePlusImpl<SysUserMapper, SysUser>
/**
* 导入用户数据
*
* @param userList 用户数据列表
* @param userList 用户数据列表
* @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据
* @param operName 操作用户
* @param operName 操作用户
* @return 结果
*/
@Override

View File

@ -0,0 +1,29 @@
package com.ruoyi.web.controller.system;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.config.RuoYiConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 首页
*
* @author ruoyi
*/
@RestController
public class SysIndexController
{
/** 系统基础配置 */
@Autowired
private RuoYiConfig ruoyiConfig;
/**
* 访问首页,提示语
*/
@RequestMapping("/")
public String index()
{
return StrUtil.format("欢迎使用{}后台管理框架当前版本v{},请通过前端地址访问。", ruoyiConfig.getName(), ruoyiConfig.getVersion());
}
}

View File

@ -1,8 +1,6 @@
package com.ruoyi.web.controller.system;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
@ -11,6 +9,7 @@ import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.service.ISysMenuService;
import org.springframework.beans.factory.annotation.Autowired;
@ -98,8 +97,7 @@ public class SysMenuController extends BaseController
{
return AjaxResult.error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
}
else if (UserConstants.YES_FRAME.equals(menu.getIsFrame())
&& !StrUtil.startWithAny(menu.getPath(), Constants.HTTP, Constants.HTTPS))
else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
{
return AjaxResult.error("新增菜单'" + menu.getMenuName() + "'失败地址必须以http(s)://开头");
}
@ -119,8 +117,7 @@ public class SysMenuController extends BaseController
{
return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
}
else if (UserConstants.YES_FRAME.equals(menu.getIsFrame())
&& !StrUtil.startWithAny(menu.getPath(), Constants.HTTP, Constants.HTTPS))
else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
{
return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败地址必须以http(s)://开头");
}

View File

@ -6,6 +6,7 @@ import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
@ -14,6 +15,7 @@ import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.service.SysPermissionService;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.domain.SysUserRole;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
@ -25,7 +27,7 @@ import java.util.List;
/**
* 角色信息
*
*
* @author ruoyi
*/
@RestController
@ -171,4 +173,57 @@ public class SysRoleController extends BaseController
{
return AjaxResult.success(roleService.selectRoleAll());
}
/**
* 查询已分配用户角色列表
*/
@PreAuthorize("@ss.hasPermi('system:role:list')")
@GetMapping("/authUser/allocatedList")
public TableDataInfo allocatedList(SysUser user)
{
return userService.selectAllocatedList(user);
}
/**
* 查询未分配用户角色列表
*/
@PreAuthorize("@ss.hasPermi('system:role:list')")
@GetMapping("/authUser/unallocatedList")
public TableDataInfo unallocatedList(SysUser user)
{
return userService.selectUnallocatedList(user);
}
/**
* 取消授权用户
*/
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.GRANT)
@PutMapping("/authUser/cancel")
public AjaxResult cancelAuthUser(@RequestBody SysUserRole userRole)
{
return toAjax(roleService.deleteAuthUser(userRole));
}
/**
* 批量取消授权用户
*/
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.GRANT)
@PutMapping("/authUser/cancelAll")
public AjaxResult cancelAuthUserAll(Long roleId, Long[] userIds)
{
return toAjax(roleService.deleteAuthUsers(roleId, userIds));
}
/**
* 批量选择用户授权
*/
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.GRANT)
@PutMapping("/authUser/selectAll")
public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds)
{
return toAjax(roleService.insertAuthUsers(roleId, userIds));
}
}

View File

@ -196,4 +196,31 @@ public class SysUserController extends BaseController
user.setUpdateBy(SecurityUtils.getUsername());
return toAjax(userService.updateUserStatus(user));
}
/**
* 根据用户编号获取授权角色
*/
@PreAuthorize("@ss.hasPermi('system:user:query')")
@GetMapping("/authRole/{userId}")
public AjaxResult authRole(@PathVariable("userId") Long userId)
{
SysUser user = userService.selectUserById(userId);
List<SysRole> roles = roleService.selectRolesByUserId(userId);
Map<String, Object> ajax = new HashMap<>();
ajax.put("user", user);
ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
return AjaxResult.success(ajax);
}
/**
* 用户授权角色
*/
@PreAuthorize("@ss.hasPermi('system:user:edit')")
@Log(title = "用户管理", businessType = BusinessType.GRANT)
@PutMapping("/authRole")
public AjaxResult insertAuthRole(Long userId, Long[] roleIds)
{
userService.insertUserAuth(userId, roleIds);
return success();
}
}

View File

@ -110,3 +110,30 @@ redisson:
subscriptionsPerConnection: 5
# DNS监测时间间隔单位毫秒
dnsMonitoringInterval: 5000
--- # 监控配置
spring:
boot:
admin:
# Spring Boot Admin Client 客户端的相关配置
client:
# 设置 Spring Boot Admin Server 地址
url: http://localhost:9090/admin
instance:
prefer-ip: true # 注册实例时,优先使用 IP
username: ruoyi
password: 123456
# Actuator 监控端点的配置项
management:
endpoints:
web:
# Actuator 提供的 API 接口的根目录。默认为 /actuator
base-path: /actuator
exposure:
# 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。
# 生产环境不建议放开所有 根据项目需求放开即可
include: '*'
endpoint:
logfile:
external-file: ./logs/sys-console.log

View File

@ -12,7 +12,7 @@ spring:
# 主库数据源
master:
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true
url: jdbc:mysql://172.30.0.36:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true
username: root
password: root
# 从库数据源
@ -66,7 +66,7 @@ spring:
# redis 配置
redis:
# 地址
host: localhost
host: 172.30.0.48
# 端口默认为6379
port: 6379
# 数据库索引
@ -110,3 +110,30 @@ redisson:
subscriptionsPerConnection: 5
# DNS监测时间间隔单位毫秒
dnsMonitoringInterval: 5000
--- # 监控配置
spring:
boot:
admin:
# Spring Boot Admin Client 客户端的相关配置
client:
# 设置 Spring Boot Admin Server 地址
url: http://172.30.0.90:9090/admin
instance:
prefer-ip: true # 注册实例时,优先使用 IP
username: ruoyi
password: 123456
# Actuator 监控端点的配置项
management:
endpoints:
web:
# Actuator 提供的 API 接口的根目录。默认为 /actuator
base-path: /actuator
exposure:
# 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。
# 生产环境不建议放开所有 根据项目需求放开即可
include: health,info
endpoint:
logfile:
external-file: ./logs/sys-console.log

View File

@ -64,6 +64,8 @@ logging:
# Spring配置
spring:
application:
name: ${ruoyi.name}
# 资源信息
messages:
# 国际化资源文件路径
@ -110,6 +112,8 @@ token:
# MyBatisPlus配置
# https://baomidou.com/config/
mybatis-plus:
# 不支持多包, 如有需要可在注解配置 或 提升扫包等级
# 例如 com.**.**.mapper
mapperPackage: com.ruoyi.**.mapper
# 对应的 XML 文件位置
mapperLocations: classpath*:mapper/**/*Mapper.xml
@ -156,7 +160,9 @@ mybatis-plus:
# STATEMENT 关闭一级缓存
localCacheScope: SESSION
# 开启Mybatis二级缓存默认为 true
cacheEnabled: true
cacheEnabled: false
# 更详细的日志输出 会有性能损耗
# logImpl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
# 是否打印 Logo banner
banner: true
@ -203,7 +209,7 @@ swagger:
# 请求前缀
pathMapping: /dev-api
# 标题
title: '标题:RuoYi-Vue-Plus后台管理系统_接口文档'
title: '标题:${ruoyi.name}后台管理系统_接口文档'
# 描述
description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...'
# 版本
@ -244,6 +250,8 @@ thread-pool:
# feign 相关配置
feign:
# 不支持多包, 如有需要可在注解配置 或 提升扫包等级
# 例如 com.**.**.feign
package: com.ruoyi.**.feign
# 开启压缩
compression:
@ -256,6 +264,21 @@ feign:
circuitbreaker:
enabled: true
--- # redisson 缓存配置
redisson:
cacheGroup:
# 用例: @Cacheable(cacheNames="groupId", key="#XXX") 方可使用缓存组配置
- groupId: redissonCacheMap
# 组过期时间(脚本监控)
ttl: 60000
# 组最大空闲时间(脚本监控)
maxIdleTime: 60000
# 组最大长度
maxSize: 0
- groupId: testCache
ttl: 1000
maxIdleTime: 500
--- # 分布式锁 lock4j 全局配置
lock4j:
# 获取分布式锁超时时间,默认为 3000 毫秒
@ -293,31 +316,3 @@ spring:
tablePrefix: QRTZ_
# sqlserver 启用
# selectWithLockSQL: SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?
--- # 监控配置
spring:
application:
name: ruoyi-vue-plus
boot:
admin:
# Spring Boot Admin Client 客户端的相关配置
client:
# 设置 Spring Boot Admin Server 地址
url: http://localhost:${server.port}${spring.boot.admin.context-path}
instance:
prefer-ip: true # 注册实例时,优先使用 IP
# Spring Boot Admin Server 服务端的相关配置
context-path: /admin # 配置 Spring
# Actuator 监控端点的配置项
management:
endpoints:
web:
# Actuator 提供的 API 接口的根目录。默认为 /actuator
base-path: /actuator
exposure:
# 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。
include: '*'
endpoint:
logfile:
external-file: ./logs/sys-console.log

View File

@ -0,0 +1,33 @@
#错误消息
not.null=
user.jcaptcha.error=
user.jcaptcha.expire=
user.not.exists=
user.password.not.match=
user.password.retry.limit.count=
user.password.retry.limit.exceed=
user.password.delete=
user.blocked=
role.blocked=
user.logout.success=
length.not.valid=
user.username.not.valid=
user.password.not.valid=
user.email.not.valid=
user.mobile.phone.number.not.valid=
user.login.success=
user.notfound=
user.forcelogout=
user.unknown.error=
##文件上传消息
upload.exceed.maxSize=
upload.filename.exceed.length=
##权限
no.permission=
no.create.permission=
no.update.permission=
no.delete.permission=
no.export.permission=
no.view.permission=

View File

@ -0,0 +1,36 @@
#错误消息
not.null=* 必须填写
user.jcaptcha.error=验证码错误
user.jcaptcha.expire=验证码已失效
user.not.exists=用户不存在/密码错误
user.password.not.match=用户不存在/密码错误
user.password.retry.limit.count=密码输入错误{0}次
user.password.retry.limit.exceed=密码输入错误{0}次帐户锁定10分钟
user.password.delete=对不起,您的账号已被删除
user.blocked=用户已封禁,请联系管理员
role.blocked=角色已封禁,请联系管理员
user.logout.success=退出成功
length.not.valid=长度必须在{min}到{max}个字符之间
user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成且必须以非数字开头
user.password.not.valid=* 5-50个字符
user.email.not.valid=邮箱格式错误
user.mobile.phone.number.not.valid=手机号格式错误
user.login.success=登录成功
user.notfound=请重新登录
user.forcelogout=管理员强制退出,请重新登录
user.unknown.error=未知错误,请重新登录
##文件上传消息
upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB
upload.filename.exceed.length=上传的文件名最长{0}个字符
##权限
no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]
no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]
no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]
no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]

View File

@ -75,9 +75,9 @@
r.data_scope,
r.status as role_status
from sys_user u
left join sys_dept d on u.dept_id = d.dept_id
left join sys_user_role ur on u.user_id = ur.user_id
left join sys_role r on r.role_id = ur.role_id
left join sys_dept d on u.dept_id = d.dept_id
left join sys_user_role ur on u.user_id = ur.user_id
left join sys_role r on r.role_id = ur.role_id
</sql>
<select id="selectPageUserList" parameterType="SysUser" resultMap="SysUserResult">
@ -142,6 +142,45 @@
</if>
</select>
<select id="selectAllocatedList" parameterType="SysUser" resultMap="SysUserResult">
select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time
from sys_user u
left join sys_dept d on u.dept_id = d.dept_id
left join sys_user_role ur on u.user_id = ur.user_id
left join sys_role r on r.role_id = ur.role_id
where u.del_flag = '0' and r.role_id = #{user.roleId}
<if test="user.userName != null and user.userName != ''">
AND u.user_name like concat('%', #{user.userName}, '%')
</if>
<if test="user.phonenumber != null and user.phonenumber != ''">
AND u.phonenumber like concat('%', #{user.phonenumber}, '%')
</if>
<!-- 数据范围过滤 -->
<if test="user.params.dataScope != null and user.params.dataScope != ''">
AND ( ${user.params.dataScope} )
</if>
</select>
<select id="selectUnallocatedList" parameterType="SysUser" resultMap="SysUserResult">
select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time
from sys_user u
left join sys_dept d on u.dept_id = d.dept_id
left join sys_user_role ur on u.user_id = ur.user_id
left join sys_role r on r.role_id = ur.role_id
where u.del_flag = '0' and (r.role_id != #{user.roleId} or r.role_id IS NULL)
and u.user_id not in (select u.user_id from sys_user u inner join sys_user_role ur on u.user_id = ur.user_id and ur.role_id = #{user.roleId})
<if test="user.userName != null and user.userName != ''">
AND u.user_name like concat('%', #{user.userName}, '%')
</if>
<if test="user.phonenumber != null and user.phonenumber != ''">
AND u.phonenumber like concat('%', #{user.phonenumber}, '%')
</if>
<!-- 数据范围过滤 -->
<if test="user.params.dataScope != null and user.params.dataScope != ''">
AND ( ${user.params.dataScope} )
</if>
</select>
<select id="selectUserByUserName" parameterType="String" resultMap="SysUserResult">
<include refid="selectUserVo"/>
where u.user_name = #{userName}

View File

@ -11,8 +11,6 @@ import org.apache.ibatis.annotations.CacheNamespace;
* @author ${author}
* @date ${datetime}
*/
// 如使需切换数据源 请勿使用缓存 会造成数据不一致现象
@CacheNamespace(implementation = MybatisPlusRedisCache.class, eviction = MybatisPlusRedisCache.class)
public interface ${ClassName}Mapper extends BaseMapperPlus<${ClassName}> {
}

View File

@ -256,52 +256,16 @@
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName}, export${BusinessName} } from "@/api/${moduleName}/${businessName}";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
#foreach($column in $columns)
#if($column.insert && !$column.pk && $column.htmlType == "imageUpload")
import ImageUpload from '@/components/ImageUpload';
#break
#end
#end
#foreach($column in $columns)
#if($column.insert && !$column.pk && $column.htmlType == "fileUpload")
import FileUpload from '@/components/FileUpload';
#break
#end
#end
#foreach($column in $columns)
#if($column.insert && !$column.pk && $column.htmlType == "editor")
import Editor from '@/components/Editor';
#break
#end
#end
export default {
name: "${BusinessName}",
components: {
#foreach($column in $columns)
#if($column.insert && !$column.pk && $column.htmlType == "imageUpload")
ImageUpload,
#break
#end
#end
#foreach($column in $columns)
#if($column.insert && !$column.pk && $column.htmlType == "fileUpload")
FileUpload,
#break
#end
#end
#foreach($column in $columns)
#if($column.insert && !$column.pk && $column.htmlType == "editor")
Editor,
#break
#end
#end
Treeselect
},
data() {
return {
//按钮loading
buttonLoading: false,
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 显示搜索条件
@ -510,17 +474,19 @@ export default {
#end
if (this.form.${pkColumn.javaField} != null) {
update${BusinessName}(this.form).then(response => {
this.buttonLoading = false;
this.msgSuccess("修改成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
} else {
add${BusinessName}(this.form).then(response => {
this.buttonLoading = false;
this.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
}
}

View File

@ -308,51 +308,13 @@
<script>
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName}, export${BusinessName} } from "@/api/${moduleName}/${businessName}";
#foreach($column in $columns)
#if($column.insert && !$column.pk && $column.htmlType == "imageUpload")
import ImageUpload from '@/components/ImageUpload';
#break
#end
#end
#foreach($column in $columns)
#if($column.insert && !$column.pk && $column.htmlType == "fileUpload")
import FileUpload from '@/components/FileUpload';
#break
#end
#end
#foreach($column in $columns)
#if($column.insert && !$column.pk && $column.htmlType == "editor")
import Editor from '@/components/Editor';
#break
#end
#end
export default {
name: "${BusinessName}",
components: {
#foreach($column in $columns)
#if($column.insert && !$column.pk && $column.htmlType == "imageUpload")
ImageUpload,
#break
#end
#end
#foreach($column in $columns)
#if($column.insert && !$column.pk && $column.htmlType == "fileUpload")
FileUpload,
#break
#end
#end
#foreach($column in $columns)
#if($column.insert && !$column.pk && $column.htmlType == "editor")
Editor,
#break
#end
#end
},
data() {
return {
//按钮loading
buttonLoading: false,
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 导出遮罩层
@ -567,17 +529,19 @@ export default {
#end
if (this.form.${pkColumn.javaField} != null) {
update${BusinessName}(this.form).then(response => {
this.buttonLoading = false;
this.msgSuccess("修改成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
} else {
add${BusinessName}(this.form).then(response => {
this.buttonLoading = false;
this.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
}
}