博客项目
创始人
2024-05-31 08:10:09
0

文章目录

  • 1. 创建项目
  • 2. 数据库设计
  • 3. 前置任务
    • 3.1 拦截器
    • 3.2 统一数据格式
    • 3.3 创建一个 Constant
    • 3.4 统一异常处理
    • 3.5 密码加密
  • 4. 功能实现
    • 4.1 登录功能
    • 4.2 注册功能
    • 4.3 博客列表页 (功能实现)
      • 4.3.1 左侧框
      • 4.3.2 右侧框 (分页功能 + 页面显示)
    • 4.4 博客详情页
    • 4.5 写博客功能
    • 4.6 注销功能


博客系统


前言 : 本文主要 是通过 ssm 搭配之前的 博客系统页面, 来完成一个小项目 .

项目完整代码

1. 创建项目

在这里插入图片描述


使用到的技术 :

  1. 后端 : Spring Boot + Spring MVC + MyBatis + 拦截器 / 统一异常处理 + 统一数据返回 (Spring AOP)
  2. 前端 : HTML + CSS + javaScript + jquery

2. 数据库设计


通过我们需要实现的功能 ,能够知道 需要两张表 , 第一张表 用户表 ,用来完成登录 注册 注销等功能 , 第二张表 用来存储 博客 , 查看博客等 .


1. 创建 用户列表

-- 如果存在 这个数据库就删除drop
database if exits mywebsite;-- 创建数据库create
database mywebsite;-- 选中数据库
use
mywebsite-- 创建用户表create table user
(
-- 系统分配id        int primary key auto_increment,
-- 必填username  varchar(255) not null,password  varchar(255) not null,
-- 非必填qq        varchar(255)  default '',address   varchar(255)  default '',crateTime datetime      default now(),sex       varchar(2)    default '男',
-- url 用来存放 用户 头像 图片 如果用户没有上传就使用默认的 .url       varchar(1024) default '阳台.png'
);

2. 创建 blog 表

create table blog
(blogId   int primary key auto_increment,title    varchar(1024) not null,-- 这里 一篇博客的内容可能非常多 使用 varchar可能不够 ,这里就是用 mediumtextcontent  mediumtext,--  用户 iduserid   int,-- 发布时间postTime datetime default now(),-- 类型type     varchar(255)  not null,
);


表创建好了 ,下面就可以完成一些 准备工作 ,比如 配置好环境 , 写好 拦截器 ,统一数据格式 等 .


这里统一数据格式 可以写一个类 , 通过这个类来返回 或者 通过 @ControllerAdvice + ResponseBodyAdvice 来完成 , 这里我会使用 写一个类来返回信息 .

3. 前置任务


这里先来完成 拦截器 , 统一异常处理 , 统一数据格式 .

在这里插入图片描述

application.yml

# 配置当前运行的环境 (配置文件)# spring > profiles > active
spring:profiles:active: dev # 使用开发环境的配置文件# 配置 mybatis xml 保存路径
mybatis:mapper-locations: classpath:mybatis/**Mapper.xml# 在公共 yml 文件 来 配置 mybatis 的保存路径

application-dev.yml

# 开发环境的配置文件spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mywebsite?characterEncoding=utf8username: rootpassword: 1234driver-class-name: com.mysql.cj.jdbc.Driver # 在 8.0 之前 是没有点 jc的 -> com.mysql.jdbc.Driver# 设置日志级别
logging:level:com:example:usermanager: debug# 对具体类机型日志级别设定# 开启 MyBatis SQL 打印
mybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3.1 拦截器

这里我们实现拦截器 主要有两部 : 1. 自定义拦截器 , 2. 给拦截器设置规则 (那些 需要拦截 , 那些不需要拦截)

在这里插入图片描述

附上代码 :

AppConfig 类

package com.example.usermanager.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** 系统配置文件*/@Configuration
public class AppConfig implements WebMvcConfigurer {// 注入拦截器@Autowiredprivate LoginIntercept loginIntercept;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginIntercept).addPathPatterns("/**").excludePathPatterns("/user/login").excludePathPatterns("/insert").excludePathPatterns("/css/**").excludePathPatterns("/fonts/**").excludePathPatterns("/images/**").excludePathPatterns("/js/**").excludePathPatterns("/login.html");}
}


LoginIntercept

package com.example.blog_ssm.config;import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;/*** 自定义拦截器*/@Component
public class LoginIntercept implements HandlerInterceptor {/*** true  表示已经登录 ,会继续访问目标方法* false  表示未登录 , 跳转到登录页面*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// false : 如果 没有 session 也不会创建HttpSession session = request.getSession(false);if (session != null && session.getAttribute("user") != null) {// 表示登录成功return true;}// 403 当前你没有资格访问response.setStatus(403);// 重定向response.sendRedirect("/login.html");return false;}
}


拦截器 弄好了 , 我们可以看看效果 :

在这里插入图片描述


xml 配置文件



3.2 统一数据格式


1. 创建一个类用来 统一 数据格式

在这里插入图片描述


附上代码 :

package com.example.blog_ssm.util;import lombok.Data;/*** 用来统一数据格式** @param */
@Data
public class ResponseBodyMessage {// 1. 状态码private Integer status;// 2. 信息描述private String message;// 3. 数据private T data;public ResponseBodyMessage(Integer status, String message, T data) {this.status = status;this.message = message;this.data = data;}
}


2. 使用注解

在这里插入图片描述

3.3 创建一个 Constant


之前我们写拦截器的使用 ,通过 session 中的key 获取 user 对象时 ,写了一个 “user” , 这里可以使用一个类 ,在类里面写一个 常量 ,然后 只需要通过这个 来获取 user 即可 。

在这里插入图片描述

3.4 统一异常处理

在这里插入图片描述

代码 :

package com.example.blog_ssm.config;import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;import java.util.HashMap;/*** 统一异常的拦截处理类*/@RestControllerAdvice// 使用 @ControllerAdvice 需要再加一个注解 @ResponseBody (返回一个非静态页面)public class MyExceptionAdvice {@ExceptionHandler(Exception.class)public Object exceptionAdvice(Exception e) {HashMap result = new HashMap<>();result.put("status", -1);result.put("message", "程序异常 : " + e.getMessage());result.put("data", "");return result;}
}

3.5 密码加密


在 util 包内 创建 PasswordUtil 类

package com.example.blog_ssm.util;import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.SecureUtil;
import org.springframework.util.StringUtils;/*** 密码工具类*/public class PasswordUtil {/*** 1. 加密 (加盐)*/public  String encrypt(String password) {// 密码 : 随机盐值 + 密码String salt = IdUtil.simpleUUID();String finalPassword = SecureUtil.md5(salt + password);return salt + "$" + finalPassword;}/*** 解密** @param password 要验证的密码 (未加密)* @return 数据库中的加了盐值的密码*/public  boolean decrypt(String password, String securePassword) {boolean result = false;if (StringUtils.hasLength(password) && StringUtils.hasLength(securePassword)) {// 注意 : $ 是特殊字符 , 使用 split 分割时 需要转移if (securePassword.length() == 65 && securePassword.contains("$")) {// 随机盐值 为 32  , md5 加密的 密码 32 加上 $ 1字符 总共 65 字符String[] securePasswordArr = securePassword.split("\\$");// 盐值String salt = securePasswordArr[0];// 根据盐值 加密的密码String finalPassword = securePasswordArr[1];// 根据盐值 对新的密码进行加密password = SecureUtil.md5(salt + password);// 进行对比if (finalPassword.equals(password)) {result = true;}}}return result;}
}


将 工具类 交给 spring 管理 ,后面使用 只需要注入即可 .

在这里插入图片描述


到此我们就完成了前置任务, 下面来写我们的功能

4. 功能实现

4.1 登录功能


约定一下 : 请求和响应

请求 : [{post, (登录一般使用 post)/user/login  data:{username : "张三",password :"1234"}}
]响应 : [{"status" : 1  / -1 (1 表示成功 , -1 表示失败) ."message" : "登录成功" / "登录失败","data" : true / false}
]


图一 :

在这里插入图片描述


图二 :

在这里插入图片描述


此时 后端就完成了 下面就可以来写前端了 :


图一 :

在这里插入图片描述


图二 :

在这里插入图片描述


代码 :



登录页面


我的博客系统
主页写博客

登录

用户名
密码
没有账户? 点击上面进行注册

登录功能搞完 : 下面就可以来弄 注册功能

4.2 注册功能


约定一下请求和响应 :

在这里插入图片描述


请求: [{post,url : /user/adddata:{必填"username" : xxx,"password" : xxx,非必填"address" : xxx,......}}
]响应 : [{data:{"status" : 1 / -1  (注册成功 / 注册失败)"message" : "","data" : true / false}}
]


图一 :

在这里插入图片描述


图二 :

在这里插入图片描述


图三 :

在这里插入图片描述


图四 :

在这里插入图片描述

附上代码 :

  /*** 2. 注册功能*/@RequestMapping(value = "/add")@Transactionalpublic ResponseBodyMessage addUser(User user, @RequestPart(required = false, value = "filename") MultipartFile file) {if (user == null) {return new ResponseBodyMessage(-1, "注册失败", false);}// 1. 判断 必填参数是否为空 (这里可以不写 ,前端大概率 是会判断的 。 )if ("".equals(user.getUsername())) {return new ResponseBodyMessage<>(-1, "注册失败, 当前用户为输入用户名", false);}if ("".equals(user.getPassword())) {return new ResponseBodyMessage<>(-1, "注册失败,当前用户未输入密码", false);}// 2. 校验用户名的 唯一性 :  如果 用户名已经纯在了 那么就不能注册User user2 = userService.getUserByUserName(user.getUsername());if (user2 != null) {return new ResponseBodyMessage<>(-1, "注册失败, 用户名已存在", false);}// 3. 手动设置 为 '' 的数据if ("".equals(user.getAddress())) {user.setAddress(null);}if ("".equals(user.getQq())) {user.setQq(null);}if ("".equals(user.getSex())) {user.setSex(null);}if ("".equals(user.getUrl())) {user.setUrl(null);}// 4. 对密码进行加密操作user.setPassword(passwordUtil.encrypt(user.getPassword()));// 5. 如果用户 上传了头像 ,可以将图片存入到本地if (file != null) {// 此时上传了头像 :// 获取到文件名 + 类型String fileNameAndType = file.getOriginalFilename();// 比如文件名为 : 阳台.png , 此时可以获取到 . 的 下标int index = fileNameAndType.lastIndexOf(".");// 从 index 位置开始截取String postfix = fileNameAndType.substring(index);// 判断一下 图片的格式是否符合预期要求if (".jpg".equals(postfix) || ".png".equals(postfix)) {// 通过 uuid 来设置文件名String uuid = IdUtil.simpleUUID();String imgFileStr = uuid + postfix;// 创建文件String path = IMAGE_PATH + imgFileStr;File imgFile = new File(path);if (!imgFile.exists()) {imgFile.mkdir();}try {
//                指定图片 , 上传之后的存储位置file.transferTo(imgFile);// 文件上传成功 :user.setUrl(imgFileStr);userService.addUser(user);return new ResponseBodyMessage<>(1, "注册成功", true);} catch (IOException e) {
//                e.printStackTrace();// 如果 创建失败 , 手动事务回滚TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}// 此时 注册失败return new ResponseBodyMessage<>(-1, "注册失败", false);} else {return new ResponseBodyMessage<>(-1, "图片格式有误", false);}}// 6. 调用 userService 中的 addUser 方法 进行用户添加 (此时未上传图片 , 图片 为 默认)Integer ret = userService.addUser(user);if (ret != 1) {return new ResponseBodyMessage<>(-1, "注册失败", false);}return new ResponseBodyMessage<>(1, "注册成功", true);}


后端写完, 来完成我们的前端 :


之前并没有完成 注册页面 , 这里直接来拷贝一下


1. add.html




添加用户


添加用户

男   
是   


用到的 css 可以到 我 的资源里面下载 出来 , 比较多 这里就不拷贝到上面 了 .

在这里插入图片描述


这里我们需要使用 FormData 来 发送我们的数据 可以看来看一下这 : FormData

在这里插入图片描述

代码 :




添加用户

添加用户

男   
图片样式:

上传文件使用到的 input 标签, 和 使用到的change 事件 : input 标签 change 事件


效果 :

在这里插入图片描述


到此我们的注册功能就完成了 , 下面就来写我们的博客列表页 .

4.3 博客列表页 (功能实现)

4.3.1 左侧框


图一 :

在这里插入图片描述


AppConfig 类

package com.example.blog_ssm.config;import com.example.blog_ssm.util.PasswordUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class AppConfig implements WebMvcConfigurer {// 1. 注入拦截器@Autowiredprivate LoginIntercept loginIntercept;@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/product/**").addResourceLocations("file:D:/ret/");}@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginIntercept).addPathPatterns("/**").excludePathPatterns("/user/login").excludePathPatterns("/user/add").excludePathPatterns("/css/**").excludePathPatterns("/js/**").excludePathPatterns("/imgs/**").excludePathPatterns("/login.html").excludePathPatterns("/add.html").excludePathPatterns("/product/**");}@Beanpublic PasswordUtil passwordUtil() {return new PasswordUtil();}
}


图二 :

在这里插入图片描述


后端完成了 ,下面就可以来完成我们的前端 :

在这里插入图片描述


图三 :

在这里插入图片描述


图四 :

在这里插入图片描述


图五 :

在这里插入图片描述


图六 :

在这里插入图片描述


图七 :

在这里插入图片描述



左侧部分 就完成了, 下面就来完成我们的右侧部分 ,这里我们可以写一个分页器

4.3.2 右侧框 (分页功能 + 页面显示)


图一 :

在这里插入图片描述

图二 :

在这里插入图片描述


图三 :

在这里插入图片描述

图四 :

在这里插入图片描述

这里不好截图 直接看代码 :



博客列表页

我的博客系统
主页写博客注销

Math.ceil() - JavaScript | MDN (mozilla.org)


页面效果:

在这里插入图片描述


上面我们的代码其实还有一个没中不足的地方 , 我们的文章 应该是 后发布的在前面, 而不是 以前发布的在前面 ,这里就来修改一下 ,也非常简单 , 就是给我们的SQL 加一个 排序 (按照时间排序即可)

在这里插入图片描述

到此我们的博客列表页的内容就完成了 , 下面就来完成我们的 博客详情页

4.4 博客详情页


这里我们主要实现查看 博客的功能 .


图一 :

在这里插入图片描述


图二 :

在这里插入图片描述


图三 :

在这里插入图片描述


图四 :

在这里插入图片描述


图五 :

在这里插入图片描述


图六 :

在这里插入图片描述


图七 :

在这里插入图片描述


前端代码 :



博客详情页

我的博客系统
主页写博客注销

Gitee 地址
文章分类
12

我的第一篇博客

2023-03-02

4.5 写博客功能


图一 :

在这里插入图片描述


图二 :

在这里插入图片描述


图三 :

在这里插入图片描述


图四 :

在这里插入图片描述


图五 :

在这里插入图片描述


最后完成我们的注销 功能 这个 小项目就完成了 .

4.6 注销功能


图一 :

在这里插入图片描述


图二 :

在这里插入图片描述


到此 这个 小项目就完成了, 其实这个项目还有很多东西可以加 ,这些大家都可以 自由发挥 .

相关内容

热门资讯

山西省榆次常家庄园简介导游词 山西省榆次常家庄园简介导游词  常家庄园位于榆次西南东阳镇车辋村,距榆次17.5公里。车辋由四个小自...
黄山的景点导游词 黄山的景点导游词(通用7篇)  作为一名导游,通常需要准备好一份导游词,导游词一般是根据实际的游览景...
西双版纳热带植物园导游词 西双版纳热带植物园导游词推荐  各位朋友,大家好。今天我们将游览闻名遐迩、风光绚丽的中国科学院西双版...
浙江仙华山导游词 浙江仙华山导游词  作为一名具备丰富知识的导游,通常会被要求编写导游词,导游词事实上是一种对旅游景点...
广州资政大夫祠的导游词 广州资政大夫祠的导游词  新华镇三华村,有一处资政大夫祠古建筑群,建于清同治二年(1863)  整个...
贵州万峰林导游词 贵州万峰林导游词  作为一位杰出的导游,总不可避免地需要编写导游词,导游词具有极强的实用性,涉及的知...
鸟巢导游词英文 鸟巢导游词英文范文  作为一名乐于为游客排忧解难的'导游,通常需要准备好一份导游词,导游词的主要特点...
开封包公祠导游词 开封包公祠导游词  包公祠全名“包公孝肃祠”,位于合肥市 环城南路东段的一个土墩上,是包河公园的主 ...
浙江省安吉大竹海导游词 浙江省安吉大竹海导游词  导游内容:大竹海概况→五女湖.五女船→竹龙引泉→动感影视吧→投缘池→幽泉煮...
斗篷山导游词最新 斗篷山导游词最新范文  作为一位不辞辛劳的导游,就不得不需要编写导游词,导游词是讲解当地的基本情况,...
云南省大理概况导游词 云南省大理概况导游词(精选5篇)  作为一无名无私奉献的导游,通常会被要求编写导游词,导游词是导游员...
武当山南岩宫导游词 武当山南岩宫导游词(精选12篇)  作为一名可信赖的导游人员,常常需要准备导游词,导游词具有极强的实...
合肥包公园导游词 合肥包公园导游词  包公园,位于安徽省合肥市芜湖路72号,始建于北宋嘉祐七年,是为纪念北宋著名清官包...
景点贵阳花溪公园导游词 景点贵阳花溪公园导游词  作为一位兢兢业业的旅游从业人员,时常需要用到导游词,借助导游词可以更好地宣...
孔庙导游词   孔庙导游词(一)  尊敬的各位来宾:  你们好!我受旅游、接待部门的委托,对光临名城曲阜参观游览...
石家庄驼梁景区导游词 石家庄驼梁景区导游词尊敬的各位游客:  大家好!  欢迎大家来到驼梁,我是中游旅行社的一名导游员,我...
介绍傣家竹楼导游词300 傣家竹楼是傣族固有的典型建筑。下层高约七八尺,四无遮栏,牛马拴束于柱上。上层近梯处有一露台,转进为长...
电视剧《乱世佳人》简介及经典... 电视剧《乱世佳人》简介及经典台词  电视剧简介:  《乱世佳人》亦可称为民国版《美人心计》,由唐嫣饰...
丹东鸭绿江导游词 丹东鸭绿江导游词  鸭绿江是我们中国和朝鲜的分界线,各位导游,请看下面的丹东鸭绿江导游词,希望可以帮...
幼儿园运动会闭幕式主持词 幼儿园运动会闭幕式主持词  主持人在台上表演的灵魂就表现在主持词中。随着社会一步步向前发展,各种场合...