Binding With Multiple Tables Spring Thymeleaf

Viewed 226

I know the title of this question is not clear, but before disliking let me explain my problem.

I have a social media with java spring using JPA and thymeleaf.

Users have ids, usernames, and creation dates.

In the posts table there is a field called "authorid", so when someone makes a new post the system only writes his user id, not his username.

Now, I have a page on the site, available at "localhost:8080/showAllPosts/" which shows ALL the application posts from the most recent to the least recent. The controller looks something like this:

@Controller
public class MyController {

  @GetMapping("/showAllPosts") 
  public String showAllPosts(Model model) {

    List<Post> post = new ArrayList<>();
    model.addAttribute("post", post);

    List<Post> posts = postRepository.findAll();
    model.addAttibute("posts", posts);

    return "showallposts.html";
  }
}

The showallposts.html page looks like this:

<table>
                    <tbody>
                        <tr th:if="${posts.empty}">
                            <td colspan="2">No Posts Available</td>
                        </tr>
                        <tr th:each="post : ${posts}">
                            <td>                                
<span th:text="'posted by ' + ${post.authorid}>
                                <span th:text="${post.postcontent}"></span>
                                <br>                                
                            </td>
                            <td>                            
                            </td>
                        </tr>
                    </tbody>
                </table>

As you can see, it shows the post content, and "posted by" plus the author. The only problem is that the post.authorid returns the numeric id of user who posted, and I wanted the username. Is there something we can do with the users model?

Notice that in the users repository I have this method:

@Query(value = "SELECT u.username FROM Users u WHERE u.userid = ?1")
public String findUsernameById(Long userid);

ALL help is appreciated! <3

1 Answers

Alternatively, you can use a DTO to move the post with the author's name into the Thymeleaf view.

  1. Create a new class like PostDto:
public class PostDto {
    private Long id;
    private String postContent;
    private Long authorId;
    private String String authorName;

    // other fields
    // getters and setters
}
  1. Convert your post entity class to PostDto using the Stream API. During the mapping, you can get the username by authorId via UserRespository and supplement the post dto object with the author's name.
@Controller
public class MyController {

    @Autowired
    private UserRepository userRepository;

    @GetMapping("/showAllPosts") 
    public String showAllPosts(Model model) {
        List<Post> post = new ArrayList<>();

        model.addAttribute("post", post);

        List<Post> posts = postRepository.findAll().stream()
            .map(post -> {
                PostDto dto = toDto(post);
                dto.setAuthorName(userRepository.findUsernameById(post.getAuthorId()));
            })

        model.addAttibute("posts", posts);

        return "showallposts.html";
    }


    private PostDto toDto(Post post) {
        PostDto dto = new PostDto();
        dto.setId(post.getId);
        dto.setPostContent(post.getPostContent());
        dto.setAuthorId(post.getAuthorId());
    }
}
  1. Use in the Thymeleaf view as ${post.authorName}.
<table>
    <tbody>
        <tr th:if="${posts.empty}">
            <td colspan="2">No Posts Available</td>
        </tr>
        <tr th:each="post : ${posts}">
            <td>
                <span th:text="'posted by ' + ${post.authorName}>
                <span th:text="${post.postcontent}"></span>
                <br> 
            </td>
            <td>
            </td>
        </tr>
    </tbody>
</table>
Related