You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular对接Spring Boot表单(无需传图片)保存报错的解决求助

问题描述

原本打算实现带图片的注册表单保存功能,Spring Boot REST API在Postman中可正常运行,但现在希望仅保存数据而不上传图片,Angular端对接时出现以下报错:

  • POST http://localhost:8080/patient/post 400 (Bad Request)
  • Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'image' is not present]

相关代码

Spring Controller类

@RestController
@RequestMapping("/patient/")
@CrossOrigin(origins = "http://localhost:4200", allowCredentials = "true")

public class PatientRegistrationController {
    @Autowired
    PatientRegistrationService registrationService;
    
    
       static String path = "F:\\patientPhoto\\"; 
    
    @PostMapping("post")
    
    @RequestParam.
    
     public void createPatient(@RequestParam("patInfo") String patInfo, @RequestParam("image") MultipartFile image)  {
        
        String fullPath =  path+image.getOriginalFilename();
        
        
         
        PatientRegistrationEntity patient = objectMapperReadValue(patInfo,PatientRegistrationEntity.class);
        
          
        
            try {
                
                image.transferTo(new File(fullPath)); //save to pc hdd
                
            } catch (IllegalStateException e) {
                 
                e.printStackTrace();
            } catch (IOException e) {
                 
                e.printStackTrace();
            }
    
        patient.setPatinetPhotoPaht(fullPath); //save path name to database
        
     registrationService.savepatient(patient);

       
   } }

Angular Service类

export class PatientServiceService {
private api = "http://localhost:8080";

  constructor(private http: HttpClient) { }

  public getpatinetList(): Observable<patientIface[]>{
    return this.http.get<patientIface[]>(`${this.api}/patient/post`);
  }

  private _refreshNeeds = new Subject<void>();

  get refreshNeeds(){
    return this._refreshNeeds;
  }

  public addPatient(patientRegistration: patientIface, image:File): Observable<patientIface>{
    const patInfo = JSON.stringify(patientRegistration); 
    console.log(typeof patInfo);

    const formData = new FormData();
    formData.append('patInfo', patInfo);
    formData.append('image', image);
    
    return this.http.post<patientIface>(`${this.api}/patient/post`, formData).pipe(
      tap( () => {
        this._refreshNeeds.next();
      }
      )
    );
  }

组件代码

createpatient() {
    // console.log(this.patientForm.value.dateOfBirth.toLocaleDateString());
    
    
    this.patientForm.value.dateOfBirth = this.patientForm.value.dateOfBirth?.toLocaleDateString(); 

    console.log("this.patientForm.value", this.patientForm.value);

    const imageFile = this.patientForm.value.patientImage;
    this.patientService.addPatient(this.patientForm.value,  imageFile).subscribe(
      (data: patientIface) => {
        console.log("data", data);
        this.router.navigate(["patient-table"])
      }
    );
  }
解决方案

问题核心是Spring后端将image参数设为必填,同时前端无论是否有图片都会传递该参数,导致无图片时触发错误。需前后端同步修改:

1. Spring Boot后端修改

调整请求参数为可选

将@RequestParam("image") MultipartFile image改为@RequestParam(value = "image", required = false) MultipartFile image,让图片参数变为非必填。

适配无图片的业务逻辑

仅当图片存在且非空时,执行文件保存和路径设置;无图片时直接跳过图片处理逻辑。

修改后的Controller代码:

@RestController
@RequestMapping("/patient/")
@CrossOrigin(origins = "http://localhost:4200", allowCredentials = "true")
public class PatientRegistrationController {
    @Autowired
    PatientRegistrationService registrationService;
    
    @Autowired
    private ObjectMapper objectMapper; // 补充注入ObjectMapper,修复原代码的方法调用错误
    
    static String path = "F:\\patientPhoto\\"; 
    
    @PostMapping("post")
    public void createPatient(@RequestParam("patInfo") String patInfo, 
                              @RequestParam(value = "image", required = false) MultipartFile image)  {
        
        // 解析患者信息
        PatientRegistrationEntity patient = objectMapper.readValue(patInfo, PatientRegistrationEntity.class);
        
        // 仅当图片存在且非空时处理
        if (image != null && !image.isEmpty()) {
            String fullPath = path + image.getOriginalFilename();
            try {
                image.transferTo(new File(fullPath)); // 保存图片到本地
            } catch (IllegalStateException | IOException e) {
                e.printStackTrace();
            }
            patient.setPatinetPhotoPaht(fullPath); // 保存图片路径到数据库
        } else {
            // 无图片时设置路径为null或空字符串,根据业务需求调整
            patient.setPatinetPhotoPaht(null);
        }
        
        registrationService.savepatient(patient);
    }
}

2. Angular前端修改

允许图片参数为空

修改addPatient方法,仅当图片存在时才将其添加到FormData中:

public addPatient(patientRegistration: patientIface, image?: File): Observable<patientIface>{
    const patInfo = JSON.stringify(patientRegistration); 

    const formData = new FormData();
    formData.append('patInfo', patInfo);
    
    // 仅当图片存在且大小大于0时添加到表单
    if (image && image.size > 0) {
        formData.append('image', image);
    }
    
    return this.http.post<patientIface>(`${this.api}/patient/post`, formData).pipe(
      tap( () => {
        this._refreshNeeds.next();
      }
      )
    );
}

组件中处理无图片场景

确保未选择图片时传递的参数为undefined,避免传递空文件对象:

createpatient() {
    this.patientForm.value.dateOfBirth = this.patientForm.value.dateOfBirth?.toLocaleDateString(); 

    console.log("this.patientForm.value", this.patientForm.value);

    // 无图片时传递undefined
    const imageFile = this.patientForm.value.patientImage ? this.patientForm.value.patientImage : undefined;
    this.patientService.addPatient(this.patientForm.value, imageFile).subscribe(
      (data: patientIface) => {
        console.log("data", data);
        this.router.navigate(["patient-table"])
      }
    );
}

内容的提问来源于stack exchange,提问作者Mahadi Hasan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 02:02:09