【问题记录】fastjson序列化MultipartFile接口入参导致的异常

目录

  • 一、异常场景复现
    • 1、maven
    • 2、java
      • 2-1、Java-aspect
      • 2-2、java-controller
    • 3、触发
  • 二、异常堆栈
  • 三、堆栈分析
  • 四、问题定位
  • 五、问题解决
    • 1、思路分析
    • 2、代码实现
      • 2-1、controller
      • 2-2、FileParam
  • 六、再次调用,无异常

一、异常场景复现

1、maven


<dependency>
    <groupId>com.fasterxml.jackson.jaxrsgroupId>
    <artifactId>jackson-jaxrs-json-providerartifactId>
    <version>2.13.3version>
dependency>

<dependency>
    <groupId>org.projectlombokgroupId>
    <artifactId>lombokartifactId>
    <version>1.18.24version>
    <scope>providedscope>
dependency>

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-aopartifactId>
    <version>2.6.2version>
dependency>

2、java

2-1、Java-aspect

package com.example.temp.apo;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Slf4j
public class LogAspect {

    @Pointcut("execution(public * com.example.temp.controller..*.*(..))")
    public void logPointCut() {
    }

    @Before("logPointCut()")
    public void doBefore(JoinPoint joinPoint) {
        log.info(" |---- 请求体: {}", JSON.toJSONString(joinPoint.getArgs()));
    }

    @After("logPointCut()")
    public void doAfter() {
    }

    @AfterThrowing(value = "logPointCut()", throwing = "e")
    public void afterThrowing(Throwable e) {
    }
}

2-2、java-controller

package com.example.temp.controller;

import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

@RestController
@RequestMapping("file")
public class FileController {
    @PostMapping(value = "/upload")
    public Object importLicense(@RequestParam("file") MultipartFile file) {
        if (file == null || file.isEmpty()) {
            return "上传文件不能为空";
        }
        return null;
    }
}

3、触发

【问题记录】fastjson序列化MultipartFile接口入参导致的异常_第1张图片

二、异常堆栈

2023-07-23 07:03:49.148 [traceId:]  ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] -175 -Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.alibaba.fastjson.JSONException: write javaBean error, fastjson version 1.2.83, class org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile, fieldName : 0, write javaBean error, fastjson version 1.2.83, class org.springframework.web.multipart.MultipartFileResource, fieldName : resource] with root cause
java.io.FileNotFoundException: MultipartFile resource [file] cannot be resolved to absolute file path
	at org.springframework.core.io.AbstractResource.getFile(AbstractResource.java:138)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.alibaba.fastjson.util.FieldInfo.get(FieldInfo.java:571)
	at com.alibaba.fastjson.serializer.FieldSerializer.getPropertyValueDirect(FieldSerializer.java:143)
	at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:284)
	at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:154)
	at com.alibaba.fastjson.serializer.FieldSerializer.writeValue(FieldSerializer.java:318)
	at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:472)
	at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:154)
	at com.alibaba.fastjson.serializer.JSONSerializer.writeWithFieldName(JSONSerializer.java:360)
	at com.alibaba.fastjson.serializer.JSONSerializer.writeWithFieldName(JSONSerializer.java:338)
	at com.alibaba.fastjson.serializer.ObjectArrayCodec.write(ObjectArrayCodec.java:118)
	at com.alibaba.fastjson.serializer.JSONSerializer.write(JSONSerializer.java:312)
	at com.alibaba.fastjson.JSON.toJSONString(JSON.java:793)
	at com.alibaba.fastjson.JSON.toJSONString(JSON.java:731)
	at com.alibaba.fastjson.JSON.toJSONString(JSON.java:688)
	at com.example.temp.apo.LogAspect.doBefore(LogAspect.java:20)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)

三、堆栈分析

  1. nested exception is com.alibaba.fastjson.JSONException: write javaBean error ,提示到fastjson序列化javaBean时出错,且后面提示class org.springframework.web.multipart.MultipartFileResource,指出MultipartFile相关。
  2. **at com.example.temp.apo.LogAspect.doBefore(LogAspect.java:20)**指明了异常所在代码位置,该行代码为:
log.info(" |---- 请求体: {}", JSON.toJSONString(joinPoint.getArgs()));

四、问题定位

基本可以断定,异常源自于JSON.toJSONString(joinPoint.getArgs()),该语句目的是为了打印接口参数信息,但【上传】接口的参数为MultipartFile file,导致fastjson序列化异常。

五、问题解决

1、思路分析

由于日志切面是公共切面,去除**JSON.toJSONString(joinPoint.getArgs())参数打印信息,属于因噎废食下下策,那么只能从【上传】文件接口入手了。
既然fastjson与MultipartFile不合,那么我们可以考虑将MultipartFile封装入一个Po对象中,并在MultipartFile属性字段上加上注解
@JSONField(serialize = false)**这样一来,对于日志切面而言,【上传】
接口的参数就不是MultipartFile,而是一个自定义的普通java对象,且MultipartFile不必序列化。

2、代码实现

2-1、controller

@PostMapping(value = "/upload")
    public Object importLicense(FileParam fileParam) {

        if (fileParam == null
                || fileParam.getFile() == null
                || fileParam.getFile().isEmpty()) {
            return "上传文件不能为空";
        }
        return null;
    }

2-2、FileParam

package com.example.temp.param;

import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import org.springframework.web.multipart.MultipartFile;

@Data
public class FileParam {
    @JSONField(serialize = false)
    private MultipartFile file;
    private String Context;
}

六、再次调用,无异常

你可能感兴趣的:(java,后端,前端,bug)