当前位置: 移动技术网 > IT编程>开发语言>Java > Spring Boot中使用JDBC Templet的方法教程

Spring Boot中使用JDBC Templet的方法教程

2019年07月19日  | 移动技术网IT编程  | 我要评论

前言

spring 的 jdbc templet 是 spring 对 jdbc 使用的一个基本的封装。他主要是帮助程序员实现了数据库连接的管理,其余的使用方式和直接使用 jdbc 没有什么大的区别。

业务需求

jdbc 的使用大家都比较熟悉了。这里主要为了演示在 springboot 中使用 spring jdbc templet 的步骤,所以我们就设计一个简单的需求。一个用户对象的 curd 的操作。对象有两个属性,一个属性是id,一个属性是名称。存储在 mysql 的 auth_user 表里面。

新建项目和增加依赖

在 intellij idea 里面新建一个空的 springboot 项目。具体步骤参考
intellij idea创建spring-boot项目的图文教程。根据本样例的需求,我们要添加下面三个依赖

<dependency>
 <groupid>org.springframework.boot</groupid>
 <artifactid>spring-boot-starter-web</artifactid>
</dependency>
<dependency>
 <groupid>org.springframework.boot</groupid>
 <artifactid>spring-boot-starter-jdbc</artifactid>
</dependency>
<dependency>
 <groupid>mysql</groupid>
 <artifactid>mysql-connector-java</artifactid>
 <version>6.0.6</version>
</dependency>

因为要发布 http rest 的服务,所以添加 spring-boot-starter-web 依赖,这里我们要使用 jdbc tempet 方法来访问数据库,所以添加了 spring-boot-starter-jdbc 依赖,要访问 mysql 数据库,所以添加了 mysql 最新版本的 jdbc 驱动程序。

准备数据库环境

假定在 linux 操作系统上已经安装了 mysql 5.7。以下操作都是在操作系统的命令行中,通过 root 用户登录到 mysql 的命令行客户端中执行的。

建库建表

create database springboot_jdbc;
create table auth_user (uuid bigint not null,name varchar(32), primary key (uuid)) default charset=utf8mb4;

设定用户权限

grant all privileges on springboot_jdbc.* to 'springboot'@'%' identified by 'springboot';
flush privileges;

配置数据源(连接池)

springboot 的数据源是自动配置的。在 springboot 2.0 中,有几种数据源配置可选,他们按照 hikaricp -> tomcat pooling -> commons dbcp2 优先顺序来选择最后实际使用哪个数据源。

在项目加入 spring-boot-starter-jdbc 依赖的时候,就已经包括了 hikaricp 数据源的依赖,所以这里自动配置 hikaricp 连接池数据源。

在 appplications.properties 中增加如下的配置

#通用数据源配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.driver
spring.datasource.url=jdbc:mysql://10.110.2.5:3306/spring-boot-jdbc?charset=utf8mb4&usessl=false
spring.datasource.username=springboot
spring.datasource.password=springboot
# hikari 数据源专用配置
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.minimum-idle=5

其中 hikari 数据源的大部分配置如下图。每个配置代表的含义可以自行查询一下

程序开发

用户数据库实体

根据需求,对应的用户数据实体有两个属性,一个是 id ,一个是 name 。这是一个纯 pojo 对象。

package com.yanggaochao.springboot.learn.springbootjdbclearn.domain.dao;
/**
 * 用户实体对象
 *
 * @author 杨高超
 * @since 2018-03-09
 */
public class userdo {
 private long id;
 private string name;

 public long getid() {
 return id;
 }

 public void setid(long id) {
 this.id = id;
 }

 public string getname() {
 return name;
 }

 public void setname(string name) {
 this.name = name;
 }
}

通用的 http rest 返回对象

通常在 http rest 接口中,我们不仅想直接返回业务对象的内容,还要返回一些通用的信息,例如接口调用的结果,调用失败的时候返回的自定义文本消息等。那么我们就需要建立两个通用的 rest 返回对象,除了返回通用的接口调用结果和文本消息,一个包括一个单独的业务内容,一个包含一个持有多个业务内容的集合。具体定义如下

单独业务内容返回对象

package com.yanggaochao.springboot.learn.springbootjdbclearn.domain.bo;
/**
 * 单个对象返回结果
 *
 * @author 杨高超
 * @since 2018-03-09
 */
public class restitemresult<t> {
 private string result;
 private string message;
 private t item;

 public string getresult() {
 return result;
 }

 public void setresult(string result) {
 this.result = result;
 }

 public string getmessage() {
 return message;
 }

 public void setmessage(string message) {
 this.message = message;
 }

 public t getitem() {
 return item;
 }

 public void setitem(t item) {
 this.item = item;
 }
}

集合业务内容返回对象

package com.yanggaochao.springboot.learn.springbootjdbclearn.domain.bo;
import java.util.collection;
/**
 * 集合对象返回结果
 *
 * @author 杨高超
 * @since 2018-03-09
 */
public class restcollectionresult<t> {
 private string result;
 private string message;
 private collection<t> items;

 public string getresult() {
 return result;
 }

 public void setresult(string result) {
 this.result = result;
 }

 public string getmessage() {
 return message;
 }

 public void setmessage(string message) {
 this.message = message;
 }

 public collection<t> getitems() {
 return items;
 }

 public void setitems(collection<t> items) {
 this.items = items;
 }
}

数据持久层开发

用户数据持久层接口定义

package com.yanggaochao.springboot.learn.springbootjdbclearn.dao;
import com.yanggaochao.springboot.learn.springbootjdbclearn.domain.dao.userdo;
import java.util.list;

/**
 * 用户数据层接口
 *
 * @author 杨高超
 * @since 2018-03-09
 */
public interface userdao {
 /**
 * 向数据库中保存一个新用户
 *
 * @param user 要保存的用户对象
 * @return 是否增肌成功
 */
 boolean add(userdo user);

 /**
 * 更新数据库中的一个用户
 *
 * @param user 要更新的用户对象
 * @return 是否更新成功
 */
 boolean update(userdo user);

 /**
 * 删除一个指定的用户
 *
 * @param id 要删除的用户的标识
 * @return 是否删除成功
 */
 boolean delete(long id);

 /**
 * 精确查询一个指定的用户
 *
 * @param id 要查询的用户的标识
 * @return 如果能够查询到,返回用户信息,否则返回 null
 */
 userdo locate(long id);

 /**
 * 通过名称模糊查询用户
 *
 * @param name 要模糊查询的名称
 * @return 查询到的用户列表
 */
 list<userdo> matchname(string name);
}

用户数据持久层实现

package com.yanggaochao.springboot.learn.springbootjdbclearn.dao.impl;
import com.yanggaochao.springboot.learn.springbootjdbclearn.dao.userdao;
import com.yanggaochao.springboot.learn.springbootjdbclearn.domain.dao.userdo;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.jdbc.core.jdbctemplate;
import org.springframework.jdbc.support.rowset.sqlrowset;
import org.springframework.stereotype.repository;
import java.util.arraylist;
import java.util.list;

/**
 * 用户对象数据库访问实现类
 *
 * @author 杨高超
 * @since 2018-03-09
 */
@repository
public class userdaojdbctempletimpl implements userdao {
 private final jdbctemplate jdbctemplate;

 @autowired
 public userdaojdbctempletimpl(jdbctemplate jdbctemplate) {
 this.jdbctemplate = jdbctemplate;
 }

 @override
 public boolean add(userdo user) {
 string sql = "insert into auth_user(uuid,name) values(?,?)";
 return jdbctemplate.update(sql, user.getid(), user.getname()) > 0;
 }

 @override
 public boolean update(userdo user) {
 string sql = "update auth_user set name = ? where uuid = ?";
 return jdbctemplate.update(sql, user.getname(), user.getid()) > 0;
 }

 @override
 public boolean delete(long id) {
 string sql = "delete from auth_user where uuid = ?";
 return jdbctemplate.update(sql, id) > 0;

 }

 @override
 public userdo locate(long id) {
 string sql = "select * from auth_user where uuid=?";
 sqlrowset rs = jdbctemplate.queryforrowset(sql, id);

 if (rs.next()) {
  return generateentity(rs);
 }
 return null;
 }

 @override
 public list<userdo> matchname(string name) {
 string sql = "select * from auth_user where name like ?";
 sqlrowset rs = jdbctemplate.queryforrowset(sql, "%" + name + "%");
 list<userdo> users = new arraylist<>();
 while (rs.next()) {
  users.add(generateentity(rs));
 }
 return users;
 }

 private userdo generateentity(sqlrowset rs) {
 userdo wechatpay = new userdo();
 wechatpay.setid(rs.getlong("uuid"));
 wechatpay.setname(rs.getstring("name"));
 return wechatpay;
 }
}

这里首先用一个注解 @repository 表示这是一个数据持久层的类,springboot 将自动将这个类实例化。然后在构造函数上增加一个 @autowired ,springboot 在实例化这个类的时候,会自动将 jdbctemplet 实例注入到这个类里面。这里 jdbctemplet 实例是  springboot 根据 applications.properties 中数据源相关的配置自动配置出来的。按照 springboot 自动配置数据源的算法,这里将会配置的数据源是 hikaricp。

剩下的则和普通的 spring jdbctemplet 开发一样,通过程序员手动在对象和数据库 sql 之间进行转换,实现了用户的增加、修改、删除、模糊匹配、精确查询等功能。

数据业务层开发

数据业务层接口定义

package com.yanggaochao.springboot.learn.springbootjdbclearn.service;
import com.yanggaochao.springboot.learn.springbootjdbclearn.domain.dao.userdo;
import java.util.list;
/**
 * 用户服务层接口
 *
 * @author 杨高超
 * @since 2018-03-09
 */
public interface userservice {
 userdo add(userdo user);
 userdo update(userdo user);
 boolean delete(long id);
 userdo locate(long id);
 list<userdo> matchname(string name);
}

数据业务层实现

package com.yanggaochao.springboot.learn.springbootjdbclearn.service.impl;
import com.yanggaochao.springboot.learn.springbootjdbclearn.dao.userdao;
import com.yanggaochao.springboot.learn.springbootjdbclearn.domain.dao.userdo;
import com.yanggaochao.springboot.learn.springbootjdbclearn.service.userservice;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.service;
import java.util.date;
import java.util.list;
/**
 * 用户业务层实现类
 *
 * @author 杨高超
 * @since 2018-03-09
 */
@service
public class userserviceimpl implements userservice {
 private final userdao userdao;
 @autowired
 public userserviceimpl(userdao userdao) {
 this.userdao = userdao;
 }

 @override
 public userdo add(userdo user) {
 user.setid(new date().gettime());
 if (userdao.add(user)) {
  return user;
 }
 return null;
 }

 @override
 public userdo update(userdo user) {
 if (userdao.update(user)) {
  return locate(user.getid());
 }
 return null;
 }

 @override
 public boolean delete(long id) {
 return userdao.delete(id);
 }

 @override
 public userdo locate(long id) {
 return userdao.locate(id);
 }

 @override
 public list<userdo> matchname(string name) {
 return userdao.matchname(name);
 }
}

这里通过一个 @service 注解声明这个实现类是一个业务层的类。持久层的 userdao 通过 @autowired 让 springboot 实例化这个业务层类的时候,自动将对应的持久层类注入到这个业务类中。

这里在增加用户对象的时候,给用户设定标识的时候,简单的用了一个当前时间的毫秒数作为标识。实际开发的过程中,这个地方需要用一个保证全局唯一的机制来保证这个标识不能重复。

对外服务层开发

package com.yanggaochao.springboot.learn.springbootjdbclearn.web;
import com.yanggaochao.springboot.learn.springbootjdbclearn.domain.bo.restcollectionresult;
import com.yanggaochao.springboot.learn.springbootjdbclearn.domain.bo.restitemresult;
import com.yanggaochao.springboot.learn.springbootjdbclearn.domain.dao.userdo;
import com.yanggaochao.springboot.learn.springbootjdbclearn.service.userservice;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.web.bind.annotation.*;
import java.util.list;
/**
 * 用户 http rest 接口
 *
 * @author 杨高超
 * @since 2018-03-09
 */
@restcontroller
@requestmapping("api/v1/user")
public class userapi {
 @autowired
 private userservice userservice;

 @requestmapping(value = "/add", method = requestmethod.post)
 public restitemresult<userdo> add(@requestbody userdo user) {
 restitemresult<userdo> result = new restitemresult<>();
 user = userservice.add(user);
 if (user != null) {
  result.setitem(user);
  result.setresult("success");
 } else {
  result.setmessage("新增用户失败");
  result.setresult("failure");
 }
 return result;
 }

 @requestmapping(value = "/update", method = requestmethod.post)
 public restitemresult<userdo> update(@requestbody userdo user) {
 restitemresult<userdo> result = new restitemresult<>();
 user = userservice.update(user);
 if (user != null) {
  result.setitem(user);
  result.setresult("success");
 } else {
  result.setmessage("修改用户失败");
  result.setresult("failure");
 }
 return result;
 }

 @requestmapping(value = "/delete/{uuid}", method = requestmethod.get)
 public restitemresult<userdo> delete(@pathvariable long uuid) {
 restitemresult<userdo> result = new restitemresult<>();
 if (userservice.delete(uuid)) {
  result.setresult("success");
 } else {
  result.setmessage("删除用户失败");
  result.setresult("failure");
 }
 return result;
 }

 @requestmapping(value = "/locate/{uuid}", method = requestmethod.get)
 public restitemresult<userdo> locate(@pathvariable long uuid) {
 restitemresult<userdo> result = new restitemresult<>();
 userdo user = userservice.locate(uuid);
 if (user != null) {
  result.setitem(user);
  result.setresult("success");
 } else {
  result.setmessage("查询用户失败");
  result.setresult("failure");
 }
 return result;
 }

 @requestmapping(value = "/match/{name}", method = requestmethod.get)
 public restcollectionresult<userdo> match(@pathvariable string name) {
 restcollectionresult<userdo> result = new restcollectionresult<>();
 list<userdo> users = userservice.matchname(name);
 result.setitems(users);
 result.setresult("success");
 return result;
 }
}

这里 @restcontroller 用来声明这是一个 http rest 接口类。通过类上的 @requestmapping 和方法上的 @requestmapping组合形成每个接口的调用路由。方法上的 @requestmapping 中的 method 属性声明了 http 调用的方法。 @requestbody 注解自动将 post 数据中的 json 对象转成 pojo 对象。@pathvariable 将 http url 路径中的数据自动转换成为服务方法的参数。

http rest 接口测试

测试通过 apache commons的 httpclient 来调用 http rest 服务。

http resst 调用辅助类

package com.yanggaochao.springboot.learn.springbootjdbclearn;
import org.apache.commons.httpclient.defaulthttpmethodretryhandler;
import org.apache.commons.httpclient.httpclient;
import org.apache.commons.httpclient.methods.getmethod;
import org.apache.commons.httpclient.methods.postmethod;
import org.apache.commons.httpclient.methods.stringrequestentity;
import org.apache.commons.httpclient.params.httpmethodparams;

import java.io.bufferedreader;
import java.io.inputstream;
import java.io.inputstreamreader;
import java.io.reader;
import java.util.map;

/**
 * @author 杨高超
 * @since 2018-03-09
 */
public class httpclienthelper {


 /**
 * 用 get 方法发起一个http请求
 *
 * @param url 要访问的 http 的 url
 * @return 访问 http 后得到的回应文本
 */
 public string httpgetrequest(string url, map<string, string> headers) {
 try {
  httpclient httpclient = new httpclient();
  getmethod method = new getmethod(url);
  method.setrequestheader("content-type", "application/json; charset=utf-8");
  method.getparams().setparameter(httpmethodparams.retry_handler,
   new defaulthttpmethodretryhandler(3, false));
  if (headers != null) {
  for (string key : headers.keyset()) {
   method.setrequestheader(key, headers.get(key));
  }
  }

  int statuscode = httpclient.executemethod(method);
  if (statuscode == 200) {
  return parseinputstream(method.getresponsebodyasstream());
  } else {
  system.out.println(url + " status = " + statuscode);
  }
 } catch (exception e) {
  e.printstacktrace();
 }
 return null;
 }

 /**
 * 用 post 方法发起一个 http 请求
 *
 * @param url 要访问的 http 的 url
 * @param data post 请求中的 data 数据
 * @return 访问 http 后得到的回应文本
 */

 public string httppostrequest(string url, string data, map<string, string> headers) {
 try {
  httpclient httpclient = new httpclient();
  postmethod method = new postmethod(url);
  method.setrequestheader("content-type",
   "application/json;charset=utf-8");
  method.setrequestheader("user-agent", "mozilla/5.0 (windows nt 6.1; wow64) applewebkit/537.36 (khtml, like gecko) chrome/34.0.1847.131 safari/537.36");
  if (headers != null) {
  for (string key : headers.keyset()) {
   method.setrequestheader(key, headers.get(key));
  }
  }

  method.setrequestentity(new stringrequestentity(data, "json", "utf-8"));
  int statuscode = httpclient.executemethod(method);
  if (statuscode == 200) {
  return parseinputstream(method.getresponsebodyasstream());
  } else {
  system.out.println(url + " status = " + statuscode + parseinputstream(method.getresponsebodyasstream()));
  }
 } catch (exception e) {
  e.printstacktrace();
 }
 return null;
 }


 /**
 * 从 java.io.reader 中解析文本数据
 *
 * @param rd java.io.reader 对象
 * @throws exception 发生错误时抛出异常
 */
 private string parsereader(reader rd) throws exception {
 bufferedreader brd = new bufferedreader(rd);
 string line;
 stringbuilder respongsecontext = new stringbuilder();

 while ((line = brd.readline()) != null) {
  respongsecontext.append(line).append("\n");
 }
 //rd.close();
 if (respongsecontext.length() > 0) {
  respongsecontext.deletecharat(respongsecontext.length() - 1);
 }
 return respongsecontext.tostring();
 }

 /**
 * 从输入流中解析文本数据
 *
 * @param is 输入流
 * @throws exception 发生错误时抛出异常
 */
 private string parseinputstream(inputstream is) throws exception {
 return parsereader(new bufferedreader(new inputstreamreader(is)));
 }
}

这里主要是实现了用 get 和 post 方法调用 http rest 服务的方法。

测试用例

采用 junit 来执行测试用例。为了实现测试,我们额外增加了下面的 maven 依赖

<dependency>
 <groupid>commons-httpclient</groupid>
 <artifactid>commons-httpclient</artifactid>
 <version>3.1</version>
 <scope>test</scope>
</dependency>
<dependency>
 <groupid>org.codehaus.jettison</groupid>
 <artifactid>jettison</artifactid>
 <version>1.3.3</version>
 <scope>test</scope>
</dependency>
package com.yanggaochao.springboot.learn.springbootjdbclearn;
import org.codehaus.jettison.json.jsonobject;
import org.junit.after;
import org.junit.before;
import org.junit.test;
import java.net.urlencoder;
import java.util.arraylist;
import java.util.list;

/**
 * description:
 *
 * @author 杨高超
 * @since 2018-03-09
 */
public class userapitest {
 private string useraddurl = "http://localhost:3030/security/api/v1/user/add";
 private string userlocateurl = "http://localhost:3030/security/api/v1/user/locate/";
 private string userdeleteurl = "http://localhost:3030/security/api/v1/user/delete/";
 private string userupdateurl = "http://localhost:3030/security/api/v1/user/update";
 private string usermatchurl = "http://localhost:3030/security/api/v1/user/match/";
 jsonobject adduser = new jsonobject();
 long adduserid = null;
 list<long> userids = new arraylist<>();
 @before
 public void before() throws exception {
 adduser.put("name", "美羊羊");
 jsonobject addresultjson = new jsonobject(new httpclienthelper().httppostrequest(useraddurl, adduser.tostring(), null));
 assert ("success".equals(addresultjson.getstring("result")));
 adduserid = addresultjson.getjsonobject("item").getlong("id");

 jsonobject user = new jsonobject();
 user.put("name", "喜羊羊");
 addresultjson = new jsonobject(new httpclienthelper().httppostrequest(useraddurl, user.tostring(), null));
 assert ("success".equals(addresultjson.getstring("result")));
 userids.add(addresultjson.getjsonobject("item").getlong("id"));
 user.put("name", "灰太狼");
 addresultjson = new jsonobject(new httpclienthelper().httppostrequest(useraddurl, user.tostring(), null));
 assert ("success".equals(addresultjson.getstring("result")));
 userids.add(addresultjson.getjsonobject("item").getlong("id"));
 }

 @test
 public void testupdateuser() throws exception {
 jsonobject user = new jsonobject();
 user.put("name", "霉羊羊");
 user.put("id", adduserid);
 new httpclienthelper().httppostrequest(userupdateurl, user.tostring(), null);
 jsonobject locateresultjson = new jsonobject(new httpclienthelper().httpgetrequest(userlocateurl + adduserid, null));
 assert (user.getstring("name").equals(locateresultjson.getjsonobject("item").getstring("name")));
 }


 @test
 public void testmatchuser() throws exception {
 jsonobject matchresultjson = new jsonobject(new httpclienthelper().httpgetrequest(usermatchurl + urlencoder.encode("羊","utf-8"), null));
 assert (matchresultjson.has("items") && matchresultjson.getjsonarray("items").length() == 2);
 matchresultjson = new jsonobject(new httpclienthelper().httpgetrequest(usermatchurl + urlencoder.encode("狼","utf-8"), null));
 assert (matchresultjson.has("items") && matchresultjson.getjsonarray("items").length() == 1);
 }

 @after
 public void after() throws exception {
 if (adduserid != null) {
  jsonobject deleteresultjson = new jsonobject(new httpclienthelper().httpgetrequest(userdeleteurl + adduserid, null));
  assert ("success".equals(deleteresultjson.getstring("result")));
 }

 for (long userid : userids) {
  jsonobject deleteresultjson = new jsonobject(new httpclienthelper().httpgetrequest(userdeleteurl + userid, null));
  assert ("success".equals(deleteresultjson.getstring("result")));
 }
 }
}

这里在 @test 声明了两个测试用例,一个测试了用户修改功能,一个测试了用户模糊查询功能。  @before 声明了在执行每个测试用例之前要做的准备工作。这里首先往数据库中插入三条数据,同时也测试了数据的增加功能、精确查询的功能。@after 声明了执行每个测试用例后的清理工作。这里主要是将之前插入的数据给删除了。这里同步测试了用户删除的功能。

后记

这里就展示了一个完整的 springboot 使用 jdbc templet 的完整样例。如果有在 spring 下使用 jdbc templet 的经历,那么在 spring 里面主要是减少了很多配置的工作。

本文涉及的代码已经上传到 github 上,大家也可以通过

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对移动技术网的支持。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网