基于Spring Boot 的Blog开发 原

转载请注明出处:Gaussic

一、引言

之前写过几篇关于利用Spring MVC来开发的博客,从博客下面的评论以及GitHub上的Issues看还是会出现许多的问题,且大部分的问题都出在配置上。虽然说Spring MVC的配置较SSH简化了不少,但是在使用过程中仍然会觉得配置的吃力。

为了进一步简化配置,考虑使用Spring Boot将之前的项目重写,以及对各个模块进行重构。由于是一步步探索的过程,因而在此一步一步记录下来,除了自我学习以外,更方便未来review文档,同时希望能为读者带来一定的便利。

二、Spring Boot

Spring是一套非常大的框架,在这个框架下有许多的子项目,这些项目可以在 https://spring.io/projects 找到,我们需要用到的两个主要项目就是 Spring Framework 和 Spring Data。这些子项目可以被运用到许许多多的场景,随意组合。然而,可能是历史原因,开发者往往会受到框架组合和配置的困扰,一个个的xml文件让人看起来是非常头痛的事情,而且一旦某个部分配置出错,需要花费很长的时间来找出这个错误,这样做效率是极低的。

为了极大的简化配置,甚至达到零配置的可能,Spring团队开发出了 Spring Boot框架,与其说它是一个框架,倒不如它是一个极大降低Spring开发难度的一个应用程序。

下面是官方的介绍:

Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run". We take an opinionated view of the Spring platform and third-party libraries so you can get started with minimum fuss. Most Spring Boot applications need very little Spring configuration. 大致的意思:Spring Boot使我们更加容易地创建一个独立的、生产级的,且可以直接运行的Spring应用。由于它整合了Spring platform和一些三方库的配置,使我们可以做到真正的开箱即用。大多数的Spring Boot应用只需要非常少的Spring配置。

 那它的特征有哪些呢:

  • Create stand-alone Spring applications,创建独立的Spring应用程序
  • Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files),内嵌Tomcat, Jetty或Undertow,不需要部署WAR包
  • Provide opinionated 'starter' POMs to simplify your Maven configuration,提供startet POMs,以简化Maven配置
  • Automatically configure Spring whenever possible,任何时候都可以自动配置Spring
  • Provide production-ready features such as metrics, health checks and externalized configuration,提供产品级特征,例如矩阵、健康检查以及外部化配置
  • Absolutely no code generation and no requirement for XML configuratio,绝对没有代码生成,以及不需要XML配置

有上面这几条就已经足够吸引人了。其他的不用做太多的介绍,直接从代码来看Spring Boot的配置是多么的easy。

三、开发环境

在开发之前,首先交代一下开发环境:

IDE选用IntelliJ IDEA 2016,Spring Tool Suite也是一个好的选择。

JDK使用JDK8。

就这些,不用Tomcat(Spring Boot内嵌),不用Maven(IDEA内嵌)。

四、开始开发Spring Boot应用

4.1 生成初始项目

创建项目的方法有两种,一种是使用官方的SPRING INITIALIZR,另一种是利用IDEA。

4.1.1 使用Spring Initializr生成初始项目

打开 http://start.spring.io/,如下图所示

填写好项目名,所需依赖后(目前只使用Web和JPA,数据库暂时使用内存数据库H2,方便演示),点击生成项目,会生成一个zip包,这就是你的原始项目,解压到指定目录,使用IDEA打开pom.xml:

IDEA会自动下载所有的依赖,这样原始的项目就配置完成了:

4.1.2 使用IDEA生成初始项目

这个过程其实和1.1类似,相当于1.1的本地版本。

打开IDEA,新建项目,选择Spring Initializr,点击Next:

填写项目名,Next:

选择Web、JPA和H2,Next,Finish。

这样就生成了一个和1.1一样的项目。

4.2 开发第一个Spring Restful服务

4.2.1 任务详情

打开 https://spring.io/guides,可以看到Spring官网提供的一些例程,一个例程大约15~30分钟的时间:

选择第一个例程,需要做的如下:

请求 :

http://localhost:8080/greeting

返回:

{"id":1,"content":"Hello, World!"}

请求:

http://localhost:8080/greeting?name=Gaussic

返回:

{"id":1,"content":"Hello, Gaussic!"}

我们需要做的是,发送一个请求,返回JSON格式的数据。Spring-Boot-Web整合了Spring MVC的配置,我们将利用Spring MVC来开发一个简单的Restful服务。

4.2.2 开发

创建model

首先新建一个Greeting类,这是一个POJO,在mvc框架中称之为model,用以保存数据:

package com.gaussic;

/**
 * Created by gaussic on 11/4/2016.
 * model
 */
public class Greeting {

    private final long id;
    private final String content;

    public Greeting(long id, String content) {
        this.id = id;
        this.content = content;
    }

    public long getId() {
        return id;
    }

    public String getContent() {
        return content;
    }
}

创建 controller

controller在mvc框架中是控制层, 它会解析浏览器的请求,并做特定地处理。由于我们需要开发一个简单的Restful API,Spring MVC提供了简单的 @RestController 注解,来标明某个类是一个 Restful Controller,简化Controller的配置,如下:

package com.gaussic;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.atomic.AtomicLong;

/**
 * Created by gaussic on 11/4/2016.
 * controller
 */

@RestController
public class GreetingController {

    private static final String template = "Hello, %s!";  // content 模板
    private final AtomicLong counter = new AtomicLong();  // 自动生成 id

    @RequestMapping("/greeting")
    public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
        return new Greeting(
                counter.incrementAndGet(),    // 自增
                String.format(template, name) // content模板
        );
    }
}

在运行之前,先解释一下这段代码。

首先,@RestController注解规定了GreetingController是一个Restful API的控制器,只返回API相关的数据,如果是普通的@Controller注解,如果在方法上不做特殊的配置,将默认返回一个视图(关于视图在后面会提及)。

其次,@RequestMapping("/greeting")是一个请求映射,当浏览器访问 http://localhost:8080/greeting,是,将会转入这个方法进行处理。

@RequestParam用于获取该请求的参数,当浏览器访问 http://localhost:8080/greeting?name=Gaussic是,将会把参数的值写入name中,此处默认值是World,如果不设置默认值且不传递参数,将会报错。

特别要注意的是,这个方法直接返回了一个Greeting对象,官方的解释是:

As you see in steps below, Spring uses the Jackson JSON library to automatically marshal instances of type Greeting into JSON.

也就是说,Spring会使用Jackson JSON库自动地将这个Greeting对象转化为JSON并返回。这一点非常强大,而且在编写API时是非常有作用的。

4.3 运行Spring Boot

现在所有的开发已经完成,在IDEA中运行Spring Boot非常简单,点击右上角的箭头即可:

在浏览器中访问 http://localhost:8080/greeting,返回json格式数据,刷新之后id会自增:

传入参数name,将返回新的数据:

这样,一个简单的Restful Service开发完成了。

如果需要在外部运行,需要将应用打成jar包。在此可以使用IDEA内部集成的maven进行打包,

点击右端的 Maven Projects,先选择 clean,再选择 package,将会在target文件夹下生成一个.jar文件。

现在,使用:

java -jar target/springblog-0.0.1-SNAPSHOT.jar

运行即可。

在具体的开发之前,对目录结构做一定的调整,如下图所示:

六、模板与URL

6.1 Thymeleaf模板

在上面的示例中展示了使用@RestController和@RequestMapping来处理请求并返回JSON格式数据的方法,在日常的需求中需要使用特定的模板页面来渲染,此时会使用常用的@Controller注解来标注这是一个普通的控制器类。

在pom.xml中引入Thymeleaf来作为模板引擎:

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

我们在src\main\java\com\gaussic\controller中新建MainController类,用来处理网站的几个主要请求:

package com.gaussic.controller;

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

/**
 * Created by dzkan on 2016/11/21.
 * To deal with some main requests.
 */

@Controller
public class MainController {

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

在resources\templates中新建index.html,表示首页:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"/>
    <meta http-equiv="X-UA-Compatible" content="ie=edge"/>
    <title>Document</title>
</head>
<body>
    <h1>这是首页</h1>

</body>
</html>

(在IDEA中有一个小技巧,输入 ! 然后再按Tab键,上面的代码就会自动完成,不过需要将meta的标签闭合(如上所示),其他的还有很多可以发掘,一些基本的标签组合Tab键都能自动补全,用过Sublime text的同学应该会很容易发现。)

重新启动Spring boot,访问 http://localhost:8080,将跳转到我们的首页:

从上面我们可以发现,使用普通的@Controller注解,返回的时候会查找字符串定义的模板页面,如 返回 index,spring boot 会自动的在 resources\templates 下面的 index.html 文件,如果存在嵌套目录,如 blog/list.html,那么只需返回 "blog/list" 即可。

此外,有一点需要极其注意,Thymeleaf遇到标签不闭合的状态会报错,但是部分的html5标签是可以不闭合的,例如<meta> <link> <input>等等,为了让Thymeleaf支持HTML5,需要在application.properties中配置:

spring.thymeleaf.mode=LEGACYHTML5

还需要添加nekohtml依赖:

<dependency>
    <groupId>net.sourceforge.nekohtml</groupId>
    <artifactId>nekohtml</artifactId>
    <version>1.9.22</version>
</dependency>

这样Thymeleaf才能正常的识别HTML5了,否则的话,请保证每一个标签都是闭合的。

6.2 URL映射

我们已经了解,URL的映射主要通过在Controller中定义@RequestMapping来完成。

如6.1中的index()方法:

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

以及4.2中的greeting()方法:

    @RequestMapping("/greeting")
    public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
        return new Greeting(
                counter.incrementAndGet(),    // 自增
                String.format(template, name) // content模板
        );
    }

@RequestMapping默认处理的是GET请求,以上两种情况相当于:

    @RequestMapping(value = "/", method = RequestMethod.GET)
    @RequestMapping(value = "/greeting", method = RequestMethod.GET)

如果是POST请求,可以将method改为 RequestMethod.POST。此外,新版本的Spring MVC提供了更加简化的请求方式:

  • @GetMapping:Get请求,常用于页面访问操作
  • @PostMapping:Post请求,常用于添加等表单操作
  • @PutMapping:Put请求,常用于修改或编辑等表单操作
  • @DeleteMapping:Delete操作,常用于删除操作

这一些将在后面涉及到,我们把这两个方法改为:

    @GetMapping("/")
    @GetMapping("/greeting")

此外,在4.2中使用了@RequestParam来获取参数,其url形式如下:

http://localhost:8080/greeting?name=Gaussic

@RequestParam可以非常轻松地获取以上URL的参数,然而目前大多数流行的网站都使用了Rest风格的参数,以更直观的表达url的意图,例如本文地址:

https://my.oschina.net/gaussik/blog/781773

其结构为  http://xxx.net/{username}/blog/{blogId},这样的结构相比问号的形式更加简洁明了,如果改为旧的方法,如下所示:

https://my.oschina.net?username=gaussic&type=blog&id=781773

当参数越来越多时,阅读起来就不是那么的容易。本文的所有URL都将使用后者。

那么如何获取获取形如:

https://my.oschina.net/gaussik/blog/781773

的参数呢?Spring MVC提供了@PathVariable注解,来获取URL中的路径参数。

以index()方法为例,我们将index()改为如下形式:

    @GetMapping("/{username}/blog/{blogId}")
    public String index(@PathVariable("username") String username,
                        @PathVariable("blogId") String blogId, ModelMap model) {
        model.addAttribute(username);
        model.addAttribute(blogId);
        return "index";
    }

 注意如下几点:

  • 所有的参数用{}包含,再使用@PathVariable来获取
  • 使用ModelMap来向模板页面传递数据

修改index.html,来打印传递过来的数据:

<!doctype html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>这里是首页!</h1>
    <ul>
        <li th:text="${username}">用户名:${username}</li>
        <li th:text="${blogId}">博客id:${blogId}</li>
    </ul>
</body>
</html>

重新启动,访问 http://localhost:8080/gaussic/blog/23333

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java技术栈

Spring Boot 自定义日志详解

Spring Boot 内部代码使用的是 commons-logging 来记录日志的,但是底层日志实现框架是可以随意替换的。Spring Boot为 Java...

1261
来自专栏Java学习网

Spring 3.0支持基于rest的Web服务学习总结

尽管RESTful功能被添加到Spring MVC框架非常早期通过注释和其他API功能,支持基于rest的Web服务是Spring MVC有点晚。几个jax -...

23410
来自专栏我是攻城师

Spring Boot开发之流水无情(二)

3416
来自专栏Jaycekon

Spring-Boot:6分钟掌握SpringBoot开发

 构建项目 从技术角度来看,我们要用Spring MVC来处理Web请求,用Thymeleaf来定义Web视图,用Spring Data JPA来把阅读列表持久...

4356
来自专栏一个会写诗的程序员的博客

《Spring Boot 实战:从0到1》第3章 零XML配置的Spring Boot Application第3章 零XML配置的Spring Boot

Spring Boot 提供了一种统一的方式来管理应用的配置,允许开发人员使用属性properties文件、YAML 文件、环境变量和命令行参数来定义优先级不同...

1574
来自专栏好好学习吧

linux基础学习整理

1084
来自专栏玩转JavaEE

使用Spring Cloud搭建服务注册中心

我们在之前的博客中已经介绍过阿里的分布式服务框架dubbo【Linux上安装Zookeeper以及一些注意事项】【一个简单的案例带你入门Dubbo分布式框架】,...

1.9K4
来自专栏清晨我上码

第四节 微服务OTRS SpringCould使用

1.1. 启动一个服务注册中心,只需要一个注解@EnableEurekaServer,这个注解需要在springboot工程的启动application类上...

1033
来自专栏玩转JavaEE

初识Spring Boot框架

按:最近公众号文章主要是整理一些老文章,主要是个人CSDN上的博客,也会穿插一些新的技术点。 ---- 前面的铺垫文章已经连着写了六篇了,主要是介绍了Sprin...

3815
来自专栏DT乱“码”

Spring的一些注解解析

@Repository、@Service、@Controller 和 @Component 将类标识为Bean spring 自 2.0 版本开始,陆续引入了一...

2049

扫码关注云+社区

领取腾讯云代金券