一天之内如何纯手写一个个人博客?

版本1.0

在高中时,尝试建起了个人博客,但那时候是jsp+servlet写的,数据库也是单纯的jdbc,增删该查,前端也是没用到过其他技术,图已经早不到了,想想1.0这个版本非常磕碜,而且代码编辑器是一个富文本,具体名字还给忘了,那时候也没怎么写文章,在服务器上面安静的躺了半年。

版本2.0

在大一开学前,学了SpringBoot+Mybatis+Thymeleaf等知识,匆匆忙忙用他完成了2.0版本,效果图如下,貌似也挺磕碜的,磕碜到只写了10篇文章,后来在学习其他东西,也没有管过他,又在服务器上面安静的躺了1年,但是技术用到了很多,如bootstrap做了响应式,实现三种不同布局,layui做了后端管理界面,并且也有文章评价等功能,算是一个完完整整的博客,但是唯一感到不好的是编辑器用了百度的Ueditor富文本。不知道现在有没有人用了。去问别的博主,人家用的Emlog、Wordpress、Typecho等建站系统,没为找编辑器发愁过。当时也考虑用人家开源的,但是想想也学不到啥,就放弃了。
在这里插入图片描述

版本3.0

今年假期,开始做3.0,2.0实现看不下去了,并且新学的技术也能用上,打算使用前后端分离,静态页使用nginx处理,然后通过ajax请求后端Tomcat,同样后端框架是Spring Boot+Mybatis。3.0非常简单,可以说比前两个代码量小了,暂时只有4个界面,真正的以简为主了。这回编辑器使用了Markdown,走向了正轨。

可以到http://blog.houxinlin.com/体验。gif有点卡,但是也很多缺点,没有去其他浏览器上测试,可能存在些兼容问题,只在谷歌火狐中测试过,手机上就更别说了,响应一点没做,这个到后续在加。更没有其他什么花样功能。
在这里插入图片描述
在这里插入图片描述

开发过程

以上的效果真的可以在1天内完成,只要你坐的住,并且有Spring Boot、Mybatis、Tomcat、Nginx、Ajax等基础。

一、文章编辑页面

首先是到https://pandao.github.io/editor.md/下载开源Markdown编辑器。然后引入并使用以下代码初始化。
在这里插入图片描述

 <div id="layout" style="background: #f6f6f6;">
        <header>
        </header>
        <div id="editormd">
            <textarea style="display:none;"></textarea>
        </div>
    </div>
   var zeptoEditor;
        $(function () {
            zeptoEditor = editormd("editormd", {
                width: "90%",
                height: 520,
                path: 'lib/md/editor/lib/',
                codeFold: true,
                searchReplace: true,
                saveHTMLToTextarea: true,
                imageUpload: true,
                imageUploadURL: "saasdf",
                htmlDecode: "style,script,iframe|on*",
                emoji: true,
                taskList: true,
                tocm: true,
                tex: true,
                flowChart: true,
                sequenceDiagram: true,
                onload: function () {
                    console.log("onload =>", this, this.id, this.settings);
                }
            });
        });

效果如下,但是文章免不了上传图片,他也支持,但是要做一些配置,并且后端要写图片上传接口,并返回图片的地址,而我没有写,因为考虑到我的服务器带宽小,加载图片实在慢,反而让用户体验差。所以我从别的平台写好,把Markdown复制过来在我的博客中发布即可,如简书,CSDN,这样我的服务器就可以不用承担图片资源,加载也快,索性就不做了。
在这里插入图片描述
并且做一个保存界面,如下。通过ajax提交到服务器。
在这里插入图片描述

二、首页

这部分主要动画多,都是通过transform来完成。也用不了多长时间,最后写好文章列表模板就可以通过ajax请求json数据,并使用vue渲染。

function requert(url, method, successCallback, errorCallback) {
        showLoadingDialog(true);
        $.ajax({
            type: method,
            url: host + url,
            success: result => {
                showLoadingDialog(false);
                successCallback(result)
            },
            error: (error) => {
                showLoadingDialog(false);
                errorCallback(error)
            },
        })
}

比如当点击分类文章的时候,代码如下,其中currentBlogList变量是绑定在vue上的。这部分可以做一个缓存,不用每次点击都去请求数据。

function getClassifyBlog(classify) {
    requert("blog/getBlogByClassify?title=" + classify, "GET", (result) => {
        if (result.code = 10000) {
            currentBlogList.datas = result.data
            return;
        };
        showDialog("出错了呢."+result.msg)
        
    }, () => { showDialog("出错了呢."+result.msg) })
}

function onNavClick(li) {
    clearSelectTag();
    $("#classify-ul .select").removeClass("select")
    li.classList.add("select")
    var title = $("#classify-ul .select").html();
    getClassifyBlog(title);
}

还有其他细节和功能就不写了,比如请求数据时候的loading动画,和数据出错的提示对话框。

后端

首先是设计数据表,目前只有两张表,一张文章分类表,一张博客表。
在这里插入图片描述
在这里插入图片描述
Mybatis也使用了Mybatis-plus,导致连sql也不用写了,比如获取指定文章内容:

@GetMapping("detail")
public R detail(@RequestParam("id") int id){
    TbBlog tbBlog = mTbBlogService.getById(id);
    if (tbBlog==null){
        return GeneratorResponseUtils.fail(ResponseCodeEnums.REQUEST_ERROR,"无效ID");
    }
    mTbBlogService.getBaseMapper().addWatchCount(id);
    return GeneratorResponseUtils.success(tbBlog);
}

获取前10个浏览最多的文章作为推荐。

 @Override
 public List<TbBlog> listRecommend() {
     QueryWrapper<TbBlog> tbBlogQueryWrapper = new QueryWrapper<>();
     tbBlogQueryWrapper.orderByDesc(TbBlog.WATCH_COUNT).last("limit 10");
     return list(tbBlogQueryWrapper);
 }

还有其他返回文章列表数据等也非常简单了。也全都是传说中的CURD操作,没其他难点。

但是要注意跨域问题,和Cookie携带问题。

public class CoreFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req =(HttpServletRequest) request ;
        HttpServletResponse res =(HttpServletResponse) response;
        String origin =req.getHeader("Origin");
        if (StringUtils.isNotEmpty(origin)){
            res.addHeader("Access-Control-Allow-Origin",origin);
            res.addHeader("Access-Control-Allow-Methods","*");
            res.addHeader("Access-Control-Allow-Age","3600");
            res.addHeader("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
            res.addHeader("Access-Control-Allow-Credentials","true");
        }
        chain.doFilter(request,response);
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void destroy() {
    }
}
public class CorsInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
//        // 如果是OPTIONS则结束请求
        if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
            response.setStatus(HttpStatus.NO_CONTENT.value());
            return false;
        }
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }
}
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
    @Bean
    public FilterRegistrationBean someFilterRegistration1() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter( new CoreFilter());
        registration.addUrlPatterns("/*");
        return registration;
    }
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        super.addInterceptors(registry);
        registry.addInterceptor(new CorsInterceptor()).addPathPatterns("/**");
    }
}

发布

SpringBoot内嵌Tomcat,可以直接打包成jar,但是我还是习惯了war,放到Tomcat中,可以使用Tomcat自带的manager发布,或是scp命令上传,或者其他办法,放入webapps下就可以了。idea中配置一下可以一键发布,但是要先配置下Tomcat。

接下来就是发布静态页到Nginx,打包所有静态页到压缩包。scp上传到服务器Nginx的80工作目录下。为了方便,写了个自动化发布脚本。可以到http://blog.houxinlin.com/detail.html?id=26下观看。

这样,绝大部分工作就已完成,接下来就是完成文章评价,等花里胡哨的功能。

发布了42 篇原创文章 · 获赞 7 · 访问量 7743

猜你喜欢

转载自blog.csdn.net/HouXinLin_CSDN/article/details/104323873