【问题标题】:Defining a resource assembler for a REST Spring HATEOAS controller为 REST Spring HATEOAS 控制器定义资源组装器
【发布时间】:2013-11-07 08:40:31
【问题描述】:

我正在尝试将 HATEOAS 链接添加到由 Spring REST 控制器提供服务的 JSON 资源。

我知道我应该使用https://github.com/spring-projects/spring-hateoas 中描述的资源汇编器

该示例显示了一个 Person 类和一个 PersonResource 类。

我理解 PersonResource 类定义为:

public class PersonResource extends ResourceSupport {
}

那么 Person 类是什么?是数据域类吗?

在我的例子中,我定义了一个 Admin 类,它是一个 REST 域类,我指定它具有资源支持:

public class Admin extends ResourceSupport {

    private String firstname;
    private String lastname;
    private String email;
    private String login;
    private String password;
    private String passwordSalt;

    public Admin() {
    }

    public String getFirstname() {
        return this.firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public String getLastname() {
        return this.lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getLogin() {
        return this.login;
    }

    public void setLogin(String login) {
        this.login = login;
    }

    public String getPassword() {
        return this.password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getPasswordSalt() {
        return passwordSalt;
    }

    public void setPasswordSalt(String passwordSalt) {
        this.passwordSalt = passwordSalt;
    }

    public EventAdmin toEventAdmin() {
        EventAdmin eventAdmin = new EventAdmin();

        BeanUtils.copyProperties(this, eventAdmin);

        return eventAdmin;
    }

    public static Admin fromEventAdmin(EventAdmin eventAdmin) {
        Admin admin = new Admin();

        BeanUtils.copyProperties(eventAdmin, admin);

        return admin;
    }

}

我的 REST 控制器只看到这个 Admin 类,因为它是一个 REST 域类。它不知道也不应该知道任何数据域类。

所以我想知道如何在这里使用资源汇编器支持。

我不明白为什么我应该在这里有一个额外的数据域管理类。

亲切的问候,

按照 Mike 的回答,我的控制器现在看起来像这样:

@RequestMapping(method = RequestMethod.POST, produces = "application/json; charset=utf-8")
@ResponseBody
public ResponseEntity<Admin> add(@RequestBody Admin admin, UriComponentsBuilder builder) {
    AdminCreatedEvent adminCreatedEvent = adminService.add(new CreateAdminEvent(admin.toEventAdmin()));
    HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.add("Content-Type", "application/json; charset=utf-8");
    responseHeaders.setLocation(builder.path("/admin/{id}").buildAndExpand(adminCreatedEvent.getAdminId()).toUri());
    Admin createdAdmin = adminResourceAssembler.toResource(adminCreatedEvent.getEventAdmin());
    ResponseEntity<Admin> responseEntity = new ResponseEntity<Admin>(createdAdmin, responseHeaders, HttpStatus.CREATED);
    return responseEntity;
}

之前,我没有使用资源组装器,而是:

Admin createdAdmin = Admin.fromEventAdmin(adminCreatedEvent.getEventAdmin());
createdAdmin.add(linkTo(methodOn(AdminController.class).add(createdAdmin, builder)).withSelfRel());

但它没有给我 url 中的资源 ID。

【问题讨论】:

    标签: rest spring-hateoas


    【解决方案1】:

    您的ResourceAssembler 实现需要了解数据域类和 REST 域类,因为它的工作是将前者转换为后者。

    如果您想让控制器了解您的数据类,您可以创建一个资源转换服务,该服务将从存储库中检索数据并使用ResourceAssembler 将其转换为控制器可以了解的资源.

    @Component
    public class AdminResourceAssembler extends ResourceAssemblerSupport<Admin, AdminResource> {
        public AdminResourceAssembler() {
            super(AdminController.class, AdminResource.class);
        }
    
        public AdminResource toResource(Admin admin) {
            AdminResource adminResource = createResourceWithId(admin.getId(), admin); // adds a "self" link
            // TODO: copy properties from admin to adminResource
            return adminResource;
        }
    }
    
    @Service
    public class AdminResourceService {
        @Inject private AdminRepository adminRepository;
        @Inject private AdminResourceAssembler adminResourceAssembler;
    
        @Transactional
        public AdminResource findOne(Long adminId) {
            Admin admin = adminRepository.findOne(adminId);
            AdminResource adminResource = adminResourceAssembler.toResource(admin);
            return adminResource;
        }
    }
    
    @Controller
    @RequestMapping("/admins")
    public class AdminController {
        @Inject private AdminResourceService adminResourceService;
    
        @RequestMapping(value="/{adminId}", method=RequestMethod.GET)
        public HttpEntity<AdminResource> findOne(@PathVariable("adminId") Long adminId) {
            AdminResource adminResource = adminResourceService.findOne(adminId);
            return new ReponseEntity<>(adminResource, HttpStatus.OK);
        }
    }
    

    【讨论】:

    • 事实上,我也已经在尝试将我的数据域与 REST 域分离,使用事件作为与核心业务应用程序的通信端口。我想知道这是否不是矫枉过正。无论如何,它在我的控制器中可以正常工作: Admin createdAdmin = adminResourceAssembler.toResource(adminCreatedEvent.getEventAdmin());
    • 我现在想知道如何拥有子资源的链接。目前,在我的主资源中,管理资源没有链接,因为汇编器的 toResource 方法只提供了子主资源的链接。
    • Spring Data REST 可以做到这一点,PersistentEntityResourceAssembler 可能是开始了解该部分如何工作的好地方。
    • 服务类应该不知道 xxxResource,因为资源只是属于控制器层的表示方面。
    猜你喜欢
    • 2016-02-07
    • 2016-11-05
    • 2015-03-08
    • 2018-04-26
    • 1970-01-01
    • 2016-01-22
    • 1970-01-01
    • 2015-12-03
    • 2018-03-02
    相关资源
    最近更新 更多