弹簧休息控制器不适用于文件上传

Posted

技术标签:

【中文标题】弹簧休息控制器不适用于文件上传【英文标题】:Spring rest controller not working for file upload 【发布时间】:2020-03-17 11:05:30 【问题描述】:

我用 mongodb 尝试了一个没有任何 View 的 rest api。我的应用程序在 Spring Boot 嵌入式服务器上运行良好,没有错误。使用独立的 tomcat 应用程序运行时没有错误,但无法访问 @RestController 映射的 url。它显示 404 页面未找到。它没有创建该 url,但其他 url 工作正常。

这里是配置

FileStorageProperties.java

@Component
public class FileStorageProperties 
    private static String baseDir = "E://temp//FileManager//";
    private String uploadDir = "";

    public String getUploadDir() 
        return baseDir + uploadDir;
    

    public void setUploadDir(String uploadDir) 
        this.uploadDir = baseDir + uploadDir;
    

MediaTypeUtils.java

public class MediaTypeUtils 

    // abc.zip
    // abc.pdf,..
    public static MediaType getMediaTypeForFileName(ServletContext servletContext, String fileName) 
        // application/pdf
        // application/xml
        // image/gif, ...
        String mineType = servletContext.getMimeType(fileName);
        try 
            MediaType mediaType = MediaType.parseMediaType(mineType);
            return mediaType;
         catch (Exception e) 
            return MediaType.APPLICATION_OCTET_STREAM;
        
    


这是模型

Avatar.java:

@Document
@Component
public class Avatar 
    @Id
//  @Indexed(unique = true)
    private String id;
    private String originalName;
    @Indexed(unique = true)
    private String generatedName;
    private String size;
    @DBRef
    private User user;

    public String getId() 
        return id;
    

    public void setId(String id) 
        this.id = id;
    

    public String getOriginalName() 
        return originalName;
    

    public void setOriginalName(String originalName) 
        this.originalName = originalName;
    

    public String getGeneratedName() 
        return generatedName;
    

    public void setGeneratedName(String generatedName) 
        this.generatedName = generatedName;
    

    public String getSize() 
        return size;
    

    public void setSize(String size) 
        this.size = size;
    

    public User getUser() 
        return user;
    

    public void setUser(User user) 
        this.user = user;
    

    @Override
    public String toString() 
        return "Avatar [id=" + id + ", originalName=" + originalName + ", generatedName=" + generatedName + ", size="
                + size + ", user=" + user + "]";
    



上传文件响应.java

public class UploadFileResponse 
    private String fileName;
    private String fileType;
    private long size;

    public String getFileName() 
        return fileName;
    

    public void setFileName(String fileName) 
        this.fileName = fileName;
    

    public String getFileType() 
        return fileType;
    

    public void setFileType(String fileType) 
        this.fileType = fileType;
    

    public long getSize() 
        return size;
    

    public void setSize(long size) 
        this.size = size;
    

    public UploadFileResponse(String fileName, String fileType, long size) 
        this.fileName = fileName;
        this.fileType = fileType;
        this.size = size;
    

FileStorageException.java

public class FileStorageException extends RuntimeException 
    /**
     * 
     */
    private static final long serialVersionUID = -2482390550398268830L;

    public FileStorageException(String message) 
        super(message);
    

    public FileStorageException(String message, Throwable cause) 
        super(message, cause);
    

MyFileNotFoundException.java

@ResponseStatus(HttpStatus.NOT_FOUND)
public class MyFileNotFoundException extends RuntimeException 
    /**
     * 
     */
    private static final long serialVersionUID = -7680896574598153059L;

    public MyFileNotFoundException(String message) 
        super(message);
    

    public MyFileNotFoundException(String message, Throwable cause) 
        super(message, cause);
    

现在存储库:

AvatarRepository.java

public interface AvatarRepository extends MongoRepository<Avatar, String>

    public Avatar findAvatarByGeneratedName(String generatedName);
    public Avatar findAvatarByUser(User user);


AvatarRepositopryImpl.java - 有一些重写的​​ MongoRepository 方法在以下代码中被忽略,因为它们根本没有使用。

@Repository
public class AvatarRepositopryImpl implements AvatarRepository 
    @Autowired
    MongoTemplate mongoTemplate;

    private static final String COLLECTION_NAME = "avatar";

    @Override
    public <S extends Avatar> List<S> saveAll(Iterable<S> entities) 
        // TODO Auto-generated method stub
        return null;
    

    @Override
    public List<Avatar> findAll() 
        return mongoTemplate.findAll(Avatar.class, COLLECTION_NAME);
    

    @Override
    public <S extends Avatar> S save(S entity) 
        return mongoTemplate.save(entity);
    

    @Override
    public void deleteById(String id) 
        mongoTemplate.remove(id);
    

    @Override
    public void delete(Avatar entity) 
        mongoTemplate.remove(entity);
    

    @Override
    public Avatar findAvatarByGeneratedName(String generatedName) 
        Query query = new Query();
        query.addCriteria(Criteria.where("generatedName").is(generatedName));
        return (Avatar) mongoTemplate.findOne(query, Avatar.class);
    

    @Override
    public Avatar findAvatarByUser(User user) 
//      System.out.println(user);
        Query query = new Query();
        query.addCriteria(Criteria.where("user").is(user));
        return (Avatar) mongoTemplate.find(query, Avatar.class);
    


这是我的服务:

AvatarService.java

@Service
public class AvatarService 

    @Autowired
    private Avatar avatar;
//
//  @Autowired
//  private FileStorageService fileStorageService;

    @Autowired
    AvatarRepository avatarRepository;

    /**
     * @param fileStorageService
     * @param avatarRepository
     */

    public Avatar findAvatarByGeneratedName(String generatedName) 
        return avatarRepository.findAvatarByGeneratedName(generatedName);
    

    public Avatar findAvatarByUser(User user) 
        System.out.println(user);
        return avatarRepository.findAvatarByUser(user);
    

    public Avatar saveAvatar(User user,String fileOriginalName, String fileNameToSave, String fileSize) 
        avatar.setId(UUID.randomUUID().toString());
        avatar.setOriginalName(fileOriginalName);
        avatar.setGeneratedName(fileNameToSave);
        avatar.setSize(fileSize);
        avatar.setUser(user);

        return avatarRepository.save(avatar);
    

    public void deleteAvatarByGeneratedName(String generatedName, Avatar avatar) 
        avatar = findAvatarByGeneratedName(generatedName);
        avatarRepository.deleteById(avatar.getId());
    

AvatarManager.java

public class AvatarManager 

    AvatarService avatarService;

    @Autowired
    Avatar avatar;

    public AvatarManager(AvatarService avatarService) 
        this.avatarService = avatarService;
    

    public String saveAvatar(User user, MultipartFile file) 
        deleteAvatarByUser(user);
        String[] ext = file.getOriginalFilename().split(Pattern.quote("."));
        String generatedName = new UUIDGenerator().generateId(avatar).toString() + "." + ext[ext.length - 1];
        avatarService.saveAvatar(user, file.getOriginalFilename(), generatedName, file.getSize() + "");
        new FileStorageService(new FileStorageProperties()).uploadFile(file, generatedName);
        new UploadFileResponse(generatedName, file.getContentType(), file.getSize());
        return generatedName;
    

    public void deleteAvatar(String generatedName) 
        Avatar avatar = avatarService.findAvatarByGeneratedName(generatedName);
        if (avatar != null) 
            new FileStorageService(new FileStorageProperties()).deleteFile(generatedName);
            avatarService.deleteAvatarByGeneratedName(generatedName, avatar);
        
    

    public void deleteAvatarByUser(User user) 
//      System.out.println(user);
        avatar = avatarService.findAvatarByUser(user);
//      System.out.println(avatar.getGeneratedName());
        if (avatar != null) 
            deleteAvatar(avatar.getGeneratedName());
        
    

    public ResponseEntity<Resource> downloadAvatar(String avatarGeneratedName, HttpServletRequest request) 
//      System.out.println(request);
        return new FileStorageService(new FileStorageProperties()).downloadFile(avatarGeneratedName, request);
    

现在的控制器。我给出了两个映射。第一个不涉及文件管理器。它适用于两台服务器。另一个是在 Spring Boot 嵌入式服务器上工作,但不在独立的 tomcat 上。它也没有显示任何错误或创建任何 url。

这里是Controller.java

@CrossOrigin(origins =  "*" )
@RestController
public class UserController 

    @Autowired
    EmployeeService employeeService;

    @Autowired
    UserService userService;

    @Autowired
    AvatarService avatarService;

    @Autowired
    BCryptPasswordEncoder passwordEncoder;

//It works on both server


@RequestMapping(value = "/login", method = RequestMethod.POST)
        public String loginEmployee(@RequestParam Map<String, String> data) 
            return new EmployeeManager(employeeService, userService)
                    .validateUserLogin(data.get("0").toString(), data.get("1"), passwordEncoder).toString();
        

    //It doesn't work with standalone server
        @RequestMapping(value = "/edit-employee-profile", method = RequestMethod.POST)
    public void editProfileEmployee(@RequestParam(value = "avatar", required = false) MultipartFile file,
            @RequestParam(value = "user") String data) 
        JSONParser jp = new JSONParser(data);
        System.out.println(jp);
        LinkedHashMap<String, Object> userInfo;
        try 
            userInfo = jp.parseObject();
            User user = userService.findUserByEmail(userInfo.get("email").toString());
            System.out.println(user);
            user.setAvatarExistance(true);
            userService.updateUser(user);
//      Employee employee = employeeService.findEmployeeByUser(user);
            System.out.println(data);
            new EmployeeManager(employeeService, userService).employeeProfileEdit(data);
            if (file != null) 
                System.out.println(file);
                new AvatarManager(avatarService).saveAvatar(user, file);
            
         catch (Exception e) 
            // TODO Auto-generated catch block
            e.printStackTrace();
        
//      return "";
    

【问题讨论】:

这听起来很明显,但导致 404 的 curl/postman 请求也很有用。 你还有其他spring的配置类吗? 对不起控制器错误。现在我已经编辑了这个问题。该项目在给定的链接上。 drive.google.com/open?id=1PjGVp-hu2lFGjThy4WTrSV47yIWbdp6C 您是否将文件内容作为请求参数(URL 的一部分)上传? 感谢大家的参与。我发现了控制器中异常处理的问题。如果我在控制器上进行异常处理,则不会创建该 url 映射,否则可以。 【参考方案1】:

将文件作为请求正文(而不是 URL 参数和@RequestParam)发布,以不超过safe maximum URL length:

@RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
public void uploadFile(ModelMap m, MultipartHttpServletRequest request) 

    MultiValueMap<String, MultipartFile> multiFileMap = request.getMultiFileMap();
    List<MultipartFile> files = multiFileMap.isEmpty() ? null : multiFileMap.values().iterator().next();
    MultipartFile file = files != null && !files.isEmpty() ? files.get(0) : null;

    // ...

【讨论】:

我想我在那里用过帖子。你可以再次修改。 :) 顺便说一句,感谢您的提醒。我应该避免 MultipartFile 文件的@RequestParam。 你是对的,当然,谢谢!查看修改后的答案

以上是关于弹簧休息控制器不适用于文件上传的主要内容,如果未能解决你的问题,请参考以下文章

验证不适用于引导文件上传

JQuery AJAX 上传文件不适用于超过 10 MB 的文件

Dropzone多个文件上传不适用于Excel文件

Jquery文件上传不适用于Select2

文件上传到 azure 文件共享不适用于更大的文件

PHP/jQuery S3 上传不适用于带空格的文件