博客项目
创始人
2024-05-31 09:57:54
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 注销功能


图一 :

在这里插入图片描述


图二 :

在这里插入图片描述


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

相关内容

热门资讯

清朝有很多有名的历史人物,能给... 清朝有很多有名的历史人物,能给大家说几个清朝的历史人物吗?林则徐,张之洞,乾隆皇帝,曾国藩,朱耷,这...
曹丕的“太子四友”指的是谁 曹丕的“太子四友”指的是谁首先说,曹丕这四个,陈群司马懿是顶级的谋士和政治家,吴质有些小聪明,朱铄不...
在这次遇难者中存在了几名幸存者... 在这次遇难者中存在了几名幸存者。这句话是不是逻辑错误这句话的逻辑没有问题,有问题的是用词不当。遇难者...
在中国古代,有许多充满哲学智慧... 在中国古代,有许多充满哲学智慧的成语典故、寓言故事,如...在中国古代,有许多充满哲学智慧的成语典故...
清澈的意思是什么,… 清澈的意思是什么,…清净而明澈清而透明【造句】看着他清澈而又天真的眼眸,我的心久久不能平静……
蚂蚁森林合种爱情树一方退出怎么... 蚂蚁森林合种爱情树一方退出怎么找回来两个人合种的爱情树,我退出来,我怎么再次加入进去继续合作那个树?...
有好看的古代修炼小说推荐吗? 有好看的古代修炼小说推荐吗?古代重生穿越修炼......让我帮你找一下这些古代修炼的小说,找到这些类...
女主重生爱上前世辜负的人 女主重生爱上前世辜负的人重生我是你正妻渣女重生之竹马重生之弃渣重生之夫君可欺重生之换我疼你重生妇归来...
华胥引有广播剧吗 华胥引有广播剧吗现有的华胥引的广播剧是忆语广播剧社出品的,只有十三月和杯(这个是错字,请无视,居然输...
选文韩麦尔先生在说了,我的朋友... 选文韩麦尔先生在说了,我的朋友们我就要离开你们呢了,再见了银头鲑鱼tj75rt6yturdrruv ...
中通快递从北京保定市到广东揭阳... 中通快递从北京保定市到广东揭阳普宁要多久?中通快递从北京保定市到广东揭阳普宁要多久?从北京到广东需要...
关于离婚悲伤的歌曲 关于离婚悲伤的歌曲关于离婚悲伤的歌曲林俊杰《可惜没如果》 张靓颖《我走以后》 金志文《流着泪说分手》...
形容文笔差怎么说啊? 形容文笔差怎么说啊?哥哥姐姐,麻烦问下,我是做文员的,形容文案方面的工作很差应该怎么说啊?粗鄙怎么样...
我想做未婚妈妈,可行吗? 我想做未婚妈妈,可行吗?没关系吧?我同学好多他们妈妈都是30岁以后省得他们,都没事啊,但是如果你自己...
如何在两个excel表格里筛选... 如何在两个excel表格里筛选出重复的名字如何在两个excel表格里筛选出重复的名字1、电脑打开EX...
且试天下 哪些小说是用白绫做武... 且试天下 哪些小说是用白绫做武器的?神雕侠侣吖- -..小龙女一开始就是用白绫的聊斋 辛十四娘嘿嘿~...
自带高冷体质,笑起来温暖又治愈... 自带高冷体质,笑起来温暖又治愈的星座,你了解吗?虽然天生高冷体质,但是笑起来特别的温暖治愈的新作用天...
火星未解之谜 火星未解之谜多列举一些,每个事例最好长一点,谢啦~“火星人脸”, “地表被水冲击河道”,“原始大气和...
我是1991年10月4号生的,... 我是1991年10月4号生的,是什么星座啊有的说是处女座有的说是天平座,糊涂了,到底是什么啊很负责任...
梦见白狐狸,然后当时我骑着自行... 梦见白狐狸,然后当时我骑着自行车,我想躲开它,他很凶的的追赶我,最后它向我扑了过来,然后我就醒乐.你...