Spring Boot 使用 JdbcTemplate
1. 前言
如果我們的項目非常簡單,僅僅是對數(shù)據(jù)庫幾張表進行簡單的增刪改查操作,那么實際上直接使用 JDBC 操作數(shù)據(jù)庫就可以了。
由于 JDBC 中有很多模板代碼,每次都是加載驅動-建立數(shù)據(jù)庫連接-查詢或操作數(shù)據(jù)庫-關閉數(shù)據(jù)庫連接這樣的模板代碼, Spring 提供了 JdbcTemplate 對原生 JDBC 進行了簡單的封裝。
本篇文章,我們來實現(xiàn)一個完整的、基于 Spring Boot + JdbcTemplate + MySQL 的商品管理項目實例。
2. 技術選型
數(shù)據(jù)庫使用 MySQL ,商品信息存儲到商品表內即可。
后端項目使用 Spring Boot ,通過控制器暴露 RESTful 風格的接口供前端調用,通過 JdbcTemplate 實現(xiàn)對數(shù)據(jù)庫的操作。
前端項目使用 Bootstrap 開發(fā),通過 jQuery 提供的 $.ajax 方法訪問后端接口。
3. 數(shù)據(jù)庫模塊實現(xiàn)
只需要一張商品表,保存商品相關的信息即可。我們使用 Navicat 新建數(shù)據(jù)庫 shop ,并在其中新建數(shù)據(jù)表 goods 。
實例:
CREATE TABLE `goods` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一編號',
`name` varchar(255) DEFAULT '' COMMENT '商品名稱',
`price` decimal(10,2) DEFAULT '0.00' COMMENT '商品價格',
`pic` varchar(255) DEFAULT '' COMMENT '圖片文件名',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Tips: 默認值最好不要采用 NULL , NULL 會影響索引的效率,而且在查詢時需要用 is null 或 is not null 篩選,容易被忽略。
4. Spring Boot 后端實現(xiàn)
我們新建一個 Spring Boot 項目,通過 JdbcTemplate 訪問數(shù)據(jù)庫,同時接口依舊采用 RESTful 風格。
4.1 使用 Spring Initializr 創(chuàng)建項目
Spring Boot 版本選擇 2.2.5 ,Group 為 com.imooc
, Artifact 為 spring-boot-jdbctemplate
,生成項目后導入 Eclipse 開發(fā)環(huán)境。
4.2 引入項目依賴
我們引入 Web 項目依賴、熱部署依賴。由于本項目需要訪問數(shù)據(jù)庫,所以引入 spring-boot-starter-jdbc
依賴和 mysql-connector-java
依賴。 pom.xml 文件中依賴項如下:
實例:
<!-- 熱部署 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- jdbc -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- myql驅動 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
4.3 建立項目結構
依次新建以下類結構
- GoodsDo:商品類,對應 goods 商品表;
- GoodsDao:商品數(shù)據(jù)訪問類,用于訪問數(shù)據(jù)庫;
- GoodsService:商品服務類,用于封裝對商品的操作;
- GoodsController:商品控制器類,用于對外提供 HTTP 接口;
- CorsConfig:跨域配置類,允許前端頁面跨域訪問后端接口。
此時項目目錄如下:
4.4 開發(fā)商品類
開發(fā)商品類 GoodsDo ,代碼如下:
實例:
/**
* 商品類
*/
public class GoodsDo {
/**
* 商品id
*/
private Long id;
/**
* 商品名稱
*/
private String name;
/**
* 商品價格
*/
private String price;
/**
* 商品圖片
*/
private String pic;
// 省略get set方法
4.5 開發(fā)商品數(shù)據(jù)訪問類
商品數(shù)據(jù)訪問類 GoodsDao 是本篇的重點,通過注入 JdbcTemplate 類型的組件,實現(xiàn)數(shù)據(jù)庫操作。注入代碼如下:
實例:
/**
* 商品數(shù)據(jù)庫訪問類
*/
@Repository // 標注數(shù)據(jù)訪問類
public class GoodsDao {
@Autowired
private JdbcTemplate jdbcTemplate;
}
由于我們已經(jīng)引入了 spring-boot-starter-jdbc
依賴,所以 Spring Boot 項目已經(jīng)為我們自動配置了 JdbcTemplate 組件,我們拿來即用即可,這就是 Spring Boot 的強大之處!
此時我們啟動應用,發(fā)現(xiàn)報錯信息:
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
此處我們可以再度體會 Spring Boot 強大之處, Spring Boot 在為我們自動配置了 JdbcTemplate 之余,還在嘗試自動為我們配置數(shù)據(jù)源 DataSource ,即 JdbcTemplate 要操作的真實數(shù)據(jù)庫信息。報錯信息已經(jīng)提示我們,沒有合適的數(shù)據(jù)庫驅動、也沒有合適的 URL 屬性。
4.6 配置數(shù)據(jù)源信息
我們只需要通過配置文件指定數(shù)據(jù)源信息, Spring Boot 就可以識別配置,并加載到數(shù)據(jù)源組件中。 JdbcTemplate 也可以自動識別該數(shù)據(jù)源,從而實現(xiàn)對數(shù)據(jù)庫的操作。配置文件信息如下:
實例:
# 配置數(shù)據(jù)庫驅動
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# 配置數(shù)據(jù)庫url
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/shop?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
# 配置數(shù)據(jù)庫用戶名
spring.datasource.username=root
# 配置數(shù)據(jù)庫密碼
spring.datasource.password=123456
需要注意的是,我們在 URL 配置中指定了編碼方式,這樣可以防止出現(xiàn)數(shù)據(jù)庫中文亂碼情況。同時指定了時區(qū)為北京時間所在的東八區(qū)(GMT%2B8),避免因時區(qū)問題導致錯誤。
此時再次啟動 Spring Boot 應用,正常運行,說明我們的數(shù)據(jù)源配置生效了。
4.7 通過 JdbcTemplate 操作數(shù)據(jù)庫
通過 JdbcTemplate 進行增刪改查操作非常簡潔, Spring 官方封裝了原生 JDBC 中冗余的模板代碼,使數(shù)據(jù)庫訪問操作更加簡潔,代碼如下:
實例:
/**
* 商品數(shù)據(jù)庫訪問類
*/
@Repository // 標注數(shù)據(jù)訪問類
public class GoodsDao {
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* 新增
*/
public void insert(GoodsDo goods) {
jdbcTemplate.update("insert into goods(name,price,pic)values(?,?,?)", goods.getName(), goods.getPrice(),
goods.getPic());
}
/**
* 刪除
*/
public void delete(Long id) {
jdbcTemplate.update("delete from goods where id =?", id);
}
/**
* 更新
*/
public void update(GoodsDo goods) {
jdbcTemplate.update("update goods set name=?,price=?,pic=? where id=?", goods.getName(), goods.getPrice(),
goods.getPic(), goods.getId());
}
/**
* 按id查詢
*/
public GoodsDo getById(Long id) {
return jdbcTemplate.queryForObject("select * from goods where id=?", new RowMapper<GoodsDo>() {
@Override
public GoodsDo mapRow(ResultSet rs, int rowNum) throws SQLException {
GoodsDo goods = new GoodsDo();
goods.setId(rs.getLong("id"));
goods.setName(rs.getString("name"));
goods.setPrice(rs.getString("price"));
goods.setPic(rs.getString("pic"));
return goods;
}
}, id);
}
/**
* 查詢商品列表
*/
public List<GoodsDo> getList() {
return jdbcTemplate.query("select * from goods", new RowMapper<GoodsDo>() {
@Override
public GoodsDo mapRow(ResultSet rs, int rowNum) throws SQLException {
GoodsDo goods = new GoodsDo();
goods.setId(rs.getLong("id"));
goods.setName(rs.getString("name"));
goods.setPrice(rs.getString("price"));
goods.setPic(rs.getString("pic"));
return goods;
}
});
}
}
getById 和 getList 方法中使用了匿名內部類,如果不了解的可以先去學習下相關知識。
4.8 開發(fā)商品服務類
商品服務類比較簡單,直接調用 GoodsDao 完成商品服務方法封裝即可。
實例:
/**
* 商品服務類
*/
@Service
public class GoodsService {
@Autowired
private GoodsDao goodsDao;
/**
* 新增商品
*/
public void add(GoodsDo goods) {
goodsDao.insert(goods);
}
/**
* 刪除商品
*/
public void remove(Long id) {
goodsDao.delete(id);
}
/**
* 編輯商品信息
*/
public void edit(GoodsDo goods) {
goodsDao.update(goods);
}
/**
* 按id獲取商品信息
*/
public GoodsDo getById(Long id) {
return goodsDao.getById(id);
}
/**
* 獲取商品信息列表
*/
public List<GoodsDo> getList() {
return goodsDao.getList();
}
}
4.9 開發(fā)商品控制器類
我們還是遵循之前的 RESTful 風格,制定后端訪問接口如下:
動詞 | 接口含義 | 接口地址 |
---|---|---|
GET | 查詢商品(id=1)信息 | http://127.0.0.1:8080/goods/1 |
GET | 查詢商品列表信息 | http://127.0.0.1:8080/goods |
POST | 新增商品 | http://127.0.0.1:8080/goods |
PUT | 修改商品(id=1)信息 | http://127.0.0.1:8080/goods/1 |
DELETE | 刪除商品(id=1) | http://127.0.0.1:8080/goods/1 |
我們根據(jù)上面的接口列表,實現(xiàn)控制器類代碼如下:
實例:
/**
* 商品控制器類
*/
@RestController
public class GoodsController {
@Autowired
private GoodsService goodsService;
/**
* 按id獲取商品信息
*/
@GetMapping("/goods/{id}")
public GoodsDo getOne(@PathVariable("id") long id) {
return goodsService.getById(id);
}
/**
* 獲取商品列表
*/
@GetMapping("/goods")
public List<GoodsDo> getList() {
return goodsService.getList();
}
/**
* 新增商品
*/
@PostMapping("/goods")
public void add(@RequestBody GoodsDo goods) {
goodsService.add(goods);
}
/**
* 編輯商品
*/
@PutMapping("/goods/{id}")
public void update(@PathVariable("id") long id, @RequestBody GoodsDo goods) {
// 修改指定id的博客信息
goods.setId(id);
goodsService.edit(goods);
}
/**
* 移除商品
*/
@DeleteMapping("/goods/{id}")
public void delete(@PathVariable("id") long id) {
goodsService.remove(id);
}
}
4.10 開發(fā)跨域配置類
由于我們是前后端分離的項目開發(fā)方式,所以需要為 Spring Boot 添加跨域配置類:
實例:
/**
* 跨域配置類
*/
@Configuration
public class CorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")// 對所有請求路徑
.allowedOrigins("*")// 允許所有域名
.allowCredentials(true)// 允許cookie等憑證
.allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH")// 允許所有方法
.maxAge(3600);
}
};
}
}
5. 前端頁面開發(fā)
本節(jié)主要介紹 Spring Boot 中 JdbcTemplate 的用法,所以前端頁面僅給出代碼和注釋,不再進行詳細介紹了。
前端只有一個頁面,使用 Bootstrap 的樣式和插件,通過 jQuery 的 $.ajax 方法訪問后端接口,邏輯并不復雜。
此處簡單展示下瀏覽商品部分的前端代碼,感興趣的同學可以從 Git倉庫 查看完整代碼。
實例:
//瀏覽商品
function viewGoods() {
var row = "";
//先清空表格
$('#GoodsTable').find("tr:gt(0)").remove();
$.ajax({
type: "GET",
url: "http://127.0.0.1:8080/goods",
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (res) {
console.log(res);
$.each(res, function (i, v) {
row = "<tr>";
row += "<td>" + v.id + "</td>";
row += "<td>" + v.name + "</td>";
row += "<td>" + v.price + "</td>";
row += "<td>" + v.pic + "</td>";
row +=
"<td><a class='btn btn-primary btn-sm' href='javascript:editGoods(" + v.id + ")' >編輯</a>";
row +=
"<a class='btn btn-danger btn-sm' href='javascript:removeGoods(" + v.id + ")' >刪除</a></td>";
row += "</tr>";
console.log(row);
$("#GoodsTable").append(row);
});
},
error: function (err) {
console.log(err);
}
});
}
6. 項目效果
直接使用瀏覽器打開前端頁面,效果如下:
7. 小結
本篇重點演示了 Spring Boot 中使用 JdbcTemplate 的方法。
基于 Spring Boot 自動裝配的功能,我們只需要引入相應的依賴,編寫必要的數(shù)據(jù)庫參數(shù)配置,即可直接使用 JdbcTemplate 。所謂開箱即用,就是只需必要的操作,就可以直接到達可用的境界。