Spring Boot入门学习笔记

209 阅读6分钟

Spring Boot入门学习笔记

参考Spring快速入门指南

第一个Spring Boot 项目

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController // 告诉Spring,这个代码描述应该可在网上的端点
public class DemoApplication {

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

  @GetMapping("/hello")
  // @RequestParam告诉Spring期望name请求中的值
  public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
    	return String.format("Hello %s!", name);
  }
}

构建RESTful Web服务

RESTful: URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操作(简单理解)。

Tip 另一个解释

看Url就知道要什么 看http method就知道干什么 看http status code就知道结果如何

1. Spring 初始化

Initializr提供了一种快速的方法来提取应用程序所需的所有依赖关系,并为您完成许多设置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>rest-service</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>rest-service</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

2. 创建资源类

package com.example.restservice;

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;
	}
}

3. 创建控制器 处理http请求

package com.example.restservice;

import java.util.concurrent.atomic.AtomicLong;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
// 
@RestController
public class GreetingController {

	private static final String template = "Hello, %s!";
	private final AtomicLong counter = new AtomicLong();

	@GetMapping("/greeting")
	public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
		return new Greeting(counter.incrementAndGet(), String.format(template, name));
	}
}

4. 总结

  1. @GetMapping批注确保将HTTP GET请求/greeting映射到该greeting()方法,

Tip

其他HTTP动词也有伴随注释(例如@PostMappingPOST)。@RequestMapping它们都有一个注释,它们都源自这些注释,并且可以用作同义词(例如@RequestMapping(method=GET);

  1. @RequestParam将查询字符串参数的值绑定name到方法的name参数greeting()

  2. @RestController注释,该注释将类标记为控制器,其中每个方法均返回域对象而不是视图。这是同时包含@Controller和的简写@ResponseBody。

  3. @SpringBootApplication 是一个方便注释,它添加了以下所有内容:

@Configuration:将类标记为应用程序上下文的Bean定义的源。

@EnableAutoConfiguration:告诉Spring Boot根据类路径设置,其他bean和各种属性设置开始添加bean。例如,如果spring-webmvc在类路径上,则此注释将应用程序标记为Web应用程序并激活关键行为,例如设置DispatcherServlet。

@ComponentScan:告诉Spring在包中寻找其他组件,配置和服务com/example,让它找到控制器。

访问数据库 - MySQL

1. Spring Initializr

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>accessing-data-mysql</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>accessing-data-mysql</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

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

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

2. 创建application.properties文件

在此定义连接属性。

spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/db_example
spring.datasource.username=springuser
spring.datasource.password=ThePassword

3. 创建@Entity模型

package com.example.accessingdatamysql;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity // This tells Hibernate to make a table out of this class
public class User {
  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private Integer id;

  private String name;

  private String email;

  public Integer getId() {
    return id;
  }

  public void setId(Integer id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

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

  public String getEmail() {
    return email;
  }

  public void setEmail(String email) {
    this.email = email;
  }
}

4. 创建Repository

package com.example.accessingdatamysql;

import org.springframework.data.repository.CrudRepository;

import com.example.accessingdatamysql.User;

// This will be AUTO IMPLEMENTED by Spring into a Bean called userRepository
// CRUD refers Create, Read, Update, Delete

public interface UserRepository extends CrudRepository<User, Integer> {

}

5. 创建Control

package com.example.accessingdatamysql;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller // This means that this class is a Controller
@RequestMapping(path="/demo") // This means URL's start with /demo (after Application path)
public class MainController {
  @Autowired // This means to get the bean called userRepository
         // Which is auto-generated by Spring, we will use it to handle the data
  private UserRepository userRepository;

  @PostMapping(path="/add") // Map ONLY POST Requests
  public @ResponseBody String addNewUser (@RequestParam String name
      , @RequestParam String email) {
    // @ResponseBody means the returned String is the response, not a view name
    // @RequestParam means it is a parameter from the GET or POST request

    User n = new User();
    n.setName(name);
    n.setEmail(email);
    userRepository.save(n);
    return "Saved";
  }

  @GetMapping(path="/all")
  public @ResponseBody Iterable<User> getAllUsers() {
    // This returns a JSON or XML with the users
    return userRepository.findAll();
  }
}

6. 创建Application 类

package com.example.accessingdatamysql;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AccessingDataMysqlApplication {

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

}

访问数据库 - JPA

1. Spring Initializr

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>accessing-data-jpa</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>accessing-data-jpa</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2. 定义Entity

package com.example.accessingdatajpa;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Customer {

  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private Long id;
  private String firstName;
  private String lastName;

  protected Customer() {}

  public Customer(String firstName, String lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  @Override
  public String toString() {
    return String.format(
        "Customer[id=%d, firstName='%s', lastName='%s']",
        id, firstName, lastName);
  }

  public Long getId() {
    return id;
  }

  public String getFirstName() {
    return firstName;
  }

  public String getLastName() {
    return lastName;
  }
}

3.定义Simple Queries

package com.example.accessingdatajpa;

import java.util.List;

import org.springframework.data.repository.CrudRepository;

public interface CustomerRepository extends CrudRepository<Customer, Long> {

  List<Customer> findByLastName(String lastName);

  Customer findById(long id);
}

4. 创建Application 类

package com.example.accessingdatajpa;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class AccessingDataJpaApplication {

  private static final Logger log = LoggerFactory.getLogger(AccessingDataJpaApplication.class);

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

  @Bean
  public CommandLineRunner demo(CustomerRepository repository) {
    return (args) -> {
      // save a few customers
      repository.save(new Customer("Jack", "Bauer"));
      repository.save(new Customer("Chloe", "O'Brian"));
      repository.save(new Customer("Kim", "Bauer"));
      repository.save(new Customer("David", "Palmer"));
      repository.save(new Customer("Michelle", "Dessler"));

      // fetch all customers
      log.info("Customers found with findAll():");
      log.info("-------------------------------");
      for (Customer customer : repository.findAll()) {
        log.info(customer.toString());
      }
      log.info("");

      // fetch an individual customer by ID
      Customer customer = repository.findById(1L);
      log.info("Customer found with findById(1L):");
      log.info("--------------------------------");
      log.info(customer.toString());
      log.info("");

      // fetch customers by last name
      log.info("Customer found with findByLastName('Bauer'):");
      log.info("--------------------------------------------");
      repository.findByLastName("Bauer").forEach(bauer -> {
        log.info(bauer.toString());
      });
      // for (Customer bauer : repository.findByLastName("Bauer")) {
      //  log.info(bauer.toString());
      // }
      log.info("");
    };
  }

}

5. 总结

Tip

  1. @Entity 实体
  2. @Table对应的表名字
  3. @Id对象的ID
  4. @GeneratedValue以指示应该自动生成ID。
  5. @SpringBootApplication 是一个方便注释,它添加了以下所有内容:
    @Configuration:将类标记为应用程序上下文的Bean定义的源。
    @EnableAutoConfiguration:告诉Spring Boot根据类路径设置,其他bean和各种属性设置开始添加bean。例如,如果spring-webmvc在类路径上,则此注释将应用程序标记为Web应用程序并激活关键行为,例如设置DispatcherServlet。
    @ComponentScan:告诉Spring在包中寻找其他组件,配置和服务com/example,让它找到控制器。

6. Spring Data Jpa提供的接口

  1. findBy + 属性名(首字母大写) + 查询条件

Tip

findByNameLike(String name) findByName(String name) findByNameAndAge(String name, Integer age) findByNameOrAddress(String name)

2.@Query注解的查询和更新

    /**
      * SQL nativeQuery的值是true 执行的时候不用再转化
      * @param name
      * @return
      */
@Query(value = "SELECT * FROM table_user WHERE name = ?1", nativeQuery = true)
    List<User> findByUsernameSQL(String name);
    /**
     * 基于HQL (Hibernate 查询语言)
     * @Modifying DELETE和UPDATE操作的时候必须加此注解
     * @param name
     * @param id
     * @return
     */
@Query("Update User set name = ?1 WHERE id = ?2")
    @Modifying
    int updateNameAndId(String name, Integer id);

3.CrudRepository添加了对数据的增删改查的方法 继承了Repository Crud: 增删改查

>增删
>save(S):S
>saveAll(Iterable<S>): Iterable<S>
>查
>findById(ID): Optional<T>
>findAll():Iterable<T>
>findAllById(Iterable<ID>):Iterable<T>
>
>existsById(ID): boolean
>count():long
>删
>deleteById(ID): void
>delete(T):void
>deleteAll(Iterable<?extends T>):void
>deleteAll(): void
  1. PagingAndSortingRepository 继承了CrudRepository

  2. JPARepository: 继承了PagingAndSortingRepository接口

Tip

JPARepository优点: 对继承父接口中方法的返回值进行了适配,因为在父类接口中通常都返回迭代器,需要我们自己进行强制类型转化。而在JpaRepository中,直接返回了List

  1. JpaSpecificationExecutor 单独存在的,需要配合这JpaRepository一起使用
/**
 * JpaSpecificationExecutor是单独存在的,需要配合这JpaRepository一起使用
 */
@Repository
public interface UserJpaSpecificationExecutor extends JpaSpecificationExecutor<User>, JpaRepository<User, Integer> {
}
>findOne(Specification<T>):Optional<T>
>findAll(Specification<T>):List<T>
>findAll(Specification<T>,Pageable)
>findAll(Specification<T>, sort): List<T>
>count(Specification<T>): long
/**
*多条件查询
*
* Predicate封装了单个查询条件
* @param root 对查询对象属性的封装,比如我们这里是查询User,因此root可以看成是User
* @param query CriteriaQuery封装了查询中的各部分信息, Select from order
* @param builder CB查询条件的构造器
* @return
*/
List<AccountEntity> accountEntityList = accountRepository.findAll((root, query, builder) -> {
            Predicate predicate = builder.like(root.get("name"), "%" + searchTerm + "%");
            Predicate predicate1 = builder.notEqual(root.get("type"), "Manufacturer");
            return builder.and(predicate, predicate1);
        }, PageRequest.of(0, 10)).getContent();