【Spring Boot】分层开发 Web 应用程序(含实例)

news2024/9/21 2:40:32

分层开发 Web 应用程序

  • 1.应用程序分层开发模式:MVC
    • 1.1 了解 MVC 模式
    • 1.2 MVC 和三层架构的关系
  • 2.视图技术 Thymeleaf
  • 3.使用控制器
    • 3.1 常用注解
      • 3.1.1 @Controller
      • 3.1.2 @RestController
      • 3.1.3 @RequestMapping
      • 3.1.4 @PathVariable
    • 3.2 将 URL 映射到方法
    • 3.3 在方法中使用参数
      • 3.3.1 获取路径中的值
      • 3.3.2 获取路径中的参数
      • 3.3.3 通过 Bean 接收 HTTP 提交的对象
      • 3.3.4 用注解 @ModelAttribute 获取参数
      • 3.3.5 通过 HttpServletRequest 接收参数
      • 3.3.6 用 @RequestParam 绑定入参
      • 3.3.7 用 @RequestBody 接收 JSON 数据
      • 3.3.8 上传文件 MultipartFile
      • 3.3.9 上传图片
  • 4.理解模型
  • 5.实现 MVC 模式的 Web 应用程序(实战)
    • 5.1 添加依赖
    • 5.2 创建实体模型
    • 5.3 创建控制器
    • 5.4 创建用于展示的视图

1.应用程序分层开发模式:MVC

1.1 了解 MVC 模式

Spring Boot 开发 Web 应用程序主要使用 MVC 模式。MVC 是 Model(模型)、View(视图)、Controller(控制器)的简写。

  • Model:是 Java 的实体 Bean,代表存取数据的对象或 POJO(Plain Ordinary JavaObiects,简单的 Java 对象),也可以带有逻辑。其作用是在内存中暂时存储数据,并在数据变化时更新控制器(如果要持久化,则需要把它写入数据库或者磁盘文件中)。
  • View:主要用来解析、处理、显示内容,并进行模板的渲染。
  • Controller:主要用来处理视图中的响应。它决定如何调用 Model(模型)的实体 Bean、如何调用业务层的数据增加、删除、修改和查询等业务操作,以及如何将结果返给视图进行渲染。建议在控制器中尽量不放业务逻辑代码。

这样分层的好处是:将应用程序的用户界面和业务逻辑分离,使得代码具备良好的可扩展性可复用性、可维护性和灵活性。

如果不想使用 MVC 开发模式也是可以的,MVC 只是一个非常合理的规范。MVC 的关系如下图所示。

在这里插入图片描述
如果读者对 MVC 开发模式理解得不深入,那么往往会以为用户通过浏览器访问 MVC 模型的页面就是访问视图(View)。实际上,它并不是直接访问视图,而是访问 DispatcherServlet 处理映射和调用视图渲染,然后返回给用户的数据。

在整个 Spring MVC 框架中,DispatcherServlet 处于核心位置,继承自 HttpServlet。它负责协调和组织不同组件,以完成请求处理并返回响应工作。

整个工程流程如下:

  • 客户端(用户)发出的请求由 Tomcat(服务器)接收,然后 Tomcat 将请求转交给 DispatcherServlet 处理。
  • DispatcherServlet 匹配控制器中配置的映射路径,进行下一步处理。
  • ViewResolver 将 ModelAndView 或 Exception 解析成 View。然后 View 会调用 render() 方法,并根据 ModelAndView 中的数据渲染出页面。

在 MVC 开发模式中,容易混淆的还有 Model,它往往会被认为是业务逻辑层或 DAO 层。这种理解并不能说是错误的,但并不是严格意义上的 MVC 模式。

1.2 MVC 和三层架构的关系

🚀 可参考博主写的一篇博文《MVC框架和经典三层结构》

三层架构,就是将整个应用程序划分为 表现层(UI)、业务逻辑层(Service)、数据访问层(DAO / Repository)。

  • 表现层:用于展示界面。主要对用户的请求进行接收,以及进行数据的返回。它为客户端(用户)提供应用程序的访问接口(界面)。
  • 业务逻辑层:是三层架构的服务层,负责业务逻辑处理,主要是调用 DAO 层对数据进行增加、删除、修改和查询等操作。
  • 数据访问层:与数据库进行交互的持久层,被 Service 调用。在 Spring Data JPA 中由 Hibernate 来实现。
  • Repository 和 DAO 层一样,都可以进行数据的增加、删除、修改和查询。它们相当于仓库管理员,执行进 / 出货操作。
  • DAO 层的工作是 存取对象。Repository 层的工作是 存取和管理对象
  • 简单理解就是:Repository = 管理对象(对象缓存和在 Repository 的状态)+ DAO。

严格地说,MVC 是三层架构中的 UI 层。通过 MVC 把三层架构中的 UI 层又进行了分层。

由此可见,三层架构是基于业务逻辑或功能来划分的,而 MVC 是基于页面或功能来划分的。

2.视图技术 Thymeleaf

Spring Boot 主要支持 Thymeleaf、Freemarker、Mustache、Groovy Templates 等模板引擎。

Thymeleaf 可以轻易地与 Spring MVC 等 Web 框架进行集成。

Thymeleaf 语法并不会破坏文档的结构,所以 Thymeleaf 模板依然是有效的 HTML 文档。模板还可以被用作工作原型,Thymeleaf 会在运行期内替换掉静态值。它的模板文件能直接在浏览器中打开并正确显示页面,而不需要启动整个 Web 应用程序。

现代软件开发基本遵循前后端分离模式,会有专门的前端框架,如 Vue、React 等,本文对于 Thymeleaf 不再展开,有兴趣可以自行了解。

Thymeleaf 解决了前端开发人员要和后端开发人员配置一样环境的尴尬和低效。它通过属性进行模板渲染,不需要引入不能被浏览器识别的新的标签。页面直接作为 HTML 文件,用浏览器打开页面即可看到最终的效果,可以降低前后端人员的沟通成本。

要使用 Thymeleaf,首先需要引入依赖。直接在 pom.xml 文件中加入以下依赖即可。

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

3.使用控制器

在 Spring MVC 中,控制器(Controller)负责处理由 DispatcherServlet 接收并分发过来的请求。它把用户请求的数据通过业务处理层封装成一个 Model,然后再把该 Model 返回给对应的 View 进行展示。

Controller 无须继承特定的类或实现特定的接口。只需使用 @Controller(@RestController)来标记一个控制器,然后用注解 @RequestMapping 定义 URL 请求和 Controller 方法之间的映射,这样 Controller 就能被外界访问到。它可以包含多个请求处理方法。

3.1 常用注解

Spring MVC 控制器中常使用的注解有如下几种。

3.1.1 @Controller

@Controller 标记在类上。使用 @Controller 标记的类表示是 Spring MVC 的 Controller 对象。分发处理器将会扫描使用了该注解的类,并检测其中的方法是否使用了注解 @RequestMapping。注解 @Controler 只是定义了一个控制器类,使用了注解 @RequestMapping 的方法才是真正处理请求的处理器,完成映射关系。

3.1.2 @RestController

@RestController 是 Spring 4.0 之后才有的注解。它等价于原来的注解 @Controller 加上注解 @ResponseBody 的功能,直接返回字符串。用它来标注 Rest 风格的控制器类。

3.1.3 @RequestMapping

它用来处理请求地址映射的注解,可用在类或方法上。如果用在类上,则表示类中的所有响应请求的方法都以该地址作为父路径。

RequestMapping 注解有 6 个属性。

  • value:指定请求的地址。
  • method:指定请求的 method 类型,例如 GETHEADPOSTPUTPATCHDELETEOPTIONSTRACE
  • consumes:消费消息,指定处理请求的提交内容类型(Content-Type),例如 application/jsontext/html
  • produces:生产消息,指定返回的内容类型。仅当 request 请求头中的 Accept 类。含该指定类型时才返回。
  • params:指定 request 中必须包含某些参数值才让该方法处理请求。
  • headers:指定 request 中必须包含某些指定的 header 值才能让该方法处理请求。

3.1.4 @PathVariable

将请求 URL 中的模板变量映射到功能处理方法的参数上,即获取 URI 中的变量作为参数。以下代码先通过获取路径中的 id 值,再根据获取的 id 值来获取数据库中产品的对象。

@RequestMapping(value="/product/{id}",method = RequestMethod.GET)
public String getProduct(@PathVariable("id") String id){
    Product product = productRepository.findById(id);
    System.out.println("产品 id :" + product.getId());
    System.out.println("产品名称 :" + product.getTitle());
    return "product/show"
}

3.2 将 URL 映射到方法

将 URL(统一资源定位符)映射到方法,是通过注解 @RequestMapping 来处理的。URL 映射其实就是用控制器定义访问的 URL 路径。用户通过输入路径来访问某个方法。
在这里插入图片描述
注解 @RequestMapping 可以在类和方法上使用。如在类上使用,则可以窄化映射。如以下代码:

@RestController
@RequestMapping("news")
Public class NewsController {
    // GET方式
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public void add(){}
    // POST方式
    @RequestMapping(value = "/", method = RequestMethod.POST)
    public void save(){}
}

访问 addsave 方法都需要加上 news 级目录,如下所示。

  • GET 方式访问 add 方法的路径:http://localhost:8080/news/
  • POST 方式访问 save 方法的路径:http://localhost:8080/news/

这里的路径是一样的,但并不错误,因为资源路径一样,只是 HTTP 方法不一样。

Spring Boot 还提供了更简洁的编写 URL 映射的方法,如 @GetMapping("/"),它等价于 @RequestMapping(value="", method = RequestMethod.GET)。除此之外还有下面的写法。

  • @GetMapping:处理 GET 请求。
  • @PostMapping:处理 POST请求
  • @DeleteMapping:处理删除请求。
  • @PutMapping:处理修改请求。

3.3 在方法中使用参数

对于程序开发的初学者来说,比较困难的可能并不是理论,而是程序的具体实现。比如,如何把最简单的程序运行起来,如何实现参数的接收和发送等。本节讲解的就是如何在控制器的方法中使用参数。

3.3.1 获取路径中的值

/**
*Description:根据id 获取文章对象
*/
@GetMapping("article/{id}")
public ModelAndView getArticle(@PathVariable("id") Integer id) {
    Article articles = articleRepository.findById(id);
    ModelAndView mav = new ModelAndView("article/show");
    mav.addObject("article", articles);
    return mav;
}

在访问 http://localhostarticle/123 时,程序会自动将 URL 中的模板变量 {id} 绑定到通过 @PathVariable 注解的同名参数上,即 “程序获取路径中 123 的值”。

3.3.2 获取路径中的参数

对于路径中的参数获取,可以写入方法的形参中。下面代码是获取参数 username 的值。

@RequestMapping("/addUser")
public String addUser(String username) {
}

这里的参数和上面所讲的获取路径值是不一样的,比如 http://localhostuser/?username=longzhiran,它是由 = 隔开的。

3.3.3 通过 Bean 接收 HTTP 提交的对象

可以通过 Bean 获取 HTTP 提交的对象,如以下代码:

public String addUser(UserModel user)

3.3.4 用注解 @ModelAttribute 获取参数

用于从 Model、Form 或 URL 请求参数中获取属性值,如以下代码:

@RequestMapping(value="addUser",method=RequestMethod.POST)
public String addUser(@ModelAttribute("user") UserModel user)

3.3.5 通过 HttpServletRequest 接收参数

可以通过 HttpServletRequest 接收参数,如以下代码:

@RequestMapping("/addUser")
public String addUser(HttpServletRequest request) {
    System.out.println("name:" + request.GETParameter("username"));
    return "/index";
}

3.3.6 用 @RequestParam 绑定入参

用法如以下代码:

@RequestParam(value="username",required=false)

当请求参数不存在时会有异常发生,可以通过设置属性 required=false 来解决。

3.3.7 用 @RequestBody 接收 JSON 数据

可以通过 @RequestBody 注解来接收 JSON 数据,如以下代码:

@RequestMapping(value = "adduser", method = {RequestMethod.POST})
@ResponseBody
public void saveUser(@RequestBody List<User> users) {
    userService.Save(users);
}

3.3.8 上传文件 MultipartFile

通过 @RequestParam 获取文件,如以下代码:

public String singleFileUpload(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) {
    if (file.isEmpty()) {
        redirectAttributes.addFlashAttribute("message", "请选择文件");
        return "redirect:uploadStatus";
    }
    try {
        byte[] bytes = file.getBytes();
        Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
        Files.write(path, bytes);
        redirectAttributes.addFlashAttribute("message", "成功上传 " + file.getOriginalFilename() + "");
    } catch (IOException e) {
        e.printStackTrace();
    }
    return "redirect:/uploadStatus";
}

出于安全考虑,在生产环境中需要判断文件的类型,一般不允许上传 .exe 等格式的可执行文件。

3.3.9 上传图片

很多人在整合富文本编辑器时不容易成功,特别是在不同版本要求返回的数据类型不一样时,而网络上的资料很多是不带版本号或是过时的。

CKEditor 4.10.1 之后的版本只有返回的是 JSON 格式的数据才能成功,如 [{"uploaded":1, "fileName":"fileName", "url"="", "message":"上传成功"}]

4.理解模型

模型(Model)在 MVC 模式中是实体 Bean,代表一个存取数据的对象或 POJO(Plain OrdinaryJava Object)。它可以带有逻辑,其作用是暂时存储数据(存在内存中),以便进行持久化(存入数据库或写入文件),以及在数据变化时更新控制器。简单地理解是:Model 是数据库表对应的实体

以下代码定义了一个用户实体 Bean(Model)。

@Getter
@Setter
public class User {
    //定义id
    private long id;
    //定义用户名
    private String name;
    //定义用户年龄
    private int age;
}

可以通过常用的 GetterSetter 封装来对实体 Bean 进行赋值、获值操作,并在其中添加逻辑代码。

5.实现 MVC 模式的 Web 应用程序(实战)

在这里插入图片描述

5.1 添加依赖

MVC 模式的 Web 应用程序需要依赖 Spring Boot 的 spring-boot-starter-web(Starter)还需要添加模板的依赖。具体依赖如以下代码:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<optional>true</optional>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-test</artifactId>
	<scope>test</scope>
</dependency>

5.2 创建实体模型

创建实体 Bean,用于和 Controller 进行数据交互。

package com.example.demo.model;
import lombok.Data;

@Data
public class User {
    //定义id
    private long id;
    //定义用户名
    private String name;
    //定义用户年龄
    private int age;
}

5.3 创建控制器

控制器层用来实例化实体 Bean(Model),并传值给视图模版。

package com.example.demo.controller;
import com.example.demo.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class MVCDemoController {
    //映射URL地址
    @GetMapping("/mvcdemo")
    public ModelAndView hello() {
        //实例化对象
        User user = new User();
        user.setName("pipi");
        user.setAge(26);
        //定义mvc中的视图模板
        ModelAndView modelAndView = new ModelAndView("mvcdemo");
        //传递user实体对象给视图
        modelAndView.addObject("user",user);
        return modelAndView;
    }
}

5.4 创建用于展示的视图

以下代码用于获取控制器中传递的实体 Bean,并进行渲染。

<!DOCTYPE html>
<!--thymeleaf模板支持-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
	<div>
	    <!-- 显示由控制器传递过来的实体user的值-->
	    <div th:text="${user.name}"></div>
	    <div th:text="${user.age}"></div>
	</div>
</body>
</html>

启动项目,然后访问 http://localhost:8080/mvcdemo

在这里插入图片描述

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

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

相关文章

【JVM实践与应用】

JVM实践与应用 1.类加载器(加载、连接、初始化)1.1 类加载要完成的功能1.2 加载类的方式1.3 类加载器1.4 双亲委派模型1.5自定义ClassLoader1.6 破坏双亲委派模型2.1 类连接主要验证内容2.2 类连接中的解析2.3 类的初始化3.1 类的初始化时机3.2 类的初始化机制和顺序3.2 类的卸…

电子电器架构 - AUTOSAR软件架构Current Features in a Nutshell

电子电器架构 - AUTOSAR软件架构Current Features in a Nutshell 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的…

数据清洗操作及众所周知【数据分析】

各位大佬好 &#xff0c;这里是阿川的博客 &#xff0c; 祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 前面的博客 数据分析—技术栈和开发环境搭建 …

7.Redis之String编码方式应用场景业务

1.内部编码 字符串类型的内部编码有 3 种&#xff1a; • int&#xff1a;8 个字节&#xff08;64位&#xff09;的⻓整型。 • embstr&#xff1a;⼩于等于 39 个字节的字符串。压缩字符串.适用于表示比较短的字符串。 • raw&#xff1a;⼤于 39 个字节的字符串。普通字…

红蓝对抗-HW红蓝队基本知识(网络安全学习路线笔记)

第一, 什么是蓝队 蓝队&#xff0c;一般是指网络实战攻防演习中的攻击一方。 蓝队一般会采用针对目标单位的从业人员&#xff0c;以及目标系统所在网络内的软件、硬件设备同时执行多角度、全方位、对抗性的混合式模拟攻击手段&#xff1b;通过技术手段实现系统提权、控制业务、…

阻塞信号集和未决信号集_代码实现

1. 程序验证内容 将编号为0,1,2添加到阻塞信号集中&#xff0c;i<信号编号时&#xff0c;发出信号&#xff0c;观察未决信号集状态 当解除阻塞后&#xff0c;原先的信号是否执行&#xff0c;执行顺序是什么 2. 代码实现 #include <unistd.h> #include <stdlib.h…

AI数据面临枯竭

Alexandr Wang&#xff1a;前沿研究领域需要大量当前不存在的数据&#xff0c;未来会受到这个限制 Alexandr Wang 强调了 AI 领域面临的数据问题。 他指出&#xff0c;前沿研究领域&#xff08;如多模态、多语言、专家链式思维和企业工作流&#xff09;需要大量当前不存在的数…

鸿蒙 DevEcoStudio:发布进度条通知

使用notificationManager及wantAgent实现功能import notificationManager from ohos.notificationManager import wantAgent from ohos.app.ability.wantAgent Entry Component struct Index {State message: string 发布进度条通知progressValue: number0async publicDownloa…

【数据结构(邓俊辉)学习笔记】二叉树02——遍历

文章目录 0.概述1. 先序遍历1.1 递归版1.1.1 实现1.1.2 时间复杂度1.1.3 问题 1.2 迭代版11.3 迭代版21.3.1 思路1.3.2 实现1.3.3 实例 2. 中序遍历2.1 递归形式2.2 迭代形式2.2.1 观察2.2.2 思路&#xff08;抽象总结&#xff09;2.2.3 构思 实现2.2.4 分摊分析 3. 后序遍历3…

单条16g和双条8g哪个好

单条16g和双条8g各有优劣,具体选择要根据个人需求和电脑配置来决定。 以下是一些参考信息: •单条16g内存的价格比双条8g内存的价格低,而且16g的内存容量大,一条内存十分的方便。 •两条8g内存可以组成双通道,电脑运行速度要快一些。 •对于普通使用电脑的人群与热衷于…

linux下的实时同步服务简介与实验(sersync+nfs+rsync)

目录 实时同步是什么定时同步的缺陷实时同步简介 Sersync简介rsyncinotify-tools与rsyncsersync架构的区别&#xff1f; SerSync工作流程SerSync同步架构Sersync配置详解执行文件配置文件 NFSSersyncRsync实时同步服务实验0. 实验简介1. 实验架构2. 实验环境3. 实验步骤front主…

【调试笔记-20240521-Linux-编译 QEMU/x86_64 可运行的 OpenWrt 固件】

调试笔记-系列文章目录 调试笔记-20240521-Linux-编译 QEMU/x86_64 可运行的 OpenWrt 固件 文章目录 调试笔记-系列文章目录调试笔记-20240521-Linux-编译 QEMU/x86_64 可运行的 OpenWrt 固件 前言一、调试环境操作系统&#xff1a;Ubuntu 22.04.4 LTS编译环境调试目标 二、调…

etcd基础知识总结

文章目录 核心概念什么是etcd为什么需要etcd分布式中CAP理论etcd中常用的术语etcd的特性etcd的应用场景etcd的核心架构小结 etcd搭建小结 Etcdctl小结 etcd网关和grpc-GetwayEtcd 网关模式grpc-Geteway小结 etcd读请求执行流程Etcd 写请求执行流程写请求之QuotaKVServer模块写请…

晶圆厂的PE转客户工程师前景怎么样?

知识星球&#xff08;星球名&#xff1a; 芯片制造与封测技术社区&#xff0c;星球号&#xff1a; 63559049&#xff09;里的学员问&#xff1a; 目前在晶圆厂做PE&#xff0c;倒班oncall压力太大把身体搞坏了&#xff0c;现在有一个design house的CE客户工程师的offer&…

绘唐科技绘唐ai工具邀请码

绘唐科技绘唐ai工具邀请码 绘唐AI工具 https://qvfbz6lhqnd.feishu.cn/wiki/QBr4wOAz2ilF4NknrqbcoKRhn2c TensorFlow是一个开源的机器学习框架,由Google开发并维护。它提供了一个灵活且高效的接口,用于构建和训练各种机器学习模型。 TensorFlow的基本概念包括: 1. 张量(…

Qt Creator(1)【概述篇】

阅读导航 引言一、Qt概述1. 什么是Qt2. Qt的发展史3. Qt支持的平台4. Qt的优点5. Qt的应用场景 二、Qt下载安装 引言 在探索编程和软件开发的旅程中&#xff0c;我们已经奠定了坚实的基础&#xff0c;通过学习C语言和C&#xff0c;我们不仅掌握了结构化编程和面向对象编程的核…

[数组查找]2.图解二分查找及其代码实现

二分查找 二分查找也是一种在数组中查找数据的算法。和线性查找不同&#xff0c;它只能查找已经排好序的数据。二分查找通过比较数组中间的数据与目标数据的大小&#xff0c;可以得知目标数据是在数组的左边还是右边。因此&#xff0c;比较一次就可以把查找范围缩小一半。重复执…

天工 AI 3.0,彻底爆了!

作为一名 AI 博主&#xff0c;深知一个优秀的AI工具能大大提高我们日常学习、工作效率&#xff0c;比如我之前学习一些AI方向的算法知识&#xff0c;需要搜索大量博客、付费购买专业课程等。光在找到有用的资料就耗费不少时间了&#xff0c;更何况需要阅读全文去整理汇总&#…

1.2 程序员职业发展

目录 1 程序员职业发展方向 2 计算机研究生为何青睐AI赛道 1 程序员职业发展方向 2 计算机研究生为何青睐AI赛道 计算机类研究生&#xff0c;大部分以人工智能作为主赛道&#xff0c;原因如下&#xff1a; 广阔的就业前景&#xff1a;人工智能是当今科技发展的前沿领域&…

专业渗透测试 Phpsploit-Framework(PSF)框架软件小白入门教程(十二)

本系列课程&#xff0c;将重点讲解Phpsploit-Framework框架软件的基础使用&#xff01; 本文章仅提供学习&#xff0c;切勿将其用于不法手段&#xff01; 接上一篇文章内容&#xff0c;讲述如何进行Phpsploit-Framework软件的基础使用和二次开发。 我们&#xff0c;继续讲一…