Spring boot入門(三):SpringBoot集成結合AdminLTE(Freemarker),利用generate自動生成代碼,利用DataTable和PageHelper進行分頁顯示javascript
關於SpringBoot和PageHelper,前篇博客已經介紹過,Spring boot入門(二):Spring boot集成MySql,Mybatis和PageHelper插件,前篇博客大體講述了SpringBoot如何集成Mybatis和Pagehelper,可是沒有作出實際的範例,本篇博客是鏈接上一篇寫的。經過AdminLTE前端框架,利用DataTable和PageHelper進行分頁顯示,經過對用戶列表的增刪改查操做,演示DataTable和PageHelper的使用。css
AdminLTE 是一個徹底響應管理模板。基於 Bootstrap3 框架,易定製模板。適合多種屏幕分辨率,從小型移動設備到大型臺式機。內置了多個頁面,包括儀表盤、郵箱、日曆、鎖屏、登陸及註冊、404 錯誤、500 錯誤等頁面。具體介紹見官方網站:adminlte.io/,咱們能夠直接今後網站下載該模板,其外觀以下:html
首先在官網下載AdminLTE模板,而後將此模板的所有文件拷貝到項目下:前端
拷貝後,將 AdminLTE 文件進行了拆分,其中 base 裏面是AdminLTE自帶的全部 JS 包和 css 文件,main中是AdminLTE主頁面渲染頁面,index 是入口。這麼作的目的:直接將 base 經過 FreeMarker 中宏的形式引入到index 入口頁面中,那麼全部的 JS 文件將一直曾在最底層的頁面下,在後期的其它頁面的開發中,不須要再次引入 JS 包,避免 JS 包混亂。java
啓動項目:mysql
generate 的介紹比較多,此處直接介紹配置的步驟及代碼jquery
編寫 generatorConfig.xml 文件,並放在 templates 根目錄下,若放在其它目錄中,則須要在 pom.xml 中配置路徑,不然,編譯的時候沒法經過。具體錯誤:git
[ERROR] Failed to execute goal org.mybatis.generator:mybatis-generator-maven-plugin:1.3.5:generate (default-cli) on project edu: configfile D:\8_Project\learn\edu\src\main\resources\generatorConfig.xml does not exist -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
複製代碼
generatorConfig.xml 的腳本以下,其中 targetProject 的路徑須要曾在,不然會報錯,參考blog.csdn.net/hh680821/ar…github
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- <properties resource="application.properties"/>-->
<context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat">
<!--屬性配置 -->
<property name="beginningDelimiter" value="`"/>
<property name="endingDelimiter" value="`"/>
<!--去除註釋 -->
<commentGenerator>
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--若是mapper接口須要實現其它接口,那麼須要配置MapperPlugin,value中是實現的接口或類名 -->
<plugin type="tk.mybatis.mapper.generator.MapperPlugin">
<property name="mappers" value="com.tswc.edu.utils.MyMapper"/>
</plugin>
<!--必定要放在plugin下面,不然報錯 -->
<commentGenerator>
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--數據庫鏈接池-->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/edu"
userId="root"
password="123456">
</jdbcConnection>
<!--自動生成實體類-->
<javaModelGenerator targetPackage="generator" targetProject="src/main/java"/>
<!--自動生成map接口-->
<sqlMapGenerator targetPackage="generator" targetProject="src/main/java"/>
<!--自動生成mybatis的xml文件-->
<javaClientGenerator targetPackage="generator" targetProject="src/main/java"
type="XMLMAPPER"/>
<!--數據庫表名,此處若是須要去掉某個自帶函數,須要添加參數-->
<!--1,schema:數據庫的schema;
2,catalog:數據庫的catalog;
3,alias:爲數據表設置的別名,若是設置了alias,那麼生成的全部的SELECT SQL語句中,列名會變成:alias_actualColumnName
4,domainObjectName:生成的domain類的名字,若是不設置,直接使用表名做爲domain類的名字;能夠設置爲somepck.domainName,那麼會自動把domainName類再放到somepck包裏面;
5,enableInsert(默認true):指定是否生成insert語句;
6,enableSelectByPrimaryKey(默認true):指定是否生成按照主鍵查詢對象的語句(就是getById或get);
7,enableSelectByExample(默認true):MyBatis3Simple爲false,指定是否生成動態查詢語句;
8,enableUpdateByPrimaryKey(默認true):指定是否生成按照主鍵修改對象的語句(即update);
9,enableDeleteByPrimaryKey(默認true):指定是否生成按照主鍵刪除對象的語句(即delete);
10,enableDeleteByExample(默認true):MyBatis3Simple爲false,指定是否生成動態刪除語句;
11,enableCountByExample(默認true):MyBatis3Simple爲false,指定是否生成動態查詢總條數語句(用於分頁的總條數查詢);
12,enableUpdateByExample(默認true):MyBatis3Simple爲false,指定是否生成動態修改語句(只修改對象中不爲空的屬性);
13,modelType:參考context元素的defaultModelType,至關於覆蓋;
14,delimitIdentifiers:參考tableName的解釋,注意,默認的delimitIdentifiers是雙引號,若是相似MYSQL這樣的數據庫,使用的是`(反引號,那麼還須要設置context的beginningDelimiter和endingDelimiter屬性)
15,delimitAllColumns:設置是否全部生成的SQL中的列名都使用標識符引發來。默認爲false,delimitIdentifiers參考context的屬性
注意,table裏面不少參數都是對javaModelGenerator,context等元素的默認屬性的一個複寫;-->
<table tableName="t_user">
<generatedKey column="id" sqlStatement="Mysql" identity="true"/>
</table>
</context>
</generatorConfiguration>
複製代碼
假設產生此錯誤:web
[ERROR] Failed to execute goal org.mybatis.generator:mybatis-generator-maven-plugin:1.3.5:generate (default-cli) on project edu: XML Parser Error on line 60: 元素類型爲 "context" 的內容必須匹配 "(property*,plugin*,commentGenerator?,(connectionFactory|jdbcConnection),javaTypeResolver?,javaModelGenerator,sqlMapGenerator?,javaClientGenerator?,table+)"。 -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
複製代碼
緣由就是:generate 中,標籤都是有順序的,此類錯誤就是標籤的順序存在問題
此時,xml 文件以及配置結束,須要在 idea 中配置啓動操做:mybatis-generator:generate,如圖
DataTable 是一款簡單易用的分頁插件,基於 JQuery 寫的,裏面提供了豐富的分頁參數,主要經過 Ajax 實現數據的先後端傳輸
首先引入 JS 和 CSS 包:
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css" />
<script src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js"></script>
複製代碼
其外,還須要格式化相關提示文字,通常命名爲:language.json
{
"sEmptyTable": "沒有相關數據",
"sInfo": "從 _START_ 到 _END_ 條記錄 總記錄數爲 _TOTAL_ 條",
"sInfoEmpty": "記錄數爲0",
"sInfoFiltered": "(所有記錄數 _MAX_ 條)",
"sInfoPostFix": "",
"sInfoThousands": ",",
"sLengthMenu": "顯示 _MENU_ 條",
"sLoadingRecords": "正在加載...",
"sProcessing": "正在獲取數據,請稍候...",
"sSearch": "搜索",
"sZeroRecords": "沒有您要搜索的內容",
"oPaginate": {
"sFirst": "首頁",
"sPrevious": "上一頁",
"sNext": "下一頁",
"sLast": "尾頁",
"sJump": "跳轉"
},
"oAria": {
"sSortAscending": ": 以升序排序",
"sSortDescending": ": 以降序排序"
}
}
複製代碼
具體的實現方式以下代碼:
var user_tab;
var user_list_param;
$(function () {
var url="/admin/user/listPage";
user_list_setParm();
user_tab = $('#user_tab').DataTable({
"fnDrawCallback": function () {
},
"dom": '<"top"i>rt<"bottom"flp><"clear">',
//"ordering":false,//是否排序
"processing": true,
"searching": false,
"serverSide": true, //啓用服務器端分頁
"order": [[ 5, "asc" ]],//默認排序字段
"bInfo": true,
"bAutoWidth": false,
"scrollX": true,
"scrollCollapse": false,
/*fixedColumns: {
leftColumns: 0,
rightColumns: 1
},*/
"language":{"url":"/plugins/datatables/language.json"},
"ajax":{"url":url,"data":user_list_param,"type":"post"},
"columns":[
{"data":"id"},
{"data":null},
{"data":"userName"},
{"data":"password"},
{"data":"trueName"},
{"data":"createTime"},
{"data":"id"}
],
"columnDefs" : [
{
targets: 0,
data: null,
orderable:false,
render: function (data) {
return '<input type="checkbox" class="userCheckbox" value="'+data+'"/>';
}
},
{
targets: 1,
data: null,
orderable:false,
render: function (data) {
No=No+1;
return No;
}
},
{
"targets" : -1,
"data" : null,
orderable:false,
"render" : function(data) {
var data = "'"+data+"'";
var btn1='<a class="btn btn-xs btn-warning" target="modal" modal="hg" href=""><i class="fa fa-edit"></i>修改</a> ';
var btn2 = '<a class="btn btn-xs btn-danger" target="modal" modal="hg" onclick="user_list_delete('+data+')"><i class="fa fa-remove"></i>刪除</a> ';
return btn1+btn2;
}
}
]
}).on('preXhr.dt', function ( e, settings, data ) {
No=0;
}).on('xhr.dt', function(e, settings, json, xhr) {
});
});
複製代碼
這裏面須要說明的:
a. 若是開啓排序,那麼後端接受參數的方式:
@RequestParam(value = "order[0][column]", required = false) Integer orderIndex
@RequestParam(value = "order[0][dir]", required = false) String orderDir
複製代碼
其中orderIndex爲排序的字段,而orderDir爲排序的方式(升序或者降序)。orderIndex中是前端table中字段的列號,因此通暢,還須要在後臺初始化一個數組,而後再數組中取實際須要排序的字段,例如:
1 String[] cols = {"", "", "user_name", "password", "true_name", "create_time"};
2 Result<Page<TUser>> result = userService.listPage((start / pageSize) + 1, pageSize, cols[orderIndex], orderDir);
複製代碼
b. 通常在對列表進行了增刪改查後,須要從新刷新列表,而此時,大多數狀況下,想列表保持當前頁面刷新,那麼須要使用函數
user_tab.draw(false);
其中user_tab爲table的JQuery對象,若是不須要保持此頁面,去掉false便可。
c. 須要凍結某列的時候,須要使用到fixedColumns函數,可使用on進行函數回調,使用dom,進行頁面統計文字的顯示位置"dom": '<"top"i>rt<"bottom"flp><"clear">',
public Result<Page<TUser>> listPage(int pageCurrent, int pageSize, String userName, String trueName, String cols, String orderDir) {
Example example = new Example(TUser.class);
Criteria criteria = example.createCriteria();
ExampleUtils.getLikeExample(criteria, "userName", userName);
ExampleUtils.getLikeExample(criteria, "trueName", trueName);
example.setOrderByClause(cols + " " + orderDir);
//example.orderBy(cols+" "+orderDir);
Result<Page<TUser>> result = new Result<Page<TUser>>();
PageHelper.startPage(pageCurrent, pageSize);
List<TUser> tUsers = userMapper.selectByExample(example);
PageInfo<TUser> pageInfo = new PageInfo<TUser>(tUsers, pageSize);
Page<TUser> resultData = new Page<TUser>((int) pageInfo.getTotal(), pageInfo.getPages(), pageCurrent, pageSize, tUsers);
result.setResultData(resultData);
result.setErrCode(0);
result.setStatus(true);
return result;
}
複製代碼
因爲,須要配個DataTable,因此須要從新編寫page類,保證字段的一致性,這裏就放棄了PageHelper自帶的PageInfo,實際上,這2個類中,字段類型基本一致,區別不大。
前端ftl:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用戶列表</title>
</head>
<body>
<div class="box-body">
<div class="clearfix">
<form class="form-horizontal">
<input id="user_list_repeatApply" name="user_list_repeatApply" type="reset" style="display:none;"/>
<div class="form-group clearfix">
<label class="col-md-1 control-label">登陸名稱</label>
<div class="col-md-2">
<input type="text" class="input-sm form-control" id="user_list_user_name" name="user_list_user_name" placeholder="請輸入登陸名稱...">
</div>
<label class="col-md-1 control-label">用戶名</label>
<div class="col-md-2">
<input type="text" class="input-sm form-control" id="user_list_true_name" name="user_list_true_name" placeholder="請輸入用戶名...">
</div>
<button type="button" onclick="user_list_query();" class="btn btn-sm btn-primary" ><i class="fa fa-search"></i>搜索</button>
<button type="button" onclick="user_list_add();" class="btn btn-sm btn-success" ><i class="fa fa-square-o"></i>增長</button>
<button type="button" onclick="user_list_delete('1');" class="btn btn-sm btn-danger" ><i class="fa fa-remove"></i>刪除</button>
<button type="button" onclick="user_list_reset();" class="btn btn-sm btn-default">重置</button>
</div>
</form>
</div>
<table id="user_tab" class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th><input type="checkbox" title="全選" /></th>
<th>序號</th>
<th>登陸名稱</th>
<th>登陸密碼</th>
<th>用戶名</th>
<th>加入時間</th>
<th>操做</th>
</tr>
</thead>
</table>
</div>
<script type="text/javascript">
var user_tab;
var user_list_param;
$(function () {
var url="/admin/user/listPage";
user_list_setParm();
user_tab = $('#user_tab').DataTable({
"fnDrawCallback": function () {
},
"dom": '<"top"i>rt<"bottom"flp><"clear">',
//"ordering":false,//是否排序
"processing": true,
"searching": false,
"serverSide": true, //啓用服務器端分頁
"order": [[ 5, "asc" ]],//默認排序字段
"bInfo": true,
"bAutoWidth": false,
"scrollX": true,
"scrollCollapse": false,
/*fixedColumns: {
leftColumns: 0,
rightColumns: 1
},*/
"language":{"url":"/plugins/datatables/language.json"},
"ajax":{"url":url,"data":user_list_param,"type":"post"},
"columns":[
{"data":"id"},
{"data":null},
{"data":"userName"},
{"data":"password"},
{"data":"trueName"},
{"data":"createTime"},
{"data":"id"}
],
"columnDefs" : [
{
targets: 0,
data: null,
orderable:false,
render: function (data) {
return '<input type="checkbox" class="userCheckbox" value="'+data+'"/>';
}
},
{
targets: 1,
data: null,
orderable:false,
render: function (data) {
No=No+1;
return No;
}
},
{
"targets" : -1,
"data" : null,
orderable:false,
"render" : function(data) {
var data = "'"+data+"'";
var btn1='<a class="btn btn-xs btn-warning" target="modal" modal="hg" href=""><i class="fa fa-edit"></i>修改</a> ';
var btn2 = '<a class="btn btn-xs btn-danger" target="modal" modal="hg" onclick="user_list_delete('+data+')"><i class="fa fa-remove"></i>刪除</a> ';
return btn1+btn2;
}
}
]
}).on('preXhr.dt', function ( e, settings, data ) {
No=0;
}).on('xhr.dt', function(e, settings, json, xhr) {
});
});
//搜索框內容重置
function user_list_reset() {
$("input[name='user_list_repeatApply']").click();
}
//增長
function user_list_add() {
}
//刪除
function user_list_delete(param) {
var href = "/";
var title = "<p>警告! 所選取的數據將會被刪除!</p>";
var cb;
if(param=="1") {
var checkNum = $('input:checkbox[class="userCheckbox"]:checked').length;
var checkVal =[];
if(checkNum==0) {
alertMsg("<p>請選擇數據</p>","warning");
return;
}
$.each($('input:checkbox[class="userCheckbox"]:checked'),function(){
checkVal.push($(this).val());
});
cb = "user_list_delete_data('"+checkVal+"');";
} else {
cb = "user_list_delete_one_data('"+param+"');";
}
$("#smModal").attr("action",href).attr("callback", cb).find(".modal-body").html(title).end().modal("show");
//$("#smModal").modal("show");
}
function user_list_delete_data(checkVal) {
var options = {
url: '/admin/user/delete?checkVal='+checkVal,
type: 'get',
dataType: 'text',
success: function (data) {
if(data>0) {
user_tab.draw(false);
alertMsg("<p>成功刪除"+data+"條記錄</p>","success");
} else {
alertMsg("<p>刪除失敗</p>","danger");
}
}
};
$.ajax(options);
}
function user_list_delete_one_data(id) {
var options = {
url: '/admin/user/deleteOne?id='+id,
type: 'get',
dataType: 'text',
success: function (data) {
user_tab.draw(false);
alertMsg("<p>刪除成功</p>","success");
}
};
$.ajax(options);
}
//搜索
function user_list_query() {
user_list_setParm();
user_tab.settings()[0].ajax.data = user_list_param;
user_tab.ajax.reload();
}
//動態拼接參數
function user_list_setParm() {
var user_list_user_name = $("#user_list_user_name").val();
var user_list_true_name = $("#user_list_true_name").val();
user_list_param = {
"user_list_user_name" : user_list_user_name,
"user_list_true_name" : user_list_true_name
};
}
</script>
</body>
</html>
複製代碼
後臺類:
控制層
package com.tswc.edu.controller;
/**
* @ProjectName: edu
* @Package: com.tswc.edu.controller
* @ClassName: UserContraller
* @Author: DengZeng
* @Description: ${description}
* @Date: 2018/12/15 15:37
* @Version: 1.0
*/
import com.tswc.edu.entity.TUser;
import com.tswc.edu.service.UserService;
import com.tswc.edu.utils.Page;
import com.tswc.edu.utils.PageBean;
import com.tswc.edu.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 用戶管理
*
* @author UserContraller
* @create 2018-12-15 15:37
**/
@RequestMapping(value = "/admin/user")
@Controller
class UserContraller {
@Autowired
private UserService userService;
@RequestMapping(value = "/list")
public void list() {
}
//用戶列表
@ResponseBody
@RequestMapping(value = "/listPage", method = RequestMethod.POST)
public PageBean<TUser> listPage(@RequestParam(value = "start", defaultValue = "1") int start,
@RequestParam(value = "length", defaultValue = "10") int pageSize,
@RequestParam(value = "user_list_user_name") String userName,
@RequestParam(value = "user_list_true_name") String trueName,
@RequestParam(value = "order[0][column]", required = false) Integer orderIndex,
@RequestParam(value = "order[0][dir]", required = false) String orderDir) {
String[] cols = {"", "", "user_name", "password", "true_name", "create_time"};
Result<Page<TUser>> result = userService.listPage((start / pageSize) + 1, pageSize, userName, trueName, cols[orderIndex], orderDir);
if (result.isStatus()) {
return new PageBean<TUser>(result.getResultData());
}
return new PageBean<TUser>();
}
//刪除所選擇的的數據
@ResponseBody
@RequestMapping(value = "/delete", method = RequestMethod.GET)
public int delete(@RequestParam(value = "checkVal") String[] ids) {
int result = 0;
result = userService.delete(ids);
return result;
}
//刪除一條數據
@ResponseBody
@RequestMapping(value = "/deleteOne", method = RequestMethod.GET)
public void deleteOne(@RequestParam(value = "id") String id) {
userService.deleteOne(id);
}
}
複製代碼
服務層
package com.tswc.edu.service;
/**
* @ProjectName: edu
* @Package: com.tswc.edu.service
* @ClassName: UserService
* @Author: DengZeng
* @Description: ${description}
* @Date: 2018/12/15 21:25
* @Version: 1.0
*/
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.tswc.edu.entity.TUser;
import com.tswc.edu.mapper.UserMapper;
import com.tswc.edu.utils.ExampleUtils;
import com.tswc.edu.utils.Page;
import com.tswc.edu.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.entity.Example.Criteria;
import java.util.Arrays;
import java.util.List;
/**
* 用戶管理服務層
*
* @author UserService
* @create 2018-12-15 21:25
**/
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public Result<Page<TUser>> listPage(int pageCurrent, int pageSize, String userName, String trueName, String cols, String orderDir) {
Example example = new Example(TUser.class);
Criteria criteria = example.createCriteria();
ExampleUtils.getLikeExample(criteria, "userName", userName);
ExampleUtils.getLikeExample(criteria, "trueName", trueName);
example.setOrderByClause(cols + " " + orderDir);
//example.orderBy(cols+" "+orderDir);
Result<Page<TUser>> result = new Result<Page<TUser>>();
PageHelper.startPage(pageCurrent, pageSize);
List<TUser> tUsers = userMapper.selectByExample(example);
PageInfo<TUser> pageInfo = new PageInfo<TUser>(tUsers, pageSize);
Page<TUser> resultData = new Page<TUser>((int) pageInfo.getTotal(), pageInfo.getPages(), pageCurrent, pageSize, tUsers);
result.setResultData(resultData);
result.setErrCode(0);
result.setStatus(true);
return result;
}
public int delete(String[] ids) {
List<String> idList = Arrays.asList(ids);
Example example = new Example(TUser.class);
Criteria criteria = example.createCriteria();
criteria.andIn("id", idList);
return userMapper.deleteByExample(example);
}
public void deleteOne(String id) {
userMapper.deleteByPrimaryKey(id);
}
}
複製代碼
Mapper 接口
package com.tswc.edu.mapper;
import com.tswc.edu.entity.TUser;
import com.tswc.edu.utils.MyMapper;
public interface UserMapper extends MyMapper<TUser> {
}
複製代碼