个人博客项目

3 篇文章 0 订阅
1 篇文章 0 订阅

Myblog

码云:link

需求

  • 界面简洁,好看

  • 展示模块(展示我们的blog)

  • 登录模块(认证用户)

  • 后台模块(管理我们的blog)

    • 文章
      • 写文章
      • 看文章
      • 草稿箱,回收站,已发布
      • 修改文章
    • 文件上传(附件可供整个blog使用)
    • 日志(记录我们的操作)
    • 统计

实现

使用工具
  • Maven3.8.1
  • java1.8.0
  • idea2020.1.3
  • mysql5.7.34
页面展示

博客展示
首页
请添加图片描述归档–文章
请添加图片描述友链
在这里插入图片描述搜索
在这里插入图片描述

登录
在这里插入图片描述
后台
在这里插入图片描述swagger界面–可在线测试,记录,同步更新我们的接口,

在这里插入图片描述

1.设计数据库

文章表(包含文章的所有信息)
在这里插入图片描述

分类关联表(将文章和文章分类关联在一起)

在这里插入图片描述

标签关联表(将文章和文章标签关联在一起)
在这里插入图片描述

分类表和标签表
在这里插入图片描述
在这里插入图片描述

附件表–我们上传的附件

在这里插入图片描述

友链表–友情链接
在这里插入图片描述

日志表–记录我们的操作

在这里插入图片描述
菜单表–博客展示页面的菜单
在这里插入图片描述

设置表

在这里插入图片描述
用户表-我们的管理人员
在这里插入图片描述

主题表–我们的主题
在这里插入图片描述

补充

  • 文章表可通过文章分类,标签关联表将分类表,标签表连在一起–我们的文章有对应分类和标签
2.创建实体类对象(与数据库中中的表做映射)–resultMap

在这里插入图片描述

分类和标签实体类对象继承文章类–文章的所有信息–与我们查询数据库(连表查询得到的数据做映射)

3.导入依赖
<name>mayday</name>
<description>
学不在入,而在于出,分享热爱
</description>

<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>2.0.4.RELEASE</version>
   <relativePath />
</parent>

<properties>
   <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
   <java.version>1.8</java.version>
   <druid.version>1.1.10</druid.version>
   <fastjson.version>1.2.47</fastjson.version>
   <pagehelper.version>5.1.6</pagehelper.version>
   <hutool-all.version>4.1.14</hutool-all.version>
   <thumbnailator.version>0.4.8</thumbnailator.version>
   <ehcache.version>3.6.3</ehcache.version>
   <MDTool.version>1.2.1</MDTool.version>
   <rome.version>1.0</rome.version>
</properties>

<dependencies>
   <!--支持切面-->
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
   </dependency>
   <!--前端模板-->
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
   </dependency>
   <!--web-->
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
   <!--mybatis-->
   <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>1.3.2</version>
   </dependency>
   <!--缓存-->
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-cache</artifactId>
   </dependency>
   <!--连接数据库-->
   <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <scope>runtime</scope>
   </dependency>
   <!--springboot测试-->
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
   </dependency>
   <!-- 日志 -->
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-logging</artifactId>
   </dependency>
   <!-- 热部署 -->
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <optional>true</optional>
      <scope>true</scope>
   </dependency>
   <!-- druid数据库连接池,数据源 -->
   <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
   <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>${druid.version}</version>
   </dependency>
   <!--json工具-->
   <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>${fastjson.version}</version>
   </dependency>
   <!--mybatis分页插件-->
   <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper</artifactId>
      <version>${pagehelper.version}</version>
   </dependency>
   <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-autoconfigure -->
   <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper-spring-boot-autoconfigure</artifactId>
      <version>1.2.7</version>
   </dependency>
   <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter -->
   <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper-spring-boot-starter</artifactId>
      <version>1.2.7</version>
   </dependency>

   <!-- Java工具包-->
   <dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>${hutool-all.version}</version>
   </dependency>
   <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
   <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
   </dependency>
   <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <!-- 此包一般在Servlet容器中都有提供 -->
      <scope>provided</scope>
   </dependency>
   <!--缩略图生成库-压缩图片工具类 -->
   <!-- https://mvnrepository.com/artifact/net.coobird/thumbnailator -->
   <dependency>
      <groupId>net.coobird</groupId>
      <artifactId>thumbnailator</artifactId>
      <version>${thumbnailator.version}</version>
   </dependency>
   <!-- https://mvnrepository.com/artifact/org.ehcache/ehcache -->
   <!--Java的进程内缓存框架-->
   <dependency>
      <groupId>org.ehcache</groupId>
      <artifactId>ehcache</artifactId>
      <version>${ehcache.version}</version>
   </dependency>
   <!--将markdown转换为html的工具-->
   <dependency>
      <groupId>com.youbenzi</groupId>
      <artifactId>MDTool</artifactId>
      <version>${MDTool.version}</version>
   </dependency>
   <!-- rss -->
   <dependency>
      <groupId>rome</groupId>
      <artifactId>rome</artifactId>
      <version>${rome.version}</version>
   </dependency>
   <!--在线API框架-->
   <dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger2</artifactId>
      <version>2.9.2</version>
   </dependency>
   <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
   <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
   <dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger2</artifactId>
      <version>2.9.2</version>
   </dependency>
   <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
   <dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger-ui</artifactId>
      <version>2.9.2</version>
   </dependency>
</dependencies>
4.配置(yaml)
server: 
  port: 8888
logging:
    level:
    	#可以设置要输出内容的等级并输出到控制台
        org.springframework: info
        com.songhaozhi.mayday.mapper: debug
        com.songhaozhi.mayday.web: debug
        #配置文件所在地(定义输出到文件,输出到控制台,设置输出什么等级的日志)
    config: classpath:logback-spring.xml

spring: 
  mvc:
  #静态资源路劲--/--静态文件夹static
    static-path-pattern: /**
  thymeleaf: 
    servlet:
      content-type: text/html
    encoding: UTF-8
    cache: false
  datasource: 
         type: com.alibaba.druid.pool.DruidDataSource
         url: jdbc:mysql://localhost:3306/myblog?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
         username: root
         password: 123456
         driver-class-name: com.mysql.jdbc.Driver
mybatis: 
  typeAliasesPackage: com.songhaozhi.mayday.model.domain
  mapperLocations: classpath:mapper/*/*.xml
  #是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN映射 到经典 Java 属性名 aColumn
  configuration:
    map-underscore-to-camel-case: true
pagehelper:
  #分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。 你可以配置helperDialect属性来指定分页插件使用哪种方言
  helper-dialect: mysql
  #分页合理化参数,默认值为false。当该参数设置为 true 时,pageNum<=0 时会查询第一页, pageNum>pages(超过总数时),会查询最后一页
  reasonable: true
  support-methods-arguments: true
  #为了支持startPage(Object params)方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值,
  params: count=countSql
private Integer userId;

在这里插入图片描述

5.自定义配置(拦截器,资源处理,视图解析)
  • 日志
  • 缓存
  • 初始化(启动程序就会执行)
    • 加载菜单
    • 设置选项
    • 主题
  • 拦截器
    • 登录拦截–session判断
    • 首页拦截–非AJAX请求,就把我们初始化的东西给前端
    • 注册拦截–判断我们是否注册blog(不会拦截安装请求和静态资源)
      • 未注册:进行注册–初始化我们的菜单,设置,主题,用户,文章到数据库(初始化)
  • swagger配置
    • 注意点:配置资源处理,注意我们的请求(带参数的请求)占有swagger-ui.html,会把我们的swagger-ui.html看成参数
6.项目结构

在这里插入图片描述

实体类对象
  • 日志接口–存放我们的日志关键

    public interface LogConstant {
    
       String LOGIN = "登录后台";
       
       String SUCCESS = "操作成功";
    
       String ERROR = "操作失败";
    
       String UPLOAD_ATTACHMENT = "上传附件";
    
       String UPLOAD_SUCCESS = "上传成功";
       
       String UPDATE_PWD="修改密码";
    
       String DELETE_ATTACHMENT = "删除附件";
    
       String DELETE_SUCCESS = "删除成功";
    
       String LOGIN_SUCCES = "登录成功";
    
       String LOGIN_ERROR = "登录失败";
    
       String PUBLISH_AN_ARTICLE = "发表文章";
    
       String UPDATE_AN_ARTICLE = "更新文章";
    
       String REMOVE_AN_ARTICLE = "删除文章";
    
       String PUBLISH_AN_PAGE = "发布页面";
    
       String UPDATE_AN_PAGE = "更新页面";
    
       String REMOVE_AN_PAGE = "删除页面";
    
       String PUBLISH_AN_THEME = "添加主题";
    
       String REMOVE_AN_THEME = "删除主题";
    
       String INSTALL_SUCCESS = "安装MAYDAY";
    
    }
    

    我们可以直接取

  • 消息实体类–用于返回信息给前端

    • public class JsonResult {
      	private boolean flag;
      	private String msg;
      	private Object data;
      
      	public JsonResult() {
      		super();
      	}
      
      	public JsonResult(boolean flag, String msg) {
      		super();
      		this.flag = flag;
      		this.msg = msg;
      	}
      
      	public JsonResult(boolean flag, String msg, Object data) {
      		super();
      		this.flag = flag;
      		this.msg = msg;
      		this.data = data;
      	}
      
      	public boolean isFlag() {
      		return flag;
      	}
      
      	public void setFlag(boolean flag) {
      		this.flag = flag;
      	}
      
      	public String getMsg() {
      		return msg;
      	}
      
      	public void setMsg(String msg) {
      		this.msg = msg;
      	}
      
      	public Object getData() {
      		return data;
      	}
      
      	public void setData(Object data) {
      		this.data = data;
      	}
      
      }
      

      通过@ResponseBody将方法的返回值直接输出到前端页面–返回对象(前端会自动解析为json数据)

      也可以将对象转换为json格式

  • 通用变量类–可以所有类使用

    package com.songhaozhi.mayday.model.dto;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import com.songhaozhi.mayday.model.domain.Menu;
    public class MaydayConst {
       /**
        * user_session
        */
       public static final String USER_SESSION_KEY = "user_session";
       /**
        * 最大页码
        */
       public static final int MAX_PAGE = 100;
       /**
        * 所有设置选项
        */
       public static Map<String, String> OPTIONS = new HashMap<String, String>();
       /**
        * 所有菜单
        */
       public static List<Menu> MENUS = new ArrayList<Menu>();
       /**
        * 主题
        */
       public static String THEME_NAME;
       
       /**
        * 同一IP十分钟以内重复访问同一篇文章只算一次
        */
       public static final Integer IP_REPEAT_TIME=600;
       
       /**
         * 点击次数超过多少更新到数据库
         */
        public static final int CLICK_EXCEED = 10; 
    }
    
  • 枚举类–(很多对象–存放着值)

文章功能

查看文章
  • 可编辑,操作,删除文章

  • 三个模块–回收站,草稿,已发布

    • 设计数据库

      • 文章表–包含文章的信息—状态
      • 分类表–包含分类信息
      • 标签表–包含标签信息
      • 文章–标签
      • 文章–分类
    • 创建实体类对象

      方法一:

      • 创建文章实体类对象–对应以上三表联合的表

      • 创建分类实体类

      • 创建标签实体类

      方法二

      • 创建文章实体类对象–对应文章

        • 创建一个子类(包含分类信息和标签信息)
      • 创建分类实体类

      • 创建标签实体类

    • 构建SQL语句

      • 通过状态(0,1,2–区别回收站,草稿,已发布)和请求方式(post–安全)获取相应的文章(多表查询获取文章的所有信息)–通过文章id和标签id,分类id的绑定表进行获取数据
      • 通过状态获取个数
      • 通过文章url进行查找文章—id主键
      • 修改
        • 传入文章信息----对象–修改文章
        • 传入标签id–插入到表(文章–标签)
        • 传入分类id----插入到表(文章–分类)
      • 改变状态移动
      • 通过id进行删除
    • MVC的操作

写文章

前端提供一个页面(富文本编辑)—发送请求-保存(1)发布(0)-表单的信息发送给服务器–服务器的控制层接收请求,接收到所有有信息(分类ID,标签ID,文章信息)–将文章信息插入到数据库(生成文章ID)—构建文章ID和标,分ID绑在一起的实体类对象—插入数据库—相应到文章页面

用户功能

重点:了解MVC三层模型,设计数据库,设计Dao层(Mapper-xml)CRUD

  • 登录

    • Ajax发送请求,接收数据,跳转或刷新----通过设置Session验证并跳转
  • 查看个人资料,修改个人资料

    • 发送请求—处理请求—查询或修改数据库—响应数据—前端刷新(window.location.reload();)或跳转(window.location.href = “/admin/login”;
  • 密码修改

    • 发送请求—处理请求—查询或修改数据库—响应数据—前端刷新或跳转
  • 未完待续

统计功能

发布的文章

友链

附件

  • 上传附件

    /**
     * 上传功能
     * @param file
     * @param request
     * @return
     */
    public JsonResult uploadAttachment(@RequestParam(value = "file") MultipartFile file, HttpServletRequest request) {
        //接收前端传来的文件
       
       if (!file.isEmpty()) {
          try {
               1.处理文件---为文件创建目录
             // 获取用户目录
             String userPath = System.getProperties().getProperty("user.home") + "/mayday/";
             // 保存目录
             StringBuffer hold = new StringBuffer("upload/");
             // 获取时间,以年月创建目录
             Date date = DateUtil.date();
             hold.append(DateUtil.thisYear()).append("/").append(DateUtil.thisMonth() + 1).append("/");
             File mediaPath = new File(userPath, hold.toString());
             // 如果没有该目录则创建
             if (!mediaPath.exists()) {
                mediaPath.mkdirs();
             }
             System.out.println("路径++++++" + mediaPath);
             SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
             // 生成文件名称
              2.处理文件---为文件创建名字
             String nameSuffix = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf("."))
                   .replaceAll(" ", "_").replaceAll(",", "") + format.format(DateUtil.date())
                   + new Random().nextInt(1000);
             // 文件后缀
             String fileSuffix = file.getOriginalFilename()
                   .substring(file.getOriginalFilename().lastIndexOf(".") + 1);
             // 上传文件名加后缀
             String fileName = nameSuffix + "." + fileSuffix;
    		3.处理文件---将文件放入指定的文件里(路径+文件名)
             // 转存文件
             file.transferTo(new File(mediaPath.toString(), fileName));
    		4.获取图片和压缩图片路径
             // 原图片路径
             StringBuffer originalPath = new StringBuffer();
             originalPath.append(mediaPath.getAbsolutePath()).append("/").append(fileName);
             // 压缩图片路径
             StringBuffer compressPath = new StringBuffer();
             compressPath.append(mediaPath.getAbsolutePath()).append("/").append(nameSuffix).append("_small.")
                   .append(fileSuffix);
              5.压缩图片
             // 压缩图片
             Thumbnails.of(originalPath.toString()).size(256, 256).keepAspectRatio(false).toFile(compressPath.toString());
              6.获取数据库路劲
             // 原图数据库路径
             StringBuffer originalDataPath = new StringBuffer();
             originalDataPath.append("/").append(hold).append(fileName);
             // 压缩图数据库路径
             StringBuffer compressDataPath = new StringBuffer();
             compressDataPath.append("/").append(hold).append(nameSuffix).append("_small.").append(fileSuffix);
              7.将附件放入数据库
             // 添加数据库
             Attachment attachment = new Attachment();
             attachment.setPictureName(fileName);
             attachment.setPicturePath(originalDataPath.toString());
             attachment.setPictureType(file.getContentType());
             attachment.setPictureCreateDate(date);
             attachment.setPictureSuffix(new StringBuffer().append(".").append(fileSuffix).toString());
             attachment.setPictureSmallPath(compressDataPath.toString());
             attachment.setPictureWh(MaydayUtil.getImageWh(new File(mediaPath.toString() + "/" + fileName)));
             attachment.setPictureSize(MaydayUtil.parseSize(new File(mediaPath.toString() + "/" + fileName).length()));
             attachmentService.save(attachment);
             // 添加日志
             logService.save(new Log(LogConstant.UPLOAD_ATTACHMENT, LogConstant.UPLOAD_SUCCESS,
                   ServletUtil.getClientIP(request), DateUtil.date()));
          } catch (Exception e) {
             log.error("上传附件错误" + e.getMessage());
             return new JsonResult(false, "系统未知错误");
          }
       } else {
          return new JsonResult(false, "文件不能为空");
       }
       return new JsonResult(true, "上传成功");
    }
    
  • 查看附件详情

    • 前端点击图片触发事件,发送请求—通过Id获得当前附件—响应详情页面

      <!--显示图片以及图片的事件-->
      <div class="row">
         <th:block th:each="attachment : ${info.list}">
            <div class="col-lg-2 col-md-3 col-sm-6 col-6 div-thumbnail"
               th:onclick="'javascript:viewDetails('+${attachment.id}+')'">
               <a href="#"><img
                  class="img-thumbnail img-fluid img-responsive"
                  th:src="${attachment.pictureSmallPath}"></a>
            </div>
         </th:block>
      </div>
      <script type="text/javascript">
      		function viewDetails(id) {
      			layer.open({
      				type : 2,
      				title : '附件详情',
      				anim : 2,
      				area : [ '90%', '90%' ],
      				maxmin : true,
      				content : "attachment/viewDetails/" + id
      			});
      		}
      
    • 提供相应操作–删除—通过ID删除当前附件—响应打开这个窗口的页面(parent.location.reload()

  • 分页展示附件

    • 通过条件进行查询,获得所有附件–使用分页工具,展示分页的附件给前端–前端通过图片路路径展示图片

日志功能

     <div class="col-lg-6 col-md-12">
      <div class="tile">
      <div>
      <h3 class="tile-title" style="float: left;">最新日志</h3>
<div class="dropdown" style="float: right;">
  <button type="button" class="btn btn-box-tool dropdown-toggle" data-toggle="dropdown">
   <i class="fa fa-bars"></i>
  </button>
  <div class="dropdown-menu">
     <a class="dropdown-item" href="#" onclick="viewLogs()">查看所有</a>
     <a class="dropdown-item" href="/admin/logs/clear">清空日志</a>
  </div>
</div>
</div>
        <table class="table">
        <tr>
        <td>事件</td>
        <td>结果</td>
        <td>IP</td>
        <td>时间</td>
        </tr>
        <tr th:each="log : ${logs}">
        <td th:text="${log.logTitle}"></td>
        <td th:text="${log.logContent}"></td>
        <td th:text="${log.logIp}"></td>
        <td th:text="${#dates.format(log.logDate,'yyyy/MM/dd HH:mm:ss')}"></td>
        </tr>
        </table>
        </div>
    </div>

在这里插入图片描述

前端提供一个日志界面,前端向后端发送请求

后端提供一个接口,相应数据返回

创建日志常量类(封装我们的日志常量)

创建日志类(封装我们的日志信息)

问题以及解决方法

1.无法解析Mybatis的XML文件

  • 那么一定是xml文件问题,检查代码

原博客地址

link:https://github.com/gujiniCY
对原作者的Blog的知识结构进行了总结,修改,打造成属于自己的Blog

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值