SpringCloud 服务间表单数据请求(若干文件+若干参数)
问题背景
我们的后端原始项目是一个单体应用(springboot+shiro+mybatis),后来改为分布式服务。想保留shiro的细粒度的接口访问权限的控制。所以架构方面是采用单点登录的架构模型。用户都会通过一个main-service主服务进入,首先进行接口访问权限的判断(主服务中有shiro),然后通过zuul网关进行一个请求的转发到其它服务。
着中间的问题是,所有的接口访问都是通过主服务进行访问的。也就是说前端数据都是请求的主服务的接口。有部分接口需要form表单传一些文件和参数,这里记录以下实现步骤。
依赖
让Feign支持表单传输,最后一个(feign-core)要注意版本,版本过低不支持文件传输
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form</artifactId>
<version>3.8.0</version>
</dependency>
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form-spring</artifactId>
<version>3.8.0</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<version>10.1.0</version>
</dependency>
配置文件(放在客户端服务)2个文件
FeignSpringFormEncoder 文件
import feign.RequestTemplate;
import feign.codec.EncodeException;
import feign.codec.Encoder;
import feign.form.ContentType;
import feign.form.FormEncoder;
import feign.form.MultipartFormContentProcessor;
import feign.form.spring.SpringManyMultipartFilesWriter;
import feign.form.spring.SpringSingleMultipartFileWriter;
import org.springframework.web.multipart.MultipartFile;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.Map;
public class FeignSpringFormEncoder extends FormEncoder {
public FeignSpringFormEncoder() {
this(new Default());
}
public FeignSpringFormEncoder(Encoder delegate) {
super(delegate);
MultipartFormContentProcessor processor = (MultipartFormContentProcessor)this.getContentProcessor(ContentType.MULTIPART);
processor.addFirstWriter(new SpringSingleMultipartFileWriter());
processor.addFirstWriter(new SpringManyMultipartFilesWriter());
}
public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
if (bodyType.equals(MultipartFile.class)) {
MultipartFile file = (MultipartFile) object;
Map<String, Object> data = Collections.singletonMap(file.getName(), object);
super.encode(data, MAP_STRING_WILDCARD, template);
return;
} else if (bodyType.equals(MultipartFile[].class)) {
MultipartFile[] file = (MultipartFile[]) object;
if(file != null) {
Map<String, Object> data = Collections.singletonMap(file.length==0?"":file[0].getName(), object);
super.encode(data, MAP_STRING_WILDCARD, template);
return;
}
}
super.encode(object, bodyType, template);
}
}
MultipartSupportConfig 文件
import feign.codec.Encoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public
class MultipartSupportConfig {
@Bean
public Encoder feignFormEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
return new FeignSpringFormEncoder(new SpringEncoder(messageConverters));
}
}
实体类和客户端的Controller、FeignClient
实体类(试卷类,里面有试卷信息和试卷文件和若干试题图片)
public class PaperForm implements Serializable {
private String modelId;
private String paperCode;
private String name;
private MultipartFile file;
private MultipartFile[] pictures;
private String subjectId;
private String subjectName;
private String pageDate;
private String description;
private String createId;
private String creator;
private Integer createType;
public String getPaperCode() {
return paperCode;
}
public void setPaperCode(String paperCode) {
this.paperCode = paperCode;
}
public MultipartFile[] getPictures() {
return pictures;
}
public void setPictures(MultipartFile[] pictures) {
this.pictures = pictures;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public MultipartFile getFile() {
return file;
}
public void setFile(MultipartFile file) {
this.file = file;
}
public String getSubjectId() {
return subjectId;
}
public void setSubjectId(String subjectId) {
this.subjectId = subjectId;
}
public String getSubjectName() {
return subjectName;
}
public void setSubjectName(String subjectName) {
this.subjectName = subjectName;
}
public String getPageDate() {
return pageDate;
}
public void setPageDate(String pageDate) {
this.pageDate = pageDate;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getCreateId() {
return createId;
}
public void setCreateId(String createId) {
this.createId = createId;
}
public String getCreator() {
return creator;
}
public void setCreator(String creator) {
this.creator = creator;
}
public String getModelId() {
return modelId;
}
public void setModelId(String modelId) {
this.modelId = modelId;
}
public Integer getCreateType() {
return createType;
}
public void setCreateType(Integer createType) {
this.createType = createType;
}
@Override
public String toString() {
return "PaperForm{" +
"modelId='" + modelId + '\'' +
", paperCode='" + paperCode + '\'' +
", name='" + name + '\'' +
", file=" + file +
", pictures=" + Arrays.toString(pictures) +
", subjectId='" + subjectId + '\'' +
", subjectName='" + subjectName + '\'' +
", pageDate='" + pageDate + '\'' +
", description='" + description + '\'' +
", createId='" + createId + '\'' +
", creator='" + creator + '\'' +
", createType=" + createType +
'}';
}
}
前端访问接口
@Controller
@RequestMapping("/paperFile")
public class FileUploadController {
@Autowired
PaperFileFeign paperFileFeign;
@ResponseBody
@PostMapping("/uploadPaper")
public Result uploadPaper(@RequestParam("modelId") String modelId,
@RequestParam("name") String name,
@RequestParam("file") MultipartFile file,
@RequestParam("pictures") MultipartFile[] pictures,
@RequestParam("subjectId") String subjectId,
@RequestParam("subjectName") String subjectName,
@RequestParam("pageDate") String pageDate,
@RequestParam("description") String description,
@RequestParam("createType") Integer createType){
//实体类 将表单请求转成json
PaperForm paperForm=new PaperForm();
paperForm.setModelId(modelId);
paperForm.setName(name);
paperForm.setFile(file);
paperForm.setPictures(pictures);
paperForm.setSubjectId(subjectId);
paperForm.setSubjectName(subjectName);
paperForm.setPageDate(pageDate);
paperForm.setDescription(description);
paperForm.setCreateType(createType);
//获取当前登录用户
User user = (User) SecurityUtils.getSubject().getPrincipal();
String createId =user.getId();
String creator =user.getCode();
paperForm.setCreateId(createId);
paperForm.setCreator(creator);
paperFileFeign.uploadPaper(paperForm);
//这里我直接返回的成功,要调试不要这样搞。服务端异常也会返回成功
return ResultUtil.createResult(200,"成功");
}
PaperFileFeign 通过feign进行请求转发。
import com.winfuture.config.MultipartSupportConfig;
import com.winfuture.data.Result;
import com.winfuture.model.bank.form.PaperForm;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PostMapping;
//配置支持文件传输,configuration = MultipartSupportConfig.class
@FeignClient(value = "zuul",configuration = MultipartSupportConfig.class)
@Service
public interface PaperFileFeign {
//配置支持文件传输 consumes = MediaType.MULTIPART_FORM_DATA_VALUE
@PostMapping(value = "/bank/paper/uploadPaper", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
Result uploadPaper(PaperForm paperForm);
}
服务端Controller
@Controller
@RequestMapping("/paper")
public class PapersController {
//service层 自己的业务
@Autowired
PapersService papersService;
/*上传试卷文件,管理员录入(基础题库,模拟题库)*/
@PostMapping(value = "uploadPaper",produces = MediaType.APPLICATION_JSON_UTF8_VALUE,
consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Result uploadPaper(PaperForm paperForm){
try {
String modelId = paperForm.getModelId();
String name = paperForm.getName();
MultipartFile file = paperForm.getFile();
MultipartFile[] pictures =paperForm.getPictures();
String subjectId=paperForm.getSubjectId();
String subjectName=paperForm.getSubjectName();
String pageDate = paperForm.getPageDate();
String description =paperForm.getDescription();
Integer createType = paperForm.getCreateType();
String createId =paperForm.getCreateId();
String creator =paperForm.getCreator();
papersService.uploadPaper(modelId,name,file,pictures,subjectId,subjectName,pageDate,description,createType,createId,creator);
return ResultUtil.createResult(200,"成功");
} catch (Exception e) {
e.printStackTrace();
return ResultUtil.createResult(400,"异常");
}
}
}
记录一下。