从简到繁——SSM个人博客搭建完全记录【4】前台页面设计

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/van_brilliant/article/details/80260767

前言

  搭建完一个简单的后台管理系统之后,接下来进行前台页面的开发。一共两个前台页面——主页和博客页面,在看了很多博客之后我决定仿照王垠的博客,风格简洁,当然主要还是因为实现起来比较简单。

后端开发

  前台对应的后端只有Controller层,Service层和Dao层在之前都已经编写好,直接调用即可。HomeController.java代码如下:

package com.vansl.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.vansl.dto.BlogData;
import com.vansl.entity.BlogComment;
import com.vansl.service.BlogCommentService;
import com.vansl.service.BlogService;
import com.vansl.service.BlogTypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * @author: vansl
 * @create: 18-3-17 下午11:58
 */
@Controller
public class HomeController {

    @Autowired
    BlogService blogService;

    @Autowired
    BlogTypeService blogTypeService;

    @Autowired
    BlogCommentService blogCommentService;

    // 主页
    @GetMapping("/")
    public  String index(HttpServletRequest request){
        request.setAttribute("welcome","主页");
        request.setAttribute("articleList",blogService.selectAll(1,true,1,Integer.MAX_VALUE).getData());
        request.setAttribute("typeData", JSON.toJSONString(blogTypeService.selectAll(1)));
        //返回index.jsp
        return "index";
    }
    
    // 选择分类后显示分类所属文章
    @GetMapping(value="/article",params ={"userId","typeId"})
    public  String index(Integer userId,Integer typeId,HttpServletRequest request){
        request.setAttribute("welcome","博客分类");
        request.setAttribute("articleList",blogService.selectByTypeId(userId,typeId,true,1,Integer.MAX_VALUE).getData());
        request.setAttribute("typeData", JSON.toJSONString(blogTypeService.selectAll(1)));
        //返回index.jsp
        return "index";
    }
    
    // 博客页面
    @GetMapping("/article/{id}")
    public  String article(@PathVariable  Integer id, HttpServletRequest request){
        BlogData blogData=blogService.selectById(id);
        // 如果未发表则拒绝访问
        if (blogData.getPublished()==1){
            return "denied";
        }
        // 返回评论信息
        List<BlogComment> comments=blogCommentService.selectByBlogId(id,1,Integer.MAX_VALUE);
        //转换地址和时间
        for (BlogComment comment:comments){
            try {
                JSONObject addressJson=(JSONObject)JSON.parseObject(comment.getAddress()).get("data");
                comment.setAddress((String)addressJson.get("city")+" "+addressJson.get("isp"));
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        request.setAttribute("blogData",blogData);
        request.setAttribute("blogContent",blogService.selectContentByBlogId(id));
        request.setAttribute("comments",comments);

        //返回article.jsp
        return "article";
    }
}

页面开发

  博客主页主要是一个取出文章信息列表和分类列表,然后实现无极分类建立树形结构;而文章页面主要是一个评论的提交。由于页面结构和功能都比较简单,不再赘述。直接放上代码。

index.jsp:

<%--
  Created by IntelliJ IDEA.
  User: vansl
  Date: 18-4-30
  Time: 下午12:41
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<html>
<head>
    <title>vansl-个人网站-${welcome}</title>
    <link rel="stylesheet" href="/css/index.css">
    <script src="/layui/layui.js"></script>
    <script src="/js/jquery-3.3.1.min.js"></script>
</head>

<body>
    <nav class="top">
        <div class="navbar-brand">代码与漫谈</div>
        <div class="navbar-module">
            <ul>
                <li class="active">
                    <a href="/#">博客</a>
                </li>
                <li>
                    <a href="/others">其他</a>
                </li>
                <li>
                    <a href="/login">管理</a>
                </li>
            </ul>
        </div>
    </nav>

    <div class="content">

        <div class="category"></div>

        <div class="article">
            <ul class="article-list">

                <c:forEach var = "article" items="${articleList}" begin="0">
                    <li class="article-list-item">
                        <a href="/article/${article.id}">${article.title}</a>
                    </li>
                </c:forEach>

            </ul>
        </div>
    </div>
</body>

<script type="text/javascript">
    var jq= jQuery.noConflict();

    //菜单列表html
    var menu = '';

    function BuildTree(data) {
        if (data&&data.length> 0) {
            menu += '<ul>';
            for (var i in data) {
                menu+= '<li><a href="/article?userId=1&typeId='+data[i].id+'">'+data[i].text+'</a>';
                //如果有子节点则加上一层ul实现缩进
                if(data[i].children){
                    BuildTree(data[i].children);
                }
                menu+= '</li>';
            }
            menu += '</ul>';
        }

    }

    jq(function () {
        BuildTree(${typeData});
        jq(".category").append(menu);

    });

</script>

</html>

index.css,做了简单的分辨率适配:

a{
    text-decoration:none;
}

li{
    list-style: none;
}

nav.top{
    background-color: #fff;
    opacity: .9;
    width:100%;
    height:50px;
    top:0;
    left:0;
    position: fixed;
    border-bottom:solid 1px #e7e7e7;
    z-index:999;
}

@media (max-width: 1000px) {
    nav.top{
        height:180px;
    }
}

nav .navbar-brand{
    float: left;
    font-size: 24px;
    color: #777;
    padding: 10px;
    height: 50px;
    margin-left: 10px;
}

@media (max-width: 1000px) {
    nav .navbar-brand{
        font-size: 58px;
        padding: 50px;
        height:180px;
    }
}

div.navbar-module{
    font-size: 24px;
    color: #777;
}

@media (max-width: 1000px) {
    div.navbar-module{
        font-size: 58px;
    }
}

.navbar-module>ul{
    float: right;
    display: block;
    margin: 0;
}
.navbar-module li{
    float: left;
    position: relative;
    display: block;
    margin: 0;
}

.navbar-module li>a{
    text-shadow: 0 1px 0 rgba(255,255,255,.25);
    height: 30px;
    padding: 10px 15px;
    display: block;
    color: #555;
}

@media (max-width: 1000px) {
    .navbar-module li>a{
        height: 120px;
        padding: 30px 30px;
    }
}

.navbar-module li.active>a{
    background-image: linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);
    background-repeat: repeat-x;
    box-shadow: inset 0 3px 9px rgba(0,0,0,.075);
    background-color: #e7e7e7;
}

div.content{
    z-index: 1;
}

div.category{
    width:10%;
    margin-top:20px;
    margin-left: -30px;
    position: fixed;
}

@media (max-width: 1000px) {
    div.category{
        width:30%;
    }
}

.category li{
    margin-top: 3px;
}
.category ul{
    display: block;
    margin-top: 10px;
    margin-bottom: 20px;

}
.category a{
    white-space: nowrap;
    font-size: 18px;
    border: 1px solid #ddd;
    background-color: #fff;
    color: #428bca;
}

@media (max-width: 1000px) {
    .category a {
        font-size: 43px;
    }
}

div.article{
    display: block;
    margin-left: 10%;
    margin-top:100px;
    margin-bottom: 20px;
}

@media (max-width: 1000px) {
    div.article{
        margin-top:300px;
        margin-left: 30%;
    }
}

.article-list:first-child {
    border-top-right-radius: 4px;
    border-top-left-radius: 4px;
}

li.article-list-item{
    border: 1px solid #ddd;
    background-color: #fff;
    cursor: pointer;
    padding: 15px 20px;
    margin-bottom: -1px;
}

li.article-list-item:hover{
    background-color: #EDEDED;
}

.article-list-item a{
    display: block;
    font-size: 21px;
    color: #428bca;
}

@media (max-width: 1000px) {
    .article-list-item a{
        font-size: 58px;
    }
}

.article-list-item a:hover{
    text-decoration: underline;
}

li{
    list-style: none;
}

nav.top{
    background-color: #fff;
    opacity: .9;
    width:100%;
    height:50px;
    top:0;
    left:0;
    position: fixed;
    border-bottom:solid 1px #e7e7e7;
    z-index:999;
}

@media (max-width: 1000px) {
    nav.top{
        height:180px;
    }
}

nav .navbar-brand{
    float: left;
    font-size: 24px;
    color: #777;
    padding: 10px;
    height: 50px;
    margin-left: 10px;
}

@media (max-width: 1000px) {
    nav .navbar-brand{
        font-size: 58px;
        padding: 50px;
        height:180px;
    }
}

div.navbar-module{
    font-size: 24px;
    color: #777;
}

@media (max-width: 1000px) {
    div.navbar-module{
        font-size: 58px;
    }
}

.navbar-module>ul{
    float: right;
    display: block;
    margin: 0;
}
.navbar-module li{
    float: left;
    position: relative;
    display: block;
    margin: 0;
}

.navbar-module li>a{
    text-shadow: 0 1px 0 rgba(255,255,255,.25);
    height: 30px;
    padding: 10px 15px;
    display: block;
    color: #555;
}

@media (max-width: 1000px) {
    .navbar-module li>a{
        height: 120px;
        padding: 30px 30px;
    }
}

.navbar-module li.active>a{
    background-image: linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);
    background-repeat: repeat-x;
    box-shadow: inset 0 3px 9px rgba(0,0,0,.075);
    background-color: #e7e7e7;
}

div.content{
    z-index: 1;
}

div.category{
    width:10%;
    margin-top:20px;
    margin-left: -30px;
    position: fixed;
}

@media (max-width: 1000px) {
    div.category{
        width:30%;
    }
}

.category li{
    margin-top: 3px;
}
.category ul{
    display: block;
    margin-top: 10px;
    margin-bottom: 20px;

}
.category a{
    white-space: nowrap;
    font-size: 18px;
    border: 1px solid #ddd;
    background-color: #fff;
    color: #428bca;
}

@media (max-width: 1000px) {
    .category a {
        font-size: 43px;
    }
}

div.article{
    display: block;
    margin-left: 10%;
    margin-top:100px;
    margin-bottom: 20px;
}

@media (max-width: 1000px) {
    div.article{
        margin-top:300px;
        margin-left: 30%;
    }
}

.article-list:first-child {
    border-top-right-radius: 4px;
    border-top-left-radius: 4px;
}

li.article-list-item{
    border: 1px solid #ddd;
    background-color: #fff;
    cursor: pointer;
    padding: 15px 20px;
    margin-bottom: -1px;
}

li.article-list-item:hover{
    background-color: #EDEDED;
}

.article-list-item a{
    display: block;
    font-size: 21px;
    color: #428bca;
}

@media (max-width: 1000px) {
    .article-list-item a{
        font-size: 58px;
    }
}

.article-list-item a:hover{
    text-decoration: underline;
}

article.jsp:

<%--
  Created by IntelliJ IDEA.
  User: vansl
  Date: 18-5-5
  Time: 上午11:54
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<html>
<head>
    <title>${blogData.title}</title>
    <script src="/js/jquery-3.3.1.min.js"></script>
    <script src="/layui/layui.js"></script>
    <script src="/js/article.js"></script>

    <link rel="stylesheet" href="/css/article.css">

</head>
<body  style="height: 100%">

<div class="inner">
    <h2 id="article-title">${blogData.title}</h2>

    <p id="article-time" align="right">
        <fmt:formatDate value="${blogData.time}" pattern="yyyy/MM/dd" />
    </p>

    <div id="article-content">${blogContent}</div>
</div>

<div class="comment-list">
    <c:forEach var = "comment" items="${comments}" begin="0">
        <div class="comment">
            <strong>${comment.name}(${comment.contact}):</strong>
            <p>
                ${comment.content}
            </p>
            <strong class="comment-info" style="font-weight:bold;">
                <fmt:formatDate value="${comment.time}" type="date" pattern="yyyy/MM/dd HH:mm:ss" />
                ${comment.address}
            </strong>
        </div>
    </c:forEach>
</div>

<div class="submit_commit">
        <label>称       呼<span style="color:red">*</span></label><input id="name" />
    <label>联系方式<span style="color:red">*</span></label><input id="contact" />
        <label>评论内容<span style="color:red">*</span></label>
        <textarea id="comment-content"></textarea>
        <button id="submit">提交</button>
</div>
</body>

</html>
articel.js:
var jq= jQuery.noConflict();

function parseTime(time){
    var date = new Date(time);//如果date为13位不需要乘1000
    var Y = date.getFullYear() + '/';
    var M = (date.getMonth()+1 < 10 ? '0'+(date.getMonth()+1) : date.getMonth()+1) + '/';
    var D = (date.getDate() < 10 ? '0' + (date.getDate()) : date.getDate());
    return Y+M+D;
}
jq("#article-time").text(parseTime("${blogData.time}"));

//点击之后恢复未填写信息而变红的输入框颜色
var commentInfo=["#name","#contact","#comment-content"];
commentInfo.forEach(function (item) {
    jq(item).click(function(){
        jq(item).css("border","1px solid LightGrey");
    });
});
jq("#submit").click(function () {
    //检查是否所有字段已经填写
    for (var i=0 ;i < commentInfo.length; i++) {
        if(!jq(commentInfo[i]).val()){
            layui .use('layer', function(){
                jq(commentInfo[i]).css("border","1px solid red");
                var layer = layui.layer;
                layer.msg('请补全评论信息', {icon: 2,time: 1000});
            });
            return;
        }
    }
    //禁用按钮防止重复提交
    jq('#submit').click(function () {
        return false;
    });
    // 异步提交数据
    jq.ajax({
        url: "/comment/",
        type: "post",
        data:JSON.stringify({
            "name":jq('#name').val(),
            "contact":jq('#contact').val(),
            "content":jq('#comment-content').val(),
            "blogId":window.location.href.split("/")[4],
        }),
        contentType: "application/json; charset=utf-8",
        success: function (result) {
            layui .use('layer', function(){
                var layer = layui.layer;
                layer.msg('评论发表成功', {icon: 1,time: 3000});
            });
            setTimeout(function () {
                window.location.reload();
            },1000);
        }
    });
});

article.css:

body {
    font-family: "lucida grande", "lucida sans unicode", lucida, helvetica, "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif;
    font-size: 18px;
}
@media (max-width: 1000px) {
    body {
        font-size:48px;
    }
}
#article-title{
    font-family: "Palatino Linotype", "Book Antiqua", Palatino, Helvetica, STKaiti, SimSun, serif;
    padding: 5px;
    border-bottom: 2px LightGrey solid;
    width: 98%;
    line-height: 150%;
    color: #666666;
}
div.inner {
    margin: 0% 14%;
    padding: 2% 8% 4% 8%;
    border: 1px solid LightGrey;
}

@media (max-width: 1000px) {
    div.inner {
        margin: 0% 2%;
        padding: 1% 4% 2% 4%;
    }
}

div.comment-list>div.comment{
    margin: 2% 14%;
    border: 1px solid LightGrey;
    height:auto!important;
}
strong{
    display:block;
}
@media (max-width: 1000px) {
    div.comment-list>div.comment{
        font-size: 38px;
        margin: 1% 2%;
    }
}

div.submit_commit {
    margin: 2% 14%;
    display: grid;
    grid-row-gap:10px;
    grid-template-rows: 30px 30px 80px 30px;
    grid-template-columns: 120px 400px;
}

@media (max-width: 1000px) {
    div.submit_commit {
        margin: 1% 2%;
        grid-template-rows: 60px 60px 160px 60px;
        grid-template-columns: 30% 60%;
        font-size: 38px;
    }
}

#comment-content{
    overflow: hidden;
}  

  打开服务器,页面如下:

    

  一个具有文章与评论发表、管理功能的简单博客系统就完成了。至此尚未完成的部分还有:文章图片上传、用户登录、全文搜索。

猜你喜欢

转载自blog.csdn.net/van_brilliant/article/details/80260767