项目编号:BS-PT-089
一,项目简介
随着网络的迅速崛起,让互联网逐渐成为人们日常生活沟通交流的主要媒介,而具体的交流方式也随着科技的进步不断更新。过去,人们并没 有己的博客,因此只能通过比较分散,又缺乏条理的方式来展现自己的想法与心情,例如通过即时聊天软件或是在论坛上发表贴子等,但这些方法操作复杂,对个人信息的安全保护性能也不是很强。因此随着博客在网络上的普及,人们便可以通过博客表达自己的思想与感受,展示自己并让更多的人了解你,可以说博客是不受局限,言论由的网络个人日记。博客作为一个可以让人们提高写作水平的训练基地,表达文字的网络载体,它注重对自我感受和生活表达,经常写博客能够极快的磨练博主的写作技巧,并能使其思想意识更加深刻、敏锐。
博客,又叫网络日志,是一个通常由个人管理,不定期发布新的文章的网站。博客上的文章通常根据发布的时间,用倒序的方式由新到旧排列。许多博客专注在特定的课题上提供评论和新闻,其他的被作为个人日记。一个典型的博客结合了文字、图像、其他博客或者网站的链接、以及其他相关的主题为主的媒体。能够让读者以互动的方式留下意见,是许多博客的重要要素。大部分的博客内容以文字为主,博客是社会媒体网络的一部分。
各大网站上都有自己的博客系统,但是功能上都有所不同和局限性,我们为了实现一种属于我们自己的博客系统,尽量做到功能简洁,页面美观,更方便于流行的博客系统。
前台包含有5个模块,如图1所示。
用户登录:用户在使用博客系统之前需要登录注册,注册的方式提供了手机号注册和邮箱注册,注册完后登录时还需要验证码验证,验证成功才能进入博客主页。
博客页面展示:主页展示的是所有人的博客信息,用户可以在这里可以根据关键词搜索博客,还可以评论博客,有喜欢的博客还可以收藏起来,还可以根据类型的不同找博客,还有排行榜可以看到优质博客。
个人中心:个人中心展示的是个人信息,订单管理钱包管理还有自己的博客,个人信息里面可以查看浏览记录,可以修改手机号码,邮箱,密码等等,这里还添加了一个身份证的认证。订单管理里面是购买收费博客和广告的记录。钱包里面可以查看余额,可以充值和提现,提现是提现在银行卡里面。
发表博客:发表博客之前要先选择博客的分类,在分类下去新增博客,还可以添加图片到博客中,博客新增完毕可以选择是否收费,选择完毕在发表。
广告模块:这是一个盈利的功能,当用户看博客的时候会有广告在附近,用户可以通过花钱的方式消除广告。
后台包含有6个模块,如图2所示。
用户管理:管理员可以新增用户,修改用户,删除用户,查询用户的信息,用户可以自己注册,也可以管理员手动进行注册,用户名不能重复,如果用户忘记了密码可以联系管理员进行密码重置。
博客审核:用户发布的博客,管理员需要审核,一些非法信息或者暴力的内容等不能展示出来,审核通过后管理员可以手动发布帖子,审核不通过会提示用户,审核不通过。
广告管理:管理员可以新增广告到博客主页上,还可以对广告进行删除,修改的操作,还可以查看广告。
博客管理:管理员可以删除用户发布的博客,也可以修改用户的博客,还可以查询博客。
订单管理:当用户花钱购买付费的博客或者广告时,会生成一个未支付订单,等用户付完款后会修改成已支付订单,主页才能查看博客或者消除广告。
充值提现审核:用户点击提现后,选择提现的金额,发起提现,此时会进入提现审核状态,后台会收到,当管理员审核状态修改成通过时,用户提现的金额才能存到银行卡中,管理员还可以随时查看审核的状态。
1.技术要求
(1)技术实施方案
博客系统采用了前后端分离的技术,前端我使用了vue框架,css,js,html等,使用的开发工具是WebStorm,缓存使用了redis,使用了RESP可视化工具。
后端我使用了SpringBoot快速开发脚手架,使用的开发工具是IDEA,数据库方面我用的是MySql,可视化工具采用的是Navicat。
前后端交互是前端使用Ajax进行跨域访问到后端的数据,得到数据后就返回到前端。
(2)系统测试方案
收集资料对IDEA开发工具,Java语言,Mysql数据库,vue框架进行深入学习和使用。根据系统分析对博客系统进行分类设计和详细设计。根据系统设计和详细设计对各功能进行系统实现。按规定对系统进行完整的测试,找出存在的问题,进一步完善博客系统。
2.工作要求
(1)技术可行性:
使用Vue+SpringBoot实现项目的前后端开发。Vue是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue也完全能够为复杂的单页应用提供驱动。Vue使用了双向数据绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化,这就是Vue的精髓所在。SpringBoot,在当前互联网后端开发中,JavaEE占据了主导地位。对JavaEE开发,首选框架是Spring框架。在传统的Spring开发中,需要使用大量的与业务无关的XML配置才能使Spring框架运行起来,这点备受许多开发者诟病。为了进一步简化Spring应用的开发,SpringBoot诞生了。其设计目的是为了进一步简化Spring应用的搭建及开发过程。Spring Boot 可以轻松创建独立的、生产级的基于 Spring 的应用程序,您可以“直接运行”这些应用程序。我们对 Spring 平台和第三方库采取了固执的观点,因此您可以轻松上手。大多数 Spring Boot 应用程序需要最少的 Spring 配置。所以技术是完全可行的。
二,环境介绍
语言环境:Java: jdk1.8
数据库:Mysql: mysql5.7
应用服务器:Tomcat: tomcat8.5.31
开发工具:IDEA或eclipse
后台开发技术:springboot+mybatis
前台开发技术:vue+elementUI
三,系统展示
博客前台
用户注册和登录
手机验证码登录:
本博客的特点是可以设置收费的博文和免费的博文,查看收费的博文需要从个人账户中扣费
个人中心中可以绑定自己的银行卡并进行在线充值和提现
提现
发布博文时可以选择收费或是免费的
博文分类浏览
阅读排行榜
我的收藏
浏览记录
个人中心
后台登录
数据统计
用户管理
博客管理
分类管理
充值记录
提现审核
订单管理
前端轮播广告图片管理
四,核心代码展示
package com.dys.controller; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.dys.R.R; import com.dys.pojo.Classification; import com.dys.pojo.Posts; import com.dys.service.ClassificationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequestMapping("/classification") public class ClassificationController { @Autowired private ClassificationService classificationService; /** * 前端 * 查询所有的分类信息 * @return */ @PostMapping public R getClassification(){ List<Classification> list = classificationService.list(null); System.out.println("数据"+list); return R.ok(list); } /** * 条件分页查询,根据传来的条件去找到对应的数据 * @param page 分页 * @param search 条件 * @return R */ @GetMapping("/selectClassification") public R selectClassification(Page<Classification> page,@RequestParam String search){ Page<Classification> classificationPage = classificationService.selectClassification(page, search); return R.ok(classificationPage); } /** * 新增分类 * @param classification 分类对象 * @return R */ @PostMapping("/addClassification") public R addClassification(@RequestBody Classification classification){ boolean isOk = classificationService.addClassification(classification); return isOk ? R.ok() : R.error(); } /** * 修改分类 * @param classification 分类对象 * @return R */ @PostMapping("/updateClassification") public R updateClassification(@RequestBody Classification classification){ boolean isOk = classificationService.updateClassification(classification); return isOk ? R.ok() : R.error(); } /** * 删除分类 * 注:删除分类的同时还要删除有这个分类对应的博客 * 在根据博客id删除收藏,历史记录,排行榜里面的对应的博客信息 * 在根据博客里面的用户id删除对应的创作博客信息 * @param id 分类ID * @return R */ @DeleteMapping("/deleteClassification/{id}") public R deleteClassification(@PathVariable String id){ boolean isOk = classificationService.deleteClassification(id); return isOk ? R.ok() : R.error(); } /** * 后端 * 图表数据查询,先查询出所有的分类ID * 在根据ID去博客表找对应的博客的数量 * 返回每个分类有多少个博客 * @return R */ @GetMapping("/selectEChartsData") public R selectEChartsData(){ List<Classification> list = classificationService.selectEChartsData(); return R.ok(list); } }
package com.dys.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.OrderItem; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.dys.R.R; import com.dys.mapper.CollectionMapper; import com.dys.pojo.Collection; import com.dys.pojo.Posts; import com.dys.service.CollectionService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/collection") public class CollectionController { @Autowired private CollectionService collectionService; /** * 新增收藏记录 * @param collection * @return */ @PostMapping("/addCollection") public R addCollection(@RequestBody Collection collection){ //加上@RequestBody后可以接收前端传来的数据,把数据新增到数据库中 // boolean isOk = collectionService.saveCollection(collection); //返回数据,当数据为真时返回成功,为假时返回失败 // return isOk ? R.ok() : R.error("已经收藏过了"); //TODO collectionService.save(collection); String id = collection.getId(); return R.ok(id); } /** * 删除收藏记录 * @param id * @return */ @DeleteMapping("/deleteCollection/{id}") public R deleteCollection(@PathVariable String id){ // Collection collection = new Collection(); // collection.setUsersId(usersId); // collection.setPostsId(postsId); // boolean isOk = collectionService.deleteCollection(collection); boolean isOk = collectionService.removeById(id); return isOk ? R.ok() : R.error(); } /** * 查询是否收藏 * @param collection * @return */ @PostMapping("/listCollection") public R listCollection(@RequestBody Collection collection){ LambdaQueryWrapper<Collection> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Collection::getUsersId,collection.getUsersId()).eq(Collection::getPostsId,collection.getPostsId()); return R.ok(collectionService.getOne(wrapper)); } /** * 根据用户id查询所有已收藏的博客 * 上面是数据没分页,下面是将数据分页 * @param id * @return */ // @PostMapping("/listAllCollection/{id}") // public R listAllCollection(@PathVariable String id){ // return R.ok(collectionService.listAllCollection(id)); // } @GetMapping("/listAllCollection/{id}") public R listAllCollection(Page<Collection> page,@PathVariable String id){ page.addOrder(OrderItem.desc("create_time")); return R.ok(collectionService.listAllCollection(page,id)); } }
package com.dys.controller; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.OrderItem; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.dys.R.R; import com.dys.pojo.Classification; import com.dys.pojo.Posts; import com.dys.pojo.dto.PostsDTO; import com.dys.service.ClassificationService; import com.dys.service.PostsService; import com.dys.service.UsersService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.Comparator; import java.util.List; @RestController @RequestMapping("/posts") public class PostsController { /** * 博客表 */ @Resource private PostsService postsService; /** * 分类表 */ @Autowired private ClassificationService classificationService; /** * 用户表 */ @Autowired private UsersService usersService; /** * 后台 * 条件分页查询 * @param page 分页类,获取里面三个值:total:一共有多少个数据,size:每页可以存放的数据条数,current:当前是第几页 * @param search 搜索的关键字 * @return R */ @GetMapping("/postsPagingQuery") public R postsPagingQuery(Page<Posts> page, @RequestParam String search){ // //mybatis-plus中的条件构造器,需要用到Lambda语法,使用Wrapper // LambdaQueryWrapper<Posts> lambdaQueryWrapper = new LambdaQueryWrapper<>(); // //调用了like方法,实现模糊查询,lambda表达式查询条件,::获取实体类中的方法 ::--》Java8后:获取方法 // //StrUtil--》一个工具类,isNotEmpty和isNotBlank都是非空判断的方法(isNotBlank会排除空格,isNotEmpty不会排除空格) if (search == null){ } // lambdaQueryWrapper.like(StrUtil.isNotBlank(search),Posts::getTitle,search); // //按照修改时间降序排列 // Page<Posts> postsPage = page.addOrder(OrderItem.desc("update_time")); // //mybatis-plus好用自带的分页的方法,可以传两个参数(分页的起始位置,结束位置),接收前端传来的参数,查询的数量 // Page<Posts> servicePosts = postsService.page(postsPage, lambdaQueryWrapper); // // List<Posts> records = servicePosts.getRecords(); // records.forEach(item->{ // //TODO 填充typeName // String typeName = classificationService.getTypeNameByTypeId(item.getClassificationId()); // String usersName = usersService.getUserNameByUsersId(item.getUsersId()); // item.setTypeName(typeName); // item.setUsersName(usersName); // }); // //返回数据 // return R.ok(servicePosts); Page<Posts> postsPage = postsService.postsPagingQuery(page, search); List<Posts> records = postsPage.getRecords(); records.forEach(item->{ //TODO 填充typeName String typeName = classificationService.getTypeNameByTypeId(item.getClassificationId()); String usersName = usersService.getUserNameByUsersId(item.getUsersId()); item.setTypeName(typeName); item.setUsersName(usersName); }); return R.ok(postsPage); } /** * 博客数据按浏览量排序 * @param posts * @return */ @GetMapping("/getPostsAndViews") public R getPostsAndViews(Posts posts){ // //按照浏览量降序排列 // Page<Posts> postsPage = page.addOrder(OrderItem.desc("views")); // //mybatis-plus好用自带的分页的方法,可以传两个参数(分页的起始位置,结束位置),接收前端传来的参数,查询的数量 // Page<Posts> servicePosts = postsService.page(postsPage); List<Posts> list = postsService.list(); //list.sort(Comparator.comparing(Posts::getViews).reversed()); .reversed() --》 根据条件进行降序排序 list.sort(Comparator.comparing(Posts::getViews).reversed()); //返回数据 return R.ok(list); } /** * 查看博客详情,多表查询,根据用户id,类型id查询对应的名字 * @param id * @return */ @GetMapping("/{id}/{isStatus}") public R getPostsId(@PathVariable boolean isStatus,@PathVariable String id){ // Posts byId = postsService.getByIdWithTypeNameUsersName(id); PostsDTO byId = postsService.getByIdWithTypeNameUsersName(isStatus,id); return R.ok(byId); } /** * 根据分类id查询对应的分类数据 * @param id * @return */ @GetMapping("/classificationByIdData/{id}") public R classificationByIdData(Page<Posts> page,@PathVariable String id){ // List<Posts> typeData = postsService.getByIdWithTypeData(page,id); Page<PostsDTO> typeData = postsService.getByIdWithTypeData(page,id); return R.ok(typeData); } /** * 新增方法 * @param posts Posts实体类 * @return R */ @PostMapping public R savePosts(@RequestBody Posts posts){ //加上@RequestBody后可以接收前端传来的数据,把数据新增到数据库中 boolean isOk = postsService.save(posts); //返回数据,当数据为真时返回成功,为假时返回失败 return isOk ? R.ok() : R.error(); } /** * 修改方法 * @param posts Posts实体类 * @return R */ @PatchMapping("/updatePosts") public R updatePosts(@RequestBody Posts posts){ boolean isOk = postsService.updateById(posts); return isOk ? R.ok() : R.error(); } /** * 删除博客,删除博客的同时要删除历史记录中的博客和收藏的博客 * @param id Posts实体类 * @return R */ @DeleteMapping("/{id}") public R deletePosts(@PathVariable String id){ boolean isOk = postsService.deletePosts(id); return isOk ? R.ok() : R.error(); } /** * 前端 * 条件分页查询根据用户ID查找自己创作的博客 * @param id 用户ID * @param postsPage 分页 * @param search 搜索条件 * @return R */ @GetMapping("/selectBlogById") public R selectBlogById(Page<Posts> postsPage,@RequestParam String id,@RequestParam String search){ Page<Posts> page = postsService.selectBlogById(postsPage, id, search); return R.ok(page); } }
五,项目总结
本项目开发实现了一个博客平台系统,相较于传统的博客系统来讲,它可以实现付费博文的功能,作者可以通过付费的知识型博文来进行收费获得一定的收益,这就像CSDN上可以发布收费的博客或专栏一样,希望本项目的实现能给大家一些参考思路。