Spring Boot 入门
Spring Boot
Spring Boot 是一个可以让你轻松创建独立的、生产级的、基于 Spring 的 Web 应用程序。
单模块项目创建
创建一个单模块项目,我们可以使用 https://start.spring.io 网站生成,然后用IDEA打开。
我们也可以直接用IDEA创建。
左侧菜单栏选择 Spring Initializr,然后 Next。
这里我们需要填写项目的Metadata信息1
GroupID 项目组织的唯一标识符,遵循Java包名规则,以反向域名开始。 ArtifactID 项目的唯一标识符,即项目名称。小写字母,不要有特殊字符。 Version 项目版本号,开发阶段使用版本号后接 -SNAPSHOT 方便开发,发布部署后去掉。 Name 项目名称,和 ArtifactID 保持一致。 Package 项目包名,一般为GroupID + ArtifactID。
这里我们可以选择项目依赖,比如Spring Web。它使用Spring MVC框架,Tomcat作为默认嵌入式容器(服务器),并且包含RESTful。 至此,我们就创建好单模块项目了。测试一下吧。 添加Greeting.java
package com.example.demo.controller; 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; } }
GreetingController.java
package com.example.demo.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.atomic.AtomicLong; @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)); } }
最后的目录结构如图 试试在浏览器访问http://127.0.0.1:8080/greeting
多模块项目创建
一般情况下,大中型项目都会划分模块,一方面是为了遵循面向对象设计原则,同时也是因为模块化设计可以提高项目结构清晰度,方便扩展,重用等。那如何划分模块呢,一般根据项目类型决定,没有一定之规。但还是有一些规律可循,比如经典的MVC架构模式,即Model(模型)、View(视图)、Controller(控制器)。对应Spring Web 应用,我一般使用这样的设计及命名:
web web层一般位于应用程序的最上层,也就是入口层,用于处理用户输入及响应。其实就是MVC中的Controller。 service service层位于web层之下,充当事务边界。一般作为公共API。 domain 域模型[fn:2]通常是用于数据库的持久化,在 Java 中,它们通常符合 javabean 规范,即它们具有 get 和 set 方法来表示单个属性和一个无参数的构造函数。是领域驱动设计里的一个重要概念。 dao DAO全称数据访问对象,可以理解为对数据库 CRUD 的操作接口。
这次什么也不用选,因为我们是在创建外层结构。外层pom.xml属于管理和统筹项目信息及依赖,这里不需要Spring Web。或者说放到web模块的pom里更合适些。 删掉 .mvn 目录、 mvnw 及 mvnw.cmd 文件,保留.gitignore,demo.iml,pom.xml。.idea是IDEA编辑器的一些配置信息,也需要保留。src目录,暂时先不要删,我们待会需要将DemoApplication启动文件放到创建好的web模块的包下。这块有个细节要 注意DemoApplication启动文件,也就是主类应该放到根包中,位于其他类之上。它隐式地定义了一个基本的“搜索包”,如果您正在编写一个 JPA 应用程序,@enableautoconfiguration 注释类的包将用于搜索@entity 项。另外如果主类在根包中,不需要指定 basePackage 属性。 依次创建web模块,service模块,domain2模块3,dao模块。为了方便区分,我们在创建时加上前缀如demo-web、demo-service、demo-domain、demo-dao。
如果你现在启动,会发现如下图console所示, 那是因为我们还没有添加 Spring Web 依赖。我们在demo-web下的pom.xml添加
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
再次运行,可以发现tomcat为我们启动了8080端口。如下图。 同样,我们也添加下Greeting.java,GreetingController.java文件测试下。代码可以参照单项目创建示例。 在浏览器访问http://127.0.0.1:8080/greeting?name=Tom
现在其实也还是单模块运行,我们先整理下父pom.xml文件。一步步来。
- 删除 dependencies 标签及其依赖,因为 Spring Boot 提供的父工程已包含,并且父 pom 原则上都是通过 dependencyManagement 标签管理依赖包。
- 删除 build 标签及其中的所有内容。spring-boot-maven-plugin 插件作用是打一个可运行的包,多模块项目仅仅需要在入口类所在的模块添加打包插件,这里父模块不需要打包运行。而且该插件已被包含在 Spring Boot 提供的父工程中,这里删掉即可。
- 配置模块间依赖关系
在父pom文件里添加
<dependencyManagement> <dependencies> <dependency> <groupId>com.example</groupId> <artifactId>demo-web</artifactId> <version>${demo.version}</version> </dependency> <dependency> <groupId>com.example</groupId> <artifactId>demo-service</artifactId> <version>${demo.version}</version> </dependency> <dependency> <groupId>com.example</groupId> <artifactId>demo-dao</artifactId> <version>${demo.version}</version> </dependency> <dependency> <groupId>com.example</groupId> <artifactId>demo-domain</artifactId> <version>${demo.version}</version> </dependency> </dependencies> </dependencyManagement>
注意:为了方便及统一管理各子模块的版本,我们将它定义在properties标签里。通过 ${demo.version} 获取。
<properties> <java.version>1.8</java.version> <demo.version>0.0.1-SNAPSHOT</demo.version> </properties>
根据依赖关系,我们在demo-dao模块的pom文件添加
<dependencies> <dependency> <groupId>com.example</groupId> <artifactId>demo-domain</artifactId> </dependency> </dependencies>
在demo-service模块的pom文件里添加
<dependencies> <dependency> <groupId>com.example</groupId> <artifactId>demo-domain</artifactId> </dependency> <dependency> <groupId>com.example</groupId> <artifactId>demo-dao</artifactId> </dependency> </dependencies>
在demo-web模块的pom文件里添加,这里因为我们已经在之前添加Spring Web依赖了,我们直接把dependency项追加到dependencies项就好。如下:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.example</groupId> <artifactId>demo-service</artifactId> </dependency> </dependencies>
上面子模块中依赖无需添加版本号,它们会从父模块自动查找。
接着,我们测试下通过web层调取service层是否正常。
首先在demo-service层创建com.example.demo.service包,然后创建DemoService接口类及impl目录(用于存放接口实现类),接着创建接口实现类DemoServiceImpl DemoService.java
package com.example.demo.service; public interface DemoService { String test(); }
DemoServiceImpl.java
package com.example.demo.service.impl; import com.example.demo.service.DemoService; import org.springframework.stereotype.Service; @Service public class DemoServiceImpl implements DemoService { @Override public String test() { return "interface test"; } }
这里使用到 @Service 注解,我们需要在demo-service模块的pom.xml依赖项里追加此依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </dependency>
我们打开web层的GreetingController文件,添加:
@Autowired private DemoService demoService; @GetMapping("/test") public String test() { return demoService.test(); }
在浏览器访问 http://127.0.0.1:8080/hello/test 返回 interface test 表明一切正常。
集成MyBatis
在父pom.xml文件添加依赖
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> <scope>provided</scope> </dependency>
添加到dependencyManagement下的依赖属于声明,并不会自动引入,所以需要在子模块下引入。
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
通过mybatis-generator工具生成dao层相关文件,我这里使用的是IDEA插件 MyBatisCodeHelperPro 生成的。使用它需要先用IDEA连接数据库,然后选择表,右键选择Mybatis generator,配置存放位置。
我们在demo-service子模块调用,打开DemoServiceImpl文件,使用 @Autowired 注入,具体如下。
@Autowired private SysDictMapper sysDictMapper; @Override public String test() { SysDict sysDict = sysDictMapper.selectByPrimaryKey(1); return sysDict.toString(); }
这种注入方式已不被推荐,所以也可以这样写
private final SysDictMapper sysDictMapper; public DemoServiceImpl(SysDictMapper sysDictMapper) { this.sysDictMapper = sysDictMapper; } @Override public String test() { SysDict sysDict = sysDictMapper.selectByPrimaryKey(1); return sysDict.toString(); }
在demo-web模块下的resources文件夹下创建属性配置文件: application.properties ,然后添加配置
spring.datasource.driverClassName = com.mysql.cj.jdbc.Driver spring.datasource.url = jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8 spring.datasource.username = root spring.datasource.password = mybatis.mapper-locations = classpath:mybatis/*.xml mybatis.type-aliases-package = com.example.demo.dao.entity
我们运行下发现会报错
Description: Field sysDictMapper in com.example.demo.service.impl.DemoServiceImpl required a bean of type 'com.example.demo.dao.mapper.SysDictMapper' that could not be found. Action: Consider defining a bean of type 'com.example.demo.dao.mapper.SysDictMapper' in your configuration.
解决这个问题有两种方法
- 在SysDictMapper接口增加 @Mapper 注解,确保扫描注册时可以识别到这个接口。
- 在启动类上增加 @MapperScan 注解,并设置搜索包。
@MapperScan("com.example.demo.dao.mapper")
再次启动,访问http://127.0.0.1:8080/hello/test 可以发现我们获取到了数据库内的信息。
多环境属性配置
一般情况,我们都会有【开发】【测试】【正式】环境,所以不同环境间的配置也就不同。我们在上面已经新建了一个 application.properties 配置文件。接下来我们再新建三个配置文件,分别为:
application-dev.properties application-test.properties application-prod.properties
application.properties 为主配置,注意用于环境区分和公共配置。各环境配置文件为各自环境配置。 例如主配置为
server.port = 8080 spring.profiles.active=dev spring.application.name=demo app.id=demo mybatis.mapper-locations = classpath:mybatis/*.xml mybatis.type-aliases-package = com.example.demo.dao.entity
开发环境配置为
spring.datasource.driverClassName = com.mysql.cj.jdbc.Driver spring.datasource.url = jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8 spring.datasource.username = root spring.datasource.password =
配置环境除了properties语法,还有一种yaml语法,看个人喜欢。
另外提醒下在连接mysql后面有一堆参数,一定要知道其含义再使用,否则会带来意想不到的问题
?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false&autoReconnect=true&useAffectedRows=true
比如,useAffectedRows = true ,在判断更新、删除时,稍不注意就会掉坑里。详情可以看当JDBC执行删改时,会返回什么值
Comments:
Email questions, comments, and corrections to hi@smartisan.dev.
Submissions may appear publicly on this website, unless requested otherwise in your email.