《Spring Boot in Action》【2. 开发第一个应用】
来源:互联网 发布:审批工作流数据库设计 编辑:程序博客网 时间:2024/06/01 10:38
2 开发第一个应用
2.1 项目骨架
从本章开始,我们要开发一个简单的reading-list应用,用来维护一个reading-list,包括录入书的信息,查看阅读列表,删除书等操作。
技术上,Spring MVC处理Web请求,Thymeleaf作为模板引擎编写页面,Spring Data JPA操作数据库,使用内置H2数据库,用Gradle管理项目。
使用Spring Initializer生成
生成的项目结构
项目结构符合Gradle或者Maven的一般规范:
- 主代码位于/src/main/java
- 主资源位于/src/main/resources
- 测试代码位于/src/test/java
- 测试资源位于/src/test/resources
ReadingListApplication类有两个作用:主配置类和启动类。尽管Spring Boot自动配置特性能减少许多配置,但是至少需要有一个配置类来激活自动配置,@SpringBootApplication注解组合了其他三个有用的注解:
- Spring的@Configuration注解,指派该类成为配置类
- Spring的@ComponentScan注解,激活组件扫描功能,因此Web控制器类(@Controller)以及其他组件(如@Component,@Service等)可以自动注册为Spring application context中的beans
- Spring Boot的@EnableAutoConfiguration注解,激活自动配置
如何运行呢?有三种方法:
1. 直接运行
如果你在IDEA里,直接右键ReadingListApplication.java,点击Run就可以运行了(多亏了main函数)
2. Gradle或Maven
使用Spring Boot Gradle Plugin提供的bootRun task:
gradle bootRun
或者Maven goal:
mvn spring-boot:run
3. 打包运行
gradle buildjava -jar build/libs/readinglist-0.0.1-SNAPSHOT.jar
正常情况下应用启动,访问localhost:8080,不过目前还没有Controller,所以会是HTTP 404 Not Found
注:如果有其他的配置,建议放到其他的@Configuration配置类中,独立于ReadingListApplication类
测试
ReadingListApplicationTests类是测试类:
package readinglist;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration;import readinglist.ReadingListApplication;@RunWith(SpringJUnit4ClassRunner.class)@SpringApplicationConfiguration(classes = ReadingListApplication.class)@WebAppConfigurationpublic class ReadingListApplicationTests { @Test public void contextLoads() { }}
在一般的Spring测试类中,你都会用注解@ContextConfiguration
来加载Spring应用上下文,不过在Spring Boot测试类中,你用注解@SpringApplicationConfiguration
来代替。此类目前只有contextLoads()一个测试方法,用来验证ReadingListApplication
这个配置类是否没有问题。
配置应用属性
你可以在application.properties文件中加入一行:
server.port=8000
这样内置Tomcat服务器就会监听8000端口了(默认是8080)。这个文件自动会被载入,不用我们管。
如何构建
Spring Boot为Gradle何Maven提供了构建插件,以Gradle为例:
buildscript { ext { springBootVersion = '1.3.5.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") }}apply plugin: 'java'apply plugin: 'idea'apply plugin: 'spring-boot'jar { baseName = 'readinglist' version = '0.0.1-SNAPSHOT'}sourceCompatibility = 1.8targetCompatibility = 1.8repositories { mavenCentral()}dependencies { compile('org.springframework.boot:spring-boot-starter-data-jpa') compile('org.springframework.boot:spring-boot-starter-thymeleaf') compile('org.springframework.boot:spring-boot-starter-web') runtime('com.h2database:h2') testCompile('org.springframework.boot:spring-boot-starter-test') }task wrapper(type: Wrapper) { gradleVersion = '1.12'}
构建插件的主要作用是能把所有依赖包打进一个user-JAR包,并且加入了manifest,使之能够用java -jar运行。
上面的依赖都没有指定版本,因为starter的版本和Spring Boot的版本是一样的,你可以使用gradle dependencies(或mvn dependency:tree)来查看项目的依赖版本。
如果你想排除starter中的某个传递性依赖,比如Jackson JSON library(from web starter),你可以exclude它:
compile("org.springframework.boot:spring-boot-starter-web") { exclude group: 'com.fasterxml.jackson.core'}
类似的,如果你想用另一个版本的Jackson,也是可以的,但是Gradle和Maven的传递性依赖解析机制是不一样,在Maven中,总是选择最近的依赖(直接依赖优先级高于传递性依赖),所以直接引入一个Jackson依赖就可以了,它会覆盖传递性依赖,在Gradle中则不同,Gradle会选择更高版本的依赖,所以如果你选择的Jackson版本高于starter中的版本,那没什么问题,如果低于starter中的版本,那就必须先像上面一样exclude掉了。
2.2 写代码
定义领域对象
package readinglist;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;@Entitypublic 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; // getters and setters}
@Entity定义了这是一个JPA实体类,@Id指定了这个实体的identity,@GeneratedValue说明这个字段会自动生成。
定义Repository接口
package readinglist;import java.util.List;import org.springframework.data.jpa.repository.JpaRepository;public interface ReadingListRepository extends JpaRepository<Book, Long> { List<Book> findByReader(String reader);}
只需要定义一个继承Spring Data JPA的JpaRepository的接口,ReadingListRepository继承了18个通用的持久化操作,JpaRepository的两个参数Book和Long,分别指明了domain类型和这个domain的id类型,我们添加了一个findByReader方法,提供一个reader的名字,就能找出相关的Book列表,不用担心,当应用启动的时候,Spring Data会自动实现这个接口,你什么也不用做。
定义Spring MVC Controller
package 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;@Controller@RequestMapping("/")public class ReadingListController { @Autowired private ReadingListRepository readingListRepository; @RequestMapping(value = "/{reader}", method = RequestMethod.GET) public String readersBooks(@PathVariable("reader") String reader, Model model) { List<Book> readingList = readingListRepository.findByReader(reader); if (readingList != null) { model.addAttribute("books", readingList); } return "readingList"; } @RequestMapping(value = "/{reader}", method = RequestMethod.POST) public String addToReadingList(@PathVariable("reader") String reader, Book book) { book.setReader(reader); readingListRepository.save(book); return "redirect:/{reader}"; }}
编写页面
readersBooks()方法返回一个逻辑视图名“readingList”,所以我们在src/main/resources/templates目录下建一个readingList.html,内容如下:
<html> <head> <title>Reading List</title> <link rel="stylesheet" th:href="@{/style.css}"></link> </head> <body> <h2>Your Reading List</h2> <div th:unless="${#lists.isEmpty(books)}"> <dl th:each="book : ${books}"> <dt class="bookHeadline"> <span th:text="${book.title}">Title</span> by <span th:text="${book.author}">Author</span> (ISBN: <span th:text="${book.isbn}">ISBN</span>) </dt> <dd class="bookDescription"> <span th:if="${book.description}" th:text="${book.description}">Description</span> <span th:if="${book.description eq null}"> No description available</span> </dd> </dl> </div> <div th:if="${#lists.isEmpty(books)}"> <p>You have no books in your book list</p> </div> <hr/> <h3>Add a book</h3> <form method="POST"> <label for="title">Title:</label> <input type="text" name="title" size="50"></input><br/> <label for="author">Author:</label> <input type="text" name="author" size="50"></input><br/> <label for="isbn">ISBN:</label> <input type="text" name="isbn" size="15"></input><br/> <label for="description">Description:</label><br/> <textarea name="description" cols="80" rows="5"> </textarea><br/> <input type="submit"></input> </form> </body></html>
添加css
在src/main/resources/static目录下建一个style.css:
body { background-color: #cccccc; font-family: arial,helvetica,sans-serif;}.bookHeadline { font-size: 12pt; font-weight: bold;}.bookDescription { font-size: 10pt;}label { font-weight: bold;}
至此,一个完整的项目就写完了,几乎没有什么配置,我们写的完全都是业务代码。这是如何做到的呢?
Spring Boot会引入一个包spring-boot-autoconfigure,里面有各种Configuration类,Spring Boot利用了Spring 4.0引入的条件配置(conditional configuration)来实现自动配置,你可以自己写条件,只要实现Condition接口,覆盖它的matches()方法即可,比如:
package readinglist;import org.springframework.context.annotation.Condition;import org.springframework.context.annotation.ConditionContext;import org.springframework.core.type.AnnotatedTypeMetadata;public class JdbcTemplateCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { try { context.getClassLoader().loadClass("org.springframework.jdbc.core.JdbcTemplate"); return true; } catch (Exception e) { return false; } }}@Conditional(JdbcTemplateCondition.class)public MyService myService() { // ...}
MyService bean只有在JdbcTemplate类在classpath的情况下才会被创建。
- 《Spring Boot in Action》【2. 开发第一个应用】
- 第一个Spring Boot应用
- 第一个Spring Boot应用
- 第一个Spring Boot应用
- Spring Boot 第一个应用
- 2.玩转Spring Boot 第一个应用Hello World
- Spring Boot配置的第一个应用
- Spring Boot学习笔记-创建第一个Spring Boot应用
- Netty In Action 读书笔记 - 第二章 第一个Netty应用
- Netty in action—第一个Netty应用
- 创建你的第一个Spring Boot应用
- 用Marven构建第一个Spring Boot应用
- Spring Boot配置的第一个应用(如何启动)
- 研磨SpringCloud系列(一)第一个Spring Boot应用
- 部署你的第一个Spring Boot 应用
- SpringBoot学习笔记001--创建第一个spring boot应用
- 第一个Spring Boot应用(Hello World)
- 1.安装和启动第一个Spring Boot 应用
- vue2+axios 增删改查
- Linux 根目录介绍
- 浅谈小程序
- Android点击事件分发
- 496. Next Greater Element I
- 《Spring Boot in Action》【2. 开发第一个应用】
- ArcGIS水文分析实战教程(15)库容和淹没区计算
- centos 安装php7 redis扩展
- matplotlib--3d显示
- Unreal 后期处理材质范例
- 《基于R语言的自动数据收集》--第3章 XML和JSON
- Java并发编程:同步容器
- 详细的JDK安装方式 java开发环境搭建之JDK配置
- 解决com.alibaba.fastjson.JSON返回数据自动把首字母改为小写问题