前言
- JAX-RS:JAX-RS是可以用可以用于实现RESTFul应用程序的JAVA API,给开发者提供了一系列的RESTFul注解
- Jersey:是基于JAX-RX API的实现框架,用于实现RESTful Web 服务的开源框架。
JAX-RX常用的注解:
@javax.ws.rs.Path // 请求的资源类或资源方法的uri路径
@javax.ws.rs.GET //表示此方法响应HTTP GET请求。
@javax.ws.rs.POST // 表示此方法响应HTTP POST请求。
@javax.ws.rs.PUT // 通常用来更新数据,PUT操作
@javax.ws.rs.DELETE // 通常用来删除数据。
@javax.ws.rs.Produces //设置Http返回报文,报文体的内容类型
@javax.ws.rs.Consumes //客户端请求的MIME媒体类型
@javax.ws.rs.QueryParam // 一般是GET请求的参数,相当于SpringMVC框架的@RequestParam
@javax.ws.rs.FormParam // 媒体类型为”application/x-www-form-urlencoded” 的参数
@javax.ws.rs.PathParam // uri中指定的路径参数绑定到资源方法参数
开发环境
- SpringBoot2.2.1.RELEASE
- Jersey2.x
- JDK1.8
- Maven 3.2+
搭建一个SpringBoot项目
在IDEA里new一个project,这里使用Spring Initializer
快速创建一个SpringBoot项目,Server url可以使用Spring官网的,也可以使用阿里的,然后点击Next
选择jdk版本,还有使用maven做jar管理
选择需要的jar,选择之后,生成的项目会自动加上maven配置
如果是自己搭建的项目,可以自己加上spring-boot-starter-jersey
的maven配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
点击Next会生成一个SpringBoot项目,注意也可以加上lombok
和hutool
组件,方便开发项目
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.11</version>
</dependency>
加上jersey-media-multipart
,注意不要加上版本号,因为自己加的版本号可能会和spring-boot-starter-jersey
版本冲突,不加上版本号,通过SpringBoot的版本仲裁机制,自动加载对应版本的jar,加上jersey-media-multipart
依赖就可以使用@FormDataParam
注解,上传文件一般都是要form-data
方式
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
</dependency>
项目代码实现
简单加一个返回结果的枚举类,方便返回参数
package com.example.springbootjersey.common;
import lombok.Data;
import org.springframework.http.HttpStatus;
@Data
public class ResultBean<T> {
/**
* 状态
* */
private int status;
/**
* 描述
* */
private String desc;
/**
* 数据返回
* */
private T data;
public ResultBean(int status, String desc, T data) {
this.status = status;
this.desc = desc;
this.data = data;
}
public ResultBean(T data) {
this.status = HttpStatus.OK.value();
this.desc = "处理成功";
this.data = data;
}
public static <T> ResultBean<T> ok(T data) {
return new ResultBean(data);
}
public static <T> ResultBean<T> ok() {
return new ResultBean(null);
}
public static <T> ResultBean<T> badRequest(String desc,T data) {
return new ResultBean(HttpStatus.BAD_REQUEST.value(), desc, data);
}
public static <T> ResultBean<T> badRequest(String desc) {
return new ResultBean(HttpStatus.BAD_REQUEST.value(), desc, null);
}
public static <T> ResultBean serverError(String desc, T data){
return new ResultBean(HttpStatus.INTERNAL_SERVER_ERROR.value(),"服务器内部异常:"+desc,data);
}
public static <T> ResultBean serverError(String desc){
return new ResultBean(HttpStatus.INTERNAL_SERVER_ERROR.value(),"服务器内部异常:"+desc,null);
}
}
写一个文件上传的api接口
package com.example.springbootjersey.endpoint;
import com.example.springbootjersey.common.ResultBean;
import com.example.springbootjersey.entity.FileUploadResult;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import java.io.InputStream;
public interface IFileServerClient {
ResultBean<FileUploadResult> uploadFile(InputStream inputStream , FormDataContentDisposition fileDisposition);
}
在SpringBoot里封装的Jersey使用Endpoint
作为一个Resource
,在JAX-RS
项目里一般使用Resource
,SpringBoot使用Endpoint
,那项目也跟着命名,关键点,要先设置客户端传入的媒体类型,这里使用multipart/form-data
方式,加上注解@Consumes(MediaType.MULTIPART_FORM_DATA)
,@FormDataParam
定义传入的对象
package com.example.springbootjersey.endpoint;
import com.example.springbootjersey.common.ResultBean;
import com.example.springbootjersey.entity.FileUploadResult;
import com.example.springbootjersey.manager.FileUploadHandler;
import lombok.extern.slf4j.Slf4j;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.io.InputStream;
@Path("/api")
@Service
@Produces({MediaType.APPLICATION_JSON , MediaType.APPLICATION_XML})
@Slf4j
public class FileServerEndpoint implements IFileServerClient {
@Resource
private FileUploadHandler fileUploadHandler;
@POST
@Path("/v1/uploadFile")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Override
public ResultBean<FileUploadResult> uploadFile(@FormDataParam("file") InputStream inputStream,
@FormDataParam("file") FormDataContentDisposition fileDisposition) {
try {
FileUploadResult result = fileUploadHandler.fileUpload(inputStream ,fileDisposition);
return ResultBean.ok(result);
} catch (Exception e) {
log.error("exception:{}" , e);
return ResultBean.badRequest("error" , null);
}
}
}
具体的业务实现,拿到对应的InputStream
,就可以创建文件,注意这个文件大小不能从FormDataContentDisposition
直接拿,里面的getSize
方法拿到的是-1
,可能是bug,所以从File
里拿
package com.example.springbootjersey.manager;
import cn.hutool.core.io.FileUtil;
import com.example.springbootjersey.entity.FileUploadResult;
import lombok.extern.slf4j.Slf4j;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@Component
@Slf4j
public class FileUploadHandler {
public FileUploadResult fileUpload(InputStream inputStream , FormDataContentDisposition fileDisposition) throws IOException {
String fileName = fileDisposition.getFileName();
String fileType = fileName.substring(fileName.lastIndexOf("."));
File file = FileUtil.writeFromStream(inputStream, new File("D:/server/" + fileName));
long length = file.length();
log.info("fileName : [{}] , fileTye : [{}], size:[{}]" , fileName , fileType , length);
return FileUploadResult.builder()
.fileName(fileName)
.fileUrl(file.getPath())
.fileSize(length)
.fileType(fileType).build();
}
}
配置类,注意要加上MultiPartFeature
,也要注册,@ApplicationPath
是定义应用的根路径,默认是/*
package com.example.springbootjersey.configuration;
import com.example.springbootjersey.endpoint.FileServerEndpoint;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.context.annotation.Configuration;
import javax.ws.rs.ApplicationPath;
@Configuration
@ApplicationPath("/server")
public class JerseyConfig extends ResourceConfig{
public JerseyConfig() {
register(FileServerEndpoint.class);
register(MultiPartFeature.class);
}
}
写好代码,丢一个文件测试一下看看,在POST MAN
里测试,注意要form-data
方式