我試圖從Web客戶端上傳多部分表單數據到Spring MVC控制器。我搜索了「春天」實施以下的curl命令:如何使用客戶端上載多部分表單數據
curl -v -X POST -F "[email protected]" -F "id=12345" -F "name=Walmart" http://localhost:8080/api/cardprovider/logo
請注意:我不這樣做在一個HTML表單的形式上傳,這不是我想要達到的目標。
現在我的問題是:
- 你會使用Apache Commons的HttpClient這個在這個 blog的解釋呢?
- 或者是否有一個「春天」的魔法庫,將 幫我做到這一點?
我已經花了幾天的時間尋找使用Spring庫的解決方案,但所有Spring手冊中的例子都參考了HTML表單上傳,或者只有基本的文本纔是非常基本和簡單的。
Spring對我來說相當新穎,但裏面有這麼多優秀的庫,如果不會有Spring的人會想到讓它更容易上傳多部分數據(看起來像如果它將從表單發送)。
上述curl命令與下面的服務器端代碼成功合作:
控制器:
@Controller
@RequestMapping("/api/cardprovider/logo")
public class CardproviderLogoResourceController {
@Resource(name = "cardproviderLogoService")
private CardproviderLogoService cardproviderLogoService;
/**
* Used to upload a binary logo of a Cardprovider through a Multipart request. The id is provided as form element.
* <p/>
* Example to upload a file using curl:
* curl -v -X POST -F "[email protected]" -F "id=12345" -F "name=Walmart" http://localhost:8080/api/cardprovider/logo
* <p/>
*
* @param logo the Multipart request
* @param id the Cardprovider id
* @param name the Cardprovider name
*/
@RequestMapping(value = "", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.NO_CONTENT)
public void storeCardproviderLogo(@RequestParam(value = "logo", required = false) MultipartFile logo,
@RequestParam(value = "name") String name,
@RequestParam(value = "id") String id) throws IOException {
cardproviderLogoService.storeLogo(logo, id, name);
}
}
這裏是我的服務類存儲到一個GridFS的數據庫中的多部分請求:
服務:
@Service
public class CardproviderLogoService {
@Autowired
GridFsOperations gridOperation;
/**
* Create the logo in MongoDB GridFS with the data returned from the Multipart
* <p/>
*
* @param logo the MultipartFile content
* @param id the Cardprovider id
* @param name the Cardprovider name
* @return true if the image can be saved in the database, else false
*/
public Boolean storeLogo(MultipartFile logo, String id, String name) {
Boolean save_state = false;
BasicDBObject metadata = new BasicDBObject();
metadata.put("cardproviderId", id);
metadata.put("cardproviderName", name);
metadata.put("contentType", logo.getContentType());
metadata.put("fileName", createLogoFilename(name, logo.getOriginalFilename()));
metadata.put("originalFilename", logo.getOriginalFilename());
metadata.put("dirShortcut", "cardproviderLogo");
metadata.put("filePath", "/resources/images/cardproviders/logos/");
try {
gridOperation.store(logo.getInputStream(),
metadata.getString("fileName").toLowerCase().replace(" ", "-"),
metadata);
save_state = true;
} catch (Exception ex) {
Logger.getLogger(CardproviderLogoService.class.getName())
.log(Level.SEVERE, "Storage of Logo failed!", ex);
}
return save_state;
}
/**
* Creates the new filename before storing the file in MongoDB GridFS. The filename is created by taking the
* name of the Cardprovider, lowercase the name and replace the whitespaces with dashes. At last the file
* extension is added that was provided by the original filename.
* <p/>
*
* @param name the Cardprovider name
* @param originalFilename the original filename
* @return the new filename as String
*/
private String createLogoFilename(String name, String originalFilename) {
String cpName = name.toLowerCase().replace(" ", "-");
String extension = "";
int i = originalFilename.lastIndexOf('.');
if (i > 0 && i < originalFilename.length() - 1) {
extension = originalFilename.substring(i + 1).toLowerCase();
}
return cpName + "." + extension;
}
}
謝謝你UR幫助和親切的問候, 克里斯
解決方案
我可以解決這個問題下面的方式。我有我的HtmlController採用的形式輸入並建立一個連接到RestController傳輸文件。
這裏是HtmlController的方法:
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String addCardprovider(
@ModelAttribute("cardproviderAttribute") Cardprovider cardprovider,
Model model) {
// Prepare acceptable media type
List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>();
acceptableMediaTypes.add(MediaType.APPLICATION_XML);
// Prepare header
HttpHeaders headers = new HttpHeaders();
headers.setAccept(acceptableMediaTypes);
// Pass the new person and header
HttpEntity<Cardprovider> entity = new HttpEntity<Cardprovider>(
cardprovider, headers);
// Send the request as POST
try {
// Save Cardprovider details
ResponseEntity<Cardprovider> response = restTemplate.exchange(
"http://localhost:8080/api/cardprovider", HttpMethod.POST,
entity, Cardprovider.class);
// Save Cardprovider logo
String tempDir = System.getProperty("java.io.tmpdir");
File file = new File(tempDir + "/" + cardprovider.getLogo().getOriginalFilename());
cardprovider.getLogo().transferTo(file);
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
parts.add("id", response.getBody().getId());
parts.add("name", response.getBody().getName());
parts.add("logo", new FileSystemResource(file));
restTemplate.postForLocation("http://localhost:8080/api/cardprovider/logo", parts);
} catch (Exception e) {
e.printStackTrace();
}
// This will redirect to /web/cardprovider/getall
return "redirect:/web/cardprovider/getall";
}
嗨馬塞爾,謝謝您的回答。這是一個好消息。我認爲Spring會爲此提供解決方案。但它真的好像他們沒有。看起來Spring仍然缺乏針對JAX-RS(Jersey)的一些功能。將Jersey與Spring混合處理大數據量(如SAX解析大型XML文件)也很常見?我想盡可能少使用庫,但需要使用二進制傳輸和大文件解析的某些功能。 –
@ChristopherArmstrong,grrrh我錯過了最明顯的......我會更新我的答案。至於你在評論中的問題,這取決於。我之前的項目基於Spring WebMVC。因此,我們擁有JAX-RS所需的所有功能(不需要額外的JAX-RS庫)。在我目前的項目中,我們有GWT並提供了一個SOAP API。對於SOAP,我們使用也實現JAX-RS的CXF。因此,我們再次看到Jersey無需爲CXF構建我們的REST服務。 –
非常感謝您的回覆。我可以用春休來解決我的問題,但我也假設,在某些情況下,如果需要符合jsr 311或其他特殊需求,仍然需要或建議混合其他休息框架。從許可的角度來看,cxf爲球衣提供了更多的自由。但球衣有最好的文件。兩者都可以集成到春天。 –