Spring Boot 2+Thymeleaf企业应用实战
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

3.2 Web配置

在Servlet 3规范出来之后,Web项目可以不使用web.xml配置文件。该规范提供了相关注解,可以用来实现web.xml的配置工作,例如Servlet、Listener、Filter等都可以使用注解进行配置。这一节将向大家介绍相关的Web配置。

3.2.1 Servlet配置

新建一个名称为“web-test”的Maven项目,在该项目中只使用“spring-boot-starter-web”依赖。新建启动类,请见代码清单3-6。

代码清单3-6:codes\03\3.2\web-test\src\main\java\org\crazyit\boot\c3\WebApp.java

@SpringBootApplication
@ServletComponentScan
public class WebApp {

    public static void main(String[] args) {
      SpringApplication.run(WebApp.class, args);
    }
}

在启动类中,除了包含原来的SpringBootApplication注解外,还加入了ServletComponentScan注解,这个注解主要用于扫描源码包中的Servlet组件,包括使用@WebServlet、@WebFilter和@WebListener进行修饰的类。接下来,新建一个Servlet,使用@WebServlet进行修饰,请见代码清单3-7。

代码清单3-7:odes\03\3.2\web-test\src\main\java\org\crazyit\boot\c3\web\MyServlet.java

@WebServlet(value = "/servlet")
public class MyServlet extends HttpServlet {
    public MyServlet() {
        System.out.println("my servlet class");
    }

    protected void service(HttpServletRequest arg0, HttpServletResponse arg1)
          throws ServletException, IOException {
        System.out.println("servlet service method");
    }
}

代码清单3-7定义了一个MyServlet,在浏览器中访问http://localhost:8080/servlet,则可以看到这个service方法的执行情况。MyServlet依然继承于HttpServlet,只是使用@WebServlet进行了修饰。该注解主要有以下属性。

name:String类型,配置servlet的名称。

value:String数组,相当于配置了urlPatterns属性。

urlPatterns:String数组,用于配置多个url-pattern,配置方式如下:

@WebServlet(urlPatterns = {"a", "b"})

loadOnStartup:相当于<load-on-startup>元素。

initParams:WebInitParam数组,用于设置Servlet的初始化参数,配置方式如下:

@WebServlet(value = "/servlet", initParams = { @WebInitParam(name = "paramA", value= "angus") })

asyncSupported:等同于Servlet的<async-supported>元素,用于配置该Servlet是否支持异步。

description:等同于<description>元素。

displayName:等同于<display-name>元素。

3.2.2 Listener配置

监听器(Listener)与Servlet一样,使用@WebListener注解进行修饰后,就可以被ServletComponentScan扫描并注册,请见代码清单3-8。

代码清单3-8:codes\03\3.2\web-test\src\main\java\org\crazyit\boot\c3\web\MyListener.java

@WebListener
public class MyListener implements ServletContextListener {

    public void contextInitialized(ServletContextEvent sce) {
      System.out.println("context init");
    }

    public void contextDestroyed(ServletContextEvent sce) {

    }
}

@WebListener注解只有一个value属性,用来描述这个Listener,其使用方法较为简单,在此不再赘述。

3.2.3 Filter配置

使用@WebFliter来修饰一个过滤器(Filter),请见代码清单3-9。

代码清单3-9:codes\03\3.2\web-test\src\main\java\org\crazyit\boot\c3\web\MyFilter.java

@WebFilter(value = "/filter/*")
public class MyFilter implements Filter {

    public void init(FilterConfig filterConfig) throws ServletException {
      System.out.println("my filter init");
    }

    public void doFilter(ServletRequest request, ServletResponse response,
          FilterChain chain) throws IOException, ServletException {
      System.out.println("doFilter method");
      chain.doFilter(request, response);
    }

    public void destroy() {

    }
}

@WebFilter注解主要有以下属性。

filterName:String类型,用于指定过滤器名称。

value:String数组,相当于配置了urlPatterns。

urlPatterns:String数组,用于配置多个url-pattern,等同于<url-pattern>元素。

servletNames:配置过滤器将会在哪些Servlet中使用。

dispatcherTypes:DispatcherType数组,相当于配置了<filter-mapping>的<dispatcher>元素,其取值可以为FORWARD、INCLUDE、REQUEST、ASYNC、ERROR。

除了以上几个属性外,还有initParams、asyncSupported、description与displayName属性,它们的使用方法与@WebServlet一致。

通过上面的例子可以知道,Servlet、Listener与Filter这3个注解基本上与web.xml中的配置一样,只是将XML代码变为注解而已,使用方法较为简单。再次提醒,要想让这3个注解生效,则需要使用ServletComponentScan注解。

3.2.4 构建可部署的war包

前面的所有示例都使用了内嵌的Tomcat服务器,这些项目最终可被打成jar包来运行,每个jar包都可以被看作一个独立的Web服务器。对于传统的Web开发,一般会将Web应用打成一个war包,然后将其部署到Web服务器中运行。Spring Boot也支持传统的部署模式。新建一个Maven项目,其pom.xml文件内容如代码清单3-10所示。

代码清单3-10:codes\03\3.2\war-test\pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
    http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.crazyit.boot.c3</groupId>
    <artifactId>war-test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <build>
        <finalName>war-test</finalName>
    </build>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-tomcat</artifactId>
          <scope>provided</scope>
        </dependency>
    </dependencies>

</project>

注意pom.xml文件中的粗体字部分,该项目最终会被打成一个名称为“war-test”的war包,其所依赖的“spring-boot-starter-tomcat”项目,会由war所在的容器提供。接下来,编写启动类与测试用的控制器,请见代码清单3-11。

代码清单3-11:codes\03\3.2\war-test\src\main\java\org\crazyit\boot\c3\WarApp.java

@SpringBootApplication
@RestController
public class WarApp extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
      return application.sources(WarApp.class);
    }

    public static void main(String[] args) {
      SpringApplication.run(WarApp.class, args);
    }

    @GetMapping("/hello")
    public String hello() {
      return "hello";
    }
}

启动类继承自SpringBootServletInitializer类,这里需要重写父类的configure方法。SpringBootServletInitializer类将会调用configure方法来得到一个SpringApplicationBuilder实例。根据名称可知,这个SpringApplicationBuilder会帮我们创建Spring上下文,实际上它会帮我们创建WebApplicationContext实例,其在创建Spring上下文的过程中,会查找使用了@Configuration注解的配置类,然后对它们进行初始化。

对于启动类,我们可以这样理解:在Eclipse运行main方法时,会使用原来的方式(执行jar包的方式)来启动Web应用(含服务器),如果将项目打成一个war包放到Web服务器上运行,就会创建WebApplicationContext,在创建的过程中,会调用configure方法。另外,父类调用一个方法来实现部分工作,但该方法需要由继承的子类来实现,这种模式是GoF设计模式的一种:模板方法。

编写完启动类和控制器之后,使用命令行工具,进入项目的根目录(codes\03\3.2\ war-test),输入Maven命令对项目进行构建:mvn clean package。执行成功后,到codes\03\3.2\war-test\target目录,可以看到war-test.war,将该包复制到Tomcat的webapps下。启动Tomcat后,访问:http://localhost:8080/war-test/hello,在正常情况下可以看到结果,笔者在Tomcat 8中测试成功,建议使用7.0以上版本的Tomcat。

3.2.5 JSP配置

JSP是传统Web应用最常使用的表现层技术,Spring Boot的官方文档不建议在可执行的jar包中使用JSP,但我们可以在war包里面使用它。新建一个Maven项目,在配置中将其打成一个war包(packaging元素),在pom.xml文件中加入相应的依赖,请见代码清单3-12。

代码清单3-12:codes\03\3.2\jsp-test\pom.xml

<dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.tomcat.embed</groupId>
      <artifactId>tomcat-embed-jasper</artifactId>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
    </dependency>
</dependencies>

前面两个依赖我们之前介绍过,这里重点来看下“tomcat-embed-jasper”,这个包主要用于编译JSP,它同样由容器提供。另外,本例将会使用JSTL标签,因此加入JSTL的依赖。在src/main/resources下新建application.yml,添加以下内容:

spring:
  mvc:
    view:
      prefix: /pages/
      suffix: .jsp

这段内容用于配置Spring MVC视图,本例默认会将JSP文件放到src/main/webapp/ pages目录下。新建启动类与控制器,请见代码清单3-13。

代码清单3-13:codes\03\3.2\jsp-test\src\main\java\org\crazyit\boot\c3\JspApp.java

@SpringBootApplication
@Controller
public class JspApp extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
      return application.sources(JspApp.class);
    }

    public static void main(String[] args) {
      SpringApplication.run(JspApp.class, args);
    }

    @GetMapping("/hello")
    public String hello(HttpServletRequest request) {
      request.setAttribute("name", "angus");
      return "hello";
    }
}

控制器的hello方法会设置名称为name的参数,最后跳转到pages下面的hello.jsp。新建hello.jsp,内容请见代码清单3-14。

代码清单3-14:codes\03\3.2\jsp-test\src\main\webapp\pages\hello.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<c:set var="ctx" value="${pageContext.request.contextPath}" />
<! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
    <head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
      <link rel="stylesheet" href="${ctx}/css/test.css" type="text/css" />
      <script type="text/javascript" src="${ctx}/js/test.js"></script>
      <title></title>
    </head>
    <body>
      <div onClick="myClick()" class="main_text">Hello ${name}</div>
    </body>
</html>

这是一个最简单的JSP文件,在开头声明了JSTL的标签库与ctx变量,该变量用于定位CSS与JS资源。在JSP中使用了一个div元素来显示name参数。本例的项目结构如图3-2所示。

图3-2 项目结构

在Eclipse中运行JspApp类,打开浏览器访问:http://localhost:8080/hello,则可以看到JSP页面的输出。同样地,可以使用命令行工具进入jsp-test目录,执行mvn clean package命令将项目打成一个war包,放到另外的Tomcat容器下运行。在浏览器中访问:http://localhost:8080/jsp-test/hello,可以看到同样的结果。