《精通Spring MVC 4》——2.9 使用WebJars实现质感设计

简介: 在Java Web应用中,Redirect/Forward是典型的可选方案。它们都会改变展现给用户的视图,其中的区别在于Redirect会发送一个302头信息,它会在浏览器内部触发导航,而Forward则不会导致URL的变化。

本节书摘来自异步社区《精通Spring MVC 4》一书中的第2章,第2.9节,作者:【美】Geoffroy Warin著,更多章节内容可以访问云栖社区“异步社区”公众号查看

2.9 使用WebJars实现质感设计

现在,我们的应用已经很棒了,但是在美学方面却差得很多。你可能听说过质感设计(material design),这是Google的扁平化设计。

如图2-10所示,我们将会使用Materialize,这是一个非常漂亮的CSS和JavaScript库,与Bootstrap类似。

screenshot

图2-10

在第1章中,我们曾经简单介绍过WebJars,现在要开始使用它们了。在依赖中,我们要添加jQuery和Materialize CSS:

compile 'org.webjars:materializecss:0.96.0'
compile 'org.webjars:jquery:2.1.4'

每个WebJar的结构都是标准的,每个库的JS和CSS文件都会位于/webjars/{lib}/ {version}/*.js中。

例如,如果要添加jQuery到我们的页面中,那Web页面需要如下所示:

``
接下来修改一下控制器,让它显示所有Tweet对象的列表,而不是只显示简单的文本:

package masterSpringMvc.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.social.twitter.api.SearchResults;
import org.springframework.social.twitter.api.Tweet;
import org.springframework.social.twitter.api.Twitter;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@Controller
public class TweetController {

    @Autowired
    private Twitter twitter;

    @RequestMapping("/")
    public String hello(@RequestParam(defaultValue =
"masterSpringMVC4") String search, Model model) {
        SearchResults searchResults = twitter.searchOperations().
search(search);
        List<Tweet> tweets = searchResults.getTweets();
        model.addAttribute("tweets", tweets);
        model.addAttribute("search", search);
        return "resultPage";
    }
}

在视图中,将Materialize CSS包含进来:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en">
    <meta charset="UTF-8"/>
    <title>Hello twitter</title>

    <link href="/webjars/materializecss/0.96.0/css/materialize.css"
type="text/css" rel="stylesheet" media="screen,projection"/>
</head>
<body>
<div class="row">

    <h2 class="indigo-text center" th:text="|Tweet results for
${search}|">Tweets</h2>

    <ul class="collection">
        <li class="collection-item avatar" th:each="tweet :
${tweets}">
            <img th:src="${tweet.user.profileImageUrl}" alt=""
class="circle"/>
            <span class="title" th:text="${tweet.user.
name}">Username</span>
            <p th:text="${tweet.text}">Tweet message</p>
        </li>
    </ul>

</div>

<script src="/webjars/jquery/2.1.4/jquery.js"></script>
<script src="/webjars/materializecss/0.96.0/js/materialize.js"></
script>
</body>
</html>

如图2-11所示结果看起来会好很多。

..tu0211.tif{}
screenshot

图2-11

2.9.1 使用布局
我们最后想实现的就是将UI中可重用的代码块放到模板之中。为了实现该功能,我们需要使用thymeleaf-layout-dialect依赖,它已经包含在项目的spring-boot-starter-thymeleaf依赖里面。

我们会创建一个新的文件,名为default.html,并将其放在src/main/resources/templates/ layout之中,它包含了每个页面中都重复出现的代码:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
    <meta http-equiv="Content-Type" content="text/html;
charset=UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-
scale=1, maximum-scale=1.0, user-scalable=no"/>
    <title>Default title</title>

    <link href="/webjars/materializecss/0.96.0/css/materialize.css"
type="text/css" rel="stylesheet" media="screen,projection"/>
</head>
<body>
<section layout:fragment="content">
    <p>Page content goes here</p>
</section>

<script src="/webjars/jquery/2.1.4/jquery.js"></script>
<script src="/webjars/materializecss/0.96.0/js/materialize.js"></
script>
</body>
</html>

现在,我们要修改resultPage.html文件,让它使用布局,这会简化它的内容:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorator="layout/default">
<head lang="en">
    <title>Hello twitter</title>
</head>
<body>
<div class="row" layout:fragment="content">

    <h2 class="indigo-text center" th:text="|Tweet results for
${search}|">Tweets</h2>

    <ul class="collection">
        <li class="collection-item avatar" th:each="tweet :
${tweets}">

            <img th:src="${tweet.user.profileImageUrl}" alt=""
class="circle"/>
            <span class="title" th:text="${tweet.user.
name}">Username</span>

            <p th:text="${tweet.text}">Tweet message</p>
        </li>
    </ul>
</div>
</body>
</html>

其中,layout:decorator="layout/default"能够表明去哪里查找布局。这样,我们可以将内容注入到布局的不同layout:fragment区域中。需要注意的是,每个模板都是合法的HTML文件,我们可以非常容易地重写它的标题。

2.9.2 导航
我们现在已经有了一个很棒的用于展现Tweet的小应用,但是,我们的用户需要提供一个“search”请求参数,这该如何实现呢(见图2-12)?

screenshot

图2-12

如果我们能够在应用上增加一个小表单的话,那就非常完美了。

我们接下来要做的事情如下所示。

首先,我们需要修改TweetController,为应用增加第二个视图。访问应用的根目录会展现出搜索页面,在search域中点击回车键会展现结果页面:

@Controller
public class TweetController {

    @Autowired
    private Twitter twitter;

    @RequestMapping("/")
    public String home() {
        return "searchPage";
    }

    @RequestMapping("/result")
    public String hello(@RequestParam(defaultValue =
"masterSpringMVC4") String search, Model model) {
        SearchResults searchResults = twitter.searchOperations().
search(search);
        List<Tweet> tweets = searchResults.getTweets();
        model.addAttribute("tweets", tweets);
        model.addAttribute("search", search);
        return "resultPage";
    }
}

我们会添加另外一个页面到templates文件夹下,并将其命名为searchPage.html文件。这个页面会包含一个简单的表单,它会通过get方法将要搜索的术语传递到结果页面:

<!DOCTYPE html>
<html xmlns:th="http://www.w3.org/1999/xhtml"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorator="layout/default">
<head lang="en">
    <title>Search</title>
</head>
<body>

<div class="row" layout:fragment="content">

    <h4 class="indigo-text center">Please enter a search term</h4>

    <form action="/result" method="get" class="col s12">
        <div class="row center">
            <div class="input-field col s6 offset-s3">
                <i class="mdi-action-search prefix"></i>
                <input id="search" name="search" type="text"
class="validate"/>
                <label for="search">Search</label>
            </div>
        </div>
    </form>
</div>

</body>
</html>

这是一个很简单的HTML,但是已经可以正常运行了,你现在可以尝试一下。

如果不允许展现某些搜索结果的话,该怎么办呢?假设如果用户输入struts的话,我们想展现一个出错页面。

要实现该功能,最好的方式就是修改提交数据的表单。在控制器中,我们可以拦截提交的内容并实现该业务相关的规则。

首先,要修改searchPage中的表单,原来的内容如下所示:

<form action="/result" method="get" class="col s12">
现在,我们将表单改成如下的形式:

<form action="/postSearch" method="post" class="col s12">
我们还需要在服务器端处理该POST请求。在TweetController中添加如下的方法:

@RequestMapping(value = "/postSearch", method = RequestMethod.POST)
public String postSearch(HttpServletRequest request,
    RedirectAttributes redirectAttributes) {
        String search = request.getParameter("search");
        redirectAttributes.addAttribute("search", search);
        return "redirect:result";
}

在这里,有几项比较新鲜的内容:

在请求映射的注解中,指定了想要处理的HTTP方法,也就是POST;
在方法参数中,直接注入了两个属性,它们是request和RedirectAttributes;
检索到请求中post提交过来的数据,并将其传递给下一个视图;
现在不是直接返回视图的名称,而是重定向到另一个URL。
RedirectAttributes是一个Spring的模型,专门用于redirect场景下传送值。

screenshot

在Java Web应用中,Redirect/Forward是典型的可选方案。它们都会改变展现给用户的视图,其中的区别在于Redirect会发送一个302头信息,它会在浏览器内部触发导航,而Forward则不会导致URL的变化。在Spring MVC中,我们可以任意使用这两种方案,只需在方法返回的字符串上添加“redirect:”或“forward:”前缀即可。在这两种场景中,我们所返回的字符串都不会像前面看到的那样解析为视图,而是触发到特定URL的导航。
之前的样例有些牵强,在下一章中会进行更加巧妙的处理。如果你在postSearch方法上添加一个断点的话,就会发现它会在post表单之后进行调用。

那么,该怎样显示错误信息呢?

我们改一下postSearch方法:

@RequestMapping(value = "/postSearch", method = RequestMethod.POST)
public String postSearch(HttpServletRequest request,
    RedirectAttributes redirectAttributes) {
        String search = request.getParameter("search");
        if (search.toLowerCase().contains("struts")) {
                redirectAttributes.addFlashAttribute("error", "Try
using spring instead!");
                return "redirect:/";
        }
        redirectAttributes.addAttribute("search", search);
        return "redirect:result";
}

如果用户的搜索包含“struts”这个术语的话,我们会将其重定向到searchPage页面并且使用flash属性添加一点错误信息。

这个特殊的属性会在该请求的时间范围内一直存活,直到页面渲染完成才消失。当使用POST-REDIRECT-GET模式的时候,它是非常有用的,就像刚刚做的这样。

我们接下来需要在searchPage结果页面中展现这个错误信息:

<!DOCTYPE html>
<html xmlns:th="http://www.w3.org/1999/xhtml"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorator="layout/default">
<head lang="en">
    <title>Search</title>
</head>
<body>

<div class="row" layout:fragment="content">

    <h4 class="indigo-text center">Please enter a search term</h4>

    <div class="col s6 offset-s3">
        <div id="errorMessage" class="card-panel red lighten-2"
th:if="${error}">
            <span class="card-title" th:text="${error}"></span>
        </div>
        <form action="/postSearch" method="post" class="col s12">
            <div class="row center">
                <div class="input-field">
                    <i class="mdi-action-search prefix"></i>
                    <input id="search" name="search" type="text"
class="validate"/>
                    <label for="search">Search</label>
                </div>
            </div>
        </form>
    </div>
</div>

</body>
</html>

现在,如果用户试图搜索包含“struts2”的Tweet,将会得到有用且合适的答案(见图2-13)。

screenshot

图2-13

相关文章
|
28天前
|
JSON 前端开发 Java
SSM:SpringMVC
本文介绍了SpringMVC的依赖配置、请求参数处理、注解开发、JSON处理、拦截器、文件上传下载以及相关注意事项。首先,需要在`pom.xml`中添加必要的依赖,包括Servlet、JSTL、Spring Web MVC等。接着,在`web.xml`中配置DispatcherServlet,并设置Spring MVC的相关配置,如组件扫描、默认Servlet处理器等。然后,通过`@RequestMapping`等注解处理请求参数,使用`@ResponseBody`返回JSON数据。此外,还介绍了如何创建和配置拦截器、文件上传下载的功能,并强调了JSP文件的放置位置,避免404错误。
|
1月前
|
前端开发 Java 应用服务中间件
【Spring】Spring MVC的项目准备和连接建立
【Spring】Spring MVC的项目准备和连接建立
52 2
|
2月前
|
缓存 前端开发 Java
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
Soring Boot的起步依赖、启动流程、自动装配、常用的注解、Spring MVC的执行流程、对MVC的理解、RestFull风格、为什么service层要写接口、MyBatis的缓存机制、$和#有什么区别、resultType和resultMap区别、cookie和session的区别是什么?session的工作原理
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
|
1月前
|
XML 前端开发 Java
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
本文阐述了Spring、Spring Boot和Spring MVC的关系与区别,指出Spring是一个轻量级、一站式、模块化的应用程序开发框架,Spring MVC是Spring的一个子框架,专注于Web应用和网络接口开发,而Spring Boot则是对Spring的封装,用于简化Spring应用的开发。
97 0
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
|
2月前
|
XML 缓存 前端开发
springMVC02,restful风格,请求转发和重定向
文章介绍了RESTful风格的基本概念和特点,并展示了如何使用SpringMVC实现RESTful风格的请求处理。同时,文章还讨论了SpringMVC中的请求转发和重定向的实现方式,并通过具体代码示例进行了说明。
springMVC02,restful风格,请求转发和重定向
|
3月前
|
Java 数据库连接 Spring
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
文章是关于Spring、SpringMVC、Mybatis三个后端框架的超详细入门教程,包括基础知识讲解、代码案例及SSM框架整合的实战应用,旨在帮助读者全面理解并掌握这些框架的使用。
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
|
3月前
|
XML JSON 数据库
SpringMVC入门到实战------七、RESTful的详细介绍和使用 具体代码案例分析(一)
这篇文章详细介绍了RESTful的概念、实现方式,以及如何在SpringMVC中使用HiddenHttpMethodFilter来处理PUT和DELETE请求,并通过具体代码案例分析了RESTful的使用。
SpringMVC入门到实战------七、RESTful的详细介绍和使用 具体代码案例分析(一)
|
3月前
|
前端开发 应用服务中间件 数据库
SpringMVC入门到实战------八、RESTful案例。SpringMVC+thymeleaf+BootStrap+RestFul实现员工信息的增删改查
这篇文章通过一个具体的项目案例,详细讲解了如何使用SpringMVC、Thymeleaf、Bootstrap以及RESTful风格接口来实现员工信息的增删改查功能。文章提供了项目结构、配置文件、控制器、数据访问对象、实体类和前端页面的完整源码,并展示了实现效果的截图。项目的目的是锻炼使用RESTful风格的接口开发,虽然数据是假数据并未连接数据库,但提供了一个很好的实践机会。文章最后强调了这一章节主要是为了练习RESTful,其他方面暂不考虑。
SpringMVC入门到实战------八、RESTful案例。SpringMVC+thymeleaf+BootStrap+RestFul实现员工信息的增删改查
|
3月前
|
JSON 前端开发 Java
Spring MVC返回JSON数据
综上所述,Spring MVC提供了灵活、强大的方式来支持返回JSON数据,从直接使用 `@ResponseBody`及 `@RestController`注解,到通过配置消息转换器和异常处理器,开发人员可以根据具体需求选择合适的实现方式。
157 4
|
3月前
|
XML 前端开发 Java
Spring MVC接收param参数(直接接收、注解接收、集合接收、实体接收)
Spring MVC提供了灵活多样的参数接收方式,可以满足各种不同场景下的需求。了解并熟练运用这些基本的参数接收技巧,可以使得Web应用的开发更加方便、高效。同时,也是提高代码的可读性和维护性的关键所在。在实际开发过程中,根据具体需求选择最合适的参数接收方式,能够有效提升开发效率和应用性能。
118 3
下一篇
无影云桌面