[Spring] SpringMVC 简介(三)

目录

九、SpringMVC 中的 AJAX 请求

1、简单示例

2、@RequestBody(重点关注“赋值形式”)

3、@ResponseBody(经常用)

4、为什么不用手动接收 JSON 字符串、转换 JSON 字符串

5、@RestController

十、文件上传与下载

1、ResponseEntity

2、文件下载

3、文件上传

4、解决文件重名导致内容覆盖的问题

十一、拦截器

1、拦截器的三个方法

2、拦截器的简单示例

3、拦截器的配置方法

4、多个拦截器的执行顺序

5、preHandle 返回 false 的情况

十二、控制器方法异常处理

1、异常处理解析器

2、使用 xml 配置

3、显示域对象的数据

4、使用注解配置


九、SpringMVC 中的 AJAX 请求

Ajax 请求的前端发送有很多种方式,可以使用 Vue,也可以使用 JQuery。

1、简单示例

下面是一个服务器获取请求头中的信息,并响应一个字符串的简单 Ajax 示例。

(1)index.html 

使用 Ajax 请求传递两个请求参数,并接收服务器端的响应数据,格式为 text。

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript" th:src="@{/static/js/JQuery-3.7.0.js}"></script><script type="text/javascript">$(function() {$("#ajaxButton").click(function() {$.ajax({url:"/Demo_Rest/testAjax",data: { // 在请求头"username": "admin","password": "123456",},type: "get",dataType: "text",success: function(data) {alert(data);}});});});</script>
</head>
<body><h1>index 页面</h1><input id="ajaxButton" type="button" value="发起 ajax 请求"/>
</body>
</html>

(2)java 代码

注意,因为 Ajax 请求是做局部更新,因此不需要进行转发,也不需要重定向,返回类型是用 void 即可。 

@RequestMapping(value = "/testAjax")
public void testAjax(String username, String password, HttpServletResponse resp) throws IOException {System.out.println("username: " + username + ", password: " + password);resp.getWriter().write("testAjax");return;
}

2、@RequestBody(重点关注“赋值形式”)

@RequestBody 可以获取请求体,在控制器方法设置一个形参,使用 @RequestBody 进行标识,当前请求的请求体就会为当前注解所标识的形参赋值。

需要注意的是,使用了 @RequestBody 后,Ajax 就要发送 POST 请求,而不能发送 GET 请求。可见:https://juejin.cn/post/7222833868503236667

(1)导入依赖 jackson

Spring 默认的 json 解析器就是 jackson,其实没必要导入,但是可以写上。

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.15.2</version>
</dependency>

(2)@RequestBody 的赋值形式

当 @RequestBody 修饰一个方法参数时,会将所有的请求参数都赋值给方法参数。什么意思呢?

假设请求体中的请求参数username : "admin", password : "123456", age : 12

  • 若方法参数为 @RequestBody String user

  • 若方法参数为 @RequestBody User user

  • 若方法参数为 @RequestBody Map<String, Object> map

关于 @RequestBody 与 @RequestParam 的区别 以及 是否添加 @RequestBody 注解,这两个问题也很重要。

可以参考:https://blog.csdn.net/weixin_43606226/article/details/106545024

(3)使用注意

仅对使用 JQuery 的情况而言,其他方法(比如:vue)不需要注意。

当我们传递 JSON 格式的数据时:

  • 需要添加 contentType: "application/json";
  • 需要使用 JSON.stringify(data);
<script type="text/javascript">$(function() {$("#ajaxButton").click(function() {var user = {username: "admin",password: "123456",age: 12,};$.ajax({url:"/Demo_Rest/testAjax",data: JSON.stringify(user),contentType: "application/json",type: "post",dataType: "text", /* 返回数据类型 */success: function(data) {alert(data);}});});});
</script>

3、@ResponseBody(经常用)

@ResponseBody 用于标识一个控制器方法,可以将该方法的返回值(String、实体类)直接作为响应体响应到浏览器。

一般情况下,就是将一个 JSON 格式的 json 字符串,响应到客户端,再由客户端浏览器将其解析成 json 对象。而使用了 @ResponseBody 和 @RequestBody 之后,就不是这样的了,具体后面解释。

(1)返回普通字符串的情况

@RequestMapping(value = "/testResponseBody")
@ResponseBody
public String responseBody() {return "success";
}

访问 /testResponseBody,那么就会出现如下结果:

而这显然不是我们之前所编写的 success.html 页面,而仅仅是一个字符串数据。

(2)返回实体类的情况

将 user 的信息发送给服务器,服务器修改 username 后,响应新的 user 信息。

(2-1)index.html

<script type="text/javascript">$(function() {$("#ajaxButton").click(function() {var user = {username: "admin",password: "123456",age: 12,};$.ajax({url:"/Demo_Rest/testResponseBody",data: JSON.stringify(user),contentType: "application/json",type: "post",dataType: "json", /* 返回数据类型 */success: function(data) {alert(data.username);}});});});
</script>

(2-2)Java 代码

@RequestMapping(value = "/testResponseBody")
@ResponseBody
public User responseBody(@RequestBody User user) {System.out.println(user);user.setUsername("wyt");return user;
}

(3)常见的 Java 对象转换为 Json 之后的类型

  • 实体类:Json 对象;
  • Map:Json 对象;
  • List:Json 数组;

4、为什么不用手动接收 JSON 字符串、转换 JSON 字符串

在 SpringMVC 的核心配置文件中开启 mvc 的注解驱动:

<mvc:annotation-driven/>

此时在 HandlerAdaptor 中会自动装配一个消息转换器:MappingJackson2HttpMessageConverter,它是由 JackSon 这个 JSON 解析器提供的,其作用有:

  • 既可以将浏览器传递的请求参数构成的 JSON 字符串转换为 JSON 对象
  • 也可以将响应到浏览器的 Java 对象转换为 JSON 格式的字符串

5、@RestController

实际开发中,@ResponseBody 使用的情况非常多,而我们只需要给控制类写上一个 @RestController,就可以同时起到 @Controller 和 @ResponseBody 的作用。

十、文件上传与下载

文件上传与下载的方式有很多,不一定要用 ResponseEntity 这种方法。

1、ResponseEntity

ResponseEntity 是一个类型,用于控制器方法的返回值类型,该控制器方法的返回值就是响应到浏览器的响应报文。

有关文件上传与下载的步骤,可以查看:https://blog.csdn.net/joyride_run/article/details/132814877

2、文件下载

在此最奉上喜欢的图片(R-C.jpg):

(1)Java 代码 

@RequestMapping(value = "/fileDownload", method = RequestMethod.GET)
public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {// 1.获取要下载的文件名String downloadFilename = "R-C.jpg";// 2.获取ServletContext对象ServletContext servletContext = session.getServletContext();// 3.获取服务器中文件的真实路径String realPath = servletContext.getRealPath("/static/img/" + downloadFilename);// 4.创建输入流InputStream inputStream = new FileInputStream(realPath);// 5.创建字节数组int count = 0;while (count == 0) count = inputStream.available();// 防止数据未送达,导致count=0,但是本地读文件一般不会有这种错误byte[] bytes = new byte[count];// 6.将流读到字节数组中inputStream.read(bytes);// 7.创建HttpHeaders对象设置响应头信息MultiValueMap<String, String> headers = new HttpHeaders();headers.add("Content-Disposition", "attachment;filename=" + downloadFilename);// 8.设置响应状态码HttpStatus statusCode = HttpStatus.OK;// 9.创建ResponseEntity对象ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, statusCode);// 10.关闭输入流inputStream.close();return responseEntity;
}

(2)index.html 

<a th:href="@{/fileDownload}">下载R-C.jpg文件</a>

(3)效果

3、文件上传

(1)如何获取上传的文件信息

  • SpringMVC 将上传的文件封装到 MultipartFile 对象中,通过此对象可以获取文件相关信息
  • 使用 MultipartFile 对象需要配置文件上传解析器
  • 使用 MultipartFile 对象需要引入依赖 commons-fileupload

由于 MultipartResolver 是一个接口,我们需要配置它的实现类 CommonsMulitipartResolver。

<!-- 配置文件上传解析器id 必须为 multipartResolver
-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.5</version>
</dependency>

(2)输出文件名

  • 使用 MultipartFile 的类方法 getOriginalFilename(),可以获取上传文件的文件名。

(2-1)Java 代码

@RequestMapping(value = "/fileUpload", method = RequestMethod.POST)
public String upload(MultipartFile multipartFile) {String filename = multipartFile.getOriginalFilename();System.out.println(filename);return "success";
}

(2-2)index.html

  • 这里有一个很重要的点,就是表单上传文件的 name 的属性值必须要与 MultipartFile 的参数名相同。
<form th:action="@{/fileUpload}" method="post" enctype="multipart/form-data">头像:<input type="file" name="multipartFile"/> <br/><input type="submit" value="上传"/>
</form>

(3)保存文件

  • 保存文件使用 SpringMVC 封装的 transferTo() 方法,则不需要再使用 IO 流进行持久化存储;
  • 因为我们不知道目录之间的分隔符是 / 还是 \,所以可以使用 File.separator;
@RequestMapping(value = "/fileUpload", method = RequestMethod.POST)
public String upload(MultipartFile multipartFile, HttpSession session) throws IOException {// 1.获取上传的文件名String filename = multipartFile.getOriginalFilename();// 2.获取文件保存的路径ServletContext servletContext = session.getServletContext();String dir = servletContext.getRealPath("/static/img/upload");// 3.创建文件对象File file = new File(dir);if (!file.exists()) {file.mkdirs(); // mkdir 只能创建下一级目录}// 4.保存文件String savePath = dir + File.separator + filename;System.out.println(savePath);multipartFile.transferTo(new File(savePath));return "success";
}

4、解决文件重名导致内容覆盖的问题

解决方法:

  • 使用时间戳;
  • 使用 UUID;

(1)使用 UUID

String filename = multipartFile.getOriginalFilename();
String extensionName = filename.substring(filename.lastIndexOf("."));
filename = UUID.randomUUID().toString() + extensionName;

十一、拦截器

SpringMVC 中的拦截器用于拦截控制器方法的执行。作用类似于 Filter,但不是完全相同。

默认情况下,未指定对哪些资源进行拦截,则会拦截所有交给 DispatcherServlet 的请求,比如:对 index 的访问,对 controller 的访问。

1、拦截器的三个方法

SpringMVC 中的拦截器有三个抽象方法:

  • preHandle:控制器方法执行之前执行,其返回值表示对控制器方法的放行(true)或拦截(false);
  • postHandle:控制器方法执行之后执行;
  • afterComplation:处理完视图和模型数据,渲染视图完毕之后执行;

2、拦截器的简单示例

SpringMVC 中的拦截器需要实现 HandlerInterceptor,并且在 SpringMVC 的配置文件中进行配置:

(1)SpringMVC 配置文件

  • 由 SpringMVC 加载,不需要写 id
<!-- 配置拦截器 -->
<mvc:interceptors><bean class="com.demo.interceptor.FirstInterceptor"></bean>
</mvc:interceptors>

(2)FirstInterceptor.java

  • 重写三个方法,其中 preHandle 的返回 false
package com.demo.interceptor;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class FirstInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("FirstInterceptor -- preHandle");return false;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("FirstInterceptor -- postHandle");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("FirstInterceptor -- afterCompletion");}
}

(3)运行结果

访问 index.html,观察页面响应结果和控制台输出:

  • 首页无法访问,以及如下输出

3、拦截器的配置方法

(1)直接嵌套 <bean> 标签

  • 在 SpringMVC 的配置文件中直接写上:
<mvc:interceptors><bean class="com.demo.interceptor.FirstInterceptor"></bean>
</mvc:interceptors>

(2)链接外部 <bean> 

  • <ref> 链接 <mvc:interceptors> 外部的 <bean> 
<bean id="firstInterceptor" class="com.demo.interceptor.FirstInterceptor"/>
<!-- 配置拦截器 -->
<mvc:interceptors><ref bean="firstInterceptor"/>
</mvc:interceptors>

(3)扫描注解方式

  • 在 FirstInterceptor 上添加 @Component,然后直接 <ref>
@Component(value = "firstInterceptor")
public class FirstInterceptor implements HandlerInterceptor {}
<mvc:interceptors><ref bean="firstInterceptor"/>
</mvc:interceptors>

(4)<mvc:interceptor>

它有两个重要的属性:

  • mvc:mapping path ="":表示需要拦截的请求;
  • mvc:exclude-mapping path="":表示不需要拦截的请求;
  • <ref> 和 <bean> 要写在这两个属性之后;

 设置了这两个请求之后,就会按照设置的内容进行拦截,而不是去拦截 DispatcherServlet。

<mvc:interceptors><mvc:interceptor><mvc:mapping path="/*"/><mvc:exclude-mapping path="/static"/><ref bean="firstInterceptor"/></mvc:interceptor>
</mvc:interceptors>

还需要注意,path = " /* ",表示的是,拦截 / 后的一层目录的请求,也就是说 /abc/* 这类请求是无法拦截的。

想要拦截对所有资源的请求,又要求使用 mvc:mapping,那么可以写 path = " /** "。

4、多个拦截器的执行顺序

我们设置两个拦截器:FirstInterceptor、SecondInterceptor。将他们的 preHandler 都设置为放行(true)。

(1)在 SpringMVC 中作如下顺序

  • 先配置 FirstInterceptor,后配置 SecondInterceptor。
<mvc:interceptors><ref bean="firstInterceptor"/><ref bean="secondInterceptor"/>
</mvc:interceptors>

(2)访问 index.html,观察输出

显然可以看出,执行 preHandle() 方法,是按照配置顺序来执行;执行另外 2 个方法,是按照配置的逆序来执行。

5、preHandle 返回 false 的情况

当拦截器 C 的 preHandle() 返回了 false:

  • C 以及 C 之前的拦截器的 preHandle() 都会执行;
  • 所有的 postHandle() 都不执行;
  • C 之前的拦截器的 afterComplation() 都会执行;

十二、控制器方法异常处理

1、异常处理解析器

对于异常处理解析器,我们可以配置,也可以不配置,SpringMVC 已经默认使用了解析器。

  • SpringMVC 提供了一个处理控制器方法执行过程中所出现的异常的接口:HandlerExceptionResolver。
  • HandlerExceptionResolver 接口的实现类有:DefaultHandlerExceptionResolver(SpringMVC 默认使用)和 SimpleMappingExceptionResolver(用户自定义使用)。

在他们的底层实现中,会返回一个 ModelAndView,这代表着我们可以利用 Model 将错误信息保存到 Request 域,还可以利用 View 进行页面跳转。比如:跳转至 error404.html 页面,并显示错误信息。 

2、使用 xml 配置

(1)Java 代码

  • 手动添加一个 1 / 0 的异常。
@RequestMapping(value = "/testException")
public String testException() {int i = 1 / 0;return "success";
}

(2)index.html 以及 error666.html

  • 访问控制器方法
<body><a th:href="@{/testException}">测试异常处理</a>
</body>
  • 展示异常页面
<body><h1>error666 页面</h1>
</body>

(3)配置异常解析器的 View

  • prop 的 key 表示处理器方法执行过程中出现的异常;
  • prop的 value 表示若出现指定异常时,设置一个逻辑视图,跳转到指定页面;
<!-- 配置异常解析器 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"><property name="exceptionMappings"><props><prop key="java.lang.ArithmeticException">error666</prop><!--.... 其他异常--></props></property>
</bean>

(4)运行结果

  • 由于 1 / 0 出现了异常,因此没有转发到 success.html 页面,而是来到了 error666.html 页面。

3、显示域对象的数据

刚才的示例中,只有 View 的功能,现在我们要添加 Model 的功能。

<property> 除了前面的 exceptionMappings,还有一个 exceptionAttribute,他们就是分别表示 View 和 Model:

  • 通过 exceptionAttribute 的 value 设置一个域数据的属性名,、即可通过这个属性名访问异常信息。

(1)SpringMVC 配置文件

  • 添加了 <property name="exceptionAttribute" value="exceptionInfo"/>
<!-- 配置异常解析器 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"><property name="exceptionMappings"><props><prop key="java.lang.ArithmeticException">error666</prop><!--.... 其他异常--></props></property><property name="exceptionAttribute" value="exceptionInfo"/></bean>

(2)error666.html

  • 获取域对象,显示异常信息
<body><h1>error666 页面</h1><p th:text="${exceptionInfo}"></p>
</body>

(3)输出结果

4、使用注解配置

(1)@ControllerAdvice

  • @ControllerAdvice 将当前类标识为异常处理的 Controller。

(2)@ExceptionHandler

  • @ExceptionHandler 有一个 value 属性,需要继承自 Throwable 的异常类的 Class 数组作为属性值,其中传入我们需要处理的异常类的 class 属性。

(3)返回值

  • 如果使用 String,那么返回值可以设置成错误页面的逻辑视图;
  • 如果使用 ModelAndView,就使用 setView 方法设置逻辑视图;

(4)Controller

  • 产生一个 math 异常
@RequestMapping(value = "/testException")
public String testException() {int i = 1 / 0;return "success";
}

(5)ExceptionHandler

  • 由于 Controller 有 math 方面的异常,因此用 ArithmeticException
@ControllerAdvice
public class ExceptionController {@ExceptionHandler(value = {ArithmeticException.class})public String handleException(Model model, Throwable exception) {model.addAttribute("exceptionInfo", exception);return "error666";}
}

(6)运行结果

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

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

相关文章

C/C++陷阱——临时变量的产生和特性

C/C陷阱——临时变量的产生和特性 在学习C常引用时&#xff0c;有这样一段代码引起了我的注意&#xff1a; int a 1; double& b a;当我编译这段代码时&#xff0c;竟然报错了&#xff1a; 按理来说&#xff0c;初始化引用时不能涉及权限的放大&#xff08;如用const in…

Kafka生产者使用案例

本文代码链接&#xff1a;https://download.csdn.net/download/shangjg03/88422633 1.生产者发送消息的过程 首先介绍一下 Kafka 生产者发送消息的过程&#xff1a; 1)Kafka 会将发送消息包装为 ProducerRecord 对象&#xff0c; ProducerRecord 对象包含了目标主题和要发送的…

如何正确维护实验室超声波清洗器?

实验室一直被视为一个严谨而严肃的场所&#xff0c;实验应遵循一定的步骤&#xff0c;使用的设备也经历了详细的选择&#xff0c;如实验室超声波清洗机&#xff0c;其特点远强于一般类型的清洗机。专门负责采购的实验室人员一般对优质服务的实验室超声波清洗机印象深刻&#xf…

计算机毕业设计 无人智慧超市管理系统的设计与实现 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

MySQL学习(二)——MySQL内置函数

文章目录 1. 函数1.1 字符串函数1.2 数值函数1.3 日期函数1.4 流程函数 2. 约束2.1 概述2.2 外键约束2.2.1 外键使用2.2.2 删除/更新行为 1. 函数 和其他编程语言一样&#xff0c;MySQL也有函数的定义。函数 是指一段可以直接被另一段程序调用的程序或代码。 也就意味着&#…

竞赛 深度学习OCR中文识别 - opencv python

文章目录 0 前言1 课题背景2 实现效果3 文本区域检测网络-CTPN4 文本识别网络-CRNN5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习OCR中文识别系统 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;…

xcode打包macos报错:FlutterInputs.xcfilelist 和 FlutterOutputs.xcfilelist

xcode 打包macos的时候&#xff0c;报错如下&#xff1a; Unable to load contents of the file list: ‘macos/ephemeral/FlutterInputs.xcfilelist’ ‘macos/ephemeral/FlutterOutputs.xcfilelist’ 解决方案&#xff1a; 我的项目macos下没有找到FlutterInputs.xcfilelis…

k8s-10 cni 网络

k8s通过CNI接口接入其他网络插件来实现网络通讯。目前比较流行的插件有flannel,calico等。 CNI插件存放位置: # cat /etc/cni/net.d/10-flannel.conflist 插件使用的解决方案如下: 虚拟网桥&#xff0c;虚拟网卡&#xff0c;多个容器共用一个虚拟网卡进行通信。多路复用: Mac…

零经验想跳槽转行网络安全,需要准备什么?

最近在后台看到很多私信都是有关转行网络安全的问题&#xff0c;目前咨询最多的都是&#xff1a;觉得现在的工作没有发展空间&#xff0c;替代性强&#xff0c;工资低&#xff0c;想跳槽转行网络安全。其中&#xff0c;他们主要关心的是&#xff1a;没有经验怎么学习&#xff1…

2022最新版-李宏毅机器学习深度学习课程-P14 批次(batch)与动量(momentum)

一、batch 回顾epoch、shuffle batch size大还是小&#xff1f;都有好处 大batchsize的好处 由于GPU有并行计算的能力&#xff0c;左边并不一定用时更长 反而是&#xff0c;batch size小的时候&#xff0c;要跑完一个epoch所用的update时间更长&#xff0c;所以时间方面的比较…

java 两个list比较,删除相同的元素

概述 在Java开发中&#xff0c;经常需要比较两个List并删除相同的元素。本文将介绍整个流程&#xff0c;并提供相应的代码示例&#xff0c;帮助新手开发者完成这个任务。 流程 下面是比较两个List并删除相同元素的流程&#xff1a; 代码示例 创建两个List 我们首先需要创建两…

[开源]企业级流程中心,基于flowable和bpmn.js封装的流程引擎

一、开源项目简介 企业级流程中心&#xff08;基于flowable和bpmn.js封装的流程引擎&#xff0c;采用Springboot&#xff0c;Mybatis-plus, Ehcache, sa-token 等框架技术,前端采用Vue3&Antd&#xff0c;Vben&#xff09;。 二、开源协议 使用Apache-2.0开源协议 三、界…

docker 复习

文章目录 docker 安装配置镜像加速器拉取镜像的仓库&#xff1a; docker 部署Mysql 镜像命令的详细解释docker 相关命令总结 docker 安装 查看是否安装的镜像已经在系统中存在&#xff1a; docker images &#xff08;存在2&#xff0c;不存在 3&#xff09; 卸载旧版本 yum r…

技术分享:深入浅出讲解GLSB是什么?

在互联网早期&#xff0c;由于网络不是很发达&#xff0c;流量也相对比较小&#xff0c;单体架构已经能足够满足需求。但伴随着互联网越来越&#xff0c;网站的流量请求甚至能达到上千亿。为了实现高可用&#xff0c;需要用到多台机器来提升处理流量的能力。在这种环境下&#…

C++项目实战——基于多设计模式下的同步异步日志系统-⑫-日志宏全局接口设计(代理模式)

文章目录 专栏导读日志宏&全局接口设计全局接口测试项目目录结构整理示例代码拓展示例代码 专栏导读 &#x1f338;作者简介&#xff1a;花想云 &#xff0c;在读本科生一枚&#xff0c;C/C领域新星创作者&#xff0c;新星计划导师&#xff0c;阿里云专家博主&#xff0c;C…

DevExpress Reporting中文教程 - 如何在macOS等系统中生成导出报表文档

DevExpress Reporting是.NET Framework下功能完善的报表平台&#xff0c;它附带了易于使用的Visual Studio报表设计器和丰富的报表控件集&#xff0c;包括数据透视表、图表&#xff0c;因此您可以构建无与伦比、信息清晰的报表。 在本文中&#xff0c;我们将讨论如何在.NET MA…

如何制作有专业水准的的电子杂志:专家教你秘籍

​随着数字化时代的到来&#xff0c;电子杂志作为一种新型的传媒形式&#xff0c;越来越受到人们的关注和喜爱。但是&#xff0c;如何制作一份具有专业水准的电子杂志呢&#xff1f; 今天&#xff0c;给大家分享一款在线就能制作的电子杂志------FLBOOK&#xff0c;让你轻松打造…

宝塔面板部署express以及MySql项目

第一次在宝塔面板上部署express和MySql项目&#xff0c;部署过程一直跑不通接口&#xff0c;特此记录一下。 在部署的时候&#xff0c;建议第一步把数据库MySql给跑通&#xff0c;中间好多原因是由于数据库的原因给引起的。 一.连接数据库 &#xff08;1&#xff09;在宝塔面…

CSS变量 var()的用法

写在前面 这里介绍一下开发中常用的css变量var()&#xff0c;它可以实现样式的动态设置&#xff0c;使用方法主要分为全局使用和局部使用两种。 如何定义CSS变量var() 在CSS文件中&#xff0c;变量需要使用 – 作为前缀来定义&#xff0c;后面跟上变量名和值&#xff0c;如&a…

从0开始学go第八天

gin获取URL路径参数 package main//获取path&#xff08;URL&#xff09;参数 import ("net/http""github.com/gin-gonic/gin" )func main() {r : gin.Default()r.GET("/:name/:age", func(c *gin.Context) {//获取路径参数name : c.Param(&quo…