【个人博客系统网站】我的博客列表页 · 增删改我的博文 · 退出登录 · 博客详情页 · 多线程应用

news2025/6/18 9:19:36

【JavaEE】进阶 · 个人博客系统(4)

在这里插入图片描述

文章目录

  • 【JavaEE】进阶 · 个人博客系统(4)
    • 1. 增加博文
    • 1.1 预期效果
      • 1.1 约定前后端交互接口
      • 1.2 后端代码
      • 1.3 前端代码
      • 1.4 测试
    • 2. 我的博客列表页
      • 2.1 期待效果
      • 2.2 显示用户信息以及博客信息
        • 2.2.1 约定前后端交互接口
        • 2.2.2 后端代码
        • 2.2.3 前端代码
        • 2.2.4 测试
      • 2.3 删除文章
        • 2.3.1 约定前后端交互接口
        • 2.3.2 后端代码
        • 2.3.3 前端代码
        • 2.3.4 测试
      • 2.4 退出登录
        • 2.4.1 约定前后端交互接口
        • 2.4.2 后端代码
        • 2.4.3 前端代码
        • 2.4.4 测试
    • 3. 修改文章
      • 3.1 页面初始化
        • 3.1.1 约定前后端接口
        • 3.1.2 后端代码
        • 3.1.3 前端代码
        • 3.1.4 测试
      • 3.2 修改文章
        • 3.2.1 约定前后端交互接口
        • 3.2.2 后端代码
        • 3.2.3 前端代码
        • 3.2.4 测试
    • 4. 博客详情页
      • 4.1 期待效果
      • 4.2 约定前后端交换接口
      • 4.3 后端代码
      • 4.4 前端代码
      • 4.5 测试

【JavaEE】进阶 · 个人博客系统(4)

1. 增加博文

1.1 预期效果

a

用户在网页中编写标题和正文,点击提交,选择

  1. 输入摘要
  2. 取消,继续编写文章

提交成功后,选择

  1. 继续写文章
  2. 返回“我的博客列表页”

1.1 约定前后端交互接口

后端:

  1. /art/publish
  2. 将前端传递过来的数据保存到数据库
  3. 返回受影响行数

前端:

  1. /art/publish
  2. 标题,正文,摘要
  3. 当前登录用户sessionid

1.2 后端代码

在这里插入图片描述

  1. controller层

由于经常需要对字符串进行检查,我封装了一个方法:

  • 为什么前端检验完了,后端还检验呢?
    • 千万别相信“前端”,因为这个“前端”,可能不是浏览器正常的流程,也可能是通过postman等方式发送的请求,这个就可以绕开前端代码的校验~
    • 不用担心,因为
public class APPUtils {
   /**
     * 字符串全部都有长度才返回true
     * @param strings
     * @return
     */
    public static boolean hasLength(String... strings) {
        for(String x : strings) {
            if(!StringUtils.hasLength(x)) {
                return false;
            }
        }
        return true;
    }
}

修改:

在这里插入图片描述

在这里插入图片描述

@RequestMapping("/publish")
public CommonResult publish(@RequestBody ArticleInfo articleInfo, HttpServletRequest request) {
    // 1. 获取当前用户详信息
    UserInfo userInfo = SessionUtils.getUser(request);
    articleInfo.setUid(userInfo.getId());
    articleInfo.setPhoto(userInfo.getPhoto());
    // 2. 校验参数
    if(!APPUtils.hasLength(articleInfo.getContent(), articleInfo.getSummary(), articleInfo.getTitle())) {
        return CommonResult.fail(-1, "非法参数!");
    }
    // 3. 提交到数据库中
    int rows = articleService.publish(articleInfo);
    // 4. 返回
    return CommonResult.success(rows);
}
  1. service层
@Autowired
private ArticleMapper articleMapper;

public int publish(ArticleInfo articleInfo) {
    return articleMapper.insert(articleInfo);    
}
  1. mapper层
@Insert("insert into articleinfo (title, content, summary, uid, photo) values (#{title}, #{content}, #{summary}, #{uid}, #{photo})")
int insert(ArticleInfo articleInfo);
  1. 拦截器配置
    • 拦截,不排除此接口

1.3 前端代码

在这里插入图片描述

function publish() {
    var title = jQuery("#text");
    var content = jQuery("#content");
    // 1. 参数校验
    if (title.val().trim() == "") {
        alert("标题不能为空!");
        title.focus();
        return false;
    }
    if (content.val().trim() == "") {
        alert("正文不能为空!");
        content.focus();
        return false;
    }
    // 2. 输入摘要
    var summary = prompt("请输入摘要:");
    if(summary == "") {
        return false;
    }
    // 3. 发送请求
    jQuery.ajax({
        url: "/art/publish",
        method: "POST",
        contentType: "application/json; charset=utf8",
        data: JSON.stringify({
            title: title.val().trim(),
            content: content.val().trim(),
            summary: summary.val().trim(),
        }),
        // 3. 处理响应
        success: function (body) {
            if (body.code == 200 && body.data == 1) {
                if(confirm("发布成功!请问是否继续创作?")) {
                    location.href = location.href;
                }else {
                    location.href = "myblog_lists.html";
                }
            } else {
                alert("发布失败:" + body.msg);
            }
        },
    });
}

1.4 测试

在这里插入图片描述

在这里插入图片描述

为了避免写文章过程中session过去,我将session设置为永不过期:

在这里插入图片描述

2. 我的博客列表页

2.1 期待效果

在这里插入图片描述

  1. 左侧窗口显示用户信息
  2. 右侧窗口显示用户创作的博文简介
    1. 标题
    2. 时间以及阅读量
    3. 摘要
    4. 查看正文,修改文章,删除文章按钮
  3. 右上角
    1. 点击主页跳转到所有人的博客列表页
    2. 点击写博客跳转到博客创作页
    3. 点击退出登录,后端删除登录记录,跳转到登录页面

2.2 显示用户信息以及博客信息

2.2.1 约定前后端交互接口

后端:

  1. /article/get_mylist
  2. 通过当前登录用户查询博客
  3. 返回用户信息以及博客信息的组合

前端:

  1. /article/get_mylist
  2. get
  3. 接受响应,投喂给页面

2.2.2 后端代码

  1. controller层
@RequestMapping("/get_mylist")
public CommonResult getMylist(HttpServletRequest request) {
    // 1. 获取当前登录用户
    UserInfo userInfo = SessionUtils.getUser(request);
    // 2. 通过此用户发布的所有文章
    List<ArticleInfo> list = articleService.getListByUid(userInfo.getId());
    // 3. 标题 / 正文太长 处理
    ArticleUtils.substringList(list);
    // 4. 返回给前端
    Map<String, Object> map = new HashMap<>();
    map.put("user", userInfo);
    map.put("list", list);
    return CommonResult.success(map);
}
// 文章工具类
public class ArticleUtils {

    //标题截取长度
    private static final int _TITLE_LENGTH = 40;
    //摘要截取长度
    private static final int _SUMMARY_LENGTH = 160;

    public static void substringList(List<ArticleInfo> list) {
        if(list != null && list.size() != 0) {
            // 并发处理 list 集合
            list.stream().parallel().forEach((art) -> {
                //标题截取
                if(art.getTitle().length() > _TITLE_LENGTH) {
                    art.setTitle(art.getTitle().substring(0, _TITLE_LENGTH) + "...");
                }
                //摘要截取
                if(art.getSummary().length() > _SUMMARY_LENGTH) {
                    art.setSummary(art.getSummary().substring(0, _SUMMARY_LENGTH) + "...");
                }
            });
        }
    }
}
  1. service层
public List<ArticleInfo> getListByUid(int uid) {
    return articleMapper.getListByUid(uid);
}
  1. mapper层
@Select("select * from articleinfo where uid = #{uid} order by id desc")
List<ArticleInfo> getListByUid(@Param("uid") int uid); //越晚发布排在越前
  1. 拦截器配置
    • 不排除此接口
  2. 时间格式配置

可以接受数据库时间的类型一般是:

  1. Date
  2. LocalDataTime
  3. TimeStamp

网络资料

LocalDateTime和Date是Java中表示日期和时间的两种不同的类,它们有一些区别和特点。

  1. 类型:LocalDateTime是Java 8引入的新类型,属于Java 8日期时间API(java.time包)。而Date是旧版Java日期时间API(java.util包)中的类。

  2. 不可变性:LocalDateTime是不可变的类型,一旦创建后,其值是不可变的。而Date是可变的类型,可以通过方法修改其值。

  3. 线程安全性:LocalDateTime是线程安全的,多个线程可以同时访问和操作不同的LocalDateTime实例。而Date是非线程安全的,如果多个线程同时访问和修改同一个Date实例,可能会导致不可预期的结果。

  4. 时间精度:LocalDateTime提供了纳秒级别的时间精度,可以表示更加精确的时间。而Date只能表示毫秒级别的时间精度。

  5. 时区处理:LocalDateTime默认不包含时区信息,表示的是本地日期和时间。而Date则包含时区信息,它的实际值会受到系统默认时区的影响。

而TimeStamp就是long类型的时间戳的包装~

对于时间格式的控制:

  1. json的构造本身是通过getter去获取的,所以可以重写getter来控制显示效果

  2. 全局配置:

    在这里插入图片描述

    但是这只适合jdk8之前的Date类型

  3. 局部配置:

    • 对于时间类型的属性,是可以通过注解@JsonFormat来配置的:

    在这里插入图片描述

2.2.3 前端代码

左:

在这里插入图片描述

右:

在这里插入图片描述

jQuery.ajax({
    type: "get",
    url: "/art/get_mylist",
    success: function (body) {
        if (body.code == 200) {
            // 1. 改变左侧窗口
            jQuery(".card img").attr("src", body.data.user.photo);
            jQuery(".card h3").text(body.data.user.name);
            if(body.data.user.git.trim() != "") {
                jQuery(".card a").attr("href", body.data.user.git);
            }
            jQuery("#count").text(body.data.list.length);
            // 2. 显示文章,构造博客html元素
            for (var blog of body.data.list) {
                console.log(body.title);
                var art =
                    '<div class="blog"><div class="title">' + blog.title + "</div>";
                art +=
                    '<div class="date">' +
                    blog.createtime +
                    " 阅读量:" +
                    blog.rcount +
                    "</div>";
                art += '<div class="content">' + blog.summary + "</div>";
                art += '<div class="thing">';
                art +=
                    '<a href="blog_detail.html?aid=' + blog.id + '">查看正文</a>';
                art +=
                    '<a href="myblog_update.html?aid=' + blog.id + '">修改文章</a>';
                art +=
                    '<div id="del" style="background-color: rgba(255, 0, 0, 0.6)" οnclick="del(' +
                    blog.id +
                    ')">删除文章</div>';
                art += "</div></div>";
                // 3. 追加到div.article
                jQuery(".article").append(jQuery(art));
            }
        }
    },
});

你也可以,以标签为单位去设置属性以及嵌套,这有逻辑的构建;而我这里是单纯的拼接字符串,用jQuery(str),构造html元素

2.2.4 测试

在这里插入图片描述

2.3 删除文章

2.3.1 约定前后端交互接口

后端:

  1. /art/delete
  2. 根据当前登录用户id,和删除文章对应的作者id,判断是否有权限删除,有才能删除
  3. 返回受影响行数

前端:

  1. /art/delete
  2. post
  3. JSON:id(文章id)
  4. 如果受影响行数为1,刷新页面

2.3.2 后端代码

  1. controller层
@RequestMapping("/delete")
public CommonResult delete(@RequestBody ArticleInfo articleInfo, HttpServletRequest request) {
    // 1. 获取当前登录用户的id
    int uid = SessionUtils.getUser(request).getId();
    // 2. 设置到文章对象里
    articleInfo.setUid(uid);
    // 3. 删除
    int rows = articleService.delete(articleInfo);
    // 4. 返回
    return CommonResult.success(rows);
}
  1. service层
public int delete(ArticleInfo articleInfo) {
    return articleMapper.delete(articleInfo);
}
  1. mapper层
@Delete("delete from articleinfo where id = #{id} and uid = #{uid}")
// 查找文章和检测权限在一步搞定
int delete(ArticleInfo articleInfo);
  1. 拦截器配置
    • 拦截,不排除

2.3.3 前端代码

function del(aid) {
    // 0. 参数校验
    if (parseInt(aid) == NaN || aid <= 0) {
        return false;
    }
    jQuery.ajax({
        method: "post",
        url: "/art/delete",
        contentType: "application/json; charset=utf8",
        data: JSON.stringify({
            id: aid,
        }),
        success: function (body) {
            if (body.code == 200 && body.data == 1) {
                location.href = location.href;
            } else {
                alert("删除失败!\n");
            }
        },
    });
}

2.3.4 测试

在这里插入图片描述

2.4 退出登录

2.4.1 约定前后端交互接口

后端:

  1. /user/logout
  2. 根据当前用户进行删session操作
  3. 无返回值

前端:

  1. /user/logout
  2. a标签的get

2.4.2 后端代码

  1. controller层
@RequestMapping("/logout")
public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException {
    // 设置为null也可以,但这是因为我们的判断原理的原因
    //SessionUtils.setUser(request, null);
    // 调用工具类里的注销方法
    SessionUtils.remove(request);
    response.sendRedirect("blog_login.html");
}
/**
 * 注销
 * @param request
 */
public static void remove(HttpServletRequest request) {
    HttpSession session = request.getSession(false);
    if(session != null && session.getAttribute(ApplicationVariable.SESSION_KEY) != null) {
        session.removeAttribute(ApplicationVariable.SESSION_KEY);
    }
}
  1. 拦截器配置
    • 拦截,不排除

2.4.3 前端代码

<a href="/user/logout">退出登录</a>

2.4.4 测试

在这里插入图片描述

3. 修改文章

在这里插入图片描述
在这里插入图片描述

预期效果就是:原有数据显示出来,供用户修改

3.1 页面初始化

3.1.1 约定前后端接口

后端:

  1. /art/get_art
  2. 根据uid和aid查询文章
  3. 返回文章信息

前端:

  1. /art/get_art
  2. post,json,aid
  3. 将数据投喂到网页

3.1.2 后端代码

  1. controller层
@RequestMapping("/get_art")
public CommonResult getArt(@RequestBody ArticleInfo articleInfo, HttpServletRequest request) {
    // 1. 获取当前登录用户的id
    int uid = SessionUtils.getUser(request).getId();
    // 2. 设置到文章对象里
    articleInfo.setUid(uid);
    // 3. 查询文章
    ArticleInfo art = articleService.getArt(articleInfo);
    // 4. 返回(查询不到一个对象,是null;如果查询不到对象集合,返回的是空集合)
    return art == null ? CommonResult.fail(-1, "查询不到!") : CommonResult.success(art);
}
  1. service层
public ArticleInfo getArt(ArticleInfo articleInfo) {
    return articleMapper.getArticleCheck(articleInfo);
}
  1. mapper层
@Select("select * from articleinfo where id = #{id} and uid = #{uid}")
ArticleInfo getArticleCheck(ArticleInfo articleInfo);//检查权限的查询文章

@Select("select * from articleinfo where id = #{id}")
ArticleInfo getArticle(ArticleInfo articleInfo);
  1. 拦截器配置
    • 拦截,不排除

3.1.3 前端代码

<script>
    var aid = getParamValue("aid");
    // 1. 校验参数
    function init() {
        if (aid == null || aid <= 0) {
            alert("非法参数!");
            location.href = "myblog_lists.html";
            return false;
        }
        // 2. 查询文章
        jQuery.ajax({
            url: "/art/get_art",
            method: "post",
            contentType: "application/json; charset=utf8",
            data: JSON.stringify({
                id: aid,
            }),
            success: function (body) {
                if (body.code == 302) {
                    location.href = body.msg;
                    return false;
                }
                if (body.code == 200) {
                    jQuery("#text").val(body.data.title);
                    jQuery("#content").val(body.data.content);
                    jQuery("#summary").val(body.data.summary);//用隐藏输入框保存摘要信息
                } else {
                    alert("发布失败:" + body.msg);
                }
            },
        });
    }
    init();
</script>

在这里插入图片描述

注意:

  1. 如果直接写代码的话,而不是调用方法,默认页面跟代码一起加载,而调用方法是页面加载后调用此init方法
    • 如果不采取这种方式的话,会导致请求返回的页面,被拦截器拦下
  2. 为什么还是用json而不是用querystring直接发送请求
    • 习惯吧,因为json比较通用,如果还需要其他信息,querystring不方便
  3. 修改页跟添加页是一样的,为什么不重用?
    • 重用会导致一些没有必要的判断,不符合单一设计原则,麻烦/乱/开发不舒适,耦合度高…

3.1.4 测试

在这里插入图片描述

3.2 修改文章

3.2.1 约定前后端交互接口

后端:

  1. /art/update
  2. 接受文章数据
  3. 返回受影响行数

前端:

  1. /art/update
  2. post,json,上传文章数据
  3. 成功则跳转到我的博客列表页

3.2.2 后端代码

  1. controller层
@RequestMapping("/update")
public CommonResult update(@RequestBody ArticleInfo articleInfo, HttpServletRequest request) {
    // 0. 确认用户
    int uid = SessionUtils.getUser(request).getId();
    articleInfo.setUid(uid);
    // 1. 校验参数
    if(!APPUtils.hasLength(articleInfo.getContent(), articleInfo.getSummary(), articleInfo.getTitle())) {
        return CommonResult.fail(-1, "非法参数!");
    }
    // 2. 修改
    int rows = articleService.update(articleInfo);
    // 3. 返回
    return CommonResult.success(rows);
}
  1. service层
public int update(ArticleInfo articleInfo) {
    return articleMapper.updateArticle(articleInfo);
}
  1. mapper层
    • 必须是有权限才能修改
    • 更新时间修改为当下
@Update("update articleinfo set content = #{content}, title = #{title}, summary = #{summary}, updatetime = now() where id = #{id} and uid = #{uid}")
int updateArticle(ArticleInfo articleInfo);
  1. 拦截器配置
    • 拦截,不排除

3.2.3 前端代码

在这里插入图片描述

function update() {
    if (aid == null || aid <= 0) {
        alert("非法参数!");
        location.href = "myblog_lists.html";
        return false;
    }
    var title = jQuery("#text");
    var content = jQuery("#content");
    // 1. 参数校验
    if (title.val().trim() == "") {
        alert("标题不能为空!");
        title.focus();
        return false;
    }
    if (content.val().trim() == "") {
        alert("正文不能为空!");
        content.focus();
        return false;
    }
    // 2. 输入摘要
    var summary = prompt("请输入摘要:", jQuery("#summary").val());
    if (summary.trim() == "") {
        return false;
    }
    jQuery("#summary").val(summary);
    // 3. 发送请求
    jQuery.ajax({
        url: "/art/update",
        method: "POST",
        contentType: "application/json; charset=utf8",
        data: JSON.stringify({
            id: aid,
            title: title.val().trim(),
            content: content.val().trim(),
            summary: summary.trim(),
        }),
        // 3. 处理响应
        success: function (body) {
            if (body.code == 302) {
                location.href = body.msg;
                return false;
            }
            if (body.code == 200 && body.data == 1) {
                location.href = "myblog_lists.html";
            } else {
                alert("修改失败:" + body.msg);
            }
        },
    });
}

3.2.4 测试

4. 博客详情页

4.1 期待效果

在这里插入图片描述

  1. 根据是否登录,改变导航栏
  2. 根据querystring中的aid,显示对应的博文,和作者信息
  3. 每次访问成功,阅读量加1(本次显示是加1之前)
  4. 作者的文章总数通过后端计算
  5. 正文以html的样式渲染出来

这样的复杂查询可以用到并发编程:

  • 【JavaEE】Callable接口(NO.6线程创建方法)-JUC的常见类-与线程安全有关集合类_s:103的博客-CSDN博客
  • 用有返回值的线程创建方式(获取的时候若未结束,等待…)

4.2 约定前后端交换接口

后端:

  1. /art/detail
  2. 通过aid,找到文章
  3. 通过文章,uid找到作者,查询总文章数,通过aid修改文章阅读量
  4. 返回:
    1. “login”,true/false,true代表登录中
    2. “count”,文章数
    3. “user”,用户
    4. “art”,文章

前端:

  1. /art/detail
  2. json,aid
  3. 接受响应,投喂给代码

4.3 后端代码

  1. controller层
    1. 查询文章信息
    2. 校验文章是否存在
    3. 根据uid查询用户总文章数的任务
    4. 根据uid查询用户信息的任务
    5. 根据aid更新阅读量的任务
    6. 线程池执行任务
    7. 构造响应数据,并返回
@Autowired
private ArticleService articleService;
@Autowired
private UserService userService;
@RequestMapping("/detail")
public CommonResult detail(@RequestBody ArticleInfo articleInfo, HttpServletRequest request) throws ExecutionException, InterruptedException {
    // 1. 查询文章信息
    ArticleInfo art = articleService.getArtByAid(articleInfo);
    // 2. 校验文章是否存在
    if(art == null) {
        return CommonResult.fail(-1, "非法参数!");
    }
    // 3. 根据uid查询用户总文章数的任务
    FutureTask<Integer> task1 = new FutureTask<Integer>(() -> {
        return articleService.getArtNumberByUid(art.getUid());
    });
    // 4. 根据uid查询用户信息的任务
    FutureTask<UserInfo> task2 = new FutureTask<UserInfo>(() -> {
        return userService.getUserByUid(art.getUid());
    });
    // 5. 根据aid更新阅读量的任务
    FutureTask<Integer> task3 = new FutureTask<Integer>(() -> {
        return articleService.incrementRCount(art.getId());
    });
    // 6. 线程池执行任务
    APPUtils.THREAD_POOL.submit(task1);
    APPUtils.THREAD_POOL.submit(task2);
    APPUtils.THREAD_POOL.submit(task3);
    // 7. 构造响应数据,并返回
    Map<String, Object> map = new HashMap<>();
    map.put("login", SessionUtils.getUser(request) != null);
    map.put("count", task1.get());
    map.put("user", task2.get());
    map.put("art", art);
    return CommonResult.success(map);
}

在这里插入图片描述

  1. service层

ArticleService:

public int getArtNumberByUid(int uid) {
    return articleMapper.getArtNumberByUid(uid);
}

public int incrementRCount(int aid) {
    return articleMapper.incrementRCount(aid);
}

UserService:

public UserInfo getUserByUid(int uid) {
    return userMapper.getUserByUid(uid);
}
  1. mapper层

ArticleMapper:

@Select("select count(*) from articleinfo where uid=#{uid}")
int getArtNumberByUid(@Param("uid") int uid);

@Update("update articleinfo set rcount = rcount + 1 where id = #{aid}")
int incrementRCount(@Param("aid") int aid);

UserMapper:

@Select("select * from userinfo where id = #{uid}")
UserInfo getUserByUid(@Param("uid") int uid);
  1. 拦截器配置
    • 排除拦截
    • editor.md是个目录,要排除整个目录才对,不然后面渲染不上去,之前可以渲染是因为我们处于登录状态~
    • 因为详情页不需要登录~

在这里插入图片描述

4.4 前端代码

  1. 导航栏

在这里插入图片描述

  • 网页图标

在这里插入图片描述

  1. 右侧用户卡片

在这里插入图片描述

  1. 右侧文章信息

在这里插入图片描述

var aid = getParamValue("aid");
function init() {
    if (aid == null || aid <= 0) {
        alert("非法参数!");
        return false;
    }
    jQuery.ajax({
        method: "post",
        url: "/art/detail",
        contentType: "application/json; charset=utf8",
        data: JSON.stringify({
            id: aid,
        }),
        success: function (body) {
            if (body.code == 200) {
                // 1. 导航栏显示
                if (body.data.login == false) {
                    jQuery("#icon").attr("href", "img/logo2.png");
                    jQuery(".navigation img").attr("src", " img/logo2.png");
                    jQuery(".navigation .space").css("width", "75%");
                    jQuery(".title").text("未登录");
                    jQuery("#add").hide();
                    jQuery("#logout").text("登录");
                    jQuery("#logout").attr("href", "blog_login.html");
                }
                // 2. 文章数显示
                jQuery("#count").text(body.data.count);
                // 3. 用户信息显示
                jQuery(".card img").attr("src", body.data.user.photo);
                jQuery(".card h3").text(body.data.user.name);
                if (body.data.user.git.trim() != "") {
                    jQuery(".card a").attr("href", body.data.user.git);
                }
                // 4. 文章信息显示
                jQuery(".article h3").text(body.data.art.title);
                jQuery(".article .date").text(
                    body.data.art.createtime + " 阅读量:" + body.data.art.rcount
                );
                editormd.markdownToHTML("pc", {
                    markdown: body.data.art.content,
                });
            } else {
                alert("查看失败:" + body.msg);
            }
        },
    });
}
init();

4.5 测试

在这里插入图片描述


文章到此结束!谢谢观看
可以叫我 小马,我可能写的不好或者有错误,但是一起加油鸭🦆

代码:myblog_system/src · 游离态/马拉圈2023年9月 - 码云 - 开源中国 (gitee.com)


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

文件能做二维码吗?多种文件格式在线转二维码

怎么把文件做成二维码&#xff1f;在使用电脑办公时&#xff0c;必不可少的经常会使用word、excel、ppt等文件格式&#xff0c;那么当需要将文件生成二维码使用时&#xff0c;如何操作才能快速制作二维码呢&#xff1f;可以使用二维码生成器来在线制作二维码&#xff0c;与使用…

知识储备--基础算法篇-子串

1.子串 1.1第560题-和为k的子数组 给你一个整数数组 nums 和一个整数 k &#xff0c;请你统计并返回 该数组中和为 k 的连续子数组的个数 。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,1], k 2 输出&#xff1a;2 一开始想用滑动窗口&#xff0c;但是在运行过程中碰…

定时任务管理器(xxl-job)

文章目录 xxl-job简介安装使用拉取xxl-job项目导入数据库表启动 admin 服务端Spring Boot 整合 xxl-job修改执行器新建定时任务 xxl-job简介 XXL-JOB是一个分布式任务调度平台&#xff0c;其核心设计目标是开发迅速、学习简单、轻量级、易扩展。开箱即用。 admin &#xff1a;…

uni-app 可视化创建的项目 移动端安装调试插件vconsole

可视化创建的项目&#xff0c;在插件市场找不到vconsole插件了。 又不好npm install vconsole 换个思路&#xff0c;先创建一个cli脚手架脚手架的uni-app项目&#xff0c;然后再此项目上安装vconsole cli脚手架创建uni-app项目 安装插件 项目Terminal运行命令&#xff1a;npm…

商城开发:店铺管理系统应具备哪些功能?

电子商务的迅猛发展&#xff0c;越来越多的企业选择在线商城作为业务拓展的重要渠道。而要实现一个成功的在线商城&#xff0c;一个强大而高效的店铺管理系统是不可或缺的。店铺管理系统作为商城的核心管理工具&#xff0c;应具备一系列功能&#xff0c;以提供卓越的用户体验和…

游戏海外运营需要准备什么?

游戏海外运营需要充分的准备和计划&#xff0c;以确保游戏在目标市场中取得成功。以下是一些游戏海外运营需要准备的关键方面。 游戏平台 游戏出海必不可少的就是游戏平台&#xff0c;而且要注意的是&#xff0c;海外游戏平台的搭建和国内有所不同&#xff0c;对于支付方式和语…

zabbix监控网络设备和zabbix proxy

监控linux主机 [rootrocky8 conf]# yum -y install net-snmp vim /etc/snmp/snmpd.conf com2sec notConfigUser default 123456##修改此行,设置团体密码,默认为public,此处 改为123456 view systemview included .1. ##添加此行,自定义授权,否则 zabbix 无法获取数据 [rootr…

【Redis】NoSQL之Redis的配置及优化

关系数据库与非关系数据库 关系型数据库 关系型数据库是一个结构化的数据库&#xff0c;创建在关系模型&#xff08;二维表格模型&#xff09;基础上&#xff0c;一般面向于记录。 SQL 语句&#xff08;标准数据查询语言&#xff09;就是一种基于关系型数据库的语言&a…

websocket--技术文档--spring后台+vue基本使用

阿丹: 给大家分享一个可以用来进行测试websocket的网页&#xff0c;个人觉得还是挺好用的. WebSocket在线测试工具 还有一个小家伙ApiPost也可以进行使用websocket的测试。 本文章只是基本使用--给大家提供思路简单实现&#xff01;&#xff01; 使用spring-boot建立一个服…

SNI代理与DNS解析相结合

在当今互联网时代&#xff0c;加密通信已成为保护用户隐私和数据安全的重要手段。而使用HTTPS协议进行加密传输更是日益普及。然而&#xff0c;在构建一个高效且灵活的HTTPS代理服务器时&#xff0c;我们常常面临着一些挑战。 针对这个问题&#xff0c;引入SNI&#xff08;Ser…

关于在本地启动跨域非nodejs的前后端分离项目

目前的前后端分离&#xff0c;dev开发模式下&#xff0c;本地启动时会首先启动一个nodejs作为服务器&#xff0c;把本地网页启动起来&#xff0c;同时对后端的接口请求&#xff0c;可以经过proxy来实现&#xff0c;从而避免了浏览器的跨域检查。 但是有些陈旧的基于jquerylayu…

【LeetCode-中等题】46. 全排列

文章目录 题目方法一&#xff1a;递归回溯 题目 这题中nums中的数各不相同&#xff0c;所以不需要去重&#xff1a; 而下面这题&#xff0c;nums中的数会存在重复值&#xff0c;就需要去重&#xff1a; 方法一&#xff1a;递归回溯 关键在于递归之后还要还原做回溯动作&#…

ToBeWritten之威胁狩猎

也许每个人出生的时候都以为这世界都是为他一个人而存在的&#xff0c;当他发现自己错的时候&#xff0c;他便开始长大 少走了弯路&#xff0c;也就错过了风景&#xff0c;无论如何&#xff0c;感谢经历 转移发布平台通知&#xff1a;将不再在CSDN博客发布新文章&#xff0c;敬…

高并发下机器QPS计算、最佳线程数计算

一、QPS&#xff0c;每秒查询 QPS&#xff1a;Queries Per Second意思是“每秒查询率”&#xff0c;是一台服务器每秒能够相应的查询次数&#xff0c;是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。互联网中&#xff0c;作为域名系统服务器的机器的性能经常…

macos13 arm芯片(m2) 搭建hbase docker容器 并用flink通过自定义richSinkFunction写入数据到hbase

搭建hbase docker容器 下载镜像 https://hub.docker.com/r/satoshiyamamoto/hbase/tags 点击run 使用镜像新建容器 填写容器名和 容器与宿主机的端口映射 测试 通过宿主机访问容器内的hbase webUI http://localhost:60010/master-status

WINGREEN 03ZSTI4-00-501

中央处理单元&#xff08;CPU&#xff09;支持&#xff1a;WINGREEN 03ZSTI4-00-501 控制主板模块可能配备了一个或多个CPU核心&#xff0c;用于处理数据和执行指令。 内存支持&#xff1a; 它可以支持系统内存&#xff08;RAM&#xff09;&#xff0c;以存储和访问数据。 输…

C语言共用体详解

文章目录 共用体解释代码说明小端存储 Little Endian共用体与小端存储为什么只能用第一个成员类型的值初始化一个共用体变量 共用体解释 共用体&#xff08;Union&#xff09;是一种特殊的数据类型&#xff0c; 它允许在同一个内存位置存储不同的数据类型。 共用体的所有成员共…

ICCOA蓝牙数字车钥匙2.0

近期&#xff0c;ICCOA智慧车联开放联盟宣布&#xff0c;由小米、vivo、OPPO、长安、深蓝、吉利、极氪、比亚迪、北汽、蔚来、零跑、雪球、瓶钵、融卡等企业联合参与制定的ICCOA蓝牙数字车钥匙2.0标准&#xff08;简称DK2.0&#xff09;&#xff0c;于2023年9月1日正式发布实施…

【网络编程·数据链路层】MAC帧/以太网协议/ARP协议/RARP协议

需要云服务器等云产品来学习Linux的同学可以移步/-->腾讯云<--/-->阿里云<--/-->华为云<--/官网&#xff0c;轻量型云服务器低至112元/年&#xff0c;新用户首次下单享超低折扣。 目录 一、MAC帧 1、IP地址和MAC地址的区别 2、MAC帧协议 3、MTU对IP协议的…

Python 3.x标准数据类型

文章目录 一、数字1.1 基本的数字类型有:1.2 整数数字表示方式二、字符串2.1 操作符2.2 格式化百分号format 格式化输出位置匹配2.3 字符串 索引和切片2.4 切片:字符串 [ 起始索引:终止索引:步长 ]字符串连接操作三、列表3.1 列表的定义3.2 常用方法(功能:增删改查)增删除…