SpringMVC 进阶

SpringMVC 进阶

一、拦截器

SpringMVC 中 Interceptor 拦截器的主要作⽤是拦截⽤⼾的请求并进⾏相应的处理。⽐如通过它来进⾏权限验证,或者是来判断⽤⼾是否登陆等操作。对于 SpringMVC 拦截器的定义⽅式有两种:

实现接⼝:org.springframework.web.servlet.HandlerInterceptor

继承适配器:org.springframework.web.servlet.handler.HandlerInterceptorAdapter

1.拦截器实现

实现 HandlerInterceptor 接⼝
/*** 拦截器的实现*  实现 HandlerInterceptor 接口*/
public class MyInterceptor01 implements HandlerInterceptor {/*** 在目标Handler(方法)执行前执行*      返回true:执行Handler方法*      返回false:阻止目标Handler执行* @param request* @param response* @param handler* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("目标Handler执行前执行MyInterceptor01 --> preHandle方法...");/*** 返回true:执行Handler方法* 返回false:阻止目标Handler执行*/return true;}/*** 在 目标Handler(方法)执行后,视图生成前 执行* @param request* @param response* @param handler* @param modelAndView* @throws Exception*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("目标Handler执行后,视图生成前执行MyInterceptor01 --> postHandle方法...");}/*** 在 目标Handler(方法)执行后,视图生成后 执行* @param request* @param response* @param handler* @param ex* @throws Exception*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("目标Handler执行后,视图生成后执行MyInterceptor01 --> afterCompletion方法...");}
}
拦截器xml配置
<!-- 拦截器配置:方式一 --><mvc:interceptors><!--使用bean标签定义一个Interceptor直接定义在mvc:interceptors标签中,表示拦截器会拦截所有的请求--><bean class="com.xxxx.springmvc.interceptor.MyInterceptor01"/></mvc:interceptors>
<!-- 拦截器配置:方式二 (推荐使用) --><mvc:interceptors><!--定义在 mvc:interceptor 标签中,可以自定义需要被拦截的请求。可以定义多个拦截器。如果有多个拦截器,则会根据配置的先后顺序来执行--><mvc:interceptor><!-- 通过 mvc:mapping 配置需要被拦截的资源。支持通配符。可配置多个。 --><!-- "/**"表示拦截所有的请求 --><mvc:mapping path="/**"/><!-- 通过 mvc:exclude-mapping 标签配置不需要拦截的资源。支持通配符。可配置多个。--><!--"/url/"表示url路径下的所有资源 --><mvc:exclude-mapping path="/url/*"/><bean class="com.xxxx.springmvc.interceptor.MyInterceptor01"/></mvc:interceptor></mvc:interceptors>
继承 HandlerInterceptorAdapter

实际上最终还是 HandlerInterceptor 接⼝实现。

子类实现类
/*** 拦截器实现*      继承 HandlerInterceptorAdapter 适配器*/
public class MyInterceptor02 extends HandlerInterceptorAdapter {/*** 在 目标Handler(方法)执行前 执行*      返回true:执行Handler方法*      返回false:阻止目标Handler执行* @param request* @param response* @param handler* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("目标Handler执行前执行MyInterceptor02 --> preHandle方法...");return true;}/*** 在 目标Handler(方法)执行后,视图生成前 执行* @param request* @param response* @param handler* @param modelAndView* @throws Exception*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("目标Handler执行后,视图生成前执行MyInterceptor02 --> postHandle方法...");}/*** 在 目标Handler(方法)执行后,视图生成后 执行* @param request* @param response* @param handler* @param ex* @throws Exception*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("目标Handler执行后,视图生成后执行MyInterceptor02 --> afterCompletion方法...");}
}
拦截器xml配置
<mvc:interceptors><mvc:interceptor><!-- 拦截的资源 --><mvc:mapping path="/**"/><!-- 放行的资源 --><mvc:exclude-mapping path="/url/test01"/><mvc:exclude-mapping path="/url/test02"/><bean class="com.xxxx.springmvc.interceptor.MyInterceptor02"/></mvc:interceptor>
</mvc:interceptors>
多个拦截器实现

SpringMVC 框架⽀持多个拦截器配置,从⽽构成拦截器链,对客⼾端请求进⾏多次拦截操作。

拦截器代码实现

这⾥参考MyInterceptor01、MyInterceptor02代码

拦截器xml配置
<mvc:interceptors><!--拦截器链(多个拦截器)如果有多个拦截满足拦截的要求,则会根据配置的先后顺序执行先配置的拦截器的 preHandle方法,先执行先配置的拦截器的 postHandle、afterCompletion方法,后执行--><mvc:interceptor><mvc:mapping path="/**"/><bean class="com.xxxx.springmvc.interceptor.MyInterceptor02"/></mvc:interceptor><mvc:interceptor><mvc:mapping path="/**"/><bean class="com.xxxx.springmvc.interceptor.MyInterceptor01"/></mvc:interceptor></mvc:interceptors>

2.拦截器应用 - 非法请求拦截

使⽤拦截器完成⽤⼾是否登录请求验证功能

用户控制器

UserInfoController 定义

/*** 用户模块*      用户登录 (不需要拦截)*      用户添加 (需要拦截)*      用户更新 (需要拦截)*      用户删除 (需要拦截)*/
@Controller
@RequestMapping("/userInfo")
public class UserInfoController {/*** 用户登录* @return*/@RequestMapping("/login")public ModelAndView userLogin(HttpSession session){System.out.println("用户登录...");ModelAndView modelAndView = new ModelAndView();// 设置视图modelAndView.setViewName("success");// 如果用户登录,则设置用户对象到session作用域中User user = new User();user.setId(1);user.setUserName("admin");user.setUserPwd("123456");session.setAttribute("user", user);return modelAndView;}/*** 用户添加* @return*/@RequestMapping("/add")public ModelAndView userAdd(){System.out.println("用户添加...");ModelAndView modelAndView = new ModelAndView();// 设置视图modelAndView.setViewName("success");return modelAndView;}/*** 用户更新* @return*/@RequestMapping("/update")public ModelAndView userupdate(){System.out.println("用户更新...");ModelAndView modelAndView = new ModelAndView();// 设置视图modelAndView.setViewName("success");return modelAndView;}/*** 用户删除* @return*/@RequestMapping("/delete")public ModelAndView userDelete(){System.out.println("用户删除...");ModelAndView modelAndView = new ModelAndView();// 设置视图modelAndView.setViewName("success");return modelAndView;}
}
页面定义

success.jsp 定义

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body><h3>登录页面</h3>
</body>
</html>
非法请求拦截器定义

LoginInterceptor 定义

public class LoginInterceptor extends HandlerInterceptorAdapter {/*** 在 目标方法执行前 执行* @param request* @param response* @param handler* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 获取session作用域中的user对象User user = (User) request.getSession().getAttribute("user");// 判断session作用域的user对象是否为空if (user == null){ // 如果为空,表示用户未登录// 拦截请求并跳转到登录页面response.sendRedirect(request.getContextPath() + "/login.jsp");// 不执行目标方法return false;}// 执行目标方法return true;}
}
拦截器xml配置

servlet-context.xml 配置

<!-- 非法访问拦截 拦截器 -->
<mvc:interceptors><mvc:interceptor><!-- 拦截所有请求 --><mvc:mapping path="/**"/><mvc:exclude-mapping path="/userInfo/login"/><mvc:exclude-mapping path="/uploadFile"/><mvc:exclude-mapping path="/uploadFiles"/><bean class="com.xxxx.springmvc.interceptor.LoginInterceptor"/></mvc:interceptor>
</mvc:interceptors>

二、文件上传

1.环境配置

pom.xml文件修改
    <!-- 添加 commons-fileupload 依赖 --><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.2</version></dependency>
servlet-context.xml修改
<!-- 文件上传 --><bean id="multipartResolver"class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><!-- 允许文件上传的最大尺寸 --><property name="maxUploadSize"><value>104857600</value></property><!--设置文件放入临时文件夹的最大大小限制。此值是阈值,低于此值,则保存在内存中,如高于此值,则生成硬盘上的临时文件。--><property name="maxInMemorySize"><value>4096</value></property></bean>

2.代码实现

单文件上传
页面表单

input 的type设置为file

form 表单的method设为post

form 表单的enctype设置为multipart/form-data,以⼆进制的形式传输数据

<form method="post" action="uploadFile" enctype="multipart/form-data"><input type="file" name="file"/><button>上传</button>
</form>
代码实现
/*** 单文件上传** @return*/
@Controller
public class FileController {@RequestMapping("/uploadFile")public String uploadFile(HttpServletRequest request, @RequestParam("file") MultipartFile file) {// 判断文件是否为空,如果不为空则进行对应的文件上传操作if (!file.isEmpty()) {try {// 获取项目所在的路径 (绝对路径)String path = request.getServletContext().getRealPath("/");// 设置上传文件存放的目录File uploadFile = new File(path + "/upload");// 判断文件目录是否存在,如果不存在则新建对应的目录if (!uploadFile.exists()) {// 新建目录uploadFile.mkdir();}// 获取上传文件的文件名String originalName = file.getOriginalFilename();// 获取上传文件的后缀名String suffix = originalName.substring(originalName.lastIndexOf("."));// 通过系统当前时间的毫秒数,生成随机的文件名String fileName = System.currentTimeMillis() + suffix;// 上传文件 (转存文件到指定目录)file.transferTo(new File(uploadFile, fileName));// 如果上传成功,设置作用域request.setAttribute("msg", "文件上传成功!");} catch (IOException e) {e.printStackTrace();// 如果上传失败,设置作用域request.setAttribute("msg", "文件上传失败!");}} else {// 如果上传文件不存在,设置作用域request.setAttribute("msg", "文件不存在!");}return "result";}
}
多文件件上传
页面表单
    <form method="post" action="uploadFiles" enctype="multipart/form-data"><input type="file" name="files"/><input type="file" name="files"/><button>上传</button></form>
代码实现
 @RequestMapping("/uploadFiles")public String uploadFiles(HttpServletRequest request, @RequestParam("files") List<MultipartFile> files){// 判断文件集合是否为空if (files != null && files.size() > 0) {for (MultipartFile file : files ) {// 上传文件saveFile(file, request);}}return "result";}/*** 上传文件* @param file* @param request*/public void saveFile(MultipartFile file, HttpServletRequest request) {// 判断文件是否为空,如果不为空则进行对应的文件上传操作if (!file.isEmpty()) {try {// 获取项目所在的路径 (绝对路径)String path = request.getServletContext().getRealPath("/");// 设置上传文件存放的目录File uploadFile = new File(path + "/upload");// 判断文件目录是否存在,如果不存在则新建对应的目录if (!uploadFile.exists()) {// 新建目录uploadFile.mkdir();}// 获取上传文件的文件名String originalName = file.getOriginalFilename();// 获取上传文件的后缀名String suffix = originalName.substring(originalName.lastIndexOf("."));// 通过系统当前时间的毫秒数,生成随机的文件名String fileName = System.currentTimeMillis() + suffix;// 上传文件 (转存文件到指定目录)file.transferTo(new File(uploadFile, fileName));// 如果上传成功,设置作用域request.setAttribute("msg","文件上传成功!");} catch (IOException e) {e.printStackTrace();// 如果上传失败,设置作用域request.setAttribute("msg","文件上传失败!");}} else {// 如果上传文件不存在,设置作用域request.setAttribute("msg","文件不存在!");}}

三、SSM 框架集成与测试

1.环境配置

配置 pom.xml
修改 JDK 版本
  <properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties>
添加坐标依赖
<dependencies><!-- junit 测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- spring 核心jar --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.4.RELEASE</version></dependency><!-- spring 测试jar --><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.2.4.RELEASE</version></dependency><!-- spring jdbc --><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.4.RELEASE</version></dependency><!-- spring事物 --><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.2.4.RELEASE</version></dependency><!-- aspectj切面编程的jar --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.5</version></dependency><!-- c3p0 连接池 --><dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.5.2</version></dependency><!-- mybatis --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.3</version></dependency><!-- 添加mybatis与Spring整合的核心包 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.3</version></dependency><!-- mysql 驱动包 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.19</version></dependency><!-- 日志打印相关的jar --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.2</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.2</version></dependency><!-- 分页插件 --><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.1.10</version></dependency><!-- spring web --><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.2.4.RELEASE</version></dependency><!-- spring mvc --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.4.RELEASE</version></dependency><!-- web servlet --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.0.1</version></dependency><!-- 添加json 依赖jar包(注意版本问题) --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.10.0</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.10.0</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.10.0</version></dependency><!-- commons-fileupload --><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.2</version></dependency></dependencies>
设置资源目录和插件
<build><finalName>ssm</finalName><!--Maven 项目:如果源代码(src/main/java)存在xml、properties、tld 等文件Maven 默认不会自动编译该文件到输出目录,如果要编译源代码中xml properties tld 等文件需要显式配置 resources 标签--><resources><resource><directory>src/main/resources</directory></resource><resource><directory>src/main/java</directory><includes><include>**/*.xml</include><include>**/*.properties</include><include>**/*.tld</include></includes><filtering>false</filtering></resource></resources><plugins><!-- 编译环境插件 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.3.2</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><!-- jetty插件 --><plugin><groupId>org.eclipse.jetty</groupId><artifactId>jetty-maven-plugin</artifactId><version>9.4.27.v20200227</version><configuration><scanIntervalSeconds>10</scanIntervalSeconds><!-- 设置端口 --><httpConnector><port>8080</port></httpConnector><!-- 设置项目路径 --><webAppConfig><contextPath>/ssm</contextPath></webAppConfig></configuration></plugin></plugins></build>
配置 web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="3.0"xmlns="http://java.sun.com/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"><!-- 启动spring容器--><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring.xml</param-value></context-param><!-- 设置监听器 --><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- 编码过滤 utf-8 --><filter><description>char encoding filter</description><filter-name>encodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param></filter><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!-- servlet请求分发器 --><servlet><servlet-name>springMvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:servlet-context.xml</param-value></init-param><!-- 表示启动容器时初始化该Servlet --><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>springMvc</servlet-name><!-- 这是拦截请求, "/"代表拦截所有请求,"*.do"拦截所有.do请求 --><url-pattern>/</url-pattern><!--<url-pattern>*.do</url-pattern>--></servlet-mapping></web-app>
配置 servlet-context.xml
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!-- 开启扫描器 --><context:component-scan base-package="com.xxxx.ssm.controller" /><!-- mvc 注解驱动 并添加json 支持 --><mvc:annotation-driven><mvc:message-converters><!-- 返回信息为字符串时 处理 --><bean class="org.springframework.http.converter.StringHttpMessageConverter"/><!-- 将对象转换为json 对象 --><bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/></mvc:message-converters></mvc:annotation-driven><!-- 使用默认的 Servlet 来响应静态文件 --><mvc:default-servlet-handler/><!-- 配置视图解析器 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"id="internalResourceViewResolver"><!-- 前缀:在WEB-INF目录下的jsp目录下 --><property name="prefix" value="/WEB-INF/jsp/"/><!-- 后缀:以.jsp结尾的资源 --><property name="suffix" value=".jsp"/></bean><!-- 文件上传 --><bean id="multipartResolver"class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><!-- 允许文件上传的最大尺寸 --><property name="maxUploadSize"><value>104857600</value></property><!--设置文件放入临时文件夹的最大大小限制。此值是阈值,低于此值,则保存在内存中,如高于此值,则生成硬盘上的临时文件。--><property name="maxInMemorySize"><value>4096</value></property></bean></beans>
配置 spring.xml

在项⽬的 src/main/resources 下创建 spring.xml ⽂件, 内容如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd"><!-- 扫描基本包 --><context:component-scan base-package="com.xxxx.ssm" ><!--  context:exclude-filter标签:排除对某个注解的扫描 (过滤controller层) --><context:exclude-filter type="annotation"expression="org.springframework.stereotype.Controller" /></context:component-scan><!-- 加载properties 配置文件 --><context:property-placeholder location="classpath:db.properties" /><!-- aop --><aop:aspectj-autoproxy /><!-- 配置c3p0 数据源 --><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="${jdbc.driver}"></property><property name="jdbcUrl" value="${jdbc.url}"></property><property name="user" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></bean><!-- 配置事务管理器 --><bean id="txManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property></bean><!-- 设置事物增强 --><tx:advice id="txAdvice" transaction-manager="txManager"><tx:attributes><tx:method name="add*" propagation="REQUIRED" /><tx:method name="insert*" propagation="REQUIRED" /><tx:method name="update*" propagation="REQUIRED" /><tx:method name="delete*" propagation="REQUIRED" /></tx:attributes></tx:advice><!-- aop 切面配置 --><aop:config><aop:pointcut id="servicePointcut"expression="execution(* com.xxxx.ssm.service..*.*(..))" /><aop:advisor advice-ref="txAdvice" pointcut-ref="servicePointcut" /></aop:config><!-- 配置 sqlSessionFactory --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"></property><property name="configLocation" value="classpath:mybatis.xml" /><property name="mapperLocations" value="classpath:com/xxxx/ssm/mapper/*.xml" /></bean><!-- 配置扫描器 --><bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer"><!-- 扫描com.xxxx.ssm.dao这个包以及它的子包下的所有映射接口类 --><property name="basePackage" value="com.xxxx.ssm.dao" /><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /></bean>
</beans>
配置 mybatis.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><typeAliases><package name="com.xxxx.ssm.po"/></typeAliases><plugins><plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin></plugins>
</configuration>
配置 db.properties

在项⽬的 src/main/resources 下创建 db.properties ⽂件,内容如下(mysql 创建数据库ssm)

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
jdbc.username=root
jdbc.password=root
添加 log4j.properties

在项⽬的 src/main/resources 下创建 log4j.properties ⽂件,内容如下

log4j.rootLogger=DEBUG, Console
# Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

2.添加源代码

添加包

在项⽬的 src/main/java 下创建对应的包结构

com.xxxx.ssm.controller

com.xxxx.ssm.service

com.xxxx.ssm.mapper

com.xxxx.ssm.dao

com.xxxx.ssm.po

添加 User.java

在 com.xxxx.ssm.po 包下创建 JavaBean ⽂件 User.java (数据库字段对应如下)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

public class User {private Integer userId;private String userName;private String userPwd;private String userEmail;private Date createDate;private Date updateDate;
}
添加UserDao.java 接口

com.xxxx.ssm.dao 包下创建 UserDao.java ⽂件,提供对应的⽤⼾详情查询功能

public interface UserDao {User queryUserByUserId(Integer userId);
}
添加UserMapper.xml 映射文件

com.xxxx.ssm.mapper 包下创建 UserMapper.xml ⽂件,提供select 查询标签配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xxxx.ssm.dao.UserDao"><select id="queryUserByUserId" parameterType="int" resultType="com.xxxx.ssm.po.User">select user_id as userId,user_name as userName,user_pwd as userPwdfrom tb_userwhere user_id = #{userId}</select>
</mapper>
添加 UserService.java

com.xxxx.ssm.service 包下创建UserService.java ⽂件,提供⽤⼾详情查询⽅法

@Service
public class UserService {// 注入userDao@Autowiredprivate UserDao userDao;public User queryUserByUserId(Integer userId){User user = userDao.queryUserByUserId(userId);return user;}}
添加 HelloController.java

在 com.xxxx.ssm.controller 包下创建 HelloController.java ⽂件

@Controller
public class UserController extends BaseController {// 注入userService@Autowiredprivate UserService userService;@RequestMapping("/hello")public String hello (Model model){// 调用UserService层的方法User user = userService.queryUserByUserId(1);// 将数据存到model对象中model.addAttribute("user",user);return "hello";}}
添加 hello.jsp 视图⽂件

在src/main/webapp/WEB-INF 创建jsp ⽬录,并在该⽬下创建hello.jsp ,展⽰查询的⽤⼾信息

<body>欢迎你,${user.userName}
</body>

四、RestFul URL

模型 - 视图 - 控制器(MVC)是⼀个以设计界⾯应⽤程序为基础的设计思想。

Restful ⻛格的 API 是⼀种软件架构⻛格,设计⻛格⽽不是标准,只是提供了⼀组设计原则和约束条件。它主要⽤于客⼾端和服务器交互类的软件。基于这个⻛格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

在Restful ⻛格中,⽤⼾请求的 url 使⽤同⼀个 url,⽤请求⽅式:get,post,delete,put…等⽅式对请求的处理⽅法进⾏区分,这样可以在前后台分离式的开发中使得前端开发⼈员不会对请求的资源地址产⽣混淆和⼤量的检查⽅法名的⿇烦,形成⼀个统⼀的接⼝。

GET(SELECT):从服务器查询,可以在服务器通过请求的参数区分查询的⽅式。

POST(CREATE):在服务器端新建⼀个资源,调⽤ insert 操作。

PUT(UPDATE):在服务器端更新资源,调⽤ update 操作。

PATCH(UPDATE):在服务器端更新资源(客⼾端提供改变的属性)。(⽬前 jdk7 未实现,tomcat7 不⽀持)。

DELETE(DELETE):从服务器端删除资源,调⽤ delete 语句。

1.SpringMVC 支持 RestFul URL 风格设计

如何使用 Java 构造没有扩展名的RestFul URL ,如 /forms/1?

SpringMVC 是通过 @RequestMapping 及 @PathVariable 注解提供的。

通过如@RequestMapping(value=“/blog /{id}”, method = RequestMethod.DELETE),即可处理 /blog/1 的 delete请求。

2.RestFul URL 映射地址配置

准备环境
添加 Account

在 src/resources/java 对应的 com.xxxx.ssm.po ⽬录下新建 Account.java 实体类

public class Account {private Integer id;private String aname;private String type;private Double money;private Integer userId;private Date createTime;private Date updateTime;private String remark;}
添加 AccountDao

在 src/resources/java 对应的 com.xxxx.ssm.dao ⽬录下新建 AccountDao.java 接⼝类

public interface AccountDao {public Account selectById(Integer id);public int save(Account account);public int update(Account account);public int delete(Integer id);
}
添加 AccountMapper

在 src/resources/java 对应的 com.xxxx.ssm.mapper ⽬录下新建 AccountMapper.xml 映射⽂件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.xxxx.ssm.dao.AccountDao" ><resultMap id="BaseResultMap" type="com.xxxx.ssm.po.Account" ><id column="id" property="id" jdbcType="INTEGER" /><result column="aname" property="aname" jdbcType="VARCHAR" /><result column="type" property="type" jdbcType="VARCHAR" /><result column="money" property="money" jdbcType="DOUBLE" /><result column="user_id" property="userId" jdbcType="INTEGER" /><result column="create_time" property="createTime" jdbcType="DATE" /><result column="update_time" property="updateTime" jdbcType="DATE" /><result column="remark" property="remark" jdbcType="VARCHAR" /></resultMap><sql id="Base_Column_List" >id, aname, type, money, user_id, create_time, update_time, remark</sql><!-- 查询操作 --><select id="selectById" resultMap="BaseResultMap" parameterType="java.lang.Integer" >select<include refid="Base_Column_List" />from tb_accountwhere id = #{id,jdbcType=INTEGER}</select><!-- 删除操作 --><delete id="delete" parameterType="java.lang.Integer" >delete from tb_accountwhere id = #{id,jdbcType=INTEGER}</delete><!-- 添加操作 --><insert id="save" parameterType="com.xxxx.ssm.po.Account" >insert into tb_account<trim prefix="(" suffix=")" suffixOverrides="," ><if test="id != null" >id,</if><if test="aname != null" >aname,</if><if test="type != null" >type,</if><if test="money != null" >money,</if><if test="userId != null" >user_id,</if><if test="createTime != null" >create_time,</if><if test="updateTime != null" >update_time,</if><if test="remark != null" >remark,</if></trim><trim prefix="values (" suffix=")" suffixOverrides="," ><if test="id != null" >#{id,jdbcType=INTEGER},</if><if test="aname != null" >#{aname,jdbcType=VARCHAR},</if><if test="type != null" >#{type,jdbcType=VARCHAR},</if><if test="money != null" >#{money,jdbcType=DOUBLE},</if><if test="userId != null" >#{userId,jdbcType=INTEGER},</if><if test="createTime != null" >#{createTime,jdbcType=DATE},</if><if test="updateTime != null" >#{updateTime,jdbcType=DATE},</if><if test="remark != null" >#{remark,jdbcType=VARCHAR},</if></trim></insert><!-- 更新操作 --><update id="update" parameterType="com.xxxx.ssm.po.Account" >update tb_account<set ><if test="aname != null" >aname = #{aname,jdbcType=VARCHAR},</if><if test="type != null" >type = #{type,jdbcType=VARCHAR},</if><if test="money != null" >money = #{money,jdbcType=DOUBLE},</if><if test="userId != null" >user_id = #{userId,jdbcType=INTEGER},</if><if test="createTime != null" >create_time = #{createTime,jdbcType=DATE},</if><if test="updateTime != null" >update_time = #{updateTime,jdbcType=DATE},</if><if test="remark != null" >remark = #{remark,jdbcType=VARCHAR},</if></set>where id = #{id,jdbcType=INTEGER}</update>
</mapper>
添加 AccountService
@Service
public class AccountService {@Autowiredprivate AccountDao accountDao;public Account selectById(Integer id){return accountDao.selectById(id);}public int saveAccount(Account account){return accountDao.save(account);}public int updateAccount(Account account){return accountDao.update(account);}public int delAccount(Integer id){return accountDao.delete(id);}}
URL 映射地址配置
/*** RestFul URL 配置*      1. 设置请求类型*          GET(查询)     @GetMapping*          DELETE(删除)  @DeleteMapping*          POST(添加)    @PostMapping*          PUT(更新)     @PutMapping*      2. URL设置时,不体现动作行为 (没有动词)*          例如:/account/1、/account/2、/account*      3. 定义参数格式*          1. 路径参数 ( @PathVariable )*          2. json格式 ( @RequestBody )*          3. 普通表单参数*      4. 设置响应数据*          json格式 ( @ResponseBody )*/
@Controller
public class AccountController extends BaseController {@Autowiredprivate AccountService accountService;/*** 查询操作*      传统的 URL 访问:*          http://localhost:8080/ssm/account/queryAccountById?id=1*      RestFul URL 访问:*          @GetMapping("/account/{id}")*          http://localhost:8080/ssm/account/1*      @PathVariable 将形参设置为参数路径,声明在形参前面* @param id* @return*/// @RequestMapping("/account/queryAccountById")@GetMapping("/account/{id}")@ResponseBodypublic Account queryAccountById(@PathVariable  Integer id) {// 设置异常return accountService.selectById(id);}/*** 删除操作* @param id* @return*/@DeleteMapping("/account/{id}")@ResponseBodypublic Map<String,String> deleteAccountById(@PathVariable Integer id) {// 调用service层的删除方法,返回受影响的行数int row = accountService.delAccount(id);// 判断受影响的行数是否大于0Map<String ,String> map = new HashMap<>();if (row > 0) {// 删除成功map.put("code","200");map.put("msg","删除成功!");} else {// 删除失败map.put("code","500");map.put("msg","删除失败!");}return  map;}/*** 添加操作* @param account* @return*/@PostMapping("/account")@ResponseBodypublic Map<String,String> addAccount(@RequestBody Account account) {Map<String ,String> map = new HashMap<>();// 调用service层的添加方法,返回受影响的行数int row = accountService.saveAccount(account);// 判断受影响的行数是否大于0if (row > 0) {// 删除成功map.put("code","200");map.put("msg","添加成功!");} else {// 删除失败map.put("code","500");map.put("msg","添加失败!");}return map;}/*** 更新操作* @param account* @return*/@PutMapping("/account")@ResponseBodypublic Map<String,String> updateAccount(@RequestBody Account account) {Map<String ,String> map = new HashMap<>();// 调用service层的添加方法,返回受影响的行数int row = accountService.updateAccount(account);// 判断受影响的行数是否大于0if (row > 0) {// 删除成功map.put("code","200");map.put("msg","更新成功!");} else {// 删除失败map.put("code","500");map.put("msg","更新失败!");}return map;}
}

五、全局异常统⼀处理

SpringMVC 对于异常处理这块提供了⽀持,通过 SpringMVC 提供的全局异常处理机制,能够将所有类型的异常处理从各处理过程解耦出来,既保证了相关处理过程的功能较单⼀,也实现了异常信息的统⼀处理和维护

全局异常实现⽅式 Spring MVC 处理异常有 3 种⽅式:

  1. 使⽤ Spring MVC 提供的简单异常处理器 SimpleMappingExceptionResolver

  2. 实现 Spring 的异常处理接⼝ HandlerExceptionResolver ⾃定义⾃⼰的异常处理器

  3. 使⽤ @ExceptionHandler 注解实现异常处理

1.异常处理实现

全局异常处理方式一
配置简单异常处理器

配置 SimpleMappingExceptionResolver 对象

<!-- 配置全局异常统⼀处理的 Bean (简单异常处理器) -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- ⻚⾯在转发时出现异常,设置默认的错误⻚⾯ (error代表的是⼀个视图) -->
<property name="defaultErrorView" value="error"></property>
<!-- 异常发⽣时,设置异常的变量名 -->
<property name="exceptionAttribute" value="ex"></property>
</bean>

可以在处理异常的⻚⾯获取异常信息

${ex}
使自定定义异常

参数异常

package com.xxxx.ssm.exception;/*** 自定义异常:参数异常*/
public class ParamsException extends RuntimeException {private Integer code = 300;private String msg = "参数异常!";public ParamsException() {super("参数异常!");}public ParamsException(String msg) {super(msg);this.msg = msg;}public ParamsException(Integer code) {super("参数异常!");this.code = code;}public ParamsException(Integer code, String msg) {super(msg);this.code = code;this.msg = msg;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}
}

业务异常

package com.xxxx.ssm.exception;/*** 自定义异常:业务异常*/
public class BusinessException extends RuntimeException {private Integer code=400;private String msg="业务异常!";public BusinessException() {super("业务异常!");}public BusinessException(String msg) {super(msg);this.msg = msg;}public BusinessException(Integer code) {super("业务异常!");this.code = code;}public BusinessException(Integer code, String msg) {super(msg);this.code = code;this.msg = msg;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}
}
设置⾃定义异常与⻚⾯的映射
<!-- 设置⾃定义异常与⻚⾯的映射 -->
<property name="exceptionMappings">
<props>
<!-- key:⾃定义异常对象的路径; 标签中设置具体的处理⻚⾯的视图名-->
<prop key="com.xxxx.ssm.exception.BusinessException">error</prop>
<prop key="com.xxxx.ssm.exception.ParamsException">error</prop>
</props>
</property>

使⽤ SimpleMappingExceptionResolver 进⾏异常处理,具有集成简单、有良好的扩展性、对已有代码没有⼊侵性等优点,但该⽅法仅能获取到异常信息,若在出现异常时,对需要获取除异常以外的数据的情况不适⽤。

全局异常处理方式二(推荐)
实现 HandlerExceptionResolver 接⼝
/**
* 全局异常统⼀处理
*/
@Component
public class GlobalExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, Object handler, Exception ex) {
ModelAndView mv = new ModelAndView("error");
mv.addObject("ex","默认错误信息");
return mv;
}
}
⾃定义异常处理
/**
* 全局异常统⼀处理
*/
@Component
public class GlobalExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, Object handler, Exception ex) {
ModelAndView mv = new ModelAndView("error");
mv.addObject("ex","默认错误信息");
// 判断是否是⾃定义异常
if (ex instanceof ParamsException) {
mv.setViewName("params_error");
ParamsException e = (ParamsException) ex;
mv.addObject("ex", e.getMsg());
}
if (ex instanceof BusinessException) {
mv.setViewName("business_error");
BusinessException e = (BusinessException) ex;
mv.addObject("ex", e.getMsg());
}
return mv;
}

使⽤实现 HandlerExceptionResolver 接⼝的异常处理器进⾏异常处理,具有集成简单、有良好的扩展性、对已有代码没有⼊侵性等优点,同时,在异常处理时能获取导致出现异常的对象,有利于提供更详细的异常处理信息。

全局异常处理方式三

⻚⾯处理器继承 BaseController

public class BaseController {
@ExceptionHandler
public String exc(HttpServletRequest request,HttpServletResponse response,Exception ex){
request.setAttribute("ex", ex);
if(ex instanceof ParamsException){
return "error_param";
}
if(ex instanceof BusinessException){
return "error_business";
}
return "error";
}
}

使⽤ @ExceptionHandler 注解实现异常处理,具有集成简单、有扩展性好(只需要将要异常处理的 Controller 类继承于 BaseController 即可)、不需要附加Spring 配置等优点,但该⽅法对已有代码存在⼊侵性(需要修改已有代码,使相关类继承于 BaseController),在异常处理时不能获取除异常以外的数据。

2.未捕获异常的处理

在 web.xml 中通过(Websphere/Weblogic)或者(Tomcat)节点配置特定异常情况的显⽰⻚⾯。

  <!-- 出错页面定义 --><error-page><exception-type>java.lang.Throwable</exception-type><location>/500.jsp</location></error-page><error-page><error-code>404</error-code><location>/404.jsp</location></error-page><error-page><error-code>500</error-code><location>/500.jsp</location></error-page>

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

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

相关文章

【Linux网络】从原理到实操,感受PXE无人值守自动化高效批量网络安装系统

一、PXE网络批量装机的介绍 1、常见的三种系统安装方式 2、回顾系统安装的过程&#xff0c;了解系统安装的必要条件 3、什么是pxe 4、搭建pxe的原理 5、Linux的光盘镜像中的isolinux中的相关文件学习 二、关于实现PXE无人值守装机的四大文件与五个软件的对应关系详解 5个…

超详细~25考研规划~感恩现在努力的你!!!

25考研规划 俄语&#xff0c;翻译过来叫我爱你 考试时间 第一天 8.30-11.30政治——100分 2.00-5.00英语——100分 第二天 8.30-11.30数学——150分 2.00-5.00专业课——150分 1.什么是25考研 将在2024年12月参加考研&#xff0c;2025年本科毕业&#xff0c;9月读研究…

探索Scrapy中间件:自定义Selenium中间件实例解析

简介 Scrapy是一个强大的Python爬虫框架&#xff0c;可用于从网站上抓取数据。本教程将指导你创建自己的Scrapy爬虫。其中&#xff0c;中间件是其重要特性之一&#xff0c;允许开发者在爬取过程中拦截和处理请求与响应&#xff0c;实现个性化的爬虫行为。 本篇博客将深入探讨…

SpringCloud 微服务全栈体系(十四)

第十一章 分布式搜索引擎 elasticsearch 四、RestAPI ES 官方提供了各种不同语言的客户端&#xff0c;用来操作 ES。这些客户端的本质就是组装 DSL 语句&#xff0c;通过 http 请求发送给 ES。官方文档地址&#xff1a;https://www.elastic.co/guide/en/elasticsearch/client/…

Python 自动化(十八)admin后台管理

admin后台管理 什么是admin后台管理 django提供了比较完善的后台数据库的接口&#xff0c;可供开发过程中调用和测试使用 django会搜集所有已注册的模型类&#xff0c;为这些模型类提供数据管理界面&#xff0c;供开发使用 admin配置步骤 创建后台管理账号 该账号为管理后…

程序员带你入门人工智能

随着人工智能技术的飞速发展&#xff0c;越来越多的程序员开始关注并学习人工智能。作为程序员&#xff0c;我们可能会对如何开始了解人工智能感到困惑。今天&#xff0c;我将向大家介绍一些如何通过自学了解人工智能的经验和方法&#xff0c;帮助大家更好地入门这个充满挑战和…

李沐的学习Pytorch环境配置

https://github.com/Miraclelucy/dive_into_deep_learning/tree/main 上面是别人的笔记 可以学一下。 如果没有梯子&#xff0c;按照清华源配置 清华源conda配置 最好下载 1.11版本torch那一套 然后装d2l版本可以装 pip install d2l0.17.6然后可以用 http://localhost:8889/…

学习笔记6——垃圾回收

学习笔记系列开头惯例发布一些寻亲消息 链接&#xff1a;https://baobeihuijia.com/bbhj/contents/3/190801.html java垃圾回收&#xff08;stop the world&#xff09; 专注于堆和方法区的垃圾回收&#xff0c;年轻代&#xff0c;老年代&#xff0c;永久代判断对象是否还存…

Linux shell编程学习笔记26:stty(set tty)

之前我们探讨了Linux中的tty&#xff0c;tty命令的主要功能是显示当前使用的终端名称。 如果我们想进一步对tty进行设置&#xff0c;就要用到stty。 stty的功能&#xff1a;显示和修改终端特性&#xff08;Print or change terminal characteristics&#xff09;。 1 stty -…

关于新能源汽车的英语翻译

近年来&#xff0c;随着全球对环保和可持续发展的重视&#xff0c;新能源汽车已经成为汽车产业的重要发展方向。各国政府和企业都在加大投入&#xff0c;推动新能源汽车的技术研发和产业化发展&#xff0c;进而促进了新能源汽车翻译的需求不断提升 。那么&#xff0c;关于新能源…

智慧城市安全监控的新利器

在传统的城市管理中&#xff0c;井盖的监控一直是一个难题&#xff0c;而井盖异动传感器的出现为这一问题提供了有效的解决方案。它具有体积小、重量轻、安装方便等特点&#xff0c;可以灵活地应用于各种类型的井盖&#xff0c;实现对城市基础设施的全方位监控。 智能井盖监测终…

Android图片涂鸦,Kotlin(1)

Android图片涂鸦&#xff0c;Kotlin&#xff08;1&#xff09; import android.content.Context import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.graphics.Path import android.graphics.PointF import android.…

RobotFramework之用例执行时添加命令行参数(十三)

学习目录 引言 标签tag 设置变量 随机执行顺序 设置监听器 输出日志目录和文件 引言 Robot Framework 提供了许多命令行选项&#xff0c;可用于控制测试用例的执行方式以及生成的输出。本节介绍一些常用的选项语法。 标签tag 之前文章我们介绍过&#xff0c;在测试套件…

Appium自动化测试:通过appium的inspector功能无法启动app的原因

在打开appium-desktop程序&#xff0c;点击inspector功能&#xff0c;填写app的配置信息&#xff0c;启动服务提示如下&#xff1a; 报错信息&#xff1a; An unknown server-side error occurred while processing the command. Original error: Cannot start the cc.knowyo…

分库分表

分库&#xff0c;分表&#xff0c;分库分表 “只分库“&#xff0c;“只分表“&#xff0c;“既分库又分表" 何时分库 在面对高并发的情况下&#xff0c;数据库连接成为性能瓶颈。当数据QPS过高导致数据库连接数不足时&#xff0c;考虑分库。在读多写少的场景下&#x…

window上Clion配置C++版本的opencv

window上Clion配置opencv 注意版本一定要对的上&#xff0c;否则可能会出错&#xff0c;亲测 widnows 11mingw 8.1.0opencv 4.5.5 mingw8.1下载地址https://sourceforge.net/projects/mingw/ 配置环境变量 cmake下载 安装完添加环境变量 来到官网&#xff0c;下载 windows 对…

性能测试学习——项目环境搭建和Jmete学习二

项目环境搭建、Jmeter学习二 环境的部署虚拟机的安装虚拟机中添加项目操作步骤 使用环境的注意事项Jmeter的安装和简单使用Jemter的使用的进阶Jemter元件 Jmeter属性执行顺序和作用域作用域以自定义用户变量和用户参数(前置处理器)为例如何解决用户变量和线程组同级时&#xff…

字符串函数详解

一.字母大小写转换函数. 1.1.tolower 结合cppreference.com 有以下结论&#xff1a; 1.头文件为#include <ctype.h> 2.使用规则为 #include <stdio.h> #include <ctype.h> int main() {char ch A;printf("%c\n",tolower(ch));//大写转换为小…

【Rust】快速教程——从hola,mundo到所有权

前言 学习rust的前提如下&#xff1a; &#xff08;1&#xff09;先把Rust环境装好 &#xff08;2&#xff09;把VScode中关于Rust的插件装好 \;\\\;\\\; 目录 前言先写一个程序看看Rust的基础mut可变变量let重定义覆盖变量基本数据类型复合类型&#xff08;&#xff09;和 [ …

前端面试:如何实现并发请求数量控制?

题目&#xff1a;实现一个并发请求函数concurrencyRequest(urls, maxNum) 要求如下&#xff1a; 要求最大并发数 maxNum;每当有一个请求返回&#xff0c;就留下一个空位&#xff0c;可以增加新的请求;所有请求完成后&#xff0c;结果按照 urls 里面的顺序依次打出&#xff1b;…