Spring Boot控制器返回通用类型(A或B)。

huangapple go评论65阅读模式
英文:

Spring Boot Controller return generic types (A or B)

问题

您的控制器函数中使用的ResponseMessage<?>中的问号?并不是最好的方式,您可以使用Java的通配符<? extends T>来更好地表示返回值,其中TResponseMessage的类型参数。这将更准确地表明您的函数可能返回不同类型的ResponseMessage。这是一个更新后的示例:

public ResponseMessage<? extends Object> findRecent(@AuthenticationPrincipal LoginUser user) {
    Optional<TodoResponse> todo = todoService.findRecent(user.getId());
    return todo.isPresent() ? ResponseMessage.ok(todo.get()) : ResponseMessage.noContent();
}

在这种情况下,您的findRecent函数可以返回ResponseMessage<TodoResponse>ResponseMessage<String>,具体取决于todoService.findRecent的返回值。这种方式更具灵活性,同时仍然提供了类型安全。

英文:

I develop simple todo-list application with spring boot. And I wanna send common response dto from all request. The data filed in ReponseMessage is Generic because it can be various type.

public class ResponseMessage&lt;T&gt; {
    private int statusCode = HttpStatus.OK.value();
    private String message = &quot;&quot;;
    protected T data;  // this is generic. it can be many response dto.

    public static ResponseMessage&lt;String&gt; ok() {
        return new ResponseMessage&lt;&gt;(&quot;&quot;);
    }

    public static &lt;T&gt; ResponseMessage&lt;T&gt; ok(T data) {
        return new ResponseMessage&lt;&gt;(data);
    }

    public static ResponseMessage&lt;Object&gt; noContent() {
        return new ResponseMessage&lt;&gt;(HttpStatus.NO_CONTENT.value(), HttpStatus.NO_CONTENT.getReasonPhrase(), &quot;&quot;);
    }

    protected ResponseMessage(T data) {
        this.data = data;
    }

    private ResponseMessage(int statusCode, String message, T data) {
        this.statusCode = statusCode;
        this.message = message;
        this.data = data;
    }

    protected ResponseMessage() {}

    public int getStatusCode() {
        return statusCode;
    }

    public String getMessage() {
        return message;
    }

    public T getData() {
        return data;
    }
}

Now i need to make a feature that find a recend todo.

If todo exists, send ResponseMessage<TodoResponse>.

{
  &quot;statusCode&quot;: 200,
  &quot;message&quot;: &quot;&quot;,
  &quot;data&quot;: [
    {
        &quot;id&quot;: 1,
        &quot;title&quot;: &quot;test&quot;,
        &quot;status&quot;: &quot;TODO&quot;
    }
  ]
}

If todo doesn't exist, send ResponseMessage<Srring>.

{
  &quot;statusCode&quot;: 200,
  &quot;message&quot;: &quot;&quot;,
  &quot;data&quot;: []
}

Now my controller function return like this.

public ResponseMessage&lt;?&gt; findRecent(@AuthenticationPrincipal LoginUser user) {
    Optional&lt;TodoResponse&gt; todo = todoService.findRecent(user.getId());
    return todo.isPresent() ? ResponseMessage.ok(todo.get()) : ResponseMessage.noContent();
}

I know that the question mark '?' is not good. so what is better way to return A or B in this case? plz help me.

答案1

得分: 1

如果将noContent().data设置为null,您可以安全地分配任何类型:

public static <T> ResponseMessage<T> noContent() {
    return new ResponseMessage<>(HttpStatus.NO_CONTENT.value(), HttpStatus.NO_CONTENT.getReasonPhrase(), null);
}

另外,请注意调用Optional.isPresent()然后再调用get()有点类似反模式。在您的情况下,您可以简化为:

return todoService.findRecent(user.getId())
        .map(ResponseMessage::ok)
        .orElseGet(ResponseMessage::noContent);
英文:

If you set noContent().data to null, you can safely assign it any type:

public static &lt;T&gt; ResponseMessage&lt;T&gt; noContent() {
    return new ResponseMessage&lt;&gt;(HttpStatus.NO_CONTENT.value(), HttpStatus.NO_CONTENT.getReasonPhrase(), null);
}

Also note that calling Optional.isPresent() and then get() is something of an antipattern. In your case, you can simplify it to this:

return todoService.findRecent(user.getId())
        .map(ResponseMessage::ok)
        .orElseGet(ResponseMessage::noContent);

huangapple
  • 本文由 发表于 2023年2月16日 05:09:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/75465456.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定