微服务springcloud与springboot maven常见问题整理记录
1. 组件问题
(1) 使用nacos组件注册服务时,可不用指定@EnableDiscoveryClient注解
(2) 使用openfeign封装外部接口时,只用在fallback类指定@EnableFeignClients说明即可注入,打开fallback设置yml中的
feign:
hystrix:
enabled: true #设置熔断调用
2. 扫描问题
(1) @SpringBootApplication( exclude/*用来排除auto-configuration的类*/ = {BaseException.class})
(2) @ComponentScan(
/* 指定扫描的基包路径*/
basePackages = "com.XXX.cloud",
/* 用于排除注入的定义的BEAN类 */
excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = BaseException.class))
3. 多模块maven问题
(1) 在dependency中有spring-boot-starter-web并使用spring-boot-maven-plugin打包,则是web项目,应有启动的main方法或@SpringBootApplication注解的启动类
(2) 引用某个模块的方式,从<packaging>pom</packaging>类型的maven模块扩展或dependency中增加<packaging>jar</packaging>类型的模块
默认的packaging类型是jar
(3) 打包问题:
指令:
compile 编译
install 安装本地
deploy 安装本地并推远程仓库
package 打包
在maven多模块module组织的项目中,
打普通的jar工具包,可使用默认的打包配置(不设置<build><plugins><plugins><build>),
打包可执行的web项目时使用spring-boot-maven-plugin工具(外部引用不了可执行的web项目jar包中的方法或类)
说明:
<build>
<plugins>
<!--<plugin>-->
<!--<groupId>org.apache.maven.plugins</groupId>-->
<!--<artifactId>maven-compiler-plugin</artifactId>-->
<!--<version>3.3</version>-->
<!--<configuration>-->
<!--<source>${java.version}</source>-->
<!--<target>${java.version}</target>-->
<!--编译后保持方法形参名称不变-->
<!--<compilerArgs>-->
<!--<arg>-parameters</arg>-->
<!--</compilerArgs>-->
<!--</configuration>-->
<!--</plugin>-->
<!-- 在打好的jar包中保留javadoc注释,实际会另外生成一个xxxxx-sources.jar -->
<!--<plugin>-->
<!--<groupId>org.apache.maven.plugins</groupId>-->
<!--<artifactId>maven-source-plugin</artifactId>-->
<!--<version>2.4</version>-->
<!--<executions>-->
<!--<execution>-->
<!--<id>attach-sources</id>-->
<!--<goals>-->
<!--<goal>jar</goal>-->
<!--</goals>-->
<!--</execution>-->
<!--</executions>-->
<!--</plugin>-->
</plugins>
</build>
4. 异常问题
(1) 网关gateway异常
<!-- 异常 There was an unexpected error (type=Service Unavailable, status=503). -->
服务模块未启动或客户端负载均衡loadbalancer
增加<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
(2) 组件nacos异常: [NACOS HTTP-POST] The maximum number of tolerable server reconnection errors
修改: application.yml -> bootstrap.yml
(3) 启动指令nohup java -jar XXX.jar & 系统内存不足时启动jar包提示内存不足异常,可修改-Xms500M -Xmx500M参数
(4) 异常Feign调用报错:No qualifying bean of type ‘org.springframework.boot.autoconfigure.http.HttpMessageConvert
修改注入bean HttpMessageConverters
@Bean
@ConditionalOnMissingBean
public HttpMessageConverters httpMessageConverters(ObjectProvider<HttpMessageConverter<?>> converters) {
return new HttpMessageConverters(converters.orderedStream().collect(Collectors.toList()));
}
5. 关于SPRINGBOOT事务注解
@Transactional(rollbackFor = Exception.class)
//多个函数调用只用外层使用事务注解,在内层函数的事务注解只控制内层以及内层内部调用的部分
@Transactional(rollbackFor = Exception.class)
private int fun1() throws Exception
{
fun2();
}
//@Transactional(rollbackFor = Exception.class)
private int fun2() throws Exception
{
}
6. 关于OPEN-FEIGN调用传header参数
/**
* Feign调用,携带header
*/
@Configuration
public class FeignConfig implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes == null) {return; }
HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
Enumeration<String> values = request.getHeaders(name);
while (values.hasMoreElements()) {
String value = values.nextElement();
template.header(name, value);
}
}
}
}
}
7. 关于MP-PLUS(版本3.4.2)字段填充
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
//this.strictInsertFill(metaObject, "id", Long.class, IdUtil.getId());
this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
this.strictInsertFill(metaObject, "createBy", Long.class, UserUtil.getUserId());
this.strictInsertFill(metaObject, "updateTime", Date.class, new Date());
this.strictInsertFill(metaObject, "updateBy", Long.class, UserUtil.getUserId());
this.strictInsertFill(metaObject, "deleted", Integer.class, 0);
//this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐)
// 或者
//this.strictUpdateFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
// 或者
//this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.strictInsertFill(metaObject, "updateTime", Date.class, new Date());
this.strictInsertFill(metaObject, "updateBy", Long.class, UserUtil.getUserId());
//this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐)
// 或者
//this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
// 或者
//this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
}
}
8. 传参与返回值时间格式转换
当前端传来的是键值对,用@DateTimeFormat 规定接收的时间格式。
当前端传来json串,后台用@ReuqestBody接收,必须用@JsonFormat 规定接收的时间格式。@ReuqestBody 如果不使用@JsonFormat 接收空格会自动转换成 T 导致时间转化错误
返回给前端的时间值,只能用@JsonFormat 规定返回格式 @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") private Date createTime;
@DateTimeFormat 无法决定返回值的格式。
@JsonFormat 是jackson提供。
@DateTimeFormat 由spring提供。
9. 参数校验
(1)在controller控制层参数校验
例public BaseResult<String> add(@RequestBody @Validated /*或@Valid*/ SysRequest sysRequest){} && 在SysRequest中的参数使用JSR-303校验注解
(2) 在service层校验
有不同方式
在ISysService或SysServiceImpl类的位置使用@Validated注解
&&在ISysService方法内的参数中使用@Valid注解或同时在ISysService与SysServiceImpl类方法内的参数中使用@Valid注解
&&在SysRequest中的参数使用JSR-303校验注解
例
@Validated
public class SysServiceImpl implements ISysService { }
public interface ISysService{
int add(@Valid SysRequest sysRequest);
}
(3) 分组参数校验