Java技术栈版本选择

Java相关技术选择

组件名称 版本 说明
Java 1.8.0_212 elasticsearch依赖最低版本1.8.0_131
springboot2至少依赖1.8
Spring Boot 2.1.5.RELEASE feign多文件需要简单配置
Servlet 容器 tomcat 忠宇反馈评审人员对于不熟悉的undertow持否定态度,采用springboot自带的tomcat
Elasticsearch 6.3.2 采用restclient代替transportclient,根据需要再开发2.4相关版本
数据库 PostgreSQL(11.4)
持久层框架 MyBatis(3.5.1) mybatis-spring-boot-starter(2.0.1)内部mybatis就是3.5.1
swagger 2.7.0 从2.8.0之后版本ui不好用
参数校验 javax.validation 统一异常处理
统一异常处理 分层处理 需要自己封装
统一返回数据对象 需要自己封装
工具类 commons-lang3
commons-collections4
commons-io
http(okhttp)
json(jackson)
日期操作
需要自己封装

版本详情

Java

官方当前1.8最新稳定版 Java SE Development Kit 8u212

最低要求版本1.8.0_131(elasticsearch6.0官方要求的最低版本)

Spring Boot

最新稳定版 2.1.5.RELEASE

之前项目中使用springboot 如果需要使用feign的文件上传需要配置的地方比较多
2.0以后feign采用openfeign,不需要配置,只有在多文件上传时需要简单配置

class MultipartSupportConfig {

    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;

    @Bean
    public Encoder feignEncoder() {
        return new SpringMultipartEncoder(new SpringEncoder(messageConverters));
    }
}

class SpringMultipartEncoder extends SpringFormEncoder {

    public SpringMultipartEncoder() {
        this(new Default());
    }

    public SpringMultipartEncoder(Encoder delegate) {
        super(delegate);
        MultipartFormContentProcessor processor = (MultipartFormContentProcessor) getContentProcessor(ContentType.MULTIPART);
        processor.addWriter(new SpringSingleMultipartFileWriter());
        processor.addWriter(new SpringManyMultipartFilesWriter());
    }

    @Override
    public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
        if (bodyType.equals(MultipartFile.class)) {
            // 单MultipartFile判断
            MultipartFile file = (MultipartFile) object;
            Map data = singletonMap(file.getName(), object);
            super.encode(data, MAP_STRING_WILDCARD, template);
            return;
        } else if (bodyType.equals(MultipartFile[].class)) {
            // MultipartFile数组处理
            MultipartFile[] file = (MultipartFile[]) object;
            if (file != null) {
                Map data = singletonMap(file.length == 0 ? "" : file[0].getName(), object);
                super.encode(data, MAP_STRING_WILDCARD, template);
                return;
            }
        }
        // 其他类型调用父类默认处理方法
        super.encode(object, bodyType, template);
    }
}

文件上传的feign配置

@FeignClient(name = "file", url = "http://127.0.0.1:8080", configuration = FileFeign.MultipartSupportConfig.class)

Servlet容器

使用springboot自带的tomcat

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

使用统一异常处理捕获文件大小异常

配置文件上传大小为10M示例

application.yml

server:
  # 该配置项可以在统一异常处理中捕获上传文件大小异常
  tomcat:
    max-swallow-size: -1
spring:
  servlet:
    multipart:
      max-file-size: 10MB

统一异常处理

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MaxUploadSizeExceededException.class)
    @ResponseStatus(value = HttpStatus.PAYLOAD_TOO_LARGE)
    public String handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) {
        return e.getMessage();
    }

}

上面的方法只能处理单文件的异常,对于多文件上传,一个表单项上传多文件的情况,如果是每个文件不过超过10MB,那么选择两个6MB的同样会报错,可以采用如下配置

@SpringBootApplication(exclude = MultipartAutoConfiguration.class)

在启动类上排除MultipartAutoConfiguration,使用自定义的MultipartResolver

@Value("${spring.servlet.multipart.max-file-size:1MB}")
private String maxFileSize;

@Bean(name = "multipartResolver")
@Primary
public MultipartResolver multipartResolver() {
    log.info("maxUploadSize {}", maxFileSize);
    long maxSize = DataSize.parse(maxFileSize).toBytes();
    CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
    multipartResolver.setDefaultEncoding("utf-8");
    multipartResolver.setMaxUploadSizePerFile(maxSize);
    return multipartResolver;
}

Elasticsearch

使用6.3.2作为开发版本

采用RestHighLevelClient操作

依赖

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>6.3.2</version>
</dependency>

示例

RestHighLevelClient client = new RestHighLevelClient(
    RestClient.builder(
            new HttpHost("localhost", 9200, "http"),
            new HttpHost("localhost", 9201, "http")));

创建索引
client.indices().create(request);
删除索引
client.indices().delete(request);
查询数据
client.search(request);

数据库

PostgreSQL 11.4

持久层框架

MyBatis 3.5.1

mybatis-spring-boot-starter(2.0.1)内部mybatis就是3.5.1

swagger

从2.8.0开始界面变化太大,操作不方便,使用2.7.0

依赖

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>${swagger.version}</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>${swagger.version}</version>
</dependency>

参数校验

比如参数不能为空,一些正则的校验

@NotEmpty(message = "手机号不能为空")
@Pattern(regexp = "^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$", message = "手机号格式不对")
private String telephone;

示例

请求对象
@Data
public class ParamVo {
    @NotEmpty(message = "用户名不能为空")
    private String username;
    @NotEmpty(message = "手机号不能为空")
    @Pattern(regexp = "^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$", message = "手机号格式不对")
    private String telephone;
}

请求controller
@ApiOperation(value = "参数校验")
@PostMapping("/paramValidate")
public ParamVo paramValidate(@RequestBody @Valid ParamVo paramVo) {
    return paramVo;
}

统一异常处理
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ResponseBody
public String handleBindException(MethodArgumentNotValidException e) {
    // log.error("参数校验异常:{}", e);
    StringBuilder errorStr = new StringBuilder();
    e.getBindingResult().getAllErrors().
            forEach(x -> errorStr.append(x.getDefaultMessage() + ","));
    String message = errorStr.substring(0, errorStr.length() - 1);
    // message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
    return message;
}