feat: Spring实战学习

This commit is contained in:
Bunny 2025-01-27 12:02:36 +08:00
parent da5a5d1314
commit 4efb99a655
75 changed files with 829 additions and 36 deletions

View File

@ -9,6 +9,7 @@
<file url="file://$PROJECT_DIR$/multithreading1/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/multithreading1/src/main/resources-filtered" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/mvc/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/spring-demo/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources-filtered" charset="UTF-8" />

View File

@ -6,6 +6,7 @@
<list>
<option value="$PROJECT_DIR$/pom.xml" />
<option value="$PROJECT_DIR$/mvc/pom.xml" />
<option value="$PROJECT_DIR$/spring-demo/pom.xml" />
</list>
</option>
<option name="ignoredFiles">

View File

@ -1,4 +1,4 @@
# `SpringMVC`笔记
# `Spring`笔记
- 公共AI网站https://chatgptplus.cn/
- vue3官网https://cn.vuejs.org/
@ -147,6 +147,90 @@ public class FooController {
在这个例子中,如果访问 `/foo/bar`,它会首先匹配 `/foo/{id}`,因为它更精确。
## 编写Spring应用
### `@SpringBootApplication` 注解
1. **`@EnableAutoConfiguration`**
- 这个注解让 Spring Boot 根据项目中的依赖,自动配置 Spring 应用程序。Spring Boot 提供了大量的自动配置支持,帮助我们省去手动配置许多常见的功能。
- 例如,如果你的项目中加入了 `spring-boot-starter-web` 依赖Spring Boot 会自动配置一个嵌入式的 Tomcat 服务器和一些常见的 Web 功能。
2. **`@ComponentScan`**
- 这个注解启用 Spring 的组件扫描机制。它会扫描当前类所在的包及其子包,自动发现并注册 `@Component`、`@Service`、`@Repository`、`@Controller` 等注解标注的类。
- 通过 `@ComponentScan`你不需要手动指定要扫描的包Spring Boot 会自动扫描当前包及其子包下的所有组件。
3. **`@Configuration`**
- 这个注解表示该类是一个 Spring 配置类,类似于 XML 配置文件,用于定义 Spring 应用的 Bean 配置。
- 该类可以包含 `@Bean` 注解的方法,返回要管理的 Bean。
### `@SpringBootTest` 注解
`@SpringBootTest` 注解是用于测试 Spring Boot 应用的一个重要注解,它提供了一种方便的方式来启动 Spring Boot 应用上下文,并对整个 Spring Boot 应用进行集成测试。这个注解本身也包含了多个注解,它使得我们能够在测试类中创建一个完整的 Spring 容器来进行集成测试。
具体来说,`@SpringBootTest` 是一个组合注解,它整合了以下几个主要的注解:
1. **`@ContextConfiguration`**
- `@ContextConfiguration` 注解用于加载 Spring 配置文件或者配置类,在测试时会初始化 Spring 容器。`@SpringBootTest` 默认会加载 Spring Boot 应用的主配置类(即包含 `@SpringBootApplication` 注解的类),作为 Spring 容器的上下文。
- 它的作用是让测试类能够加载到 Spring 配置并创建一个完整的应用上下文。
2. **`@TestExecutionListeners`**
- 该注解指定了测试执行时的监听器。在 Spring 测试框架中,`@TestExecutionListeners` 会提供某些扩展功能,如事务管理、环境配置等,但它的实际作用在大多数测试中不太明显,通常由 Spring Boot 自动配置。
3. **`@DirtiesContext`**
- 这个注解会告诉 Spring 在测试执行之后清除(或重置)应用上下文,通常用于测试中的应用上下文需要被清理或重置,以避免测试间的相互影响。`@SpringBootTest` 会根据需要处理上下文的清理工作。
4. **`@BootstrapWith`**
- 这个注解是用于引导测试的,它会指定 `SpringBootTestContextBootstrapper` 来启动 Spring Boot 测试上下文。这是一个 Spring Boot 测试框架中的内部机制,用于初始化应用上下文并准备测试。
### 测试页面
编写控制界面,返回`index.html`
```java
@RequestMapping
@Controller
public class HomeController {
@Operation(summary = "主页内容")
@GetMapping("index")
public String index() {
return "index";
}
}
```
测试页面返回结果
```java
@WebMvcTest(HomeController.class)
class HomeControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
void index() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/"))// 访问路径
.andExpect(MockMvcResultMatchers.status().isOk())// 判断状态是否成功
.andExpect(MockMvcResultMatchers.view().name("index"))// 判断视图名称是否是index
// 是否包含字段
.andExpect(MockMvcResultMatchers.content().string(Matchers.containsString("欢迎。。。")));
}
}
```
访问index的页面
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index 测试页面</title>
</head>
<body>
<h1>欢迎。。。</h1>
<img alt="" th:src="@{/images/icon_3.png}">
<img alt="通常MVC项目静态资源放在 static/images 下" src="images/index/diannao.png">
</body>
</html>
```
## 访问控制
请求地址时返回对应的网页文件
@ -501,17 +585,13 @@ public class WebConfig implements WebMvcConfigurer {
`SessionInterceptor` 可以用于监控和管理 Session 数据。
### 8. **总结**
在 Spring MVC 中,向 Session 共享数据主要有以下几种方式:
- **`HttpSession`**:通过 `HttpSession` 对象存储和读取 Session 数据。
- **`@SessionAttributes`**:通过 `@SessionAttributes` 注解将模型属性添加到 Session 中。
- **`@ModelAttribute`**:结合 `@SessionAttributes` 使用,将模型数据持久化到 Session 中。
- **`@RequestParam``@PathVariable`**:将请求参数或路径变量存储到 Session 中。
- **Session 过期与清理**:可以通过配置控制会话超时,或手动清除 Session 数据。
Spring MVC 提供的 Session 管理机制非常灵活,能够满足各种需求。
> 在 Spring MVC 中,向 Session 共享数据主要有以下几种方式:
>
> - **`HttpSession`**:通过 `HttpSession` 对象存储和读取 Session 数据。
> - **`@SessionAttributes`**:通过 `@SessionAttributes` 注解将模型属性添加到 Session 中。
> - **`@ModelAttribute`**:结合 `@SessionAttributes` 使用,将模型数据持久化到 Session 中。
> - **`@RequestParam``@PathVariable`**:将请求参数或路径变量存储到 Session 中。
> - **Session 过期与清理**:可以通过配置控制会话超时,或手动清除 Session 数据。
## 向application域共享数据
@ -656,14 +736,11 @@ public class AppConfig {
在这种情况下Spring 管理的 Bean 会在应用级别共享,类似于 `ServletContext` 中存储的数据。
### 6. **总结**
- `Application` 域(即 `ServletContext`)用于在整个应用程序范围内共享数据,适合存储全局共享的信息、配置和常量。
- 通过 `HttpServletRequest.getServletContext()``@Autowired` 注解可以访问 `ServletContext` 并向 `Application` 域中共享数据。
- 数据存储在 `Application` 域中可以在整个应用程序生命周期内有效,适用于共享全局性的、无需频繁更新的数据。
- 应谨慎存储敏感数据,并注意线程安全和数据的生命周期。
通过合理地使用 `Application` 域,你可以实现全局共享的数据管理,并且不需要担心会话或请求的生命周期问题。
> - `Application` 域(即 `ServletContext`)用于在整个应用程序范围内共享数据,适合存储全局共享的信息、配置和常量。
> - 通过 `HttpServletRequest.getServletContext()``@Autowired` 注解可以访问 `ServletContext` 并向 `Application` 域中共享数据。
> - 数据存储在 `Application` 域中可以在整个应用程序生命周期内有效,适用于共享全局性的、无需频繁更新的数据。
> - 应谨慎存储敏感数据,并注意线程安全和数据的生命周期。
>
## 重定向和转发使用
@ -851,12 +928,325 @@ public class RedirectController {
}
```
### 5. **总结**
- **重定向Redirect**:客户端浏览器会发起一次新的请求,地址栏 URL 会发生变化,适用于需要跨请求跳转或外部跳转的场景。
- **转发Forward**:请求在服务器内部被转发,地址栏 URL 不变,适用于同一请求的内部跳转。
通过合理使用转发和重定向,你可以灵活地控制请求流转和用户体验。
## Spring 表单验证
在 Spring MVC 中,表单验证是通过一系列的注解来完成的。
### **`@NotNull`**
- **作用**:确保字段值不为空。
- **用法**:用于字段、方法参数或返回值上,表示该字段不能为空。如果字段为空,将验证失败并返回相应的错误信息。
- 示例
```java
@NotNull(message = "用户名不能为空")
private String username;
```
### **`@NotEmpty`**
- **作用**:确保字段不为空,并且不为一个空字符串。
- **用法**:用于字符串、集合等类型,验证字段不仅不能为空,而且不能为空字符串。
- 示例
```java
@NotEmpty(message = "密码不能为空")
private String password;
```
### **`@NotBlank`**
- **作用**:确保字段不为空,并且不为一个空白字符串(即非空白字符)。
- **用法**:类似于 `@NotEmpty`,但除了不为空,还要求去除空白字符后不能为零长度。
- 示例
```java
@NotBlank(message = "电子邮件不能为空")
private String email;
```
### **`@Size(min, max)`**
- **作用**:验证字段的大小,适用于字符串、集合、数组等类型。
- **用法**:可以设置最小值和最大值来限制字段的长度或集合的大小。
- 示例
```java
@Size(min = 6, max = 20, message = "密码长度必须在6到20之间")
private String password;
```
### **`@Email`**
- **作用**:验证字段是否符合有效的电子邮件格式。
- **用法**:用于验证字符串字段是否为有效的电子邮件地址格式。
- 示例
```java
@Email(message = "请输入有效的电子邮件地址")
private String email;
```
### **`@Pattern(regexp)`**
- **作用**:根据正则表达式验证字段值。
- **用法**:可以根据自定义的正则表达式来验证字段的内容。
- 示例
```java
@Pattern(regexp = "^\\d{10}$", message = "请输入有效的手机号码")
private String phoneNumber;
```
### **`@Min(value)``@Max(value)`**
- **作用**:确保数字类型字段的值在指定范围内。
- **用法**`@Min` 用于验证值是否大于等于指定的最小值,`@Max` 用于验证值是否小于等于指定的最大值。
- 示例
```java
@Min(value = 18, message = "年龄不能小于18岁")
@Max(value = 100, message = "年龄不能大于100岁")
private int age;
```
### **`@DecimalMin(value)``@DecimalMax(value)`**
- **作用**:用于验证浮动值是否在指定范围内,类似于 `@Min``@Max`,但适用于 `BigDecimal``Double` 类型的数值。
- **用法**`@DecimalMin` 验证值是否大于等于指定的最小值,`@DecimalMax` 验证值是否小于等于指定的最大值。
- 示例
```java
@DecimalMin(value = "0.0", inclusive = true, message = "价格不能小于0")
private BigDecimal price;
```
### **`@Future`**
- **作用**:验证日期字段的值是否为将来日期。
- **用法**:用于 `java.util.Date`、`java.time.LocalDate` 或 `java.time.LocalDateTime` 等日期类型的字段。
- 示例
```java
@Future(message = "日期必须是未来的时间")
private LocalDate eventDate;
```
### **`@Past`**
- **作用**:验证日期字段的值是否为过去的日期。
- **用法**:类似于 `@Future`,但是验证日期必须是过去的时间。
- 示例
```java
@Past(message = "出生日期必须是过去的时间")
private LocalDate birthDate;
```
### **`@AssertTrue`**
- **作用**:验证字段值是否为 `true`
- **用法**:适用于布尔类型字段,如果值不是 `true`,则验证失败。
- 示例
```java
@AssertTrue(message = "必须接受条款和条件")
private boolean acceptedTerms;
```
### **`@AssertFalse`**
- **作用**:验证字段值是否为 `false`
- **用法**:适用于布尔类型字段,如果值不是 `false`,则验证失败。
- 示例
```java
@AssertFalse(message = "不能接受条款")
private boolean declinedTerms;
```
### **`@Valid``@Validated`**
- **作用**:触发嵌套对象的验证。
- **用法**:当你有嵌套对象(如表单中的对象属性是另一个对象),使用 `@Valid``@Validated` 注解来递归验证该对象。
- 示例
```java
@Valid
private Address address;
```
### **`@Digits(integer, fraction)`**
- **作用**:验证数字字段的有效性,确保字段值是一个有效的数字,并且整数部分和小数部分的位数符合指定要求。
- **用法**`integer` 参数用于指定数字的整数部分的最大位数,`fraction` 参数用于指定小数部分的最大位数。
- 示例
```java
@Digits(integer = 5, fraction = 2, message = "金额应为最大5位整数和2位小数")
private BigDecimal amount;
```
- 这个例子验证金额字段的最大值为 `99999.99`即最多5位整数和2位小数
### **`@CreditCardNumber`**
- **作用**:验证信用卡号的有效性,确保其符合信用卡的常见格式,通常包括 Luhn 算法的验证。
- **用法**:该注解用于验证信用卡号的格式是否有效。
- 示例
```java
@CreditCardNumber(message = "请输入有效的信用卡号")
private String creditCardNumber;
```
- 该注解会根据常见的信用卡规则(如 VISA、MasterCard 等)验证输入的信用卡号是否合法。
### **`@Range(min, max)`**(不是 Spring 内置的,但通常来自 Hibernate Validator
- **作用**:验证字段值是否在指定的范围内。常用于 `Integer`、`Long`、`Double` 等数值类型的字段。
- **用法**:指定字段的有效范围,当值不在范围内时会验证失败。
- 示例
```java
@Range(min = 1, max = 100, message = "数字必须在1到100之间")
private int quantity;
```
- 该注解会验证 `quantity` 字段的值是否在 `1``100` 之间。
### **`@URL`**
- **作用**:验证字段是否为有效的 URL 格式。
- **用法**:用于字符串类型的字段,验证其是否符合有效的 URL 格式。
- 示例
```java
@URL(message = "请输入有效的网址")
private String website;
```
### **`@Valid``@Validated`**
- **作用**:用于嵌套对象的验证,确保嵌套对象的字段也进行验证。
- **用法**:这两个注解会触发嵌套对象的验证,通常用于嵌套的复杂表单数据结构。
- 示例
```java
@Valid
private Address address;
```
- 如果 `Address` 类中有字段使用了验证注解,`@Valid` 会递归地验证 `Address` 对象的所有字段。
### **`@FutureOrPresent`**
- **作用**:验证日期或时间字段的值是否是当前日期(包括今天)或未来的日期。
- **用法**:该注解用于日期和时间字段,确保其为今天或将来的日期。
- 示例
```java
@FutureOrPresent(message = "事件日期必须是今天或将来")
private LocalDate eventDate;
```
### **`@PastOrPresent`**
- **作用**:验证日期或时间字段的值是否是当前日期(包括今天)或过去的日期。
- **用法**:与 `@FutureOrPresent` 相反,确保字段是过去或今天的日期。
- 示
```java
@PastOrPresent(message = "出生日期必须是过去的时间或今天")
private LocalDate birthDate;
```
### **`@Null`**
- **作用**:验证字段是否为 `null`。如果字段不为空,则验证失败。
- **用法**:该注解可以用于字段或方法参数上,确保字段值必须为 `null`
- 示例
```java
@Null(message = "该字段必须为null")
private String nickname;
```
### **`@ScriptAssert(lang, script)`**
- **作用**:通过自定义脚本验证字段值。
- **用法**:允许使用自定义脚本(如 JavaScript来执行复杂的验证逻辑。需要指定脚本语言和脚本内容。
- 示例
```java
@ScriptAssert(lang = "javascript", script = "_this.password == _this.confirmPassword", message = "密码和确认密码必须一致")
private String password;
private String confirmPassword;
```
- 这个注解可以用于检查两个字段值是否一致。
### **`@UniqueElements`**Hibernate Validator 扩展)
- **作用**:确保集合中的元素是唯一的,常用于 List 或 Set 类型字段。
- **用法**:适用于集合类型字段,确保集合中的元素不重复。
- 示例
```java
@UniqueElements(message = "列表中的元素必须唯一")
private List<String> tags;
```
## Thymeleaf快速入门
@ -1117,15 +1507,18 @@ Thymeleaf 是一种现代化的 Java 模板引擎,广泛用于生成 HTML、XM
- 设置 `input``placeholder``${placeholderText}` 的值。
------
### 23. **`th:errors`**
### 总结
显示与 `username` 属性相关的错误信息。如果 `username` 为空或者不符合验证规则,这里就会显示出相应的错误消息。
Thymeleaf 提供了许多强大的指令来处理模板中的动态内容、条件渲染、迭代和属性绑定。常见的指令包括:
```html
<div th:errors="*{email}"></div> <!-- 错误信息展示 -->
```
- `th:text`、`th:utext`:用于设置文本内容。
- `th:each`:用于循环遍历。
- `th:if`、`th:unless`:用于条件判断。
- `th:attr`、`th:id`、`th:class`:用于设置 HTML 属性。
- `th:replace`、`th:include`:用于片段包含。
- `th:switch`、`th:case`:用于类似 `switch` 的条件语句。
你还可以通过 `th:errors` 对错误消息进行自定义格式化。例如,使用 `*{field}` 可以获取字段的错误信息。
```html
<div th:errors="*{username}">Error</div>
```
如果验证失败,错误消息将显示在 `<div>` 中。如果没有错误,它会显示默认的 "Error" 文本。

View File

@ -20,7 +20,7 @@ public class Knife4jConfig {
// 使用协议
License license = new License().name("MIT").url("https://MUT.com");
// 相关信息
Info info = new Info().title("家庭理财管理系统").description("家庭理财管理系统").version("v1.0.0").contact(contact).license(license).termsOfService("MIT");
Info info = new Info().title("Spring MVC").description("Spring MVC 学习").version("v1.0.0").contact(contact).license(license).termsOfService("MIT");
return new OpenAPI().info(info).externalDocs(new ExternalDocumentation());
}
@ -28,6 +28,6 @@ public class Knife4jConfig {
// 管理员相关分类接口
@Bean
public GroupedOpenApi groupedOpenAdminApi() {
return GroupedOpenApi.builder().group("后台管理").pathsToMatch("/user/**").build();
return GroupedOpenApi.builder().group("用户管理管理").pathsToMatch("/user/**").build();
}
}

View File

@ -0,0 +1,32 @@
11:10:36:949 INFO 11120 --- [spring-demo] [main] c.b.s.controller.HomeControllerTest : Starting HomeControllerTest using Java 17.0.9 with PID 11120 (started by 13199 in F:\学习\代码\Java\MultiThread\spring-demo)
11:10:36:951 INFO 11120 --- [spring-demo] [main] c.b.s.controller.HomeControllerTest : The following 1 profile is active: "dev"
11:10:37:324 INFO 11120 --- [spring-demo] [main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
11:10:37:341 INFO 11120 --- [spring-demo] [main] o.s.v.b.OptionalValidatorFactoryBean : Failed to set up a Bean Validation provider: jakarta.validation.NoProviderFoundException: Unable to create a Configuration, because no Jakarta Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.
11:10:37:500 INFO 11120 --- [spring-demo] [main] o.s.b.t.m.w.SpringBootMockServletContext : Initializing Spring TestDispatcherServlet ''
11:10:37:500 INFO 11120 --- [spring-demo] [main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet ''
11:10:37:501 INFO 11120 --- [spring-demo] [main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 1 ms
11:10:37:527 INFO 11120 --- [spring-demo] [main] c.b.s.controller.HomeControllerTest : Started HomeControllerTest in 0.888 seconds (process running for 1.391)
11:10:58:580 INFO 15932 --- [spring-demo] [main] c.b.s.controller.HomeControllerTest : Starting HomeControllerTest using Java 17.0.9 with PID 15932 (started by 13199 in F:\学习\代码\Java\MultiThread\spring-demo)
11:10:58:584 INFO 15932 --- [spring-demo] [main] c.b.s.controller.HomeControllerTest : The following 1 profile is active: "dev"
11:10:58:965 INFO 15932 --- [spring-demo] [main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
11:10:58:980 INFO 15932 --- [spring-demo] [main] o.s.v.b.OptionalValidatorFactoryBean : Failed to set up a Bean Validation provider: jakarta.validation.NoProviderFoundException: Unable to create a Configuration, because no Jakarta Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.
11:10:59:140 INFO 15932 --- [spring-demo] [main] o.s.b.t.m.w.SpringBootMockServletContext : Initializing Spring TestDispatcherServlet ''
11:10:59:140 INFO 15932 --- [spring-demo] [main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet ''
11:10:59:141 INFO 15932 --- [spring-demo] [main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 1 ms
11:10:59:161 INFO 15932 --- [spring-demo] [main] c.b.s.controller.HomeControllerTest : Started HomeControllerTest in 0.902 seconds (process running for 1.458)
11:12:10:789 INFO 1180 --- [spring-demo] [main] c.b.s.controller.HomeControllerTest : Starting HomeControllerTest using Java 17.0.9 with PID 1180 (started by 13199 in F:\学习\代码\Java\MultiThread\spring-demo)
11:12:10:792 INFO 1180 --- [spring-demo] [main] c.b.s.controller.HomeControllerTest : The following 1 profile is active: "dev"
11:12:11:166 INFO 1180 --- [spring-demo] [main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
11:12:11:185 INFO 1180 --- [spring-demo] [main] o.s.v.b.OptionalValidatorFactoryBean : Failed to set up a Bean Validation provider: jakarta.validation.NoProviderFoundException: Unable to create a Configuration, because no Jakarta Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.
11:12:11:337 INFO 1180 --- [spring-demo] [main] o.s.b.t.m.w.SpringBootMockServletContext : Initializing Spring TestDispatcherServlet ''
11:12:11:337 INFO 1180 --- [spring-demo] [main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet ''
11:12:11:338 INFO 1180 --- [spring-demo] [main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 1 ms
11:12:11:366 INFO 1180 --- [spring-demo] [main] c.b.s.controller.HomeControllerTest : Started HomeControllerTest in 0.902 seconds (process running for 1.455)
11:13:43:498 INFO 12616 --- [spring-demo] [main] c.b.s.controller.HomeControllerTest : Starting HomeControllerTest using Java 17.0.9 with PID 12616 (started by 13199 in F:\学习\代码\Java\MultiThread\spring-demo)
11:13:43:501 INFO 12616 --- [spring-demo] [main] c.b.s.controller.HomeControllerTest : The following 1 profile is active: "dev"
11:13:43:877 INFO 12616 --- [spring-demo] [main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
11:13:43:891 INFO 12616 --- [spring-demo] [main] o.s.v.b.OptionalValidatorFactoryBean : Failed to set up a Bean Validation provider: jakarta.validation.NoProviderFoundException: Unable to create a Configuration, because no Jakarta Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.
11:13:44:041 INFO 12616 --- [spring-demo] [main] o.s.b.t.m.w.SpringBootMockServletContext : Initializing Spring TestDispatcherServlet ''
11:13:44:041 INFO 12616 --- [spring-demo] [main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet ''
11:13:44:042 INFO 12616 --- [spring-demo] [main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 1 ms
11:13:44:062 INFO 12616 --- [spring-demo] [main] c.b.s.controller.HomeControllerTest : Started HomeControllerTest in 0.888 seconds (process running for 1.466)

127
spring-demo/pom.xml Normal file
View File

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.bunny</groupId>
<artifactId>spring-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-demo</name>
<description>spring-demo</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
<fastjson2.version>2.0.47</fastjson2.version>
<version>${junit.version}</version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring-security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
</dependency>
<!-- devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- knife4j -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>4.5.0</version>
</dependency>
<!-- thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- fastjson2 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>${fastjson2.version}</version>
</dependency>
<!-- hutool -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.27</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,11 @@
package cn.bunny.springdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringDemoApplication.class, args);
}
}

View File

@ -0,0 +1,33 @@
package cn.bunny.springdemo.configuration;
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@Slf4j
public class Knife4jConfig {
@Bean
public OpenAPI openAPI() {
// 作者等信息
Contact contact = new Contact().name("Bunny").email("1319900154@qq.com").url("http://bunny-web.site");
// 使用协议
License license = new License().name("MIT").url("https://MUT.com");
// 相关信息
Info info = new Info().title("Spring ").description("Spring 学习").version("v1.0.0").contact(contact).license(license).termsOfService("MIT");
return new OpenAPI().info(info).externalDocs(new ExternalDocumentation());
}
// 管理员相关分类接口
@Bean
public GroupedOpenApi groupedOpenAdminApi() {
return GroupedOpenApi.builder().group("基础请求").pathsToMatch("/api/**").build();
}
}

View File

@ -0,0 +1,17 @@
package cn.bunny.springdemo.controller;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@RequestMapping
@Controller
public class HomeController {
@Operation(summary = "主页内容")
@GetMapping("index")
public String index() {
return "index";
}
}

View File

@ -0,0 +1,38 @@
server:
port: 8080
logging:
level:
cn.bunny.service.mapper: info
cn.bunny.service.controller: info
cn.bunny.service.service: info
root: info
pattern:
dateformat: HH:mm:ss:SSS
file:
path: "logs/${spring.application.name}"
#mybatis-plus:
# configuration:
# map-underscore-to-camel-case: true
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 查看日志
bunny:
master:
host: 192.168.3.130
port: 3306
database: family_financial
username: root
password: "123456"
mongodb:
database: financial
host: 192.168.3.130
port: 27017
username: admin
password: "123456"
authentication-database: admin
additional-hosts: 192.168.3.130

View File

@ -0,0 +1,20 @@
spring:
application:
name: spring-demo
profiles:
active: dev
servlet:
multipart:
max-file-size: 6MB
# datasource:
# type: com.zaxxer.hikari.HikariDataSource
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://${bunny.master.host}:${bunny.master.port}/${bunny.master.database}?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true
# username: ${bunny.master.username}
# password: ${bunny.master.password}
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>400</title>
</head>
<body>
<h1>400</h1>
</body>
</html>

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>404</title>
</head>
<body>
<h1>404</h1>
</body>
</html>

View File

@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
<meta charset="UTF-8">
<title>500 - 服务器错误</title>
<meta content="width=device-width, maximum-scale=1, initial-scale=1" name="viewport"/>
<style>
html, body {
height: 100%;
}
body {
color: #333;
margin: auto;
padding: 1em;
display: table;
user-select: none;
box-sizing: border-box;
font: lighter 20px "微软雅黑";
}
a {
color: #3498db;
text-decoration: none;
}
h1 {
margin-top: 0;
font-size: 3.5em;
}
main {
margin: 0 auto;
text-align: center;
display: table-cell;
vertical-align: middle;
}
.btn {
color: #fff;
padding: .75em 1em;
background: #3498db;
border-radius: 1.5em;
display: inline-block;
transition: opacity .3s, transform .3s;
}
.btn:hover {
transform: scale(1.1);
}
.btn:active {
opacity: .7;
}
</style>
</head>
<body>
<main>
<h1>:'(</h1>
<p>服务器开小差啦!管理员正在修理中...</p>
<p>还请阁下静候站点恢复~</p>
</main>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index 测试页面</title>
</head>
<body>
<h1>欢迎。。。</h1>
<img alt="" th:src="@{/images/icon_3.png}">
<img alt="通常MVC项目静态资源放在 static/images 下" src="images/index/diannao.png">
</body>
</html>

View File

@ -1,10 +1,10 @@
package cn.bunny.mvc;
package cn.bunny.springdemo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class MvcApplicationTests {
class SpringDemoApplicationTests {
@Test
void contextLoads() {

View File

@ -0,0 +1,24 @@
package cn.bunny.springdemo.controller;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
@WebMvcTest(HomeController.class)
class HomeControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
void index() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/"))// 访问路径
.andExpect(MockMvcResultMatchers.status().isOk())// 判断状态是否成功
.andExpect(MockMvcResultMatchers.view().name("index"))// 判断视图名称是否是index
.andExpect(MockMvcResultMatchers.content().string(Matchers.containsString("欢迎。。。")));// 是否包含字段
}
}