Skip to content

常见问题

TIP

提问之前,请先查阅下面的常见问题。

前端

前端项目install安装包时因node版本小于10报错

这个需要你升级你的node版本,你可以前往Node.js官网 下载安装10以上版本的node即可解决。

修改自定义组件重新上传后未显示最新修改内容

修改上传的自定义组件文件时,若文件名未修改,由于浏览器缓存,会出现组件修改部分未生效的问题。可通过在文件名添加后缀的方式解决。或在打包命令中添加--filename $RANDOM参数,但该方法生成的文件名不会包含comName编码。建议通过在文件名添加后缀的方式进行解决。

实际接口调用与代码编写的请求路径不一致,请求路径添加了前缀

在使用盘古公共请求函数request时,请求路径需要以/开头,例如/api/user,否则,实际请求路径会添加页面路由前缀。

前端页签的打开和关闭

  • 打开
  1. 调用this.$router.push({path: '/xxx'})即可新增一个页签
  2. 调用框架中提供的多页签的操作方法
jsx
this.$multiTab.open(fullPath)
  • 关闭
  1. 调用this.$multiTab.closeCurrentPage()即为关闭当前页签
  2. 调用this.$multiTab.close()不传参数即为关闭当前页签,传指定的fullPath即为关闭fullPath对应的多页签
  • 关闭当前页签跳转到另一个页签,可如下操作
jsx
this.$multiTab.closeCurrentPage();
setTimeout(() => {
  this.$router.push("/tableListApp/tablelist");
});

Q: 首次配置SSO登录时错误?

1、检查申请的回调地址,结尾是否包含了‘/’,如果包含了请联系sso的管理员去掉‘/’。 2、配置sso登录参数时,sso的id和secret请勿直接复制,可能有字体格式,建议手动填写。

后端

如何获取当前登录用户?

java
// 使用SecurityUtils获取LoginUser
LoginUser loginUser = SecurityUtils.getLoginUser();

// 获取userId
Long userId = SecurityUtils.getLoginUser().getUserId();

// 获取loginName
String loginName = SecurityUtils.getLoginUser().getLoginName();

Q: 如何本地调试接口?

在对应模块的src/main/resource/application.yml文件中配置忽略接口鉴权的url,便于开发调试。

yaml
security:
  oauth2:
    ignore:
      urls:
        - /order/list     #忽略对 /order/list 的鉴权
        - /order/*        #忽略匹配 /order/* 模式的鉴权
        - /order/get/*    #忽略匹配 /order/get/* 模式的鉴权

查询接口请求路径字符串类型传参中包含.

当传参封装在请求的url上,且传参类型为字符串,传入参数后缀包含了.,需要将路径中的传参更改为{demo:{username:.+}

jsx
样例:请求参数demo字段的值为aaa.ex  接口的编写方式如下所示:

/**
 * 查询
 */
@GetMapping("test/{demo:.+}")
public Demo selectDemo(@PathVariable("demo") String demo) {
    return service.select(demo);
}

行数据权限在菜单或数据权限扩展接口中配置后,该条数据权限不生效

当行数据权限在菜单或者数据权限扩展接口中配置后,该条数据权限不生效,请排查以下因素:

  1. 检查页面请求的Headers中menuCode参数与数据扩展接口中配置的菜单编码menuCode是否一致:
java
menuCode: loginLog
Pragma: no-cache
Referer: http://pangea.test.devapps.hisense.com/monitor/loginLog
  1. 检查相对应的mapper.xml中的resultMap的property或实体中是否有数据权限的规则字段:
xml
 <resultMap id="OrganizationResult" type="Organization">
      <result property="id" column="id"/>
      <result property="orgCode" column="org_code"/>
      <result property="orgName" column="org_name"/>
      <result property="orgLevel" column="org_level"/>
      <result property="typeCode" column="type_code"/>
      <result property="fullName" column="full_name"/>
      <result property="enabled" column="enabled"/>
      <result property="sortNum" column="sort_num"/>
      <result property="parentCode" column="parent_code"/>
</resultMap>

引入bpmClientjar包后,yml的配置取不到,导致调用流程失败

引入bpmClientjar包后,调用方法可以调到,但是yml的配置取不到,导致调用流程失败,造成这个问题的原因是包的扫描路径导致,bpmClient的路径是下图:

而使用框架的系统扫描的设置一般是这样:

java
@EnableDiscoveryClient
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, ResourceServerConfig.class})
@MapperScan("com.hisense.demo.mapper")
@EnableCustomConfig
public class PangeaDemoApp {
   public static void main(String[] args) {
       SpringApplication.run(PangeaDemoApp.class, args);
   }
}

使用 @SpringBootApplication的默认加载路径去加载实体类,而系统的路径和bpmClient的路径明显不一致,就会导致bpmClient的类不会被扫描到,就会导致上面的问题,运行时找不到配置和方法,加上@ComponentScan扫描后可以解决问题:

java
@EnableDiscoveryClient
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, ResourceServerConfig.class})
@MapperScan("com.hisense.demo.mapper")
@EnableCustomConfig
@ComponentScan({"com.hisense.demo","com.hisense.pangea"})
public class PangeaDemoApp {
    public static void main(String[] args) {
        SpringApplication.run(PangeaDemoApp.class, args);
    }
}

通过@ComponentScan指定扫描路径,当需要注意带着当前启动类之前扫描的路径。

框架生成代码id过长不好维护的问题

使用框架生成的代码,数据新增时,生成的id是经过雪花算法生成,id很长,不好维护,返回给前端还会丢失精度,系统也没有那么大数据量,根本不需要雪花算法。使用默认生成的方法,新增数据是使用的mybatis-plussave方法,默认生成id的算法就是雪花算法导致的这个问题,如下操作可以避免此问题。

  1. 新建配置类MybatisPlusConfigurer,指定mapper的位置
java
    @Configuration
    @MapperScan("com.hisense.*.*.mapper")
    public class MybatisPlusConfigurer {
       
       /**
        * Sequence主键自增
        *
        */
       @Bean
       public OracleKeyGenerator oracleKeyGenerator() {
           return new OracleKeyGenerator();
       }
    }
  1. 在数据实体类上做如下修改,主要是@KeySequence@TableId
java
    @KeySequence("LANGUAGE_SEQUENCE")
    @TableName("sys_oss")
    public class Organization implements Serializable {
    
        /**
         * 唯一标识
         */
        @Id
        @TableId(value = "id", type = IdType.INPUT)
        private Long id;
        }

@KeySequence指定序列,@TableId指定根据序列自增的列,就能根据序列生成id,而不用雪花算法生成。

页面上删除按钮后,挂载该页面的菜单权限突然消失

  • 详情:
    • 当一个菜单下仅只有一个按钮时,在角色管理勾选了该菜单以及该按钮的权限。
    • 若后续删除此按钮,则同时该菜单的权限也被同时删除了,需重新够选该菜单的权限。
    • 以上情况仅限于只有一个按钮的菜单,需特别注意。

<img class="preview-img-sm" src={require('/img/docs/FAQ-7.png').default}/>

  • 原因:前端采用树形强关联结构,当父节点只有一个子节点时,选父节点必选子节点,删除子节点则父节点必跟着一起删除。所以,当菜单下只有一个按钮时,删除该按钮,默认挂载该按钮的菜单权限,如下:

  • 措施:在角色管理中,需重新够选该菜单的权限。

系统升级到2.0.4或更高版本后,Feign调用不通,提示调用失败,会被熔断

原因:框架调整了feign,需要允许sentinel,在配置文件添加配置:

xml
feign:
 sentinel:
   enabled: true

新增应用或菜单后,勾选权限失效

  • 详情: 新增了一个应用或者菜单之后,进角色管理勾选权限,保存显示成功,但不生效,再次打开后,该应用或菜单的权限依然没有被勾上。

  • 原因:填写的应用编码或菜单编码包含-

  • 措施:应用编码或菜单编码不允许包含-

新增菜单后,也勾选了权限,但是进应用后看不到该菜单

  • 详情: 新增了一个菜单之后,进角色管理勾选权限,但进入应用之后看不到该菜单,如下图

  • 原因: 使用开发工具 下的菜单管理 创建的菜单,导致该条数据不包含app_code(应用编码)
  • 措施:
    1.在数据库sys_menu表为该菜单数据添加app_code(应用编码)
    2.建议使用开发平台,在应用下创建菜单
    3.升级版本至2.1.0+,新版本已修复此问题

sso账号登录直接报错,提示找不到用户

  • 原因:system服务需要配置是去测试还是生产的ldap查询数据

  • 措施:需要确认好这个账号是不是只在开发用,生产没有该账号,或者相反直接通过配置环境变量方式即可,环境变量值如下:

变量名称变量含义样例
LDAP_TOKEN_URLldap 查token地址ssodev.hisense.com
LDAP_USER_APPSECRET_IDldap申请的idsys_xizxdev
LDAP_USER_APPSECRET_KEYldap申请的key2222e0ae8bdfc3ecbafd56c56b9daaab
LDAP_WEB_SERVICEldap查询的地址http://idmdev.hisense.com

Q:系统配置成https后,服务无法正常使用

  • 原因:服务是http,https不能访问不安全的链接导致的。

  • 解决方案:(以报表服务为例)
    1.配置报表代理地址,假设是https://pangea.dev.devapps.hisense.com/ureport,这个是要被代理的地址。
    2.前端nginx添加代理逻辑

	location /ureport/ {
            proxy_pass https://pangea-ureport.devapps.hisense.com/;
    }

@CacheEvict只能清除二级缓存(redis),一级缓存清除不了

  • 详情: A和B两个服务, A服务使用@Cacheable注解将数据查询或保存至缓存中, B服务将A服务存在缓存中的数据清除, 但发现,redis缓存(二级缓存)清除后,第二次保存时未保存在redis缓存中(二级缓存)

  • 原因: 框架缓存分为一级缓存和二级缓存, 一级缓存为本地缓存,采用cache; 二级缓存为redis缓存.每个服务中都会有一个本地服务, 服务与服务之间的一级缓存是不通的, 但二级缓存redis作为公共缓存, 一个系统下所有的服务共用一个二级缓存 所以当跨服务使用@CacheEvict只能清除本地缓存及二级缓存,不能清除@Cacheable所在服务的本地缓存

  • 措施: 将@CacheEvict和@Cacheable放在一个服务中

使用缓存注解未生效

  • 请检查确认是否存在类内调用的情况,如存在改为类间方法调用
  • 使用Spring注解标识的方法在Spring加载类的时候会生成代理类,调用时会通过代理类调用原本类的方法;而同一个类中方法间调用并不会通过代理类,而是直接调用

使用saveOrUpdate()或者使用saveOrUpdateBatch(),报错,提示

Error attempting to get column 'CREATED_DATE' from result set;    
Cause: java.sql.SQLException: 请求的转换无效\n;   
uncategorized SQLException; SQL state [99999]; error code [17132]; 请求的转换无效;   
nested exception is java.sql.SQLException: 请求的转换无效;
  • 使用saveOrUpdate类方法会去先查数据,然后保存,问题就出在查询之后的保存,数据库的字段格式和java代码的字段类型不匹配导致,排查后发现CREATED_DATE设置的是VARCHAR2(255)类型, 而java代码是Date类型,数据库应该用TIMESTAMP(6),这个错误可以推广到其他数据类型。

应用频繁重启,或者接口返回时间长,服务出现注册不上等情况

  • 排查后是应用内存不足导致的问题
    • 云平台分配的应用资源的内存大小,是否可以满足配置,在如下设置:
    • 另外一个需要注意的是,环境变量中需要加上内存限制,配合内存设置:
      JAVA_OPTIONS=-Xms3300M -Xmx3300M -Xmn800M
    • 上述内存优化配置后扔存在重启情况,出现一下报错: 明显是MetaspaceSize 大小设置的问题,需要在云平台环境变量设置: GC_MAX_METASPACE_SIZE = 256

时间相差8小时或者出现中文乱码

  • 设置云平台环境变量
    • 时区问题 TZ=Asia/Shanghai
    • 乱码问题 LC_ALL=en_US.utf-8

个别用户突然登不上系统,大部分正常,日志提示“SSO认证失败,请联系管理员”

  • 账号在SSO认证不通过导致登不上系统
    • 确认近期是否修改过密码,而SSO修改密码没成功,用旧的密码尝试登录
    • 重新设置SSO密码,再尝试登录
    • 以上方案还不行,请联系SSO管理员查询该账号状态是否正常

项目启动后查询报错,都提示wait millis 60000, active 0, maxActive 100, creating 0, createErrorCount 1640

  • 出现该问题的原因是,数据库是serviceName形式,而用的PID的形式去连接数据库导致,解决方案就是用正确的方式连接数据库即可,详细配置方式参见Pangea配置属性详解的数据库属性

如何在spring cloud gateway 网关层解决跨域问题

  • 在网关的yml文件中增加跨域配置即可在网关层解决跨域问题
spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]': 
            # 允许携带认证信息
            # 允许跨域的源(网站域名/ip),设置*为全部
            # 允许跨域请求里的head字段,设置*为全部
            # 允许跨域的method, 默认为GET和OPTIONS,设置*为全部
            # 跨域允许的有效期
            allow-credentials: true
            allowed-origins: 
            - "http://localhost:13009"
            - "http://localhost:13010"
            allowed-headers: "*"
            allowed-methods: 
            - OPTIONS
            - GET
            - POST
            max-age: 3600
            # 允许response的head信息
            # 默认仅允许如下6个:
            #     Cache-Control
            #     Content-Language
            #     Content-Type
            #     Expires
            #     Last-Modified
            #     Pragma
            #exposed-headers:

调用上传加密文件接口时,提示IP不在白名单内

  • 项目内的加密客户端需要调用发布在网关的接口,调用网关接口需要将部署服务所在的虚机ip或云平台内标签对应的node ip添加至调用白名单

调用接口404错误问题排查思路参考

系统运行中有时候会遇到调用接口报404错误,大部分情况是接口路径书写错误,只要修改代码即可。 但有一种情况,接口路径明明是对的,运行时也很正常,只是偶尔发生404错误。有可能是因为在path路径中带有@PathVariable参数,比如路径为:@GetMapping("/getUserInfo/{id}"),如果id是一个错误的值,就会报404错误,解决问题要从数据层面进行排查。

云平台迁移后导出功能出错

遇到需要对发布的服务进行环境迁移时,平台管理员一般会把整个项目下所有的服务包括流水线配置,缓存、日志等都整体进行拷贝,基本不需要项目组进行调整,但是股权系统在迁移后,所有导出功能不可用,经排查发现是因为在新的环境下需要创建一个名为excel-templatesStorage,用于暂存导出文件用。

F5刷新时从token读取用户信息token失效的问题

股权系统在云平台部署UAT环境后,访问系统登录成功,可以打开页面功能页面,貌似一切正常,但是用F5刷新的时候,从token读取用户信息,发现token失效,排查发现是nginx配置问题导致,按以下信息配置,重启前端服务后,问题解决。

java
 location / {
                location ~ .*\.(js|css|jpg|jpeg|git|png|bmp|swf|htm|html|json|xml|svg|woff|ttf|eot|map|ico)$ {
                expires      1h;
                if (-f $request_filename) {
                    break;
                }
            }

            #动态页面
            if (!-e $request_filename) {
                proxy_pass http://jhipster-gate:8080;
            }
        }
修改后:
 location / {
            try_files $uri $uri/ /index.html; 
        }

脚手架启动报获取版本空指针异常

问题现象 :脚手架启动过程中,在检测版本时,日志中报获取版本号空指针异常,如下:

log
java.lang.IllegalStateException: Failed to execute ApplicationRunner
 at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:778)
 at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:765)
 at org.springframework.boot.SpringApplication.run(SpringApplication.java:322)
 at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
 at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
 at com.hisense.maindata.MaindataApplication.main(MaindataApplication.java:22)
Caused by: java.lang.NullPointerException: null
 at com.hisense.pangea.version.service.DefaultVersionService.getVersion(DefaultVersionService.java:29)
 at com.hisense.pangea.version.service.VersionChecker.compareVersion(VersionChecker.java:80)
 at com.hisense.pangea.version.service.VersionChecker.run(VersionChecker.java:72)
 at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:775)
 ... 5 common frames omitted

原因分析: 在处理请求返回的响应中,使用了FastJsonHttpMessageConverters消息转换器,获取版本请求响应的data中并非是json格式的字符串,所以FastJsonHttpMessageConverters消息转换器并不能将获取的版本号进行正常返回 修复措施: 删除fastJsonHttpMessageContertersbean, 使用默认的HttpMessageConverters。在项目中添加如下代码:

java
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class HttpMessageConvertersConfig {

    @Bean
    public HttpMessageConverters httpMessageConverters(){
        return new HttpMessageConverters();
    }
}
java
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.stereotype.Component;
import java.util.Iterator;

@Component
public class RemoveRegistyBeanFactory implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {

        if(beanDefinitionRegistry.containsBeanDefinition("fastJsonHttpMessageConverters")){
            beanDefinitionRegistry.removeBeanDefinition("fastJsonHttpMessageConverters");
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {}
}

公共导入功能导入后报错,报错信息如下:

text
Maximum upload size exceeded; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException: The field file exceeds its maximum permitted size of 5242880 bytes

原因分析: SpringBoot做文件上传时出现了The field file exceeds its maximum permitted size of 5242880 bytes.错误,显示文件的大小超出了允许的范围。查看了官方文档,原来Spring Boot工程嵌入的tomcat限制了请求的文件大小,这一点在Spring Boot的官方文档中有说明,原文如下

65.5 Handling Multipart File Uploads Spring Boot embraces the Servlet 3 javax.servlet.http.Part API to support uploading files. By default Spring Boot configures Spring MVC with a maximum file of 1Mb per file and a maximum of 10Mb of file data in a single request. You may override these values, as well as the location to which intermediate data is stored (e.g., to the /tmp directory) and the threshold past which data is flushed to disk by using the properties exposed in the MultipartProperties class. If you want to specify that files be unlimited, for example, set the multipart.maxFileSize property to -1.The multipart support is helpful when you want to receive multipart encoded file data as a @RequestParam-annotated parameter of type MultipartFile in a Spring MVC controller handler method.

文档说明表示,每个文件的配置最大为1Mb,单次请求的文件的总数不能大于10Mb。要更改这个默认值需要在配置文件(如application.properties)中加入两个配置

需要设置以下两个参数

yml
spring:
    servlet:
        multipart.max-file-size=100MB
        multipart.max-request-size=1000MB

盘古模块引入后,无法扫描到模块中的xml类型文件,导致执行方法报错

问题现象

text
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)

原因分析

在mybatis-plus中mapper接口与mapper配置文件在做映射绑定的时候出现问题,简单说,就是接口与xml要么是找不到,要么是找到了却匹配不到。

解决方案

在application.yml中配置xml文件全路径,如下:

text
mybatis-plus:
		mapperLocations: classpath*:/com/XXX/**/**.xml

已表单引擎模块举例:

text
mybatis-plus:
  type-aliases-package: com.hisense.pangea.domain
  # 配置mapper的扫描,找到所有的mapper.xml映射文件
  mapperLocations: classpath*:/mapper/system/**.xml,classpath*:com/hisense/pangea/page/design/mappings/**.xml

部署

云平台配置文件中应该使用什么账号来作为credentialsId?

许多系统在一开始部署云平台服务时,图省事直接使用项目人员(如技术经理)的个人账号进行credentialsId的配置,但因为该账户为LDAP账号,用户一旦修改该账号的密码,就会导致CredentialId失效,从而导致进行发版时无法读取代码。

所以,在一开始部署云平台服务时,一定要申请一个独立的可取权限的系统账户,专门用户云平台读取代码用。在云平台的流水线pipeline配置文件中,配置从git仓库读取项目代码的 credentialsId,其值为在Jenkins>>Credentials中输入有权限的用户和密码后生成的:

def credentialsId = "2f62420a-abe1-4b1f-aab2-93bb46bbdc08"