如何将 marshaller 对象写入 httpresponse 对象并将其下载为 xml 文件

how to write marshaller object to httpresponse object and download it as xml file

我正在尝试使用 JaxB 从我的数据 class 创建一个 xml 文件并下载它。

我已经从 java 对象创建了 marshaller 对象。但是我无法 return 这个对象作为 xml 文件。当我点击该方法时,我得到一个空的 xml 文件已下载。我是File IO编码的新手,请在这方面帮助我。

以下是我的控制器方法

import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class MyController{

@RequestMapping(value = PRODUCT_CODE_PATH_VARIABLE_PATTERN, method = RequestMethod.GET)
public void downloadProduct(@PathVariable("productCode") @NotNull final String productCode, final HttpServletRequest request, final HttpServletResponse response) throws Exception
    {
        response.setContentType("application/xml");
        response.setHeader("Content-Disposition", "attachment; filename=" + productCode + ".xml");
        final ProductDataJaxb productDataJaxb = getProductJaxObj(productCode);
        final JAXBContext jaxbContext = JAXBContext.newInstance(ProductDataJaxb.class);
        final Marshaller marshaller = jaxbContext.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        final OutputStream outputStream = new FileOutputStream(productCode + ".xml");
        marshaller.marshal(productDataJaxb, outputStream);

    }
}

我的数据 class 其 xml 表示是我在下载的 xml 文件中想要的。

import java.util.List;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;


@XmlRootElement(name = "Product")
@XmlType(propOrder ={ "code", "categories", "description" })
public class ProductDataJaxb
{

    private String code;
    private String description;
    private List<String> categories;

    /**
     * @return the code
     */
    @XmlElement
    public String getCode()
    {
        return code;
    }

    /**
     * @param code
     *           the code to set
     */
    public void setCode(final String code)
    {
        this.code = code;
    }

    /**
     * @return the description
     */
    @XmlElement
    public String getDescription()
    {
        return description;
    }

    /**
     * @param description
     *           the description to set
     */
    public void setDescription(final String description)
    {
        this.description = description;
    }

    /**
     * @return the categories
     */
    @XmlElement
    public List<String> getCategories()
    {
        return categories;
    }

    /**
     * @param categories
     *           the categories to set
     */
    public void setCategories(final List<String> categories)
    {
        this.categories = categories;
    }

  }

在您的 downloadProduct 方法中,您应该 add/change/remove 一些事情:

  • 将 return-type 更改为 ProductDataJaxb
  • 添加@ResponseBody注解表示return-value 应该进入 HTTP 响应
  • @RequestMapping注解中指定输出media-type"application/xml"以指示在HTTP响应
  • 中应该设置哪个Content-Type
  • 删除所有 JAXB 编组内容,因为 Spring 会为您完成。
  • 您不再需要 HttpServletRequestHttpServletResponse 方法参数

您的方法将如下所示:

@RequestMapping(value = PRODUCT_CODE_PATH_VARIABLE_PATTERN,
        method = RequestMethod.GET,
        produces = "application/xml")
@ResponseBody
public ProductDataJaxb downloadProduct(@PathVariable("productCode") @NotNull final String productCode) throws Exception
{
    final ProductDataJaxb productDataJaxb = getProductJaxObj(productCode);
    return productDataJaxb;
}

经过反复试验,我得到了如下解决方案来实现我的要求。

@RequestMapping(value = PRODUCT_CODE_PATH_VARIABLE_PATTERN, method = RequestMethod.GET)
public void downloadProduct(@PathVariable("productCode") @NotNull final String productCode, final HttpServletRequest request,
        final HttpServletResponse response) throws Exception
{
    response.setContentType("application/xml");
    response.setHeader("Content-Disposition", "attachment; filename=" + productCode + ".xml");
    final ProductDataJaxb productDataJaxb = getProductJaxObj(productCode);
    final JAXBContext jaxbContext = JAXBContext.newInstance(ProductDataJaxb.class);
    final Marshaller marshaller = jaxbContext.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
    marshaller.marshal(productDataJaxb, response.getOutputStream());

}

我只需将 HttpResponse 对象的输出 Stream 对象传递给 marshal 方法即可完成此操作。天哪!我现在真的需要学习 IO 概念.... :)