2.1.2 创建控制器类

控制器是 Spring MVC 框架的主要参与者。它们的主要工作是处理 HTTP 请求,或者将请求传递给视图以呈现 HTML(浏览器显示),或者直接将数据写入响应体(RESTful)。在本章中,我们将重点讨论使用视图为 web 浏览器生成内容的控制器的类型。在第 6 章中,我们将讨论如何在 REST API 中编写处理请求的控制器。

对于 Taco Cloud 应用程序,需要一个简单的控制器来执行以下操作:

  • 处理请求路径为 /design 的 HTTP GET 请求
  • 构建配料列表
  • 将请求和配料数据提交给视图模板,以 HTML 的形式呈现并发送给请求的 web 浏览器

下面的 DesignTacoController 类处理这些需求。

程序清单 2.2 Spring 控制器类的开始

package tacos.web;import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;import lombok.extern.slf4j.Slf4j;
import tacos.Ingredient;
import tacos.Ingredient.Type;
import tacos.Taco;@Slf4j
@Controller
@RequestMapping("/design")
@SessionAttributes("tacoOrder")
public class DesignTacoController {

  @ModelAttribute
  public void addIngredientsToModel(Model model) {
    List<Ingredient> ingredients = Arrays.asList(
      new Ingredient("FLTO", "Flour Tortilla", Type.WRAP),
      new Ingredient("COTO", "Corn Tortilla", Type.WRAP),
      new Ingredient("GRBF", "Ground Beef", Type.PROTEIN),
      new Ingredient("CARN", "Carnitas", Type.PROTEIN),
      new Ingredient("TMTO", "Diced Tomatoes", Type.VEGGIES),
      new Ingredient("LETC", "Lettuce", Type.VEGGIES),
      new Ingredient("CHED", "Cheddar", Type.CHEESE),
      new Ingredient("JACK", "Monterrey Jack", Type.CHEESE),
      new Ingredient("SLSA", "Salsa", Type.SAUCE),
      new Ingredient("SRCR", "Sour Cream", Type.SAUCE)
    );

    Type[] types = Ingredient.Type.values();
    for (Type type : types) {
      model.addAttribute(type.toString().toLowerCase(),
      filterByType(ingredients, type));
    }
  }

  @GetMapping
  public String showDesignForm(Model model) {
    model.addAttribute("taco", new Taco());
    return "design";
  }
  private Iterable<Ingredient> filterByType(
        List<Ingredient> ingredients, Type type) {
    return ingredients
        .stream()
        .filter(x -> x.getType().equals(type))
        .collect(Collectors.toList());
  }
}

关于 DesignTacoController,首先要注意的是在类级应用的一组注解。第一个是 @Slf4j,它是 Lombok 提供的注解,在运行时将自动生成类中的 SLF4J(Java 的简单日志门面,https://www.slf4j.org/)记录器。这个适当的注解具有与显式地在类中添加以下行相同的效果:

private static final org.slf4j.Logger log =
      org.slf4j.LoggerFactory.getLogger(DesignTacoController.class);

稍后您将使用这个 Logger。

下一个应用到 DesignTacoController 的注解是 @Controller。此注解用于将该类标识为控制器并将其标记为组件扫描的候选对象,以便 Spring 将发现该类并在 Spring 应用程序上下文中自动创建 DesignTacoController 实例作为 bean。

DesignTacoController 也用 @RequestMapping 注解。@RequestMapping 注解在类级应用时,指定该控制器处理的请求的类型。在本例中,它指定 DesignTacoController 将处理路径以 /design 开头的请求。

处理 GET 请求

类级别的 @RequestMapping 注解用于 showDesignForm() 方法时,可以用 @GetMapping 注解进行改进。@GetMapping 与类级别的 @RequestMapping 配对使用,指定当接收到 /design 的 HTTP GET 请求时,showDesignForm() 将用来处理请求。

@GetMapping 只是一系列请求映射注解中的一个。表 2.1 列出了 Spring MVC 中提供的所有请求映射注解的一部分。

表 2.1 Spring MVC 请求映射注解

注解 描述
@RequestMapping 通用请求处理
@GetMapping 处理 HTTP GET 请求
@PostMapping 处理 HTTP POST 请求
@PutMapping 处理 HTTP PUT 请求
@DeleteMapping 处理 HTTP DELETE 请求
@PatchMapping 处理 HTTP PATCH 请求

showDesignForm() 处理 /design 的 GET 请求时,它实际上没有做多少工作。它所做的主要工作是返回一个字符串值“design”,这是视图的逻辑名称,将用于将模型渲染到浏览器的。但在此之前,它也会填充给定模型,在一个名为“design”的键下有一个空的 Taco 对象。这将使可以在表单上创作出一幅墨西哥玉米卷的杰作。

GET 请求似乎没有多大作用。但恰恰相反,/design 比 showDesignForm() 方法更复杂。您也会注意到,有一个名为addIngredientsToModel() 的方法,该方法用 @ModelAttribute 注解。处理请求时也将调用此方法,并将构造一个要放入模型中的配料对象。该列表目前已硬编码。当我们到达第三章,您将从数据库中提取可用的玉米卷配料列表。

一旦准备好了原料列表,接下来的几行 showDesignForm() 将根据原料类型过滤该列表。然后将配料类型列表作为属性添加到传递到 showDesignForm() 的 Model 对象。Model 是一个对象,它在控制器和负责呈现数据的视图之间传输数据。最后,放置在 Model 类属性中的数据被复制到 servlet 响应属性中,视图可以在其中找到它们。showDesignForm() 方法最后返回 “design”,这是将用于向浏览器呈现 Model 的视图的逻辑名称。

DesignTacoController 真的开始成形了。如果您现在运行应用程序并将您的浏览器指向 /design 路径,DesignTacoController 的 showDesignForm() 将被占用,它从存储库中获取数据并将其放在 Model 中,然后将请求传递给视图。但是因为还没有定义视图,所以请求会发生可怕的转变,导致 HTTP 500(Internal Server Error)错误。为了解决这个问题,让我们将注意力转移到视图上,其中的数据将用 HTML 进行修饰,并在用户的 web 浏览器中显示。

results matching ""

    No results matching ""