博客系统-SpringBoot版本

news2024/10/6 18:35:19

相比于之前使用Servlet来完成的博客系统,SpringBoot版本的博客系统功能更完善,使用到的技术更接近企业级,快来看看吧~

目录

1.项目介绍

2.数据库准备

3.实体化类

4.返回格式

5.登录和注册功能

6.登出(注销)功能

7.判定是否登录

8.添加、修改、查询、删除文章

9.查询文章列表、分页、展示阅读次数

查询文章列表

展示阅读次数

分页功能

10.拦截器

11.统一异常处理和统一数据返回格式

统一异常处理

统一数据返回格式

12.加盐处理


1.项目介绍

本项目集成了用户注册、用户登录、用户登出(注销)、验证登录状态、添加文章、查询文章、修改文章、展示阅读次数、文章列表查询、删除文章、分页功能。

其中,使用了统一功能处理返回的数据,对密码进行了加盐加密操作,使用拦截器完成验证用户登录状态。

并且使用分层思想:

2.数据库准备

-- 创建数据库
drop database if exists mycnblog;
create database mycnblog DEFAULT CHARACTER SET utf8mb4;

-- 使用数据数据
use mycnblog;

-- 创建表[用户表]
drop table if exists  userinfo;
create table userinfo(
    id int primary key auto_increment,
    username varchar(100) not null,
    password varchar(65) not null,
    photo varchar(500) default '',
    createtime timestamp default current_timestamp,
    updatetime timestamp default current_timestamp,
    `state` int default 1
) default charset 'utf8mb4';

-- 创建文章表
drop table if exists  articleinfo;
create table articleinfo(
    id int primary key auto_increment,
    title varchar(100) not null,
    content text not null,
    createtime timestamp default current_timestamp,
    updatetime timestamp default current_timestamp,
    uid int not null,
    rcount int not null default 1,
    `state` int default 1
)default charset 'utf8mb4';


-- 添加一个用户信息
INSERT INTO `mycnblog`.`userinfo` (`id`, `username`, `password`, `photo`, `createtime`, `updatetime`, `state`) VALUES 
(1, 'admin', 'admin', '', '2024-2-12 17:10:48', '2024-2-12 17:10:48', 1);

-- 文章添加测试数据
insert into articleinfo(title,content,uid)
    values('Java','Java正文',1);
    

3.实体化类

在createtime和updatetime之前加上时间格式化注释JsonFormat,可以统一时间格式。

4.返回格式

在和前端进行交互的时候,我们新建一个类来完成对所有返回的结果的规定。

包括了返回的状态码code,返回的信息msg,返回的数据data。并且重载success和fail方法。

每个controller返回给前端的数据就是一个AjaxResult success()或者AjaxResult fail();

@Data
public class AjaxResult implements Serializable {
    private Integer code;
    private String msg;
    private Object data;

    public static AjaxResult success(Object data) {
        AjaxResult ajaxResult = new AjaxResult();
        ajaxResult.setCode(200);
        ajaxResult.setMsg("");
        ajaxResult.setData(data);
        return ajaxResult;
    }

    public static AjaxResult success(Object data, String msg) {
        AjaxResult ajaxResult = new AjaxResult();
        ajaxResult.setCode(200);
        ajaxResult.setMsg(msg);
        ajaxResult.setData(data);
        return ajaxResult;
    }

    public static AjaxResult fail(Integer code, String msg) {
        AjaxResult ajaxResult = new AjaxResult();
        ajaxResult.setCode(code);
        ajaxResult.setMsg(msg);
        ajaxResult.setData("");
        return ajaxResult;
    }

    public static AjaxResult fail(Integer code, String msg, Object data) {
        AjaxResult ajaxResult = new AjaxResult();
        ajaxResult.setCode(code);
        ajaxResult.setMsg(msg);
        ajaxResult.setData(data);
        return ajaxResult;
    }
}

5.登录和注册功能

    <insert id="reg">
        insert into userinfo(username, password) value (#{username},#{password})
    </insert>

    <select id="login" resultType="com.example.spring_myblogsystem.entity.UserInfo">
        select * from userinfo
        where username = #{username}
    </select>
@Mapper
public interface UserMapper {
    int reg(UserInfo userInfo);

    UserInfo login(@Param("username") String username);
}
@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    public int reg(UserInfo userInfo) {
        return userMapper.reg(userInfo);
    }

    public UserInfo login(String username) {
        return userMapper.login(username);
    }
}

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/reg")
    public AjaxResult reg(UserInfo userInfo) {
        if (userInfo == null || !StringUtils.hasLength(userInfo.getUsername()) || !StringUtils.hasLength(userInfo.getUsername())) {
            return AjaxResult.fail(-1, "参数非法");
        }
        userInfo.setPassword(PasswordTooles.encrypt(userInfo.getPassword()));
        int result = userService.reg(userInfo);
        return AjaxResult.success(result);
    }

    @RequestMapping("/login")
    public AjaxResult login(String username, String password, HttpServletRequest request) {
        if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password)) {
            return AjaxResult.fail(-1, "参数非法");
        }
        UserInfo userInfo = userService.login(username);
        if (userInfo == null || userInfo.getId() <= 0) {
            return AjaxResult.fail(-2, "用户名或密码错误");
        }
        if (PasswordTooles.decrypt(password, userInfo.getPassword())) {
            return AjaxResult.fail(-2, "用户名或密码错误");
        }
        HttpSession session = request.getSession();
        session.setAttribute(ApplicationVariale.SESSION_USERINFO_KEY,userInfo);
        return AjaxResult.success(1);
    }

在登录过程中,用到了session来判定登录状态,所以在传形参的时候,不光是要传用户名和密码,还需要把request也一起传输过去,用来设置当前session。因为session有多个地方需要使用,所以把session单独拿出来定义:

public class ApplicationVariale {
    public static final String SESSION_USERINFO_KEY = "SESSION_KEY_USERINFO";

}

6.登出(注销)功能

只需要使用removeAttribute来移除session就可以实现注销功能。

    @RequestMapping("/logout")
    public AjaxResult logout(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        session.removeAttribute(ApplicationVariale.SESSION_USERINFO_KEY);
        return AjaxResult.success(1);
    }

7.判定是否登录

在某些页面,需要判定用户是否登录了,比如在博客正文的页面,就需要根据用户登录情况来显示不同的按钮。未登录则显示登录按钮,已经登录了则显示博客主页按钮。

    @RequestMapping("/islogin")
    public AjaxResult isLogin(HttpServletRequest request) {
        if (UserSessionTools.getLoginUser(request) == null) {
            return AjaxResult.success(0);
        }
        return AjaxResult.success(1);
    }

并且因为判定登录功能可能会多次使用到,所以把相关的功能写到common中,方便调用。传递的参数是request,用来判定当前session的情况。

public class UserSessionTools {
    public static UserInfo getLoginUser(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session != null && session.getAttribute(ApplicationVariale.SESSION_USERINFO_KEY) != null) {
            return (UserInfo) session.getAttribute(ApplicationVariale.SESSION_USERINFO_KEY);
        }
        return null;
    }
}

8.添加、修改、查询、删除文章

    <insert id="add">
        insert into articleinfo(title,content,uid)
        values(#{title},#{content},#{uid})
    </insert>
    <update id="update">
        update articleinfo set title=#{title},content=#{content},updatetime=#{updatetime}
        where id=#{id} and uid=#{uid}
    </update>

    <select id="getDetailByIdAndUid" resultType="com.example.spring_myblogsystem.entity.ArticleInfo">
        select * from articleinfo where id=#{id} and uid=#{uid}
    </select>

    <delete id="del">
        delete from articleinfo where id = #{id} and uid = #{uid}
    </delete>
@Mapper
public interface ArticleMapper {
    int add(ArticleInfo articleInfo);
    ArticleInfo getDetailByIdAndUid(@Param("id")Integer id,@Param("uid")Integer uid);
    int update(ArticleInfo articleInfo);
    int del(@Param("id") Integer id, @Param("uid") Integer uid);
@Service
public class ArticleService {
    @Autowired
    private ArticleMapper articleMapper;
    public int add(ArticleInfo articleInfo){
        return articleMapper.add(articleInfo);
    }
    public ArticleInfo getDetailByIdAndUid(Integer id,Integer uid){
        return articleMapper.getDetailByIdAndUid(id,uid);
    }
    public int update(ArticleInfo articleInfo){
        return articleMapper.update(articleInfo);
    }

    public int del(Integer id, Integer uid) {
        return articleMapper.del(id, uid);
    }
@RestController
@RequestMapping("/art")
public class ArticleController {
    @Autowired
    private ArticleService articleService;

    @RequestMapping("/add")
    public AjaxResult add(ArticleInfo articleInfo, HttpServletRequest request){
        if (articleInfo == null ||
                !StringUtils.hasLength(articleInfo.getTitle()) ||
                !StringUtils.hasLength(articleInfo.getContent())){
            return AjaxResult.fail(-1,"参数异常");
        }
        UserInfo userInfo = UserSessionTools.getLoginUser(request);
        articleInfo.setUid(userInfo.getId());
        int result = articleService.add(articleInfo);
        return AjaxResult.success(result);
    }

    @RequestMapping("/getdetailbyid")
    public AjaxResult getDetailByIdAndUid(Integer id,HttpServletRequest request){
        if(id == null || id <=0){
            return AjaxResult.fail(-1,"参数非法");
        }
        UserInfo userInfo = UserSessionTools.getLoginUser(request);
        return AjaxResult.success(articleService.getDetailByIdAndUid(id, userInfo.getId()));
    }

    @RequestMapping("/update")
    public AjaxResult update(ArticleInfo articleInfo,HttpServletRequest request){
        if(articleInfo == null || articleInfo.getId() <= 0 || !StringUtils.hasLength(articleInfo.getContent()) || !StringUtils.hasLength(articleInfo.getTitle())){
            return AjaxResult.fail(-1,"参数有误");
        }
        UserInfo userInfo = UserSessionTools.getLoginUser(request);
        articleInfo.setUid(userInfo.getId());
        articleInfo.setUpdatetime(userInfo.getUpdatetime());
        return AjaxResult.success(articleService.update(articleInfo));
    }

    @RequestMapping("/del")
    public AjaxResult del(Integer id, HttpServletRequest request) {
        if (id == null || id <= 0) {
            return AjaxResult.fail(-1, "参数错误");
        }
        UserInfo userInfo = UserSessionTools.getLoginUser(request);
        int result = articleService.del(id, userInfo.getId());
        return AjaxResult.success(result);
    }

可以看到,几乎所有的方法都是先对传入的参数进行非空校验,再对session的情况进行判定。实现都很简单。

在getDetailByIdAndUid和del中,一次性传入了文章id和uid。这是为了校验当前查看文章的用户是文章的作者,只有这种情况才能够对文章进行后续的修改和删除。

9.查询文章列表、分页、展示阅读次数

相比于前面的增删查改操作来说,这个部分要复杂很多。

查询文章列表

    <select id="getListByUid" resultType="com.example.spring_myblogsystem.entity.ArticleInfo">
        select * from articleinfo
        where uid = #{uid}
        order by id desc;
    </select>
List<ArticleInfo> getListByUid(@Param("uid") Integer id);
public List<ArticleInfo> getListByUid(Integer id) {
        return articleMapper.getListByUid(id);
    }
    @RequestMapping("/mylist")
    public AjaxResult mylist(HttpServletRequest request) {
        UserInfo userInfo = UserSessionTools.getLoginUser(request);
        List<ArticleInfo> list = articleService.getListByUid(userInfo.getId());
        //todo:将文章正文截取成文章摘要
        for (ArticleInfo item : list) {
            String content = StringTools.subLength(item.getContent(), 200);
            item.setContent(content);
        }
        return AjaxResult.success(list);
    }

展示阅读次数

定义一个先rcount变量,记录文章的阅读次数。先做查询操作,等前面页面刷新时,rcount自增1并且存储到数据库中。

    <update id="addRcount">
        update articleinfo
        set rcount=rcount + 1
        where id = #{id}
    </update>
    public Integer getCount() {
        return articleMapper.getCount();
    }
    @RequestMapping("/getcount")
    public AjaxResult getCount() {
        return AjaxResult.success(articleService.getCount());
    }

分页功能

分页功能也就是实现这四个功能。

我们先定义几个变量:

  • pageIndex:记录页面当前的页码(从1开始)
  • pageSize:记录每页最大条数
  • pageCount:记录总页数
  • offset:数据库中从第几条开始查询

首页功能很好实现,规定当前页码是1,offset只需要是0开始就行了。

当设置pageSize为2时,总页数和offset都可以被算出来。同时需要再数据库中查询两次,一次是根据相关的参数查询文章,另一次是查询一共有多少条文章。

    <select id="getListByPage" resultType="com.example.spring_myblogsystem.entity.ArticleInfo">
        select * from articleinfo
        order by id desc
        limit #{pageSize} offset #{offset}
    </select>    

    <select id="getCount" resultType="java.lang.Integer">
        select count(id)
        from articleinfo
    </select>

例如当前是第一页,查询的文章为从第0条开始查询,当前页码为1,offset为0。

如果到了第二页,查询的文章从第2条开始查询,当前页码为1,offset为2。

也就是说,offset有如下公式:offset = (pageIndex - 1)× pageSize 

    @RequestMapping("/getlistbypage")
    public AjaxResult getListByPage(Integer pageSize, Integer pageIndex) {
        if (pageSize == null || pageSize == 0) {
            pageSize = 2;
        }
        if (pageIndex == null || pageIndex <= 1) {
            pageIndex = 1;
        }
        int offset = (pageIndex - 1) * pageSize;
        List<ArticleInfo> list = articleService.getListByPage(pageSize, offset);
        list.stream().parallel().forEach((item -> {
            item.setContent(StringTools.subLength(item.getContent(), 150));
        }));
        return AjaxResult.success(list);
    }

同时用一个list来存储相关的文章,通过list.stream.forEach来遍历,并且可以使用parallel()多线程处理,效率更快。

处理完了首页、上一页和下一页,末页需要用到getCount,获取到一共有多少条文章,然后再根据这个数字来判定总页数,通过getCount/pageSize就可以得到。得到总页数后,再传回数据库查询,得到末页的文章。

10.拦截器

虽然前面已经对session做了判定,判断用户是否登录,但是我们用一个统一的拦截器来完成对代码的过滤等等。

比如在登入一个页面时,如果要求用户密码、权限等的验证,就可以用自定义的拦截器进行密码验证和权限限制。对符合的登入者才跳转到正确页面。这样如果有新增权限的话,不用在controller里修改任何代码,直接在interceptor里修改就行了。

Spring中的拦截器是通过动态代理的方式实现和环绕通知的方式实现的,并且是作用域controller之前,先把相关的请求预处理完,再进行程序的正常流程。

@Configuration
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession(false);
        if (session != null && session.getAttribute(ApplicationVariale.SESSION_USERINFO_KEY) != null) {
            return true;
        }
        response.sendRedirect("/login.html");
        return false;
    }
}

需要实现一个LoginInterceptor并且implements HandlerInterceptor

重写preHandle方法,来判定用户是否登录的功能,并且把需要登录才能访问的内容添加到MyConfig中。

首先添加所有的路径,然后把不需要的路径排除掉,就是拦截器拦截的内容。简单的理解为,用户需要登录才能够访问的内容都被拦截器拦截了,不需要登录就能够访问的则不添加到拦截器中。

11.统一异常处理和统一数据返回格式

统一异常处理

对于异常处理来说,最简单直接的方式就是使用 try catch 代码块来捕获系统异常。但是这种处理方式需要我们编写大量的代码,而且异常信息不易于统一维护,增加了开发工作量,甚至可能还会出现异常没有被捕获的情况。为了能够高效的处理好各种系统异常,我们需要在项目中统一集中处理我们的异常。

@RestControllerAdvice
public class MyExceptionAdvice {
    @ExceptionHandler(Exception.class)
    public AjaxResult doException(Exception e) {
        return AjaxResult.fail(-1, e.getMessage());
    }
}

@ControllerAdvice 表示控制器通知类,@ExceptionHandler 是异常处理器,两个结合表示当出现异常的时候执行某个通知, 也就是执行某个方法事件。

统一数据返回格式

在所有的controller中,我们返回给前端的都是一个AjaxResult对象,也就是包含了code、msg、data三个属性的变量。但是如果某个controller中返回的是错误的,假设返回的是1,那么就会出现错误。我们可以规定统一返回的一种格式,有助于帮助前后端程序员沟通。

//统一返回数据格式的封装
//当返回的数据不是AjaxResult的时候转换成AjaxResult
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
    @Autowired
    private ObjectMapper objectMapper;

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

    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body instanceof AjaxResult) {
            return body;
        }
        if (body instanceof String) {
            return objectMapper.writeValueAsString(AjaxResult.success(body));
        }
        return null;
    }
}

统⼀的数据返回格式可以使用 @ControllerAdvice + ResponseBodyAdvice 的方式实现。

12.加盐处理

用户输入的密码到数据库中时,非常不安全,很容易被破解。所以当我们储存到数据库中时,最好存储的是加密的密码。所以我们在服务器中需要完成对密码的加密。通过加盐的方式来处理。

密码如何加盐加密?icon-default.png?t=N7T8http://t.csdnimg.cn/9q7lU

public class PasswordTooles {
    public static String encrypt(String password) {
        //产生盐值
        String salt = UUID.randomUUID().toString().replace("-", "");
        //使用盐值+明文密码得到加密的密码
        String finalPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes());
        //将盐值和加密的密码共同返回
        String dbPassword = salt + "$" + finalPassword;
        return dbPassword;
    }

    //验证加盐加密密码
    public static boolean decrypt(String password, String dbPassword) {
        boolean result = false;
        if (StringUtils.hasLength(password) && StringUtils.hasLength(dbPassword) && dbPassword.length() == 65 && dbPassword.contains("$")) {
            String[] passwordArr = dbPassword.split("\\$");
            String salt = passwordArr[0];
            String checkPassword = encrypt(password);
            if (dbPassword.equals(checkPassword)) {
                result = true;
            }
        }
        return result;
    }
}

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

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

相关文章

【Rust】使用Rust实现一个简单的shell

一、Rust Rust是一门系统编程语言&#xff0c;由Mozilla开发并开源&#xff0c;专注于安全、速度和并发性。它的主要目标是解决传统系统编程语言&#xff08;如C和C&#xff09;中常见的内存安全和并发问题&#xff0c;同时保持高性能和底层控制能力。 Rust的特点包括&#x…

一周学会Django5 Python Web开发-Django5操作命令

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计11条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…

2024年P气瓶充装证模拟考试题库及P气瓶充装理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年P气瓶充装证模拟考试题库及P气瓶充装理论考试试题是由安全生产模拟考试一点通提供&#xff0c;P气瓶充装证模拟考试题库是根据P气瓶充装最新版教材&#xff0c;P气瓶充装大纲整理而成&#xff08;含2024年P气瓶…

单例模式:懒汉饿汉线程安全问题

在我们前几篇文章中都了解了一些关于线程的知识&#xff0c;那么在多线程的情况下如何创建单例模式&#xff0c;其中的线程安全问题如何解决&#xff1f; 目录 1.什么是单例模式&#xff1f; (饿汉模式) 2.单例模式(懒汉模式) *懒汉模式与懒汉模式的对比 *如何解决懒汉模式…

VTK 正交投影 透视投影

1.VTK默认透视投影&#xff08;近大远小&#xff09;&#xff1b; 1.调用vtkCamera的ParallelProjectionOn函数开启 2.通过vtkCamera的SetParallelScale缩放 3.通过vtkCamera的SetClippingRange设置前后裁剪平面 2.正交投影&#xff08;平行投影&#xff0c;远近一样&#xf…

Netty Review - NioEventLoopGroup源码解析

文章目录 概述类继承关系源码分析小结 概述 EventLoopGroup bossGroup new NioEventLoopGroup(1); EventLoopGroup workerGroup new NioEventLoopGroup();这段代码是在使用Netty框架时常见的用法&#xff0c;用于创建两个不同的EventLoopGroup实例&#xff0c;一个用于处理连…

Linux第51步_移植ST公司的linux内核第3步_添加修改设备树

1、设备树文件的路径 1)、创建linux中的设备树头文件 在“my_linux/linux-5.4.31/arch/arm/boot/dts/”目录中&#xff0c;以“stm32mp15xx-edx.dtsi”为蓝本&#xff0c;复制一份&#xff0c;并命名为 “stm32mp157d-atk.dtsi”&#xff0c;这就是我们开发板的设备树头文件。…

【DDD】学习笔记-四色建模法

或许正是认识到彩色 UML 在建模过程的不足之处&#xff0c;ThoughtWorks 的徐昊才在彩色 UML 基础之上提出了自己的“四色建模法”。可考的四色建模法资料仅见于徐昊在 InfoQ 上发表的文章运用四色建模法进行领域分析。在这篇文章中&#xff0c;徐昊回答了建模活动的一个关键问…

【开源】基于JAVA+Vue+SpringBoot的房屋出售出租系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 房屋销售模块2.2 房屋出租模块2.3 预定意向模块2.4 交易订单模块 三、系统展示四、核心代码4.1 查询房屋求租单4.2 查询卖家的房屋求购单4.3 出租意向预定4.4 出租单支付4.5 查询买家房屋销售交易单 五、免责说明 一、摘…

Kafka 之生产者(Producer)

目录 一. 前言 二. 生产消息 三. 幂等和事务 四. send() 发送消息 五. 原理解析 一. 前言 Kafka生产者是一个应用程序&#xff0c;它负责向 Kafka 主题发送消息。这些消息可以用于多种目的&#xff0c;如记录用户活动、收集物联网设备数据、保存日志消息或缓存即将写入数据…

《乱弹篇(十四)香火旺》

连日来&#xff0c;“大年初一烧香祈福&#xff0c;北京雍和宫人山人海”这一词条登上社交网站热搜&#xff0c;对这一现象的描述多为“初一凌晨 民众在雍和宫前排大队”&#xff0c;“大年初一&#xff0c;雍和宫内人山人海&#xff0c;烟雾缭绕”&#xff0c;“雍和宫迎来6万…

Asp .Net Core 系列:Asp .Net Core 集成 NLog

简介 NLog是一个基于.NET平台编写的日志记录类库&#xff0c;它可以在应用程序中添加跟踪调试代码&#xff0c;以便在开发、测试和生产环境中对程序进行监控和故障排除。NLog具有简单、灵活和易于配置的特点&#xff0c;支持在任何一种.NET语言中输出带有上下文的调试诊断信息…

三、案例 - MySQL数据迁移至ClickHouse

MySQL数据迁移至ClickHouse 一、生成测试数据表和数据1.在MySQL创建数据表和数据2.在ClickHouse创建数据表 二、生成模板文件1.模板文件内容2.模板文件参数详解2.1 全局设置2.2 数据读取&#xff08;Reader&#xff09;2.3 数据写入&#xff08;Writer&#xff09;2.4 性能设置…

ctfshow-文件上传(web151-web161)

目录 web151 web152 web153 web154 web155 web156 web157 web158 web159 web160 web161 web151 提示前台验证不可靠 那限制条件估计就是在前端设置的 上传php小马后 弹出了窗口说不支持的格式 查看源码 这一条很关键 这种不懂直接ai搜 意思就是限制了上传类型 允许…

计算机组成原理 1 概论

主要内容 介绍运算器、控制器、存储器结构、工作原理、设计方法及互连构成整机的技术。 主要内容&#xff1a; ◼ 数值表示与运算方法 ◼ 运算器的功能、组成和基本运行原理 ◼ 存储器及层次存储系统 ◼ 指令系统 ◼ CPU功能、组成和运行原理 ◼ 流水线 ◼ 系统总线 ◼ 输入输出…

UE5 播放本地MP3、MP4

1.创建一个媒体播放器 2.如创建视频&#xff0c;勾选。 它会多一个媒体纹理给你 3.1 设置音频 在一个actor上添加“媒体音频组件” “音频媒体播放器”赋值给它 3.2播放音频 添加一个音频媒体播放器变量&#xff0c; 赋值 地址使用绝对地址 4.1设置视频 UI上创建一个imag…

快速学习Spring

Spring 简介 Spring 是一个开源的轻量级、非侵入式的 JavaEE 框架&#xff0c;它为企业级 Java 应用提供了全面的基础设施支持。Spring 的设计目标是简化企业应用的开发&#xff0c;并解决 Java 开发中常见的复杂性和低效率问题。 Spring常用依赖 <dependencies><!-…

Linux:信号的处理

文章目录 信号处理 本篇总结的是关于信号的处理 信号处理 在之前有这样的观点&#xff1a;信号在合适的时候被处理好&#xff0c;当进程收到信号后&#xff0c;当前进程可能在做优先级更高的事&#xff0c;所以它来不及处理这个信号&#xff0c;那么就会把这个信号暂时保存起…

spring aop @annotation的用法

直接看原文: spring aop annotation的用法-CSDN博客 -------------------------------------------------------------------------------------------------------------------------------- annotation用在定义连接点时&#xff0c;对连接点进行限制。比如我们想对标注了…

双非本科准备秋招(18.2)—— 图解Monitor

对象头 普通对象&#xff1a; 数组对象&#xff1a; java中对象存储结构分为对象头&#xff08;Header&#xff09;、实例数据&#xff08;Instance Date&#xff09;和对齐填充&#xff08;Padding&#xff09;。 对象头存储着Mark Word和Klass Word&#xff0c;通过Klass Wo…