第6章 Spring Boot

6.1 简介

Spring Boot的设计目的是用来简化Spring应用的初始搭建以及开发过程,使用Spring Boot可以创建独立的Spring应用,简化了Maven配置,而且内嵌了Tomcat可以直接部署jar文件。

6.2 STS

在项目开发初期先在本地开发,测试或上线时再部署到服务器,首先确保本地环境安装了Java,然后到 https://spring.io/tools 下载开发Spring Boot项目的IDE,或者读者可以选择自己熟悉的IDE,本书采用STS讲解。

STS下载解压之后可以直接运行而且会自动使用本地的Java运行时环境,如果没有匹配好,可以在STS的Window > Preferences > Installed JREs里添加本地JDK,前提时本地环境已经安装Java环境。

6.3 创建项目

在STS中 File > New > Spring Starter Project来创建一个新项目。

5-1.jpg

选择项目所需的依赖,WebJPAMySQL Finish后STS会自动拉取项目依赖的jar包,稍微耗时耐心等待。

5-2.jpg

6.4 配置项目

此时项目仍然是无法启动的,因为创建项目时选择了JPA依赖,它是一个ORM框架,使用它必须要有可连接的数据库。找到配置文件src/main/resources/application.properties,添加下面的数据库配置

spring.datasource.url=jdbc:mysql://rm-2zenrqfr9iy0vbw17uo.mysql.rds.aliyuncs.com/test?useSSL=false
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

右键选中项目,Run AS > Spring Boot App就可以启动项目,因为Spring Boot内置了Tomcat所以不需要配置Server即可让项目运行起来,并可一个通过8080端口访问。

5-3.jpg

6.5 响应请求

src/main/java下创建新的包cn.mx.starter.controller,并在cn.mx.starter.controller下创建新的Class:IndexController.java

package cn.mx.starter.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class IndexController {

    @GetMapping("/")
    private String index() {
        return "Spring Boot";
    }
}

打开浏览器在地址栏输入 http://127.0.0.1:8080,即可收到到服务器返回的字符串:Spring Boot。

6.6 读写数据库

JPA

Java持久化API是一个将对象映射为关系数据库的标准技术,包含了Hibernate、Spring Data和Spring ORM等依赖,本书不想在此涉及太多JPA的细节,直接讲解如何使用。

Entity

在第4章创建了2个表: useraddress,分别创建这两个表对应的两个实体,并放在包cn.mx.starter.model下:

User

package cn.mx.starter.model;

import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Table(name = "user")
@Entity
public class User {

    @Id
    @GeneratedValue
    private Long id;
    
    @Column(nullable = false)
    private String name;
    
    @Column(nullable = false)
    private Integer age;
    
    @OneToMany()
    private List
addresses; // Setter Getter }

Address

package cn.mx.starter.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Table(name = "address")
@Entity
public class Address {
    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false)
    private String addr;
    
    @ManyToOne()
    private User user;
    // 防止序列化JSON时循环引用
    @JsonIgnore
    public User getUser() {
        return user;
    }
    // Setter Getter
}

Address实体里的getUser()方法多了注解@JsonIgnore,该注解是为了解除User和Address序列化时循环引用,即序列化User时调用getAddresses(),而每一个Address序列化又调用getUser(),互相循环调用直至内存异常。读者可以尝试去掉该注解体会一下。

Repository

JPA提供了非常便捷的接口访问数据库,而且默认内置了很多方法直接读取数据库,比如findById。这里创建一个 UserRepository放在包cn.mx.starter.repository下:

package cn.mx.starter.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import cn.mx.starter.model.User;

public interface UserRepository extends JpaRepository {

}

Controller

IndexController增加新的访问路径/users返回数据库查询数据,使用注解@Autowired注入UserRepository

package cn.mx.starter.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import cn.mx.starter.model.User;
import cn.mx.starter.repository.UserRepository;

@RestController
public class IndexController {

    @Autowired
    UserRepository userRepository;
    
    @GetMapping("/")
    private String index() {
        return "Spring Boot";
    }
    
    @GetMapping("/users")
    private List users() {
        return userRepository.findAll();
    }
}

浏览器访问http://127.0.0.1:8080/users会返回查询数据的JSON格式:

[
  {
    id: 1,
    name: "john",
    age: 0,
    addresses: [
      {
        id: 1,
        addr: "朝阳区亚运村路"
      },
      {
        id: 2,
        addr: "学院路北京大学"
      }
    ]
  }
]

内置查询方法

调用http://127.0.0.1:8080/users/1可以查找id=1的用户。

//IndexController

@GetMapping("/users/{id}")
private User user(@PathVariable(name="id") Long id) {
    return userRepository.findById(id).orElse(null);
}

自定义查找方法

调用http://127.0.0.1:8080/users/?name=john可以查找name=join的用户。

//IndexController

@GetMapping("/users/")
private List usersByName(@RequestParam(name="name") String name) {
    return userRepository.findByName("john");
}

因为findByName不是JPA内置方法,所以需要在UserRepository添加这个方法:

//UserRepository

public interface UserRepository extends JpaRepository {
    List findByName(String name);
}

插入数据

终端里调用命令curl -X POST http://127.0.0.1:8080/users插入一个新的用户。

//IndexController

@PostMapping("/users")
private User postUser() {
    Address addr = new Address();
    addr.setAddr("学院路中关村");
    User user = new User();
    user.setName("Jack");
    user.setAge(10);
    user.setAddresses(Arrays.asList(addr));
    addr.setUser(user);
    userRepository.save(user);
    return user;
}

更新数据

//IndexController

@PutMapping("/users/{id}")
private User putUser(@PathVariable(name="id") Long id) {
    User user = userRepository.findById(id).orElse(null);
    if (user != null) {
        user.setName("Sara");
        userRepository.save(user);
    }
    return user;
}

打印SQL

使用JPA可以方便的用操作Java对象的方式操作数据库,如果想核对数据库SQL尤其是复杂查询对应的的SQL,可以在控制台打印出每次数据操作的的SQL语句,在配置文件添加如下配置:

spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.type=trace

至此,一个简单的Spring Boot项目已经完成,连接数据库并对数据进行增删改查。JPA查询有一套内置的查找规则映射到对应的SQL查询,详情可以查阅 https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation。

该项目中我们在Controller层直接调用了Repository层访问数据,实际项目业务逻辑会比较复杂,可以在中间添加Service层专门处理业务逻辑。实际项目的复杂之处在于,业务需求复杂,从而对应的数据库表之间的关联关系就复杂,处理好表之间的关联关系,捋清业务逻辑,剩下的技术层面无非是对数据库表的增删改查。

6.7 部署项目

项目完成之后,需要将项目打包放到服务器上测试。STS已经内置了Maven所以打包非常方便,右键项目 Run AS > Maven install,会将整个项目打成jar包并放在target目录下,默认是starter-0.0.1-SNAPSHOT.jar

5-4.jpg

因为Spring Boot内置了Tomcat并一起打包到jar文件里,所以可以直接在终端运行它:

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

把打包好的jar文件传到服务器上/root目录下,scp是SSH附带的命令,通过SSH协议拷贝本地文件到远程服务器:

scp -i ~/.ssh/mx.pem target/starter-0.0.1-SNAPSHOT.jar [email protected]:/root

登录远程服务器,并且保证该服务器的网络安全组协议里开通了8080端口

ssh -i ~/.ssh/mx.pem [email protected]

运行项目,此时便可以通过IPhttp://59.110.173.162访问项目了:

java -jar starter-0.0.1-SNAPSHOT.jar

6.8 后台运行

在服务器上java -jar starter-0.0.1-SNAPSHOT.jar可以让项目运行起来,比可以通过地址正常访问,但是一旦退出远程登录则该java进程的服务就停止了,因为该服务是运行在前台。使用CentOS的Systemd来让项目可以运行在系统后台。

  1. 添加一个Systemd服务文件

    vim /etc/systemd/system/starter.service

  2. 写入如下内容,保存后退出

[Unit]
Description=starter
After=syslog.target

[Service]
ExecStart= /usr/bin/java -jar /root/starter-0.0.1-SNAPSHOT.jar

[Install]
WantedBy=multi-user.target

之后就可以通过systemctl启动、关闭和重启项目了

启动服务:

systemctl start starter.service

停止服务:

systemctl stop starter.service

服务状态:

systemctl status starter.service

开机启动:

systemctl enable starter.service

查看项目日志:

journalctl -u starter.service

你可能感兴趣的:(第6章 Spring Boot)