版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}
打开服务器,页面如下:
一个具有文章与评论发表、管理功能的简单博客系统就完成了。至此尚未完成的部分还有:文章图片上传、用户登录、全文搜索。