使用Spring Data REST公开枚举

时间:2017-06-29 15:35:04

标签: spring rest spring-mvc spring-data-rest

我正在使用Spring Boot 1.5.3,Spring Data REST,HATEOAS。 我有一个简单的实体模型:

@Entity
public class User extends AbstractEntity implements UserDetails {
private static final long serialVersionUID = 5745401123028683585L;
public static final PasswordEncoder PASSWORD_ENCODER = new BCryptPasswordEncoder();
@NotNull(message = "The name of the user cannot be blank")
@Column(nullable = false)
private String name;

/** CONTACT INFORMATION **/
private String landlinePhone;

private String mobilePhone;

@NotNull(message = "The username cannot be blank")
@Column(nullable = false, unique = true)
private String username;

@Email(message = "The email address is not valid")
private String email;

@JsonIgnore
private String password;

@Column(nullable = false)
private String timeZone = "Europe/Rome";

@JsonIgnore
private LocalDateTime lastPasswordResetDate;

@Column(nullable = false, columnDefinition = "BOOLEAN default true")
private boolean enabled = true;

@Type(type = "json")
@Column(columnDefinition = "json")
private Roles[] roles = new Roles[] {};

我的枚举角色是:

public enum Roles {
ROLE_ADMIN, ROLE_USER, ROLE_MANAGER, ROLE_TECH;

@JsonCreator
public static Roles create(String value) {
    if (value == null) {
        throw new IllegalArgumentException();
    }
    for (Roles v : values()) {
        if (value.equals(v.toString())) {
            return v;
        }
    }
    throw new IllegalArgumentException();
}
}

我正在Angular 4中创建一个客户端.Spring Data REST很棒,暴露存储库很容易返回我的模型HATEOAS:

    {
  "_embedded": {
    "users": [
      {
        "name": "Administrator",
        "username": "admin",
        "roles": [
          "Amministratore"
        ],
        "activeWorkSession": "",
        "_links": {
          "self": {
            "href": "http://localhost:8080/api/v1/users/1"
          },
          "user": {
            "href": "http://localhost:8080/api/v1/users/1{?projection}",
            "templated": true
          }
        }
      },

就像你可以看到我也通过rest-messages.properties翻译我的枚举值。大! 我的Angular页面现在需要完整的角色列表(枚举)。我有一些问题:

  • 了解服务器返回角色列表的更好方法
  • 如何返回此列表

我的第一个尝试是创建一个RepositoryRestController,以便利用Spring Data REST提供的功能。

@RepositoryRestController
@RequestMapping(path = "/api/v1")

public class UserController {

@Autowired
private EntityLinks entityLinks;

@RequestMapping(method = RequestMethod.GET, path = "/users/roles", produces = "application/json")
public Resource<Roles> findRoles() {
    Resource<Roles> resource = new Resource<>(Roles.ROLE_ADMIN);
    return resource;
}

不幸的是,由于某种原因,对此方法的调用会返回404错误。我调试了并且资源是正确创建的,所以我猜问题是在JSON转换中的某个地方。

2 个答案:

答案 0 :(得分:2)

  

如何返回此列表?

@RepositoryRestController
@RequestMapping("/roles")
public class RoleController {

    @GetMapping
    public ResponseEntity<?> getAllRoles() {
        List<Resource<Roles>> content = new ArrayList<>();
        content.addAll(Arrays.asList(
                new Resource<>(Roles.ROLE1 /*, Optional Links */),
                new Resource<>(Roles.ROLE2 /*, Optional Links */)));
        return ResponseEntity.ok(new Resources<>(content /*, Optional Links */));
    }
}

答案 1 :(得分:0)

我正在玩这个并找到了几种方法。

假设您有一个前端表单,希望显示一个包含单个Todo优先级的组合框,例如High, Medium, Low。表单需要知道primary key or id这个实例中的枚举值,值应该是组合框应该显示的可读格式化值。

如果您希望仅在一个位置自定义json响应,例如单个端点,那么我发现这很有用。秘诀就是使用值对象PriorityValue来允许您通过@Relation重命名json字段。

public enum Priority {
    HIGH("High"),
    NORMAL("Normal"),
    LOW("Low");

    private final String description;

    Priority(String description) {
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

    public static List<Priority> orderedValues = new ArrayList<>();

    static {
        orderedValues.addAll(Arrays.asList(Priority.values()));
    }
}


@RepositoryRestController
@RequestMapping(value="/")
public class PriorityController {

    @Relation(collectionRelation = "priorities")
    @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
    private class PriorityValue {
        private String id;
        private String value;

        public PriorityValue(String id,
                             String value) {
            this.id = id;
            this.value = value;
        }
    }

    @GetMapping(value = "/api/priorities", produces = MediaTypes.HAL_JSON_VALUE)
    public ResponseEntity<Resources<PriorityValue>> getPriorities() {
        List<PriorityValue> priorities = Priority.orderedValues.stream()
                .map(p -> new PriorityValue(p.name(), p.getDescription()))
                .collect(Collectors.toList());

        Resources<PriorityValue> resources = new Resources<>(priorities);
  resources.add(linkTo(methodOn(PriorityController.class).getPriorities()).withSelfRel());    
        return ResponseEntity.ok(resources);
    }

}

另一种方法是使用自定义JsonSerializer。使用它的唯一问题是在序列化优先级枚举的任何地方,您最终将使用这种格式,这可能不是您想要的。

@JsonSerialize(using = PrioritySerializer.class)
@Relation(collectionRelation = "priorities")
public enum Priority {
    HIGH("High"),
    NORMAL("Normal"),
    LOW("Low");

    private final String description;

    Priority(String description) {
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

    public static List<Priority> orderedValues = new ArrayList<>();

    static {
        orderedValues.addAll(Arrays.asList(Priority.values()));
    }
}


@RepositoryRestController
@RequestMapping(value="/api")
public class PriorityController {

    @GetMapping(value = "/priorities", produces = MediaTypes.HAL_JSON_VALUE)
    public ResponseEntity<Resources<Priority>> getPriorities() {
        Resources<Priority> resources = new Resources<>(Priority.orderedValues);

        resources.add(linkTo(methodOn(PriorityController.class).getPriorities()).withSelfRel());

        return ResponseEntity.ok(resources);
    }
}


public class PrioritySerializer extends JsonSerializer<Priority> {
    @Override
    public void serialize(Priority priority,
                          JsonGenerator generator,
                          SerializerProvider serializerProvider)
            throws IOException, JsonProcessingException {
        generator.writeStartObject();

        generator.writeFieldName("id");
        generator.writeString(priority.name());

        generator.writeFieldName("value");
        generator.writeString(priority.getDescription());

        generator.writeEndObject();
    }
}

来自http://localhost:8080/api/priorities

的最终json回复
{
    "_embedded": {
        "priorities": [
            {
                "id": "HIGH",
                "value": "High"
            },
            {
                "id": "NORMAL",
                "value": "Normal"
            },
            {
                "id": "LOW",
                "value": "Low"
            }
        ]
    },
    "_links": {
        "self": {
            "href": "http://localhost:8080/api/priorities"
        }
    }
}