【实战】如何通过html+css+mysql+php来快速的制作动态网页(以制作一个博客网站为列)

mind_programmonkey 2020-11-13 04:23:01
html Mysql css 实战 html+css+mysql+php


   在暑假的这几天时间里,制作了一个简单的博客网站。下面我将这几天的操作流程来说一下,在原文末会贴上代码,也会给出下载链接。(闲复制代码麻烦的可以到下载地址这里直接下载 点击打开链接) 刚刚更新源码到github上点击打开链接

一、开发环境的搭建

   1)apache+php+mysql环境搭建

   因为要用apache来做服务器,mysql作为数据库来存储数据,php来写代码以此实现网页与数据库的交互数据,所以需要下载上述软件,但上述软件的安装环境、配置很麻烦,所以在这里用了一个功能强大的建站集成软件包---XAMPP,具体的安装方法可见链接(点击打开链接)。

        

   当然,也有可能启动Apache时候出现错误,这里给出链接(点击打开链接),如果apache启动有错误可以参考上面这个链接来解决问题。

   2)数据库客户端软件navigat

   直接在cmd命令控制台操作数据库并不方便,不够直白,当然也可以直接用phpmyadmin来操作(上述xampp软件包安装之后在游览器输入127.0.0.1/phpmyadmin即可打开),但是phpmyadmin来操作也不方便,这里便采用Oracle公司出品的数据库客户端Navicat,这里还是给出链接(点击打开链接),按照要求下载即可,

        点击连接,输入连接名,(这里我直接取了IP地址的名字127.0.0.1),主机名和端口号都不用变,这里的用户名和密码。如果是你用的是xampp,那么用户名是root,密码为空;如果不是用的是xampp安装的,按照你设置的用户名和密码登录即可。填写完毕之后点击连接测试,没有问题直接确定即可连接好数据库。

                            

    此外你要是想掌握数据库,简单来讲你想对数据库的任何操作,都必须操作sql语句,总的来说分为四个操作:增删改查。

                  

    ①增:向数据库写入数据

    语句:insert into users (`username`,`password`) values ('name','passwd')

    (ps新手一定要注意这离users这个数据表后面的``符号是在tab键上方的引号,而values后面的就是个单引号)

    ②删:删除已有数据

    语句:delete from users WHERE id='3'

    ③改:修改数据

    语句:update set users username='新值', password='新值' WHERE id=3

    ④查:从数据库读取数据

    语句:select * from users where id>1 order by id desc limit 0,2

    如果你想进一步深入的了解mysql语句的话,看一下这里的连接,点击打开链接连接给出了这四个操作的具体参数的详解,要想用数据库一定要掌握这四个操作。


   (3)html网页的编写工具sublime text

   Sublime Text 是一个代码编辑器(Sublime Text 2是收费软件,但可以无限期试用),也是HTML和散文先进的文本编辑器。Sublime text具有漂亮的用户界面和强大的功能,非常适合写代码的程序猿。在这里还是给出sublime text的安装方法以及注册码及常用插件的安装步骤,按照连接下载即可。(点击打开链接

         

   用sublime text来写网页代码,可以掌握这样一个小技巧,先新建一个文件,格式保存为html网页格式,然后在sublime text中打开,输入html:4s 然后按下tab键即可生成大体框架。当然这个快捷键要想使用是要按照我上述给的链接,按照步骤安装好Emmet这个插件,才能使用。

  4)网站域名的配置

   一般来讲,你在游览器打开127.0.0.1这个网址,会转到apache默认目录下的一个网址,这里我对其进行修改,修改为我做项目的目录,E:\PHP\xampp\apache\conf,打开httpd.conf文件,将里面的路径修改为你存储网站的目录,在这里我的修改为

    DocumentRoot "E:/php/xampp/workplace"
    <Directory "E:/PHP/xampp/workplace">

   这里要注意按照自己的下载按照路径来修改为自己的目录,其次我还对这个127.0.0.1这个网址再次做了修改,使其虚拟域名为blog.com,具体的配置及修改还是见链接点击打开链接),修改完之后重启之后,在游览器输入blog.com,便会出现下述场景:

       

   在这里我发现我修改的DNS配置,不知道何时再前面加了一条注释,导致没法打开,大家也要注意按照我给的连接配置好之后,如果打不开再看一下配置文件有无错误。

总之,配置环境和工具基本上也搭建成功了,接下来我就开始讲解这个blog的项目。

   二、博客网站的书写

   1.总体框架

   首先在这里我先介绍一下我的总体框架,讲解一下,让大家先熟悉一下。

             

  blog是项目的名字,admin文件夹里面存储的是后台登录文件  core文件夹里面存储核心文件,theme文件夹存储网页的样式文件  upfiles文件夹是存储从本地上传到服务器的图片信息,之后config.php文件是整个博客网站的配置文件,header.inc.php是加载了一个页面样式信息,index.php文件是网站的首页,read.php文件是网站首页文章的具体链接。


   数据库表中的设计在这里我给出,方便大家参考学习,这里我主要建立了三个表,admin这个表示用来存储后台管理员注册和登录的数据,即账户和密码:


    page这个表主要是用来存储博客信息,在这里也给图片,方便安装图来建表:


   最后给出setting这个表,主要是用来存储博客的系统设置:

            

  2.网站后台admin的书写

 1)登录界面(login.php)



   关于这个页面我会在这里给出源码,登录页面其实也就是个从数据库读取的过程,这个登录页面的设计我主要是采用了bootstrap来设计的,不明白的可以百度一下bootstrap,可以参考我的链接来看一下(点击打开链接


   在这里面它包含了各式的样式、组件和JavaScript插件,可以说很好用。

        

   在这里我的使用方法是将bootstrap下载下来,然后将文件加压,复制到theme这个文件夹下面,调用方法见下面的源码,在源码中我都给出了详细的解释。

   源码:

  

<?php
/*
后台管理员登录窗口
*/
/*启动session服务,记录账号登录的cookies*/
session_start();
/*包含一个配置文件*/
include('../config.php');
if($input->get('do')=='check'){
/*获取页面提交的用户名和密码数据*/
$ausername=$input->post('ausername');
$apassword=$input->post('apassword');
/*查询页面提交的数据是否在数据库提供的数据存在的sql语句*/
$sql="select * from admin where ausername='{$ausername}' and apassword='{$apassword}' ";
/*数据库查询语句返回结果*/
$mysqli_result=$db->query($sql);
/*以数组形式存储数据库查询语句的返回结果*/
$row=$mysqli_result->fetch_array( MYSQLI_ASSOC);
/*如果row确实返回了结果,则将结果的aid存储在session里,并转向home.php文件*/
if(is_array($row)){
$_SESSION['aid']=$row['aid'];
header("location:home.php");
}else{
echo("账户或密码错误");
}
}
?>
<!--后台管理员登录界面></!-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>管理员登录界面</title>
<!--加载包含bootstrap里css和javascript里的文件></!-->
<?php include(PATH . '/header.inc.php');?>
</head>
<body>
<!--最外面的container容器></!-->
<div class="container">
<!--bootstrap使用时建议使用一个row表格类,包含12个列></!-->
<div class="row" style="margin-top:200px;">
<!--距左边3个列></!-->
<div class="col-md-3"></div>
<!--中间部分占据6列></!-->
<div class="col-md-6" ">
<div class="panel panel-primary">
<!--登录头部分></!-->
<div class="panel-heading">管理员登录</div>
<!--登录的身体部分></!-->
<div class="panel-body">
<form class="form-horizontal" action="login.php?do=check" method="post">
<!--登录的用户名那一行></!-->
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">用户名</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="ausername" id="ausername" placeholder="请输入用户名" datatype="*3-10" errormsg="请输入长度 范围在3-10之间的昵称">
</div>
</div>
<!--登录的密码那一行></!-->
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">密码</label>
<div class="col-sm-10">
<input type="password" class="form-control" name="apassword" id="apassword" placeholder="请输入密码">
</div>
</div>
<!--登录、注册那一行></!-->
<div class="form-group">
<div class="col-sm-3"></div>
<!--登录></!-->
<div class="col-sm-4">
<input type="submit" value="登录" class='btn btn-primary'>
</div>
<!--注册></!-->
<div class="col-sm-4">
<a href="register.php"><input type="button" value="注册" class="btn btn-primary"> </a>
</div>
</div>
</form>
</div>
<!--登录的尾部分></!-->
<div class="panel-footer text-right">版权所有,盗版必究</div>
</div>
</div>
<!--距离右边三列></!-->
<div class="col-md-3"></div>
</div>
</div>
<!--窗口背景的script加载></!-->
<script type="text/javascript">
window.onload = function() {
var config = {
vx : 4,
vy : 4,
height : 2,
width : 2,
count : 100,
color : "121, 162, 185",
stroke : "100, 200, 180",
dist : 6000,
e_dist : 20000,
max_conn : 10
}
CanvasParticle(config);
}
</script>
<script type="text/javascript" src="../theme/js/canvas-particle.js"></script>
</script>
</body>
</html>

   (2)注册界面(register.php)

   注册界面其实也就是个往数据库增加数据的过程。

  

   还是给出源码,源码中我给出了详解。

  

<?php
/*包含一个配置文件*/
include('../config.php');
if($input->get('do')=='check'){
/*获取用户页面注册传来的用户名和密码数据*/
$ausername=$input->post('ausername');
$apassword=$input->post('apassword');
$aconfirmpassword=$input->post('aconfirmpassword');
/*注册时的处理*/
if($apassword!=$aconfirmpassword){
echo "前后两次输入的密码不一致";
exit;
}
/*将用户填入的数据插入到数据库的sql语句*/
$sql="INSERT INTO admin(`ausername`,`apassword`) values('$ausername','$apassword')";
/*提交sql语句到数据库处理*/
$is=$db->query($sql);
/*判断是否注册成功*/
if($is){
echo "注册成功";
header("Location:login.php");
}else{
echo "注册失败";
}
}
?>
<!--后台管理员登录界面></!-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>管理员注册界面</title>
<!--加载包含bootstrap里css和javascript里的文件></!-->
<?php include(PATH . '/header.inc.php');?>
</head>
<body>
<!--最外面的container容器></!-->
<div class="container">
<!--bootstrap使用时建议使用一个row表格类,包含12个列></!-->
<div class="row" style="margin-top:200px;">
<!--距左边3个列></!-->
<div class="col-md-3"></div>
<!--中间部分占据6列></!-->
<div class="col-md-6" ">
<div class="panel panel-primary">
<!--注册头部分></!-->
<div class="panel-heading">管理员注册</div>
<!--注册的身体部分></!-->
<div class="panel-body">
<form class="form-horizontal" action="register.php?do=check" method="post">
<!--注册的用户名那一行></!-->
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">用户名</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="ausername" id="ausername" placeholder="请输入用户名">
</div>
</div>
<!--注册的密码那一行></!-->
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">密码</label>
<div class="col-sm-10">
<input type="password" class="form-control" name="apassword" id="apassword" placeholder="请输入密码">
</div>
</div>
<!--注册的密码确定那一行></!-->
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">确认密码</label>
<div class="col-sm-10">
<input type="password" class="form-control" name="aconfirmpassword" id="aconfirmpassword" placeholder="请再次输入密码">
</div>
</div>
<!--提交注册那一行></!-->
<div class="form-group">
<div class="col-sm-4"></div>
<div class="col-sm-6">
<input type="submit" value="注册" class='btn btn-primary btn-lg btn-block'>
</div>
</div>
</form>
</div>
<!--登录的尾部分></!-->
<div class="panel-footer text-right">版权所有,盗版必究</div>
</div>
</div>
<!--距离右边三列></!-->
<div class="col-md-3"></div>
</div>
</div>
<!--窗口背景的script加载></!-->
<script type="text/javascript">
window.onload = function() {
var config = {
vx : 4,
vy : 4,
height : 2,
width : 2,
count : 100,
color : "121, 162, 185",
stroke : "100, 200, 180",
dist : 6000,
e_dist : 20000,
max_conn : 10
}
CanvasParticle(config);
}
</script>
<script type="text/javascript" src="../theme/js/canvas-particle.js"></script>
</script>
</body>
</html>

   3)后台管理页面(home.php)



 在源码中将上述网站的标题那部分单独给拿出来做了一个文件(nav.inc.php,这里也是给出源码,供大家学习参考。

 home.php源码

<?php
/*
后台管理员登录之后php控制端
*/
include ('check.php');
?>
<!--后台管理员登录之后的界面<>/!-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>管理员登录</title>
<?php include(PATH . '/header.inc.php');?> <!--所有的页面都需加载这个文件></!-->
</head>
<body>
<?php include('nav.inc.php');?> <!--管理员登录页面的标题部分></!-->
</body>
</html>
 nav.inc.php

 

<!--后台管理界面的上方标题></!-->
<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="home.php">ADMIN</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li ><a href="blog.php">博客管理 <span class="sr-only">(current)</span></a></li>
<li><a href="auser.php">管理员管理</a></li>
<li><a href="setting.php">系统管理</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"> <?php echo $session_user['ausername'];?> <span class="caret"></span></a> <!--输出此时登录的账户名></!-->
<ul class="dropdown-menu">
<li><a href="logout.php">退出</a></li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav> 

  4)博客管理界面(blog.php

  这里有三个功能,修改、删除、添加博客界面,下面我将单独列出添加博客这个界面




  (5)添加博客界面(blog_add.php)

   为什么要单独列出添加博客这个界面呢?因为在添加博客这个界面中加载了一个编辑器,一个强大的在线编辑器simditor,这里还是给出下载及使用连接,大家可以作为参考,学习一下点击打开链接在这里这个编辑器如果需要图片上传功能的话,需要在文件中设置,这个文件设置为(blog_uopload.php)

   blog_add.php源码

 

<?php
/*后台除去管理员登录界面,均需加载这个文件,来验证该页面管理员是否登录*/
include ('check.php');
/*取出传来的pid从而判断是添加还是修改操作*/
$pid=$input->get('pid');
/*初始化page,为了区别添加还是修改操作*/
$page=array(
'title' => '',
'author' => '',
'content' => '',
);
/*如果pid大于0,可以得出并不是添加操作,而是修改操作*/
if($pid>0){
$sql="select * from page where pid ='{$pid}' ";
$res=$db->query($sql);
$page=$res->fetch_array(MYSQLI_ASSOC);
}
/*对于添加操作操作而言,账户或密码不能为空*/
if($input->get('do')=='add'){
$title=$input->post('title');
$author=$input->post('author');
$content=$input->post('content');
if(empty($title)||empty($author)||empty($content)){
echo("数据不能为空");
}
/*如果aid大于1,则得出更新操作,否则执行添加操作*/
if($pid>0){
$uptime=time();
$sqlTpl="UPDATE page set title='%s',author='%s',content='%s',uptime='%d' where pid='%d' ";
$sql=sprintf($sqlTpl,$title,$author,$content,$uptime,$pid);
}
else{
$intime=time();
$sqlTpl="INSERT INTO page(`title`,`author`,`content`,`intime`,`uptime`) values('%s','%s','%s','%d','%d')";
$sql=sprintf($sqlTpl,$title,$author,$content,$intime,0);
}
/*判断是否有结果*/
$is=$db->query($sql);
if($is){
header("location:blog.php");
}else{
echo "执行失败";
}
}
?>
<!--管理员添加博客或修改博客的界面<>/!-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>添加博客</title>
<?php include(PATH . '/header.inc.php');?>
<!--加载simiditor编辑器的文件></!-->
<link rel="stylesheet" type="text/css" href="../theme/simditor/styles/simditor.css" />
<script type="text/javascript" src="../theme/simditor/scripts/module.js"></script>
<script type="text/javascript" src="../theme/simditor/scripts/hotkeys.js"></script>
<script type="text/javascript" src="../theme/simditor/scripts/uploader.js"></script>
<script type="text/javascript" src="../theme/simditor/scripts/simditor.js"></script>
</head>
<body>
<?php include('nav.inc.php');?>
<div class="container">
<h2> 博客管理 <small class="pull-right"><a class='btn btn-default' href="blog.php">返回</a></small></h2>
<hr/>
<div class="rows">
<form class="form-horizontal" role="form" action="blog_add.php?do=add&pid=<?php echo $pid;?>" method="post">
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">标题</label>
<div class="col-sm-6">
<input type="text" class="form-control" name="title" placeholder="请输入标题" value='<?php echo $page['title'];?>'>
</div>
</div>
<div class="form-group">
<label for="inputPassword3" class="col-sm-2 control-label">作者</label>
<div class="col-sm-4">
<input type="text" class="form-control" name="author" placeholder="请输入作者" value='<?php echo $page['author'];?>' >
</div>
</div>
<div class="form-group">
<label for="inputPassword3" class="col-sm-2 control-label">正文</label>
<div class="col-sm-8">
<textarea id="content" name="content" class="form-control"><?php echo $page['content'];?></textarea>
<!--在script中初始化编辑器,在这里注意script里加载的textarea的ID要与上方textarea的id号一致></!-->
<script>
var editor = new Simditor({
textarea: $('#content'),
upload:{
url:'blog_upload.php',
fileKey:'file1'
}
//optional options
});
</script>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-6">
<button type="submit" class="btn btn-default">提交</button>
</div>
</div>
</form>
</div>
</div>
</body>
</html>
 
  

  blog_upload.php源码

 

<?php
/*后台除去管理员登录界面,均需加载这个文件,来验证该页面管理员是否登录*/
include('check.php');
/*将文件上传到服务器的目录里*/
$key='file1';
$dir='../upfiles/';
if(isset($_FILES[$key])){
$file=$_FILES[$key];
if($file['error']==0){
/*文件所处服务器的目录*/
$pathName=$dir . $file['name'];
/*文件所在服务器的网址*/
$urlName='http://blog.com/blog/upfiles' . $file['name'];
$is=move_uploaded_file($file['tmp_name'], $pathName);
/*判断是否移动成功*/
if(!$is){
die("上传失败");
}
/*编辑器来判断是否成功上传图片*/
$json=array(
'success' => true,
'msg' => '',
'file_path'=>$urlName
);
echo json_encode($json);
}
}
?>

  6)管理员管理界面(auser.php)

  这里还是有三个功能,修改、删除和添加,这里我就不单独一一列出来了,具体可参考文末给出的源码

 

  7)系统管理界面

  系统管理可以在这里设置标题、介绍和博客每页的显示数量

 




  3.主界面index.php)

  这里是游客访问的主界面,这里给出源码大家作为参考,

 

  阅读界面(read.php)

  当你想阅读该文章时,可点击标题进入阅读页,进行阅读,同样给出源码,作为参考





版权声明
本文为[mind_programmonkey]所创,转载请带上原文链接,感谢
https://codingchaozhang.blog.csdn.net/article/details/77164682

  1. [front end -- JavaScript] knowledge point (IV) -- memory leakage in the project (I)
  2. This mechanism in JS
  3. Vue 3.0 source code learning 1 --- rendering process of components
  4. Learning the realization of canvas and simple drawing
  5. gin里获取http请求过来的参数
  6. vue3的新特性
  7. Get the parameters from HTTP request in gin
  8. New features of vue3
  9. vue-cli 引入腾讯地图(最新 api,rocketmq原理面试
  10. Vue 学习笔记(3,免费Java高级工程师学习资源
  11. Vue 学习笔记(2,Java编程视频教程
  12. Vue cli introduces Tencent maps (the latest API, rocketmq)
  13. Vue learning notes (3, free Java senior engineer learning resources)
  14. Vue learning notes (2, Java programming video tutorial)
  15. 【Vue】—props属性
  16. 【Vue】—创建组件
  17. [Vue] - props attribute
  18. [Vue] - create component
  19. 浅谈vue响应式原理及发布订阅模式和观察者模式
  20. On Vue responsive principle, publish subscribe mode and observer mode
  21. 浅谈vue响应式原理及发布订阅模式和观察者模式
  22. On Vue responsive principle, publish subscribe mode and observer mode
  23. Xiaobai can understand it. It only takes 4 steps to solve the problem of Vue keep alive cache component
  24. Publish, subscribe and observer of design patterns
  25. Summary of common content added in ES6 + (II)
  26. No.8 Vue element admin learning (III) vuex learning and login method analysis
  27. Write a mini webpack project construction tool
  28. Shopping cart (front-end static page preparation)
  29. Introduction to the fluent platform
  30. Webpack5 cache
  31. The difference between drop-down box select option and datalist
  32. CSS review (III)
  33. Node.js学习笔记【七】
  34. Node.js learning notes [VII]
  35. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  36. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  37. 【JQuery框架,Java编程教程视频下载
  38. [jQuery framework, Java programming tutorial video download
  39. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  40. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  41. 【Vue,阿里P8大佬亲自教你
  42. 【Vue基础知识总结 5,字节跳动算法工程师面试经验
  43. [Vue, Ali P8 teaches you personally
  44. [Vue basic knowledge summary 5. Interview experience of byte beating Algorithm Engineer
  45. 【问题记录】- 谷歌浏览器 Html生成PDF
  46. [problem record] - PDF generated by Google browser HTML
  47. 【问题记录】- 谷歌浏览器 Html生成PDF
  48. [problem record] - PDF generated by Google browser HTML
  49. 【JavaScript】查漏补缺 —数组中reduce()方法
  50. [JavaScript] leak checking and defect filling - reduce() method in array
  51. 【重识 HTML (3),350道Java面试真题分享
  52. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  53. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  54. [re recognize HTML (3) and share 350 real Java interview questions
  55. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  56. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  57. 【重识 HTML ,nginx面试题阿里
  58. 【重识 HTML (4),ELK原来这么简单
  59. [re recognize HTML, nginx interview questions]
  60. [re recognize HTML (4). Elk is so simple