弹簧休息控制器不适用于文件上传
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。 你是对的,当然,谢谢!查看修改后的答案以上是关于弹簧休息控制器不适用于文件上传的主要内容,如果未能解决你的问题,请参考以下文章