本博客示例代码均来自
[美] Graig Walls 著的《SpringBoot实战》 丁雪丰译
相比繁琐的Spring配置,SpringBoot的使用给人恍若隔世的感觉;如果你接触过大数据,你也一定很烦恼,大数据环境配置基本都要搞一天,才能接触到业务。而SpringBoot的自动装配、起步依赖大大简化了配置,让你不必为这些环境性的东西花费过多时间。在配置上花费过多时间,其实并无太多意义。
用SpringBoot实现HelloWorld,最简单的方式就是安装一下Spring CLI,然后用Groovy写个Hello World! 这个过程,我才头一次感受到:这才是真的简单。
说实话,就寡人所见,没遇到过比这入门更简单的程序了…
源码地址:
https://github.com/cmhhcm/my2020.git
//里面有多个项目,用myspringboot_gradle即可。
目录结构:
.
├── HELP.md
├── build.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── cmh
│ │ └── readinglist
│ │ ├── Book.java
│ │ ├── BookController.java
│ │ ├── BookRepository.java
│ │ ├── Reader.java
│ │ ├── ReaderRepository.java
│ │ ├── ReadingListApplication.java
│ │ └── SecurityConfig.java
│ └── resources
│ ├── application.properties
│ ├── static
│ │ └── style.css
│ └── templates
│ └── readingList.html
└── test
└── java
└── com
└── cmh
└── readinglist
└── DemoApplicationTests.java
具体文件作用就不在赘述了,参考书本即可。
1、最核心的思想是:自动配置、起步依赖
简单理解就是把之前繁琐的各种xml配置,打包起来,让你可以通过引入类似org.springframework.boot:spring-boot-starter-web这样的“Wrapper”,一键式自动帮你导入相关的包,否则你需要在项目管理工具中一个一个配置,而且还要配置版本;
自动配置会根据你引入的starter包自动加载相关配置;如果你用java的方式写了相关配置(写一个类,上面加上@Configuration,实现对应逻辑),那么就优先用你写的;优先级永远是你自定义的最高;
2、Spring Initializr
还有比这更好的新建工程的方式嘛?模板都给你提供好。
这里介绍了四种方式初始化一个项目:
3、用Thymeleaf替换JSP
自己做点东西,怎能离开前端?JSP的话需要掌握JSTL等语法,这种视图是一种新的,之前不知道的;
4、启动项目有多种方式
5、条件化配置
之所以能自动配置,是因为默认加载一些配置文件的类加有条件化的注解,满足条件后才会加载默认的配置:
eg:
@ConditionOnMissingBean
缺少一个bean才会生效,如果你自定义了,那么你的优先,默认就失效了。优先级顺序类似Gradle的config: --local的配置 > --system > – global
6、自定义配置
7、安装sping boot CLI的四种方式
- sdk
- Macprots
这2种方式是新接触的,尤其是SDK的方式非常好,可以自由切换版本。
8、jpa的简化
人家自动实现18种常见的应用,一般的需求只用写接口即可,都不用实现。个人所见,其实每个Entity都至少少不了这样几个jpa层的接口:
CURD如下:
Entity save(Entity entity);
Entity update(Entity entity);
void del(Long id);
Entity getById(Long id);
List<Entity> getByIds(Set<Long> ids);
List<Entity> getBy....();//其他各种业务逻辑
不知道你重复写过多少次这种逻辑呢? 这种重复如果不思考底层实现(框架都会写好),实际并没有啥意义,对技术的成长也没什么实质性帮助,都是一些样本代码。所以人家封装好18种常用的,我们只用扩展不常用的即可。
不上点代码,感觉像写作文.
代码流程就按照实现顺序来写,来个面包屑吧:
新建一个SpringBoot initializr(IDEA -> New Project -> Spring Initializr)
选择实例所需starter:web、jdbc、jap、H2(自带数据库)、thymeleaf(新建的时候如果未选择,那么直接在build.gradle新增compile或者implementation即可)
⇒ 实体Entity Book
⇒ 实体接口:BookRepository
⇒ Controller
⇒ 页面readingList.html(H5)
⇒ 静态样式style.css
⇒ 配置文件
包括负责自动配置和条件化配置的各种的starter
plugins {
id 'org.springframework.boot' version '2.2.5.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'java'
}
group = 'com.cmh'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
// compile 'org.springframework.boot:spring-boot-starter-security'
runtimeOnly 'com.h2database:h2'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
test {
useJUnitPlatform()
}
package com.cmh.readinglist;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
/**
* @author: meice Huang
* @date: 2020/3/22 下午5:42
*/
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String reader;
private String isbn;
private String title;
private String author;
private String description;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getReader() {
return reader;
}
public void setReader(String reader) {
this.reader = reader;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
package com.cmh.readinglist;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
/**
* @author: meice Huang
* @date: 2020/3/22 下午5:55
*/
public interface BookRepository extends JpaRepository<Book, Long> {
List<Book> findByReader(String reader);
}
package com.cmh.readinglist;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.List;
/**
* @author: meice Huang
* @date: 2020/3/22 下午5:59
*/
@Controller
@RequestMapping("/readingList")
public class BookController {
private BookRepository bookRepository;
@Autowired
public BookController(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
@RequestMapping(value = "/{reader}", method = RequestMethod.GET)
public String readersBooks(@PathVariable("reader") String reader, Model model) {
List<Book> readingList = bookRepository.findByReader(reader);
if (readingList != null) {
model.addAttribute("books", readingList);
}
return "readingList";
}
@RequestMapping(value = "/{reader}", method = RequestMethod.POST)
public String addToReadingList(@PathVariable(value = "reader") String reader, Book book) {
book.setReader(reader);
bookRepository.save(book);
return "redirect:/readingList/{reader}";
}
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Reading List</title>
</head>
<body>
<h2>书单列表</h2>
<div th:unless="${#lists.isEmpty(books)}">
<dl th:each="book: ${books}">
<dt class="bookHeadline">
<span th:text="${book.title}">书名</span> by
<span th:text="${book.author}">作者</span>
(ISBN: <span th:text="${book.isbn}">ISBN</span>)
</dt>
<dd class="bookDescription">
<span th:if="${book.description}"
th:text="${book.description}">描述</span>
<span th:if="${book.description eq null}">暂无描述</span>
</dd>
</dl>
</div>
<div th:if="${#lists.isEmpty(books)}">
<p>暂无书单</p>
</div>
<hr/>
<h3>新增一本书</h3>
<form method="post">
<label for="title">书名:</label>
<input type="text" name="title" size="50"> </input><br/>
<label for="author">作者:</label>
<input type="text" name="author" size="50"></input><br/>
<label for="description">描述:</label><br/>
<textarea name="description" cols="80" rows="5"></textarea><br/>
<input type="submit">
</form>
</body>
</html>
注意thymeleaf语法。
application.properties
server.port=8000