提交 8fdc7004 编写于 作者: W wizardforcel

2019-11-28 22:07:33

上级 f0f4f256
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
> 原文: [https://javatutorial.net/implementing-controllers-in-spring](https://javatutorial.net/implementing-controllers-in-spring) > 原文: [https://javatutorial.net/implementing-controllers-in-spring](https://javatutorial.net/implementing-controllers-in-spring)
控制器在 Spring 中的主要目的是拦截传入的 http 请求,将数据发送到 Model 进行处理,最后从 Model 中获取处理后的数据,然后将完全相同的数据传递给要呈现它的 View 控制器在 Spring 中的主要目的是拦截传入的 http 请求,将数据发送到模型进行处理,最后从模型中获取处理后的数据,然后将完全相同的数据传递给要呈现它的视图
![java-featured-image](img/e0db051dedc1179e7424b6d998a6a772.jpg) ![java-featured-image](img/e0db051dedc1179e7424b6d998a6a772.jpg)
...@@ -10,15 +10,15 @@ ...@@ -10,15 +10,15 @@
![Controllers in Spring example](img/dcf7c2a74fa3d79c38fb40879ce10074.jpg) ![Controllers in Spring example](img/dcf7c2a74fa3d79c38fb40879ce10074.jpg)
春季工作流程 Spring 工作流程
现在,让我们构建一个简单的应用程序,作为在 Spring 中实现控制器的示例。 现在,让我们构建一个简单的应用程序,作为在 Spring 中实现控制器的示例。
当您要“声明”一个类作为控制器时,就像使用 @Controller 对其进行注释一样简单。 在类级别使用时,控制器现在可以处理 REST API 请求。 当您要“声明”一个类作为控制器时,就像使用`@Controller`对其进行注释一样简单。 在类级别使用时,控制器现在可以处理 REST API 请求。
### `GetMapping`注解 ### `GetMapping`注解
当使用 @Controller 注解时,可以通过使用该方法的 RequestMapping 注解来提供请求映射。 还有 @ RequestMapping,@ PostMapping,@ PutMapping 可以简化常见 HTTP 方法类型的映射。 当使用`@Controller`注解时,可以通过使用该方法的`RequestMapping`注解来提供请求映射。 还有`@RequestMapping``@PostMapping``@PutMapping`可以简化常见 HTTP 方法类型的映射。
```java ```java
package com.example.demo; package com.example.demo;
...@@ -46,9 +46,9 @@ public class DemoApplication { ...@@ -46,9 +46,9 @@ public class DemoApplication {
``` ```
上面的代码段,我们创建了一个 DemoApplication,其注释为@Controller 和@SpringBootApplication。 请注意 **@GetRequest(“ /”)**的使用。 这就是说 home()方法将显示注释中放置的内容,在本例中为“ /”,即 http:// localhost:8080 **/。** 上面的代码段,我们创建了一个`DemoApplication`,其注释为`@Controller``@SpringBootApplication`。 请注意`@GetRequest("/")`的使用。 这就是说`home()`方法将显示注释中放置的内容,在本例中为`"/"`,即`http://localhost:8080/`
在示例中,我使用的是 @RestConroller ,它基本上是控制器的专用版本,其中包括 @Controller 和@ ResponseBody 注解。 它只是简化了控制器的实现。 在示例中,我使用的是`@RestConroller`,它基本上是控制器的专用版本,其中包括`@Controller``@ResponseBody`注解。 它只是简化了控制器的实现。
当我们运行上面的代码时,我们得到以下结果: 当我们运行上面的代码时,我们得到以下结果:
...@@ -75,11 +75,11 @@ public class AccountController { ...@@ -75,11 +75,11 @@ public class AccountController {
``` ```
我们在这里所做的是,我们对类 AccountController 和方法 login()都进行了注释。 当访问 http:// localhost:8080 / account /时,我们将被带到登录页面。 请注意网址末尾的“ /”。 如果不存在,例如 http:// localhost:8080 / account,将导致错误。 我们在这里所做的是,我们对类`AccountController`和方法`login()`都进行了注释。 当访问`http://localhost:8080/account/`时,我们将被带到登录页面。 请注意网址末尾的`"/"`。 如果不存在,例如`http://localhost:8080/account`,将导致错误。
我在 account /之后加上“ *的原因是,如果我们想向其添加更多内容(例如注册),则该 URL 将能够处理具有不同路径的所有请求。 我在`account/`之后加上`*`的原因是,如果我们想向其添加更多内容(例如注册),则该 URL 将能够处理具有不同路径的所有请求。
但就目前而言,我们将仅坚持登录。 接下来,我们需要为 Login 创建一个类,并将其注释为@Controller 但就目前而言,我们将仅坚持登录。 接下来,我们需要为登录创建一个类,并将其注释为`@Controller`
```java ```java
package com.example.demo; package com.example.demo;
...@@ -99,4 +99,4 @@ public class Login { ...@@ -99,4 +99,4 @@ public class Login {
``` ```
现在,当我们访问 http:// localhost:8080 / account / login 时,它将返回“ login.jsp”文件中的内容。 现在,当我们访问`http://localhost:8080/account/login`时,它将返回`login.jsp`文件中的内容。
\ No newline at end of file \ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
> 原文: [https://javatutorial.net/pathvariable-annotation-in-spring](https://javatutorial.net/pathvariable-annotation-in-spring) > 原文: [https://javatutorial.net/pathvariable-annotation-in-spring](https://javatutorial.net/pathvariable-annotation-in-spring)
就像@RequestParam 一样,@PathVariable 注解用于从 HTTP request 中提取数据。 但是,它们略有不同。 区别在于@RequestParam 从 URL 获取参数,而@PathVariable 只是从 URI 中提取参数。 就像`@RequestParam`一样,`@PathVariable`注解用于从 HTTP request 中提取数据。 但是,它们略有不同。 区别在于`@RequestParam`从 URL 获取参数,而`@PathVariable`只是从 URI 中提取参数。
![java-featured-image](img/e0db051dedc1179e7424b6d998a6a772.jpg) ![java-featured-image](img/e0db051dedc1179e7424b6d998a6a772.jpg)
...@@ -14,20 +14,20 @@ ...@@ -14,20 +14,20 @@
http://www.yourwebsite.net/employee/1 http://www.yourwebsite.net/employee/1
``` ```
上面的 URL 中的 **1** 代表员工的 ID。 到目前为止,一切都很好。 现在,从您的 Spring 控制器开始,路径看起来像(取决于您给 id 赋予的名称): 上面的 URL 中的`1`代表员工的 ID。 到目前为止,一切都很好。 现在,从您的 Spring 控制器开始,路径看起来像(取决于您给`id`赋予的名称):
```java ```java
/employee/{id} /employee/{id}
``` ```
以上网址路径对我们有何帮助? 好吧,由于有了{}语法(碰巧称为 URI 模板),您现在可以使用@PathVariable 将其传递给方法,并且您的方法以及注释将类似于以下内容: 以上网址路径对我们有何帮助? 好吧,由于有了`{}`语法(碰巧称为 URI 模板),您现在可以使用`@PathVariable`将其传递给方法,并且您的方法以及注释将类似于以下内容:
```java ```java
@RequestMapping(value="/employee/{id}", method=RequestMethod.GET) @RequestMapping(value="/employee/{id}", method=RequestMethod.GET)
<Access Modifier> <Return Type> <Method Name> (@PathVariable <Type> id) { <body> } <Access Modifier> <Return Type> <Method Name> (@PathVariable <Type> id) { <body> }
``` ```
从上面的代码片段中可以看到,现在“ id”将从路径中引用{id}。 让我们尝试一个真实的例子: 从上面的代码片段中可以看到,现在`id`将从路径中引用`{id}`。 让我们尝试一个真实的例子:
```java ```java
@Controller @Controller
...@@ -41,9 +41,9 @@ public class EmployeeManager { ...@@ -41,9 +41,9 @@ public class EmployeeManager {
} }
``` ```
现在,Spring 查看 out id 参数,并将其与模板变量“ id”进行匹配。 现在,Spring 查看`id`参数,并将其与模板变量`id`进行匹配。
请记住,如果我的代码将“ id”(参数)命名为其他名称,则将无法使用。 但是,如果您不想为参数和模板变量使用相同的名称,则可以指定 PathVariable 注解的名称,如下所示: 请记住,如果我的代码将`id`(参数)命名为其他名称,则将无法使用。 但是,如果您不想为参数和模板变量使用相同的名称,则可以指定`PathVariable`注解的名称,如下所示:
```java ```java
@Controller @Controller
...@@ -57,16 +57,16 @@ public class EmployeeManager { ...@@ -57,16 +57,16 @@ public class EmployeeManager {
} }
``` ```
从上面的示例中可以看到,我将参数名称更改为 someRandomName ,但我还添加了@PathVariable **(“ id”)**,它再次指定了我们要引用的模板变量 至 从上面的示例中可以看到,我将参数名称更改为`someRandomName`,但我还添加了`@PathVariable("id")`,它再次指定了我们要引用的模板变量
因此,最终您有两个选择: 因此,最终您有两个选择:
1. 方法参数使用相同的名称 1. 方法参数使用相同的名称
2.@PathVariable 注解中指定模板变量的名称 2.`@PathVariable`注解中指定模板变量的名称
### 多个`@PathVariable`注解 ### 多个`@PathVariable`注解
如果您可以有多个@PathVariable,该怎么办? 我们可以做到吗? 我们可以! 实际上,这与添加单个@PathVariable 非常相似。 如果您可以有多个`@PathVariable`,该怎么办? 我们可以做到吗? 我们可以! 实际上,这与添加单个`@PathVariable`非常相似。
我来给你展示。 我来给你展示。
...@@ -84,13 +84,13 @@ public class EmployeeManager { ...@@ -84,13 +84,13 @@ public class EmployeeManager {
从上面的代码片段中可以看到,我们有两个模板变量: 从上面的代码片段中可以看到,我们有两个模板变量:
1. **公司** 1. `company`
2. **ID** 2. `id`
然后,我们提取每个模板变量,然后通过指定方法参数所引用的临时变量将它们“分配”给方法参数。 然后,我们提取每个模板变量,然后通过指定方法参数所引用的临时变量将它们“分配”给方法参数。
## `@PathVariable` vs `@RequestParam`结论 ## `@PathVariable` vs `@RequestParam`结论
尽管@PathVariable 和@RequestParam 都用于从 URL 提取值,但是可以根据 URL 的设计使用它们。 尽管`@PathVariable``@RequestParam`都用于从 URL 提取值,但是可以根据 URL 的设计使用它们。
通常,@ PathVariable 通常用于 RESTful Web 服务中,而@RequestParam 用于从查询参数中提取数据。 通常,`@PathVariable`通常用于 RESTful Web 服务中,而`@RequestParam`用于从查询参数中提取数据。
\ No newline at end of file \ No newline at end of file
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
> 原文: [https://javatutorial.net/requestbody-annotation-in-spring](https://javatutorial.net/requestbody-annotation-in-spring) > 原文: [https://javatutorial.net/requestbody-annotation-in-spring](https://javatutorial.net/requestbody-annotation-in-spring)
@RequestBody 注解可用于处理 Web 请求。 `@RequestBody`注解可用于处理 Web 请求。
![java-featured-image](img/e0db051dedc1179e7424b6d998a6a772.jpg) ![java-featured-image](img/e0db051dedc1179e7424b6d998a6a772.jpg)
更具体地说,它用于将方法参数与请求的主体绑定,其工作方式是 HttpMessageConverter 根据请求内容的类型转换请求的主体。 更具体地说,它用于将方法参数与请求的主体绑定,其工作方式是`HttpMessageConverter`根据请求内容的类型转换请求的主体。
### 语法 ### 语法
...@@ -24,7 +24,7 @@ public String congratulateEmployee(@RequestBody Employee emp) { ...@@ -24,7 +24,7 @@ public String congratulateEmployee(@RequestBody Employee emp) {
} }
``` ```
包含上述方法的完整 Controller 类: 包含上述方法的完整`Controller`类:
```java ```java
@RestController @RestController
...@@ -41,7 +41,7 @@ public class CongratulationsController { ...@@ -41,7 +41,7 @@ public class CongratulationsController {
} }
``` ```
我们的 Employee 类如下所示: 我们的`Employee`类如下所示:
```java ```java
public class Employee { public class Employee {
...@@ -58,7 +58,7 @@ public class Employee { ...@@ -58,7 +58,7 @@ public class Employee {
} }
``` ```
我们的 Manager 类如下所示: 我们的`Manager`类如下所示:
```java ```java
public class Manager { public class Manager {
...@@ -78,7 +78,7 @@ public class Manager { ...@@ -78,7 +78,7 @@ public class Manager {
就像我上面说的,我们收到的 JSON 格式反序列化为 Java 类型。 就像我上面说的,我们收到的 JSON 格式反序列化为 Java 类型。
当我们说 **@RequestBody Employee emp** 时,我们将 Employee 类型的方法参数与 Web 请求的主体绑定在一起。 RequestBody 到达如下: 当我们说`@RequestBody Employee emp`时,我们将`Employee`类型的方法参数与 Web 请求的主体绑定在一起。`RequestBody`到达如下:
```java ```java
{ {
...@@ -87,14 +87,14 @@ public class Manager { ...@@ -87,14 +87,14 @@ public class Manager {
} }
``` ```
再次感谢 HttpMessageConverter 方法,我们可以将该 RequestBody JSON 响应转换为 Employee 对象,该对象包含公共方法 getName()和 getYearsWorked( )。 这就是为什么我们可以在 RequestBody 参数上调用这些方法的原因: 再次感谢`HttpMessageConverter`方法,我们可以将该`RequestBody` JSON 响应转换为`Employee`对象,该对象包含公共方法`getName()``getYearsWorked()`。 这就是为什么我们可以在`RequestBody`参数上调用这些方法的原因:
```java ```java
String name = emp.getName();  String name = emp.getName(); 
int yearsWorked = emp.getYearsWorked(); int yearsWorked = emp.getYearsWorked();
``` ```
作为该方法的结果,我们返回了类型为“ Manager”的数据,由于 HttpMessageConverter ,我们已将返回类型转换为以下响应格式: 作为该方法的结果,我们返回了类型为`Manager`的数据,由于`HttpMessageConverter`,我们已将返回类型转换为以下响应格式:
```java ```java
{ {
...@@ -102,4 +102,4 @@ int yearsWorked = emp.getYearsWorked(); ...@@ -102,4 +102,4 @@ int yearsWorked = emp.getYearsWorked();
} }
``` ```
附带一提,RequestBody 注释与 RestController 注释一样,主要用于 REST API。 附带一提,`RequestBody`注释与`RestController`注释一样,主要用于 REST API。
\ No newline at end of file \ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
> 原文: [https://javatutorial.net/requestparam-annotation-in-spring](https://javatutorial.net/requestparam-annotation-in-spring) > 原文: [https://javatutorial.net/requestparam-annotation-in-spring](https://javatutorial.net/requestparam-annotation-in-spring)
当我们想在控制器类中读取 Web 请求参数时,将使用 RequestParam 注解。 换句话说,前端正在向我们发送一些带有键的参数(例如,从填充的表单中)。 当我们想在控制器类中读取 Web 请求参数时,将使用`RequestParam`注解。 换句话说,前端正在向我们发送一些带有键的参数(例如,从填充的表单中)。
![java-featured-image](img/e0db051dedc1179e7424b6d998a6a772.jpg) ![java-featured-image](img/e0db051dedc1179e7424b6d998a6a772.jpg)
...@@ -11,22 +11,24 @@ ...@@ -11,22 +11,24 @@
假设我们有一个表单,目的是向数据库中添加一个雇员。 每位员工将具有: 假设我们有一个表单,目的是向数据库中添加一个雇员。 每位员工将具有:
1. ID 1. ID
2. 2.
3. 3.
因此,我们的表单如下所示(假设 ID 不会自动递增): 因此,我们的表单如下所示(假设 ID 不会自动递增):
![Employee Form Example](img/3a6f549458d52b9530ed93f13c65245d.jpg) ![Employee Form Example](img/3a6f549458d52b9530ed93f13c65245d.jpg)
员工表示例 员工表示例
想象一下,上面看起来丑陋的表中填充了以下信息: 想象一下,上面看起来丑陋的表中填充了以下信息:
Id = 1 ```
Id=1
名字=乔 First Name=Joe
姓氏=母鹿 Last Name=Doe
```
现在假设我们有以下代码: 现在假设我们有以下代码:
...@@ -49,9 +51,9 @@ public class EmployeeController { ...@@ -49,9 +51,9 @@ public class EmployeeController {
} }
``` ```
我们只是将 Web 请求参数绑定到方法参数(id,firstName,lastName)。 但是,为了使此示例正常工作,我们需要从前端接收相应的密钥,否则它们将为 null 我们只是将 Web 请求参数绑定到方法参数(`id``firstName``lastName`)。 但是,为了使此示例正常工作,我们需要从前端接收相应的密钥,否则它们将为`null`
在上面的示例代码中,我们为请求参数提供了值,例如@RequestParam(“ id”)。 但是,如果目标变量名称与参数名称相同,则可以忽略该值。 因此,我们可以将上述代码片段进行如下操作: 在上面的示例代码中,我们为请求参数提供了值,例如`@RequestParam("id")`。 但是,如果目标变量名称与参数名称相同,则可以忽略该值。 因此,我们可以将上述代码片段进行如下操作:
```java ```java
@Controller @Controller
...@@ -72,11 +74,11 @@ public class EmployeeController { ...@@ -72,11 +74,11 @@ public class EmployeeController {
} }
``` ```
它之所以起作用,是因为“ id”与我们作为方法参数给出的名称相同,实际上是“ id”。 此外,我们无法对其他参数执行相同的操作,因为“名字”与“名字”不同。 它之所以起作用,是因为`id`与我们作为方法参数给出的名称相同,实际上是`id`。 此外,我们无法对其他参数执行相同的操作,因为`First Name``firstName`不同。
#### `@RequestParam`的必需元素 #### `@RequestParam`的必需元素
RequestParam 还支持“ required”元素,该元素几乎完成了所要表达的内容–它指定是否需要特定的参数。 对于我们的示例,我们可以说名字不是必需的。 默认情况下,requried 将设置为 true `RequestPara`还支持`required`元素,该元素几乎完成了所要表达的内容–它指定是否需要特定的参数。 对于我们的示例,我们可以说名字不是必需的。 默认情况下,`requried`将设置为`true`
```java ```java
@Controller @Controller
...@@ -96,7 +98,7 @@ public class EmployeeController { ...@@ -96,7 +98,7 @@ public class EmployeeController {
} }
``` ```
现在,firstName 不是必需的参数,因此我们没有将其添加到模型/地图中。 现在,`firstName`不是必需的参数,因此我们没有将其添加到模型/地图中。
#### `@RequestParam`还具有`defaultValue`元素 #### `@RequestParam`还具有`defaultValue`元素
...@@ -120,4 +122,4 @@ public class EmployeeController { ...@@ -120,4 +122,4 @@ public class EmployeeController {
} }
``` ```
现在,即使表单没有完全填写(用户省略了姓氏字段),如果我们引用了 lastName 参数,也将在其中存储“ Doe”。 我们为什么要使用“ defaultValue”元素的一个著名示例是日期。 假设我们具有与上面相同的形式,但是那里也有一个“日期”字段。 好吧,如果用户/员工没有在该字段中输入任何内容,我们可以假设是今天,因此我们将今天的日期作为默认值输入。 这只是许多例子中的一个。 现在,即使表单没有完全填写(用户省略了姓氏字段),如果我们引用了`lastName`参数,也将在其中存储`Doe`。 我们为什么要使用`defaultValue`元素的一个著名示例是日期。 假设我们具有与上面相同的形式,但是那里也有一个“日期”字段。 好吧,如果用户/员工没有在该字段中输入任何内容,我们可以假设是今天,因此我们将今天的日期作为默认值输入。 这只是许多例子中的一个。
\ No newline at end of file \ No newline at end of file
...@@ -2,23 +2,23 @@ ...@@ -2,23 +2,23 @@
> 原文: [https://javatutorial.net/interceptors-in-spring](https://javatutorial.net/interceptors-in-spring) > 原文: [https://javatutorial.net/interceptors-in-spring](https://javatutorial.net/interceptors-in-spring)
顾名思义,在春季,拦截器拦截我们通过实现 HandlerInterceptor 接口来请求。 它为我们提供了一些方法,使我们能够拦截控制器类正在处理的传入请求或控制器类已经处理的响应。 顾名思义,在 Spring,拦截器拦截我们通过实现`HandlerInterceptor`接口来请求。 它为我们提供了一些方法,使我们能够拦截控制器类正在处理的传入请求或控制器类已经处理的响应。
![java-featured-image](img/e0db051dedc1179e7424b6d998a6a772.jpg) ![java-featured-image](img/e0db051dedc1179e7424b6d998a6a772.jpg)
接口提供给我们的方法有: 接口提供给我们的方法有:
1. **preHandle()** –返回 true 或 false。 如果返回 true,则处理程序执行链继续,否则停止。 1. `preHandle()` – 返回`true``false`。 如果返回`true`,则处理程序执行链继续,否则停止。
2. **postHandle()**处理程序执行后调用。 2. `postHandle()`处理程序执行后调用。
3. **afterCompletion()**在请求完成并生成视图之后调用。 3. `afterCompletion()`在请求完成并生成视图之后调用。
### `HandlerInterceptor`与`HandlerInterceptorAdapter` ### `HandlerInterceptor`与`HandlerInterceptorAdapter`
首先,我说过我们需要实现 HandlerInterceptor 接口,但是我们也可以实现 HandlerInterceptorAdapter 。 它们之间有 1 个区别,就是 HandlerInterceptor 我们必须覆盖我上面提到的所有三种方法,而 HandlerInterceptorAdapter 允许我们仅覆盖所需的方法 方法。 首先,我说过我们需要实现`HandlerInterceptor`接口,但是我们也可以实现`HandlerInterceptorAdapter`。 它们之间有 1 个区别,就是`HandlerInterceptor`我们必须覆盖我上面提到的所有三种方法,而`HandlerInterceptorAdapter`允许我们仅覆盖所需的方法。
### 代码实现 ### 代码实现
通常,这 3 种方法的工作流程会引发 Exception **或返回 true 的** 通常,这 3 种方法的工作流程会引发`Exception`或返回`true`
```java ```java
@Component @Component
...@@ -57,23 +57,23 @@ public class EmployeeInterceptor implements HandlerInterceptor { ...@@ -57,23 +57,23 @@ public class EmployeeInterceptor implements HandlerInterceptor {
让我们分解上面的代码示例。 让我们分解上面的代码示例。
首先我们创建我们的类并实现 HandlerInterceptor ,因为它会覆盖所有三个方法。 按照惯例,类名必须在初始名称之后具有 **拦截器** 。 然后,我们重写 **preHandle()**方法。 它包含 3 个参数-请求,响应和处理程序,并且不要忘记**引发异常。** 首先我们创建我们的类并实现`HandlerInterceptor`,因为它会覆盖所有三个方法。 按照惯例,类名必须在初始名称之后具有`Interceptor`。 然后,我们重写`preHandle()`方法。 它包含 3 个参数-请求,响应和处理程序,并且不要忘记`throws Exception`
### `preHandle()` ### `preHandle()`
我的 preHandle()方法非常简单–它从请求中获取用户名和密码,然后检查它们是否为空以及是否为空,然后抛出异常,指出“空用户名或密码”。 如果它们不为空,则返回 true。 在正常环境中,您当然会做更多的验证,但是为了简单起见,我这样做了。 我的`preHandle()`方法非常简单–它从请求中获取用户名和密码,然后检查它们是否为空以及是否为空,然后抛出异常,指出“空用户名或密码”。 如果它们不为空,则返回`true`。 在正常环境中,您当然会做更多的验证,但是为了简单起见,我这样做了。
### `postHandle()` ### `postHandle()`
如果没有引发异常并记录请求,我的 postHandle()方法从返回 true 不会起到什么作用。 它包含 4 个参数-请求,响应,处理程序和 modelAndView。 它还**引发异常。** 通常,此方法用于修改 ModelAndView(通常通过添加其他属性)或简单地确定处理程序方法处理客户请求所花费的时间。 如果没有引发异常并记录请求,我的`postHandle()`方法从返回`true`不会起到什么作用。 它包含 4 个参数-请求,响应,处理程序和`modelAndView`。 它还`throws Exception`。通常,此方法用于修改`ModelAndView`(通常通过添加其他属性)或简单地确定处理程序方法处理客户请求所花费的时间。
### `afterCompletion()` ### `afterCompletion()`
我的 afterCompletion()方法记录了请求和异常,但是在此之前,它通过说 **exc!= null** 来检查是否有异常,如果存在,那么我们说 **exc.printStackTrace ()** 我的`afterCompletion()`方法记录了请求和异常,但是在此之前,它通过说`exc != null`来检查是否有异常,如果存在,那么我们说`exc.printStackTrace()`
### 配置 ### 配置
我们的拦截器尚未添加到 Spring 配置中。 要添加它,我们必须实现一个自定义@Configuration 文件,该文件扩展了 WebMvcConfigurerAdapter ,该文件在 addInterceptors 方法内添加了拦截器。 我们的拦截器尚未添加到 Spring 配置中。 要添加它,我们必须实现一个自定义`@Configuration`文件,该文件扩展了`WebMvcConfigurerAdapter`,该文件在`addInterceptors`方法内添加了拦截器。
```java ```java
@Configuration @Configuration
...@@ -85,4 +85,4 @@ public class AppConfig extends WebMvcConfigurerAdapter { ...@@ -85,4 +85,4 @@ public class AppConfig extends WebMvcConfigurerAdapter {
} }
``` ```
另外,请记住,您必须在 addInterceptors 方法中指定适当的路径模式。 另外,请记住,您必须在`addInterceptors`方法中指定适当的路径模式。
\ No newline at end of file \ No newline at end of file
...@@ -51,11 +51,11 @@ public class WithoutIOCDemo { ...@@ -51,11 +51,11 @@ public class WithoutIOCDemo {
``` ```
从该简单示例中可以看到,defineRace 方法依赖于诸如 Human,Sark 和 Mavvek 之类的较低级对象。 从该简单示例中可以看到,`defineRace`方法依赖于诸如`Human``Sark``Mavvek`之类的较低级对象。
**请注意:** 方法 spawn()刚刚组成,我们可以假装它存在并且按照它说的去做。 **请注意**:方法`spawn()`刚刚组成,我们可以假装它存在并且按照它说的去做。
现在,让我们看一下如何通过使用 IOC 并使得 defineRace 方法不依赖于较低级别的对象来获得与上述示例相同的结果。 现在,让我们看一下如何通过使用 IOC 并使得`defineRace`方法不依赖于较低级别的对象来获得与上述示例相同的结果。
## 使用 IOC 的顶层概述代码实现 ## 使用 IOC 的顶层概述代码实现
...@@ -81,8 +81,8 @@ public class WithIOCDemo { ...@@ -81,8 +81,8 @@ public class WithIOCDemo {
} }
``` ```
乍一看,这种方法为我们节省了很多代码行,而且确实如此。 但是更详细一点,这也使我们的**确定 RaceAndSpawn()**方法不依赖于可用的 **Creature** 种族(人类,萨克和 Mavvek(请参考上面的示例))。 “不依赖”是指与没有 IOC 实现的示例不同,我们的方法不需要在 方法中实例化相应的**生物** **。 现在所有方法所做的就是生成生物。** 乍一看,这种方法为我们节省了很多代码行,而且确实如此。 但是更详细一点,这也使我们的`determineRaceAndSpawn()`方法不依赖于可用的`Creature`种族(人类,Sark 和 Mavvek(请参考上面的示例))。 “不依赖”是指与没有 IOC 实现的示例不同,我们的方法不需要在方法中实例化相应的**生物**。 现在所有方法所做的就是生成生物。
简而言之,我们消除了 **和** 实例化生物**以及产生**的负担。 现在,它只会生成它。 简而言之,我们消除了实例化以及生成生物的负担。 现在,它只会生成它。
因此,如果将函数从**确定 RaceAndSpawn()**重命名为: **spawnCreature(),这将是有意义的。** 因此,如果将函数从`determineRaceAndSpawn()`重命名为:`spawnCreature()`,这将是有意义的。
\ No newline at end of file \ No newline at end of file
...@@ -15,9 +15,9 @@ IoC 容器是 Spring 中的一个框架,用于管理 POJO(普通的旧 Java ...@@ -15,9 +15,9 @@ IoC 容器是 Spring 中的一个框架,用于管理 POJO(普通的旧 Java
1. 通过将它们作为参数传递给构造函数 1. 通过将它们作为参数传递给构造函数
2. 通过将它们作为参数传递给对象的 setter 方法 2. 通过将它们作为参数传递给对象的 setter 方法
Spring IoC 容器的基础有两个软件包: **org.springframework.beans****org.springframework.context** Spring IoC 容器的基础有两个软件包:`org.springframework.beans``org.springframework.context`
[BeanFactory](https://docs.spring.io/spring/docs/1.2.x/reference/beans.html) 接口管理许多 Bean,同时,这些 Bean 之间也具有依赖关系。 它提供了基本功能,更重要的是,它提供了 **ApplicationContext** ,它是 BeanFactory 的子接口。 在应用程序运行时,它是只读的;如果实现允许并管理 Bean 的生命周期,则可以重新加载它。 [`BeanFactory`](https://docs.spring.io/spring/docs/1.2.x/reference/beans.html) 接口管理许多 Bean,同时,这些 Bean 之间也具有依赖关系。 它提供了基本功能,更重要的是,它提供了`ApplicationContext`,它是`BeanFactory`的子接口。 在应用程序运行时,它是只读的;如果实现允许并管理 Bean 的生命周期,则可以重新加载它。
此时,依赖关系不是由 Java 对象管理,而是由框架管理。 **倒置** (如果您知道我的意思)。 此时,依赖关系不是由 Java 对象管理,而是由框架管理。 **倒置** (如果您知道我的意思)。
...@@ -25,7 +25,7 @@ Spring IoC 容器的基础有两个软件包: **org.springframework.beans** ...@@ -25,7 +25,7 @@ Spring IoC 容器的基础有两个软件包: **org.springframework.beans**
![IoC Container](img/5282d34ac45723aba9479d489d60afe6.jpg) ![IoC Container](img/5282d34ac45723aba9479d489d60afe6.jpg)
从上图可以看到,本质上发生的是配置元数据(对象的实例化,配置和组装),并且 JOVO 正在传递到 IOC 容器(很可能是 ApplicationContext 的实例)。 从上图可以看到,本质上发生的是配置元数据(对象的实例化,配置和组装),并且 JOVO 正在传递到 IOC 容器(很可能是`ApplicationContext`的实例)。
### 如何实例化`ApplicationContext` ### 如何实例化`ApplicationContext`
...@@ -33,13 +33,13 @@ Spring IoC 容器的基础有两个软件包: **org.springframework.beans** ...@@ -33,13 +33,13 @@ Spring IoC 容器的基础有两个软件包: **org.springframework.beans**
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml"); ApplicationContext context = new ClassPathXmlApplicationContext("services.xml");
``` ```
ApplicationContext 也视为简单的配置。 它从 XML 文件或注释中加载“配置”。 需要在应用程序的开头创建 ApplicationContext,以便它读取应用程序读取所需的所有内容。 `ApplicationContext`也视为简单的配置。 它从 XML 文件或注释中加载“配置”。 需要在应用程序的开头创建`ApplicationContext`,以便它读取应用程序读取所需的所有内容。
以防万一,您可以在应用程序中包含许多 ApplicationContext。 您甚至可以使它们从同一配置文件读取。 这是个好习惯吗? 取决于您要实现的目标。 大多数人会建议将所有 bean 配置在一个位置(通过 XML 或另一个位置)并由单个应用程序上下文加载。 以防万一,您可以在应用程序中包含许多`ApplicationContext`。 您甚至可以使它们从同一配置文件读取。 这是个好习惯吗? 取决于您要实现的目标。 大多数人会建议将所有 bean 配置在一个位置(通过 XML 或另一个位置)并由单个应用程序上下文加载。
以下示例取自[原始 Spring 文档](https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/beans.html),请随时查看以获取有关 Spring 的深入了解。 以下示例取自[原始 Spring 文档](https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/beans.html),请随时查看以获取有关 Spring 的深入了解。
**services.xml** `services.xml`
```java ```java
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
...@@ -62,11 +62,11 @@ ApplicationContext context = new ClassPathXmlApplicationContext("services.xml"); ...@@ -62,11 +62,11 @@ ApplicationContext context = new ClassPathXmlApplicationContext("services.xml");
</beans> </beans>
``` ```
同样,您可以将 services.xml 视为配置文件,然后将 **ApplicationContext** 加载/读取。 同样,您可以将`services.xml`视为配置文件,然后将`ApplicationContext`加载/读取。
## 结论 ## 结论
当您只用简单的 DI(去势注入)而无法使用时,为什么还要使用 IoC 容器? 当您只用简单的 DI(依赖注入)而无法使用时,为什么还要使用 IoC 容器?
好吧,这里有几个原因: 好吧,这里有几个原因:
......
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
> 原文: [https://javatutorial.net/dispatcher-servlet-in-spring](https://javatutorial.net/dispatcher-servlet-in-spring) > 原文: [https://javatutorial.net/dispatcher-servlet-in-spring](https://javatutorial.net/dispatcher-servlet-in-spring)
调度程序 Servlet 是 [Spring Web MVC 中最重要的组件。](https://javatutorial.net/implementing-spring-mvc-controllers) 调度器 Servlet 是 [Spring Web MVC 中最重要的组件](https://javatutorial.net/implementing-spring-mvc-controllers)
![java-featured-image](img/e0db051dedc1179e7424b6d998a6a772.jpg) ![java-featured-image](img/e0db051dedc1179e7424b6d998a6a772.jpg)
为什么调度程序 servlet 是最重要的组件? 因为它充当胶水,这意味着它接收到传入的 URL 并找到正确的方法和视图。 它通过 **HTTP 请求**接收 URL。 您还可以将其视为中间件,因为它与两端进行通信-HTTP 请求的发送方和 Spring 应用程序。 Dispatcher Servlet 完全**集成**在 IoC 容器中,并允许您使用 Spring 拥有的所有功能。 为什么调度器 servlet 是最重要的组件? 因为它充当胶水,这意味着它接收到传入的 URL 并找到正确的方法和视图。 它通过 **HTTP 请求**接收 URL。 您还可以将其视为中间件,因为它与两端进行通信-HTTP 请求的发送方和 Spring 应用程序。调度器 Servlet 完全**集成**在 IoC 容器中,并允许您使用 Spring 拥有的所有功能。
![Dispatcher Servlet example](img/7278e3b6b6bc80336ad492e1b2587755.jpg) ![Dispatcher Servlet example](img/7278e3b6b6bc80336ad492e1b2587755.jpg)
...@@ -14,19 +14,19 @@ ...@@ -14,19 +14,19 @@
以上介绍是顶级概述。 现在,让我们更具体地了解它在幕后的发生方式。 以上介绍是顶级概述。 现在,让我们更具体地了解它在幕后的发生方式。
1. 服务器请求到达服务器,并且 Dispatcher Servlet 收到。 1. 服务器请求到达服务器,并且调度器 Servlet 收到。
2. Dispatcher Servlet 授予了**处理程序对象**,在大多数情况下,它将是 HandlerExecutionChain 的实例,该实例来自 **HandlerMapping** 对象,该对象基于 URL 映射 。 2.调度器 Servlet 授予了**处理程序对象**,在大多数情况下,它将是`HandlerExecutionChain`的实例,该实例来自`HandlerMapping`对象,该对象基于 URL 映射 。
1. 有两种定义 URL 映射的方法: 1. 有两种定义 URL 映射的方法:
1. web.xml 文件 1. `web.xml`文件
2. 控制器的方法注释 2. 控制器的方法注释
3. 已从处理程序对象中检索到 **HandlerInterceptor** 对象的一个​​或多个实例。 3. 已从处理程序对象中检索到`HandlerInterceptor`对象的一个​​或多个实例。
4. 从处理程序对象中检索 **HandlerAdapter** 的实例。 4. 从处理程序对象中检索`HandlerAdapter`的实例。
1. 由于这个实例,我们可以调用句柄方法,该方法导致执行控制器类具有的任何逻辑。 1. 由于这个实例,我们可以调用句柄方法,该方法导致执行控制器类具有的任何逻辑。
5. HandlerInterceptor 实例上的后处理逻辑已执行。 这是调用渲染方法之前的最后一步。 5. `HandlerInterceptor`实例上的后处理逻辑已执行。 这是调用渲染方法之前的最后一步。
6. **ViewResolver** 实例完成返回给响应的适当视图组件。 6.`ViewResolver`实例完成返回给响应的适当视图组件。
7. 最后,在该视图的实例上调用了渲染方法。 7. 最后,在该视图的实例上调用了渲染方法。
分派器 Servlet 继承自 **HttpServlet** ,并在 Web 应用程序的 web.xml 文件中声明。 同样,如果您从上面阅读了步骤 2,您将看到我们需要 URL 映射。 首先,URL 映射将请求映射到分派器处理程序进行处理。 现在,使用 URL 映射的一种方法是将其存储在相同的 web.xml 文件中。 分派器 Servlet 继承自`HttpServlet`,并在 Web 应用程序的`web.xml`文件中声明。 同样,如果您从上面阅读了步骤 2,您将看到我们需要 URL 映射。 首先,URL 映射将请求映射到分派器处理程序进行处理。 现在,使用 URL 映射的一种方法是将其存储在相同的`web.xml`文件中。
```java ```java
<web-app> <web-app>
...@@ -45,8 +45,8 @@ ...@@ -45,8 +45,8 @@
</web-app> </web-app>
``` ```
此代码段示例摘自 [Spring 文档](https://docs.spring.io/spring/docs/3.0.0.M4/spring-framework-reference/html/ch15s02.html) 此代码段示例摘自 [Spring 文档](https://docs.spring.io/spring/docs/3.0.0.M4/spring-framework-reference/html/ch15s02.html)
示例代码段显示,所有以.form 结尾的请求都将由示例 Dispatcher servlet 处理。 示例代码段显示,所有以`.form`结尾的请求都将由示例调度器 servlet 处理。
初始化 Dispatcher servlet 后,框架将在应用程序的 **web-inf** 目录中查找名称为[servlet-name] -servlet.xml 的文件,并在该目录中创建 Bean 并覆盖所有定义 在全局范围内以相同名称定义的 bean 的数量。 初始化调度器 servlet 后,框架将在应用程序的`web-inf`目录中查找名称为`[servlet-name]-servlet.xml`的文件,并在该目录中创建 Bean 并覆盖在全局范围内以相同名称定义的 bean 的所有定义。
\ No newline at end of file \ No newline at end of file
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
依赖注入是您必须了解的 Spring 基础知识之一。 依赖注入是您必须了解的 Spring 基础知识之一。
当您创建一个复杂的应用程序时,您将有可能使不同的对象一起工作。 理想情况下,您希望这些对象彼此独立。 此设计原则是控制反转的原则,它强调 Java 类彼此之间保持独立,然后 ocntainer 会将其从对象创建和维护中解放出来。 如果您不熟悉 IoC,强烈建议您阅读[关于该主题的文章](https://javatutorial.net/ioc-in-spring) 当您创建一个复杂的应用程序时,您将有可能使不同的对象一起工作。 理想情况下,您希望这些对象彼此独立。 此设计原则是控制反转的原则,它强调 Java 类彼此之间保持独立,然后容器会将其从对象创建和维护中解放出来。 如果您不熟悉 IoC,强烈建议您阅读[关于该主题的文章](https://javatutorial.net/ioc-in-spring)
考虑一下您将如何按照传统方法创建对象依赖关系。 您将必须创建对象类型的实例变量,然后使用构造函数和设置方法或一个(构造方法/设置方法)。 像这样: 考虑一下您将如何按照传统方法创建对象依赖关系。 您将必须创建对象类型的实例变量,然后使用构造函数和设置方法或一个(构造方法/设置方法)。 像这样:
...@@ -36,9 +36,9 @@ public class Employee{ ...@@ -36,9 +36,9 @@ public class Employee{
} }
``` ```
您能明白为什么第二个例子更好吗? 因为现在员工无需担心公司的实现,所以它将独立于员工实现,并将提供给员工 ]通过构造函数,换句话说,是在 Employee 初始化时。 换句话说,如果没有公司的一部分,员工将无法生存。 否则,他就不会当雇员。 您能明白为什么第二个例子更好吗? 因为现在员工无需担心公司的实现,所以它将独立于员工实现,并通过构造函数提供给员工,换句话说,是在`Employee`初始化时。 换句话说,如果没有公司的一部分,员工将无法生存。 否则,他就不会当雇员。
依赖项(公司)通过构造函数注入到 Employee 类中。 依赖项(公司)通过构造函数注入到`Employee`类中。
DI 有 2 种类型: DI 有 2 种类型:
...@@ -62,6 +62,6 @@ public void setCompany(Company company) { ...@@ -62,6 +62,6 @@ public void setCompany(Company company) {
} }
``` ```
至于使用哪种类型,通常建议对强制性依赖项使用 Constructor DI,对可选性依赖项使用 setter。 至于使用哪种类型,通常建议对强制性依赖项使用构造器 DI,对可选性依赖项使用 setter。
多亏了 DI,现在员工类不需要查找公司,并且它既不知道位置,也不知道它的类别。 多亏了 DI,现在员工类不需要查找公司,并且它既不知道位置,也不知道它的类别。
\ No newline at end of file
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
本教程描述了实现 Spring MVC 控制器的不同方法,并提供了示例。 本教程描述了实现 Spring MVC 控制器的不同方法,并提供了示例。
在我以前的教程[中,使用 STS 创建简单的 Spring Web App](https://javatutorial.net/spring-web-app-sts) ,我向您展示了如何构建引入控制器的 Spring Boot App。 本教程是对上一个教程的扩展。 在我以前的教程[使用 STS 创建简单的 Spring Web App](https://javatutorial.net/spring-web-app-sts),我向您展示了如何构建引入控制器的 Spring Boot App。 本教程是对上一个教程的扩展。
在开始实现之前,让我们快速概述一下控制器如何参与 MVC 工作流程。 在开始实现之前,让我们快速概述一下控制器如何参与 MVC 工作流程。
...@@ -12,11 +12,11 @@ ...@@ -12,11 +12,11 @@
Spring MVC 架构工作流程 Spring MVC 架构工作流程
1. 来自客户端的传入请求由 Dispatcher Servlet 解释 1. 来自客户端的传入请求由调度器 Servlet 解释
2. Dispatcher Servlet 通过解析请求属性并使对象对处理程序可用来进行初始处理。 2. 调度器 Servlet 通过解析请求属性并使对象对处理程序可用来进行初始处理。
3. 确定并调用适当的处理程序以进一步处理请求。 确定适当控制器上的适当方法 3. 确定并调用适当的处理程序以进一步处理请求。 确定适当控制器上的适当方法
4. 控制器处理请求并返回`ModelAndView`的实例 4. 控制器处理请求并返回`ModelAndView`的实例
5. Dispatcher Servlet 进一步处理`ModelAndView`的实例,以将响应发送给客户端 5. 调度器 Servlet 进一步处理`ModelAndView`的实例,以将响应发送给客户端
## 在 Spring Boot 应用程序中启用 JSP ## 在 Spring Boot 应用程序中启用 JSP
...@@ -47,7 +47,7 @@ spring.mvc.view.suffix=.jsp ...@@ -47,7 +47,7 @@ spring.mvc.view.suffix=.jsp
## 实现 Spring 控制器返回 JSP 页面 ## 实现 Spring 控制器返回 JSP 页面
以下示例演示如何在 Spring Controller 方法中返回 JSP 页面。 请注意`@Controller`注释和`@RequestMapping`注释的用法。 如果我们想返回一个 JSP 页面,我们将不使用`@ResponseBody`注释(如第二个示例所示)。 以下示例演示如何在 Spring `Controller`方法中返回 JSP 页面。 请注意`@Controller`注释和`@RequestMapping`注释的用法。 如果我们想返回一个 JSP 页面,我们将不使用`@ResponseBody`注释(如第二个示例所示)。
```java ```java
package net.javatutorial.tutorials; package net.javatutorial.tutorials;
...@@ -72,15 +72,15 @@ public class ControllerExampleJSP { ...@@ -72,15 +72,15 @@ public class ControllerExampleJSP {
} }
``` ```
`@RequestMapping`注释将网址 http:// localhost:8080 / hellojsp 插入到控制器的方法`helloJSP()`中。 此方法返回`index.jsp`的解析内容 `@RequestMapping`注释将网址`http://localhost:8080/hellojsp`插入到控制器的方法`helloJSP()`中。 此方法返回`index.jsp`的解析内容
![Rendered JSP page using Spring controller](img/0bc963468dda0ec04620615cbdf2a0bd.jpg) ![Rendered JSP page using Spring controller](img/0bc963468dda0ec04620615cbdf2a0bd.jpg)
使用 Spring 控制器渲染 JSP 页面 使用 Spring 控制器渲染 JSP 页面
## 用 ResponseBody 实现控制器 ## 用`ResponseBody`实现控制器
与前面的示例不同,此示例将返回由方法而不是 JSP 页面生成的 String。 我们唯一需要更改的就是将`@ResponseBody`注解添加到我们的控制器方法中 与前面的示例不同,此示例将返回由方法而不是 JSP 页面生成的`String`。 我们唯一需要更改的就是将`@ResponseBody`注解添加到我们的控制器方法中
```java ```java
package net.javatutorial.tutorials; package net.javatutorial.tutorials;
...@@ -108,13 +108,13 @@ public class ControllerResponseBodyExample { ...@@ -108,13 +108,13 @@ public class ControllerResponseBodyExample {
} }
``` ```
在浏览器中调用 http:// localhost:8080 / helloresponsebody 将产生以下输出: 在浏览器中调用`http://localhost:8080/helloresponsebody`将产生以下输出:
![Output using Spring Controller and ResponseBody](img/72d388f7f9e19a4eef194d82e3af63fd.jpg) ![Output using Spring Controller and ResponseBody](img/72d388f7f9e19a4eef194d82e3af63fd.jpg)
使用 Spring Controller 和 ResponseBody 进行输出 使用 Spring `Controller``ResponseBody`进行输出
## 实现 Spring RestController ## 实现 Spring `RestController`
`@RestController`注释用作方便注释,以表示诸如`@Controller``@ResponseBody`之类的注释。 在类级别使用时,控制器可以处理 REST API 请求。 `@RestController`注释用作方便注释,以表示诸如`@Controller``@ResponseBody`之类的注释。 在类级别使用时,控制器可以处理 REST API 请求。
...@@ -143,11 +143,11 @@ public class RestControllerExample { ...@@ -143,11 +143,11 @@ public class RestControllerExample {
``` ```
在浏览器中调用 http:// localhost:8080 / hellorest 将产生以下输出: 在浏览器中调用`http://localhost:8080/hellorest`将产生以下输出:
![Output using Spring RestController](img/9852bd43729d0e2f6d7f1e1e1bbe7ec6.jpg) ![Output using Spring RestController](img/9852bd43729d0e2f6d7f1e1e1bbe7ec6.jpg)
使用 Spring RestController 输出 使用 Spring `RestController`输出
## 在方法和类级别使用`@RequestMapping`注释 ## 在方法和类级别使用`@RequestMapping`注释
...@@ -187,10 +187,10 @@ public class MethodAndClassLevelAnnotations { ...@@ -187,10 +187,10 @@ public class MethodAndClassLevelAnnotations {
``` ```
向以下网址 http:// localhost:8080 / user / 发出请求,将调用`login()`方法。 注意,注释`login()`方法的`@RequestMapping`没有参数。 向以下网址`http://localhost:8080/user/`发出请求,将调用`login()`方法。 注意,注释`login()`方法的`@RequestMapping`没有参数。
在类级别使用的`@RequestMapping("/user/*")`注释用作 catch all 方法,以使用“ / *表示的不同路径来处理所有请求。 在类级别使用的`@RequestMapping("/user/*")`注释用作兜底方法,以使用`/*`表示的不同路径来处理所有请求。
请求 http:// localhost:8080 / user / logout 将调用`logout()`方法。 `@GetMapping`注释是一个组合的注释,用作`@RequestMapping(method = RequestMethod.GET)` 请求`http://localhost:8080/user/logout`将调用`logout()`方法。 `@GetMapping`注释是一个组合的注释,用作`@RequestMapping(method = RequestMethod.GET)`
您可以在[我们的 GitHub 存储库](https://github.com/JavaTutorialNetwork/Tutorials/tree/master/SpringImplementingControllers)中找到本教程中的代码示例。 您可以在[我们的 GitHub 存储库](https://github.com/JavaTutorialNetwork/Tutorials/tree/master/SpringImplementingControllers)中找到本教程中的代码示例。
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册