前后端开发之——文章分类管理

原文地址:前后端开发之——文章分类管理 - Pleasure的博客

下面是正文内容:

前言

上回书说到

文章管理系统之添加文章分类。就是通过点击“新建文章分类”按钮从而在服务端数据库中增加一个文章分类。

对于文章分类这个对象,增删改查属于配套的基础操作。这篇博文就主要聚焦于“增”之外的“删改查”配套操作。这里的查不是指搜索,而是指查询数据库信息用于前端显示。

前端使用语言:Vue,后端使用语言:SpringBoot

正文

前端思路分析

当用户点击界面上的按钮后跳出之前的弹窗,

修改完相关信息后点击确认触发按钮绑定的updateCategory函数向后端发送表单,

updateCategory函数在开头的script部分进行了声明是调用后端修改文章分类接口的异步函数

updateCategory函数中的articleCategoryUpdateService服务在api文件夹下的article.js文件中进行了定义,以put的方式向后端“/category”发送id,categoryName,categoryAlias的值用来修改数据库中的记录。

“删”同理,点击按钮触发deleteCategory函数。

函数,弹窗,表单,接口都有自己对应的代码

后端思路分析

后端文件结构需要查看专栏之前的文章,这里就不重复进行申明了

数据访问层CategoryMapper.java,定义CategoryMapper函数用于向数据库添加数据,

服务层CategoryService.java中先声明接口,然后在CategoryServiceImpl.java中定义CategoryService函数通过调用ControllerMapper函数实现添加,(不要忘记在pojo文件夹下声明Category类)

请求层CategoryController.java,调用服务层的函数categoryService.add(category)通过post/get/put等不同的方式实现添加。

需要注意的是:

由于新增文章分类的时候向后端发送的json文件不携带id字段,是由数据库中的id主键自动生成,而更新和删除操作向后端发送的json文件则需要携带,所以在pojo文件夹下声明Category类时需要进行注解分组校验。

页面展示

实现代码

部分项目结构和代码需要参考专栏之前的文章

前端Vue

categorys和categoryModel的声明略

采用了element-plus的UI交互组件,官方参考文档:Overview 组件总览 | Element Plus

根据自己的需要自行拼接

api文件夹下的article.js(接口,删除操作相对于新增需要额外携带id字段作为区别)

import request from '@/utils/request.js'
export const articleCategoryListService = ()=>{
    return request.get('/category')
}
//文章分类添加
export const articleCategoryAddService = (categoryData)=>{
    return request.post('/category',categoryData)
}
//文章分类修改
export const articleCategoryUpdateService = (categoryData)=>{
    return request.put('/category',categoryData)
}
//文章分类删除
export const articleCategoryDeleteService = (id)=>{
    return request.delete('/category?id='+id)
}

声明要用到的异步函数(放在script部分)

/声明一个异步的函数
import { articleCategoryListService, articleCategoryAddService, articleCategoryUpdateService, articleCategoryDeleteService } from '@/api/article.js'
const articleCategoryList = async () => {
    let result = await articleCategoryListService();
    categorys.value = result.data;

}
articleCategoryList();

显示文章分类的函数(放在script部分)

//定义变量,控制标题的展示
const title = ref('')

const showDialog = (row) => {
    dialogVisible.value = true; title.value = '编辑分类'
    //数据拷贝
    categoryModel.value.categoryName = row.categoryName;
    categoryModel.value.categoryAlias = row.categoryAlias;
    //扩展id属性,将来需要传递给后台,完成分类的修改
    categoryModel.value.id = row.id
}

编辑文章分类的函数(放在script部分)

//编辑分类
const updateCategory = async () => {
    //调用接口
    let result = await articleCategoryUpdateService(categoryModel.value);
    ElMessage.success(result.msg ? result.msg : '编辑成功')

    //调用获取所有文章分类的函数
    articleCategoryList();
    dialogVisible.value = false;
}

删除文章分类的弹窗和函数(放在script部分)

import { ElMessageBox } from 'element-plus'
const deleteCategory = (row) => {
    ElMessageBox.confirm(
        '确认删除当前文章分类?',
        'Warning',
        {
            confirmButtonText: 'OK',
            cancelButtonText: 'Cancel',
            type: 'warning',
        }

    )
        .then(async () => {
            //调用接口
            let result = await articleCategoryDeleteService(row.id);
            ElMessage({
                type: 'success',
                message: 'Delete completed',
            })
            articleCategoryList();
        })
        .catch(() => {
            ElMessage({
                type: 'info',
                message: 'Delete canceled',
            })
        })
}

页面显示部分(即template部分,包括了弹窗和表格)

<template>
    <el-page-header :icon="null">
        <template #content>
            <div class="flex items-center">
                <el-avatar :size="32" class="mr-3"
                    src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png" />
                <span class="text-large font-600 mr-3"> 文章分类列表</span>
            </div>
        </template>
        <template #extra>
            <el-button type="primary" @click="dialogVisible = true; title = '新建文章分类'; clearData()">新建文章分类</el-button>
            <el-dialog v-model="dialogVisible" :title="title" width="30%">
            <el-form :model="categoryModel" :rules="rules" label-width="100px" style="padding-right: 30px">
                <el-form-item label="文章分类名" prop="categoryName">
                    <el-input v-model="categoryModel.categoryName" minlength="1" maxlength="10"></el-input>
                </el-form-item>
                <el-form-item label="备注和说明" prop="categoryAlias">
                    <el-input v-model="categoryModel.categoryAlias" minlength="1" maxlength="15"></el-input>
                </el-form-item>
            </el-form>
            <template #footer>
                <span class="dialog-footer">
                    <el-button @click="dialogVisible = false">取消</el-button>
                    <el-button type="primary" @click="title == '新建文章分类' ? addCategory() : updateCategory()"> 确认 </el-button>
                </span>
            </template>
        </el-dialog>
        </template>
    </el-page-header>
    <el-divider></el-divider>
    <el-table :data="categorys" style="width: 100%">
        <el-table-column label="id" prop="id" />
        <el-table-column label="分类名称" prop="categoryName"></el-table-column>
        <el-table-column label="分类别名" prop="categoryAlias"></el-table-column>
        <el-table-column label="操作" width="100">
            <template #default="{ row }">
                <el-button :icon="Edit" circle plain type="primary" @click="showDialog(row)"></el-button>
                <el-button :icon="Delete" circle plain type="danger" @click="deleteCategory(row)"></el-button>
            </template>
        </el-table-column>
        <template #empty>
            <el-empty description="没有数据" />
        </template>
    </el-table>
</template>

后端SpringBoot

增删改查的操作上大体相同,所以就合并进行展示了。

实体类(Category.java)

package org.example.pojo;

import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.groups.Default;
import lombok.Data;
import org.apache.ibatis.annotations.Update;
import java.time.LocalDateTime;

@Data
public class Category {
    @NotNull(groups = Update.class)
    private Integer id;//主键ID
    @NotEmpty/*(groups = {Add.class, Update.class})*/
    private String categoryName;//分类名称
    @NotEmpty/*(groups = {Add.class, Update.class})*/
    private String categoryAlias;//分类别名
    private Integer createUser;//创建人ID
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;//创建时间
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;//更新时间

    public interface Add extends Default {

    }
    public interface Update extends Default{

    }
}

请求层(CategoryController.java)

package org.example.controller;

import org.apache.ibatis.annotations.Mapper;
import org.example.pojo.Result;
import org.example.pojo.Category;
import org.example.service.CategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/category")
public class CategoryController {
    @Autowired
    private CategoryService categoryService;
    @PostMapping
    public Result add(@RequestBody @Validated(Category.Add.class) Category category){
        categoryService.add(category);
        return Result.success();
    }

    @GetMapping
    public Result<List<Category>> list(){
        List<Category> cs = categoryService.list();
        return Result.success(cs);
    }

    @GetMapping("/detail")
    public  Result<Category> detail(Integer id){
        Category c = categoryService.findById(id);
        return Result.success(c);
    }

    @PutMapping
    public Result update(@RequestBody @Validated(Category.Update.class) Category category){
        categoryService.update(category);
        return Result.success();
    }

    @DeleteMapping
    public Result delete(Integer id){
        categoryService.deleteById(id);
        return Result.success();
    }
}

服务层(CategoryServiceImpl.java,CategoryService.java只需进行声明函数略)

package org.example.service.impl;

import org.example.mapper.CategoryMapper;
import org.example.pojo.Category;
import org.example.service.CategoryService;
import org.example.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

@Service
public class CategoryServiceImpl implements CategoryService {
    @Autowired
    private CategoryMapper categoryMapper;
    @Override
    public void add(Category category){
        category.setCreateTime(LocalDateTime.now());
        category.setUpdateTime(LocalDateTime.now());
        Map<String,Object> map = ThreadLocalUtil.get();
        Integer userId = (Integer) map.get("id");
        category.setCreateUser(userId);
        categoryMapper.add(category);
    }
    @Override
    public List<Category> list(){
        Map<String,Object> map = ThreadLocalUtil.get();
        Integer userId = (Integer) map.get("id");
        return categoryMapper.list(userId);
    }
    @Override
    public Category findById(Integer id) {
        Category c = categoryMapper.findById(id);
        return c;
    }
    @Override
    public void update(Category category){
        category.setUpdateTime(LocalDateTime.now());
        categoryMapper.update(category);
    }
    @Override
    public void deleteById(Integer id){
        categoryMapper.deleteById(id);
    }
}

数据访问层(CategoryMapper.java)

package org.example.mapper;
import org.apache.ibatis.annotations.*;
import org.example.pojo.Category;
import java.util.List;
@Mapper
public interface CategoryMapper {
    @Insert("insert into category(category_name,category_alias,create_user,create_time,update_time)" +
    "values (#{categoryName},#{categoryAlias},#{createUser},#{createTime},#{updateTime})")
    void add(Category category);
    @Select("select * from category where create_user = #{userId}")
    List<Category> list(Integer userId);
    @Select("select * from category where id = #{id}")
    Category findById(Integer id);
    @Update("update category set category_name=#{categoryName},category_alias=#{categoryAlias},update_time=now() where id=#{id}")
    void update(Category category);
    @Delete("delete from category where id=#{id}")
    void deleteById(Integer id);
}

尾声

一周一码,后面就是文章管理的部分了。

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

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

相关文章

k8s 持久化存储解析:hostPath与NFS的应用与探索

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Kubernetes航线图&#xff1a;从船长到K8s掌舵者》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、前言 1、k8s为什么要有持久化存储 2、NFS简介…

post请求搜索功能爬虫

<!--爬虫仅支持1.8版本的jdk--> <!-- 爬虫需要的依赖--> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.2</version> </dependency>…

基于单片机干湿垃圾自动分类系统

**单片机设计介绍&#xff0c;基于单片机干湿垃圾自动分类系统 文章目录 一 概要二、功能设计三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的干湿垃圾自动分类系统是一个集成传感器技术、机械控制和单片机编程于一体的自动化解决方案。该系统的主要目标是实…

归并排序和计数排序

计数排序 计数排序是一种非比较排序。 count_sort 还会用到相对大小。 节省空间。 前提是遍历数组找到max和min 从而进一步确定range。 然后将数在数组中的相对位置&#xff0b;min对其进行输出。 void count_sort(int* a, int n) {int max a[0], min a[0],cnt0;for …

漂亮的个人主页HTML源码

漂亮的个人主页HTML源码&#xff0c;页面简约&#xff0c;一个卡片式的风格介绍&#xff0c;喜欢的朋友们可以拿去研究 源码下载 漂亮的个人主页HTML源码

TCP挥手中TIME_WAIT存在的原因

四次挥手的一般过程如图所示&#xff1a; 在客户端收到FIN结束报文的时候不是立刻进入CLOSED状态&#xff0c;而是进入TIME_WAIT状态&#xff0c;一般等2MLS后进入关闭状态。 原因&#xff1a; 1.可靠地终止 TCP 连接。 2.保证让迟来的 TCP报文段有足够的时间被识别并丢弃。 …

【CSDN云VS腾讯云】要不然怎么说CSDN开发云是打工人和学生党的福音呢?

&#x1f341;作者简介&#xff1a;&#x1f3c5;云计算领域优质创作者&#x1f3c5;新星计划第三季python赛道TOP1&#x1f3c5; 阿里云ACE认证高级工程师&#x1f3c5; ✒️个人主页&#xff1a;小鹏linux &#x1f48a;个人社区&#xff1a;小鹏linux&#xff08;个人社区&a…

Go 实战|使用 Wails 构建轻量级的桌面应用:仿微信登录界面 Demo

概述 本文探讨 Wails 框架的使用&#xff0c;从搭建环境到开发&#xff0c;再到最终的构建打包&#xff0c;本项目源码 GitHub 地址&#xff1a;https://github.com/mazeyqian/go-run-wechat-demo 前言 Wails 是一个跨平台桌面应用开发框架&#xff0c;他允许开发者利用 Go …

ElasticSearch分词检索

1. 倒排索引&#xff1a;表示一种数据结构&#xff0c;分词词条与文档id集合的隐射关系 2. 它跟关系型数据库是一种互补的关系&#xff0c;因为关系型数据库支持事务操作&#xff0c;满足ACID原则 #ik分词器下载 https://github.com/infinilabs/analysis-ik/releases POST /_a…

前端学习之DOM编程-案例div移动

这个案例是当你的鼠标按压下去后&#xff0c;div跟着你的鼠标移动而移动&#xff0c;当你的鼠标抬起后&#xff0c;div不随着鼠标移动而移动。类似于电脑移动应用图标的感觉。 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset&quo…

《Java面试自救指南》(专题四)Java基础

文章目录 有序集合有哪些?线程安全的集合有哪些&#xff1f;HashMap底层原理ConcurrentHashMap的底层数据结构ArrayList底层原理&#xff0c;ArrayList和Vector/LinkedList的区别String&#xff0c;StringBuffer&#xff0c;StringBuilder的区别 扩展&#xff1a;String不可变…

【THM】Exploit Vulnerabilities(利用漏洞)-

介绍 在这个房间里,我们将讨论一些识别漏洞的方法,并结合我们的研究技能来了解这些漏洞是如何被滥用的。 此外,您还会发现一些公开可用的资源,这些资源是您在执行漏洞研究和利用时的技能和工具的重要补充。然后,您将在房间的最后将所有这些应用到实际挑战中。 自动化与…

2021-2023年全国地表水水质监测数据集

1.监测范围 国家地表水水质自动监测网水质自动监测站。 2.监测项目监测项目为国家水质自动监测站配备的监测指标&#xff0c;主要包括五参数(水温、pH、溶解氧、电导率和浊度)、氨氮、高锰酸盐指数、总氮、总磷&#xff0c;部分水站增测总有机碳、叶绿素a、藻密度、VOCs、生物…

Day:004(2) | Python爬虫:高效数据抓取的编程技术(数据解析)

正则表达式实战-腾讯新闻 需求&#xff1a; 使用正则获取腾讯新闻标题内容 网站&#xff1a;https://sports.qq.com/ 代码&#xff1a; import reimport requests from fake_useragent import UserAgenturl https://sports.qq.com/ # 构建请求头信息 headers {User-Agent:…

Python爬取公众号封面图(零基础也能看懂)

&#x1f4da;博客主页&#xff1a;knighthood2001 ✨公众号&#xff1a;认知up吧 &#xff08;目前正在带领大家一起提升认知&#xff0c;感兴趣可以来围观一下&#xff09; &#x1f383;知识星球&#xff1a;【认知up吧|成长|副业】介绍 ❤️感谢大家点赞&#x1f44d;&…

#{} 和 ${}区别

1、参数是Integer类型时候没区别&#xff08;#是预编译SQL&#xff0c;$是即时SQL&#xff09; 2、当参数是String类型时&#xff0c;就会出错了 &#xff08;1&#xff09;这是$的报错信息&#xff0c;因为我们的参数admin并没有加引号所以不满足字符串条件 (2)正确的SQL &am…

【最大值线段树】【二分查找】2286. 以组为单位订音乐会的门票

本文涉及知识点 线段树 最大值线段树 二分查找算法合集 LeetCode2286. 以组为单位订音乐会的门票 一个音乐会总共有 n 排座位&#xff0c;编号从 0 到 n - 1 &#xff0c;每一排有 m 个座椅&#xff0c;编号为 0 到 m - 1 。你需要设计一个买票系统&#xff0c;针对以下情况…

Win10 下 git error unable to create file Invalid argument 踩坑实录

原始解决方案参看&#xff1a;https://stackoverflow.com/questions/26097568/git-pull-error-unable-to-create-file-invalid-argument 本问题解决于 2024-02-18&#xff0c;使用 git 版本 2.28.0.windows.1 解决方案 看 Git 抛出的出错的具体信息&#xff0c;比如如下都来自…

星系炸弹(蓝桥杯真题填空题)

import java.time.LocalDate; import java.time.temporal.ChronoUnit; public class BombExplosionDate { public static void main(String[] args) { // 定义贝塔炸弹的放置日期和定时天数 LocalDate placementDate LocalDate.of(2014, 11, 9); int daysToExplode 10…

【攻防世界】FlatScience

dirsearch 扫描发现四个文件 在login.php 中发现 输入 http://61.147.171.105:61912/login.php/?debug 发现源码 <?php if(isset($_POST[usr]) && isset($_POST[pw])){$user $_POST[usr];$pass $_POST[pw];$db new SQLite3(../fancy.db);$res $db->query(…