专栏名称: Guo_1_9
目录
相关文章推荐
51好读  ›  专栏  ›  Guo_1_9

Spring之旅第八站:Spring MVC Spittr舞台的搭建、基本的控制器(JavaCon...

Guo_1_9  · 掘金  ·  · 2018-02-24 11:20

正文

请到「今天看啥」查看全文


class WebConfig { }

这可以运行起来,它的确能够启用Spring MVC,但还有不少问题要解决。

1、没有配置视图解析器,如果这样的话,Spring默认会使用BeanNameView-Resolver,这个视图解析器会查找ID与视图名称匹配的bean,并且查找的bean要实现View接口,它以这样的方式来解析视图。

2、没有启用组件扫描。这样的结果就是,Spirng只能找到显示声明在配置类中的控制器。

3、这样配置的话,DispatcherServlet会映射为默认的Servlet,所以他会处理所有的请求,包括对静态资源的请求,如图片 和样式表(在大多数情况下,这可能并不是你想要的结果)。

因此我们需要在WebConfig这个最小的Spring MVC配置上再加一些内容,从而让他变得真正实用。

@Configuration
@EnableWebMvc                           //启用Spring MVC
@ComponentScan("com.guo.spittr.web")    //启用组件扫描
public class WebConfig extends WebMvcConfigurerAdapter {
    @Bean
    public ViewResolver viewResolver () {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        //配置JSP视图解析器
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        resolver.setExposeContextBeansAsAttributes(true);
        return resolver;
    }

    @Override
    //我们要求DispatcherServlet将静态资源的请求转发到Servlet容器中默认的Servlet上,
    //而不是使用DispatcherServlet本来来处理此类请求。
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        //配置静态资源的处理
        configurer.enable();
    }
}

第一件需要注意的是WebConfig现在添加了@ComponentScan注解,此时将会扫描 com.guo.spittr.web 包来查找组件。稍后你会看到,我们编写的控制器将会带有@Controller注解,这会使其成为组件扫描时的候选bean。因此,我们不需要在配置类中显示声明任何的控制器。

接下来,我们添加了一个ViewResolver bean,更具体的将是 InternalResourceViewResolver 。将会在第6章更为详细的讨论视图解析器。我们只需要知道他会去查找jsp文件,在查找的时候,它会在视图名称上加一个特定的前缀和后缀。(例如:名为home的视图会被解析为/WEB-INF/views/home.jsp)

最后新的WebConfig类还扩展里 WebMvcConfigurerAdapter 并重写了其 configureDefaultServletHandling() 方法,通过调用 DefaultServletHandlerConfigurer 的enable()方法,我们要求DispatcherServlet将静态资源的请求转发到Servlet容器中默认的Servlet上,而不是使用DispatcherServlet本来来处理此类请求。

WebConfig已经就绪,那么RootConfig呢?因为本章聚焦于Web开发,而Web相关的配置通过DisPatcherServlet创建的应用上下文都已经配好了,因此现在的RootConfig相对很简单:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
/**
 * Created by guo on 23/2/2018.
 */
@Configuration
@ComponentScan(basePackages = {"com.guo.spittr"},
    excludeFilters = {
        @Filter(type = FilterType.ANNOTATION,value = EnableWebMvc.class)})
public class RootConfig {

}

唯一需要注意的是RootConfig使用了@ComponentScan注解,这样的话,我们就有很多机会用非Web的组件来完善RootConfig。

5.1.3 Spittr应用简介

为了实现在线社交的功能,我们将要构造一个简单的微博(microblogging)应用,在很多方面,我们所构建的应用于最早的微博应用Twitter很类似,在这个过程中,我们会添加一些小的变化。当然我们使用Spirng技术来构建这个应用。

因为从Twitter借鉴了灵感并通过Spring来进行实现,所以它就有了一个名字:Spitter。

Spittr应用有两个基本的领域概念:Spitter(应用的用户)和Spittle(用户发布的简短状态更新)。当我们在书中完善Spittr应用的功能时,将会介绍这两个概念。在本章中,我们会构建应用的Web层,创建展现Spittle的控制器以及处理用户注册为Spitter的表单。

舞台已经搭建完成了,我们已经配置了DispatcherServlet,启用了基本的Spring MVC组件,并确定了目标应用。让我们进入本章的核心内容:使用Spring MVC 控制器处理Web请求。

5.2 编写 基本的控制器

在SpringMVC中,控制器只是在方法上添加了@RequestMapping注解的类,这个注解声明了他们所要处理的请求。

开始的时候,我们尽可能简单,假设控制器类要处理对/的请求,并对渲染应用的首页。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * Created by guo on 24/2/2018.
 * 首页控制器
 */
@Controller
public class HomeController {
    @RequestMapping(value = "/",method = RequestMethod.GET)           //处理对“/”的Get请求
    public String home() {
        return "home";                                                //视图名为home
    }
}

写完测试了下,好使,

你可能注意到第一件事就是HomeController带有@Controller注解,很显然这个注解是用来声明控制器的,但实际上这个注解对Spirng MVC 本身影响不大。

@Controller是一个构造型(stereotype)的注解。它基于@Component注解。在这里,它的目的就是辅助实现组件扫描。因为homeController带有@Controller注解,因此组件扫描器会自动去找到HomeController,并将其声明为Spring应用上下文中的bean。

Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
	String value() default "";
}

其实你可以让HomeController带有@Component注解,它所实现的效果是一样的。但是在表意性上可能差一些,无法确定HomeController是什么组件类型。

HomeController唯一的一个方法,也就是Home方法,带有@RequestMapping注解,他的Value属性指定了这个方法所要处理的请求路径,method属性细化了它所能处理的HTTP方法,在本例中,当收到对‘/’的HTTP GET请求时,就会调用home方法。

home()方法其实并没有做太多的事情,它返回一个String类型的“home”,这个String将会被Spring MVC 解读为要渲染的视图名称。DispatcherServlet会要求视图解析器将这个逻辑名称解析为实际的视图。

鉴于我们配置 InternalResourceViewResolver 的方式,视图名“home”将会被解析为“/WEB-INF/views/home.jsp”

Spittr应用的首页,定义为一个简单的JSP

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
  <head>
    <title>Spitter</title>
    <link rel="stylesheet"
          type="text/css"
          href="<c:url value="/resources/style.css" />" >
  </head>
  <body>
    <h1>Welcome to Spitter</h1>
    <a href="<c:url value="/spittles" />">Spittles</a> |
    <a href="<c:url value="/spitter/register" />">Register</a>
  </body>
</html>

测试控制器最直接的办法可能是构建并部署应用,然后通过浏览器对其进行访问,但是自动化测试可能会给你更快的反馈和更一致的独立结果,所以,让我们编写一个针对HomeController的测试

5.2.1 测试控制器

编写一个简单的类来测试HomoController。

import static org.junit.Assert.*;
import org.junit.Test;

public class HomeControllerTest {
    @Test
    public void testHomePage() throws Exception {
        HomeController controller = new HomeController();
        assertEquals("home",controller.home());
    }
}

在测试中会直接调用home()方法,并断言返回包含 "home"值的String类型。它完全没有站在Spring MVC控制器的视角进行测试。这个测试没有断言当接收到针对“/”的GET请求时会调用home()方法。因为它返回的值就是“home”,所以没有真正判断home是试图的名称。

不过从Spring 3.2开始,我们可以按照控制器的方式进行测试Spring MVC中的控制器了。而不仅仅是POJO进行测试。Spring现在包含了一种mock Spirng MVC 并针对控制器执行 HTTP请求的机制。这样的话,在测试控制器的时候,就没有必要在启动Web服务器和Web浏览器了。

为了阐述如何测试Spirng MVC 容器,我们重写了HomeControllerTest并使用Spring MVC 中新的测试特性。

import org.junit.Test;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

/**
 * Created by guo on 24/2/2018.
 */
public class HomeControllerTest1  {
    @Test                                                             //大家在测试的时候注意静态导入的方法
    public void testHomePage() throws Exception {
        HomeController controller = new






请到「今天看啥」查看全文


推荐文章
正商参略  ·  这叫规矩!懂吗?
8 年前
指尖阅读  ·  他怎么爱你,就怎么睡你!
8 年前