SpringBoot+Spring6入门指南: 使用命令行快速搭建restful web api模板


发布者 ourjs  发布时间 1732180161951
关键字 java 

使用SpringBoot可以快速搭建Spring项目,有如下的优点:

  1. 快速搭建Spring应用,可即大简化spring项目的开发配置
  2. 嵌入Tomcat、Jetty、Undertow,不需要手动配置服务器
  3. 提供starter简化marven/gradle配置、直接声明所需的依赖即可,不再需要手动处理版本冲突和依赖安装
  4. 无需配置xml、通过注释来开发配置: @Component、@Autowired、@Value、@Qualifier、@Scope、@Repository、@Service、@Controller

安装 Spring boot cli

下载解压

https://docs.spring.io/spring-boot/installing.html#getting-started.installing.cli

然后添加到环境变量 path 即可

安装完成后命令行查检版本:

spring --version
>spring CLI v3.3.5

Spring boot cli 初始化项目

Spring Boot目前支持jdk17,使用jdk21构建后,运行项目目前会报错。

通过命令行创建spring web项目,默认使用gradle来管理项目依赖。

spring init --dependencies=web --packaging=jar --java-version=17 --group=com.ourjs springwebapi

gradle同样是android/ react-native的默认依赖管理器。

创建后,运行一下,首次运行会自动下载依赖。

··· ./gradlew bootRun ···

如果在IDE中,找到 @SpringBootApplication 注解的类,点击运行即可。

添加 Controller

可通过 @Controller @Service @Autowired 等装饰器注释实现controller注册、以及service、dto、dao对象的自动注入。 这与 node.js的nest.js、python fastapi、C# webapi 等框架非常类似:

比如创建一个 HelloController:

  1. HelloController.java应该位于Spring Boot应用程序的主类(通常是带有@SpringBootApplication注解的类)所在的包或其子包中。这是因为Spring Boot默认只会扫描主类所在包及其子包中的组件。
  2. HelloController.java应该包含@RestController或@Controller注解,以及用于映射HTTP请求的注解(如@GetMapping, @PostMapping等)

如下例所示,通过 @RestController、 @Autowired、@GetMapping("/hello") 来进行类型声明和依赖注入

package com.ourjs.springwebapi.controllers;

import com.onceoa.springwebapi.services.HelloWorldService;
import com.onceoa.springwebapi.services.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

//声明它是一个 controller, 不需要额外配置
@RestController
public class HelloWorldController {
    private final HelloWorldService helloWorldService;
    private final UserService userService;

    //通过 Autowired 实现自动注入,不需要再配置xml或进行类型绑定
    @Autowired
    public HelloWorldController(
        HelloWorldService helloWorldService,
        UserService userService
    ) {
        this.helloWorldService = helloWorldService;
        this.userService = userService;
    }

    //声明一个get方法
    @GetMapping("/hello")
    public String Hello() {
        return helloWorldService.getHello();
    }
}

添加 Service

添加 Service 也非常简单,用 @Service 注释即可。通过与 @Autowired 的配合,该service实例可自动注入到controller构造函数中

package com.ourjs.springwebapi.services;

import org.springframework.stereotype.Service;

@Service
public class HelloWorldService {
    public String getHello() {
        return "Hello world service";
    }
}

添加接口层也很方便,比如创建UserService接口、接口实现类为UserServiceImpl:

package com.ourjs.springwebapi.services;

public interface UserService {
    public String getHello(String user1, String user2);
}

接口实现类UserServiceImpl使用 @Service 装饰即可,不需要额外配置实现类和接口的手动绑定。

package com.ourjs.springwebapi.services.impls;

import com.onceoa.springwebapi.services.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    public String getHello(String user1, String user2) {
        return String.format("This is %s %s from user Service!", user1, user2);
    }
}

这样一个spring rest api项目即搭建完成。

按功能模块重构

使用装饰器构建的spring项目重构也非常简单。 比如 UserController、UserService、UserServiceImpl、UserDto 这些文件分散在这些包下面:

package com.ourjs.springwebapi.controllers;
package com.ourjs.springwebapi.services;
package com.ourjs.springwebapi.services.impls;
package com.ourjs.springwebapi.dto;

我们可以按功能模块划分的原则将这些相关文件都放到 com.ourjs.springwebapi.user 这个包下面。

实现所有相关功能放到一个文件夹、包里。只需要更改 package 声明和文件位置即可。目录结构如下:

com.ourjs.springwebapi.user
    UserController.java
    UserDto.java
    UserService.java
    UserServiceImpl.java

按功能模块划分的另一个好处是同一个包下面的类引用不再需要import导入。 下面的例子同样演示如何通过装饰器获取 PathVariable RequestParam 和 json 的接收和返回

package com.onceoa.springwebapi.user;

//同一个包下,不需要引用
//import com.onceoa.springwebapi.user.UserService;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/user")
public class UserController {
    UserService userService;

    public UserController(
            UserService userService
    ) {
        this.userService = userService;
    }

    /*
    const res = await fetch('/user/create', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ name: "kris z", age: 30 }),
    })
    console.log(await res.json()) //result age+1: { name: "kris z", age: 31 }
    * */
    @PostMapping("/create")
    public UserDto createUser(
            @RequestBody UserDto userDto
    ) {
        userDto.setAge(userDto.getAge() + 1);
        return userDto;
    }

    @GetMapping("/hello/{user}")
    public String HelloUser(
            @PathVariable String user,
            @RequestParam(name = "user", required = false, defaultValue = "") String user2
    ) {
        return userService.getHello(user, user2);
    }
}

Getting Started

Reference Documentation

For further reference, please consider the following sections:

Guides

The following guides illustrate how to use some features concretely:

Additional Links

These additional references should also help you: