0

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

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 返回

4

3 回答 3

0

资源组装器用于将一个 pojo/entity/whatever 转换为 1 个 hatoas 资源。您正在尝试将列表转换为列表。

如果你的汇编程序是

public class RoleResourceAssembler extends ResourceAssemblerSupport<List<RoleModel>, RolesResource> {

RolesResource 是您想要的……它应该可以工作。

但是,我建议您考虑使用 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);
}

但是..杰克逊将 PagedResources 编组为 XML 时遇到了一些问题...对于 JSON 来说效果很好。

于 2014-08-18T17:09:33.570 回答
0

似乎使用 ResourceAssemblerSupport 不可能将 HATEOAS 资源列表编组为 XML。原因是扩展 ResourceAssemblerSupport 的类的 toResources() 方法返回的资源列表没有 @XmlRootElement 并且 JAXB 无法编组它。我必须创建类

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

@XmlRootElement
public class RoleResource  extends ResourceSupport {
    private RoleModel role;
    ...
}

并手动构建我的资源列表。当我尝试使用 Spring HATEOAS 资源包装器时出现同样的问题

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

由于 Spring 的 Resource 类未使用 @XmlRootElement 注释,因此 REST 控制器无法将其编组为 XML

于 2014-08-29T13:13:41.133 回答
0

如果您唯一的要求是使用 org.springframework.hateoas.Link 生成链接并将其编组为 XML,那么以下内容可能会有所帮助。

将 Link 项目添加到您的模型类。

@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);
}
于 2015-03-03T17:32:54.967 回答