一、项目启动相关问题
1、项目启动一直卡在Initializing Spring embedded WebApplicationContext
1.1 分析
项目启动不报错,一直卡着不动;若是无缘无故出现,可能是断点断到方法上了;
1.2 原因
方法断点会降低调试器的速度,方法断点的使用成本很高尽量不要用;
1.3 解决
取消方法断点,或者直接把所有断点设为失效,不使用方法断点,可直接断点方法内代码。
2、错误: 找不到或无法加载主类 com.ruoyi.*Application
2.1 分析
移动了启动类的位置,class里没有重新编译;
2.2 解决
使用maven clean,清理一下,maven test测试成功即可;也可直接删除target目录,build -> rebuild project重新生成target即可。
3、启动成功后报错:dynamic-datasource can not find primary datasource
3.1 报错
com.baomidou.dynamic.datasource.exception.CannotFindDataSourceException: dynamic-datasource can not find primary datasource
3.2 分析
在pom.xml里面引入了动态数据源,可能没有直接引入:dynamic-datasource-spring-boot-starter,在pom.xml引入了ruoyi-common-datasource,而这个pom中引入了dynamic-datasource-spring-boot-starter;引入了没有使用,没有指定primary,则报出警告。
3.3 解决
1、如果要使用动态数据源,在yml文件中配置dynamic节点,具体可参考ruoyi-system.yml,下面简单举个例子:
spring:
application:
name: test
datasource:
dynamic:
primary: master
strict: true
datasource:
master:
url: xxxxx
username: xxx
password: xxx
2、若不需要使用动态数据源,在pom.xml中删除坐标引入即可。
二、新建子模块相关问题
1、接口报404或Whitelabel Error Page(也是404)
1.1 报错
没有找到对应controller的RequestMapping;
1.2 解决(前后端分离版)
①在父项目中的pom.xml添加对应的模块<modules>和<dependency>,参考ruoyi-generator;
②在子模块ruoyi-admin中的pom.xml,添加对应模块的<dependency>,参考ruoyi-generator;
③(※重要)将父项目的pom.xml,子模块admin的pom.xml,新建的子模块的pom.xml,分别右键->maven->Reload Project,然后整个项目 Rebuild Project,期间先关闭服务再操作,若仍然404,可关闭并重新打开开发工具,重新操作一遍该步骤。
1.3 解决(微服务版)
①保证modules的pom.xml添加了新建的子模块依赖
② 在限流策略里面添加新增模块配置(可直接复制system的,记得改resource):
③在网关配置里添加新模块的路由配置(可直接复制system的,记得改名称):
若仍然有问题,继续看下面:
④在vue的新模块api.js里,前缀与第③步前缀不一致,可以改成一致,也可以在api.js里增加前缀,但是保证整个url能与controller的@RequestMapping对应(注意:第③步网关配置的filters -StripPrefix=1,会过滤第一个字符串,即图中的'/xiaoya',到后台请求url,则不会再有'/xiaoya',参考下方api.js、controller),
2、接口访问报403错误(权限问题),只调postman调用/浏览器直接调用无问题,前端调用403错误
2.1 解决(前后端分离版)
去掉在:SecurityConfig.java 自定义的 .antMatchers("/test/**").anonymous(), 若依前端访问不是匿名,带有token,所以不使用anonymous(),默认的 authenticated 即可。
3、*Mapper.xml扫描不到(Invalid bound statement (not found))
3.1 分析
Invalid bound statement (not found): com.xxx.xxx.mapper.xxxMapper.selectList
准备将生成的*Mapper.xml放入至其他子模块试一下,发现文件名不对
这里没有合并,就看出问题来了 ,文件名称有问题
3.2 解决
这里的mapper.family,是一个文件名,family并不是一个子文件夹,将文件名修改好就行了。
4、启动后报错:dynamic-datasource can not find primary datasource
4.1 原因
新建模块直接复制了system的pom文件,里面使用了多数据源,而新建的模块里面不需要使用多数据源,或者没有用到多数据源,导致的这个问题。
4.2 解决
要么使用多数据源,要么删除依赖
删除依赖:ruoyi-common-datasource(而这个依赖引用的是common模块内的dynamic-datasource-spring-boot-starter依赖)
5、启动后报错(但是不影响启动):Server check fail, please check server 127.0.0.1 ,port 9848 is available
5.1 原因
nacos2.0版本,新增了gRPC 的通信方式(用于客户端向服务端发起连接请求),新增了两个端口。这两个端口在nacos原先的端口上(默认8848),进行一定偏移量自动生成;
客户端向服务端发起连接请求失败:
服务端:端口是否开放问题; 本地:几个服务同时启动,导致等待时间超过3秒
5.2 解决
【服务端】
①防火墙增加端口开放:8848、9848、9849;②服务器上启动的时候加上这句 -p 8848:8848 -p 9848:9848 -p 9849:9849 --privileged=true
【本地】:
1>直接忽略
8848是nacos默认端口,当应用类启动,会默认连接这个端口。如同一时间,多个应用同时启动,连接这个端口,服务器会卡,连接3秒超时后,连接失败的应用会尝试访问新端口9848,如果依然不行,会再去访问8848端口,反复连上后,就不会再报错了,也就启动成功了。
2>处女座请看这里
把GrpcClient.class源码弄下来,将超时时间改长即可,3秒可改成30秒:
(PS:如何修改源码:找到该源码的全路径,在自己项目路径下新建一个相同全路径的类,将源码粘贴至新建的类中,然后在该类中对相应代码进行正确修改即可,需要注意的一个问题,后面版本升级时需要注意该类的升级(本地类的加载,优先于依赖引入))
6、启动后报错:APPLICATION FAILED TO START
6.1 报错
Field *Mapper in com.*.*.service.impl.*ServiceImpl required a bean of type 'com.*.*.mapper.*Mapper' that could not be found.
6.2 原因
无法扫描到Mapper文件。
6.3 解决
在com.ruoyi.common.security.annotation.EnableCustomConfig 接口中,修改扫描注解:
@MapperScan({"com.ruoyi.**.mapper", "com.你的com名.**.mapper"})
或增加:
@MapperScan("com.你的com名.**.mapper")
7、启动后报错:Error parsing Mapper XML. The XML location is 'file [E:*\RuoYi-Cloud\ruoyi-modules\*\target\classes\mapper\*\*Mapper.xml]'.Could not resolve type alias '*'. Cause: java.lang.ClassNotFoundException: Cannot find class: *
7.1 原因
在*Mapper.xml里面,无法扫描到自定义类型的类所在包(没有配置实体类包扫描)。
7.2 解决
①将type类型,实体类指定具体的包名;
<resultMap type="com.你的com.domain.你的实体类" id="">...
包括Mapper.xml内,所有的自定义实体类型,包括 parameterType,都需要加上包名;
②修改设置Mybatis>typeAliasesPackage: com.你的com.**.domain(你的模块下的.yml文件,微服务在nacos里修改)
三、权限相关问题
1、获取用户信息异常
是由于权限控制,必须登录获取当前用户信息所致:@PreAuthorize("@ss.hasPermi('test:test:list')")
1.1 解决
若不需要登录就能访问,可以直接注释这个权限。
四、任务调度(定时任务)相关问题
1、自定义定时任务的bean无法访问:No bean named '*********Task' available
1.1 原因
新增的子模块,子模块内的bean无法被ruoyi-job加载到。
1.2 解决(微服务版)
①可直接在ruoyi-job模块内,在task包下,增加自定义定时任务类,增加 @Component 或 @Service,将类加载bean即可(参考RyTask.java)(否则需要在启动类里面指定加载注入bean);
②将Bean调用方式改成Class类调用:完整包名.类名.方法名()(有参则加括号,无参可加括号可不加)(注意:新增的模块,需要引入到ruoyi-job模块中,不然无法被加载上)
2、新增/修改定时任务时,提示:新增/修改任务'*****'失败,目标字符串不在白名单内
2.1 原因
若依框架在Contants里面设置了定时任务包名前缀的白名单数组:JOB_WHITELIST_STR,不在数组内的会被拦截;
2.2 解决
找到Constants.java,在常量数组JOB_WHITELIST_STR内增加你新增的子模块包名前缀。
3、定时任务里面调用其他模块的service,使用@Autowire自动注入,注入对象为null,调用里面的方法报错:空指针异常java.lang.NullPointerException,使用SpringUtils.getBean()也无法获取bean
3.1 原因
其他模块没有被依赖,spring没有加载bean;
3.2 解决:(前后端分离版)
若需要调用其他模块的service,则需要引入其他模块的依赖,且启动类需要添加scanBasePackages,要扫描Mapper文件需要添加MapperScan;
3.3 解决:(微服务版)
使用Feign调用其他服务接口api的方式:
①添加依赖(核心模块core默认已有)
<!-- spring cloud openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
②新建RemoteUserService.java
服务接口
注意:@FeignClient的value值,对应被调用方的应用名称
(bootstrap.yml的spring:application:name)
package com.ruoyi.system.api;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import com.ruoyi.common.core.constant.ServiceNameConstants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.system.api.factory.RemoteUserFallbackFactory;
import com.ruoyi.system.api.model.LoginUser;
/**
* 用户服务
*
* @author ruoyi
*/
@FeignClient(contextId = "remoteUserService", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = RemoteUserFallbackFactory.class)
public interface RemoteUserService
{
/**
* 通过用户名查询用户信息
*
* @param username 用户名
* @return 结果
*/
@GetMapping(value = "/user/info/{username}")
public R<LoginUser> getUserInfo(@PathVariable("username") String username);
}
③新建RemoteUserFallbackFactory.java
降级实现
package com.ruoyi.system.api.factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.system.api.RemoteUserService;
import com.ruoyi.system.api.model.LoginUser;
import feign.hystrix.FallbackFactory;
/**
* 用户服务降级处理
*
* @author ruoyi
*/
@Component
public class RemoteUserFallbackFactory implements FallbackFactory<RemoteUserService>
{
private static final Logger log = LoggerFactory.getLogger(RemoteUserFallbackFactory.class);
@Override
public RemoteUserService create(Throwable throwable)
{
log.error("用户服务调用失败:{}", throwable.getMessage());
return new RemoteUserService()
{
@Override
public R<LoginUser> getUserInfo(String username)
{
return R.fail("获取用户失败:" + throwable.getMessage());
}
};
}
}
④消费者TestUserController.java
新增info
查询用户方法
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestUserController
{
@Autowired
private RemoteUserService remoteUserService;
/**
* 获取当前用户信息
*/
@GetMapping("/user/{username}")
public Object info(@PathVariable("username") String username)
{
return remoteUserService.getUserInfo(username);
}
}
⑤启动类添加@EnableRyFeignClients
注解,默认的@EnableRyFeignClients
扫描范围com.ruoyi(其他不在此目录下,在EnableRyFeignClients.java里修改)
。
⑥启动后访问http://localhost:8888/user/admin
,返回正确数据表示测试通过。
五、前后端接口访问问题(api/controller访问问题)
1、Feign使用@RequestBody传值报错:com.ruoyi.common.core.exception.ServiceException: JSON parse error: Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed between tokens; nested exception is com.fasterxml.jackson.core.JsonParseException: Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed between tokens
at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 2]
1.1 原因
由于接口参数值内容过大/数量过多后,默认使用gzip压缩,然后解码时乱码无法解码导致这个问题;
1.2 分析
参数使用List传值,少量条数正常, 大量条数能复现问题;
花了一上午,使用了各种方案,为了各位少走弯路,特意贴出解决办法(②可以解决,但不合适,直接使用第③个解决):
1.3 解决
过程:
①在application-dev.yml中设置feign.compression.response.useGzipDecoder=true(设置Gzip解码方式,feign 2.2.x版本之后 默认已经支持 gzip解码了)
②在application-dev.yml中设置feign.compression.request.min-request-size=10240(size要大到过滤掉你的数据大小,原理:设置压缩数据大小的下限,传输数据大小低于这个值则不会压缩)
③分析过程:将List改为String类型接收后,能看出控制台日志是乱码导致无法解码:
controller:
console:
解决方案:在feign配置api接口中,post接口设置消费者类型:
consumes = "application/json;charset=UTF-8"
2、微服务api调用其他服务报错:没有访问权限,请联系管理员授权
2.1 原因
由于Mapping不一致导致无权限;
2.2 解决
检查Feign接口内方法Mapper类型和Controller方法上的Mapper类型是否一致。
3、前后端传值,对象里包含对象,请求报错:Property referenced in indexed property path 'readRecord[userId]' is neither an array nor a List nor a Map.
3.1 问题重现
3.1.1 前端:参数对象
3.1.2 后端:实体、控制器
3.2 报错
Property referenced in indexed property path 'readRecord[userId]' is neither an array nor a List nor a Map.
3.3 解决
修改前端:传值方式修改成(内部对象改为字符串方式):
方法①
或
方法②
4、knife4j接口文档没有排序,设置@ApiOperationSupport(order = 1)不生效
4.1 问题
对应版本:knife4j v2.0.4,接口方法增加了@ApiOperationSupport(order = 1),仍然不排序
4.2 原因
没有开启增强模式
4.3 解决
在application-dev.yml 和 自己相应模块的yaml里增加配置:
knife4j:
# 开启增强配置
enable: true
# 开启生产环境屏蔽 production: true时就访问不了swagger了
production: false
4.4 示例
六、工具类相关问题
1、文件上传下载
1.1 文件上传
后台报错:Content type 'multipart/form-data;boundary=----WebKitFormBoundarymn2IDPynGhlHwALI;charset=UTF-8' not supported;
解决:去掉:@RequestBody,body不会接收file。
2、日志
2.1 SQL日志打印
2.1.1 解决
需要SQL日志打印的模块添加mybatis配置(.yml):
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
3、数据字典
3.1 若依接口
文件:data.js
①查询字典数据列表:/system/dict/data/list
②查询字典数据详细:/system/dict/data/{dictCode}
③根据字典类型查询字典数据信息:/system/dict/data/type/{dictType}
3.2 自定义多级数据字典
①方式一:数据字典数据分割方式(前端根据数据值进行分组):
一级数据字典:dict_value:11、12、13
二级数据字典:dict_value:1101、1102、1201、1202、1203、1301
三级数据字典:dict_value:110101、110102、110201
......
②方式二:树表方式(可参考sys_dept部门表树结构)
(1、若不设置children,则前端根据数据parent_id进行分组;2、若设置children,则前端直接可取到树状的data):
create table test (
id bigint(20),
parent_id bigint(20),
name varchar(30)
)