Java——搭建自己的RESTful API服務器(SpringBoot、Groovy)
這又是一篇JavaWeb相關的博客,內容涉及:
- SpringBoot:微框架,提供快速構建服務的功能
- SpringMVC:Struts的替代者
- MyBatis:數據庫操作庫
- Groovy:能與Java結合的高級語言,底層為Java
- Maven:用於簡化jar包導入和打包
- log4j:日志管理
我們要做的是一個簡單的接口,根據URL請求得到對應的數據,數據格式可以是JSON或者Xml
效果如下:
可以看到,這里使用了Get方法,請求了當前服務器中所有書本信息,並得到了一個JSON格式的結果。
如果需要得到Xml格式,只需要設置請求頭的Accept字段為text/xml或者application/xml即可:
接着,開始我們的項目:
這里使用的是社區版的IDEA,原因很簡單,因為我們根本不需要配置服務器,SpringBoot自帶了Tomcat的支持,所以運行項目只需要運行一個main方法即可。
步驟如下:
- 創建並配置項目
- 編寫項目代碼(MyBatis、SpringMVC)
- 配置Log
- 打包
① 創建並配置項目
a.創建一個Maven項目(省略)
b.修改pom.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <modelVersion>4.0.0</modelVersion> 6 7 <groupId>com.fndroid.javaweb</groupId> 8 <artifactId>springboottest</artifactId> 9 <version>1.0-SNAPSHOT</version> 10 11 <!-- 依賴starter-parent--> 12 <parent> 13 <groupId>org.springframework.boot</groupId> 14 <artifactId>spring-boot-starter-parent</artifactId> 15 <version>1.4.2.RELEASE</version> 16 </parent> 17 18 <dependencies> 19 <!-- 這是一個web項目--> 20 <dependency> 21 <groupId>org.springframework.boot</groupId> 22 <artifactId>spring-boot-starter-web</artifactId> 23 <exclusions> 24 <exclusion> 25 <artifactId>log4j-over-slf4j</artifactId> 26 <groupId>org.slf4j</groupId> 27 </exclusion> 28 </exclusions> 29 </dependency> 30 31 <!-- 從parent項目中出去logging這個包,因為我們使用的是log4j --> 32 <dependency> 33 <groupId>org.springframework.boot</groupId> 34 <artifactId>spring-boot-starter</artifactId> 35 <exclusions> 36 <exclusion> 37 <groupId>org.springframework.boot</groupId> 38 <artifactId>spring-boot-starter-logging</artifactId> 39 </exclusion> 40 </exclusions> 41 </dependency> 42 43 <!-- 引入log4j支持 --> 44 <dependency> 45 <groupId>org.springframework.boot</groupId> 46 <artifactId>spring-boot-starter-log4j</artifactId> 47 <version>1.3.8.RELEASE</version> 48 </dependency> 49 <dependency> 50 <groupId>com.jayway.jsonpath</groupId> 51 <artifactId>json-path</artifactId> 52 <scope>test</scope> 53 </dependency> 54 <!-- groovy支持--> 55 <dependency> 56 <groupId>org.codehaus.groovy</groupId> 57 <artifactId>groovy-all</artifactId> 58 <version>2.4.7</version> 59 </dependency> 60 <!-- 使用Mybatis--> 61 <dependency> 62 <groupId>org.mybatis.spring.boot</groupId> 63 <artifactId>mybatis-spring-boot-starter</artifactId> 64 <version>1.1.1</version> 65 </dependency> 66 <!-- jdbc驅動--> 67 <dependency> 68 <groupId>mysql</groupId> 69 <artifactId>mysql-connector-java</artifactId> 70 <version>6.0.5</version> 71 <scope>runtime</scope> 72 </dependency> 73 <dependency> 74 <groupId>log4j</groupId> 75 <artifactId>log4j</artifactId> 76 <version>1.2.17</version> 77 </dependency> 78 <!-- 支持生成xml --> 79 <dependency> 80 <groupId>com.fasterxml.jackson.dataformat</groupId> 81 <artifactId>jackson-dataformat-xml</artifactId> 82 </dependency> 83 </dependencies> 84 85 <properties> 86 <java.version>1.8</java.version> 87 </properties> 88 89 90 <build> 91 <plugins> 92 <!-- 用於生成jar文件--> 93 <plugin> 94 <groupId>org.springframework.boot</groupId> 95 <artifactId>spring-boot-maven-plugin</artifactId> 96 </plugin> 97 </plugins> 98 </build> 99 100 <repositories> 101 <repository> 102 <id>spring-releases</id> 103 <url>https://repo.spring.io/libs-release</url> 104 </repository> 105 </repositories> 106 <pluginRepositories> 107 <pluginRepository> 108 <id>spring-releases</id> 109 <url>https://repo.spring.io/libs-release</url> 110 </pluginRepository> 111 </pluginRepositories> 112 </project>
這里引入了一些依賴,對應的作用在代碼中已經注釋出來了。注意:使用parent標簽引入父類的所有依賴中,如果有需要的,可以使用exclusion除去,參考31-41行代碼。
同時注意到,這里還引入了groovy的支持,這就使得我們的編譯器可以創建和編寫Groovy代碼。
最后的plugin是用於打包jar,必須要添加,才能使用maven命令對項目進行打包發布。
c.創建application.yml文件
這里創建的可以是properties,但是yml文件更為直觀,而且IDEA能高亮顯示,並且官方的一些demo都是使用yml配置:
mybatis: mapperLocations: classpath:mybatis/*-mapper.xml config: classpath:mybatis/mybatis-conf.xml typeAliasesPackage: com.fndroid checkConfigLocation: false spring: datasource: url: jdbc:mysql://localhost:3306/books?serverTimezone=UTC&useSSL=false username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver
這里配置了mybatis的一些屬性,SpringBoot雖然會默認配置屬性,但是當檢查到用戶配置的時候,會優先使用用戶配置的信息。
這個配置文件會在Application定義中用到。
d.在resources目錄下創建mybatis文件夾,在用於放置mybatis的配置文件以及mapper文件
e.在src/main/java目錄下創建對應的包,分別為dao、controller、service、entity等分別用於存放SpringMVC對應的類
配置完畢后目錄結構:
這里先不用管Application和log4j.properties這兩個文件,后面用到的時候會創建。至此項目就基本搭建完畢了,可以開始編寫代碼了。
② 編寫項目代碼
先說明一點,這里用的是Groovy,相比Java代碼會更加簡單,而且Groovy底層是編譯為Java運行的。
根據功能,現在希望通過下面兩個URL得到對應的結果:
獲取所有書本信息:http://localhost:8080/books
根據id獲取對應書本信息:http://localhost:8080/book/2 (獲取id為2的書本信息)
a.根據數據表,創建對應的實體類Book。在entity包中創建一個名為Book的groovy腳本:
1 package com.fndroid.entity 2 3 import javax.xml.bind.annotation.XmlRootElement 4 5 @XmlRootElement(name = 'book') 6 class Book { 7 int id 8 String title 9 String description 10 String pub_time 11 String author 12 13 Book() { 14 } 15 16 Book(int id, String title, String description, String pub_time, String author) { 17 this.id = id 18 this.title = title 19 this.description = description 20 this.pub_time = pub_time 21 this.author = author 22 } 23 }
這里沒有對類進行修飾,Groovy默認會設定為public,而字段則默認是private,並且,Groovy會默認為private的字段生成setter和getter方法,所以也就不用我們自己寫了。
b.創建controller,在controller對應的包中創建BookController:
1 package com.fndroid.controller 2 3 import com.fndroid.entity.Book 4 import com.fndroid.services.BookServices 5 import org.springframework.web.bind.annotation.PathVariable 6 import org.springframework.web.bind.annotation.RequestMapping 7 import org.springframework.web.bind.annotation.RestController 8 9 import javax.annotation.Resource 10 11 @RestController 12 class BookController { 13 14 @Resource 15 BookService service; 16 17 @RequestMapping('/books') 18 List<Book> getBooks() { 19 service.getBooks() 20 } 21 22 @RequestMapping('/book/{id}') 23 Book getBook(@PathVariable(name = 'id')int id) { 24 service.getBook(id) 25 } 26 }
這是SpringMVC的知識,@RestController表明這個類為RESTful的Controller。
使用@Resource表明通過注入取得BookServices的對象。
@RequestMapping則是表明請求的路徑,根據路徑執行對應的方法。
@PathVariable用於獲取路徑中名為id的值,用作查詢
可以看到這里的方法有返回值類型而沒有return語句,這是Groovy的特性,默認會將最后一個語句作為返回值。
c.創建Services,並定義對應方法:
上面Controller使用到兩個BookService的方法,需要我們對其進行編寫:
1 package com.fndroid.services 2 3 import com.fndroid.entity.Book 4 import com.fndroid.dao.IBookDao 5 import org.springframework.stereotype.Service 6 7 import javax.annotation.Resource 8 @Service 9 class BookService { 10 @Resource 11 IBookDao bookDao; 12 13 List<Book> getBooks() { 14 bookDao.getBooks() 15 } 16 17 Book getBook(int id){ 18 bookDao.getBook(id) 19 } 20 }
@Service表明此類為SpringMVC的服務層,並且通過注解注入了IBookDao的對象。
d.創建Dao接口IBookDao:
1 package com.fndroid.dao 2 3 import com.fndroid.entity.Book 4 import org.springframework.stereotype.Repository 5 6 @Repository 7 interface IBookDao { 8 List<Book> getBooks() 9 Book getBook(int id) 10 }
@Repository表明此類為實體Bean類
接口只需要定義對應的方法即可。
e.根據接口編寫mapper文件,在mybatis文件夾中創建一個book-mapper.xml文件:
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="com.fndroid.dao.IBookDao"> 6 <select id="getBooks" resultType="com.fndroid.entity.Book"> 7 select * from book 8 </select> 9 10 <select id="getBook" resultType="com.fndroid.entity.Book" parameterType="Integer"> 11 select * from book where id = #{id} 12 </select> 13 </mapper>
這里要注意,mapper元素的namespace需要定義為我們Dao對應的全路徑名,接着定義兩個select分別對應我們的兩個方法,id對應方法名,resultType對應返回值,parameterType對應參數,接着在select中編寫SQL語句即可。
注意:這里getBooks雖然會返回多個行,但是resultType依然是Book而不是List,因為MyBatis會幫我們組裝成List。
f.定義mybatis-conf.xml
一般情況下對於MyBatis的配置如別名等會聲明在此文件中:
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE configuration 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-config.dtd"> 5 <configuration> 6 <settings> 7 <setting name="logImpl" value="LOG4J"/> 8 </settings> 9 10 <typeAliases> 11 <typeAlias type="com.fndroid.entity.Book" alias="Book"/> 12 </typeAliases> 13 </configuration>
如果這里定義了Book的別名,則上面的mapper文件可以直接使用"Book"代替"com.fndroid.entity.Book"
g.創建程序的入口Application類:
1 package com.fndroid 2 3 import org.apache.ibatis.session.SqlSessionFactory 4 import org.apache.tomcat.jdbc.pool.DataSource 5 import org.mybatis.spring.SqlSessionFactoryBean 6 import org.mybatis.spring.annotation.MapperScan 7 import org.mybatis.spring.boot.autoconfigure.MybatisProperties 8 import org.springframework.boot.SpringApplication 9 import org.springframework.boot.autoconfigure.SpringBootApplication 10 import org.springframework.boot.context.properties.ConfigurationProperties 11 import org.springframework.context.annotation.Bean 12 import org.springframework.context.annotation.Primary 13 import org.springframework.core.io.support.PathMatchingResourcePatternResolver 14 import org.springframework.jdbc.datasource.DataSourceTransactionManager 15 import org.springframework.transaction.PlatformTransactionManager 16 17 @SpringBootApplication 18 @MapperScan('com.fndroid.dao') 19 class Application { 20 21 static void main(String[] args) { 22 SpringApplication.run(Application.class, args) 23 } 24 25 @Bean 26 @ConfigurationProperties(prefix = 'spring.datasource') 27 DataSource dataSource() { 28 new DataSource() 29 } 30 31 @Bean 32 SqlSessionFactory sqlSessionFactory() throws Exception { 33 def sqlSessionFactoryBean = new SqlSessionFactoryBean() 34 sqlSessionFactoryBean.setDataSource(dataSource()) 35 def resolve = resolver() 36 def mybatisProperties = this.mybatisProperties() 37 sqlSessionFactoryBean.setConfigLocation(resolve.getResource(mybatisProperties.getConfigLocation())) 38 sqlSessionFactoryBean.setMapperLocations(resolve.getResources(mybatisProperties.mapperLocations[0])) 39 sqlSessionFactoryBean.getObject() 40 } 41 42 @Bean 43 @Primary 44 @ConfigurationProperties(prefix = 'mybatis') 45 MybatisProperties mybatisProperties() { 46 new MybatisProperties() 47 } 48 49 @Bean 50 PathMatchingResourcePatternResolver resolver(){ 51 new PathMatchingResourcePatternResolver() 52 } 53 54 @Bean 55 PlatformTransactionManager transactionManager() { 56 new DataSourceTransactionManager(dataSource()) 57 } 58 }
16行@SpringBootApplication注解表明此類為SpringBoot的入口,並且啟動自動配置和組件掃描(掃描controller和service等注解聲明的類)等功能。
17行@MapperScan表明從dao包下面尋找mapper(這里的mapper指的是對應的Dao類)
21-23行定義了一個main方法,這個方法就是程序的入口,這里調用SpringApplication的靜態方法run來啟動一個Spring程序
25-29行通過注解@Bean注入了一個DataSource類型的對象,因為DataSource的屬性需要表明數據庫的連接信息,所以需要添加@ConfigurationProperties注解,這個注解會將我們先前定義的application.yml文件中,對應的屬性配置給這個DataSource對象
31-40行通過@Bean注解來注入SqlSessionFactory對象,這個對象會被Spring容器調用進行數據庫操作,我們要將application.yml中配置的mapper和conf路徑設置到SqlSessionFactoryBean中,最后通過getObject方法返回一個SqlSessionFactory的對象
42-47行則使用@Bean注解取得application.yml文件中對應mybatis的配置信息
54-57行則是將DataSource設置給PlatformTranscationManager,這就可以讓Spring來處理JDBC的事務了
③ 配置Log
其實項目到這里已經可以運行了,但是實際上運行起來控制台並不會有詳細的運行信息輸出,原因是我們在pom.xml中已經除去了默認的logging,也就是logback。如果需要使用logback,很簡單,只需要在resource中添加一個logback的配置文件就可以了。而這里用的是log4j,所以需要在resource中創建log4j.properties文件,這里不能用yml,因為log4j不支持。
1 # 全局配置 2 log4j.rootLogger=INFO, stdout, file 3 # mybatis的配置 4 log4j.logger.com.fndroid.dao.IBookDao=TRACE 5 # 控制台輸出配置 6 log4j.appender.stdout=org.apache.log4j.ConsoleAppender 7 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 8 log4j.appender.stdout.layout.ConversionPattern=%d %5p [%t] - %m%n 9 # 文件輸出配置 10 log4j.appender.file=org.apache.log4j.FileAppender 11 log4j.appender.file.layout=org.apache.log4j.PatternLayout 12 log4j.appender.file.layout.ConversionPattern=%d %5p [%t] - %m%n 13 log4j.appender.file.File=D:/log.log4j 14 log4j.appender.file.ImmediateFlush=true
第2行聲明根Logger輸入的日志類型為INFO,輸出對象為控制台和文件
第4行則是表明對於對應的Dao類,我們希望顯示查詢語句和查詢結果,所以這里是TRACE
第6-8配置控制台輸出,包括顯示布局和格式
第10-14則是文件輸出,包括顯示布局、格式和輸出路徑等
到這里,項目已經可以在終端使用maven命令:mvn spring-boot:run 來運行項目,或者直接使用IDEA運行對應的main方法,可以看到,控制台打印了容器開啟的信息,而D盤中也生成了對應的log.log4j文件:
下面是啟動成功的信息:
使用調試工具或者瀏覽器訪問URL:http://localhost:8080/books
瀏覽器會顯示對應的xml結果文件:
返回控制台,可以看到SQL語句也被輸出了:
這就證明我們的Log配置沒有問題了
注意:如果需要重啟,要先關閉前一個Application,否則會提示端口被占用。
④ 打包
對於SpringBoot項目,打包非常簡單,只需要使用終端輸入:mvn packag 命令即可在項目的target目錄下生成一個jar文件,只需要在服務器環境下使用java -jar xxx.jar命令即可啟動這個SpringBoot項目。