簡介: 使用 mybatis 連接 mysql 數據庫, 一套簡單的增刪改查流程, 前台用 bootstrap, bootstrap-table 框架, 最后用 druid 監控數據庫連接情況
項目源碼:https://github.com/y369q369/springBoot.git -> DruidMybatisMysql
私聊QQ: 1486866853
1.demo的完整結構
2. pom.xml 依賴 和 application.yml 配置
1) pom.xml 主要 依賴 mysql-connector-java , mybatis-spring-boot-starter ,druid-spring-boot-starter

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.demo</groupId> <artifactId>DruidMybatisMysql</artifactId> <version>0.0.1-SNAPSHOT</version> <name>DruidMybatisMysql</name> <description>使用druid管理數據庫,mybatis連接mysql數據庫</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.0</version> </dependency> <!-- web依賴,包含servlet,內置tomcat等 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- thymeleaf模板依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!-- mysql依賴 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!-- mybatis依賴 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <!-- druid依賴包,配合springBoot項目使用 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.14</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
2) application配置

# springBoot內置容器的配置 server: # 端口號 port: 8086 servlet: # 項目前綴 context-path: /dataSource spring: # 數據源配置 datasource: # mysql數據庫配置 driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC username: root password: ok # druid配置 druid: # 配置監控統計攔截的filters,去掉后監控界面sql無法統計,'wall'用於防火牆 filters: config,wall,stat # 初始化數量 initialSize: 5 # 最小連接池數量 minIdle: 2 # 最大連接池數量 maxActive: 20 # 連接超時時間 maxWait: 60000 # 打開psCache, 對支持游標的數據庫性能提升巨大 poolPreparedStatements: true # 指定每個連接PsCache的大小 maxPoolPreparedStatementPerConnectionSize: 20 # 配置間隔多久才進行一次檢測,檢測需要關閉的空閑連接,單位是毫秒 timeBetweenEvictionRunsMillis: 6000 # 指定一個空閑連接最少空閑多久后可被清除,單位是毫秒 minEvictableIdleTimeMillis: 300000 # 驗證數據庫連接的查詢語句 validationQuery: select 'x' # 當連接空閑時,是否執行連接測試 testWhileIdle: true # 當從連接池借用連接時,是否測試該連接 testOnBorrow: false # 在連接歸還到連接池時是否測試該連接 testOnReturn: false # 打開mergeSql,慢sql記錄 connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 # thymeleaf 模板引擎配置 thymeleaf: cache: false # thymeleaf模板對html5沒有結束符的標簽解決 mode: LEGACYHTML5 # thymeleaf修飾的動態頁面 自定義根目錄(默認就是templates) prefix: classpath:/templates/ # mybatis配置 mybatis: # 映射xml的文件位置 mapper-locations: classpath:mybatis/*.xml # 實體類所在包,簡化xml中resultMap中實體類的全類名寫法 type-aliases-package: demo.domain
3.代碼 : 建表sql , 后台代碼 , mapper.xml 和 前台html

create table `test`( `test_id` varchar(36) not null comment '唯一id' primary key, `test_password` varchar(32) not null comment '密碼', `test_name` varchar(32) not null comment '名稱' ) comment '測試'

package demo.domain; /** * @author GrassPrince * @Da2019年4月3日 2019年4月3日 - 下午8:09:33 * @Description Test */ public class Test { /** 唯一id */ private String testId; /** 密碼 */ private String testPassword; /** 名稱 */ private String testName; public Test(String testId, String testPassword, String testName) { this.testId = testId; this.testPassword = testPassword; this.testName = testName; } public Test() { } public String getTestId() { return testId; } public void setTestId(String testId) { this.testId = testId; } public String getTestPassword() { return testPassword; } public void setTestPassword(String testPassword) { this.testPassword = testPassword; } public String getTestName() { return testName; } public void setTestName(String testName) { this.testName = testName; } @Override public String toString() { return "Test [testId=" + testId + ", testPassword=" + testPassword + ", testName=" + testName + "]"; } }

package demo.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import demo.domain.Test; import demo.service.TestService; /** * @author GrassPrince * @Da2019年4月3日 2019年4月3日 - 下午7:42:54 * @Description 測試 controller : 增刪改查 */ @Controller @RequestMapping("/test") public class TestController { @Autowired private TestService testService; // 跳轉到測試頁面 @GetMapping("/testHtml") public ModelAndView testHtml() { return new ModelAndView("test"); } // 根據testId查詢test @PostMapping("/queryById") @ResponseBody public List<Test> queryById(@RequestParam ("testId") String testId) { return testService.queryById(testId); } // 根據testId刪除test @DeleteMapping("/deleteById") @ResponseBody public String deleteById(@RequestParam("testId") String testId) { Integer deleteNum = testService.deleteById(testId); if(deleteNum == 0) { return "刪除失敗"; } return "刪除成功"; } //批量刪除 @DeleteMapping("/deleteIds") @ResponseBody public String deleteIds(@RequestParam("testIds") String testIds) { Integer deleteNum = testService.deleteIds(testIds); if(deleteNum == 0) { return "刪除失敗"; } return "刪除成功"; } // 修改test @PutMapping("/updateTest") @ResponseBody public String updateTest(Test test) { Integer updateNum = testService.updateTest(test); if(updateNum == 0) { return "更新失敗"; } return "更新成功"; } // 新建一個test @PostMapping("/add") @ResponseBody public String add(Test test) { Integer addNum = testService.add(test); if(addNum == 0) { return "新增失敗"; } return "新增成功"; } }

package demo.service; import java.util.List; import demo.domain.Test; /** * @author GrassPrince * @Da2019年4月3日 2019年4月3日 - 下午7:50:50 * @Description 測試的service接口 */ public interface TestService { /** 根據testId查詢test */ List<Test> queryById(String testId); /** 根據testId刪除test */ Integer deleteById(String testId); /** 批量刪除 */ Integer deleteIds(String testIds); /** 修改test */ Integer updateTest(Test test); /** 新增test */ Integer add(Test test); }

package demo.service.impl; import java.util.List; import java.util.UUID; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import demo.domain.Test; import demo.mapper.TestMapper; import demo.service.TestService; /** * @author GrassPrince * @Da2019年4月3日 2019年4月3日 - 下午7:51:26 * @Description 測試的 service實現類 */ @Service public class TestServiceImpl implements TestService{ @Autowired private TestMapper testMapper; /** 根據testId查詢test */ @Override public List<Test> queryById(String testId) { return testMapper.queryById(testId); } /** 根據testId刪除test */ @Override public Integer deleteById(String testId) { return testMapper.deleteById(testId); } /** 批量刪除 */ @Override public Integer deleteIds(String testIds) { String[] deleteIds = testIds.split(","); return testMapper.deleteIds(deleteIds); } /** 修改test */ @Override public Integer updateTest(Test test) { return testMapper.updateTest(test); } /** 新增test */ @Override public Integer add(Test test) { // 用uuid設置隨機的主鍵id test.setTestId(UUID.randomUUID().toString().replace("-", "")); return testMapper.add(test); } }

package demo.mapper; import java.util.List; import org.apache.ibatis.annotations.Param; import demo.domain.Test; /** * @author GrassPrince * @Da2019年4月3日 2019年4月3日 - 下午7:53:50 * @Description 測試的mapper */ public interface TestMapper { /** 根據testId查詢test */ List<Test> queryById(@Param("testId") String testId); /** 根據testId刪除test */ Integer deleteById(@Param("testId") String testId); /** 批量刪除 */ Integer deleteIds(@Param("testIds") String[] deleteIds); /** 修改test */ Integer updateTest(Test test); /** 新增test */ Integer add(Test test); }

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- 對應mapper接口的全類名 --> <mapper namespace="demo.mapper.TestMapper"> <!-- domain實體類 與 數據庫表 做映射, type -> 實體類全類名,由於配置過type-aliases-package故只需配置類名 , id -> 這個resultMap 的唯一引用id --> <resultMap type="Test" id="testMap"> <id property="testId" column="test_id"/> <result property="testPassword" column="test_password"/> <result property="testName" column="test_name"/> </resultMap> <!-- id:對應mapper接口的方法名, resultMap: 對應定義的上方的resultMap,返回對應的實體類 --> <!-- 返回值會自動根據對象數量映射成單個對象或對象集合 --> <!-- mapper接口中有參數的方法:已經在接口中通過注解的方式傳入,此處不需再次接收 --> <select id="queryById" resultMap="testMap"> select * from test <where> <if test="testId != null and testId != ''"> test_id = #{testId} </if> </where> </select> <delete id="deleteById"> delete from test where test_id = #{testId} </delete> <delete id="deleteIds"> delete from test <where> <if test="testIds != null and testIds.length > 0"> test_id in <foreach collection="testIds" item="testId" open="(" close=")" separator=","> #{testId} </foreach> </if> </where> </delete> <update id="updateTest"> update test set test_password = #{testPassword}, test_name = #{testName} where test_id = #{testId} </update> <insert id="add"> insert into test values(#{testId}, #{testPassword}, #{testName}) </insert> </mapper>

package demo; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan("demo.mapper") public class DruidMybatisMysqlApplication { public static void main(String[] args) { SpringApplication.run(DruidMybatisMysqlApplication.class, args); } }

<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>查詢</title> <meta name="keywords" content="keyword1,keyword2,keyword3"> <meta name="description" content="this is my page"> <meta name="content-type" content="text/html; charset=UTF-8"> <!-- springEL的引入 樣式格式 --> <!-- bootstrap的樣式 --> <link rel="stylesheet" th:href="@{/bootstrap-4.3.1-dist/css/bootstrap.css}"/> <!-- bootstrap-table的樣式 --> <link rel="stylesheet" th:href="@{/bootstrap-table-dist/bootstrap-table.css}"/> </head> <body> <div style="text-align: center; padding-top: 80px"> <h1>測試查詢</h1> <div class="row" style="margin-top: 50px"> <div class="col-md-4 text-right"> <label for="testId">id:</label> </div> <div class="col-md-2"> <input type="text" id="testId" class="form-control"> </div> <div class="col-md-3"> <button class="btn btn-primary" onclick="init()">查詢</button> <button class="btn btn-success" onClick="AddModel()">新增</button> <button class="btn btn-warning" onClick="deleteIds()">批量刪除</button> </div> </div> <div style="margin-top: 20px; padding: 0 10%;"> <table id="testTable" class="table table-bordered table-striped table-hover"></table> </div> </div> <!-- 新增/修改test的公用模態框 --> <div id="addTestModel" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="title"></h5> <button type="button" class="close" data-dismiss="modal" aria-label="true"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <div id="operateId" class="input-group input-group-lg" style="margin:10px 0"> <div class="input-group-prepend" > <label class="input-group-text" for="id">testId</label> </div> <input type="text" id="id" readonly class="form-control" aria-label="Large" aria-describedby="inputGroup-sizing-sm" > </div> <div class="input-group input-group-lg" style="margin:10px 0"> <div class="input-group-prepend"> <label class="input-group-text" for="name">testName</label> </div> <input type="text" id="name" class="form-control" aria-label="Large" aria-describedby="inputGroup-sizing-sm"> </div> <div class="input-group input-group-lg" style="margin:10px 0"> <div class="input-group-prepend"> <label class="input-group-text" for="password">testPassword</label> </div> <input type="text" id="password" class="form-control" aria-label="Large" aria-describedby="inputGroup-sizing-sm"> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-info" id="updateButton" onClick="operateTest('updateTest', 'put')">修改</button> <button type="button" class="btn btn-success" id="addButton" onClick="operateTest('add', 'post')">新增</button> <button type="button" class="btn btn-secondary" data-dismiss="modal">關閉</button> </div> </div> </div> </div> <!-- =============================================================== --> <!-- jquery的js腳本 --> <script type="text/javascript" th:src="@{/jquery-3.3.1.js}"></script> <!-- bootstrap的js腳本 --> <script type="text/javascript" th:src="@{/bootstrap-4.3.1-dist/js/bootstrap.js}"></script> <!-- bootstrap-table的js腳本 --> <script type="text/javascript" th:src="@{/bootstrap-table-dist/bootstrap-table.js}"></script> <!-- bootstrap-table的中文js腳本 --> <script type="text/javascript" th:src="@{/bootstrap-table-dist/locale/bootstrap-table-zh-CN.js}"></script> <!-- js通過內聯方式獲取后台的request數據 --> <script type="text/javascript"> $(function(){ init(); }) function init() { $("#testTable").bootstrapTable('destroy'); $("#testTable").bootstrapTable({ method:"post", contentType : "application/x-www-form-urlencoded", //springmvc 請求類型為post, 加上 url:"queryById", dataType:"json", cache:false, //是否啟用緩存 striped: true, //是否顯示行間隔色 clickToSelect: true, //是否啟用點擊選中行 uniqueId: "testId", //每一行的唯一標識,一般為主鍵列 queryParams: { //傳遞的參數 "testId" : $("#testId").val() }, columns:[ //返回的參數 { checkbox: true },{ field:"", title:"序號", formatter: function(value, row, index) { return index + 1; } },{ field:"testId", //后台返回的參數名,變量名要保持一致 title:"唯一id" //頁面表格中顯示的字段 },{ field:"testName", title:"名稱" },{ title:"操作", formatter:function(value,row,index){ return "<button class='btn btn-info' onclick='updateModel(\"" + row.testId +"\")'>修改</button> " + " <button class='btn btn-warning' onclick='deleteById(\"" + row.testId +"\")'>刪除</button>"; } } ],onLoadSuccess : function(data){ console.log(data); } }); } //打開新增模態框 function AddModel() { clearData(); $("#title").text("新增test"); $("#operateId").hide(); $("#updateButton").hide(); $("#addButton").show(); $("#addTestModel").modal('show'); } //打開修改模態框 function updateModel(testId) { $("#title").text("修改test"); $("#operateId").show(); $("#addButton").hide(); $("#updateButton").show(); var row = $("#testTable").bootstrapTable('getRowByUniqueId', testId) $("#id").val(row.testId); $("#name").val(row.testName); $("#password").val(row.testPassword); $("#addTestModel").modal('show'); } //新增/修改test公共方法 function operateTest(url, type) { $.ajax({ url: url, type: type, data: { "testId" : $("#id").val(), "testName" : $("#name").val(), "testPassword" : $("#password").val(), }, success:function(data){ $("#addTestModel").modal('hide'); init(); alert(data); }, error:function(res){ console.log(res); alert("操作失敗"); } }) } // 清除模態框數據 function clearData() { $("#id").val(""); $("#name").val(""); $("#password").val(""); } // 刪除test function deleteById(testId) { $.ajax({ url: "deleteById", type: "delete", data: { "testId" : testId, }, success:function(data){ init(); alert(data); }, error:function(res){ console.log(res); alert("操作失敗"); } }) } // 批量刪除 function deleteIds() { var rows = $("#testTable").bootstrapTable('getSelections'); console.log(rows); if(rows == null || rows.length == 0) { alert("請選擇要刪除的test!"); }else { if(confirm("確定要清空數據嗎?")) { var testIds = ""; for(var i = 0; i < rows.length; i++) { if(i = 0) { testIds += rows[i].testId; }else { testIds += "," + rows[i].testId; } } $.ajax({ url: "deleteIds", type: "delete", data: { "testIds" : testIds, }, success:function(data){ init(); alert(data); }, error:function(res){ console.log(res); alert("操作失敗"); } }) } } } </script> </body> </html>
4.頁面效果( 服務啟動后地址 : http://localhost:8086/dataSource/test/testHtml )
5.集成 druid 管理數據庫: 主要是一個配置類和 application.yml的配置文件

/** * */ package demo.config; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import javax.sql.DataSource; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.support.http.StatViewServlet; import com.alibaba.druid.support.http.WebStatFilter; /** * @author GrassPrince * @Da2019年4月3日 2019年4月3日 - 下午8:00:17 * @Description druid數據庫監測配置類 -> 項目啟動后的訪問地址 http://localhost:8086/dataSource/druid/index.html */ @Configuration public class DruidConfig { /** * 注入DruidDataSource在yml配置文件中的配置 * prefix: 獲取以spring.datasource為前綴的配置內容, 減少一個個@Value獲取 */ @ConfigurationProperties(prefix = "spring.datasource") @Bean public DataSource getDataSource() { return new DruidDataSource(); } /** * 配置Druid的監控 : 一個管理后台的Servlet */ @Bean public ServletRegistrationBean<StatViewServlet> statViewServlet() { ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<StatViewServlet>(new StatViewServlet(), "/druid/*"); Map<String,String> initParams = new HashMap<String,String>(); initParams.put("loginUsername","admin"); //用戶名 initParams.put("loginPassword","123456"); //密碼 initParams.put("allow",""); //IP白名單(沒有配置或者為空,則允許所有訪問) initParams.put("deny",""); //IP黑名單 (存在共同時,deny優先於allow) bean.setInitParameters(initParams); return bean; } /** * 配置一個web監控的filter */ @Bean public FilterRegistrationBean<WebStatFilter> webStatFilter(){ FilterRegistrationBean<WebStatFilter> bean = new FilterRegistrationBean<WebStatFilter>(); bean.setFilter(new WebStatFilter()); Map<String,String> initParams = new HashMap<>(); initParams.put("exclusions", "*.js,*.css,/druid/*"); ////忽略資源 bean.setInitParameters(initParams); bean.setUrlPatterns(Arrays.asList("/*")); return bean; } }
6.配置后頁面效果
7.個人心得
1) mybatis的配置文件很少,全在 yml 文件中, 需注意 啟動類添加的 注解 @MapperScan("demo.mapper"), 掃描mapper層的接口
2) mysql數據庫url的配置 url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC ,
springBoot 2.0 以上的版本 用 mysql 8.0.12客戶端 時會出現時區錯誤, 用 serverTimezone=UTC 解決 , driver-class-name: com.mysql.cj.jdbc.Driver 也改變
3) xml中的參數在mapper接口中通過 @Param 注解注入較實用(list集合和數組都可以直接傳)