SpringBoot入门和使用实践

SpringBoot入门和使用实践

一、软件环境

  • JDK 1.8+
  • Maven 3.2.5+
  • PostMan (www.getpostman.com)

二、简介

  • Springboot角色
Spring Cloud(构建Spring Boot的分布式环境)
 |
Spring Boot(快速构建Spring的应用)
   |
Spring Framework (底层,Java EE框架)
  • Spring Boot 2.x.x 新特性
编程语言:Java 8+、Kotlin
底层框架:Spring Framework
全新特性:Web Flux(传统Spring应用使用标签或注解来描述请求或响应的映射,web flux支持声明式、函数式编程)
  • 为什么选择Web Flux
函数编程:Java 8 Lambda
响应编程:Reactive Streams(java 9 Flow API、Reactive Extensions-RXjava、Reactor)
异步编程:Servlet 3.1 或 Asyc NIO
  • 2.0 特性
  1. 自动装配:MVC、JDBC、事务等组件的装配

  2. 内置容器:Tomcat、Jetty等

  3. DevOps:针对生产的开发运维模式

三、使用

1、第一个springboot项目

  1. 编写 Rest 程序
  2. 运行 Spring Boot 应用
  3. 使用 HTTP 请求工具:PostMan
  4. 场景说明:
  • 定义用户模型,包括属性:用户ID和名称
  • 客户端发送 Post 请求,创建用户 (Web MVC)
  • 客户端发送 GET 请求,获取所有用户(Web Flux)
  • Map 存储数据
1)进入 start.spring.io
  1. Project 选择 Maven Project
  2. Language 选择 Java
  3. Spring Boot 选择 2以上的版本
  4. Group 填写:com.test
  5. Artifact 填写:first-app-demo
  6. Depencies 填写:Reactive Web
  7. 点击 Generate Project 下载项目
2)解压项目,使用 IDEA 加载项目
3)创建文件夹和类
  1. domain文件夹,创建User类,定义id和name属性(get\set\toString)
package com.test.firstappdemo.domain;

/**
 *
 * 用户模型
 * */
public class User {
    private int id;
    private String name;

    public int getId() {
        return id;
    }
    
    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
  1. repository文件夹,创建UserRepository类(@Repository、Java doc注释、public boolean save(User user) 、ConcurrentMap<Interger,User>、AtomicInteger)
package com.test.firstappdemo.repository;

import com.test.firstappdemo.domain.User;
import org.springframework.stereotype.Repository;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * {@link User} {@link @Repository}
 * */
@Repository
public class UserRepository {

    //内存型保存方式
    private final ConcurrentMap<Integer, User> userRepostory = new ConcurrentHashMap<>();
    private final static AtomicInteger idGenerator = new AtomicInteger();

    /**
     * 保存对象
     * @param user {@link User} 对象
     * @return 如果保存成功,返回<code>true</code>
     *          否则,返回<code>false</code>
     * */
    public boolean save(User user){
        //从1开始
        Integer id = idGenerator.incrementAndGet();
        user.setId(id);
        return userRepostory.put(id, user) == null;
    }
}

  1. controller文件夹,创建UserController类(@RestController、构造器注入UserRepository、@PostMapping、public User save(@RequestParam String name))
package com.test.firstappdemo.controller;

import com.test.firstappdemo.domain.User;
import com.test.firstappdemo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    // 注入用户仓储,构造器注入好处:不能修改,提前初始化
    private UserRepository userRepository;
    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @PostMapping("/person/save")
    public User save(@RequestParam String name){
        User user = new User();
        user.setName(name);
        if(userRepository.save(user)){
            System.out.printf("用户对象:%s 保存成功.\n", user);
        }
        return user;
    }
}

4) 运行启动类
  • 启动类名称:<项目名称+Application>,debug启动(启动后可查看Spring Boot版本和PID,web flux默认使用Netty容器进行启动)

  • PostMan:POST请求 【http://localhost:8080/person/save】 ;属性设置 name=zcheng

5)GET请求,查询所有用户
  • UserRepository
package com.test.firstappdemo.repository;

import com.test.firstappdemo.domain.User;
import org.springframework.stereotype.Repository;

import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * {@link User} {@link @Repository}
 * */
@Repository
public class UserRepository {

    //内存型保存方式
    private final ConcurrentMap<Integer, User> userRepostory = new ConcurrentHashMap<>();
    private final static AtomicInteger idGenerator = new AtomicInteger();

    /**
     * 保存对象
     * @param user {@link User} 对象
     * @return 如果保存成功,返回<code>true</code>
     *          否则,返回<code>false</code>
     * */
    public boolean save(User user){
        //从1开始
        Integer id = idGenerator.incrementAndGet();
        user.setId(id);
        return userRepostory.put(id, user) == null;
    }

    public Collection<User> values() {
        return userRepostory.values();
    }
}

  • UserController
package com.test.firstappdemo.controller;

import com.test.firstappdemo.domain.User;
import com.test.firstappdemo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collection;

@RestController
public class UserController {

    // 注入用户仓储,构造器注入好处:不能修改,提前初始化
    private UserRepository userRepository;
    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @PostMapping("/person/save")
    public User save(@RequestParam String name){
        User user = new User();
        user.setName(name);
        if(userRepository.save(user)){
            System.out.printf("用户对象:%s 保存成功.\n", user);
        }
        return user;
    }

    @GetMapping("/person/findAll")
    public Collection<User> findAll(){
        return userRepository.values();
    }
}
  • PostMan:GET请求【http://localhost:8080/person/findAll】
6)实现 Web Flux
  • spring 官网介绍 1.8章 Reactive Libraries
  • 传统NIO实现的Reactor模式,是同步非阻塞,Spring的Reactor是Reactive的实现,是异步非阻塞
  • Mono表示(0:1)的对象,类似Java 8的 Optional,防止空指针,查询 Mono 到 1.5.1 HandlerFunction
  • Flux表示(0:N)的对象,类似一个集合,空集合或包含很多元素
  • MVC使用@RequestMapping进行映射,Web Flux 使用函数式编程声明接口,Spring 5之后将Servlet接口进行封装
  • 通过路由函数定义类似@RequestMapping的映射
package com.test.firstappdemo.config;

import com.test.firstappdemo.domain.User;
import com.test.firstappdemo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Collection;

/**
 * 路由器函数
 * */
//从Spring 3开始逐渐使用Configuration代替xml文件
@Configuration
public class RouterFunctionConfiguration {

    /**
     * Servlet:
     * 请求接口:ServletRequest 或者 HttpServletRequest
     * 响应接口:ServletResponse 或者 HttpServletResponse
     * Spring 5.0 重新定义了服务的请求和响应:
     * 请求接口:ServerRequest
     * 响应接口:ServerResponse
     * 请求和响应接口既支持Servlet的规范,也可以自定义规范,比如:Netty(Web Server)
     * Reactive中的Flux 或 Mono 它是异步处理(非阻塞)
     * 集合对象基本上是同步处理(阻塞)
     * Flux 或 Mono 都是 Publisher(发布者)推模式来推送数据
     * Web Flux通过异步的方式提高吞吐量
     * 1.5 Functional Endpoints 介绍函数式的端点(Rest暴露)
     * 1.5.2 RouterFunction 查看例子
     * */

    /**
     * 场景:
     * 定义GET请求,并且返回所有的用户对象 URL:/person/find/all
     * 依赖仓储对象,@Autowired 可以不加,只是表明 仓储是方法注入
     *
     * */
    @Bean
    @Autowired
    public RouterFunction<ServerResponse> personFindAll(UserRepository userRepository){
        // 定义映射关系,一般s结尾都是静态类或工具类,lamda表达式,request是方法参数
        // HandlerFunction参数是ServerRequest,返回Mono
        return RouterFunctions.route(RequestPredicates.GET("/person/find/all"), request -> {
            // 获取所有对象
            Collection<User> users = userRepository.values();
            //集合对象转Flux对象
            Flux<User> userFlux = Flux.fromIterable(users);
           return ServerResponse.ok().body(userFlux, User.class);
        });
    }

}

2、构建方式

  • 图形化构建:http://start.spring.io
  • Maven
  1. Apache Maven官网:http://maven.apache.org/archetype/maven-archetype-plugin/generate-mojo.html

    // interactiveMode=false表示非交互式

  2. Windows -> CMD窗口:mvn archetype:generate -DinteractiveMode=false -DgroupId=com.test -DartifactId=first-app-demo -Dversion=1.0.0-SNAPSHOT

    // 查看文件目录

    $ dir

  3. https://spring.io/guides/gs/rest-service/ 找到 Build with Maven,复制 pom.xml 配置

    // IDEA 弹窗 Enable Auto Import

    // 默认生成的jUnit测试工具,去掉版本号,因为Spring的父工程中已经存在版本控制

  4. 然后配置启动类和控制类,和之前的内容一样

3、多模块项目

  • 重构
  • 调整主(父)工程(由jar变为子项目的管理)

  • 创建子模块工程()

    模块层:model(domain)

    持久层:presistence(repository)

    表示层:web(controller)

  • 子模块依赖管理()

  • 具体操作
  1. 修改pom.xml(有可能最后删除src时,IDEA会自动添加,所以这一步可以尝试忽略)

    pom

  2. 创建 maven 子模块

    a. web -> presistence -> model 由高往低创建

    b. 项目名称 -> New -> Module -> 不选择archetype -> artifactId填写 web -> Finish

    c. 如果web的src中java和resources未标记文件夹类型(没问题的直接跳过)

    • java 文件夹 -> 右键 -> Mark Directory as -> Sources Root
    • resources 文件夹 -> 右键 -> Mark Directory as -> Resources Root
    • test 文件夹 -> 右键 -> Mark Directory as -> Test Sources Root

    d. 迁移代码

    • 子模块创建 java 文件夹创建 com.test(这一步要看IDEA版本给不给直接拖到)

    • 选择父项目的 java 下的内容 com.xxx.xxx 拖到 web 子模块的 java文件夹中

    • Move everything from

    • Yes -> Continue

    • 选择父项目的 resources 下的内容,拖到 web 子模块的 resources文件夹中

    • 删除父项目的src文件夹

    • 运行启动类

    • 接下来根据上面步骤,把其它子模块也进行重构

    • presistence pom.xml 设置 model 依赖;复制model pom.xml

    • web pom.xml 设置 presistence 依赖;复制presistence pom.xml

    • IDEA 头部菜单 -> Build -> Build Project -> 运行启动类

  • 微服务中应用的服务职责或权限职责要单一

4、打包和运行

  • 打包方式
  • 构建 JAR 包
  • 构建 WAR 包
  • 构建 Main-Class
1)构建 jar 包
  • 父pom.xml文件添加main-class:(进入启动类 -> 选中类名右键 -> copy Reference)

    <build>
    	<plugins>
    		<plugin>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-maven-plugin</artifactId>
    			<configuration>
     <mainClass>com.test.firstappdemo.FirstAppDemoApplication</mainClass>
    			</configuration>
    		</plugin>
    	</plugins>
    </build>
    
  • 将上面父pom.xml 内容剪切到web子模块的pom.xml中

    // 跳过测试,更新第三方包

  • cmd窗口(IDEA Terminal):项目名称 -> 右键 -> copy path -> cd 项目路径 -> mvn -Dmaven.test.skip -U clean package

  • 或者 使用IDEA右侧菜单的Maven Projects的LifeCycle

  • cmd窗口(IDEA Terminal):cd web -> cd target -> java -jar web-0.0.1-SNAPSHOT.jar

2) 构建 war 包
  • web子模块添加目录 src/main/webapp/WEB-INF/web.xml

  • web pom.xml文件新增或修改

    // 默认jar

    <packaging>war<packaging>
    
  • cmd窗口(IDEA Terminal):cd web -> cd target -> java -jar web-0.0.1-SNAPSHOT.war

3) 运行模式
  • IDEA 方式(开发调试)
  • JAR/WAR 方式(一般线上)
  • Maven 插件方式(极端)
  1. cmd窗口(IDEA Terminal):项目根目录 -> mvn -Dmaven.test.skip -U clean install

  2. cmd窗口(IDEA Terminal):cd web -> mvn spring-boot:run

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

趴着喝可乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值