常见问题

如何不登录直接访问

在 ShiroConfig 中设置filterChainDefinitionMap 配置url=anon

	/admins/**=anon               # 表示该 uri 可以匿名访问
	/admins/**=auth               # 表示该 uri 需要认证才能访问
	/admins/**=authcBasic         # 表示该 uri 需要 httpBasic 认证
	/admins/**=perms[user:add:*]  # 表示该 uri 需要认证用户拥有 user:add:* 权限才能访问
	/admins/**=port[8080]         # 表示该 uri 需要使用 8080 端口
	/admins/**=roles[admin]       # 表示该 uri 需要认证用户拥有 admin 角色才能访问
	/admins/**=ssl                # 表示该 uri 需要使用 https 协议
	/admins/**=user               # 表示该 uri 需要认证或通过记住我认证才能访问
	/logout=logout                # 表示注销,可以当作固定配置
	
	注意:
	anon,authcBasic,authc,user 是认证过滤器。
	perms,roles,ssl,rest,port 是授权过滤器。
1
2
3
4
5
6
7
8
9
10
11
12
13

如何更换项目包路径

1、更换目录名称

├── xxxxx
│       └── xxxxx-admin
│       └── xxxxx-common
│       └── xxxxx-framework
│       └── xxxxx-generator
│       └── xxxxx-quartz
│       └── xxxxx-system
│       └── pom.xml
1
2
3
4
5
6
7
8

2、更换顶级目录中的pom.xml

<modules>
	<module>xxxxx-admin</module>
	<module>xxxxx-framework</module>
	<module>xxxxx-system</module>
	<module>xxxxx-quartz</module>
	<module>xxxxx-generator</module>
	<module>xxxxx-common</module>
</modules>
1
2
3
4
5
6
7
8

3、更换项目所有包名称 com.ruoyi.xxx 换成 com.xxxxx.xxx

提示

DataScopeAspect,DataSourceAspect,LogAspect 这三个类@Pointcut注解上面的包路径也需要替换com.xxxxx

CaptchaConfig 这个类验证码文本生成器参数KAPTCHA_TEXTPRODUCER_IMPL的包路径也需要替换com.xxxxx

ApplicationConfig 这个类@MapperScan注解上面的包路径也需要替换com.xxxxx

4、更换application.yml指定要扫描的Mapper类的包的路径 typeAliasesPackage包路径名称替换com.xxxxx

5、更换mapper文件的namespace包路径

ruoyi-system/resources/mapper/system/* 
ruoyi-quartz/resources/mapper/quartz/* 
ruoyi-generator/resources/mapper/generator/*
1
2
3

包路径名称替换com.xxxxx

6、更换pom文件内容

提示

以下pom.xml文件中包含ruoyi的关键字替换成xxxxx

├── xxxxx
│       └── xxxxx-admin      pom.xml
│       └── xxxxx-common     pom.xml
│       └── xxxxx-framework  pom.xml
│       └── xxxxx-generator  pom.xml
│       └── xxxxx-quartz     pom.xml
│       └── xxxxx-system     pom.xml
│       └── pom.xml
1
2
3
4
5
6
7
8

7、更换日志路径

  • 更换application.yml文件logging属性为com.xxxxx: debug
  • 更换logback.xml文件为com.xxxxx

8、启动项目验证

提示

到此步骤如能正常启动,表示更换完成。剩余的小细节可以自行调整。

业务模块访问出现404

1、单应用检查

  • 确认此用户是否已经配置菜单
  • 确认此角色是否已经配置菜单权限
  • 确认此菜单url是否和后台代码一致

如参数管理 后台配置@RequestMapping("/system/config")对应参数管理url为/system/config

2、多模块检查(多了几个步骤)

  • pom.xml 引入了业务子系统
  • ruoyi-admin 添加业务子模块的依赖
  • ruoyi-xxxxx 新增业务模块pom检查配置是否正确

PS:IDEA可能存在缓存,需要清理下缓存在编译。

IDEA更改页面不重启

经常有小伙伴问到这个问题,为什么我的用IDEA修改html页面之后不实时生效呢?

1、修改IDEA设置 File -> Settings -> Build Execution Deployment -> Build Project automatically 勾选

2、勾选Running Ctrl + Shift + Alt + / 然后选择 Registry,勾上 Compiler.autoMake.allow.when.app.running

PS:Eclipse开发工具无需任何配置。

如何使用多数据源

  1. resources 目录下修改application-druid.yml
# 从库数据源
slave:
    # 开启从库
    enabled: true
    url: 数据源
    username: 用户名
    password: 密码
1
2
3
4
5
6
7
  1. 在Service实现中添加DataSource注解
@DataSource(value = DataSourceType.SLAVE)
public List<User> selectUserList()
{
    return mapper.selectUserList();
}
1
2
3
4
5

如何更换主题皮肤

1、项目主页-个人信息中选择切换主题

2、修改主框架页-默认皮肤,在菜单参数设置修改参数键名sys.index.skinName支持如下几种皮肤

  • 蓝色 skin-blue
  • 绿色 skin-green
  • 紫色 skin-purple
  • 红色 skin-red
  • 黄色 skin-yellow

3、修改主框架页-侧边栏主题,在菜单参数设置修改参数键名sys.index.sideTheme支持如下几种主题

  • 深色主题theme-dark
  • 浅色主题theme-light

注:如需新增修改皮肤主题可以在skins.css中调整

如何获取用户登录信息

  1. 第一种方法
// 获取当前的用户信息
User currentUser = ShiroUtils.getSysUser();
// 获取当前的用户名称
String userName = currentUser.getUserName();
1
2
3
4
  1. 第二种方法(子模块可使用)
// 获取当前的用户名称
String userName = (String) PermissionUtils.getPrincipalProperty("userName");
1
2

3、界面获取当前用户信息(支持任意th标签)

<input th:value="${@permission.getPrincipalProperty('userName')}">
1

4、js中获取当前用户信息

var userName = [[${@permission.getPrincipalProperty('userName')}]];
1

如何防止请求重复提交

  1. 前端通过js控制
// 禁用按钮
$.modal.disable();
// 启用按钮
$.modal.enable();
1
2
3
4
  1. 后端通过@RepeatSubmit注解控制
/**
 * 在对应方法添加注解 @RepeatSubmit
 */
@RepeatSubmit
public AjaxResult editSave()
1
2
3
4
5

如何配置允许跨域访问

现在开发的项目一般都是前后端分离的项目,所以跨域访问会经常使用。

1、单个控制器方法CORS注解

@RestController
@RequestMapping("/system/test")
public class TestController {

    @CrossOrigin
    @GetMapping("/{id}")
    public AjaxResult getUser(@PathVariable Integer userId) {
        // ...
    }
	
	@DeleteMapping("/{userId}")
    public AjaxResult delete(@PathVariable Integer userId) {
        // ...
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

2、整个控制器启用CORS注解

@CrossOrigin(origins = "http://ruoyi.vip", maxAge = 3600)
@RestController
@RequestMapping("/system/test")
public class TestController {

    @GetMapping("/{id}")
    public AjaxResult getUser(@PathVariable Integer userId) {
        // ...
    }
	
	@DeleteMapping("/{userId}")
    public AjaxResult delete(@PathVariable Integer userId) {
        // ...
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

3、全局CORS配置(在ResourcesConfig重写addCorsMappings方法)

/**
 * web跨域访问配置
 */
@Override
public void addCorsMappings(CorsRegistry registry)
{
	// 设置允许跨域的路径
	registry.addMapping("/**")
			// 设置允许跨域请求的域名
			.allowedOrigins("*")
			// 是否允许证书
			.allowCredentials(true)
			// 设置允许的方法
			.allowedMethods("GET", "POST", "DELETE", "PUT")
			// 设置允许的header属性
			.allowedHeaders("*")
			// 跨域允许时间
			.maxAge(3600);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

日期插件精确到时分秒

1、界面设置时间格式data-format

<li class="select-time">
	<label>创建时间: </label>
	<input type="text" class="time-input" id="startTime" placeholder="开始时间" name="params[beginTime]" data-format="yyyy-MM"/>
	<span>-</span>
	<input type="text" class="time-input" id="endTime" placeholder="结束时间" name="params[endTime]" data-format="yyyy-MM"/>
</li>
1
2
3
4
5
6

2、通过js函数设置 datetimepicker日期控件可以设置format

$('.input-group.date').datetimepicker({
    format: 'yyyy-mm-dd hh:ii:ss',
    autoclose: true,
    minView: 0,
    minuteStep:1
});
1
2
3
4
5
6

laydate日期控件可以设置common.js 配置type=datetime

layui.use('laydate', function() {
	var laydate = layui.laydate;
	var startDate = laydate.render({
		elem: '#startTime',
		max: $('#endTime').val(),
		theme: 'molv',
		trigger: 'click',
		type : 'datetime',
		done: function(value, date) {
			// 结束时间大于开始时间
			if (value !== '') {
				endDate.config.min.year = date.year;
				endDate.config.min.month = date.month - 1;
				endDate.config.min.date = date.date;
			} else {
				endDate.config.min.year = '';
				endDate.config.min.month = '';
				endDate.config.min.date = '';
			}
		}
	});
	var endDate = laydate.render({
		elem: '#endTime',
		min: $('#startTime').val(),
		theme: 'molv',
		trigger: 'click',
		type : 'datetime',
		done: function(value, date) {
			// 开始时间小于结束时间
			if (value !== '') {
				startDate.config.max.year = date.year;
				startDate.config.max.month = date.month - 1;
				startDate.config.max.date = date.date;
			} else {
				startDate.config.max.year = '';
				startDate.config.max.month = '';
				startDate.config.max.date = '';
			}
		}
	});
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

代码生成不显示新建表

默认条件需要表注释,特殊情况可在GenMapper.xml去除table_comment条件

<select id="selectTableByName" parameterType="String" resultMap="TableInfoResult">
	<include refid="selectGenVo"/>
	where table_comment <> '' and table_schema = (select database())
</select>
1
2
3
4

提示

如果版本>=4.0不需要表注解,在代码生成页面导入即可。

提示您没有数据的权限

这种情况都属于权限标识配置不对在菜单管理配置好权限标识(菜单&按钮)

  1. 确认此用户是否已经配置角色
  2. 确认此角色是否已经配置菜单权限
  3. 确认此菜单权限标识是否和后台代码一致

如参数管理
后台配置@RequiresPermissions("system:config:view")对应参数管理权限标识为system:config:view

注:如需要角色权限,配置角色权限字符 使用@RequiresRoles("admin")

富文本编辑器文件上传

富文本控件采用的summernote,图片上传处理需要设置callbacks函数

$('.summernote').summernote({
	height : '220px',
	lang : 'zh-CN',
	callbacks: {
		onImageUpload: function(files, editor, $editable) {
			var formData = new FormData();
			formData.append("file", files[0]);
			$.ajax({
	            type: "POST",
	            url: ctx + "common/upload",
	            data: data,
	            cache: false,
	            contentType: false,
	            processData: false,
	            dataType: 'json',
	            success: function(result) {
	                if (result.code == web_status.SUCCESS) {
	                	$(obj).summernote('editor.insertImage', result.url, result.fileName);
					} else {
						$.modal.alertError(result.msg);
					}
	            },
	            error: function(error) {
	                $.modal.alertWarning("图片上传失败。");
	            }
	        });
		}
	}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

富文本编辑器底部回弹

富文本控件采用的summernote,如果不需要底部回弹设置followingToolbar: false

$('.summernote').summernote({
	placeholder: '请输入公告内容',
	height : 192,
	lang : 'zh-CN',
	followingToolbar: false,
	callbacks: {
		onImageUpload: function (files) {
			sendFile(files[0], this);
		}
	}
});
1
2
3
4
5
6
7
8
9
10
11

如何创建新的菜单页签

建新新的页签有以下两种方式(js&html)

// 方式1 打开新的选项卡
function dept() {
	var url = ctx + "system/dept";
	$.modal.openTab("部门管理", url);
}
// 方式2 选卡页同一页签打开
function dept() {
	var url = ctx + "system/dept";
	$.modal.parentTab("部门管理", url);
}
// 方式3 html创建
<a class="menuItem" href="/system/dept">部门管理</a>
1
2
3
4
5
6
7
8
9
10
11
12

表格数据进行汇总统计

对于某些数据需要对金额,数量等进行汇总,可以配置showFootertrue表示尾部统计

// options 选项中添加尾部统计
showFooter: true, 
// columns 中添加   
{
	field : 'balance',
	title : '余额',
	sortable: true,
	footerFormatter:function (value) {
		var sumBalance = 0;
		for (var i in value) {
			sumBalance += parseFloat(value[i].balance);
		}
		return "总金额:" + sumBalance;
	}
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

表格设置行列单元格样式

1、options参数中配置属性

rowStyle: rowStyle,
1

2、对应js添加响应方法(根据rowindex定义规则)即可

function rowStyle(row, index) {
	var style = { css: { 'color': '#ed5565' } };
	return style;
}
1
2
3
4

如何去除数据监控广告

服务监控中使用的Driud,默认底部有阿里的广告。如果是一个商业项目这个是很不雅也是不允许的

  1. 找到本地maven库中的对应的druid-1.1.xx.jar文件,用压缩包软件打开
  2. 找到support/http/resource/js/common.js, 打开找到 buildFooter 方法
this.buildFooter();
buildFooter : function() {
	var html ='此处省略一些相关JS代码';
	$(document.body).append(html);
},
1
2
3
4
5
  1. 删除此函数和及初始方法后覆盖文件
  2. 重启项目后,广告就会消失了

如何支持多类型数据库

对于某些特殊需要支持不同数据库,参考以下支持oracle mysql配置

<!--oracle驱动-->
<dependency>
	<groupId>com.oracle</groupId>
	<artifactId>ojdbc6</artifactId>
	<version>11.2.0.3</version>
</dependency>
1
2
3
4
5
6
# 数据源配置
spring:
    datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        druid:
            # 主库数据源
            master:
                url: jdbc:mysql://127.0.0.1:3306/ry?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
                username: root
                password: password
            # 从库数据源
            slave:
                # 从数据源开关/默认关闭
                enabled: true
                url: jdbc:oracle:thin:@127.0.0.1:1521:oracle
                username: root
                password: password
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

对于不同数据源造成的驱动问题,可以删除driverClassName。会自动识别驱动
如需要对不同数据源分页需要操作application.yml中的pagehelper配置 删除helperDialect: mysql 会自动识别数据源 新增autoRuntimeDialect=true 表示运行时获取数据源

如何实现翻页保留选择

  1. 配置checkbox选项field属性为state
{
	field: 'state',
	checkbox: true
},
1
2
3
4
  1. 表格选项options添加rememberSelected
rememberSelected: true,
1

如何实现跳转至指定页

  1. 表格选项options添加showPageGo
showPageGo: true,
1

如何自定义查询条件参数

1、在options中添加queryParams参数

var options = {
	url: prefix + "/list",
	queryParams: queryParams,
	columns: [{
		field: 'id',
		title: '主键'
	},
	{
		field: 'name',
		title: '名称'
	}]
};
$.table.init(options);
1
2
3
4
5
6
7
8
9
10
11
12
13

2、在当前页添加queryParams方法设置自定义查询条件如userName

function queryParams(params) {
	var search = $.table.queryParams(params);
	search.userName = $("#userName").val();
	return search;
}
1
2
3
4
5

请求后台参数为:pageSize、pageNum、searchValue、orderByColumn、isAsc、userName

3、如果是表格树,添加参数ajaxParams参数

var options = {
	code: "deptId",
	parentCode: "parentId",
	uniqueId: "deptId",
	url: prefix + "/list",
	ajaxParams: {
		"userId": "1",
		"userName": "ruoyi"
	},
	columns: [{
		field: 'id',
		title: '主键'
	},
	{
		field: 'name',
		title: '名称'
	}]
};
$.treeTable.init(options);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

如何让表格某些列隐藏掉

1、在optionscolumns设置visible

visible: false,  // 隐藏某列(列选项可见)
ignore: true,    // 列选项不可见
1
2

对于需要列选项不可见状态可以设置ignore

如何给默认的表格加边框

table-striped 换成 table-bordered

<div class="col-sm-12 select-table table-bordered">
    <table id="bootstrap-table"></table>
</div>
1
2
3

普通用户创建文件无权限

常见的有几种错误,对应去调整即可。

1、修改logback.xml,value路径

<!-- 日志存放路径 -->
<property name="log.path" value="/home/ruoyi/logs" />
1
2

2、修改ehcache-shiro.xml,path路径

<diskStore path="java.io.tmpdir"/>
1

3、修改tomcat临时的日志目录

server:
  tomcat:
    basedir: /home/ruoyi/temp
1
2
3

如何降低mysql驱动版本

1、在pom.xml中properties新增节点如:

<mysql.version>6.0.6</mysql.version>
1

2、单应用可以不添加,多模块需要在dependencyManagement声明依赖

<!-- Mysql驱动包 -->
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>${mysql.version}</version>
</dependency>
1
2
3
4
5
6

注意:如果是6以下的版本需要修改application-druid.ymldriverClassName
com.mysql.jdbc.Driver 是 mysql-connector-java 5中的
com.mysql.cj.jdbc.Driver 是 mysql-connector-java 6中的

如何配置tomcat访问日志

1、修改application.yml中的server开发环境配置

# 开发环境配置
server:
  # 服务器的HTTP端口,默认为80
  port: 80
  servlet:
    # 应用的访问路径
    context-path: /
  tomcat:
    # 存放Tomcat的日志目录
    basedir: D:/tomcat
    accesslog: 
        # 开启日志记录
        enabled: true
        # 访问日志存放目录
        directory: logs
    # tomcat的URI编码
    uri-encoding: UTF-8
    # tomcat最大线程数,默认为200
    max-threads: 800
    # Tomcat启动初始化的线程数,默认值25
    min-spare-threads: 30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

2、重启项目后,在D:/tomcat/logs目录就可以看到服务器访问日志了

如何汉化系统接口Swagger

想必很多小伙伴都曾经使用过Swagger,但是打开UI界面是纯英文的界面并不太友好,作为国人还是习惯中文界面。

  1. 找到m2/repository/io/springfox/springfox-swagger-ui/x.x.x/springfox-swagger-ui-x.x.x.jar
  2. 修改对应springfox-swagger-ui-x.x.x.jar包内resources目录下swagger-ui.html,添加如下JS代码
<!-- 选择中文版 -->
<script src='webjars/springfox-swagger-ui/lang/translator.js' type='text/javascript'></script>
<script src='webjars/springfox-swagger-ui/lang/zh-cn.js' type='text/javascript'></script>
1
2
3
  1. 本地修改结束后,在覆盖压缩包文件重启就实现汉化了

如何在html页面格式化日期

Thymeleaf主要使用org.thymeleaf.expression.Dates 这个类来处理日期,在模板中使用"#dates"来表示这个对象。

1、格式化日期
[[${#dates.format(date)}]]th:text="${#dates.format(date)}
[[${#dates.formatISO(date)}]]th:text="${#dates.formatISO(date)}
[[${#dates.format(date, 'yyyy-MM-dd HH:mm:ss')}]]th:text="${#dates.format(date, 'yyyy-MM-dd HH:mm:ss')}

2、获取日期字段
获取当前的年份:[[${#dates.year(date)}]]
获取当前的月份:[[${#dates.month(date)}]]
获取当月的天数:[[${#dates.day(date)}]]
获取当前的小时:[[${#dates.hour(date)}]]
获取当前的分钟:[[${#dates.minute(date)}]]
获取当前的秒数:[[${#dates.second(date)}]]
获取当前的毫秒:[[${#dates.millisecond(date)}]]
获取当前的月份名称:[[${#dates.monthName(date)}]]
获取当前是星期几:[[${#dates.dayOfWeek(date)-1}]]

如何在表格中实现图片预览

对于某些图片需要在表格中显示,可以使用imageView方法

// 在columns中格式化对应相关的列属性
{
	field: 'avatar',
	title: '用户头像',
	formatter: function(value, row, index) {
		return $.table.imageView(value, '/profile/avatar');
	}
},
1
2
3
4
5
6
7
8

如何去掉页脚及左侧菜单栏

1、去除页脚修改style.css

#content-main {
    height: calc(100%);
    overflow: hidden;
}
1
2
3
4

2、去左侧菜单栏(收起时隐藏左侧菜单)修改style.css

body.fixed-sidebar.mini-navbar #page-wrapper {
    margin: 0 0 0 0px;
}

body.body-small.fixed-sidebar.mini-navbar #page-wrapper {
    margin: 0 0 0 0px;
}
1
2
3
4
5
6
7

3、去左侧菜单栏(收起时隐藏左侧菜单)修改index.js

function() {
    if ($(this).width() < 769) {
        $('body').addClass('mini-navbar');
        $('.navbar-static-side').fadeIn(); // 换成 $('.navbar-static-side').hide();
        $(".sidebar-collapse .logo").addClass("hide");
    }
});

function SmoothlyMenu() {
    if (!$('body').hasClass('mini-navbar')) {
    	$(".navbar-static-side").show();  // 添加显示这一行
        $('#side-menu').hide();
        $(".sidebar-collapse .logo").removeClass("hide");
        setTimeout(function() {
            $('#side-menu').fadeIn(500);
        },
        100);
    } else if ($('body').hasClass('fixed-sidebar')) {
    	$(".navbar-static-side").hide();  // 添加隐藏这一行
        $('#side-menu').hide();
        $(".sidebar-collapse .logo").addClass("hide");
        setTimeout(function() {
            $('#side-menu').fadeIn(500);
        },
        300);
    } else {
        $('#side-menu').removeAttr('style');
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

4、隐藏左侧菜单,需要添加.canvas-menu到body元素

<body class = "canvas-menu"> 
1

如何限制账户只能一个人登录

application.yml设置maxSession1即可。

# Shiro
shiro:
  session:
    # 同一个用户最大会话数,比如2的意思是同一个账号允许最多同时两个人登录(默认-1不限制)
    maxSession: 1
    # 踢出之前登录的/之后登录的用户,默认踢出之前登录的用户
    kickoutAfter: false
1
2
3
4
5
6
7

登录页面如何不显示验证码

application.yml设置captchaEnabledfalse即可

# Shiro
shiro:
  user:
    # 验证码开关
    captchaEnabled: false
1
2
3
4
5

如何Excel导出子对象多个字段

// 单个字段导出
@Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT)
private Dept dept;

// 多个字段导出
@Excels({
    @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT),
    @Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT)
})
private Dept dept;
1
2
3
4
5
6
7
8
9
10

更多操作字符串参数读取问题

事件中需要传递字符串参数,可以参考resetPwd传递方式。

onclick=resetPwd(" + row.userId + ',' + "'" + row.userName + "'" + ")
1

完整代码

formatter: function(value, row, index) {
	var actions = [];
	actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.editTab(\'' + row.userId + '\')"><i class="fa fa-edit"></i>编辑</a> ');
	actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.userId + '\')"><i class="fa fa-remove"></i>删除</a> ');
	var more = [];
	more.push("<a class='btn btn-default btn-xs " + resetPwdFlag + "' href='javascript:void(0)' onclick=resetPwd(" + row.userId + ',' + "'" + row.userName + "'" + ")><i class='fa fa-key'></i>重置密码</a> ");
	more.push("<a class='btn btn-default btn-xs " + editFlag + "' href='javascript:void(0)' onclick='authRole(" + row.userId + ")'><i class='fa fa-check-square-o'></i>分配角色</a>");
	actions.push('<a tabindex="0" class="btn btn-info btn-xs" role="button" data-container="body" data-placement="left" data-toggle="popover" data-html="true" data-trigger="hover" data-content="' + more.join('') + '"><i class="fa fa-chevron-circle-right"></i>更多操作</a>');
	return actions.join('');
}
1
2
3
4
5
6
7
8
9
10

单元格内容过长显示处理方法

1、使用系统自带的方法格式化处理

{
	field: 'remark',
	title: '备注',
	align: 'center',
	formatter: function(value, row, index) {
		return $.table.tooltip(value);
	}
},
1
2
3
4
5
6
7
8

2、添加css控制

.select-table table {
    table-layout:fixed;
}

.select-table .table td {
	/* 超出部分隐藏 */
	overflow:hidden;
	/* 超出部分显示省略号 */
    text-overflow:ellipsis;
    /*规定段落中的文本不进行换行 */
    white-space:nowrap;
    /* 配合宽度来使用 */
	height:40px;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

表格禁用某列复选框选择方法

条件成立禁用checkbox返回(disabled : true)即可。

{
	checkbox: true,
	formatter: function (value, row, index) {
		if($.common.equals("ry", row.loginName)){
			return { disabled : true}
		} else {
			return { disabled : false}
		}
	}
},
1
2
3
4
5
6
7
8
9
10

表格默认勾选某列复选框方法

条件成立禁用checkbox返回(disabled : true)即可。

{
	checkbox: true,
	formatter: function (value, row, index) {
		if($.common.equals("ry", row.loginName)){
			return { checked : true}
		} else {
			return { checked : false}
		}
	}
},
1
2
3
4
5
6
7
8
9
10

提示

如果默认勾选,并且配置了 rememberSelected: true, 需要特殊处理下。参考demo

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
	<th:block th:include="include :: header('翻页记住选择')" />
</head>
<body class="gray-bg">
     <div class="container-div">
     	<div class="btn-group-sm" id="toolbar" role="group">
	        <a class="btn btn-success" onclick="checkItem()">
	            <i class="fa fa-check"></i> 选中项
	        </a>
        </div>
		<div class="row">
			<div class="col-sm-12 select-table table-striped">
				<table id="bootstrap-table"></table>
			</div>
		</div>
	</div>
    <div th:include="include :: footer"></div>
    <script th:inline="javascript">
        var prefix = ctx + "demo/table";
        var datas = [[${@dict.getType('sys_normal_disable')}]];

        $(function() {
            var options = {
                uniqueId: "userCode",
                url: prefix + "/list",
		        rememberSelected: true,
                columns: [{
                	field: 'state',
		            checkbox: true,
		            formatter: function(value, row, index) {
		            	if($.inArray(row.userCode, table.rememberSelectedIds[table.options.id]) !== -1 || row.userCode == 1000001 || row.userCode == 1000002){
		            		if($.inArray(row.userCode, uncheckUserCode) !== -1)
		            		{
		            			return { checked : false };
		            		}
		            		var selectedRows = table.rememberSelecteds[table.options.id];
		            		func = $.inArray('check', ['check', 'check-all']) > -1 ? 'union' : 'difference';
		            		if($.common.isNotEmpty(selectedRows)) {
		            			table.rememberSelecteds[table.options.id] = _[func](selectedRows, row);
	            			} else {
	            				table.rememberSelecteds[table.options.id] = _[func]([], row);
	            			}
		            		return { checked : true };
		            	}
		            	return { checked : false };
		        	}
		        },
				{
					field : 'userId', 
					title : '用户ID'
				},
				{
					field : 'userCode', 
					title : '用户编号'
				},
				{
					field : 'userName', 
					title : '用户姓名'
				},
				{
					field : 'userPhone', 
					title : '用户手机'
				},
				{
					field : 'userEmail', 
					title : '用户邮箱'
				},
				{
				    field : 'userBalance',
				    title : '用户余额'
				},
				{
                    field: 'status',
                    title: '用户状态',
                    align: 'center',
                    formatter: function(value, row, index) {
                    	return $.table.selectDictLabel(datas, value);
                    }
                },
		        {
		            title: '操作',
		            align: 'center',
		            formatter: function(value, row, index) {
		            	var actions = [];
		            	actions.push('<a class="btn btn-success btn-xs" href="#"><i class="fa fa-edit"></i>编辑</a> ');
                        actions.push('<a class="btn btn-danger btn-xs" href="#"><i class="fa fa-remove"></i>删除</a>');
						return actions.join('');
		            }
		        }]
            };
            $.table.init(options);
        });
        
        
        var uncheckUserCode = [];
    	$("#bootstrap-table").on("uncheck.bs.table uncheck-all.bs.table", function (e, rows) {
    		if(rows.length > 0) {
    			for (var index in rows) {
    				uncheckUserCode.unshift(rows[index].userCode);
   		        }
    		} else {
    			uncheckUserCode.unshift(rows.userCode);
    		}
    	});
        
    	$("#bootstrap-table").on("check.bs.table check-all.bs.table", function (e, rows) {
    		if(rows.length > 0) {
    			for (var index in rows) {
    				deleteItem(rows[index].userCode);
   		        }
    		} else {
    			deleteItem(rows.userCode);
    		}
    	});
    	
    	function deleteItem(item) {
    	    for (var key in uncheckUserCode) {
    	        if (uncheckUserCode[key] === item) {
    	        	uncheckUserCode.splice(key, 1)
    	        }
    	    }
    	}
        
        // 选中数据
        function checkItem(){
        	// var arrays = $.table.selectColumns("userId");
        	var arrays = $.table.selectColumns("userCode");
        	alert(arrays);
        }
    </script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

页面如何一次初始化多个表格

options中添加id参数,如果有按钮组也需要添加toolbar

// 表格1
var options = {
	id: "bootstrap-table1",
    toolbar: "toolbar1",
	// 省略 ....
};
$.table.init(options);

// 表格2
var options = {
	id: "bootstrap-table2",
    toolbar: "toolbar2",
	// 省略 ....
};
$.table.init(options);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

表格底部合计列拖动显示问题

options中添加onLoadSuccess参数。

onLoadSuccess: onLoadSuccess,

1
2
// 监听表体fixed-table-body滚动事件,赋值给表尾fixed-table-footer
function onLoadSuccess() {
	$(".fixed-table-body").on("scroll",function(){
		var sl=this.scrollLeft;
		$(this).next()[0].scrollLeft = sl;
	})
}
1
2
3
4
5
6
7

日期控件初始化时间并格式化

使用thymeleaf在页面直接获取当前时间并格式化输出

<input type="text" th:value="${#dates.format(new java.util.Date(), 'yyyy-MM-dd')}" />
<a th:text="${#dates.format(new java.util.Date().getTime(), 'yyyy-MM-dd HH:mm:ss')}">time</a>
1
2

如何调整首页左侧菜单栏宽度

调整style.css对应样式宽度,例如宽度200修改成250

body.fixed-sidebar .navbar-static-side, body.canvas-menu .navbar-static-side {
    width: 250px;
}
1
2
3
nav .logo {
	width: 250px;
}
1
2
3
#page-wrapper {
    margin: 0 0 0 250px;
}
1
2
3

如何默认显示表格卡片视图

options中添加 mobileResponsive cardView 参数

mobileResponsive: false,
cardView: true,
1
2

编辑和删除操作按钮不可用

这种情况一般是因为第一列不是唯一键或formatter序号造成的。解决方案如下,指定唯一列属性 配合删除/修改使用 未指定则使用表格行首列

options中添加 uniqueId参数,userId修改成你表的唯一列字段。

uniqueId: 'userId',
1

Tomcat部署多个War包项目异常

default-domain的值不一样就可以了 在application.yml里面配置上

spring:
  jmx:
    default-domain: applicationname
1
2
3

Tomcat临时目录tmp抛错误异常

首先,我们应该知道,对于http POST请求来说,它需要使用这个临时目录来存储post数据。
其次,因为该目录是挂在到/temp目录下的临时文件,那么对于一些OS系统,像centOS将经常删除这个临时目录,所有导致该目录不存在了

解决方案

1.在application.yml文件中设置multipart location ,并重启项目

spring:
  http:
    multipart:
      location: /data/upload_tmp
1
2
3
4

2.在application.yml文件中设置

server
  tomcat:
     basedir: /tmp/tomcat
1
2
3

3.在配置文件添加bean

@Bean
public MultipartConfigElement multipartConfigElement() {
  MultipartConfigFactory factory = new MultipartConfigFactory();
  factory.setLocation("/tmp/tomcat");
  return factory.createMultipartConfig();
}
1
2
3
4
5
6

4.添加启动参数-java.tmp.dir=/path/to/application/temp/,并重启。

如何部署配置支持https访问

Nginx 配置为例,完整流程如下

申请下载ssl证书 证书有很多种,申请成功后会得到一个压缩包,里面有2个证书

1、安装OpenSSL yum -y install openssl openssl-devel

2、运行添加ssl模块
./configure --prefix=/usr/local/nginx --with-http_ssl_module

3、配置完成后,运行命令 make

4、然后将刚刚编译好的nginx覆盖掉原有的nginx(这个时候nginx要停止状态)
cp objs/nginx /usr/local/nginx/sbin/

5、复制crt证书文件和key私钥文件到Nginx服务器/usr/local/nginx/conf目录(此处为 Nginx 默认安装目录,请根据实际情况操作)下。

6、编辑 Nginx 根目录下的 conf/nginx.conf 文件。添加内容如下:

# https 服务配置
server {
	# 侦听80端口
	listen 443 default ssl;
	ssl on;
	#证书文件名称
	ssl_certificate 1_ruoyi.vip_bundle.crt; 
	#私钥文件名称
	ssl_certificate_key 2_ruoyi.vip.key; 
	# 定义访问域名
	server_name ruoyi.vip;
	location / {
		# 存放了静态页面的根目录
		root   /home/ruoyi/projects/static-web;
		# 默认主页
		index index.html;
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

7、重启Nginx通过https访问 https://ruoyi.vip

8、如需把http的域名请求转成https,添加rewrite

rewrite ^(.*) https://$server_name$1 permanent;
1

9、解决重定向后https变成了http 的问题

proxy_redirect http:// https://; 
1

特殊字符串被过滤的解决办法

默认所有的都会过滤,可以配置 XSS excludes 属性 排除URL

# 防止XSS攻击
xss: 
  # 过滤开关
  enabled: true
  # 排除链接(多个用逗号分隔)
  excludes: /system/notice/*
  # 匹配链接
  urlPatterns: /system/*,/monitor/*,/tool/*
1
2
3
4
5
6
7
8

进入首页如何自动展开某菜单

例如,进入自动打开用户管理,调用applyPath,填入你请求菜单对应的url地址。

applyPath("/system/role")
1

打包如何分离jar包和资源文件

特殊情况需要分离lib和resouce可以修改ruoyi-admin 参考如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>ruoyi</artifactId>
        <groupId>com.ruoyi</groupId>
        <version>4.3.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
	<packaging>jar</packaging>
    <artifactId>ruoyi-admin</artifactId>
	
	<description>
	    web服务入口
	</description>

    <dependencies>
    
        <!-- SpringBoot集成thymeleaf模板 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!-- spring-boot-devtools -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<optional>true</optional> <!-- 表示依赖不会传递 -->
		</dependency>

		<!-- swagger2-->
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger2</artifactId>
		</dependency>
		
		<!--防止进入swagger页面报类型转换错误,排除2.9.2中的引用,手动增加1.5.21版本-->
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>1.5.21</version>
        </dependency>
        
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-models</artifactId>
            <version>1.5.21</version>
        </dependency>
		
		<!-- swagger2-UI-->
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger-ui</artifactId>
		</dependency>
		 
    	 <!-- Mysql驱动包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

		<!-- 核心模块-->
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-framework</artifactId>
        </dependency>
        
        <!-- 定时任务-->
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-quartz</artifactId>
        </dependency>
        
        <!-- 代码生成-->
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-generator</artifactId>
        </dependency>
        
    </dependencies>

     <build>
        <!-- jar包名 -->
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <!-- 分离lib -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <!-- 依赖包输出目录,将来不打进jar包里 -->
                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
                            <excludeTransitive>false</excludeTransitive>
                            <stripVersion>false</stripVersion>
                            <includeScope>runtime</includeScope>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <!-- copy资源文件 -->
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-resources</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <resources>
                                <resource>
                                    <directory>src/main/resources</directory>
                                </resource>
                            </resources>
                            <outputDirectory>${project.build.directory}/resources</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <!-- 打jar包时忽略配置文件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>**/*.yml</exclude>
                        <exclude>**/*.xml</exclude>
                    </excludes>
                </configuration>
            </plugin>
            <!-- spring boot repackage -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <layout>ZIP</layout>
                    <includes>
                        <include>
                            <groupId>non-exists</groupId>
                            <artifactId>non-exists</artifactId>
                        </include>
                    </includes>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
	
</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165

Linux系统验证码乱码解决方法

在云服务器(少许),或者干净的服务器上,服务器没有安装字体。

1、上传本地的 Arial.ttf 字体

2、此时执行以下三个命令:(建立字体索引信息,更新字体缓存)
mkfontscale mkfontdir fc-cache -fv

3、重新刷新你的页面