假如我们有两张表,一张用户表,一张新闻表。用户表中有id,userName,password。新闻表有id,newsTitle,newsContent,userId。因为新闻是用户发的,所有新闻表中的 userId 是 用户表中的 id 的外键。

那如果我们想在前端展示新闻,需要展示的内容有新闻标题,新闻内容(newsTitle,newsContent) 和发帖人 (userName) 。如果是正常数据库查询的话只要进行表联结查询就行了,但要放到前端展示就没这么简单了。


常规思路:

伪代码实现:
List<News> newsList = newsService.selectAllNews();
List<Users> usersList = usersService.selectAllUsers();
model.addAttribute("newsList",newsList);
model.addAttribute("usersList",usersList);
然后前端用 Thymeleaf 取的时候,用其for循环语句遍历:
<div th:each="news : ${newsList}" th:each="users : ${usersList}">
	<h3><a th:text="${news.newsTitle}">what</a></h3>
	<h3><a th:text="${news.newsContent}">what</a></h3>
	<h3><a th:text="${users.userName}">what</a></h3>
</div>

不知道一个 <div> 标签中能不能同时写两个 th:each,而且两张表中的数据取的时候也完全没用进行关联,用户和他发的内容应该是不能一一对应展示的。


下面换个思路来实现:

自定义一个类 ViewObject:
public class ViewObject {
    private Map<String, Object> objs = new HashMap<>();

    public void set(String key, Object value) {
        objs.put(key, value);
    }

    public Object get(String key) {
        return objs.get(key);
    }
}

这个类的作用是往一个 map 中存数据和取数据。map 是键值对一一对应的,如果把 uses 和 news 表中的数据都存进 map 那么就可以存储为下面这种形式:

"news":{"id":2,"title":"TITLE{1}","userId":3},"users":{"id":3,"name":"jarvis","password":"12345678"}

如果外面再包上一层 list ,那么就能实现一一对应了,通过迭代器遍历 list 后得到的数据应该是这个样子的:

{"news":{"id":1,"title":"TITLE{1}","userId":2},"users":{"id":1,"name":"williams","password":"123456"}}
{"news":{"id":2,"title":"TITLE{2}","userId":3},"users":{"id":2,"name":"jarvis","password":"12345678"}}

实现这一功能的具体代码如下:
public List<ViewObject> getNewsAndUsersList(){
    List<ViewObject> list = new ArrayList<>();

    List<News> newsList = newsService.selectAllList();
    for(News news : newsList){
        ViewObject viewObject = new ViewObject();
        viewObject.set("news",news);
        viewObject.set("users",userService.getUser(news.getUserId()));
        list.add(viewObject);
    }
    return list;
}

通过前面的分析,现在应该简单易懂。就是把一一对应的 news 和 users 数据先放进一个 map,然后将这个 map 就权当一个打包好的值,将其存进 list。迭代器或者 for 循环就能取出这个打包好的值,相当于取出一个 map,再从 map 中取相应的属性。

从 list 中取 map 再取属性的过程的代码如下:

@RequestMapping("/index")
    public void index(){
        List<ViewObject> newsList = getNewsAndUsersList();

        for(ViewObject vo : newsList){
            System.out.println(vo.get("news"));
            System.out.println(vo.get("users"));
        }
    }

可以看到打印出了数据库中所有的 map 对象:

3.png


既然到了这一步,那么 在 Thymeleaf 中展示也就很容易了,就是先从 for 循环取 list 中的数据,取出的一条条数据是 map 数据类型,然后用 map.get(key) 取到 value,value.get属性名() 取出各个属性即可。

先把 list 传给前端:

@RequestMapping("/index")
public String index(Model model){
    List<ViewObject> newsList = getNewsAndUsersList();
    model.addAttribute("newsList",newsList);
    return "home";
}

前端取值:

<div th:each="list : ${newsList}">
	<h3><a th:text="${list.get('news').getTitle()}">what</a></h3>
	<h3><a th:text="${list.get('news').getnewsContent()}">what</a></h3>
	<h3><a th:text="${list.get('users').getName()}">what</a></h3>
</div>