2013-02-07 26 views
0

我試圖從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"; 
} 

回答

0

沒有在春天,我知道的。使用Apache Commons HttpClient進行這些任務在我的圈子中是很常見的做法。

更新

當然Spring提供的支持 - 對不起,我忽略了最明顯的:RestTemplate

XML:

<bean id="restTemplate" class="org.springframework.web.client.RestTemplate"> 
<property name="messageConverters"> 
    <list> 
    <bean class="org.springframework.http.converter.StringHttpMessageConverter" /> 
    <bean class="org.springframework.http.converter.FormHttpMessageConverter" /> 
    </list> 
</property> 
</bean> 

的Java:

MultiValueMap<String, Object> form = new LinkedMultiValueMap<String, Object>(); 
form.add("key", value); 
... 
form.add("file", new FileSystemResource(file)); 
restTemplate.postForLocation(url, form); 
+0

嗨馬塞爾,謝謝您的回答。這是一個好消息。我認爲Spring會爲此提供解決方案。但它真的好像他們沒有。看起來Spring仍然缺乏針對JAX-RS(Jersey)的一些功能。將Jersey與Spring混合處理大數據量(如SAX解析大型XML文件)也很常見?我想盡可能少使用庫,但需要使用二進制傳輸和大文件解析的某些功能。 –

+0

@ChristopherArmstrong,grrrh我錯過了最明顯的......我會更新我的答案。至於你在評論中的問題,這取決於。我之前的項目基於Spring WebMVC。因此,我們擁有JAX-RS所需的所有功能(不需要額外的JAX-RS庫)。在我目前的項目中,我們有GWT並提供了一個SOAP API。對於SOAP,我們使用也實現JAX-RS的CXF。因此,我們再次看到Jersey無需爲CXF構建我們的REST服務。 –

+0

非常感謝您的回覆。我可以用春休來解決我的問題,但我也假設,在某些情況下,如果需要符合jsr 311或其他特殊需求,仍然需要或建議混合其他休息框架。從許可的角度來看,cxf爲球衣提供了更多的自由。但球衣有最好的文件。兩者都可以集成到春天。 –

相關問題