若依框架-遇到的相关问题

一、新建子模块相关问题

1、接口报404Whitelabel Error Page(也是404)

没有找到对应controller的RequestMapping;

解决(前后端分离版):

在父项目中的pom.xml添加对应的模块,参考ruoyi-generator;

在子模块ruoyi-admin中的pom.xml,添加对应模块的,参考ruoyi-generator;

※重要)将父项目的pom.xml,子模块admin的pom.xml,新建的子模块的pom.xml,分别右键->maven->Reload Project,然后整个项目 Rebuild Project,期间先关闭服务再操作,若仍然404,可关闭并重新打开开发工具,重新操作一遍该步骤

解决(微服务版):

保证modules的pom.xml添加了新建的子模块依赖

若依框架-遇到的相关问题_第1张图片

限流策略里面添加新增模块配置(可直接复制system的,记得改resource):

若依框架-遇到的相关问题_第2张图片

 ③在网关配置里添加新模块的路由配置(可直接复制system的,记得改名称):

若依框架-遇到的相关问题_第3张图片

 若仍然有问题,继续看下面:

在vue的新模块api.js里,前缀与第③步前缀不一致,可以改成一致,也可以在api.js里增加前缀,但是保证整个url能与controller的@RequestMapping对应(注意:第③步网关配置的filters -StripPrefix=1,会过滤第一个字符串,即图中的'/xiaoya',到后台请求url,则不会再有'/xiaoya',参考下方api.js、controller),

若依框架-遇到的相关问题_第4张图片

若依框架-遇到的相关问题_第5张图片

2、接口访问报403错误(权限问题),只调postman调用/浏览器直接调用无问题,前端调用403错误

解决(前后端分离版):去掉在:SecurityConfig.java 自定义的 .antMatchers("/test/**").anonymous(), 若依前端访问不是匿名,带有token,所以不使用anonymous(),默认的 authenticated 即可。

3、*Mapper.xml扫描不到(Invalid bound statement (not found))

Invalid bound statement (not found): com.xxx.xxx.mapper.xxxMapper.selectList

准备将生成的*Mapper.xml放入至其他子模块试一下,发现文件名不对

这里没有合并,就看出问题来了 ,文件名称有问题若依框架-遇到的相关问题_第6张图片

解决: 这里的mapper.family,是一个文件名,family并不是一个子文件夹,将文件名修改好就行了。

4、启动后报错:dynamic-datasource can not find primary datasource

原因:新建模块直接复制了system的pom文件,里面使用了多数据源,而新建的模块里面不需要使用多数据源,或者没有用到多数据源,导致的这个问题。

解决:要么使用多数据源,要么删除依赖

        删除依赖:ruoyi-common-datasource(而这个依赖引用的是common模块内的dynamic-datasource-spring-boot-starter依赖)

5、启动后报错(但是不影响启动):Server check fail, please check server 127.0.0.1 ,port 9848 is available

原因:nacos2.0版本,新增了gRPC 的通信方式(用于客户端向服务端发起连接请求),新增了两个端口。这两个端口在nacos原先的端口上(默认8848),进行一定偏移量自动生成;

若依框架-遇到的相关问题_第7张图片

客户端向服务端发起连接请求失败:

        服务端:端口是否开放问题;           本地:几个服务同时启动,导致等待时间超过3秒

解决:

        【服务端①防火墙增加端口开放: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:如何修改源码:找到该源码的全路径,在自己项目路径下新建一个相同全路径的类,将源码粘贴至新建的类中,然后在该类中对相应代码进行正确修改即可,需要注意的一个问题,后面版本升级时需要注意该类的升级(本地类的加载,优先于依赖引入)

若依框架-遇到的相关问题_第8张图片

6、启动后报错:APPLICATION FAILED TO START

Description:

Field *Mapper in com.*.*.service.impl.*ServiceImpl required a bean of type 'com.*.*.mapper.*Mapper' that could not be found.

原因:无法扫描到Mapper文件

解决:在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: *

原因:在*Mapper.xml里面,无法扫描到自定义类型的类所在包(没有配置实体类包扫描)

解决:

①将type类型,实体类指定具体的包名;

...

包括Mapper.xml内,所有的自定义实体类型,包括 parameterType,都需要加上包名;

②修改设置Mybatis>typeAliasesPackage: com.你的com.**.domain(你的模块下的.yml文件,微服务在nacos里修改

二、权限相关问题

1、获取用户信息异常

是由于权限控制,必须登录获取当前用户信息所致:@PreAuthorize("@ss.hasPermi('test:test:list')")

解决:若不需要登录就能访问,可以直接注释这个权限。

三、任务调度相关问题

1、自定义定时任务的bean无法访问:No bean named '*********Task' available

原因:新增的子模块,子模块内的bean无法被ruoyi-job加载到

解决(微服务版):

①可直接在ruoyi-job模块内,在task包下,增加自定义定时任务类,增加 @Component 或 @Service,将类加载bean即可(参考RyTask.java)(否则需要在启动类里面指定加载注入bean);

②将Bean调用方式改成Class类调用:完整包名.类名.方法名()(有参则加括号,无参可加括号可不加)(注意:新增的模块,需要引入到ruoyi-job模块中,不然无法被加载上

2、新增/修改定时任务时,提示:新增/修改任务'*****'失败,目标字符串不在白名单内

原因:若依框架在Contants里面设置了定时任务包名前缀的白名单数组:JOB_WHITELIST_STR,不在数组内的会被拦截;

解决:找到Constants.java,在常量数组JOB_WHITELIST_STR内增加你新增的子模块包名前缀。

3、定时任务里面调用其他模块的service,使用@Autowire自动注入,注入对象为null,调用里面的方法报错:空指针异常java.lang.NullPointerException,使用SpringUtils.getBean()也无法获取bean

原因:其他模块没有被依赖,spring没有加载bean;

解决(前后端分离版):若需要调用其他模块的service,则需要引入其他模块的依赖,且启动类需要添加scanBasePackages,要扫描Mapper文件需要添加MapperScan;

解决(微服务版):使用Feign调用其他服务接口api的方式:

添加依赖(核心模块core默认已有)



	org.springframework.cloud
	spring-cloud-starter-openfeign

新建RemoteUserService.java服务接口

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 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
{
    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 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]

原因:由于接口参数值内容过大/数量过多后,默认使用gzip压缩,然后解码时乱码无法解码导致这个问题;

分析:参数使用List传值,少量条数正常, 大量条数能复现问题;

花了一上午,使用了各种方案,为了各位少走弯路,特意贴出解决办法(②可以解决,但不合适,直接使用第③个解决)

解决方案:

在application-dev.yml中设置feign.compression.response.useGzipDecoder=true(设置Gzip解码方式,feign 2.2.x版本之后 默认已经支持 gzip解码了)

若依框架-遇到的相关问题_第9张图片

 

在application-dev.yml中设置feign.compression.request.min-request-size=10240(size要大到过滤掉你的数据大小,原理:设置压缩数据大小的下限,传输数据大小低于这个值则不会压缩)

若依框架-遇到的相关问题_第10张图片

 

分析过程:将List改为String类型接收后,能看出控制台日志是乱码导致无法解码:

controller:

若依框架-遇到的相关问题_第11张图片

 console:

若依框架-遇到的相关问题_第12张图片

 解决:在feign配置api接口中,post接口设置消费者类型:

 consumes = "application/json;charset=UTF-8"

 

 

五、工具类相关问题

1、文件上传

后台报错:Content type 'multipart/form-data;boundary=----WebKitFormBoundarymn2IDPynGhlHwALI;charset=UTF-8' not supported;

解决:去掉:@RequestBody,body不会接收file。

你可能感兴趣的:(Spring,若依框架,微服务,spring,java)