1.前言
學習了SSM框架后練手,寫這個博客大概花了一個多星期。博客基本功能都有實現,后台代碼寫地比較簡單。前端頁面仿造Hexo博主的博客頁面(傳送門:https://jerryc.me/),由於本人前端技術有限,只能寫一個大概的頁面。
2.技術總結
前端:bootstrap+layui
(bootstrap主要用於實現響應式,layui寫后台管理系統頁面)
后台:SpringMVC+Spring+Mybatis
(Maven搭建環境)
數據庫:Mysql
3.主要功能
添加文章、管理文章、顯示/隱藏文章、添加標簽分類、管理標簽分類、評論文章、評論管理、分享文章、友鏈的管理、個人資料更新
4.數據庫設計
文章表
分類表
標簽表
標簽-文章映射表
評論表
友鏈表
用戶表
5.項目結構
6.部分頁面功能
(1)博客首頁
首頁文章列表分頁功能用的是layui的分頁模塊
HTML代碼:
JS代碼:
<script>
window.onload = function() {
loadData(); //請求文章數據
getPage(); //分頁操作
}
var page = 1; //設置首頁頁碼
var limit = 5; //設置一頁顯示的條數
var count; //總條數
function loadData() {
$.ajax({
type : "post",
url : "PostController/findByPageDesc",//對應controller的URL
async : false,
dataType : 'json',
data : {
"curr" : page,
"nums" : limit,
},
success : function(msg) {
count = msg.count; //設置總條數
var html = [];
var post = msg.data;
for (var i = 0; i < post.length; i++) {
html.push('<div class=" articleboder">'
+ '<div id="'
+ post[i].id
+'" class="col-sm-6 col-xs-12 articleimg" οnclick="javascript:article(this)">'
+ '<img src="./upload/'+post[i].img+'"/></div>'
+ '<div class="col-sm-6 col-xs-12 articleintro">'
+ '<div class="hidden-xs articlehidden"></div>'
+ '<div class="visible-xs articlevisible"></div>'
+ '<div id="'
+ post[i].id
+ '" class="title" οnclick="javascript:article(this)">'
+ post[i].title
+ '</div>'
+ '<div class="articledate">'
+ ' <span><i class="fa fa-calendar" aria-hidden="true"></i><a>'
+ post[i].timeString
+ '</a></span>'
+ ' <span><a>|</a></span>'
+ ' <span><i class="fa fa-inbox article-meta__icon" aria-hidden="true"></i><a>'
+ post[i].typeString
+ '</a></span>'
+ '</div>'
+ '<div class="intro">'
+ post[i].summary
+ '</div>'
+ '</div>'
+ '</div>');
}
$(".content").empty().append(html);
}
});
}
function getPage() {
layui.use('laypage', function() {
var laypage = layui.laypage;
//執行一個laypage實例
laypage.render({
elem : 'demo2', //注意,這里的 demo2 是 ID,不用加 # 號
count : count, //數據總數,從服務端得到
limit : limit, //每頁條數設置
theme : '#1E9FFF',
jump : function(obj, first) {
//obj包含了當前分頁的所有參數,比如:
console.log(obj.curr); //得到當前頁,以便向服務端請求對應頁的數據。
console.log(obj.limit); //得到每頁顯示的條數
page = obj.curr; //改變當前頁碼
limit = obj.limit;
//首次不執行
if (!first) {
loadData(); //加載數據
}
}
});
});
}
</script>
后台代碼:
@RequestMapping("/findByPageDesc")
public @ResponseBody String findByPageDesc(Integer curr, Integer nums) throws JsonProcessingException{
int pagenum=(curr - 1)*nums;
List<Post> posts = postService.findByPageDesc(pagenum, nums);
JSONObject object = new JSONObject();
object.put("code", 0);
object.put("msg", "");
object.put("count", postService.count());
object.put("data", posts);
System.out.println(object.toJSONString());
return object.toJSONString();
}
(2)隨機顏色大小標簽
HTML代碼:
JS代碼:
<script>
//分頁
window.onload = function() {
loadData(); //請求數據
label();
}
function loadData() {
$.ajax({
type : "post",
url : "TagController/selectAll",//對應controller的URL
async : false,
dataType : 'json',
success : function(msg) {
var html = [];
var tag = msg.data;
for (var i = 0; i < tag.length; i++) {
html.push('<a href="label_detail.jsp?tagid=' + tag[i].id
+ '">' + tag[i].tag + '</a>');
}
$(".content").empty().append(html);
}
});
}
function label() {
$(document).ready(function() {
var obj = $("#wrap a");//獲取a標簽中的數據
function rand(num) {
//parseInt();將字符串轉為整數
//Math.random();生成隨機數
return parseInt(Math.random() * num + 1);
}
function randomcolor() {
var str = Math.ceil(Math.random() * 16777215).toString(16);
if (str.length < 6) {
str = "0" + str;
}
return str;
}
for (len = obj.length, i = len; i--;) {
obj[i].style.left = rand(600) + "px";//標簽左右間距
obj[i].style.top = rand(400) + "px";//標簽上下間距
obj[i].className = "color" + rand(5);
obj[i].style.zIndex = rand(5);//設置元素的堆疊順序
obj[i].style.fontSize = rand(5) + 18 + "px";//隨機字體大小這里是18-23
obj[i].style.color = "#" + randomcolor();//字體顏色
obj[i].style.padding = rand(15) + "px";
}
});
}
</script>
后台返回標簽的Json字符串
(3)寫文章
文章內容使用的是百度的ueditor,百度ueditor下載JSP版本,把解壓后的文件放進項目目錄里,查看官方文檔進行配置。
(4)文章管理頁面
文章管理頁面用的是layui的table模塊,有編輯、刪除和顯示(隱藏)三個功能。
表格數據渲染:
HTML代碼:
<table id="test" lay-filter="test"></table>
JS代碼:
<script type="text/html" id="toolbarDemo">
<div class="layui-btn-container">
<button class="layui-btn layui-btn-sm" lay-event="getCheckData">獲取選中行數據</button>
<button class="layui-btn layui-btn-sm" lay-event="getCheckLength">獲取選中數目</button>
<button class="layui-btn layui-btn-sm" lay-event="isAll">驗證是否全選</button>
</div>
</script>
<script type="text/html" id="barDemo">
<a class="layui-btn layui-btn-sm layui-bg-blue" lay-event="edit">編輯</a>
<a class="layui-btn layui-btn-sm layui-btn-danger" lay-event="del">刪除</a>
</script>
<script id="switchTpl" type="text/html">
<input type="checkbox" name="display" value = {{d.display}} lay-skin="switch" lay-text="顯示|隱藏" lay-filter="display" {{ d.display == '1' ? 'checked' : '' }}>
</script>
<script src="${pageContext.request.contextPath}/resources/layui/layui.all.js"></script>
<script>
//JavaScript代碼區域
layui.use('element', function(){
var element = layui.element;
});
//顯示或隱藏文章
layui.use('form',function(){
var form = layui.form
form.on('switch(display)', function(obj){
//根據業務判斷是開啟還是關閉
var state = obj.elem.checked?0:1;
//取數據(根據索引table.cache里面的行數據)
var index = obj.othis.parents('tr').attr("data-index");
var id = tableData[index].id;
$.ajax({
url: '../PostController/display?id='+id+'&display='+state,
type: "post",
dataType:"json",
success: function(suc) {
if(suc.code === 1) {
if(suc.msg === 0){
layer.msg("文章已隱藏", {
icon: 6
});
}else if(suc.msg === 1){
layer.msg("文章已顯示", {
icon: 6
});
}
} else {
layer.msg("設置失敗,請稍后再試!", {
icon: 5
});
}
}
});
});
});
var tableData;
layui.use('table', function(){
var table = layui.table;
table.render({
elem: '#test'
,url:'../PostController/findByPage'
,method:'post'
,limits : [5,10,15,20]
,limit : 10
,request: {
pageName: 'curr' ,//頁碼的參數名稱,默認:page
limitName: 'nums' //每頁數據量的參數名,默認:limit
}
,toolbar: '#toolbarDemo' //開啟頭部工具欄,並為其綁定左側模板
,defaultToolbar: ['filter', 'exports', 'print', { //自定義頭部工具欄右側圖標。如無需自定義,去除該參數即可
title: '提示'
,layEvent: 'LAYTABLE_TIPS'
,icon: 'layui-icon-tips'
}]
,title: '用戶數據表'
,cols: [[
{type: 'checkbox', fixed: 'left'}
,{field:'id', title:'ID', width:70, unresize: true, sort: true}
,{field:'title', title:'標題',width:328}
,{field:'typeString', title:'分類',width:158}
,{field:'clickhit', title:'點擊數',width:125, sort: true}
,{field:'replyhit', title:'評論數',width:125, sort: true}
,{field:'timeString', title:'發表時間',width:188, sort: true}
,{field:'display', title:'顯示狀態',width:120,templet:"#switchTpl"}
,{fixed: '', title:'操作', fixed: 'right', width:132, toolbar: '#barDemo'}
]]
,page: true
,id:"tableIns"
,done:function(){
tableData = table.cache.tableIns;
}
});
//頭工具欄事件
table.on('toolbar(test)', function(obj){
var checkStatus = table.checkStatus(obj.config.id);
switch(obj.event){
case 'getCheckData':
var data = checkStatus.data;
layer.alert(JSON.stringify(data));
break;
case 'getCheckLength':
var data = checkStatus.data;
layer.msg('選中了:'+ data.length + ' 個');
break;
case 'isAll':
layer.msg(checkStatus.isAll ? '全選': '未全選');
break;
//自定義頭工具欄右側圖標 - 提示
case 'LAYTABLE_TIPS':
layer.alert('這是工具欄右側自定義的一個圖標按鈕');
break;
};
});
//監聽行工具事件
table.on('tool(test)', function(obj){
var data = obj.data
,layEvent = obj.event; //獲得 lay-event 對應的值
console.log(obj)
switch(layEvent){
case 'del':
var delIndex = layer.confirm('真的刪除"' + data.title + '"嗎?', function(delIndex) {
$.ajax({
url: '../PostController/delete?id='+data.id,
type: "post",
dataType:"json",
success: function(suc) {
if(suc.code === 1) {
obj.del(); //刪除對應行(tr)的DOM結構,並更新緩存
layer.close(delIndex);
console.log(delIndex);
layer.msg("刪除成功", {
icon: 1
});
} else {
layer.msg("刪除失敗", {
icon: 5
});
}
}
});
layer.close(delIndex);
});
break;
case 'edit':
/* $.ajax({ url: '../PostController/editPost?id='+data.id, type: "get" }); */
window.location.href="../PostController/editPost?id="+data.id;
break;
}
});
});
</script>
后台查詢、刪除、顯示(隱藏)文章的Controller省略
(5)圖片上傳功能和回顯
“我的友鏈”和“基本資料”頁面都有圖片上傳,用的是layui的文件上傳功能。圖書上傳成功后,前端頁面會回顯圖片。
HTML代碼:
JS代碼:
<script src="${pageContext.request.contextPath}/resources/layui/layui.all.js"></script>
<script>
//JavaScript代碼區域
layui.use('element', function(){
var element = layui.element;
});
window.onload= function () {
loadImg();
}
layui.use('upload', function(){
var upload = layui.upload;
//普通圖片上傳
upload.render({
elem: '#test1'
,url: '../UserController/uploadImg'
,accept: 'images'
,acceptMime: 'image/*'
,size: '1024*5'
,before: function(obj){
//預讀本地文件示例,不支持ie8
obj.preview(function(index, file, result){
$('#demo1').attr('src', result); //圖片鏈接(base64)
});
}
,done: function(res, input){
layer.msg('頭像上傳成功',{icon:6});
console.log(res); //如:{"code":0 ,"msg":"","url":"http://cdn.abc.com/123.jpg"'}
document.getElementById("myimg").innerHTML=res.name;
}
});
});
function loadImg(){
$.ajax({
type:"post",
url:"../UserController/photo",//對應controller的URL
dataType: 'json',
success:function(msg){
document.getElementById('demo1').src=msg.name;
}
});
}
</script>
(6)頁面加載動畫
加載動畫並不是真的會等待頁面數據加載完成后才隱藏,只是等待1000毫秒后隱藏。
HTML代碼:
JS代碼:
<script>
window.onload = function() {
setTimeout(function(){
siteLoading.classList.remove('active')
},1000);
}
</script>
CSS樣式:
.wrapper {
height: 200px;
width: 200px;
border: 1px solid #fff;
/* 將圓形動畫定位到正中 */
position: relative;
}
.wrapper::before,
.wrapper::after{
content: '';
height: 10px;
width: 10px;
background-color: black;
border-radius: 100%;
/* 將圓形動畫定位到正中 */
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
margin: auto;
animation: dada 2s linear infinite;
}
.wrapper::after {
animation-delay: 1s;
}
@keyframes dada {
0% {
height: 0px;
width: 0px;
opacity: 1;
}
100% {
height: 100px;
width: 100px;
opacity: 0;
}
}
.loading {
display: none;
background-color: #fff;
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 100%;
z-index: 999;
justify-content: center;
align-items: center;
}
.loading.active {
display: flex;
}