项目5-博客系统1(准备工作+博客列表+博客详情页)

1.创建项目

导入以下依赖

2.项目介绍

使⽤SSM框架实现⼀个简单的博客系统
共5个页面

2.1 前端页面展示

2.1.1 用户登录


2.1.2 博客发表页


2.1.3 博客编辑页


2.1.4 博客列表页


2.1.5博客详情页

2.2 功能描述:

⽤⼾登录成功后, 可以查看所有⼈的博客.

点击 <<查看全⽂>> 可以查看该博客的正⽂内容.

如果该博客作者为当前登录⽤⼾, 可以完成博客的修改和删除操作, 以及发表新博客

3.准备工作

3.1 数据准备

3.1.1 建立SQL

-- 建表SQL
create database if not exists java_blog_spring charset utf8mb4;
USE java_blog_spring;
-- 用户表
DROP TABLE IF EXISTS java_blog_spring.user;
CREATE TABLE java_blog_spring.user(
 `id` INT NOT NULL AUTO_INCREMENT,
 `user_name` VARCHAR ( 128 ) NOT NULL,
 `password` VARCHAR ( 128 ) NOT NULL,
 `github_url` VARCHAR ( 128 ) NULL,
 `delete_flag` TINYINT ( 4 ) NULL DEFAULT 0,
 `create_time` DATETIME DEFAULT now(),
 `update_time` DATETIME DEFAULT now(),
 PRIMARY KEY ( id ),
UNIQUE INDEX user_name_UNIQUE ( user_name ASC )) ENGINE = INNODB DEFAULT
CHARACTER
SET = utf8mb4 COMMENT = '用户表';
-- 博客表
drop table if exists java_blog_spring.blog;
CREATE TABLE java_blog_spring.blog (
 `id` INT NOT NULL AUTO_INCREMENT,
 `title` VARCHAR(200) NULL,
 `content` TEXT NULL,
 `user_id` INT(11) NULL,
 `delete_flag` TINYINT(4) NULL DEFAULT 0,
 `create_time` DATETIME DEFAULT now(),
 `update_time` DATETIME DEFAULT now(),
 PRIMARY KEY (id))
ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '博客表';
-- 新增用户信息
insert into java_blog_spring.user (user_name, password,github_url)values
("lay","107","https://www.weibo.com/u/2706896955?c=spr_qdhz_bd_360ss_weibo_mr");
insert into java_blog_spring.user (user_name, password,github_url)
values("muyierf","123456","https://gitee.com/muyierf");
insert into java_blog_spring.blog (title,content,user_id) values("第1篇博
客","lay的筑梦之旅",1);
insert into java_blog_spring.blog (title,content,user_id) values("第1篇博
客","muyierf的第一篇博客",2);

 创建成功!!!

3.2 前端代码引入项目中

3.3 配置配置文件

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/java_blog_spring?characterEncoding=utf8&useSSL=false
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
  configuration:
    map-underscore-to-camel-case: true #配置驼峰⾃动转换
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #打印sql语句
  mapper-locations: classpath:mapper/**Mapper.xml
# 设置⽇志⽂件的⽂件名
logging:
  file:
  name: spring-book.log

3.4 测试项目能否启动成功

成功!!!

3.5 开发前的准备

3.5.1 项目流程

1.需求分析

2.技术方案设计
1)UML图,流程图,ER图

2)数据库设计

3)接口设计(我们需要完成的工作)

3.开发(我们需要完成的工作)

4.自测(我们需要完成的工作)

5.测试(QA)

6.联调

7. 验收

8.上线

3.5.2 数据库表的创建 

数据库表通常分两类:
1.实体表->对象 (员工表,部门表,图书表,博客表..)

2.关系表->实体之间的关系

我们的项目较为简单,所以我们只需要两个实体表即可。

用户表:用户名,密码,照片,昵称,github地址

1.根据用户名,查询用户信息
2.根据用户ID,查询用户信息

博客表: 标题,日期,内容,作者, 分类.. 

1.查询博客列表
2.根据博客ID, 查询博客信息
3.根据博客ID, 修改博客信息

4.插入博客

3.5.3 接口设计

1.用户登录
根据用户名和密码, 判断是否正确->根据用户名,查询用户信息,对比密码是否正确

2.查询用户信息
根据用户ID,查询用户信息->根据用户ID,去查询用户信息

3.博客列表

查询所有博客->查询所有博客

4.查询作者信息

1)根据博客, 拿到作者ID
2)根据作者ID,获取作者信息

->根据用户ID,去查询用户信息

5.查询博客详情

->根据博客ID, 查询博客信息

6.修改博客->根据博客ID, 修改博客信息

7.添加博客->插入博客信息

8.删除博客
1)物理删除
2)逻辑删除->根据博客ID,修改博客信息

3.5.4 建包 

  • controller
  • service
  • mapper
  • model
  • config
  • constants(里面写枚举类和常量类都可以)

4.代码部分 

4.1. 实体类(model包)

//要与数据库一致

package com.example.demo.model;

import lombok.Data;

import java.util.Date;


@Data
public class BlogInfo {
    private Integer id;
    private String title;
    private String content;
    private Integer userId;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
}
package com.example.demo.model;

import lombok.Data;

import java.util.Date;

@Data
public class UserInfo {
    private Integer id;
    private String userName;
    private String password;
    private String githubUrl;
    private Byte deleteFlag;
    private Date createTime;
    private Date updateTime;
}

4.2 公共模块

包括实体类和同一功能处理<1.拦截器2.统一功能处理3.统一结果返回>

4.2.1. 统一返回结果实体类

a. code: 业务状态码
▪ 200: 业务处理成功
▪ -1 : 业务处理失败
▪ -2 : ⽤⼾未登录
▪ 后续有其他异常信息, 可以再补充.
b. msg: 业务处理失败时, 返回的错误信息
c. data: 业务返回数据

定义业务状态码//我们将这些确定的状态码存入Constants包中,防止修改 

package com.example.demo.model;

import com.example.demo.constants.Constant;
import lombok.Data;

@Data
public class Result {
    private int code;
    private String msg;
    private Object data;
    //业务执行时返回的方法

    public static Result success(Object data){
        Result result=new Result();
        result.setData(Constant.RESULT_CODE_SUCCESS);
        result.setMsg("");
        result.setData(data);
        return result;
    }

    public static Result fail(int code,String msg){
        Result result=new Result();
        result.setData(Constant.RESULT_CODE_FAIL);
        result.setMsg(msg);
        result.setData("");
        return result;
    }

    public static Result unlogin(int code,String msg,Object data){
        Result result=new Result();
        result.setData(Constant.RESULT_CODE_UNLOGIN);
        result.setMsg("用户未登录");
        result.setData(data);
        return result;
    }
}

4.2.2 统一返回结果

4.2.2.1 统一功能处理
package com.example.demo.model.result;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

public class ResponseAdvice implements ResponseBodyAdvice {
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class selectedConverterType, ServerHttpRequest request,
                                  ServerHttpResponse response) {
        if(body instanceof Result){
            return body;
        }
        if(body instanceof String){
            ObjectMapper objectMapper=new ObjectMapper();
            try {
                return objectMapper.writeValueAsString(Result.success(body));
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
        return Result.success(body);
    }
}

 记得加此注解!!!

统⼀的数据返回格式使⽤ @ControllerAdvice 和 ResponseBodyAdvice 的⽅式实现
@ControllerAdvice 表⽰控制器通知类
添加类 ResponseAdvice , 实现 ResponseBodyAdvice 接⼝, 并在类上添加@ControllerAdvice 注解

4.2.2.2 统一异常处理

@ExceptionHandler 是异常处理器,两个结合表⽰当出现异常的时候执⾏某个通知,也就是执⾏某个⽅法事件

package com.example.demo.model.result;

import com.example.demo.constants.Constant;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
@ResponseBody
public class ExceptionAdvice {
    @ExceptionHandler
    public Result exceptionAdvice(Exception e){
        return Result.fail(Constant.RESULT_CODE_FAIL,e.getMessage());
    }
}

4.2.2.3 拦截器 

4.3 业务代码

4.3.1 持久层(mapper)

根据需求, 先⼤致计算有哪些DB相关操作, 完成持久层初步代码, 后续再根据业务需求进⾏完善

1. 用户登录页

  • 根据用户名查询用户信息(select语句)

2. 博客列表⻚

  • 根据id查询user信息(select语句->通过id查询用户表)
  • 获取所有博客列表(select语句->通过id查询博客表

3. 博客详情⻚

  • 根据博客ID查询博客信息
  • 根据博客ID删除博客(修改delete_flag=1,update)

4. 博客修改⻚

  • 根据博客ID修改博客信息(update)

5. 发表博客

  • 插⼊新的博客数据(insert)

1.BlogInfoMapper 

package com.example.demo.mapper;

import com.example.demo.model.BlogInfo;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface BlogMapper {
    //a.获取所有博客列表
    @Select("select * from blog where delete_flag=0 order by create_time desc")
    List<BlogInfo> selectAllBlog();

    //b.根据博客id查询它的博客
    @Select("select * from blog where delete_flag=0 and id=#{id}")
    BlogInfo selectByIdBlog();

    //c.插⼊新的博客数据(insert)
    @Insert("insert into blog (title,content,user_id) values (#{title},#{content},#{userId})")
    Integer insertNewBlog(BlogInfo blogInfo);

    //d.博客修改页和博客删除页(update)-动态mybatis->xml
    Integer updateBlog(BlogInfo blogInfo);

}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.example.demo.mapper.BlogInfoMapper">
    <update id="updateBlog">
        update blog
        <set>
            <if test="title!=null">
                title=#{title},
            </if>
            <if test="content!=null">
                content=#{content},
            </if>
            <if test="deleteFlag !=null">
                delete_flag = #{deleteFlag}
            </if>
        </set>
        where id=#{id}
    </update>
</mapper>

2.UserInfoMapper

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;


@Mapper
public interface UserInfoMapper {
    //1.根据id查询用户的信息
    @Select("select * from user where id = #{id}")
    UserInfo selectById(Integer id);
    //2.根据用户名查询用户的信息,登陆操作时用
    @Select("select * from user where user_name = #{userName}")
    UserInfo selectByName(String name);
}
4.3.1.1 测试持久层
package com.example.demo.mapper;

import com.example.demo.model.BlogInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class BlogInfoMapperTest {
    @Autowired
    private BlogInfoMapper blogInfoMapper;

    @Test
    void selectAllBlog() {
        System.out.println(blogInfoMapper.selectAllBlog());
    }

    @Test
    void selectByIdBlog() {
        System.out.println( blogInfoMapper.selectByIdBlog(1));
    }

    @Test
    void insertNewBlog() {
        BlogInfo blogInfo=new BlogInfo();
        blogInfo.setTitle("测试接口");
        blogInfo.setContent("单元测试测试接⼝测试接⼝");
        blogInfo.setUserId(5);
        blogInfoMapper.insertNewBlog(blogInfo);
    }

    @Test
    void updateBlog() {
        BlogInfo blogInfo=new BlogInfo();
        blogInfo.setId(3);
        blogInfo.setTitle("测试接口ing");
        blogInfo.setDeleteFlag(1);
        blogInfoMapper.updateBlog(blogInfo);
    }
}

测试成功!!!

测试结果

 数据库也成功录入信息!!!

4.3.2 实现博客列表

4.3.2.1 约定前后端交互接口
[请求]
/blog/getlist
[响应]
{
     "code": 200,
     "msg": "",
     "data": [{
     "id": 1,
     "title": "第⼀篇博客",
     "content": "111我是博客正⽂我是博客正⽂我是博客正⽂",
     "userId": 1,
     "deleteFlag": 0,
     "createTime": "2023-10-21 16:56:57",
     "updateTime": "2023-10-21T08:56:57.000+00:00"
 },
 .....
 ]
}

客户端给服务器发送⼀个 /blog/getlist 这样的 HTTP 请求, 服务器给客⼾端返回了⼀个 JSON 格
式的数据.

4.3.2.2 实现服务器代码
1.service包

2.controller包

3.后端测试

失败!!!

与预想结果不符,我想要的code为200.经过检查,set错误,导致其为默认值。

修改之后重新测试

成功!!! 

4.3.2.3 前后端交互->实现客户端代码

4.3.2.3.1 前端测试

成功!!!

4.3.2.3.2 相关部署(时间的返回格式确定)

此时⻚⾯的⽇期显⽰为时间戳, 我们从后端也⽇期进⾏处理
SimpleDateFormat 格式参考官⽅⽂档

我们建立一个utils包,进行相关的部署

重写获取博客创建时间

 重新测试

成功!!!

4.3.3 实现博客详情

⽬前点击博客列表⻚的 "查看全⽂" , 能进⼊博客详情⻚, 但是这个博客详情⻚是写死的内容. 我们期望能够根据当前的 博客 id 从服务器动态获取博客内容.
4.3.3.1 约定前后端交互接⼝

[请求]

/blog/getBlogDetail?blogId=1
[ 响应 ]
{
        "code" : 200,
        "msg" : "" ,
        "data" : {
        "id" : 1,
        "title" : " 第⼀篇博客 " ,
        "content" : "111 我是博客正⽂我是博客正⽂我是博客正⽂ " ,
        "userId" : 1,
        "deleteFlag" : 0,
        "createTime" : "2023-10-21 16:56:57" ,
        "updateTime" : "2023-10-21T08:56:57.000+00:00"
}
}
4.3.3.2 实现服务器代码
1.service包

2.controller包

3.后端测试

成功!!!

 4.3.3.3 前后端交互

首先清除写死的代码

后续将获得的内容赋值到上面

 4.3.3.3.1 前后测试成功!!! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/540383.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CSS基础+基本选择器和复合选择器(如果想知道CSS的基础+基本选择器和复合选择器知识点,那么只看这一篇就足够了!)

前言&#xff1a;在我们学习完了html之后&#xff0c;我们就要开始学习三大件中的第二件—CSS&#xff0c;CSS 可以控制多重网页的样式和布局&#xff0c;也就是将我们写好的html代码加上一层华丽的衣裳&#xff0c;使网页变得更加精美。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨…

uni-app如何生成骨架屏

为什么需要骨架屏&#xff1a;为了缓解用户打开程序时等待接口的焦虑情绪 1.打开微信开发者工具&#xff0c;找到模拟器中的页面信息&#xff0c;选择生成骨架屏 2.将生成的wxml代码复制到vscode&#xff0c;在index的components中新建一个vue文件&#xff0c;只需保留请求接口…

RPA实战演练UiBot6.0新食堂一楼问卷星(类似于之前的网页表单提交)

要使用RPA&#xff08;Robotic Process Automation&#xff0c;机器人流程自动化&#xff09;帮助新食堂进行调查问卷&#xff0c;我们可以结合UiBot 6.0来实施具体的计划。以下是一个大致的实战演练计划&#xff1a; 一、目标与需求分析 明确调查目标&#xff1a;了解新食堂…

CentOS7里ifcfg-eth0文件不存在解决方案/Centos7修改网络IP解决方案

Centos7网络IP地址手动设置 1、centos7没有ifcfg-eth0&#xff0c;我的centos7也没有其他博客说的什么ifcfg-ens33、ifcfg-ens32&#xff0c;然后我打开了我这里的ifcfg-eno***&#xff0c;结果发现就是centos6里的ifcfg-eth0里的网络配置。2、vim ifcfg-eno***&#xff08;按t…

34. UE5 RPG实现鼠标点击移动

在前面&#xff0c;我们实现过使用键盘按键wasd去实现控制角色的移动&#xff0c;现在&#xff0c;我们实现了InputAction按键触发&#xff0c;后面&#xff0c;实现一下通过鼠标点击地面实现角色移动。 我们将实现两种效果的切换&#xff0c;如果你点击地面快速松开&#xff0…

突破编程_前端_SVG(circle 圆形)

1 circle 元素的基本属性和用法 SVG 的 <circle> 元素用于在SVG文档中绘制圆形。它具有几个基本属性&#xff0c;允许定义圆形的大小、位置、填充颜色和边框样式。以下是 <circle> 元素的基本属性及其详细解释&#xff1a; 1.1 cx 和 cy 描述&#xff1a;这两个…

Docker容器嵌入式开发:Docker Ubuntu18.04配置mysql数据库

在 Ubuntu 18.04 操作系统中安装 MySQL 数据库的过程。下面是安装过程的详细描述&#xff1a; 首先&#xff0c;使用以下命令安装 MySQL 服务器&#xff1a; sudo apt install mysql-server系统会提示是否继续安装&#xff0c;按下 Y 键确认。 安装过程中&#xff0c;系统会…

模板进阶 | 非类型模板参数 | 类模板的特化 | 模板的分离编译 | 模板的优缺点

非类型模板参数 我们可以认为非类型模板参数就是一个常量&#xff0c;在我们的类里面我们是不能对它进行改造 为什么会有这样的场景&#xff0c;其次就是C语言那里我们一般使用什么。 场景1 #include<iostream> using namespace std;#define N 10 template<class T…

uniapp开发小程序手写板、签名、签字

可以使用这个插件进行操作 手写板-签名签字-lime-signature - DCloud 插件市场 但是目前这个插件没有vue3 setup Composition API的写法。所以对于此文档提供的可以直接使用,需要使用Composition API方式实现的,可以继续看。 因为Composition API方式,更加的简单、灵活,…

2024 CleanMyMac X 优化储存苹果电脑空间 的好帮手

在数字时代&#xff0c;我们的Mac设备承载着越来越多的重要信息和日常任务。然而&#xff0c;随着时间的推移&#xff0c;这些设备可能会变得缓慢、混乱&#xff0c;甚至充满不必要的文件。这就是CleanMyMac X发挥作用的地方。 CleanMyMac X是一款功能强大的Mac优化工具&#…

基于java+springboot+vue实现的药品管理系统(文末源码+Lw)23-297

摘 要 传统信息的管理大部分依赖于管理人员的手工登记与管理&#xff0c;然而&#xff0c;随着近些年信息技术的迅猛发展&#xff0c;让许多比较老套的信息管理模式进行了更新迭代&#xff0c;药品信息因为其管理内容繁杂&#xff0c;管理数量繁多导致手工进行处理不能满足广…

动态规划原理及其在优化问题中的应用解析

动态规划原理及其在优化问题中的应用解析 一、最优子结构二、重叠子问题三、何时使用动态规划法四、伪代码示例五、C代码示例七、详细说明动态规划原理7.1、最优子结构7.2 重叠子问题7.3 动态规划的实现 八、结论 动态规划是一种解决优化问题的方法&#xff0c;它通过将原问题分…

Triton Server Python 后端优化

接上文 不使用 Docker 构建 Triton 服务器并在 Google Colab 平台上部署 HuggingFace 模型 MultiGPU && Multi Instance Config 追加 instance_group [{count: 4kind: KIND_GPUgpus: [ 0, 1 ]} ]Python Backend Triton 会根据配置信息启动四个实例&#xff0c;…

win10系统中exe文件打不开

问题描述 昨天下载了某个驱动安装程序之后&#xff0c;点击.exe文件没有反应。 解决方法 1. 开启兼容模式运行 右键点击属性 点击【兼容性】&#xff0c;并且【以兼容模式运行程序】 2. 给exe文件换个文件夹再次尝试 我使用第一个方法没有用&#xff0c;之后尝试了把文…

Eureka-搭建Eureka步骤

简介&#xff1a; Eureka是Netflix开发的服务发现框架&#xff0c;本身是一个基于REST的服务&#xff0c;主要用于定位运行在AWS域中的中间层服务&#xff0c;以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中&#xff0c;以实…

转让北京100万旅行社带国内旅行社许可证条件和要求

旅行社的主要分类为国际旅行社和国内旅行社两类。国际旅行社拥有更为广泛的经营范围&#xff0c;不仅涵盖国内旅游业务&#xff0c;还包括出境旅游业务以及入境旅游业务&#xff1b;相比之下&#xff0c;国内旅行社则专注于国内旅游市场以及入境旅游业务。当前情况下&#xff0…

Pandas部分应掌握的重要知识点

目录 Pandas部分应掌握的重要知识点一、DataFrame数据框的创建1、直接基于二维数据创建&#xff08;同时使用index和columns参数&#xff09;2、基于excel文件中的数据来创建 二、查看数据框中的数据和联机帮助信息1、查看特殊行的数据2、查看联机帮助的两种常见方法&#xff0…

MDK平台 - Code, RO-data , RW-data, ZI-data详解

文章目录 1 . 前言2 . Code, RO-data , RW-data, ZI-data解析3 . RAM上电复位4 . 细节扩展5 . 总结 【全文大纲】 : https://blog.csdn.net/Engineer_LU/article/details/135149485 1 . 前言 MDK编译后&#xff0c;会列出Code, RO-data , RW-data, ZI-data&#xff0c;以下解析…

2024年会计、审计、财务与经济管理国际会议(ICAAFEM2024)

2024年会计、审计、财务与经济管理国际会议&#xff08;ICAAFEM2024&#xff09; 会议简介 2024年国际会计、审计、财务和经济管理会议&#xff08;ICAAFEM2024&#xff09;将在云南省昆明市举行。会议旨在为从事“会计、审计、财务、经济管理”研究的专家学者提供一个平台&am…

java快速幂算法

快速幂算法 参考视频(参考五角七边up大佬&#xff09; 幂运算的介绍 幂运算是指将一个数自身乘以自身多次的运算&#xff0c;其表达式为 a n a^n an&#xff0c;其中 a a a 是底数&#xff0c; n n n 是指数。 快速幂解释 快速幂算法是一种用于快速计算幂运算的算法&…