将ServerRequest处理程序函数的结果传递给HTML / Thymeleaf。

huangapple 未分类评论45阅读模式
英文:

Passing results from ServerRequest handler function to HTML/Thymeleaf

问题

我决定开始学习Spring Boot和Webflux,以便制作一个在我脑海中存在已久的Web服务。我对这方面完全是新手,但我了解一些Java,所以我正在尝试一些示例,并遇到了一些无法解决的问题。

目前,我正在尝试通过Thymeleaf将处理程序函数生成的结果(视频名称和链接)显示在我的HTML页面上,但页面上不会显示。

**处理程序函数**
---------------------

(这里有一个独立的路由器函数)
```java
public Mono<ServerResponse> listVideos(ServerRequest request) {

    Flux<Path> files = fileService.getAllFiles();

    Flux<VideoDetails> videoDetailsFlux = files.map(path -> {
        VideoDetails videoDetails = new VideoDetails();
        videoDetails.setName(path.getFileName().toString());
        videoDetails.setLink(request.uri().toString() + '/' + videoDetails.getName());
        return videoDetails;
    }).filter(videoDetails -> !videoDetails.getName().startsWith(".")).doOnError(t -> {
        throw Exceptions.propagate(t);
    });

    return ServerResponse.ok()
            .contentType(MediaType.TEXT_HTML)       // 这里原来是APPLICATION_JSON
            .render("videos", videoDetailsFlux);
}

@Data
private static class VideoDetails {
    private String name;
    private String link;
}

原本这个函数返回的是JSON。我知道我需要使用JavaScript将JSON传递到网页,但我想使用Thymeleaf来完成。除非JavaScript是更好的方法?

videos.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title>Stream Home</title>
</head>
<body>
    <h1>这是视频页面</h1>
</div>
<table id="allMovies" class="table table-striped">
    <thead>
    <tr>
        <th width="70%">名称</th>
        <th>链接</th>
    </tr>
    </thead>
    <tbody>
    <tr class="" data-th-each="video : ${VideoDetailsFlux}">
        <td>${video.name}</td>
        <td>[[${video.link}]]</td>    
    </tr>
    </tbody>
</table>
</div>
</body>
</html>

我还尝试将这个方法放到自己的控制器类中,像这样:

VideoController.java

@GetMapping("/videos")
public Mono<ServerResponse> listVideos(ServerRequest request, final Model model) {

    Flux<Path> files = fileService.getAllFiles();

    Flux<VideoDetails> videoDetailsFlux = files.map(path -> {
        VideoDetails videoDetails = new VideoDetails();
        videoDetails.setName(path.getFileName().toString());
        videoDetails.setLink(request.uri().toString() + '/' + videoDetails.getName());
        return videoDetails;
    }).filter(videoDetails -> !videoDetails.getName().startsWith(".")).doOnError(t -> {
        throw Exceptions.propagate(t);
    });

    IReactiveDataDriverContextVariable reactiveDataDrivenMode =
            new ReactiveDataDriverContextVariable(videoDetailsFlux);

    model.addAttribute("videos", reactiveDataDrivenMode);
     
    System.out.println("|||||||||||||||LIST_VIDEOS");

    return ServerResponse.ok().render("videos");
}

@Data
private static class VideoDetails {
    private String name;
    private String link;
}

videos.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title>Stream Home</title>
</head>
<body>
    <h1>这是视频页面</h1>
</div>
<table id="allMovies" class="table table-striped">
    <thead>
    <tr>
        <th width="70%">名称</th>
        <th>链接</th>
    </tr>
    </thead>
    <tbody>
    <tr class="" data-th-each="video : ${videos}">
        <td>${video.name}</td>
        <td>[[${video.link}]]</td>
    </tr>
    </tbody>
</table>
</div>
</body>
</html>

但我猜我不能混合使用ServerRequestModel,因为我会得到(type=Internal Server Error,status=500)NullPointerException。然后我尝试将其作为仅返回字符串的方法,但我不知道如何在没有“response.uri()”的情况下获取URI。也许有人可以帮助我更好地理解我做错了什么。我可能对这应该如何工作有一些误解。

编辑:

我像这样让它工作了:
但是,我不确定自制的BaseUri是否比“ServerRequest request”更好。这会在以后造成问题吗?

VideoController.java

@GetMapping("/videos")
public String listVideos(final Model model) {

    String baseUrl = "/videos";   

    Flux<Path> files = fileService.getAllFiles();

    Flux<VideoDetails> videoDetailsFlux = files.map(path -> {
        VideoDetails videoDetails = new VideoDetails();
        videoDetails.setName(path.getFileName().toString());
        videoDetails.setLink(baseUrl + '/' + videoDetails.getName());
        return videoDetails;
    }).filter(videoDetails -> !videoDetails.getName().startsWith(".")).doOnError(t -> {
        throw Exceptions.propagate(t);
    });

    IReactiveDataDriverContextVariable reactiveDataDrivenMode =
        new ReactiveDataDriverContextVariable(videoDetailsFlux);

    model.addAttribute("videos", reactiveDataDrivenMode);
     
    System.out.println("|||||||||||||||LIST_VIDEOS");

    return "videos";
}

**videos.html**
```html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title>Stream Home</title>
</head>
<body>
    <h1>这是视频页面</h1>
</div>
<table id="allMovies" class="table table-striped">
    <thead>
    <tr>
        <th width="70%">名称</th>
        <th>链接</th>
    </tr>
    </thead>
    <tbody>
    <tr class="" data-th-each="video : ${videos}">
        <td>[[${video.name}]]</td>
        <td><a th:href="${video.link}">[[${video.link}]]</a></td>
    </tr>
    </tbody>
</table>
</div>
</body>
</html>


<details>
<summary>英文:</summary>

I decided to get into Spring-Boot and Webflux to make a web service that was on my mind for some years. I&#39;m totally new to this, but I know some Java, so I&#39;m playing around with some examples and got into some problems that I can&#39;t figure out.

Right now I&#39;m trying to display the results(videoname and Link) a handler function generates to my HTML page via Thymeleaf but it wont show on the page.
&lt;br /&gt;  
&lt;br /&gt; 


**Handeler Function**
---------------------

(There is a seperate router function)

public Mono<ServerResponse> listVideos(ServerRequest request) {

    Flux&lt;Path&gt; files = fileService.getAllFiles();

    Flux&lt;VideoDetails&gt; videoDetailsFlux = files.map(path -&gt; {
        VideoDetails videoDetails = new VideoDetails();
        videoDetails.setName(path.getFileName().toString());
        videoDetails.setLink(request.uri().toString() + &#39;/&#39; + videoDetails.getName());
        return videoDetails;
    }).filter(videoDetails -&gt; !videoDetails.getName().startsWith(&quot;.&quot;)).doOnError(t -&gt; {
        throw Exceptions.propagate(t);
    });

    return ServerResponse.ok()
            .contentType(MediaType.TEXT_HTML)       //This was APPLICATION_JSON
            .render(&quot;videos&quot;, videoDetailsFlux);

            /* 
            .cacheControl(CacheControl.noCache())         
            .location(request.uri())   
            .body(videoDetailsFlux, VideoDetails.class);
            */
            

}

@Data
private static class VideoDetails {
    private String name;
    private String link;
}

This originally returned JSON. I know I would have to use Javascript to pass the JSON to the web page but I&#39;d like to do it with thymeleaf. Unless js would be the better way to do it?
&lt;br /&gt;  
&lt;br /&gt;


**videos.html**
---------------

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Stream Home</title>
</head>
<body>
<h1 > THIS IS THE VIDEOS PAGE</h1>
</div>
<table id="allMovies" class="table table-striped">
<thead>
<tr>
<th width="70%">Name</th>
<th>Link</th>
</tr>
</thead>
<tbody>
<tr class="" data-th-each="video : ${VideoDetailsFlux}">
<td>${video.name}</td>
<td>[[${video.link}]]</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>

&lt;br /&gt;  
&lt;br /&gt;


I also tried to put the method into its own controller class like this:

**VideoController.java**
------------------------

@GetMapping("/videos")
public Mono<ServerResponse> listVideos(ServerRequest request, final Model model) {

Flux&lt;Path&gt; files = fileService.getAllFiles();

    Flux&lt;VideoDetails&gt; videoDetailsFlux = files.map(path -&gt; {
        VideoDetails videoDetails = new VideoDetails();
        videoDetails.setName(path.getFileName().toString());
        videoDetails.setLink(request.uri().toString() + &#39;/&#39; + videoDetails.getName());
        return videoDetails;
    }).filter(videoDetails -&gt; !videoDetails.getName().startsWith(&quot;.&quot;)).doOnError(t -&gt; {
        throw Exceptions.propagate(t);
    });

    IReactiveDataDriverContextVariable reactiveDataDrivenMode =
            new ReactiveDataDriverContextVariable(videoDetailsFlux);

    model.addAttribute(&quot;videos&quot;, reactiveDataDrivenMode);
     
    System.out.println(&quot;|||||||||||||||LIST_VIDEOS&quot;);

    return ServerResponse.ok().render(&quot;videos&quot;);

}

@Data
private static class VideoDetails {
private String name;
private String link;
}


**videos.html**
---------------

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Stream Home</title>
</head>
<body>
<h1 > THIS IS THE VIDEOS PAGE</h1>
</div>
<table id="allMovies" class="table table-striped">
<thead>
<tr>
<th width="70%">Name</th>
<th>Link</th>
</tr>
</thead>
<tbody>
<tr class="" data-th-each="video : ${videos}">
<td>${video.name}</td>
<td>[[${video.link}]]</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>

But i guess I can&#39;t mix ServerRequest and Model, because I get (type=Internal Server Error, status=500) NullPointerException. 
Then I tried it as a String only method, but then I don&#39;t know how to get the uri() without &quot;response.uri()&quot;.

Maybe someone could help me to better understand what I&#39;m doing wrong. I probably have a general missunderstanding of how this should work.
&lt;br /&gt;
&lt;br /&gt;
**EDIT:**
---------
I got it working like this:&lt;br /&gt;
But I&#39;m not sure about the selfmade BaseUri instead of a &quot;ServerRequest request&quot;. Cold this cause any problems later on?
&lt;br /&gt;

**VideoController.java**

@GetMapping("/videos")
public String listVideos(final Model model) {

String baseUrl = &quot;/videos&quot;;   

Flux&lt;Path&gt; files = fileService.getAllFiles();

    Flux&lt;VideoDetails&gt; videoDetailsFlux = files.map(path -&gt; {
        VideoDetails videoDetails = new VideoDetails();
        videoDetails.setName(path.getFileName().toString());
        videoDetails.setLink(baseUrl + &#39;/&#39; + videoDetails.getName());
        return videoDetails;
    }).filter(videoDetails -&gt; !videoDetails.getName().startsWith(&quot;.&quot;)).doOnError(t -&gt; {
        throw Exceptions.propagate(t);
    });

    IReactiveDataDriverContextVariable reactiveDataDrivenMode =
        new ReactiveDataDriverContextVariable(videoDetailsFlux);

    model.addAttribute(&quot;videos&quot;, reactiveDataDrivenMode);
     
    System.out.println(&quot;|||||||||||||||LIST_VIDEOS&quot;);

    return &quot;videos&quot;;

}
&lt;br /&gt;
**videos.html**

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Stream Home</title>
</head>
<body>
<h1 > THIS IS THE VIDEOS PAGE</h1>
</div>
<table id="allMovies" class="table table-striped">
<thead>
<tr>
<th width="70%">Name</th>
<th>Link</th>
</tr>
</thead>
<tbody>
<tr class="" data-th-each="video : ${videos}">
<td>[[${video.name}]]</td>
<a th:href=${video.link}>[[${video.link}]]</a>
</tr>
</tbody>
</table>
</div>
</body>
</html>


</details>


huangapple
  • 本文由 发表于 2020年5月4日 21:42:26
  • 转载请务必保留本文链接:https://java.coder-hub.com/61593677.html
匿名

发表评论

匿名网友

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

确定