博客系统-SpringBoot版本

相比于之前使用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;
    }
}

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

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

相关文章

【Python】Python代码的单元测试

Python代码的单元测试 单元测试的概念 定义&#xff1a;是指对软件中的最小可测试单元进行检查和验证。 作用&#xff1a;可以确保程序模块是否否和我们规范的输出&#xff0c;保证该模块经过修改后仍然是满足我们的需求。 单元测试的策略 如果要创建单元测试&#xff0c;…

C语言-----用二维数组解决菱形的打印问题

1.打印菱形&#xff0c;多组输入&#xff0c;一个整数&#xff08;2~20&#xff09;&#xff0c;表示输出的行数&#xff0c;也表示组成“X”的反斜线和正斜线的长度。 #include <stdio.h>int main() {int n0;while(scanf("%d",&n)! EOF){int i0;int j0;f…

初识webpack(二)解析resolve、插件plugins、dev-server

目录 (一)webpack的解析(resolve) 1.resovle.alias 2.resolve.extensions 3.resolve.mainFiles (二) plugin插件 1.CleanWebpackPlugin 2.HtmlWebpackPlugin 3.DefinePlugin (三)webpack-dev-server 1.开启本地服务器 2.HMR模块热替换 3.devServer的更多配置项 (…

.NET高级面试指南专题七【SocketWebSocket】

Socket&#xff08;套接字&#xff09;是一种在计算机网络中实现通信的一种机制&#xff0c;它提供了一种标准的接口&#xff0c;使不同计算机上的程序能够通过网络进行数据交换。Socket允许在网络中的不同设备之间建立连接&#xff0c;进行双向的数据传输。 Socket通常用于实现…

Map和Set(哈希表)

目录 map&#xff1a; map说明&#xff1a; Map.Entry的说明&#xff1a;,v> Map 的常用方法: 演示&#xff1a; 注意&#xff1a; TreeMap和HashMap的区别 Set&#xff1a; 常见方法说明&#xff1a; 注意&#xff1a; TreeSet和HashSet的区别 哈希表: 冲突&a…

FileZilla Server 1.8.1内网搭建

配置环境服务器服务器下载服务器配置服务器配置 Server - ConfigureServer Listeners - Port 协议设置 Protocols settingsFTP and FTP over TLS(FTPS) Rights management(权利管理)Users(用户) 客户端建立连接 配置环境 服务器处于局域网内: 客户端 < -访问- > 公网 &l…

车载软件架构 —— Adaptive AUTOSAR软件架构

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师&#xff08;Wechat&#xff1a;gongkenan2013&#xff09;。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 本就是小人物&#xff0c;输了就是输了&#…

寒假思维训练day21

今天更新一道不错的状态压缩DP题&#xff0c;顺带总结一下状态压缩DP。 摘要&#xff1a; Part1 浅谈状态压缩DP的理解 Part2 浅谈对状态机DP的理解 Part3 关于状态压缩DP的1道例题 Part1 状态压缩DP 1、状态压缩DP&#xff1a; 事物的状态可能包含多个特征&#xff0c;…

linuxqq关闭主面板后无法再次打开的问题

文章目录 前言解决方案强调一点 前言 听说QQ出了linux版&#xff0c;所以来试试。结果试试就逝世。这次记录一个关闭后没办法打开的解决办法。 解决方案 刚安装好后如果点了关闭&#xff0c;系统托盘里也没有&#xff0c;点击图标又是重新登录。当然&#xff0c;我们最简单、…

浅谈Linux环境

冯诺依曼体系结构&#xff1a; 绝大多数的计算机都遵守冯诺依曼体系结构 在冯诺依曼体系结构下各个硬件相互配合处理数据并反馈结果给用户 其中控制器和运算器统称为中央处理器&#xff08;CPU&#xff09;&#xff0c;是计算机硬件中最核心的部分&#xff0c;像人类的大脑操控…

钓鱼邮件的发送工具GUI

一.简介 本程序利用Python语言编写&#xff0c;使用Tkinter实现图形化界面&#xff0c;可使用Pyinstaller进行exe打包&#xff0c;程序主界面截图如下&#xff1a; 二.功能 1.支持腾讯企业邮、网易企业邮、阿里企业邮、自建邮服SMTP授权账号&#xff08;其他邮服&#xff0c…

【HTML】交友软件上照片的遮罩是如何做的

笑谈 我不知道大家有没有在夜深人静的时候感受到孤苦难耐&#xff0c;&#x1f436;。于是就去下了一些交友软件来排遣寂寞。可惜的是&#xff0c;有些交友软件真不够意思&#xff0c;连一些漂亮小姐姐的图片都要进行遮罩&#xff0c;完全不考虑兄弟们的感受,&#x1f620;。所…

微信小程序(四十一)wechat-http的使用

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.模块下载 2.模块的使用 在终端输入npm install wechat-http 没有安装成功vue的先看之前的一篇 微信小程序&#xff08;二十&#xff09;Vant组件库的配置- 如果按以上的成功配置出现如下报错先输入以下语句 …

知识价值2-什么是IDE?新手用哪个IDE比较好?

IDE是集成开发环境&#xff08;Integrated Development Environment&#xff09;的缩写&#xff0c;是一种软件应用程序&#xff0c;旨在提供集成的工具集&#xff0c;以方便开发人员进行软件开发。IDE通常包括代码编辑器、编译器、调试器和其他工具&#xff0c;以支持软件开发…

crack实验

资源下载 【免费】crack资源&#xff08;这玩意还要不少于11字&#xff09;资源-CSDN文库 内容 源码 这是一段简单的密码判断程序 流程 exe直接用ida开&#xff08;因该是release的exe&#xff09; 选中分支点直接按空格 此时的va地址是0010106e用动态调试软件调试&#xf…

微信小程序学习指南:从基础知识到代码展示

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

软件实例分享,宠物店兽医电子处方开单系统软件教程

软件实例分享&#xff0c;宠物店兽医电子处方开单系统软件教程 一、软件教程问答 以下教程以 佳易王宠物店兽医电子处方软件V16.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 问&#xff1a;宠物医院电子处方单子使用的纸张大小是多少&…

Screw自动生成数据库文档

Screw简介 官方地址 Screw可以根据数据库中的表自动生成HTML、Word、Markdown格式的文档。 Springboot 3.1集成 生成Springboot项目 Spring Initializr Maven依赖 <dependency><groupId>cn.smallbun.screw</groupId><artifactId>screw-core</…

GPT4:画一只小怪兽,但是不断升级

请你画一只1级的萌怪兽 请你画一只3级的萌怪兽 请你画一只5级的小怪兽 请你画一只10级的小怪兽 请你画一只50级的怪兽 请你画一只100级的怪兽 怪兽被闪电劈了一下&#xff0c;变成了一只0.1级的可爱小怪兽

JAVA-多进程开发-创建等待进程

前言 在项目中&#xff0c;为了实现“并发编程”&#xff08;同时执行多个任务&#xff09;&#xff0c;就引入了“多进程编程”&#xff0c;把一个很大的任务&#xff0c;拆分成若干个很小的任务&#xff0c;创建多个进程&#xff0c;每个进程分别负责其中的一部分任务。 这也…