• 基于SSM的个人博客


    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;
    }
    
  • 相关阅读:
    IDOC练习(一、发送端配置)
    节约性能的一个sql
    获取用户IP地址及用户名
    获取一个结构的所有字段
    获取文件名称的两个函数
    时间戳
    SMOD和CMOD
    内表生成XML简单实例
    ABAP&nbsp;编辑器设置(主动…
    ABAP常用Function
  • 原文地址:https://www.cnblogs.com/does/p/13621481.html
Copyright © 2020-2023  润新知