Java Spring hateoas xml序列化,用于使用ResourceAssemblerSupport构建的资源列表

Java Spring hateoas xml序列化,用于使用ResourceAssemblerSupport构建的资源列表,java,xml,spring-mvc,jaxb2,spring-hateoas,Java,Xml,Spring Mvc,Jaxb2,Spring Hateoas,我正在尝试为基于SpringHateOAS的应用程序支持XML响应。对于单个资源,JSON响应和XML一样工作良好。问题从资源列表开始。Spring MVC控制器无法序列化借助ResourceAssemblerSupport派生类生成的列表。控制器抛出org.springframework.web.HttpMediaTypeNotAcceptableException:找不到curl命令的可接受表示形式 curl -k -i -H "Accept:application/xml" -H "Med

我正在尝试为基于SpringHateOAS的应用程序支持XML响应。对于单个资源,JSON响应和XML一样工作良好。问题从资源列表开始。Spring MVC控制器无法序列化借助ResourceAssemblerSupport派生类生成的列表。控制器抛出org.springframework.web.HttpMediaTypeNotAcceptableException:找不到curl命令的可接受表示形式

curl -k -i -H "Accept:application/xml" -H "Media-Type:application/xml" -X GET http://127.0.0.1:8080/admin/roles*
我的HATEOAS资源是实体类的包装器:

@XmlRootElement
@XmlSeeAlso(RoleModel.class)
public class RoleResource  extends ResourceSupport {
    public RoleModel role;

}
控制器很简单:

@RequestMapping(method = RequestMethod.GET)
   public @ResponseBody HttpEntity<List<RoleResource>> getAllRoles() 
        throws ObjectAccessException, ObjectNotFoundException {
    List<RoleModel> resp = rolesManagement.getRoles();

    return new ResponseEntity<List<RoleResource>>(roleResourceAssembler.toResources(resp),
            HttpStatus.OK);
}
资源汇编程序类:

@Configuration
public class RoleResourceAssembler extends ResourceAssemblerSupport<RoleModel, RoleResource> {

public RoleResourceAssembler() {
    super(RolesRestController.class, RoleResource.class);
}

@Bean 
public RoleResourceAssembler roleResourceAssembler(){
   return new RoleResourceAssembler();
}

@Override
public RoleResource toResource(RoleModel role) {
    RoleResource res = instantiateResource(role); 
    res.role = role;
    try {
        res.add(linkTo(methodOn(RolesRestController.class).getRole(role.getRoleId())).withSelfRel());
    } catch (ObjectAccessException | ObjectNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return res;
}

}
当我避免ResourceAssemblerSupport并手动构建资源时,如下所示:

@XmlRootElement
@XmlSeeAlso(RoleModel.class)
public class RolesList {
    private List<Resource<RoleModel>> roles;

...
}
@RequestMapping(method = RequestMethod.GET)
public @ResponseBody HttpEntity<RolesList> getAllRoles() 
        throws ObjectAccessException, ObjectNotFoundException {
    List<RoleModel> resp = rolesManagement.getRoles();

    List<Resource<RoleModel>> roles =new ArrayList<>(); 
    for (RoleModel model: resp) {
        Resource<RoleModel> res =  new Resource<RoleModel>(model);
        res.add(linkTo(methodOn(RolesRestController.class).getRole(model.getRoleId())).withSelfRel());
        roles.add(res);
    }
    RolesList list = new RolesList();
    list.setRoles(roles);

    return new ResponseEntity<RolesList>(list,
            HttpStatus.OK);
}

XML序列化工作正常。我想我可以避免使用资源汇编程序并手动构建资源,但这会使代码不那么干净和模块化。我想知道是否仍然可以使用ResourceAssemblerSupport作为资源生成器,并以XML的形式返回资源列表

资源汇编器用于将一个pojo/实体/任何东西转换为一个hateoas资源。您正在尝试将列表转换为列表

如果你是一个装配工

public class RoleResourceAssembler extends ResourceAssemblerSupport<List<RoleModel>, RolesResource> {
而RoleResource是你想要的东西……它应该会起作用

不过,我建议您考虑使用PagedResourceAssembler,它获取一页内容,并使用汇编程序创建一页资源。页面可以是完整集合,也可以只是集合中的一个页面。下面是一个简单的类别:

public HttpEntity<PagedResources<CategoryResource>> categories(
    PagedResourcesAssembler<Category> pageAssembler,
    @PageableDefault(size = 50, page = 0) Pageable pageable
){

    Page<Category> shopByCategories = categoryService.findCategories(pageable);        

    PagedResources<CategoryResource> r = pageAssembler.toResource(shopByCategories,
            this.categoryAssembler);

    return new ResponseEntity<PagedResources<CategoryResource>>(r, HttpStatus.OK);
}

但是..我在jackson将PagedResources封送为XML时遇到了一些问题…对于JSON来说效果很好。

似乎有了ResourceAssemblerSupport,就不可能将HATEOAS资源列表封送为XML。原因是扩展ResourceAssemblerSupport的类的toResources方法返回的资源列表没有@XmlRootElement,JAXB无法封送它。我必须创建像这样的类

 @XmlRootElement
    public class Roles {    
    private List<RoleResource> roleResource;
    ....
}

@XmlRootElement
public class RoleResource  extends ResourceSupport {
    private RoleModel role;
    ...
}
并手动构建我的资源列表。当我尝试使用SpringHateOAS资源包装器时,也出现了同样的问题

Resource<RoleModel> resource = new Resource<>();

由于Spring的资源类没有使用@XmlRootElement注释,因此如果您的唯一要求是生成org.springframework.hateoas.Link和marshall作为XML的链接,REST控制器无法将其封送到XML,以下内容可能会有所帮助

将链接项添加到模型类

@XmlRootElement(name="Role")
public class Roles
{
   Link link;
   <your Roles content>
   ...
}
将基类包装在列表中,以提供支持XML封送的基类标记

@XmlRootElement(name="Roles")
public class RolesList
{
   private List<Roles> rolesList;
   ...
   <constructors>
   ...
   @XmlElement(name="Role")
   public List<Roles> getRolesList()
   {
      return rolesList;
   }

   <set/get/add methods>
}
控制器代码大致如下:

@RequestMapping(method = RequestMethod.GET)
public @ResponseBody HttpEntity<RolesList> getAllRoles() 
   throws ObjectAccessException, ObjectNotFoundException
{
   RolesList resp = new RolesList(rolesManagement.getRoles());
   for (Roles r: resp)
   {
       r.setLink(linkTo(methodOn(RolesRestController.class).getRole(model.getRoleId())).withSelfRel());
   }
   return new ResponseEntity<RolesList>(resp,HttpStatus.OK);
}

另一件奇怪的事情是,通过ResourceAssemblerSupport生成的单个资源被序列化为atom而不是普通XML:ResourceAssemblerSupport有两个方法:toResource和toResources。后者将Iterable作为参数并返回资源列表。我认为这是我应该使用的。你是对的。我错过了ResourceAssembler和ResourceAssembler支持的细微差别。返回一个资源列表感觉很奇怪,在我看来,返回一个嵌入其他资源的资源要好得多。那么,这解决了你的问题吗?还是这些类仍然没有正确封送?@willOEM不,我没有。问题不在于ResourceAssemblerSupport,而在于JAXB没有处理Java的列表,因为它没有用XmlRootElement注释。由于toResources of ResourceAssemblerSupport返回资源列表,JAXB无法封送它。我的解决方案是不使用ResourceAssemblerSupport,而是使用具有XMLRootElementThank的列表类手动构建资源。我得到了你的解决方案。仅供参考,我还发现XStream可以使用资源汇编程序正确封送资源和资源对象,而无需额外配置或注释,但它们仍然是atom格式的。@您是如何使用XStream获得atom的?对我来说,它可以分解为常规XML。根据规范,HATEOS XML应该是atom。