Day41

Day41

文件的上传

浏览器底层是通过输入流读取文件,通过输出流传输到服务器,服务器通过输入流读取数据,通过输出流将文件保存在本地。注意:浏览器的表单不许用post请求,get请求会将数据显示在地址栏里。

上传头像

场景:在一个注册页面上传头像。

register.jsp:

<%--Created by IntelliJ IDEA.User: GuDate: 2024-06-13Time: 18:43To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style>body {display: flex;justify-content: center;align-items: center;height: 100vh;margin: 0;font-family: Arial, sans-serif;background: #f0f0f0;}</style>
</head>
<body><form action="RegisterServlet" method="post" enctype="multipart/form-data"><h2>欢迎来到注册页面</h2><br/>账号:<input type="text" name="username" /><br />密码:<input type="password" name="password" /><br />姓名:<input type="text" name="name" /><br />年龄:<input type="text" name="age" /><br />性别:<input type="radio" name="sex" value="man" checked="checked"/>男<input type="radio" name="sex" value="woman"/>女<br />爱好:<input type="checkbox" name="hobbies" value="football" />足球<input type="checkbox" name="hobbies" value="basketball" />篮球<input type="checkbox" name="hobbies" value="shop" />购物<br /><input type="submit" value="注册" /><br/><input type="file" name="photo"/><br/><button type="button" οnclick="fun01()">返回</button></form><script type="text/javascript">function fun01(){window.location = "register.jsp";}
</script></body>
</html>

注意:1.使用post请求,设置enctype=“multipart/form-data”(以二进制流的形式上传数据,效率比较低,不设置的话以默认的纯文本数据上传。)。2.input type=“file”。

版本一:原生文件方式处理文件

待优化点:1.相同的文件名会覆盖文件;2.存储路径绝对,其他系统无法存储。

RegisterServlet:

package com.qf.servlet;import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;@WebServlet("/RegisterServlet")
public class RegisterServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {request.setCharacterEncoding("UTF-8");response.setContentType("text/html;charset=UTF-8");//创建文件上传类对象的工厂对象DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();//利用工厂对象创建文件上传类对象ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);try {//解析请求对象List<FileItem> list = servletFileUpload.parseRequest(request);//遍历获取的集合for(FileItem fileItem:list){//如果是文本数据if(fileItem.isFormField()){String fieldName = fileItem.getFieldName();//属性名String value = fileItem.getString("UTF-8");//值System.out.println(fieldName + "--" + value);}else {//二进制数据String name = fileItem.getName();//用户输入的文件的名System.out.println(name);InputStream inputStream = fileItem.getInputStream();String path="F:\\text\\头像01.jpg";FileOutputStream fileOutputStream = new FileOutputStream(path);byte[] bs = new byte[1024];int len;while((len=inputStream.read(bs))!=-1){fileOutputStream.write(bs);}inputStream.close();fileOutputStream.close();}}} catch (FileUploadException e) {throw new RuntimeException(e);}}
}

注:不能使用request.getparameter()获取数据了,用request.getInputStream()。

版本二:使用到发布路径 + 文件名

待优化点:文件名重复仍会覆盖。

注意:1.使用IOUtil工具类2.编辑发布路径,将文件保存到项目的发布路径里,需要将IDEA里的路径改为服务器(Tomcat)里的webapp下自己创建的文件名里,如:\apache-tomcat-8.0.49\webapps\Day41_upload_war_exploded

public void method02(HttpServletRequest request,HttpServletResponse response) throws UnsupportedEncodingException {request.setCharacterEncoding("UTF-8");response.setContentType("text/html;charset=UTF-8");//创建文件上传类工厂DiskFileItemFactory factory = new DiskFileItemFactory();//创建文件上传类ServletFileUpload upload = new ServletFileUpload(factory);try {//解析数据List<FileItem> list = upload.parseRequest(request);for(FileItem file:list){if(file.isFormField()){//是文本数据System.out.println(file.getFieldName()+"--"+file.getString("UTF-8"));}else {//处理二进制数据String path = this.getServletContext().getRealPath("upload");//获取系统的发布路径//创建文件夹File file1 = new File(path);if(!file1.exists()){file1.mkdirs();}//设置文件路径String name = file.getName();String outPath = path+File.separator+name;//上传文件InputStream in = file.getInputStream();FileOutputStream out = new FileOutputStream(outPath);IOUtils.copy(in,out);in.close();out.close();}}} catch (FileUploadException | IOException e) {throw new RuntimeException(e);}}

版本三:使用UUID解决文件名重复问题

缺点:改变了文件名

public void method03(HttpServletRequest request,HttpServletResponse response) throws UnsupportedEncodingException {request.setCharacterEncoding("UTF-8");response.setContentType("text/html;charset=UTF-8");DiskFileItemFactory factory = new DiskFileItemFactory();ServletFileUpload upload = new ServletFileUpload(factory);try {List<FileItem> list = upload.parseRequest(request);for(FileItem fileItem:list){if (fileItem.isFormField()){System.out.println(fileItem.getFieldName()+"--"+fileItem.getString("UTF-8"));}else {//获取项目发布路径String realPath = this.getServletContext().getRealPath("upload");File file = new File(realPath);if(!file.exists()){file.mkdirs();}String name = fileItem.getName();UUID uuid = UUID.randomUUID();String fileName = uuid + name;String filePath = realPath +File.separator+ fileName;InputStream in = fileItem.getInputStream();FileOutputStream out = new FileOutputStream(filePath);IOUtils.copy(in,out);in.close();out.close();}}} catch (FileUploadException | IOException e) {throw new RuntimeException(e);}}

最终版:

思路:先自定义一个parseRequest()方法。通过上传文件工厂创建上传文件对象,再解析用户在注册页面填写的所有数据,其中对每一个数据项进行判别,如果是文本数据则直接用ConcurrentHashmap存储数据,其中需要注意的点为遇到多选的时候需要判断当前的键(属性名)是否已经存在于map中,如果存在就添加在后面。如果是二进制数据则需要先获取发布路径(利用File类创建文件夹),然后通过发布路径和文件名创造二进制数据下载的绝对路径,最后用map把属性名和绝对路径后面部分(自定义即可)存储起来。同时还需要创建一个用来存储输入输出流的类CopyIo,因为最终要将用户上传的文件写到发布路径里面,所以用请求创建输入流(建立客户端输入的渠道),并用绝对路径创建输出流(建立输出到发布路径的渠道),并将两个流封装到CopyIo中,以便直接使用。

接下来的思路和之前的一样,通过自定义的parseRequest()方法设置好ConcurrentHashmap和CopyIo对象。然后用自带的BeanUtils类的populate方法将数据封装到Student类中,利用这个类对象往数据库中查询,没有账号则可以注册,即先往数据库中添加数据,再用CopyIo对象中的输入输出流进行数据写入和发布输出;如果有账号则用请求存储错误信息,返回注册页面。注意:别忘了关闭资源(输入流、输出流)。

  public void parseRequest(HttpServletRequest request, Student student , CopyIO copyIO){ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();DiskFileItemFactory factory = new DiskFileItemFactory();ServletFileUpload upload = new ServletFileUpload(factory);String username=null;try {List<FileItem> list = upload.parseRequest(request);for(FileItem fileItem:list){if(fileItem.isFormField()){String fieldName = fileItem.getFieldName();String value = URLEncoder.encode(fileItem.getString(),"UTF-8");if("username".equals(fieldName)){username=value;}String s = map.get(fieldName);if(s==null){//第一次添加map.put(fieldName,value);}else{//多选的情况s = s+","+value;map.put(fieldName,s);}}else{//二进制数据String realPath = this.getServletContext().getRealPath("upload"+File.separator+"student"+File.separator+username);File file = new File(realPath);if(!file.exists()){file.mkdirs();}String fileName = fileItem.getName();String path = realPath + File.separator + fileName;copyIO.setIn(fileItem.getInputStream());copyIO.setOut(new FileOutputStream(path));map.put(fileItem.getFieldName(),"upload"+File.separator+"student"+File.separator+username+File.separator+fileName);}}BeanUtils.populate(student,map);} catch (FileUploadException | IOException | InvocationTargetException | IllegalAccessException e) {throw new RuntimeException(e);}}
public void method04(HttpServletRequest request,HttpServletResponse response) throws UnsupportedEncodingException {request.setCharacterEncoding("UTF-8");response.setContentType("text/html;charset=UTF-8");Student student = new Student();CopyIO copyIO = new CopyIO();parseRequest(request,student,copyIO);System.out.println(student);try {Student sqlStu = DBUtil.commonQueryObj(Student.class, "select * from student where username=?", student.getUsername());System.out.println(sqlStu);if(sqlStu==null){//允许注册String sql = "insert into student(username,password,name,sex,age,hobbies,photo) values (?,?,?,?,?,?,?)";DBUtil.commonInsert(sql,student.getUsername(),student.getPassword(),student.getName(),student.getSex(),student.getAge(),student.getHobbies(),student.getPhoto());//上传头像InputStream in = copyIO.getIn();OutputStream out = copyIO.getOut();int len;byte[] bs = new byte[1024];while((len=in.read(bs))!=-1){out.write(bs);}in.close();out.close();}else{//不允许注册
//                copyIO.getIn().close();
//                copyIO.getOut().close();request.setAttribute("msg","账号已存在,注册失败");request.getRequestDispatcher("register.jsp").forward(request,response);}} catch (SQLException | InstantiationException | IllegalAccessException | IOException | ServletException e) {throw new RuntimeException(e);}}

文件的下载

下载图片和压缩包

在web文件夹中设置一个download文件夹用来存放下载资源。

页面:超链接中href="download/xxx.zip"下载压缩包

href="download/xxx.jpg"下载图片

注:因为浏览器无法识别zip,所以可以直接下载,而jpg可以识别,所以会直接展示。如果想直接下载,要自己写一个servlet去实现图片下载功能。

更改发布路径,获取需要下载的文件路径,从发布路径中截取到文件名,设置编码格式,设置响应头信息即告诉浏览器以附件的形式下载而不是展示,用输入输出流读取和输出(输出流用响应获取)。

DownloadServlet:

package com.qf.servlet;import org.apache.commons.io.IOUtils;import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;@WebServlet("/DownloadServlet")
public class DownloadServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {request.setCharacterEncoding("UTF-8");response.setContentType("text/html;charset=UTF-8");//获取需要下载的文件路径String realPath = this.getServletContext().getRealPath("download\\aaa.jpg");//从下载路径中截取文件名String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);//设置编码格式fileName = URLEncoder.encode(fileName, "UTF-8");//设置响应头,使浏览器只能以附件形式下载response.setHeader("Content-disposition","attachment;fileName="+fileName);FileInputStream fileInputStream = new FileInputStream(realPath);ServletOutputStream outputStream = response.getOutputStream();IOUtils.copy(fileInputStream,outputStream);fileInputStream.close();fileInputStream.close();}
}

经验:下载图片用servlet,将下载的文件放在一个地方。

MVC设计模式

在这里插入图片描述

M-model-模型层:biz/service-服务层:做业务;dao/mapper -数据持久层:操作数据库。

V-view-视图层:页面(HTML、CSS、JS、JSP)。

C-Controller-控制器层:控制页面的跳转。

服务端分层思想:controller、biz、dao

优缺点:

缺点:使用MVC不能减少代码量, 增加系统结构和实现的复杂性

优点:整个项目结构清晰,业务逻辑清晰,降低了代码的耦合性,代码的重用性高

MVC编写顺序:先写模型层

以WEB-学生管理系统为例:

创建mapper包,

StudentMapper接口:

package com.qf.mapper;import com.qf.pojo.Student;import java.util.List;public interface StudentMapper {public void add(String username,String password,String name,String sex,int age,String hobbies,String photo);public void delete(String username);public void update(String username,String password,String name,String sex,int age,String hobbies,String photo);public Student getStudent(String username);public List<Student> getStudent(int offset,int count);public int getAllCount();
}

在mapper中创建一个包impl,实现接口,StudentMapperImpl:

package com.qf.mapper.impl;import com.qf.mapper.StudentMapper;
import com.qf.pojo.Student;
import com.qf.utils.DBUtil;import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;public class StudentMapperImpl implements StudentMapper {@Overridepublic void add(String username, String password, String name, String sex, int age, String hobbies, String photo) {try {DBUtil.commonInsert("insert into student values (?,?,?,?,?,?,?)",username,password,name,sex,age,hobbies,photo);} catch (SQLException e) {throw new RuntimeException(e);}}@Overridepublic void delete(String username) {try {DBUtil.commonUpdate("delete from student where username=?",username);} catch (SQLException e) {throw new RuntimeException(e);}}@Overridepublic void update(String username, String password, String name, String sex, int age, String hobbies, String photo) {String sql = "update student set username=?,password=?,name=?,sex=?,age=?,hobbies=?,photo=?";try {DBUtil.commonUpdate(sql,username,password,name,sex,age,hobbies,photo);} catch (SQLException e) {throw new RuntimeException(e);}}@Overridepublic Student getStudent(String username) {Student student = null;try {student = DBUtil.commonQueryObj(Student.class, "select * from student where username=?", username);} catch (SQLException | InstantiationException | IllegalAccessException e) {throw new RuntimeException(e);}return student;}@Overridepublic List<Student> getStudent(int offset, int count) {List<Student> list = new ArrayList<>();try {list = DBUtil.commonQueryList(Student.class, "select * from student ?,limit?", offset, count);} catch (SQLException e) {throw new RuntimeException(e);} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);}return list;}@Overridepublic int getAllCount() {int allCount = DBUtil.getAllCount("select count(username) from student");return allCount;}
}

注:mapper层所有的参数是service层传进来的。

同理:mapper包中写一个TeacherMapper接口:

package com.qf.mapper;import com.qf.pojo.Teacher;public interface TeacherMapper {public void update(String username,String password,String name,int courseId,String photo);public Teacher getTeacher(String username);public Teacher getTeacher(String username,String password);}

在impl中写TeacherMapperImpl

package com.qf.mapper.impl;
import com.qf.mapper.TeacherMapper;
import com.qf.pojo.Teacher;
import com.qf.utils.DBUtil;
import java.sql.SQLException;
public class TeacherMapperImpl implements TeacherMapper {@Overridepublic void update(String username, String password, String name, int courseId, String photo) {String sql = "update set teacher username=?,password=?,name=?,courseId=?,photo=?";try {DBUtil.commonUpdate(sql,username,password,name,courseId,photo);} catch (SQLException e) {throw new RuntimeException(e);}}@Overridepublic Teacher getTeacher(String username) {Teacher teacher =null;try {teacher = DBUtil.commonQueryObj(Teacher.class, "select * from teacher where username=?", username);} catch (SQLException | InstantiationException | IllegalAccessException e) {throw new RuntimeException(e);}return teacher;}@Overridepublic Teacher getTeacher(String username, String password) {Teacher teacher = null;try {teacher = DBUtil.commonQueryObj(Teacher.class, "select * from teacher where username=? and password=?", username, password);} catch (SQLException | InstantiationException | IllegalAccessException e) {throw new RuntimeException(e);}return teacher;}
}

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

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

相关文章

【数据结构与算法(C语言)】循环队列图解

目录 1. 前言1.1 普通循环队列假溢出1.1.1 初始化队列1.1.2 插满队列1.1.3 删除元素后&#xff0c;再插入元素 1.2 循环队列1.2.1 插入元素&#xff0c;队列已满1.2.2 将元素J1、J2出列&#xff0c;循环队列又空出两个空间1.2.3 元素J6可以继续入列 2. 存储结构和函数说明2.1 队…

vivado PIP or SITE_PIP、PKGPIN_BYTEGROUP

PIP是Xilinx部件上用于路由连接或网络的设备对象。PIP 称为ARC的连接多路复用器可以编程为将一根电线连接到 另一个&#xff0c;从而将节点连接在一起&#xff0c;以形成中特定NET所需的路由 设计。 SITE_PIP&#xff0c;也称为路由BEL&#xff0c;是SITE内部的连接多路复用器&…

android常用知识

透明activity样式&#xff1a; android:theme"android:style/Theme.Translucent.NoTitleBar.Fullscreen"这句代码&#xff0c;当你是建的empty activity project时&#xff0c;默认继承的是AppCompat这个类。所以在AndroidMifext.xml文件中用上述代码会导致程序错误&…

Qt | 简单的使用 QStyle 类(风格也称为样式)

01、前言 者在 pro 文件中已添加了正确的 QT+=widgets 语句 02、基础样式 1、QStyle 类继承自 QObject,该类是一个抽像类。 2、QStyle 类描述了 GUI 的界面外观,Qt 的内置部件使用该类执行几乎所有的绘制,以确保 使这些部件看起来与本地部件完全相同。 3、Qt 内置了一系…

制造业为什么需要ERP企业管理软件?

如今&#xff0c;传统的制造业管理方式逐渐变得力不从心~库存积压、生产效率低下、供应链混乱…想象一下&#xff0c;如果你的企业仍然依赖于手工记录订单、库存和财务数据&#xff0c;那么每当市场发生变动时&#xff0c;你就需要花费大量的时间和精力去重新调整生产计划、更新…

【深度学习驱动流体力学】VTK创建、处理和可视化流体数据

Visualization Toolkit&#xff08;VTK&#xff09;是一个强大的开源软件系统&#xff0c;用于处理和可视化三维数据。它提供了丰富的工具和算法&#xff0c;可以处理从简单的网格数据到复杂的流体动力学模拟数据等各种类型的数据。本文将完整介绍如何使用 VTK 创建、处理和可视…

Springboot + Mybatis 实现sql打印

参照这个视频&#xff1a;https://www.bilibili.com/video/BV1MS411N7mn/?vd_source90ebeef3261cec486646b6583e9f45f5 实现mybatis对外暴露的接口Interceptor 使用Intercepts接口,这里的写法参照mybatis-plus中的拦截器写法 Intercepts({Signature(type Executor.class, m…

BC153 [NOIP2010]数字统计

数字统计 一.题目描述二.输入描述&#xff1a;三.输出描述&#xff1a;四.数字范围五.题目思路六.代码实现 一.题目描述 请统计某个给定范围[L, R]的所有整数中&#xff0c;数字2出现的次数。 比如给定范围[2, 22]&#xff0c;数字2在数2中出现了1次&#xff0c;在数12中出现1次…

如何恢复iPhone iCloud云盘资料删除?给出建议

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

【Java】已解决com.mysql.cj.jdbc.exceptions.CommunicationsException异常

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决com.mysql.cj.jdbc.exceptions.CommunicationsException异常 一、分析问题背景 com.mysql.cj.jdbc.exceptions.CommunicationsException是Java程序在使用MySQL Connector/J与…

目标检测—Fast RCNN

介绍Fast R-CNN之前先简单回顾一下R-CNN和SPP-net R-CNN&#xff08;Regions with CNN&#xff09; affine image wraping 解析 Bounding Box Regression&#xff08;边界框回归&#xff09; 如何回归&#xff1f; 问题1&#xff1a;为什么要使用相对坐标差&#xff1f; …

立创开源学习篇(一)

1.机壳地 外面包围的一圈是机壳地&#xff0c;和金属外壳相连与电路板的GND不相连&#xff1a;&#xff08;大疆很多产品有此设计&#xff09; 屏蔽和接地&#xff1a;通过在电路板周围打孔&#xff0c;并连接到机壳地&#xff0c;可以形成有效的电磁屏蔽层&#xff08;形成金…

【C语言】回调函数 和 部分库函数的用法以及模拟实现

一、回调函数&#xff1a; 1、定义&#xff1a; 回调函数就是一个通过函数指针调用的函数。如果你把函数的指针&#xff08;地址&#xff09;作为参数传递给另一个函数&#xff0c;当这个指针被用来调用其所指向的函数时&#xff0c;我们就说这是回调函数。 2、qsort的模拟实现…

怎样打印微信文档文件?

在日常生活和工作中&#xff0c;我们经常需要打印微信中的文档文件&#xff0c;无论是工作资料、学习笔记还是其他重要信息。随着科技的发展&#xff0c;我们不再需要前往打印店进行繁琐的操作&#xff0c;而是可以通过一些便捷的在线打印平台轻松实现。今天&#xff0c;我们就…

echarts学习:通过图例事件实现选中后控制多条折线的显隐

1.问题描述 我在工作中遇到了这样一个需求&#xff1a;我们都知道点击echarts折线图的图例&#xff0c;是可以控制折线的显隐的。我现在希望点击某一个图例可以改变多条折线的显隐。 例如在下面这张图中&#xff0c;我将“xxx水位”和“yyy水位”分为一组&#xff1b;将“xxx…

SGPT论文阅读笔记

这是篇想要用GPT来提取sentence embedding的工作&#xff0c;提出了两个框架&#xff0c;一个是SGPT-BE&#xff0c;一个是SGPT-CE&#xff0c;分别代表了Bi-Encoder setting和Cross-Encoder setting。CE的意思是在做阅读理解任务时&#xff0c;document和query是一起送进去&am…

Maven 配置学习:存在两个本地私服如何配置

Maven 配置学习&#xff1a;存在两个本地私服如何配置 目录 Maven 配置学习&#xff1a;存在两个本地私服如何配置解释&#xff1a;1.本地仓库位置&#xff1a;2.Profiles 定义&#xff1a;3.Repositories 定义顺序&#xff1a;4.Active Profiles&#xff1a; 操作步骤&#xf…

在Pycharm使用Github Copilot

文章目录 1.GitHub Copilot 是什么2.注册GitHub Copilot3.官方使用文档4.安装 GitHub Copilot插件5.在Pycharm中使用6.相关功能键7.启用或禁用 GitHub Copilot 1.GitHub Copilot 是什么 GitHub Copilot 是一款 AI 编码助手&#xff0c;可帮助你更快、更省力地编写代码&#xff…

【MySQL进阶之路 | 高级篇】SQL执行过程

1. 客户端与服务器的连接 运行中的服务器程序与客户端程序本质上都是计算机的一个进程&#xff0c;所以客户端进程向服务器端进程发送请求并得到相应过程的本质就是一个进程间通信的过程. 我们可以使用TCP/IP网络通信协议&#xff0c;命名管道和共享内存等方式&#xff0c;实…

2024/6/18(RBAC,查询用户权限,细粒度授权,选课,支付宝生成二维码支付,支付结果查询需要内网穿透)

黑马程序员【学成在线项目】,P141 测试沙箱支付宝_黑马学成在线支付宝沙箱-CSDN博客 需要内网穿透