用弹簧启动创建网络应用程序


本指南将帮助您使用Spring Boot创建一个简单的网络应用程序。我们将开发一个简单的应用程序,具有登录功能以及显示todos列表的功能。我们将遵循使用JSP作为视图的MVC模式。

网络应用概述

我们将建立一个具有基本登录功能的待办事项页面(未格式化)。

文件

下面的截图显示了一个eclipse项目,其中包含了我们将要创建的所有文件。

Image

所有文件的简要概述:

  • LoginService, TodoService-包含业务逻辑。LoginService对用户id和密码进行简单的硬编码验证。TodoService包含一个检索todos列表的服务方法。
  • login.jsp, welcome.jsp, list-todos.jsp-该名称清楚地解释了每个视图包含的内容。
  • LoginController, TodoController-在MVC模式中充当控制器。逻辑控制器有一点流量。如果用户输入有效的用户id和密码组合,他们将被重定向到欢迎页面。否则,登录页面将显示错误消息。
  • pom.xml-重要的依赖关系是春季启动入门网站和Tomcat-embedded-jasper。我们稍后将讨论这些。
  • application.properties-这通常用于在Spring Boot中配置框架。在本例中,我们将在application.properties中配置视图解析器。

应用程序的截屏

登录页面

Image

如果用户输入了无效的用户标识和密码,则进入登录页面

Image

欢迎页面

Image

列出待办事项页面

Image

用Spring Initializr引导网络应用程序

用Spring Initializr创建一个网络应用程序是小菜一碟。我们将使用春季网络MVC作为我们的网络框架。

弹簧初始化器http://start.spring.io/是引导您的Spring Boot项目的好工具。

Image

如上图所示,我们需要执行以下步骤:

  • 启动弹簧初始化器并:
    • 选择com.in28minutes.springboot作为集团。
    • 选择student-services作为神器。
    • 从以下依赖项中选择:
      • Web
      • 执行机构
      • DevTools
  • 单击Generate Project。
  • 将项目导入到Eclipse中。

项目依赖关系

Spring Boot Starter Web提供了开发Web应用程序所需的所有依赖关系和自动配置。我们应该使用第一个依赖项。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

我们想使用JSP作为视图。Spring Boot Starter网站的默认嵌入式servlet容器是tomcat。为了支持JSP,我们需要添加一个对Tomcat-embedded-jasper的依赖。

<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <scope>provided</scope>
</dependency>


春季开机启动程式网页相依性

下面的截图显示了由于Spring Boot Starter Web而添加到我们的应用程序中的不同依赖关系。

Image


依赖性可分为:

  • 弹簧核心,豆类,上下文,应用
  • 网络MVC(春季MVC)
  • 杰克逊-为JSON绑定
  • 验证——休眠验证器,验证应用编程接口
  • 嵌入式Servlet容器——Tomcat
  • 日志记录-日志返回,slf4j

任何典型的web应用程序都会使用所有这些依赖关系。春季开机启动网站预装了这些。作为一名开发人员,我不需要担心这些依赖性或者它们的兼容版本。

自动配置

春季开机网络自动配置我们需要开始的基本东西。为了理解Spring Boot Starter Web引入的特性,让我们将StudentServicesApplication.java作为一个Java应用程序运行,并查看日志。

Mapping servlet: 'dispatcherServlet' to [/]

Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)

Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]


春季开机启动网站自动配置:

  • Dispatcher Servlet。
  • 错误页面。
  • Web Jars来管理您的静态依赖关系。
  • 嵌入式Servlet容器——Tomcat是默认的。

配置视图解析器

我们将在/WEB-INF/jsp/中拥有我们的jsp。我们需要用前缀和后缀配置视图解析器。

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp


登录控制器

  • public String showLoginPage(ModelMap model):映射到登录获取方法,此方法显示登录页面。
  • @Autowired LoginService service:LoginService具有验证逻辑。
  • showWelcomePage(ModelMap model, @RequestParam String name, @RequestParam String password映射到登录后方法,此方法验证用户id和密码。如果登录成功,重定向到欢迎页面。
package com.in28minutes.springboot.web.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;

import com.in28minutes.springboot.web.service.LoginService;

@Controller
@SessionAttributes("name")
public class LoginController {

    @Autowired
    LoginService service;

    @RequestMapping(value="/login", method = RequestMethod.GET)
    public String showLoginPage(ModelMap model){
        return "login";
    }

    @RequestMapping(value="/login", method = RequestMethod.POST)
    public String showWelcomePage(ModelMap model, @RequestParam String name, @RequestParam String password){

        boolean isValidUser = service.validateUser(name, password);

        if (!isValidUser) {
            model.put("errorMessage", "Invalid Credentials");
            return "login";
        }

        model.put("name", name);
        model.put("password", password);

        return "welcome";
    }

}


登录服务

具有身份验证的基本逻辑。硬编码的业务逻辑。

package com.in28minutes.springboot.web.service;

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

@Service
public class LoginService {

    public boolean validateUser(String userid, String password) {
        // in28minutes, dummy
        return userid.equalsIgnoreCase("in28minutes")
                && password.equalsIgnoreCase("dummy");
    }

}


登录视图- JSP

带有用户id和密码表单字段的简单登录页面。如果模型中填充了错误消息,${errorMessage}将显示身份验证失败错误消息。

<html>

<head>
<title>First Web Application</title>
</head>

<body>
    <font color="red">${errorMessage}</font>
    <form method="post">
        Name : <input type="text" name="name" />
        Password : <input type="password" name="password" /> 
        <input type="submit" />
    </form>
</body>

</html>


欢迎视图——JSP

成功验证时会显示欢迎页面。显示登录用户的名称和管理todos的链接。

<html>

<head>
<title>First Web Application</title>
</head>

<body>
    Welcome ${name}!! <a href="/list-todos">Click here</a> to manage your todo's.
</body>

</html>


待办事项模型和业务服务

我们使用一个基本的待办事项,包括id、用户、描述和目标日期。

package com.in28minutes.springboot.web.model;

import java.util.Date;

public class Todo {
    private int id;
    private String user;
    private String desc;
    private Date targetDate;
    private boolean isDone;

//Getters, Setters, Constructors, toString, equals and hash code
} 

我们的待办事项服务使用一个简单的数组列表来存储待办事项列表。它提供了一种检索todos的方法。

package com.in28minutes.springboot.web.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.springframework.stereotype.Service;

import com.in28minutes.springboot.web.model.Todo;

@Service
public class TodoService {
    private static List<Todo> todos = new ArrayList<Todo>();
    private static int todoCount = 3;

    static {
        todos.add(new Todo(1, "in28Minutes", "Learn Spring MVC", new Date(),
                false));
        todos.add(new Todo(2, "in28Minutes", "Learn Struts", new Date(), false));
        todos.add(new Todo(3, "in28Minutes", "Learn Hibernate", new Date(),
                false));
    }

    public List<Todo> retrieveTodos(String user) {
        List<Todo> filteredTodos = new ArrayList<Todo>();
        for (Todo todo : todos) {
            if (todo.getUser().equals(user)) {
                filteredTodos.add(todo);
            }
        }
        return filteredTodos;
    }
}


列表Todos - JSP

这是显示我们待办事项列表的页面。这是一个完全没有格式的页面。在接下来的步骤中,我们将美化这个页面并创建更多的功能,以便您可以添加、删除和更新todos。

<html>

<head>
<title>First Web Application</title>
</head>

<body>
    Here are the list of your todos:
    ${todos} 
    <BR/>
    Your Name is : ${name}
</body>

</html>

待办事项控制器

Todo控制器有一个简单的方法来检索Todo列表并将其填充到模型中。它重定向到列表-todos视图。

package com.in28minutes.springboot.web.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;

import com.in28minutes.springboot.web.service.LoginService;
import com.in28minutes.springboot.web.service.TodoService;

@Controller
@SessionAttributes("name")
public class TodoController {

    @Autowired
    TodoService service;

    @RequestMapping(value="/list-todos", method = RequestMethod.GET)
    public String showTodos(ModelMap model){
        String name = (String) model.get("name");
        model.put("todos", service.retrieveTodos(name));
        return "list-todos";
    }
}


运行应用程序

我们使用一个春季启动应用程序类来启动我们的应用程序。

package com.in28minutes.springboot.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan("com.in28minutes.springboot.web")
public class SpringBootFirstWebApplication {

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

完整的代码在我的Github repository。您可以下载Step12.zip并将其作为Maven项目导入,以便能够运行它。

您可以将它作为一个简单的Java应用程序运行。当您运行它时,您应该会看到应用程序正在启动。下面是一些日志摘录。您可以看到所有的请求映射都已正确映射。您可以通过http://localhost:8080/login启动该应用程序,并输入28分钟/虚拟的用户id/密码组合。


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.4.3.RELEASE)

2017-01-30 10:02:01.775  INFO 6070 --- [  restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2017-01-30 10:02:01.798  INFO 6070 --- [  restartedMain] o.apache.catalina.core.StandardService   : Starting service Tomcat
2017-01-30 10:02:01.800  INFO 6070 --- [  restartedMain] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.6
2017-01-30 10:02:02.498  INFO 6070 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2017-01-30 10:02:02.498  INFO 6070 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 3747 ms
2017-01-30 10:02:02.803  INFO 6070 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]
2017-01-30 10:02:03.557  INFO 6070 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/login],methods=[GET]}" onto public java.lang.String com.in28minutes.springboot.web.controller.LoginController.showLoginPage(org.springframework.ui.ModelMap)
2017-01-30 10:02:03.559  INFO 6070 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/login],methods=[POST]}" onto public java.lang.String com.in28minutes.springboot.web.controller.LoginController.showWelcomePage(org.springframework.ui.ModelMap,java.lang.String,java.lang.String)
2017-01-30 10:02:03.559  INFO 6070 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/list-todos],methods=[GET]}" onto public java.lang.String com.in28minutes.springboot.web.controller.TodoController.showTodos(org.springframework.ui.ModelMap)
2017-01-30 10:02:03.564  INFO 6070 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-01-30 10:02:03.565  INFO 6070 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-01-30 10:02:03.615  INFO 6070 --- [  restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-01-30 10:02:03.616  INFO 6070 --- [  restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-01-30 10:02:03.682  INFO 6070 --- [  restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-01-30 10:02:04.108  INFO 6070 --- [  restartedMain] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2017-01-30 10:02:04.288  INFO 6070 --- [  restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-01-30 10:02:04.307  INFO 6070 --- [  restartedMain] c.i.s.web.SpringBootFirstWebApplication  : Started SpringBootFirstWebApplication in 7.204 seconds (JVM running for 9.191)