diff --git a/README-CN.md b/README-CN.md new file mode 100644 index 0000000..a6dae9b --- /dev/null +++ b/README-CN.md @@ -0,0 +1,28 @@ +[English](README-EN.md) | 中文 | [Русский](README.md) + +## 使用Java进行Web开发的教程 + +欢迎使用Spring框架进行Java Web开发的教程!这些结构化的教程旨在提供全面的指导,涵盖Java Web开发的各个方面,侧重于Spring框架。每个教程都精心设计,重点介绍特定的概念和方法,确保对Web开发原理的牢固理解。 + +### 教程 + +1. **第1课: [Thymeleaf](docs/cn/thymeleaf/lab-work.md)** + + Thymeleaf教程提供了在Spring应用中设置Thymeleaf的实用指南。在本教程中,参与者将进行与视图设置、变量操作和其他重要功能相关的任务。 + +2. **第2课: [Spring Security](docs/cn/springsecurity/lab-work.md)** + + 本教程深入探讨了在Spring应用中使用Spring Security的安全机制。参与者将学习如何设置认证和授权机制,保护路径和资源,实现自定义登录表单以及其他相关的安全实践。 + +3. **第3课: [JPA (Java Persistence API)](docs/cn/jpa/lab-work.md)** + + JPA教程提供了在Spring应用中使用Java Persistence API的实用指南。参与者将学习如何使用JPA与数据库交互,执行CRUD操作,管理实体之间的关系以及其他重要的数据持久化任务。 + +4. **第4课: [事务](docs/cn/transactions/lab-work.md)** + + 本教程深入探讨了不同传播和隔离场景下的事务管理。参与者将学习事务控制、不同的隔离级别和传播场景,从而深入理解在Spring应用中管理事务。 + +5. **第5课: [JMeter](docs/cn/jmeter/lab-work.md)** + + JMeter系列教程提供了使用JMeter进行负载测试和性能分析的完整指南。参与者将学习如何设置JMeter、记录HTTP请求、创建和执行测试场景,以及分析测试结果。 + diff --git a/README-EN.md b/README-EN.md new file mode 100644 index 0000000..7fc6839 --- /dev/null +++ b/README-EN.md @@ -0,0 +1,30 @@ +English | [中文](README-CN.md) | [Русский](README.md) + +## Java Web Development Tutorials + +Welcome to the tutorials on Java web development utilizing the Spring framework! These structured tutorials aim to provide comprehensive guidance on various aspects of Java web development through the lens of the Spring framework. Each tutorial is meticulously designed to focus on specific concepts and methodologies, facilitating a robust understanding of web development principles. + +### Tutorials + +1. **Tutorial 1: [Thymeleaf](docs/en/thymeleaf/lab-work.md)** + + The Thymeleaf tutorial offers practical guidance on configuring Thymeleaf within a Spring application. Through this tutorial, participants will engage in activities involving the setup of views, manipulation of variables, and other essential functionalities. + + +2. **Tutorial 2: [Spring Security](docs/en/springsecurity/lab-work.md)** + + This tutorial delves into the intricacies of security mechanisms within Spring applications using Spring Security. Participants will explore configuring authentication and authorization mechanisms, safeguarding paths and resources, implementing custom login forms, and other pertinent security practices. + + +3. **Tutorial 3: [JPA (Java Persistence API)](docs/en/jpa/lab-work.md)** + + The JPA tutorial provides practical guidance on utilizing the Java Persistence API within a Spring application. Participants will learn to interact with databases using JPA, perform CRUD operations, manage entity relationships, and other essential data persistence tasks. + + +4. **Tutorial 4: [Transactions](docs/en/transactions/lab-work.md)** + + The transactions tutorial delves into controlling transactions with various propagation scenarios and isolation levels. Participants will explore transaction management, different isolation levels, and propagation scenarios, providing them with a deep understanding of transaction management in the context of Spring applications. + +5. **Tutorial 5: [JMeter](docs/en/jmeter/lab-work.md)** + + The JMeter tutorial series provides comprehensive guidance on using JMeter for load testing and performance analysis of web applications. Participants will learn to set up JMeter, record HTTP requests, create and execute test scenarios, and analyze the test results. diff --git a/README.md b/README.md new file mode 100644 index 0000000..a488b95 --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +[English](README-EN.md) | [中文](README-CN.md) | Русский + +## Учебные пособия по веб-разработке на Java + +Добро пожаловать на учебные пособия по веб-разработке на Java с использованием фреймворка Spring! Эти структурированные учебные пособия направлены на предоставление всестороннего руководства по различным аспектам веб-разработки на Java через призму фреймворка Spring. Каждое учебное пособие тщательно разработано для акцентирования на конкретных концепциях и методологиях, обеспечивая крепкое понимание принципов веб-разработки. + +### Учебные пособия + +1. **Урок 1: [Thymeleaf](docs/ru/thymeleaf/lab-work.md)** + + Учебное пособие по Thymeleaf предлагает практическое руководство по настройке Thymeleaf в приложении Spring. В рамках этого учебного пособия участники будут заниматься заданиями, связанными с настройкой представлений, манипулированием переменными и другими важными функциями. + + +2. **Урок 2: [Spring Security](docs/ru/springsecurity/lab-work.md)** + + Это учебное пособие углубляется в тонкости механизмов безопасности в приложениях Spring с использованием Spring Security. Участники изучат настройку механизмов аутентификации и авторизации, защиту путей и ресурсов, реализацию пользовательских форм входа и другие соответствующие практики безопасности. + + +3. **Урок 3: [JPA (Java Persistence API)](docs/ru/jpa/lab-work.md)** + + Учебное пособие по JPA предоставляет практическое руководство по использованию Java Persistence API в приложении Spring. Участники узнают, как взаимодействовать с базами данных с использованием JPA, выполнять операции CRUD, управлять отношениями между сущностями и другие важные задачи по сохранению данных. + + +4. **Урок 4: [Транзакции](docs/ru/transactions/lab-work.md)** + + Учебное пособие по транзакциям позволяет погрузиться в управление транзакциями с различными сценариями распространения и изоляции. Участники изучат контроль транзакций, различные уровни изоляции и сценарии распространения, что обеспечит им глубокое понимание управления транзакциями в контексте приложений Spring. + +5. **Урок 5: [JMeter](docs/ru/jmeter/lab-work.md)** + + Серия уроков по JMeter предоставляет полное руководство по использованию JMeter для тестирования нагрузки и анализа производительности веб-приложений. Участники узнают, как настроить JMeter, записать HTTP-запросы, создать и выполнить тестовые сценарии, а также проанализировать результаты тестирования. diff --git a/docs/cn/jmeter/lab-work.md b/docs/cn/jmeter/lab-work.md new file mode 100644 index 0000000..3a0b510 --- /dev/null +++ b/docs/cn/jmeter/lab-work.md @@ -0,0 +1,26 @@ +[English](../../en/jmeter/lab-work.md) | 中文 | [Русский](../../ru/jmeter/lab-work.md) + + +# JMeter实验室任务 + +欢迎来到JMeter实验室!这一系列任务的目标是帮助您练习和掌握JMeter,这是一种用于性能测试和测量Web应用程序性能的强大工具。无论您是初学者还是希望提升技能,这些实践任务都将引导您了解JMeter在负载测试、录制和分析HTTP请求方面的各个方面。 + +## 实验室任务的目标 + +本实验室的主要目标是为您提供在性能测试中使用JMeter的实际经验和熟练度。JMeter被广泛用于测试Web应用程序和服务的性能,通过这些任务,您将获得有关其配置、脚本编写、录制和分析功能的宝贵见解。 + +## 实践任务 + +- [第1课:JMeter简介和基本设置](lessons/introduction-to-jmeter-and-basic-setup.md) +- [第2课:设置HTTP(S)测试脚本记录器](lessons/setting-up-http-test-script-recorder.md) +- [第3课:配置和使用代理服务器](lessons/configuring-and-using-the-proxy-server.md) +- [第4课:配置浏览器使用代理服务器](lessons/configuring-browser-to-use-the-proxy-server.md) +- [第5课:录制和管理HTTP请求](lessons/recording-and-managing-http-requests.md) +- [第6课:组织录制的请求](lessons/organizing-recorded-requests.md) +- [第7课:创建测试方案](lessons/creating-a-test-scenario.md) +- [第8课:给HTTP请求参数化](lessons/parameterizing-http-requests.md) +- [第9课:添加监听器和运行测试](lessons/adding-listeners-and-running-tests.md) +- [第10课:执行负载测试](lessons/executing-load-testing.md) +- [第11课:分析测试结果](lessons/analyzing-test-results.md) + +## 实验室任务 \ No newline at end of file diff --git a/docs/cn/jmeter/lessons/adding-listeners-and-running-tests.md b/docs/cn/jmeter/lessons/adding-listeners-and-running-tests.md new file mode 100644 index 0000000..bf55e98 --- /dev/null +++ b/docs/cn/jmeter/lessons/adding-listeners-and-running-tests.md @@ -0,0 +1,28 @@ +# 第9课:添加监听器并运行测试 + +## 目标 +本课的目标是向JMeter中添加监听器以查看测试结果,并运行测试方案。 + +## 步骤 + +### 9.1 添加监听器 +1. **查看结果树** + - 在 **线程组** 上右键单击。 + - 选择 **添加 > 监听器 > 查看结果树**。 + +### 9.2 保存测试计划 +1. **保存** + - 单击 **测试计划** 节点。 + - 转到 **文件 > 另存为**。 + - 选择一个位置,输入文件名,并保存测试计划。 + +### 9.3 运行测试方案 +1. **执行** + - 单击 **运行 > 开始** 开始测试。 +
![run-test-scenraio-button.png](../../../srcs/jmeter/run-test-scenraio-button.png) + - 在 **查看结果树** 监听器中查看结果。 + - 确保测试结果中没有错误。 + +--- + +# [下一步:执行负载测试](executing-load-testing.md) \ No newline at end of file diff --git a/docs/cn/jmeter/lessons/analyzing-test-results.md b/docs/cn/jmeter/lessons/analyzing-test-results.md new file mode 100644 index 0000000..8a8d053 --- /dev/null +++ b/docs/cn/jmeter/lessons/analyzing-test-results.md @@ -0,0 +1,19 @@ +# 第11课:分析测试结果 + +## 目标 +本课的目标是使用电子表格分析测试结果,并为后续在JMeter中进行测试准备。 + +## 步骤 + +### 11.1 利用电子表格 +1. **导出和分析数据** + - 从 **聚合报告** 监听器中将结果导出到CSV文件。 + - 使用电子表格应用程序(例如Excel)分析平均响应时间和其他指标。 + +### 11.2 为后续运行清除统计信息 +1. **清除数据** + - 在运行新测试之前,通过选择 **运行 > 清除所有** 来清除先前的结果。 + +--- + +# [下一步:任务](../lab-work.md) \ No newline at end of file diff --git a/docs/cn/jmeter/lessons/configuring-and-using-the-proxy-server.md b/docs/cn/jmeter/lessons/configuring-and-using-the-proxy-server.md new file mode 100644 index 0000000..c438c5c --- /dev/null +++ b/docs/cn/jmeter/lessons/configuring-and-using-the-proxy-server.md @@ -0,0 +1,19 @@ +# 第3课:配置和使用代理服务器 + +## 目标 +本课的目标是在JMeter中配置代理服务器,并演示如何将其用于记录HTTP(S)请求。 + +## 步骤 + +### 3.1. 配置代理服务器 +1. **设置端口和URL模式** + - 在 **HTTP(S)测试脚本录制器** 窗口中,将 **端口** 字段设置为 `9090`。 + - 在 **排除的URL模式** 部分,点击 **添加**,输入诸如 `.*\.gif`、`.*\.js` 和 `.*\.css` 等模式。 +
![setting-port-and-url-pattern.png](../../../srcs/jmeter/setting-port-and-url-pattern.png) +### 3.2. 启动代理服务器 +1. **开始录制** + - 点击 **HTTP(S)测试脚本录制器** 窗口底部的 **开始** 按钮。 +
![start-recording-button.png](../../../srcs/jmeter/start-recording-button.png) +--- + +# [下一步:记录和管理HTTP请求](recording-and-managing-http-requests.md) \ No newline at end of file diff --git a/docs/cn/jmeter/lessons/configuring-browser-to-use-the-proxy-server.md b/docs/cn/jmeter/lessons/configuring-browser-to-use-the-proxy-server.md new file mode 100644 index 0000000..a3901e4 --- /dev/null +++ b/docs/cn/jmeter/lessons/configuring-browser-to-use-the-proxy-server.md @@ -0,0 +1,16 @@ +# 第4课:配置浏览器使用代理服务器 + +## 目标 +本课的目标是配置您的浏览器以使用在JMeter中设置的代理服务器来记录HTTP(S)请求。 + +## 步骤 + +### 4.1. 配置浏览器设置 +1. **在浏览器中设置代理** + - 打开浏览器设置,并导航到代理设置。 + - 将代理服务器地址设置为 `localhost`,端口设置为 `9090`。 + - 保存设置,如果需要,重新启动浏览器。 + +--- + +# [下一步:整理记录的请求](organizing-recorded-requests.md) \ No newline at end of file diff --git a/docs/cn/jmeter/lessons/creating-a-test-scenario.md b/docs/cn/jmeter/lessons/creating-a-test-scenario.md new file mode 100644 index 0000000..abbfe07 --- /dev/null +++ b/docs/cn/jmeter/lessons/creating-a-test-scenario.md @@ -0,0 +1,30 @@ +# 第7课:创建测试场景 + +## 目标 +本课的目标是通过整理记录的请求并在JMeter中添加动态值提取来创建一个测试场景。 + +## 步骤 + +### 7.1. 添加简单控制器 +1. **整理请求** + - 右键单击 **线程组**。 +
![thread-group-icon.png](../../../srcs/jmeter/thread-group-icon.png) + - 选择 **添加 > 逻辑控制器 > 简单控制器**。 +
![new-simple-controller-button.png](../../../srcs/jmeter/new-simple-controller-button.png) + - 将所有记录的HTTP请求从 **Recording Controller** 拖放到 **Simple Controller** 中。 + +### 7.2. 添加正则表达式提取器 +1. **动态值提取** + - 右键单击需要动态值的HTTP请求(例如,`javax.faces.ViewState`)。 + - 选择 **添加 > 后置处理器 > 正则表达式提取器**。 +
![new-regular-expression-button.png](../../../srcs/jmeter/new-regular-expression-button.png) + - 配置提取器: + - **引用名称:** `jsfViewState` + - **正则表达式:** `![regular-expression-extractor-fields.png](../../../srcs/jmeter/regular-expression-extractor-fields.png) + +--- + +# [下一步:给HTTP请求参数化](parameterizing-http-requests.md) \ No newline at end of file diff --git a/docs/cn/jmeter/lessons/executing-load-testing.md b/docs/cn/jmeter/lessons/executing-load-testing.md new file mode 100644 index 0000000..c7d2f2e --- /dev/null +++ b/docs/cn/jmeter/lessons/executing-load-testing.md @@ -0,0 +1,26 @@ +# 第10课:执行负载测试 + +## 目标 +本课的目标是在JMeter中配置和执行负载测试。 + +## 步骤 + +### 10.1. 调整线程设置 +1. **负载测试配置** + - 单击 **线程组**。 + - 根据负载测试的需求,设置 **线程数**(用户)、**Ramp-Up 周期**(秒)和 **循环次数**。 + +### 10.2. 添加汇总报告监听器 +1. **汇总报告** + - 右键单击 **简单控制器**。 + - 选择 **添加 > 监听器 > 汇总报告**。 + - 禁用 **查看结果树** 监听器,以提高负载测试期间的性能。 + +### 10.3. 运行负载测试 +1. **执行** + - 单击 **运行 > 启动** 开始执行负载测试。 + - 在 **汇总报告** 监听器中查看总结的结果。 + +--- + +# [下一步:分析测试结果](analyzing-test-results.md) \ No newline at end of file diff --git a/docs/cn/jmeter/lessons/introduction-to-jmeter-and-basic-setup.md b/docs/cn/jmeter/lessons/introduction-to-jmeter-and-basic-setup.md new file mode 100644 index 0000000..e66b2ae --- /dev/null +++ b/docs/cn/jmeter/lessons/introduction-to-jmeter-and-basic-setup.md @@ -0,0 +1,27 @@ +# 第1课:介绍JMeter和基本设置 + +## 目标 +本课的目标是介绍JMeter,并指导您完成基本设置过程,包括启动JMeter和向测试计划添加线程组。 + +## 步骤 + +### 1.1. 启动JMeter + +![jmeter-site.png](../../../srcs/jmeter/site.png) +1. **下载并安装JMeter** + - 访问[官方JMeter网站](https://jmeter.apache.org/download_jmeter.cgi)并下载最新版本。 + - 解压下载的存档文件。 + - 进入 `bin` 目录,并通过运行 `jmeter.bat` 文件(Windows)或 `jmeter.sh`(macOS/Linux)启动JMeter。 + +### 1.2. 添加线程组 +![interface.png](../../../srcs/jmeter/interface.png) +1. **创建测试计划** + - 打开JMeter。 + - 右键单击 **测试计划** 节点。 +
![test-plan.png](../../../srcs/jmeter/test-plan.png) + + - 选择 **添加 > 线程(用户) > 线程组**。 +
![test-plan.png](../../../srcs/jmeter/thread-group.png) + +--- +# [下一步:设置HTTP测试脚本记录器](setting-up-http-test-script-recorder.md) \ No newline at end of file diff --git a/docs/cn/jmeter/lessons/organizing-recorded-requests.md b/docs/cn/jmeter/lessons/organizing-recorded-requests.md new file mode 100644 index 0000000..e2ec5fe --- /dev/null +++ b/docs/cn/jmeter/lessons/organizing-recorded-requests.md @@ -0,0 +1,23 @@ +# 第6课:组织记录的请求 + +## 目标 +本课的目标是在JMeter中组织记录的HTTP请求,以便更好地管理和执行测试。 + +## 步骤 + +### 6.1. 禁用记录控制器 +1. **禁用** + - 在JMeter中右键单击 **Recording Controller**。 +
![recording-controller-button.png](../../../srcs/jmeter/recording-controller-button.png) + - 选择 **Disable** 以停止捕获进一步的请求。 +
![disable-element.png](../../../srcs/jmeter/disable-element.png) +### 6.2. 添加HTTP Cookie管理器 +1. **会话管理** + - 在 **线程组** 上右键单击。 +
![thread-group-icon.png](../../../srcs/jmeter/thread-group-icon.png) + - 选择 **添加 > 配置元件 > HTTP Cookie管理器**。 +
![new-http-cookie-manager-button.png](../../../srcs/jmeter/new-http-cookie-manager-button.png) + +--- + +# [下一步:创建测试方案](creating-a-test-scenario.md) \ No newline at end of file diff --git a/docs/cn/jmeter/lessons/parameterizing-http-requests.md b/docs/cn/jmeter/lessons/parameterizing-http-requests.md new file mode 100644 index 0000000..10c3bcd --- /dev/null +++ b/docs/cn/jmeter/lessons/parameterizing-http-requests.md @@ -0,0 +1,15 @@ +# 第8课:对HTTP请求进行参数化 + +## 目标 +本课的目标是使用提取的动态值在JMeter中对HTTP请求进行参数化。 + +## 步骤 + +### 8.1. 修改HTTP请求 +1. **使用提取的值** + - 在每个使用参数 `javax.faces.ViewState` 的HTTP请求中,将其值替换为 `${jsfViewState}`。 + - 如有必要,请确保选中 **Encode** 复选框。 + +--- + +# [下一步:添加监听器并运行测试](adding-listeners-and-running-tests.md) \ No newline at end of file diff --git a/docs/cn/jmeter/lessons/recording-and-managing-http-requests.md b/docs/cn/jmeter/lessons/recording-and-managing-http-requests.md new file mode 100644 index 0000000..6cbbe43 --- /dev/null +++ b/docs/cn/jmeter/lessons/recording-and-managing-http-requests.md @@ -0,0 +1,20 @@ +# 第5课:记录和管理HTTP请求 + +## 目标 +本课的目标是通过浏览Web应用程序记录HTTP请求,并在JMeter中管理记录的请求。 + +## 步骤 + +### 5.1. 记录HTTP请求 +1. **浏览应用程序** + - 以通常的方式浏览您的Web应用程序。JMeter将记录HTTP请求。 + +### 5.2. 停止录制 +1. **停止代理服务器** + - 返回到JMeter,并在**HTTP(S) Test Script Recorder**窗口中单击**停止**按钮。 +
![stop-recording-button.png](../../../srcs/jmeter/stop-recording-button.png) + - 在浏览器中禁用代理设置,以恢复直接的互联网访问。 + +--- + +# [下一步:组织记录的请求](organizing-recorded-requests.md) \ No newline at end of file diff --git a/docs/cn/jmeter/lessons/setting-up-http-test-script-recorder.md b/docs/cn/jmeter/lessons/setting-up-http-test-script-recorder.md new file mode 100644 index 0000000..017ba14 --- /dev/null +++ b/docs/cn/jmeter/lessons/setting-up-http-test-script-recorder.md @@ -0,0 +1,25 @@ +# 第2课:设置HTTP(S)测试脚本记录器 + +## 目标 +本课的目标是指导您在JMeter中设置HTTP(S)测试脚本记录器,包括添加Recording Controller和配置Proxy服务器。 + +## 步骤 + +### 2.1. 添加Recording Controller +1. **添加到线程组** + - 右键单击**线程组**。 +
![thread-group-icon.png](../../../srcs/jmeter/thread-group-icon.png) + + - 选择**添加 > 逻辑控制器 > Recording Controller**。 +
![recording-controller-button.png](../../../srcs/jmeter/recording-controller-button.png) + +### 2.2. 添加Proxy服务器 +1. **配置代理** + - 右键单击**工作台**节点。 +
![test-plan.png](../../../srcs/jmeter/test-plan.png) + - 选择**添加 > 非测试元件 > HTTP(S)测试脚本记录器**。 +
![test-script-recorder.png](../../../srcs/jmeter/test-script-recorder.png) + +--- + +# [下一步:配置和使用代理服务器](configuring-and-using-the-proxy-server.md) \ No newline at end of file diff --git a/docs/cn/jpa/lab-work.md b/docs/cn/jpa/lab-work.md new file mode 100644 index 0000000..4a0d0d3 --- /dev/null +++ b/docs/cn/jpa/lab-work.md @@ -0,0 +1,56 @@ +[English](../../en/jpa/lab-work.md) | 中文 | [Русский](../../ru/jpa/lab-work.md) + +# 实验任务: JPA (Java Persistence API) + +欢迎来到 Spring Boot with JPA 实验任务!在这个实验中,您将练习与使用 Spring Boot 和 JPA (Java Persistence API) 相关的各种任务。 + +## 实验任务的目标 + +这个实验的目标是提供与 Spring Boot 和 JPA 相关的关键概念和任务的实践经验。通过完成练习任务,您将掌握设置依赖关系、定义实体特性、管理实体之间关系以及使用 JpaRepository 与数据库交互等方面的技能。 + +## 练习任务 + +1. **设置数据库依赖关系** + - [设置数据库驱动程序](practice/dependencies/driver.md) + - [Spring Boot 和 JPA 依赖关系](practice/dependencies/jpa.md) + +2. **实体创建、特性、关系和获取策略** + - [创建实体](practice/creation/create-entity.md) + - [定义实体特性](practice/creation/characteristics.md) + - [管理关系](practice/creation/relationships.md) + - [获取策略](practice/creation/fetching.md) + +3. **与自定义存储库交互** + - [创建记录](practice/interacting/repository/create.md) + - [读取记录](practice/interacting/repository/read.md) + - [更新记录](practice/interacting/repository/update.md) + - [删除记录](practice/interacting/repository/delete.md) + - [自定义查询](practice/interacting/repository/query.md) + +4. **与 JPA 存储库交互** + - [创建记录](practice/interacting/jpa-repository/create.md) + - [读取记录](practice/interacting/jpa-repository/read.md) + - [删除记录](practice/interacting/jpa-repository/delete.md) + - [自定义查询](practice/interacting/jpa-repository/query.md) + + +## 实验任务 + +1. 为 PostgreSQL、MySQL、Oracle、MongoDB 和 Microsoft SQL Server 设置数据库依赖关系。 + +2. 实现下一个实体关系图: + ![img.png](../../srcs/jpa/task-er-diagram.png) + + 1. 根据实体关系图定义 Student、Enrollment 和 Course 实体的特性。 + + 2. 根据定义的特性创建 Student、Enrollment 和 Course 实体类。 + + 3. 实现有效的数据检索获取策略,以优化数据库交互。 + + 4. 通过建立适当的关联和映射,管理实体之间的关系,如 Student、Enrollment 和 Course。 + + 5. 通过在至少两个存储库中使用 Repository 层和 EntityManager,创建用于 CRUD 操作的方法,与数据库进行交互。 + + 6. 通过在至少两个存储库中使用 JpaRepository,创建用于 CRUD 操作的方法,与数据库进行交互。 + + 7. 根据应用程序的业务逻辑需求,实现自定义查询,执行高级数据检索和操作。 \ No newline at end of file diff --git a/docs/cn/jpa/practice/creation/characteristics.md b/docs/cn/jpa/practice/creation/characteristics.md new file mode 100644 index 0000000..7f54c88 --- /dev/null +++ b/docs/cn/jpa/practice/creation/characteristics.md @@ -0,0 +1,100 @@ +## 实体特性 + +### 学生实体特性: + +- `id`(UUID):实体的主键。 +- `name`(String):学生的姓名(不能为空)。 +- `email`(String):学生的电子邮件地址(必须是有效的电子邮件地址)。 +- `major`(String):学生的专业或研究领域(不能为空)。 +- `year`(int):学生的年级(不能为空)。 +- `international`(boolean):指示学生是否为国际学生(不能为空)。 + +### 定义 `id` 属性 + +向 `Student` 类添加 `id` 属性。该属性将作为实体的主键。 + +```java +@Id +@GeneratedValue(strategy = GenerationType.AUTO) +private UUID id; +``` + +- `@Id`:表示该字段是实体的主键。 +- `@GeneratedValue`:指定生成主键值的策略。 + +### 定义 `name` 属性 + +向 `Student` 类添加 `name` 属性。该属性表示学生的姓名,不能为空。 + +```java +@NotBlank +private String name; +``` + +- `@NotBlank`:确保 `name` 的值不为 null 并包含至少一个非空白字符。 + +### 定义 `email` 属性 + +向 `Student` 类添加 `email` 属性。该属性表示学生的电子邮件地址,必须是有效的电子邮件地址。 + +```java +@NotBlank +@Email +private String email; +``` + +- `@Email`:验证 `email` 的值是否为有效的电子邮件地址。 + +### 定义 `major` 属性 + +向 `Student` 类添加 `major` 属性。该属性表示学生的专业或研究领域,不能为空。 + +```java +@NotBlank +private String major; +``` + +- `@NotBlank`:确保 `major` 的值不为 null 并包含至少一个非空白字符。 + +### 定义 `year` 属性 + +向 `Student` 类添加 `year` 属性。该属性表示学生的年级,不能为空。 + +```java +@NotNull +private int year; +``` + +- `@NotNull`:确保 `year` 的值不为 null。 + +### 定义 `international` 属性 + +向 `Student` 类添加 `international` 属性。该属性表示学生是否为国际学生,不能为空。 + +```java +@NotNull +private boolean international; +``` + +- `@NotNull`:确保 `international` 的值不为 null。 + +您可以重复上述步骤,为 `Course` 和 `Enrollment` 实体创建实体特性,确保为每个属性应用适当的注释。 + +### Enrollment 实体特性: + +- `id`(UUID):实体的主键。 +- `enrollmentDate`(Date):注册日期。 +- `grade`(int):课程中获得的成绩。 + +### Course 实体特性: + +- `id`(UUID):实体的主键。 +- `name`(String):课程名称。 +- `instructor`(String):课程讲师姓名。 +- `schedule`(String):课程的安排详情。 +- `capacity`(int):课程的最大容量。 +- `online`(boolean):指示课程是否在线。 +- `startDate`(Date):课程的开始日期。 +--- + +# [下一步:管理关系](relationships.md) \ No newline at end of file diff --git a/docs/cn/jpa/practice/creation/create-entity.md b/docs/cn/jpa/practice/creation/create-entity.md new file mode 100644 index 0000000..1fdcdc2 --- /dev/null +++ b/docs/cn/jpa/practice/creation/create-entity.md @@ -0,0 +1,60 @@ +# 创建实体 + +## 介绍 + +本指南侧重于使用JPA(Java Persistence API)在Spring Boot项目中创建实体。它提供了逐步的说明,用于设置文件夹结构和创建实体类。 + +## 目标 + +本指南的目标是演示如何在Spring Boot项目中创建实体类,遵循最佳实践并利用JPA进行数据持久化。 + +## 文件夹结构 + +为了确保项目组织良好,建立正确的文件夹结构至关重要。请遵循以下准则: + +``` +src/ +└── main/ + └── java/ + └── com/ + └── example/ + └── demo/ + └── entity/ + ├── Student.java + ├── Enrollment.java + └── Course.java + +``` + +在这个结构中: +- `src/main/java` 目录包含您的Java源文件。 +- `com/example/demo/entity` 目录是您将创建实体类的地方。 + +## 创建实体类 + +要创建实体类,请按照以下步骤操作: + +1. 导航到您项目中的 `com/example/demo/entity` 目录。 +2. 为每个实体创建一个新的Java类文件。您可以为每个实体(例如,Student、Enrollment、Course)重复以下步骤。 +3. 使用 `@Entity` 注解定义您的实体类。 + +### 示例: + +```java +package com.example.demo.entity; + +import javax.persistence.Entity; + +@Entity +public class Student { + +} +``` + +`@Entity` 注解表示该类是一个JPA实体。 + +重复以上步骤以创建 `Enrollment` 和 `Course` 实体类。 + +--- + +# [下一步:实体特征定义](characteristics.md) \ No newline at end of file diff --git a/docs/cn/jpa/practice/creation/fetching.md b/docs/cn/jpa/practice/creation/fetching.md new file mode 100644 index 0000000..66ebb8e --- /dev/null +++ b/docs/cn/jpa/practice/creation/fetching.md @@ -0,0 +1,45 @@ +# Spring Boot中的获取策略与JPA:理解懒加载和急加载 + +## 介绍 + +本指南探讨了在使用JPA(Java Persistence API)的Spring Boot项目中的获取策略。具体来说,我们将深入研究懒加载和急加载的概念以及它们在实体关系中的应用。 + +## 目标 + +本指南的目标是全面了解JPA中的获取策略。通过本指南,您将了解何时使用懒加载和急加载以及如何在应用程序中实现它们。 + +## 获取策略 + +### 场景 + +在我们的实体关系中,`Student` 实体和 `Enrollment` 实体之间存在一对多的关系。同样,`Course` 实体和 `Enrollment` 实体之间也存在一对多的关系。 + +#### Student 实体 + +在 `Student` 实体中,我们与 `Enrollment` 实体之间存在一对多的关系。每个学生可以有多个注册。 + +为了表示这种关系,我们在 `Student` 实体中使用了 `@OneToMany` 注解,并指定了 `mappedBy = "student"`。在这里,我们可以选择懒加载和急加载策略来获取关联的注册。 + +```java +@OneToMany(mappedBy = "student", fetch = FetchType.EAGER, cascade = CascadeType.ALL) +private List enrollments; +``` + +在这种情况下,我们选择了急加载(`FetchType.EAGER`)。由于我们通常期望一次访问一个学生的所有注册,急加载确保在加载学生时立即获取所有注册。 + +#### Course 实体 + +类似地,在 `Course` 实体中,我们还与 `Enrollment` 实体存在一对多的关系。每个课程可以有多个注册。 + +为了表示这种关系,我们在 `Course` 实体中使用了 `@OneToMany` 注解,并指定了 `mappedBy = "course"`。在这里,我们可以选择另一种懒加载和急加载策略来获取关联的注册。 + +```java +@OneToMany(mappedBy = "course", fetch = FetchType.LAZY, cascade = CascadeType.ALL) +private List enrollments; +``` + +在这种情况下,我们选择了懒加载(`FetchType.LAZY`)。由于我们可能并不总是需要访问一个课程的所有注册,懒加载确保只有在明确请求时才获取注册。 + +--- + +# [下一步:创建存储库](../interacting/repository.md) \ No newline at end of file diff --git a/docs/cn/jpa/practice/creation/relationships.md b/docs/cn/jpa/practice/creation/relationships.md new file mode 100644 index 0000000..cfe78aa --- /dev/null +++ b/docs/cn/jpa/practice/creation/relationships.md @@ -0,0 +1,45 @@ +# 定义实体关系 + +## 介绍 + +本指南深入探讨了在使用JPA(Java Persistence API)的Spring Boot项目中理解和实现实体之间的关系。具体来说,我们将探讨 `Enrollment` 实体与其关联实体 `Student` 和 `Course` 之间的关系。 + +## 目标 + +本指南的目标是提供清晰的说明,以便在使用JPA的Spring Boot项目中定义和理解实体关系。通过本指南,您将了解如何在应用程序中建立实体之间的关联并加以实现。 + +## 实体关联 + +![img.png](../../../../srcs/jpa/er-diagram.png) + +### Enrollment 实体特征: + +- `id`(UUID):实体的主键。 +- `student`(Student):与注册关联的学生。 +- `course`(Course):与注册关联的课程。 +- `enrollmentDate`(日期):注册日期。 +- `grade`(整数):课程中获得的成绩。 + +#### 学生关系 + +`Enrollment` 实体与 `Student` 实体之间的关系代表了一个场景,即学生在课程中注册。这是一种多对一的关系,一个学生可以与多个注册相关联。要建立这种关系,在 `Enrollment` 实体中的 `student` 属性上使用 `@ManyToOne` 进行注解。 + +```java +@ManyToOne +@JoinColumn(name = "student_id") +private Student student; +``` + +#### 课程关系 + +同样,`Enrollment` 实体与 `Course` 实体之间的关系表示了多个学生注册了一个课程的场景。这也是一种多对一的关系,一个课程可以与多个注册相关联。在 `Enrollment` 实体中的 `course` 属性上进行注解,使用 `@ManyToOne`。 + +```java +@ManyToOne +@JoinColumn(name = "course_id") +private Course course; +``` + +--- + +# [下一步:获取策略](fetching.md) \ No newline at end of file diff --git a/docs/cn/jpa/practice/dependencies/driver.md b/docs/cn/jpa/practice/dependencies/driver.md new file mode 100644 index 0000000..ef401b6 --- /dev/null +++ b/docs/cn/jpa/practice/dependencies/driver.md @@ -0,0 +1,100 @@ +# JPA: 设置依赖项 + +## 简介 + +本指南着重介绍了如何为具有JPA(Java Persistence API)的Spring Boot项目设置依赖项。它涵盖了包括PostgreSQL、MySQL、Oracle、MongoDB和Microsoft SQL Server等各种数据库的数据库驱动程序的必要步骤。通过按照本指南的步骤,您将配置所有必需的依赖项,以在Spring Boot应用程序中与这些数据库建立连接。 + +## 目标 + +本指南的目标是提供清晰的说明,以便设置Spring Boot和JPA的必要依赖项,特别关注不同数据库的数据库驱动程序。 + +## 设置依赖项 + +### 数据库驱动程序 + +要连接Spring Boot应用程序中的不同数据库,请包含相应的数据库驱动程序。 + +#### PostgreSQL + +**对于Gradle:** +```groovy +implementation "org.postgresql:postgresql" +``` + +**对于Maven:** +```xml + + org.postgresql + postgresql + INSERT_VERSION_HERE + +``` + +#### MySQL + +**对于Gradle:** +```groovy +implementation "mysql:mysql-connector-java" +``` + +**对于Maven:** +```xml + + mysql + mysql-connector-java + INSERT_VERSION_HERE + +``` + +#### Oracle数据库驱动程序 + +**对于Gradle:** +```groovy +implementation 'com.oracle.database.jdbc:ojdbc8' +``` + +**对于Maven:** +```xml + + com.oracle.database.jdbc + ojdbc8 + +``` + +#### MongoDB驱动程序(MongoDB Java驱动程序) + +**对于Gradle:** +```groovy +implementation 'org.mongodb:mongodb-driver-sync:4.4.3' +``` + +**对于Maven:** +```xml + + org.mongodb + mongodb-driver-sync + 4.4.3 + +``` + +#### Microsoft SQL Server JDBC驱动程序 + +**对于Gradle:** +```groovy +implementation 'com.microsoft.sqlserver:mssql-jdbc:9.4.0.jre11' +``` + +**对于Maven:** +```xml + + com.microsoft.sqlserver + mssql-jdbc + 9.4.0.jre11 + +``` + +这些依赖项有助于数据库连接。 + +--- + +# [下一步:Spring Boot和JPA依赖项](jpa.md) \ No newline at end of file diff --git a/docs/cn/jpa/practice/dependencies/jpa.md b/docs/cn/jpa/practice/dependencies/jpa.md new file mode 100644 index 0000000..6f1667e --- /dev/null +++ b/docs/cn/jpa/practice/dependencies/jpa.md @@ -0,0 +1,183 @@ +# JPA:设置依赖关系 + +## 介绍 + +本指南侧重于为具有 JPA(Java Persistence API)的 Spring Boot 项目设置依赖关系。它涵盖了包括 Spring Boot Starter JDBC 和 Spring Boot Starter Data JPA 依赖项的必要步骤。 + +## 目标 + +本指南的目标是为 Spring Boot 和 JPA 设置必要的依赖关系,并特别关注 Spring Boot Starter JDBC 和 Spring Boot Starter Data JPA 依赖项。 + +## 设置依赖关系 + +### Spring Boot Starter JDBC + +要在 Spring Boot 应用程序中启用 JDBC 支持: + +#### Gradle + +```groovy +implementation "org.springframework.boot:spring-boot-starter-jdbc" +``` + +#### Maven + +```xml + + org.springframework.boot + spring-boot-starter-jdbc + +``` + +此依赖项为基于 JDBC 的数据访问提供了自动配置。 + +### Spring Boot Starter Data JPA + +要在 Spring Boot 应用程序中包含对 JPA(Java Persistence API)的支持: + +#### Gradle + +```groovy +implementation "org.springframework.boot:spring-boot-starter-data-jpa" +``` + +#### Maven + +```xml + + org.springframework.boot + spring-boot-starter-data-jpa + +``` + +此依赖项简化了基于 JPA 的存储库的设置,并为 Hibernate 提供了默认配置。 + +### Spring WebMVC 的附加配置 + +如果您使用 Spring WebMVC,则需要添加额外的配置以设置与持久性相关的 bean 和属性。 + +#### 创建持久性配置类 + +在 `com.example.config` 包中创建一个名为 `PersistenceConfig` 的新类: + +```java +package com.example.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.persistence.EntityManagerFactory; +import javax.sql.DataSource; + +/** + * 用于设置与持久性相关的 bean 和属性的配置类。 + * + *

+ * 该类配置了用于 JPA 的数据源、实体管理器工厂和事务管理器。 + * 它从外部属性文件中读取数据库连接属性。 + *

+ */ +@Configuration +@EnableTransactionManagement +@EnableJpaRepositories(basePackages = "com.example.repository") +@PropertySource({"classpath:application.properties"}) +public class PersistenceConfig { + + @Value("${spring.datasource.driver}") + private String dbDriver; + + @Value("${spring.datasource.url}") + private String dbUrl; + + @Value("${spring.datasource.username}") + private String dbUsername; + + @Value("${spring.datasource.password}") + private String dbPassword; + + @Value("${spring.jpa.properties.hibernate.dialect}") + private String hibernateDialect; + + @Value("${spring.jpa.properties.hibernate.show_sql}") + private boolean hibernateShowSql; + + @Value("${spring.jpa.hibernate.ddl-auto}") + private String hibernateHbm2ddlAuto; + + /** + * 数据源的 Bean 定义。 + * + *

+ * 此方法使用在 application.properties 文件中定义的属性设置数据源。 + *

+ * + * @return DataSource bean + */ + @Bean + public DataSource dataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName(dbDriver); + dataSource.setUrl(dbUrl); + dataSource.setUsername(dbUsername); + dataSource.setPassword(dbPassword); + return dataSource; + } + + /** + * EntityManagerFactory 的 Bean 定义。 + * + *

+ * 此方法使用配置的数据源和 Hibernate 属性设置实体管理器工厂。 + *

+ * + * @param dataSource 数据源 bean + * @return EntityManagerFactory bean + */ + @Bean + public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) { + LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); + em.setDataSource(dataSource); + em.setPackagesToScan("com.example.entity"); + + HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); + vendorAdapter.setDatabasePlatform(hibernateDialect); + vendorAdapter.setShowSql(hibernate + +ShowSql); + vendorAdapter.setGenerateDdl("update".equalsIgnoreCase(hibernateHbm2ddlAuto)); + em.setJpaVendorAdapter(vendorAdapter); + + return em; + } + + /** + * Spring 事务管理器的 Bean 定义。 + * + *

+ * 此方法使用配置的实体管理器工厂设置 JPA 的事务管理器。 + *

+ * + * @param entityManagerFactory 实体管理器工厂 bean + * @return 事务管理器 bean + */ + @Bean + public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { + JpaTransactionManager txManager = new JpaTransactionManager(); + txManager.setEntityManagerFactory(entityManagerFactory); + return txManager; + } +} +``` + +--- + +# [下一步:实体创建](../creation/create-entity.md) \ No newline at end of file diff --git a/docs/cn/jpa/practice/interacting/jpa-repository.md b/docs/cn/jpa/practice/interacting/jpa-repository.md new file mode 100644 index 0000000..e0dd740 --- /dev/null +++ b/docs/cn/jpa/practice/interacting/jpa-repository.md @@ -0,0 +1,52 @@ +# 创建JpaRepository + +## 介绍 + +本指南演示了如何在Spring Boot项目中使用JpaRepository创建实体管理的存储库(Repository)。 + +## 目标 + +本指南的目标是提供清晰的说明,以便在Spring Boot应用程序中设置用于管理实体的存储库。通过本指南,您将能够为`Course`实体创建存储库和服务类。 + +## 文件夹结构 + +``` +src/ +└── main/ + └── java/ + └── com/ + └── example/ + └── demo/ + ├── data/ + │ └── entities/ + │ ├── Student.java + │ ├── Enrollment.java + │ └── Course.java + └── repository/ + ├── StudentRepository.java + └── CourseRepository.java + +``` + +## 存储库类 + +### CourseRepository.java + +```java +package com.yourcompany.yourproject.repository; + +import com.yourcompany.yourproject.model.Course; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface CourseRepository extends JpaRepository { + // 添加用于课程实体的存储库方法 +} +``` + +`@Repository` 注解是一个Spring的构造型注解,用于指示被修饰的类是数据访问层中的存储库组件。它作为任何充当存储库角色的类的标记,有助于将异常转换为Spring的统一异常层次结构。 + +--- + +# [下一步:创建记录](jpa-repository/create.md) \ No newline at end of file diff --git a/docs/cn/jpa/practice/interacting/jpa-repository/create.md b/docs/cn/jpa/practice/interacting/jpa-repository/create.md new file mode 100644 index 0000000..19f9eb5 --- /dev/null +++ b/docs/cn/jpa/practice/interacting/jpa-repository/create.md @@ -0,0 +1,38 @@ +# 使用JpaRepository在表中创建记录 + +## 简介 + +本指南演示了如何在Spring Boot应用程序中使用JPA(Java Persistence API)和JpaRepository的存储库层创建表中的记录。 + +## 目标 + +本指南的目标是通过在`CourseRepository`接口中实现方法来说明在表中创建记录的过程。 + +## 存储库方法 + +### CourseRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Course; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.UUID; + +@Repository +public interface CourseRepository extends JpaRepository { + + Course save(Course course); +} +``` + +### 解释 + +JpaRepository提供的`save(Course course)`方法允许我们将新记录持久化到`Course`表中。 + +通过调用此方法并将`Course`对象作为参数传递,JpaRepository自动处理将实体持久化到数据库的过程。 + +--- + +# [下一步:读取记录](read.md) \ No newline at end of file diff --git a/docs/cn/jpa/practice/interacting/jpa-repository/delete.md b/docs/cn/jpa/practice/interacting/jpa-repository/delete.md new file mode 100644 index 0000000..ef0cb6d --- /dev/null +++ b/docs/cn/jpa/practice/interacting/jpa-repository/delete.md @@ -0,0 +1,41 @@ +# 使用JpaRepository从表中删除记录 + +## 简介 + +本指南演示了如何在Spring Boot应用程序中使用JPA(Java Persistence API)和JpaRepository的存储库层删除表中的记录。 + +## 目标 + +本指南的目标是通过在`CourseRepository`接口中实现方法来说明从表中删除记录的过程。 + +## 存储库方法 + +### CourseRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Course; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.UUID; + +@Repository +public interface CourseRepository extends JpaRepository { + + void deleteById(UUID id); +} +``` + +## 解释 + +`deleteById(UUID id)`方法的签名遵循JpaRepository的约定,用于根据唯一标识符删除记录。 + +- `delete`关键字表示此方法用于删除数据。 +- `ById`指定了要删除的记录的标识条件。在本例中,我们针对具有特定ID的记录进行操作。 + +通过遵循这种命名约定,JpaRepository会在后台自动生成适当的SQL查询,以从数据库中删除所需的记录。这简化了开发过程,无需编写显式的SQL删除语句,使开发人员可以专注于定义反映预期数据删除操作的方法签名。 + +--- + +# [下一步:自定义查询](query.md) \ No newline at end of file diff --git a/docs/cn/jpa/practice/interacting/jpa-repository/query.md b/docs/cn/jpa/practice/interacting/jpa-repository/query.md new file mode 100644 index 0000000..e5274b8 --- /dev/null +++ b/docs/cn/jpa/practice/interacting/jpa-repository/query.md @@ -0,0 +1,43 @@ +# 使用JpaRepository进行自定义查询 + +## 简介 + +本指南演示了如何在Spring Boot应用程序的存储库层中使用`@Query`注解实现自定义查询方法,该应用程序使用JPA(Java Persistence API)和JpaRepository。 + +## 目标 + +本指南的目标是说明在存储库接口中创建自定义查询方法的过程,以执行特定于应用程序要求的数据库操作。 + +## 存储库方法 + +### CourseRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Course; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; +import java.util.List; + +@Repository +public interface CourseRepository extends JpaRepository { + + @Query("SELECT c FROM Course c WHERE c.instructor = :instructor") + List findCoursesByInstructor(@Param("instructor") String instructor); +} +``` + +### 解释 + +`@Query`注解允许我们在存储库接口中直接定义自定义JPQL(Java Persistence Query Language)查询。 + +- `"SELECT c FROM Course c WHERE c.instructor = :instructor"`是一个JPQL查询,它选择所有教师与提供的值匹配的课程。 +- `@Param("instructor")`注解将方法参数`instructor`绑定到JPQL查询中的命名参数`:instructor`。 + +通过使用`@Query`,我们可以创建适用于特定数据检索需求的复杂查询,从而提供对数据库操作的灵活性和控制。 + +--- + +# [下一步:任务](../../../lab-work.md) \ No newline at end of file diff --git a/docs/cn/jpa/practice/interacting/jpa-repository/read.md b/docs/cn/jpa/practice/interacting/jpa-repository/read.md new file mode 100644 index 0000000..0579d17 --- /dev/null +++ b/docs/cn/jpa/practice/interacting/jpa-repository/read.md @@ -0,0 +1,42 @@ +# 使用JpaRepository从表中读取记录 + +## 简介 + +本指南演示了如何在Spring Boot应用程序的存储库层中使用JPA(Java Persistence API)和JpaRepository检索数据表中的数据。 + +## 目标 + +本指南的目标是通过在`CourseRepository`接口中使用JpaRepository实现一个方法,来说明从表中读取数据的过程。 + +## 存储库方法 + +### CourseRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Course; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.List; + +@Repository +public interface CourseRepository extends JpaRepository { + + List findCoursesByInstructor(String instructor); +} +``` + +### 解释 + +`findCoursesByInstructor(String instructor)`方法签名遵循Spring Data JPA识别的特定命名约定。 + +- `find`关键字表示此方法用于检索数据。 +- `Courses`表示我们要检索的实体类型。 +- `ByInstructor`指定了筛选结果的条件。在本例中,我们基于`instructor`属性查询课程。 + +通过遵循这种命名约定,Spring Data JPA在幕后自动生成适当的SQL查询,以从数据库中提取所需的数据。这简化了开发过程,无需编写显式的SQL查询,开发人员可以专注于定义反映所需数据检索操作的方法签名。 + +--- + +# [下一步:删除记录](delete.md) \ No newline at end of file diff --git a/docs/cn/jpa/practice/interacting/repository.md b/docs/cn/jpa/practice/interacting/repository.md new file mode 100644 index 0000000..abe7d96 --- /dev/null +++ b/docs/cn/jpa/practice/interacting/repository.md @@ -0,0 +1,50 @@ +# 创建存储库 + +## 简介 + +本指南演示了如何在Spring Boot项目中使用JPA(Java Persistence API)创建用于实体管理的存储库。 + +## 目标 + +本指南的目标是提供清晰的说明,以便在Spring Boot应用程序中设置用于管理实体的存储库。通过本指南,您将能够为`Student`实体创建存储库。 + +## 文件夹结构 + +``` +src/ +└── main/ + └── java/ + └── com/ + └── example/ + └── demo/ + ├── data/ + │ └── entities/ + │ ├── Student.java + │ ├── Enrollment.java + │ └── Course.java + └── repository/ + └── StudentRepository.java + +``` + +## 存储库类 + +### StudentRepository.java + +```java +package com.yourcompany.yourproject.repository; + +import com.yourcompany.yourproject.model.Student; +import org.springframework.stereotype.Repository; + +@Repository +public class StudentRepository { + // 为学生实体添加存储库方法 +} +``` + +`@Repository` 注解是Spring的一种类型注解,用于指示被修饰的类是数据访问层中的存储库组件。它作为任何充当存储库角色的类的标记,有助于将异常转换为Spring的统一异常层次结构。 + +--- + +# [下一步:创建记录](repository/create.md) \ No newline at end of file diff --git a/docs/cn/jpa/practice/interacting/repository/create.md b/docs/cn/jpa/practice/interacting/repository/create.md new file mode 100644 index 0000000..4f0df03 --- /dev/null +++ b/docs/cn/jpa/practice/interacting/repository/create.md @@ -0,0 +1,46 @@ +# 使用存储库层在表中创建新记录 + +## 简介 + +本指南演示了如何在Spring Boot应用程序中使用存储库层创建表中的新记录,该应用程序使用了JPA(Java Persistence API)。 + +## 目标 + +本指南的目标是通过利用存储库层实现在表中创建新记录的过程。我们将通过在`StudentRepository`接口中使用`EntityManager`而不是`JpaRepository`来实现这一目标。 + +## 存储库方法 + +### StudentRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Student; +import org.springframework.stereotype.Repository; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.transaction.Transactional; + +@Repository +public class StudentRepository { + + @PersistenceContext + private EntityManager entityManager; + + public void saveStudent(Student student) { + entityManager.persist(student); + } +} +``` + +### 解释 + +- `@Repository`:此注解将该类标记为数据访问层中的存储库组件。 + +- `@PersistenceContext`:此注解用于将EntityManager实例注入存储库类中。 + +- `entityManager.persist(student)`:这行代码将新的`Student`实体持久化到数据库中。 + +--- + +# [下一步:读取记录](read.md) \ No newline at end of file diff --git a/docs/cn/jpa/practice/interacting/repository/delete.md b/docs/cn/jpa/practice/interacting/repository/delete.md new file mode 100644 index 0000000..bdc3752 --- /dev/null +++ b/docs/cn/jpa/practice/interacting/repository/delete.md @@ -0,0 +1,47 @@ +# 使用存储库层从表中删除记录 + +## 简介 + +本指南演示了如何在Spring Boot应用程序中使用存储库层删除表中的记录,该应用程序使用了JPA(Java Persistence API)。 + +## 目标 + +本指南的目标是通过在`StudentRepository`接口中使用`EntityManager`实现删除表中记录的过程。 + +## 存储库方法 + +### StudentRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Student; +import org.springframework.stereotype.Repository; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.transaction.Transactional; + +@Repository +public class StudentRepository { + + @PersistenceContext + private EntityManager entityManager; + + public void deleteStudent(UUID id) { + Student studentToDelete = entityManager.find(Student.class, id); + entityManager.remove(studentToDelete); + } +} +``` + +### 解释 + +- `@Repository`:此注解将该类标记为数据访问层中的存储库组件。 + +- `@PersistenceContext`:此注解用于将EntityManager实例注入存储库类中。 + +- `entityManager.remove(studentToDelete)`:这行代码从数据库中删除`Student`实体。 + +--- + +# [下一步:自定义查询](query.md) \ No newline at end of file diff --git a/docs/cn/jpa/practice/interacting/repository/query.md b/docs/cn/jpa/practice/interacting/repository/query.md new file mode 100644 index 0000000..f8bfaf3 --- /dev/null +++ b/docs/cn/jpa/practice/interacting/repository/query.md @@ -0,0 +1,49 @@ +# 在存储库层创建自定义查询以从表中获取记录 + +## 简介 + +本指南演示了如何在Spring Boot应用程序中使用存储库层创建自定义查询来从表中获取记录,该应用程序使用了JPA(Java Persistence API)。 + +## 目标 + +本指南的目标是通过在`StudentRepository`接口中使用`EntityManager`实现创建自定义查询来从表中获取记录的过程。 + +## 存储库方法 + +### StudentRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Student; +import org.springframework.stereotype.Repository; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.transaction.Transactional; +import java.util.List; + +@Repository +public class StudentRepository { + + @PersistenceContext + private EntityManager entityManager; + + public List findStudentsByMajor(String major) { + return entityManager.createQuery("SELECT s FROM Student s WHERE s.major = :major", Student.class) + .setParameter("major", major) + .getResultList(); + } +} +``` + +### 解释 + +- `@Repository`:此注解将该类标记为数据访问层中的存储库组件。 + +- `@PersistenceContext`:此注解用于将EntityManager实例注入存储库类中。 + +- `entityManager.createQuery(...)`:这行代码创建了一个自定义的JPQL(Java Persistence Query Language)查询,以根据提供的条件(在此示例中为`major`)从表中获取记录。 + +--- + +# [下一步:创建JpaRepository](../jpa-repository.md) \ No newline at end of file diff --git a/docs/cn/jpa/practice/interacting/repository/read.md b/docs/cn/jpa/practice/interacting/repository/read.md new file mode 100644 index 0000000..a87f290 --- /dev/null +++ b/docs/cn/jpa/practice/interacting/repository/read.md @@ -0,0 +1,47 @@ +# 使用存储库层从表中读取记录 + +## 简介 + +本指南演示了如何在Spring Boot应用程序中使用存储库层从表中读取记录,该应用程序使用了JPA(Java Persistence API)。 + +## 目标 + +本指南的目标是通过在`StudentRepository`接口中使用`EntityManager`实现方法来从表中读取记录的过程。 + +## 存储库方法 + +### StudentRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Student; +import org.springframework.stereotype.Repository; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.transaction.Transactional; +import java.util.UUID; + +@Repository +public class StudentRepository { + + @PersistenceContext + private EntityManager entityManager; + + public Student findStudentById(UUID id) { + return entityManager.find(Student.class, id); + } +} +``` + +### 解释 + +- `@Repository`:此注解将该类标记为数据访问层中的存储库组件。 + +- `@PersistenceContext`:此注解用于将EntityManager实例注入存储库类中。 + +- `entityManager.find(Student.class, id)`:这行代码根据提供的`id`从数据库中检索`Student`实体。 + +--- + +# [下一步:更新记录](update.md) diff --git a/docs/cn/jpa/practice/interacting/repository/update.md b/docs/cn/jpa/practice/interacting/repository/update.md new file mode 100644 index 0000000..97a54f9 --- /dev/null +++ b/docs/cn/jpa/practice/interacting/repository/update.md @@ -0,0 +1,46 @@ +# 使用存储库层更新表中的记录 + +## 简介 + +本指南演示了如何在Spring Boot应用程序中使用存储库层更新表中的记录,该应用程序使用了JPA(Java Persistence API)。 + +## 目标 + +本指南的目标是通过在`StudentRepository`接口中使用`EntityManager`实现方法来更新表中的记录。 + +## 存储库方法 + +### StudentRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Student; +import org.springframework.stereotype.Repository; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.transaction.Transactional; + +@Repository +public class StudentRepository { + + @PersistenceContext + private EntityManager entityManager; + + public Student updateStudent(Student student) { + return entityManager.merge(student); + } +} +``` + +### 解释 + +- `@Repository`:此注解将该类标记为数据访问层中的存储库组件。 + +- `@PersistenceContext`:此注解用于将EntityManager实例注入存储库类中。 + +- `entityManager.merge(student)`:这行代码将在数据库中更新`Student`实体。 + +--- + +# [下一步:删除记录](delete.md) diff --git a/docs/cn/springsecurity/lab-work.md b/docs/cn/springsecurity/lab-work.md new file mode 100644 index 0000000..1830a34 --- /dev/null +++ b/docs/cn/springsecurity/lab-work.md @@ -0,0 +1,62 @@ +[English](../../en/springsecurity/lab-work.md) | 中文 | [Русский](../../ru/springsecurity/lab-work.md) + +# Spring Security 实验任务 + +欢迎来到 Spring Security 实验任务系列!本系列任务旨在帮助您实践并熟悉 Spring Security,从而建立一个足够的启动项目。无论您是初学者还是希望提升技能,这些动手任务将引导您完成在 Spring 应用中集成安全性的各个方面。 + +## 实验任务的目标 + +本实验任务的主要目标是让您在 Spring 环境中使用安全性获得实际经验和熟练程度。Spring Security 广泛用于身份验证、授权和保护项目,通过这些任务,您将深入了解其配置、身份验证、授权等方面。 + +## 练习任务 + +1. [任务 1:配置 Spring Security](practice/configure-spring-security.md) +2. [任务 2:创建用户的基本实现](practice/base-implementation-user.md) +3. [任务 3:密码加密](practice/password-encryption.md) +4. [任务 4:添加虚拟用户](practice/add-dummy-users.md) +5. [任务 5:为用户创建身份](practice/create-identity-to-users.md) +6. [任务 6:在服务器中创建授权基础](practice/setup-server-authorization.md) +7. [任务 7:授权已认证用户](practice/authorize-server-authenticated.md) +8. [任务 8:按角色授权](practice/authorize-server-role.md) +9. [任务 9:按权限授权](practice/authorize-server-authority.md) +10. [任务 10:配置 Thymeleaf 安全性](practice/configure-thymeleaf-security.md) +11. [任务 11:授权已认证用户](practice/authorize-client-authenticated.md) +12. [任务 12:按角色授权](practice/authorize-client-role.md) +13. [任务 13:按权限授权](practice/authorize-client-authority.md) +14. [任务 14:自定义登录表单](practice/custom-login-form.md) + +## 实验任务 + +![img.png](../../srcs/springsecurity/task.png) + +### 任务 1:设置 Spring Security +在项目中初始化 Spring Security。 + +### 任务 2:定义用户角色和权限 +定义不同的用户角色(管理员、教师、学生)及其相应的权限。 + +### 任务 3:在控制器中配置安全性 +使用基于角色的访问控制保护端点。 + +#### 实现细节 +**管理员角色**: +- 添加新教师 (`/teachers/new`) +- 修改教师资料 (`/teachers/{id}/edit`) +- 修改学生资料 (`/students/{id}/edit`) +- 修改学生成绩 (`/students/{id}/marks/edit`) + +**教师角色**: +- 修改学生成绩 (`/students/{id}/marks/edit`) +- 添加新科目 (`/subjects/new`) +- 添加新考试 (`/tests/new`) + +**学生角色**: +- 参加考试 (`/tests/{id}/take`) +- 查看成绩 (`/students/{id}/marks`) + +### 任务 4:在 Thymeleaf 模板中实现授权 +基于用户角色限制对 UI 元素的访问。 + +### 任务 5:测试基于角色的访问控制 +确保端点和 UI 元素受到正确保护。 + diff --git a/docs/cn/springsecurity/practice/add-dummy-users.md b/docs/cn/springsecurity/practice/add-dummy-users.md new file mode 100644 index 0000000..7ec6c28 --- /dev/null +++ b/docs/cn/springsecurity/practice/add-dummy-users.md @@ -0,0 +1,64 @@ +# 添加虚拟用户 + +本任务概述了更新 `CustomUserDetailsService` 类的过程,以包含用于将虚拟用户添加到内存存储的方法,从而作为用户创建的简单演示。 + +## 目标 + +更新 `CustomUserDetailsService` 类以包含添加虚拟用户的方法,允许在内存存储中初始化用户数据。 + +## 步骤 + +1. **更新 CustomUserDetailsService 类:** + + 首先,我们需要更新 `CustomUserDetailsService` 类,以包含用于添加虚拟用户的方法。我们将在 bean 初始化期间利用此方法将虚拟用户数据填充到内存存储中。 + + ```java + @Service + public class CustomUserDetailsService implements UserDetailsService { + + private final UsersRepository usersRepository; + private final PasswordEncoder passwordEncoder; + + @Autowired + public CustomUserDetailsService(UsersRepository usersRepository, PasswordEncoder passwordEncoder) { + this.usersRepository = usersRepository; + this.passwordEncoder = passwordEncoder; + + // 在 bean 初始化期间调用 addDummyUsers 方法以添加虚拟用户 + addDummyUsers(); + } + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + // 从存储库中检索用户详细信息 + CustomUserDetails userDetails = usersRepository.findByUsername(username); + if (userDetails == null) { + throw new UsernameNotFoundException("User not found with username: " + username); + } + return userDetails; + } + + // 添加虚拟用户的方法 + private void addDummyUsers() { + // 创建虚拟用户 + CustomUserDetails admin = new CustomUserDetails("admin", passwordEncoder.encode("admin"), true, true, true, true); + CustomUserDetails moderator = new CustomUserDetails("moderator", passwordEncoder.encode("moderator"), true, true, true, true); + CustomUserDetails user = new CustomUserDetails("user", passwordEncoder.encode("user"), true, true, true, true); + + // 将用户添加到存储库 + usersRepository.save(admin); + usersRepository.save(moderator); + usersRepository.save(user); + } + } + ``` + + 在这个更新的类中: + - 我们添加了一个接受 `UsersRepository` 和 `PasswordEncoder` 作为依赖项的构造函数。 + - 在 bean 初始化期间,构造函数调用 `addDummyUsers` 方法,将虚拟用户数据填充到内存存储中。 + - `addDummyUsers` 方法创建具有硬编码用户名和密码的虚拟用户。 + - 最后,虚拟用户通过 `save` 方法保存到存储库中。 + +--- + +# [下一任务: 为用户创建身份](create-identity-to-users.md) \ No newline at end of file diff --git a/docs/cn/springsecurity/practice/authorize-client-authenticated.md b/docs/cn/springsecurity/practice/authorize-client-authenticated.md new file mode 100644 index 0000000..dd3b7a8 --- /dev/null +++ b/docs/cn/springsecurity/practice/authorize-client-authenticated.md @@ -0,0 +1,54 @@ +# 客户端授权认证用户(客户端) + +这项任务概述了如何使用Thymeleaf在客户端视图中根据用户的认证状态授权用户。通过根据用户是否已经认证来显示或隐藏元素,您可以控制特定功能或操作的可见性。 + +## 目标 + +在Thymeleaf视图中根据用户的认证状态控制与添加和删除学生相关的元素的可见性。 + +## 步骤 + +1. **更新Thymeleaf模板:** + + 修改Thymeleaf模板以根据用户的认证状态有条件地显示元素。 + + ```html + + + + 学生管理 + + +

学生管理

+ + + + + + + + +
+

欢迎使用学生管理系统。在这里您可以管理学生记录。

+
+ + + ``` + + 在此模板中: + - 使用`th:if="${#authorization.expression('isAuthenticated()')}"`语句仅在用户已认证时条件显示“添加学生”和“删除学生”按钮。 + +## 解释 + +- **Thymeleaf安全方言**:`#authorization`对象是Thymeleaf安全方言的一部分,它将Spring Security与Thymeleaf集成在一起。 +- **条件显示**:使用`th:if`属性根据用户的认证状态有条件地显示或隐藏元素。 + +通过按照这些步骤,您可以根据用户是否已认证来控制Thymeleaf视图中元素的可见性,确保只有经过认证的用户才能看到和与特定功能进行交互。 + +--- + +# [下一个任务:按角色授权](authorize-client-role.md) \ No newline at end of file diff --git a/docs/cn/springsecurity/practice/authorize-client-authority.md b/docs/cn/springsecurity/practice/authorize-client-authority.md new file mode 100644 index 0000000..a465bb4 --- /dev/null +++ b/docs/cn/springsecurity/practice/authorize-client-authority.md @@ -0,0 +1,55 @@ +# 根据权限授权用户(客户端) + +本任务概述了如何使用Thymeleaf在客户端视图中根据用户的权限授权用户。通过根据用户权限显示或隐藏元素,您可以控制特定功能或操作的可见性。 + +## 目标 + +在Thymeleaf视图中根据用户的权限控制与添加和删除学生相关的元素的可见性。 + +## 步骤 + +1. **更新Thymeleaf模板:** + + 修改Thymeleaf模板以根据用户的权限有条件地显示元素。 + + ```html + + + + 学生管理 + + +

学生管理

+ + + + + + + + +
+

欢迎使用学生管理系统。在这里您可以管理学生记录。

+
+ + + ``` + + 在此模板中: + - 使用`th:if="${#authorization.expression('hasAuthority(''WRITE'')')}"`语句仅在用户具有`WRITE`权限时条件显示“添加学生”按钮。 + - 同样,使用`th:if="${#authorization.expression('hasAuthority(''DELETE'')')}"`语句仅在用户具有`DELETE`权限时条件显示“删除学生”按钮。 + +## 解释 + +- **Thymeleaf安全方言**:`#authorization`对象是Thymeleaf安全方言的一部分,它将Spring Security与Thymeleaf集成在一起。 +- **条件显示**:使用`th:if`属性根据用户的权限有条件地显示或隐藏元素。 + +通过按照这些步骤,您可以根据用户的权限控制Thymeleaf视图中元素的可见性,确保只有授权用户才能看到和与特定功能进行交互。 + +--- + +# [NEXT TASK: Lab Tasks](../lab-work.md) \ No newline at end of file diff --git a/docs/cn/springsecurity/practice/authorize-client-role.md b/docs/cn/springsecurity/practice/authorize-client-role.md new file mode 100644 index 0000000..9e2126e --- /dev/null +++ b/docs/cn/springsecurity/practice/authorize-client-role.md @@ -0,0 +1,55 @@ +# 基于角色授权用户(客户端) + +本任务概述了如何在客户端视图中根据用户的角色对用户进行授权,使用Thymeleaf来实现。通过根据用户角色显示或隐藏元素,您可以控制特定功能或操作的可见性。 + +## 目标 + +在Thymeleaf视图中根据用户的角色控制与添加和删除学生相关的元素的可见性。 + +## 步骤 + +1. **更新Thymeleaf模板:** + + 修改Thymeleaf模板以根据用户的角色有条件地显示元素。 + + ```html + + + + 学生管理 + + +

学生管理

+ + + + + + + + +
+

欢迎使用学生管理系统。在这里您可以管理学生记录。

+
+ + + ``` + + 在此模板中: + - 使用`th:if="${#authorization.expression('hasRole(''ROLE_ADMIN'')')}"`语句仅在用户具有`ROLE_ADMIN`角色时条件显示“添加学生”按钮。 + - 同样,使用`th:if="${#authorization.expression('hasRole(''ROLE_MANAGER'')')}"`语句仅在用户具有`ROLE_MANAGER`角色时条件显示“删除学生”按钮。 + +## 解释 + +- **Thymeleaf安全方言**:`#authorization`对象是Thymeleaf安全方言的一部分,它将Spring Security与Thymeleaf集成在一起。 +- **条件显示**:使用`th:if`属性根据用户的角色有条件地显示或隐藏元素。 + +通过按照这些步骤,您可以根据用户的角色控制Thymeleaf视图中元素的可见性,确保只有授权用户才能看到和与特定功能进行交互。 + +--- + +# [下一个任务:根据权限授权用户](authorize-client-authority.md) \ No newline at end of file diff --git a/docs/cn/springsecurity/practice/authorize-server-authenticated.md b/docs/cn/springsecurity/practice/authorize-server-authenticated.md new file mode 100644 index 0000000..ea235ce --- /dev/null +++ b/docs/cn/springsecurity/practice/authorize-server-authenticated.md @@ -0,0 +1,38 @@ +# 授权已认证用户 + +本任务概述了在应用中授权已认证用户的过程。通过为特定路径或端点要求认证,可以确保只有已登录的用户才能访问某些资源。 + +## 目标 + +仅允许已认证用户访问 `/second` 路径,同时允许其他路径的公共访问。 + +## 步骤 + +1. **更新安全配置:** + + 在 `WebSecurityConfig` 类中,修改 `configure(HttpSecurity http)` 方法,指定访问 `/second` 路径应仅限于已认证用户。 + + ```java + @Configuration + @EnableWebSecurity + public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests((requests) -> requests + // 其他端点... + .requestMatchers("/second").authenticated() + // 其他端点... + ); + } + } + ``` + + 在此配置中: + - 我们使用 `.authorizeHttpRequests()` 定义授权规则。 + - `.requestMatchers("/second").authenticated()` 语句指定访问 `/second` 路径应仅限于已认证用户。 + +--- + +# [下一任务: 按角色授权](authorize-server-role.md) \ No newline at end of file diff --git a/docs/cn/springsecurity/practice/authorize-server-authority.md b/docs/cn/springsecurity/practice/authorize-server-authority.md new file mode 100644 index 0000000..eeda872 --- /dev/null +++ b/docs/cn/springsecurity/practice/authorize-server-authority.md @@ -0,0 +1,39 @@ +# 按权限授权 + +本任务概述了在应用中基于用户权限进行授权的过程。通过为用户分配不同的权限,可以控制对特定功能或操作的访问。 + +## 目标 + +为具有 `WRITE` 权限的用户授权访问 `/addStudent` 路径,为具有 `DELETE` 权限的用户授权访问 `/removeStudent` 路径。 + +## 步骤 + +1. **更新安全配置:** + + 在 `WebSecurityConfig` 类中,修改 `configure(HttpSecurity http)` 方法,指定基于权限的访问控制 `/addStudent` 和 `/removeStudent` 路径。 + + ```java + @Configuration + @EnableWebSecurity + public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests((requests) -> requests + // 其他端点... + .requestMatchers("/addStudent").hasAuthority("WRITE") + .requestMatchers("/removeStudent").hasAuthority("DELETE") + // 其他端点... + ); + } + } + ``` + + 在此配置中: + - `.requestMatchers("/addStudent").hasAuthority("WRITE")` 语句指定访问 `/addStudent` 路径应限于具有 `WRITE` 权限的用户。 + - 类似地,`.requestMatchers("/removeStudent").hasAuthority("DELETE")` 限制访问 `/removeStudent` 路径仅限于具有 `DELETE` 权限的用户。 + +--- + +# [下一任务: 自定义登录表单](custom-login-form.md) \ No newline at end of file diff --git a/docs/cn/springsecurity/practice/authorize-server-role.md b/docs/cn/springsecurity/practice/authorize-server-role.md new file mode 100644 index 0000000..e6aa2ab --- /dev/null +++ b/docs/cn/springsecurity/practice/authorize-server-role.md @@ -0,0 +1,39 @@ +# 按角色授权 + +本任务概述了在应用中基于用户角色进行授权的过程。通过为用户分配不同的角色,可以控制对特定资源或功能的访问。 + +## 目标 + +为具有 `ROLE_MODERATOR` 角色的用户授权访问 `/third` 路径,为具有 `ROLE_ADMIN` 角色的用户授权访问 `/fourth` 路径。 + +## 步骤 + +1. **更新安全配置:** + + 在 `WebSecurityConfig` 类中,修改 `configure(HttpSecurity http)` 方法,指定基于角色的访问控制 `/third` 和 `/fourth` 路径。 + + ```java + @Configuration + @EnableWebSecurity + public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests((requests) -> requests + // 其他端点... + .requestMatchers("/third").hasAuthority("ROLE_MODERATOR") + .requestMatchers("/fourth").hasAuthority("ROLE_ADMIN") + // 其他端点... + ); + } + } + ``` + + 在此配置中: + - `.requestMatchers("/third").hasAuthority("ROLE_MODERATOR")` 语句指定访问 `/third` 路径应限于具有 `ROLE_MODERATOR` 权限的用户。 + - 类似地,`.requestMatchers("/fourth").hasAuthority("ROLE_ADMIN")` 限制访问 `/fourth` 路径仅限于具有 `ROLE_ADMIN` 权限的用户。 + +--- + +# [下一任务: 按权限授权](authorize-server-authority.md) \ No newline at end of file diff --git a/docs/cn/springsecurity/practice/base-implementation-user.md b/docs/cn/springsecurity/practice/base-implementation-user.md new file mode 100644 index 0000000..cd4de1a --- /dev/null +++ b/docs/cn/springsecurity/practice/base-implementation-user.md @@ -0,0 +1,188 @@ +# 为用户创建基础实现 + +在本任务中,我们将专注于为应用中的用户管理创建基础实现。这包括定义 UserDetails 实体,创建管理用户数据的存储库,以及实现 UserDetailsService 以在认证过程中加载用户详情。 + +## 目标 + +本任务的目标是在应用中建立一个稳固的用户管理基础。通过实现 UserDetails、UsersRepository 和 UserDetailsService,您将能够对用户进行认证、管理其详情,并高效地执行与用户相关的操作。 + +## 步骤 + +1. **定义 UserDetails 实体** + + 首先,定义一个代表应用中用户详情的 UserDetails 实体。该实体应实现 Spring Security 提供的 UserDetails 接口。 + + ```java + package edu.labs.yourproject.model; + + import org.springframework.security.core.GrantedAuthority; + import org.springframework.security.core.userdetails.UserDetails; + + import java.util.Collection; + + public class CustomUserDetails implements UserDetails { + + // 在这里实现 UserDetails 方法 + + } + ``` + + 实现 UserDetails 接口所需的方法,以提供用户名、密码、权限等用户详情。 + +2. **创建 UsersRepository 类** + + 由于我们目前使用内存存储,将创建一个简单的 UsersRepository 类来管理用户数据。 + + a. **创建 UsersRepository 类** + + 在 `edu.labs.yourproject.repository` 包中创建一个名为 `UsersRepository` 的新 Java 类。 + + ```java + package edu.labs.yourproject.repository; + + import org.springframework.stereotype.Repository; + import edu.labs.yourproject.model.CustomUserDetails; + import java.util.ArrayList; + import java.util.List; + + @Repository + public class UsersRepository { + + private List users = new ArrayList<>(); + + // 根据需要添加管理用户的方法 + } + ``` + + 该类将作为管理用户数据的存储库。稍后我们将添加检索、添加、更新和删除用户的方法。 + + b. **添加 findByUsername 方法** + + 在 `UsersRepository` 类中添加一个名为 `findByUsername` 的方法。该方法将根据用户名从存储库中检索用户详情。 + + ```java + public CustomUserDetails findByUsername(String username) { + for (CustomUserDetails user : users) { + if (user.getUsername().equals(username)) { + return user; + } + } + return null; // 用户未找到 + } + ``` + + `findByUsername` 方法用于根据用户名从存储库中检索用户详情。在此占位实现中,它返回 `null`,但稍后您将用实际的逻辑来替换它,以从数据库或其他数据源中获取用户详情。 + +3. **实现 UserDetailsService** + + 在此步骤中,我们将实现一个 UserDetailsService 以在认证过程中加载用户详情。该服务将从 UsersRepository 中检索用户信息。 + + a. **创建 CustomUserDetailsService 类** + + 首先,在项目的服务包中创建一个名为 `CustomUserDetailsService` 的新类。该类将实现 Spring Security 提供的 UserDetailsService 接口。 + + ```java + package edu.labs.yourproject.service; + + import org.springframework.beans.factory.annotation.Autowired; + import org.springframework.security.core.userdetails.UserDetails; + import org.springframework.security.core.userdetails.UserDetailsService; + import org.springframework.security.core.userdetails.UsernameNotFoundException; + import org.springframework.stereotype.Service; + import edu.labs.yourproject.model.CustomUserDetails; + import edu.labs.yourproject.repository.UsersRepository; + + @Service + public class CustomUserDetailsService implements UserDetailsService { + + private final UsersRepository usersRepository; + + @Autowired + public CustomUserDetailsService(UsersRepository usersRepository) { + this.usersRepository = usersRepository; + } + + // 在这里实现方法 + } + ``` + + 我们创建了 `CustomUserDetailsService` 类,并使用构造函数注入的方式自动装配 `UsersRepository` 依赖。 + + b. **重写 loadUserByUsername 方法** + + 重写 UserDetailsService 接口中定义的 `loadUserByUsername` 方法。该方法将根据提供的用户名从 UsersRepository 中检索用户详情。 + + ```java + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + // 从内存存储库中检索用户详情 + CustomUserDetails userDetails = usersRepository.findByUsername(username); + if (userDetails == null) { + throw new UsernameNotFoundException("User not found with username: " + username); + } + return userDetails; + } + ``` + + 在 `loadUserByUsername` 方法中,我们调用 UsersRepository 的 `findByUsername` 方法,根据用户名检索用户详情。如果未找到用户,我们抛出一个 UsernameNotFoundException。 + +4. **在 WebSecurityConfig 中配置 Bean** + + 打开位于项目配置包中的 WebSecurityConfig 类 (`edu.labs.yourproject.config`)。在此类中,定义 CustomUserDetails 和 UserDetailsRepository 的 bean。 + + ```java + package edu.labs.yourproject.config; + + import edu.labs.yourproject.service.CustomUserDetailsService; + import edu.labs.yourproject.repository.UsersRepository; + import org.springframework.context.annotation.Bean; + import org.springframework.context.annotation.Configuration; + import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; + import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + + @Configuration + @EnableWebSecurity + public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + // 其他代码... + + @Bean + public CustomUserDetailsService customUserDetailsService() { + // 实例化并配置 CustomUserDetailsService bean + return new CustomUserDetailsService(usersRepository()); + } + + @Bean + public UsersRepository usersRepository() { + // 实例化并配置 UsersRepository bean + return new UsersRepository(); + } + } + ``` + + 定义两个 bean 方法:`customUserDetailsService()` 和 `usersRepository()`。这些方法分别实例化并配置 CustomUserDetailsService 和 UsersRepository bean。 + +## 文件夹结构 + +项目的文件夹结构应类似如下: + +``` +src +└── main + └── java + └── edu + └── labs + └── yourproject + ├── model + │ └── CustomUserDetails.java + ├── repository + │ └── UsersRepository.java + └── service + └── CustomUserDetailsService.java +``` + +这种文件夹结构指示了在项目中创建 `CustomUserDetailsService` 类和 `UsersRepository` 接口的位置。以这种方式组织类有助于保持清晰和结构化的代码库。 + +--- + +# [下一任务: 密码加密](password-encryption.md) \ No newline at end of file diff --git a/docs/cn/springsecurity/practice/configure-spring-security.md b/docs/cn/springsecurity/practice/configure-spring-security.md new file mode 100644 index 0000000..40e5640 --- /dev/null +++ b/docs/cn/springsecurity/practice/configure-spring-security.md @@ -0,0 +1,93 @@ +# 配置 Spring Security + +在本任务中,我们将重点配置项目中的 Spring Security。Spring Security 为 Java 应用程序提供全面的安全功能,包括认证、授权和防止常见安全威胁的保护。 + +## 目标 + +本任务的目标是将 Spring Security 集成到现有项目中,确保应用程序的安全性,防止未授权访问。 + +## 步骤 + +1. **添加 Spring Security 依赖** + + - 对于 Maven 项目: + + 在项目的 `pom.xml` 文件中添加以下依赖: + + ```xml + + org.springframework.boot + spring-boot-starter-security + + ``` + + - 对于 Gradle 项目: + + 在项目的 `build.gradle` 文件中添加以下依赖: + + ```groovy + implementation 'org.springframework.boot:spring-boot-starter-security' + ``` + + 确保包含项目适用的 Spring Security 版本。 + +2. **创建安全配置类** + + 在项目的源码文件夹结构中创建一个名为 `WebSecurityConfig` 的新 Java 类。通常,该类位于 `config` 包中。文件应命名为 `WebSecurityConfig.java`。 + + 项目的文件夹结构应类似如下: + + ``` + src + └── main + └── java + └── edu + └── labs + └── yourproject + ├── config + │ └── WebMvcConfig.java + │ └── WebSecurityConfig.java + └── controller + └── PracticeController.java + ``` + +3. **配置安全配置类** + + 在 `WebSecurityConfig` 类内部,用 `@Configuration` 和 `@EnableWebSecurity` 注解对其进行标注,以表明这是 Spring Security 的配置类。同时,用 `@Bean` 注解标注 `configure` 方法。 + + ```java + package edu.labs.yourproject.config; + + import org.springframework.context.annotation.Bean; + import org.springframework.context.annotation.Configuration; + import org.springframework.security.config.annotation.web.builders.HttpSecurity; + import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; + import org.springframework.security.web.SecurityFilterChain; + + @Configuration + @EnableWebSecurity + public class WebSecurityConfig { + + @Bean + public SecurityFilterChain configure(HttpSecurity http) throws Exception { + http + // 在这里进行安全配置 + .authorizeRequests() + .anyRequest().authenticated() + .and() + .formLogin() + .and() + .httpBasic(); + return http.build(); + } + } + ``` + + 上述配置示例中: + - `.authorizeRequests()` 方法用于定义授权规则。 + - `.anyRequest().authenticated()` 表示所有请求都需要认证。 + - `.formLogin()` 和 `.httpBasic()` 启用表单登录和基本 HTTP 认证。 + +--- + +# [下一任务: 为用户创建基础实现](base-implementation-user.md) \ No newline at end of file diff --git a/docs/cn/springsecurity/practice/configure-thymeleaf-security.md b/docs/cn/springsecurity/practice/configure-thymeleaf-security.md new file mode 100644 index 0000000..fb406d1 --- /dev/null +++ b/docs/cn/springsecurity/practice/configure-thymeleaf-security.md @@ -0,0 +1,30 @@ +# 配置 Thymeleaf 与 Spring Security 集成 + +## 目标 +本任务的目标是将 Thymeleaf 与 Spring Security 集成,利用 `thymeleaf-extras-springsecurity6` 库提供的额外 Thymeleaf 方言和实用程序。 + +## 步骤 + +1. **Gradle (Groovy):** + + 在 `build.gradle` 文件中添加 `thymeleaf-extras-springsecurity6` 依赖: + + ```groovy + implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6:3.0.4.RELEASE' + ``` + +2. **Maven:** + + 在 `pom.xml` 文件中添加以下依赖: + + ```xml + + org.thymeleaf.extras + thymeleaf-extras-springsecurity6 + 3.0.4.RELEASE + + ``` + +--- + +# [下一个任务:为用户创建基本实现](base-implementation-user.md) \ No newline at end of file diff --git a/docs/cn/springsecurity/practice/create-identity-to-users.md b/docs/cn/springsecurity/practice/create-identity-to-users.md new file mode 100644 index 0000000..ad72884 --- /dev/null +++ b/docs/cn/springsecurity/practice/create-identity-to-users.md @@ -0,0 +1,61 @@ +# 为用户创建身份 + +本任务概述了在“添加模拟用户”步骤中为用户添加权限和角色的过程。通过为用户分配角色和权限,我们在应用程序中建立了他们的身份,并控制他们对各种资源和功能的访问。 + +## 目标 + +通过为之前创建的用户配置角色和权限来增强用户配置文件,从而在应用程序中定义他们的身份和访问权限。 + +## 步骤 + +1. **为用户配置文件添加角色和权限:** + + 我们将更新在 `CustomUserDetailsService` 类中创建的模拟用户配置文件,以包含角色和权限。这涉及为每个用户分配特定的角色,例如 `ADMIN`、`MODERATOR` 或 `USER`,并根据他们的角色授予相应的权限。 + + ```java + // 在 addDummyUsers() 方法内 + + // 定义角色 + String adminRole = "ROLE_ADMIN"; + String moderatorRole = "ROLE_MODERATOR"; + String userRole = "ROLE_USER"; + + // 定义权限 + List adminAuthorities = Arrays.asList( + new SimpleGrantedAuthority(adminRole), + new SimpleGrantedAuthority("READ"), + new SimpleGrantedAuthority("WRITE") + ); + + List moderatorAuthorities = Arrays.asList( + new SimpleGrantedAuthority(moderatorRole), + new SimpleGrantedAuthority("READ") + ); + + List userAuthorities = Collections.singletonList( + new SimpleGrantedAuthority(userRole) + ); + + // 创建包含角色和权限的模拟用户 + CustomUserDetails admin = new CustomUserDetails("admin", passwordEncoder.encode("admin"), true, true, true, true); + admin.setAuthorities(adminAuthorities); + admin.setRole(adminRole); + + CustomUserDetails moderator = new CustomUserDetails("moderator", passwordEncoder.encode("moderator"), true, true, true, true); + moderator.setAuthorities(moderatorAuthorities); + moderator.setRole(moderatorRole); + + CustomUserDetails user = new CustomUserDetails("user", passwordEncoder.encode("user"), true, true, true, true); + user.setAuthorities(userAuthorities); + user.setRole(userRole); + ``` + + 在这段更新的代码中: + - 我们定义了角色和权限变量,以便清晰和便于维护。 + - 每个用户配置文件现在都包含一个基于其分配角色的权限列表。 + - 权限表示为 `SimpleGrantedAuthority` 对象,并相应地添加到用户配置文件中。 + - 另外,我们为每个用户设置了角色,以便在后续步骤中实现基于角色的访问控制。 + +--- + +# [下一任务:在服务器中创建授权基础](setup-server-authorization.md) \ No newline at end of file diff --git a/docs/cn/springsecurity/practice/custom-login-form.md b/docs/cn/springsecurity/practice/custom-login-form.md new file mode 100644 index 0000000..9d7540c --- /dev/null +++ b/docs/cn/springsecurity/practice/custom-login-form.md @@ -0,0 +1,40 @@ +# 自定义登录表单 + +该任务指导您通过使用Spring Security实现自定义登录表单来启用身份验证。通过实现自定义登录表单,用户可以安全地登录到您的应用程序中。 + +## 目标 + +激活已经创建的自定义登录页面,并将其设置在指定的路径上。 + +## 步骤 + +1. **更新安全配置:** + + 在 `WebSecurityConfig` 类中,修改 `configure(HttpSecurity http)` 方法以指定自定义登录页面。 + + ```java + @Configuration + @EnableWebSecurity + public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests((requests) -> requests + // 在此添加其他授权配置 + ) + .formLogin((login) -> login + .loginPage("/custom-login-page") // 指定自定义登录页面的URL + // 在此添加其他表单登录配置 + ); + } + } + ``` + + 在此配置中: + - `.loginPage("/custom-login-page")` 语句指定了自定义登录页面的URL。 + - 您可以添加其他配置以自定义表单登录行为,例如设置登录成功或失败的URL,定义表单字段名称等。 + +--- + +# [任务列表](../lab-work.md) \ No newline at end of file diff --git a/docs/cn/springsecurity/practice/password-encryption.md b/docs/cn/springsecurity/practice/password-encryption.md new file mode 100644 index 0000000..3d9ea23 --- /dev/null +++ b/docs/cn/springsecurity/practice/password-encryption.md @@ -0,0 +1,81 @@ +# 密码加密 + +在这个任务中,我们将为Spring Security启用的应用程序中的用户身份验证配置密码加密。通过加密密码,可以通过安全地存储它们在数据库中来增强安全性。 + +## 目标 + +此设置的目标是使用Spring Security提供的BCryptPasswordEncoder配置密码加密。这样可以确保在将密码存储在数据库之前对其进行安全哈希处理。 + +## 步骤 + +1. **添加 BCryptPasswordEncoder Bean** + + 打开位于项目的配置包(`edu.labs.yourproject.config`)中的 `WebSecurityConfig` 类。在这个类中,为 BCryptPasswordEncoder 定义一个 bean。 + + ```java + package edu.labs.yourproject.config; + + import org.springframework.context.annotation.Bean; + import org.springframework.context.annotation.Configuration; + import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + + @Configuration + public class WebSecurityConfig { + + @Bean + public BCryptPasswordEncoder passwordEncoder() { + // 实例化和配置 BCryptPasswordEncoder bean + return new BCryptPasswordEncoder(); + } + } + ``` + + 定义一个名为 `passwordEncoder()` 的 bean 方法,它实例化并配置了一个 BCryptPasswordEncoder bean。这个 bean 将用于在将密码存储在数据库之前对其进行编码。 + +2. **加密密码** + + a. **更新 CustomUserDetailsService 类** + + 打开位于项目的服务包(`edu.labs.yourproject.service`)中的 `CustomUserDetailsService` 类。将 BCryptPasswordEncoder bean 注入到这个类中。 + + ```java + package edu.labs.yourproject.service; + + import org.springframework.beans.factory.annotation.Autowired; + import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + import org.springframework.stereotype.Service; + import edu.labs.yourproject.model.CustomUserDetails; + import edu.labs.yourproject.repository.UsersRepository; + + @Service + public class CustomUserDetailsService implements UserDetailsService { + + private final UsersRepository usersRepository; + + @Autowired + private BCryptPasswordEncoder passwordEncoder; + + @Autowired + public CustomUserDetailsService(UsersRepository usersRepository) { + this.usersRepository = usersRepository; + } + } + ``` + + b. **实现注册方法** + + 在 `CustomUserDetailsService` 类中定义一个方法来处理用户注册。在这个方法中,加密用户的密码然后保存到数据库中。 + + ```java + public void registerUser(CustomUserDetails user) { + // 保存用户之前加密密码 + String encodedPassword = passwordEncoder.encode(user.getPassword()); + user.setPassword(encodedPassword); + usersRepository.save(user); + } + ``` + + 此方法接受一个表示要注册的用户的 CustomUserDetails 对象。它使用 BCryptPasswordEncoder bean 对用户的密码进行加密,然后将用户保存到数据库中。 + +--- +# [下一个任务:添加虚拟用户](add-dummy-users.md) \ No newline at end of file diff --git a/docs/cn/springsecurity/practice/setup-server-authorization.md b/docs/cn/springsecurity/practice/setup-server-authorization.md new file mode 100644 index 0000000..d4dc084 --- /dev/null +++ b/docs/cn/springsecurity/practice/setup-server-authorization.md @@ -0,0 +1,40 @@ +# 设置服务器授权 + +这个任务指导您通过使用Spring Security配置安全规则来设置应用程序的授权。通过定义授权规则,您可以控制对应用程序中特定路径和端点的访问权限。 + +## 目标 + +配置授权规则,以限制或允许访问应用程序中的各种路径和端点。 + +## 步骤 + +1. **添加安全配置:** + + 在 `WebSecurityConfig` 类中,添加 `configure(HttpSecurity http)` 方法来为应用程序定义安全规则。我们将使用上一个实验任务中定义的路径和端点。 + + ```java + @Configuration + @EnableWebSecurity + public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests((requests) -> requests + .requestMatchers("/first").permitAll() + .requestMatchers("/second").permitAll() + .requestMatchers("/third").permitAll() + .requestMatchers("/fourth").permitAll() + .requestMatchers("/addStudent").permitAll() + .requestMatchers("/removeStudent").permitAll() + ); + } + } + ``` + + 在这个配置中: + - 我们使用 `.authorizeHttpRequests()` 来定义授权规则。 + - 在 lambda 表达式中,我们指定了哪些请求应该被允许。 +--- + +# [下一个任务:授权经过身份验证的用户](authorize-server-authenticated.md) \ No newline at end of file diff --git a/docs/cn/thymeleaf/lab-work.md b/docs/cn/thymeleaf/lab-work.md new file mode 100644 index 0000000..f800371 --- /dev/null +++ b/docs/cn/thymeleaf/lab-work.md @@ -0,0 +1,72 @@ +[English](../../en/thymeleaf/lab-work.md) | 中文 | [Русский](../../ru/thymeleaf/lab-work.md) + +# Thymeleaf 实验任务 + +欢迎来到 Thymeleaf 实验任务系列!本系列任务旨在帮助您实践和掌握 Thymeleaf,这是一种强大的 Java 应用模板引擎。无论您是初学者还是希望提升技能,这些动手任务将引导您完成在 Spring 应用中集成 Thymeleaf 的各个方面。 + +## 实验任务的目标 + +本实验任务的主要目标是让您在 Spring 环境中使用 Thymeleaf 获得实际经验和熟练程度。Thymeleaf 广泛用于网页开发中的服务器端渲染,通过这些任务,您将深入了解其配置、变量使用、控制器、表单处理等方面。 + +## 练习任务 + +1. [任务 1:在 Spring 中配置 Thymeleaf](practice/configure-thymeleaf.md) +2. [任务 2:创建第一个视图](practice/create-first-view.md) +3. [任务 3:处理变量](practice/working-with-variables.md) +4. [任务 4:变量与控制器](practice/variables-and-controller.md) +5. [任务 5:迭代](practice/iteration.md) +6. [任务 6:文本字面量](practice/literals.md) +7. [任务 7:表单](practice/forms.md) +8. [任务 8:表单处理](practice/form-handling.md) +9. [任务 9:查询参数和验证](practice/validation.md) +10. [任务 10:片段和布局](practice/fragments-and-layouts.md) + + +## 实验任务 + +1. **任务 1:创建带片段的 HTML 布局** + + - 为 HTML 页面的不同部分创建单独的片段,如导航栏、头部、头部标签和页脚。 + - 将这些片段组合到一个 HTML 文件中形成完整的布局。 + - 例如: + ![layout.png](../../srcs/thymeleaf/layout.png) + +2. **任务 2:创建带本地化的主页** + + - 实现一个可在路径 `/` 访问的主页。 + - 使用任务 1 中创建的布局来构建主页。 + - 使用 `#{}` 表达式处理主页内的所有文本内容,展示从文件.properties 文件中读取的本地化消息。 + - 例如: + + ![home-page.png](../../srcs/thymeleaf/home-page.png) + +3. **任务 3:创建登录和注册表单** + + - 设计并实现用户认证的登录和注册表单。 + - 使用 Thymeleaf 的模型绑定来处理表单数据。 + - 例如: + + ![login-page.png](../../srcs/thymeleaf/login-page.png) + + ![signup.png](../../srcs/thymeleaf/signup.png) + +4. **任务 4:验证登录和注册操作** + + - 实现登录和注册操作的验证。 + - 使用查询参数传递验证失败的错误信息。 + - 确保用户输入的安全和正确处理。 + - 例如: + + ![login-validation.png](../../srcs/thymeleaf/login-validation.png) + +5. **任务 5:创建用户页面** + + - 开发一个显示用户表格的用户页面。 + - 实现迭代来动态填充用户数据表。 + - 提供从页面删除或修改用户条目的功能。 + - 例如: + + ![users-page.png](../../srcs/thymeleaf/users-page.png) + + ![modify-user-page.png](../../srcs/thymeleaf/modify-user-page.png) + diff --git a/docs/cn/thymeleaf/practice/configure-thymeleaf.md b/docs/cn/thymeleaf/practice/configure-thymeleaf.md new file mode 100644 index 0000000..53d7c4c --- /dev/null +++ b/docs/cn/thymeleaf/practice/configure-thymeleaf.md @@ -0,0 +1,115 @@ +# 在Spring中配置Thymeleaf + +**描述:** + +此任务涉及在Spring应用程序中设置Thymeleaf,实现模板引擎与Web开发的无缝集成。 + +## 步骤: + +1. **创建Thymeleaf配置类:** + - 在您的Spring项目中,创建一个带有 `@Configuration` 注解的新Java类。我们建议将此类放置在 `config` 包中。 + - 将该类扩展为 `WebMvcConfigurer`。 + + 示例: + + ```java + package edu.labs.thymeleaf.config; + + import org.springframework.context.annotation.Configuration; + import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + + @Configuration + public class WebMvcConfig implements WebMvcConfigurer { + // 配置代码放在这里 + } + ``` + + 将配置类放置在 `config` 包中有助于组织,并确保项目结构清晰。根据项目的结构调整包名称。 + +2. **配置Thymeleaf模板解析器:** + - 定义一个带有 `@Bean` 注解的方法,以配置Thymeleaf模板解析器。 + - 使用 `ClassLoaderTemplateResolver`,设置前缀、后缀、模板模式和字符编码。 + + ```java + @Bean + public ClassLoaderTemplateResolver templateResolver() { + // 创建一个 ClassLoaderTemplateResolver bean + ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver(); + + // 设置Thymeleaf查找模板的路径 + templateResolver.setPrefix("/templates/"); + + // 设置模板的文件扩展名 + templateResolver.setSuffix(".html"); + + // 设置模板模式为HTML + templateResolver.setTemplateMode(TemplateMode.HTML); + + // 设置模板的字符编码 + templateResolver.setCharacterEncoding("UTF-8"); + + // 返回配置的模板解析器bean + return templateResolver; + } + ``` + +3. **配置消息源:** + - 添加一个带有 `@Bean` 注解的方法,使用 `ReloadableResourceBundleMessageSource` 配置消息源。 + - 设置默认编码。 + + ```java + @Bean + public MessageSource messageSource() { + // 创建一个 ReloadableResourceBundleMessageSource bean + ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); + + // 设置消息的默认编码 + messageSource.setDefaultEncoding("UTF-8"); + + // 返回配置的消息源bean + return messageSource; + } + ``` + +4. **配置Thymeleaf视图解析器:** + - 创建一个带有 `@Bean` 注解的方法,以配置Thymeleaf视图解析器。 + - 设置模板引擎。 + + ```java + @Bean + public ViewResolver thymeleafViewResolver() { + // 创建一个 ThymeleafViewResolver bean + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + + // 设置视图解析器的模板引擎 + resolver.setTemplateEngine(templateEngine()); + + // 返回配置的 ThymeleafViewResolver bean + return resolver; + } + ``` + +5. **配置Thymeleaf模板引擎:** + - 实现一个带有 `@Bean` 注解的方法,以配置Thymeleaf模板引擎。 + - 设置模板解析器和模板引擎消息源。 + + ```java + @Bean + public SpringTemplateEngine templateEngine() { + // 创建一个 SpringTemplateEngine bean + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + + // 为模板引擎设置模板解析器 + templateEngine.setTemplateResolver(templateResolver()); + + // 设置模板引擎消息源 + templateEngine.setTemplateEngineMessageSource(messageSource()); + + // 返回配置的 SpringTemplateEngine bean + return templateEngine; + } + ``` + +--- + +# [下一步任务:*创建第一个视图*](create-first-view.md) \ No newline at end of file diff --git a/docs/cn/thymeleaf/practice/create-first-view.md b/docs/cn/thymeleaf/practice/create-first-view.md new file mode 100644 index 0000000..03d9eea --- /dev/null +++ b/docs/cn/thymeleaf/practice/create-first-view.md @@ -0,0 +1,59 @@ +# 创建第一个视图 + +**描述:** + +在这个任务中,我们将为您的Spring应用程序创建第一个Thymeleaf视图。按照Thymeleaf配置中定义的正确文件路径,并在应用程序中注册视图。 + +## **步骤:** + +1. **创建视图文件:** + - 导航到Thymeleaf配置中指定的目录,该目录是模板的前缀。 + - 默认情况下,配置的前缀是 `/templates/`。因此,请在此目录中创建您的Thymeleaf视图文件。 + + ```plaintext + 项目目录 + └── src + └── main + └── resources + └── templates + └── practice + └── first.html + ``` + + 确保视图文件的命名合适(例如,`first.html`)。`/templates/` 目录对于Thymeleaf正确定位和处理您的模板非常重要。 + +2. **在配置类中注册视图:** + - 打开设置Thymeleaf的配置类(例如,`WebMvcConfig`)。 + - 添加以下方法以注册Thymeleaf视图: + + ```java + public void addViewControllers(ViewControllerRegistry registry) { + // 第一个视图 + registry.addViewController("/first").setViewName("practice/first"); + } + ``` + + 此方法将 URL 路径 `/first` 映射到名为 "practice/first" 的 Thymeleaf 视图。根据项目结构调整路径。 + +3. **测试视图:** + - 运行您的Spring应用程序。 + - 打开Web浏览器,导航到 `http://localhost:8080/first`。您应该看到渲染的Thymeleaf视图。 + +4. **可选: 配置从根路径的重定向:** + - 要将第一个视图设置为默认页面,您可以在 `addViewControllers` 方法中添加从根路径 ("/") 到第一个视图路径的重定向: + + ```java + public void addViewControllers(ViewControllerRegistry registry) { + // 第一个视图 + registry.addViewController("/first").setViewName("practice/first"); + + // 从根路径重定向到第一个视图 + registry.addRedirectViewController("/", "/first"); + } + ``` + + 现在,访问 `http://localhost:8080/` 将自动重定向到第一个视图。 + +--- + +# [下一个任务: *使用变量*](working-with-variables.md) \ No newline at end of file diff --git a/docs/cn/thymeleaf/practice/form-handling.md b/docs/cn/thymeleaf/practice/form-handling.md new file mode 100644 index 0000000..bfd1b23 --- /dev/null +++ b/docs/cn/thymeleaf/practice/form-handling.md @@ -0,0 +1,72 @@ +# 表单处理 + +**描述:** + +在这个续集中,我们将专注于处理表单提交并使用 `PracticeController` 渲染视图。这涉及在显示视图时将模型传递给视图,并实现处理表单提交的逻辑。 + +**步骤:** + +1. **显示表单视图(PracticeController):** + + - 打开 `PracticeController` 类并添加一个方法来显示表单视图: + + ```java + import org.springframework.stereotype.Controller; + import org.springframework.ui.Model; + import org.springframework.web.bind.annotation.GetMapping; + + @Controller + public class PracticeController { + + // 其他方法... + + @GetMapping("/third") + public String showAddStudentForm(Model model) { + model.addAttribute("model", new StudentModel()); + return "practice/third"; + } + } + ``` + + - 解释: + - `@GetMapping("/addStudentForm")`: 这个注解将方法映射到处理 `/addStudentForm` 端点的 GET 请求。 + - `showAddStudentForm(Model model)`: 这个方法接受一个 `Model` 参数,向其添加一个新的 `StudentModel`,并返回视图名称(在这种情况下为 `"thirdView"`)。更新以反映视图的正确命名。 + - `Model` 被填充了一个新的 `StudentModel` 实例,该实例将用于绑定表单字段。 + +2. **处理表单提交(PracticeController):** + + - 在 `PracticeController` 中添加一个方法来处理表单提交: + + ```java + import org.springframework.stereotype.Controller; + import org.springframework.ui.Model; + import org.springframework.web.bind.annotation.*; + + import java.util.ArrayList; + import java.util.List; + + @Controller + public class PracticeController { + + private final List students = new ArrayList<>(); + + // 其他方法... + + @PostMapping("/addStudent") + public String addStudent(@ModelAttribute("model") StudentModel model) { + students.add(model); + + return "redirect:/third"; + } + } + ``` + + - 解释: + - `@PostMapping("/addStudent")`: 这个注解将方法映射到处理 `/addStudent` 端点的 POST 请求。 + - `addStudent(@ModelAttribute("model") StudentModel model)`: 这个方法从表单提交中获取 `model` 属性(`@ModelAttribute`),并处理它。表单数据会自动绑定到 `model` 对象。 + - 此方法内的逻辑将学生添加到 `students` 列表中。在实际情况下,您通常会将学生保存到数据库或执行其他必要的操作。 + - `return "redirect:/third";`: 此行将用户重定向回表单视图(`/third`)。 + +--- + +# [下一个任务: *查询参数和验证*](validation.md) \ No newline at end of file diff --git a/docs/cn/thymeleaf/practice/forms.md b/docs/cn/thymeleaf/practice/forms.md new file mode 100644 index 0000000..54c312e --- /dev/null +++ b/docs/cn/thymeleaf/practice/forms.md @@ -0,0 +1,118 @@ +# 表单 + +**描述:** + +在这个任务中,您将创建一个名为 `third.html` 的新的 Thymeleaf 视图,并在 `PracticeController` 中实现表单处理逻辑。该表单允许用户添加具有特定详细信息的新学生,控制器将处理表单提交。 + +**步骤:** + +1. **创建第三个视图(third.html):** + + - 在 `/src/main/resources/templates/practice` 目录中创建一个名为 `third.html` 的新的 Thymeleaf 视图文件。 + + ```html + + + + + 添加学生表单 + + +
+ 添加学生 + +
+ +

+ + +

+
+
+ + + ``` + +2. **配置表单提交:** + + - 在 `form` 标签中配置表单提交详情: + + ```html +
+ ``` + + - 解释: + - `action="#"`: 此属性指定表单数据在提交时将发送到的 URL。`#` 表示表单将提交到其来源的相同 URL。 + - `th:action="@{/addStudent}"`: 这个 Thymeleaf 属性根据 Thymeleaf 表达式动态设置表单动作。`@{/addStudent}` 为 `/addStudent` 端点生成绝对 URL。 + - `th:object="${model}"`: 此属性将表单与后备对象(`model`)关联起来。Thymeleaf 使用此对象在表单提交和渲染过程中将表单字段绑定到属性。 + - `method="post"`: 此属性指定将表单数据发送到服务器时使用的 HTTP 方法。它设置为 `post`,表示表单数据将在请求体中发送。 + +3. **传递 'id' 字段:** + + - 在表单中,找到 `id` 字段的部分: + + ```html + +

+ + +

+ ``` + + - 解释: + - `th:field="*{id}"`: 此 Thymeleaf 属性将输入字段绑定到 `model` 对象的 `id` 属性。它确保在表单提交时将输入字段中输入的值设置为 `id` 属性。 + - `id="id"` 和 `name="id"`: 这些属性为输入字段提供标识符。 + +4. **重复这些步骤:** + + - 对于每个剩余字段(`firstName`、`sureName`、`isGraduated` 和 `mark`),重复这些步骤。确保根据需要更新 `label`、`id`、`name` 和 `th:field` 属性。 + - 这里是代码示例: + ```html + + + + + 添加学生表单 + + +
+ 添加学生 + + + +

+ + +

+

+ + +

+

+ + +

+

+ + +

+

+ + +

+ + + +
+ + + ``` + +## 结果 +您的视图应如下所示: + +![third-view.png](../../../srcs/thymeleaf/third-view.png) + +--- + +# [下一个任务: *表单处理*](form-handling.md) \ No newline at end of file diff --git a/docs/cn/thymeleaf/practice/fragments-and-layouts.md b/docs/cn/thymeleaf/practice/fragments-and-layouts.md new file mode 100644 index 0000000..99f4dca --- /dev/null +++ b/docs/cn/thymeleaf/practice/fragments-and-layouts.md @@ -0,0 +1,128 @@ +# 片段和布局 + +**描述:** + +在这一部分中,我们将实现 Thymeleaf 片段和布局。我们将更新现有视图以包含片段,然后创建一个新的视图来利用这些片段。 + +## **步骤:** + +1. **在 `first.html` 中添加一个片段:** + + - 打开 `practice` 目录中的 `first.html` 文件。 + - 在 `` 标签内的 `
` 中添加 `th:fragment` 属性: + + ```html + + + + + + + +
+

这是第一个视图的信息部分。

+
+ + + + ``` + +2. **在 `second.html` 中添加一个片段:** + + - 打开 `practice` 目录中的 `second.html` 文件。 + - 在 `` 标签内的 `` 中添加 `th:fragment` 属性: + + ```html + + + + + + + +
+ + + + + + + + + + + + + +
IdFirstNameSecondNameGraduatedMarkDiploma Type
+ + + + ``` + +3. **在 `third.html` 中添加一个片段:** + + - 打开 `practice` 目录中的 `third.html` 文件。 + - 在 `` 标签内的 `
` 中添加 `th:fragment` 属性: + + ```html + + + + + + + +
+ 添加学生 + +
+

学生添加成功!

+
+ +
+ +
+
+ + + + ``` + +4. **创建一个带有片段的 `fourth.html` :** + + - 在 `practice` 目录中创建一个名为 `fourth.html` 的新文件。 + - 使用 `th:insert` 和 `th:replace` 属性来包含其他视图中的片段: + + ```html + + + + + + + +
+ + +
+ + +
+ + + + ``` + + - 解释: + - `th:insert` 用于将指定片段(`info` 和 `add-student-form`)的内容包含在 `fourth.html` 文件中。 + - `th:replace` 用于在 `fourth.html` 文件中替换指定片段(`students-table`)的内容。 + +## 结果 +您的视图应如下所示: + +![fourth-view.png](../../../srcs/thymeleaf/fourth-view.png) + +--- + +# 恭喜! 您已完成所有任务。现在让我们转到 **[实验室任务](../lab-work.md#lab-work-tasks)** \ No newline at end of file diff --git a/docs/cn/thymeleaf/practice/iteration.md b/docs/cn/thymeleaf/practice/iteration.md new file mode 100644 index 0000000..df49b7b --- /dev/null +++ b/docs/cn/thymeleaf/practice/iteration.md @@ -0,0 +1,105 @@ +# 迭代 + +**描述:** + +在这个任务中,您将通过在`models/`包中创建一个`StudentModel`类并在`PracticeController`中填充学生列表来探索Thymeleaf中的迭代概念。目标是将学生列表传递给`secondView`,并渲染显示学生详细信息的表格。 + +**步骤:** + +1. **创建 StudentModel:** + - 在 `models/` 包中创建一个 `StudentModel` 类,具有以下属性: + + ```java + public class StudentModel { + private Integer id = 0; + private String firstName = ""; + private String sureName = ""; + private Boolean isGraduated = false; + private Integer mark = 0; + + // Constructor, getters, and setters + } + ``` + +2. **在 PracticeController 中填充学生列表:** + - 在 `PracticeController` 类中,创建一个 `StudentModel` 列表并用假的学生详情填充它: + + ```java + @Controller + public class PracticeController { + private final List students = new ArrayList<>(); + + public PracticeController() { + // Populate the list with users + this.students.add(new StudentModel(1, "First", "User", true, 4)); + this.students.add(new StudentModel(2, "Second", "User", false, 2)); + this.students.add(new StudentModel(3, "Third", "User", true, 5)); + this.students.add(new StudentModel(4, "Fourth", "User", false, 3)); + } + + // Rest of the controller methods + } + ``` + +3. **将学生传递给 secondView:** + - 在 `PracticeController` 的 `secondView` 方法中,将学生列表添加到模型中。 + + ```java + @Controller + public class PracticeController { + // Other methods... + + @GetMapping("/second") + public String secondView(Model model) { + // Pass the list of students to the view + model.addAttribute("students", students); + // Rest of the method... + } + } + ``` + +4. **在 second.html 中渲染学生表:** + - 打开 `second.html` Thymeleaf 视图文件。 + +5. **渲染表头:** + - 在 `` 标签内添加表头部分: + + ```html + + + + + + + + + + + +
IdFirstNamesureNameGraduatedMark
+ ``` + +6. **使用迭代渲染表体:** + - 在 `` 标签内添加表体部分,并对学生列表进行迭代以渲染每一行: + + ```html + + + + + + + + + + + ``` + +## 结果 +您的页面应如下所示: + +![second-view.png](../../../srcs/thymeleaf/second-view.png) + +--- + +# [下一个任务:*字面值*](literals.md) \ No newline at end of file diff --git a/docs/cn/thymeleaf/practice/literals.md b/docs/cn/thymeleaf/practice/literals.md new file mode 100644 index 0000000..6e6b025 --- /dev/null +++ b/docs/cn/thymeleaf/practice/literals.md @@ -0,0 +1,53 @@ +# 字面值 + +**描述:** + +在这个任务中,您将通过在 `second.html` Thymeleaf 视图中引入字面值来增强视图,以根据特定条件显示修改后的值。字面值包括将常量值添加到 `id`,在“Graduated”字段中显示“是”或“否”,以及为“Mark”和“Diploma Type”字段提供描述性标签。 + +**步骤:** + +1. **更新 second.html 中的 students-table 片段:** + - 打开 `second.html` Thymeleaf 视图文件。 + +2. **增强学生 ID 的字面值:** + - 修改 `id` 字段的表达式,将常量值(例如 100000)添加到实际学生 ID。 + + ```html + + ``` + +3. **增强 Graduated 字段的字面值:** + - 更新“Graduated”字段的表达式,如果学生毕业,则显示“是”,否则显示“否”。 + + ```html + + ``` + +4. **增强 Mark 字段的字面值:** + - 添加条件表达式,根据学生的分数显示“Mark”字段的描述性标签。 + + ```html + 良好 + 很好 + 优秀 + 未通过 + ``` + +5. **为 Diploma Type 字段添加字面值:** + - 添加条件表达式,根据学生的分数和毕业状态显示“Diploma Type”字段的描述性标签。 + + ```html + 蓝色 + 蓝色 + 红色 + 无毕业证书 + ``` + +## 结果 +您的页面应如下所示: + +![second-view-enhanced.png](../../../srcs/thymeleaf/second-view-enhanced.png) + +--- + +# [下一个任务:*表单*](forms.md) \ No newline at end of file diff --git a/docs/cn/thymeleaf/practice/validation.md b/docs/cn/thymeleaf/practice/validation.md new file mode 100644 index 0000000..844a27f --- /dev/null +++ b/docs/cn/thymeleaf/practice/validation.md @@ -0,0 +1,83 @@ +# 查询参数和验证 + +**描述:** + +在这个继续中,我们将探讨使用查询参数在视图中显示处理表单提交后的消息。这涉及调整 `thirdView` 来根据查询参数显示成功和错误消息。 + +**步骤:** + +1. **调整视图(thirdView.html):** + + - 打开 `third.html` 文件,并添加显示成功和错误消息的部分: + + ```html + + + + + + + + +
+

学生添加成功!

+
+ +
+

错误:

+
+ + + + + ``` + + - 说明: + - `
` 检查URL中是否存在查询参数 `error`。 + - 如果参数存在,则以红色显示来自 `${param.error}` 的错误消息。 + +2. **处理表单提交并进行额外验证(PracticeController):** + + - 更新 `PracticeController` 中的 `addStudent` 方法,使用 `if-else` 结构包含对学生分数的额外验证: + + ```java + import org.springframework.stereotype.Controller; + import org.springframework.ui.Model; + import org.springframework.web.bind.annotation.*; + + import java.util.ArrayList; + import java.util.List; + + @Controller + public class PracticeController { + + private final List students = new ArrayList<>(); + + // 其他方法... + + @PostMapping("/addStudent") + public String addStudent(@ModelAttribute("model") StudentModel model) { + // 额外验证: 检查分数是否超过5分。 + if (model.getMark() > 5) { + // 如果分数超过5分,重定向并显示错误消息。 + return "redirect:/third?error=分数不能超过5分"; + } else { + students.add(model); + + return "redirect:/third?addedStudent=true"; + } + } + } + ``` + +## 结果 +您的视图应如下所示: + +![third-view-error.png](../../../srcs/thymeleaf/third-view-success.png) + +![third-view-error.png](../../../srcs/thymeleaf/third-view-error.png) + + +--- + +# [下一个任务: *片段和布局*](fragments-and-layouts.md) \ No newline at end of file diff --git a/docs/cn/thymeleaf/practice/variables-and-controller.md b/docs/cn/thymeleaf/practice/variables-and-controller.md new file mode 100644 index 0000000..bcc52f7 --- /dev/null +++ b/docs/cn/thymeleaf/practice/variables-and-controller.md @@ -0,0 +1,65 @@ +# 变量和控制器 + +**描述:** + +在这个任务中,你将创建一个名为 `second.html` 的新的 Thymeleaf 视图,并探索从控制器传递变量到视图的概念。我们将不再在视图中定义标题为局部变量,而是通过控制器传递。 + +**步骤:** + +1. **创建新的视图文件:** + - 在 `/src/main/resources/templates/` 目录中创建一个名为 `second.html` 的新的 Thymeleaf 视图文件。 + + ```plaintext + 项目目录 + └── src + └── main + └── resources + └── templates + └── practice + └── second.html + ``` + +2. **定义控制器:** + - 在你的控制器类(例如 `PracticeController`)中,定义一个方法,将其映射到与新视图关联的 URL 路径。将所需的变量(例如 `title`)传递到模型中。 + + ```java + @Controller + public class PracticeController { + + @GetMapping("/second") + public String secondView(Model model) { + // 将变量传递到视图 + model.addAttribute("title", "第二页"); + + // 返回视图名称 + return "practice/second"; + } + } + ``` + + 此控制器方法将映射到 URL 路径 `/second`,并将变量 `title` 的值设置为 "第二页" 传递给 Thymeleaf 视图。 + +3. **更新视图以使用控制器传递的变量:** + - 打开 `second.html` Thymeleaf 视图文件。 + - 在 `

` 标签中使用从控制器传递的 `title` 变量。 + + ```html + + + + + 标题 + + +

欢迎来到第二页

+ + 返回首页 + + + ``` + + `th:text="${title}"` 表达式检索从控制器传递的 `title` 变量的值。 + +--- + +# [下一个任务: *迭代*](iteration.md) \ No newline at end of file diff --git a/docs/cn/thymeleaf/practice/working-with-variables.md b/docs/cn/thymeleaf/practice/working-with-variables.md new file mode 100644 index 0000000..43044a6 --- /dev/null +++ b/docs/cn/thymeleaf/practice/working-with-variables.md @@ -0,0 +1,88 @@ +# 处理变量 + +**描述:** + +在这个任务中,你将探索和利用 Thymeleaf 视图中的不同类型的局部变量,在你的 Spring 应用程序中。这些包括在视图本身中定义的变量,从控制器传递的变量,本地化的属性文件中定义的变量,以及在 Thymeleaf 配置类中定义的静态变量。 + +## **步骤:** + +1. **在 Thymeleaf 视图中定义局部变量:** + - 打开你的 Thymeleaf 视图文件(例如 `first.html`)。 + - 探索直接在视图中定义的局部变量的使用。 + - 在提供的示例代码中: + + ```html + + + 标题 + + ``` + + 局部变量 `title` 是在 HTML 的 `` 部分内定义的。 + +2. **从属性文件中获取本地化变量:** + - 查看 Thymeleaf 配置类中 `MessageSource` bean 的配置: + + ```java + @Bean + public MessageSource messageSource() { + ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); + messageSource.addBasenames("classpath:local/practice"); + messageSource.setDefaultEncoding("UTF-8"); + + return messageSource; + } + ``` + - 在路径 `/src/main/resources/local/` 下创建一个 `practice.properties` 文件,并添加以下内容: + + ```properties + student.name=我的名字 + student.group=PRE-121 + message.welcome=欢迎,{0} + message.info=你的小组是: {0} + ``` + **关于 `{0}` 的说明:** + - 本地化消息中的符号 `{0}` 表示一个占位符变量。当消息被渲染时,占位符 `{0}` 会被提供的实际值替换。例如,在消息 `欢迎,{0}` 中,`{0}` 将被变量的实际值替换,比如一个名字。 + + - 使用 `#{}` 语法在 Thymeleaf 视图中探索本地化变量的用法。 + - 在提供的示例代码中: + + ```html +

+

+ ``` + + 变量 `student.name`,`student.group`,`message.welcome` 和 `message.info` 都实现了这个想法。 + +3. **在 Thymeleaf 配置类中添加静态变量:** + - 在你的 Thymeleaf 配置类中,使用 `addStaticVariable` 方法添加静态变量: + + ```java + @Bean + public ViewResolver thymeleafViewResolver() { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.addStaticVariable("projectName", "练习任务"); + resolver.addStaticVariable("currentDateTime", LocalDateTime.now()); + resolver.setTemplateEngine(templateEngine()); + + return resolver; + } + ``` + + - 使用 `#vars` 语法在 Thymeleaf 视图中访问这些静态变量。 + - 在提供的示例代码中: + + ```html +

项目名称

+

当前日期和时间

+ ``` + +## 结果 + +现在你的页面应该如下所示: + +![first-view.png](../../../srcs/thymeleaf/first-view.png) + +--- + +# [下一个任务: *变量和控制器*](variables-and-controller.md) \ No newline at end of file diff --git a/docs/cn/transactions/lab-work.md b/docs/cn/transactions/lab-work.md new file mode 100644 index 0000000..08b3d32 --- /dev/null +++ b/docs/cn/transactions/lab-work.md @@ -0,0 +1,56 @@ +[English](../../en/transactions/lab-work.md) | 中文 | [Русский](../../ru/transactions/lab-work.md) + + +# 事务实验任务 + +欢迎来到事务实验任务!这一系列任务的目标是帮助您练习并掌握在Spring应用程序中管理事务。无论您是初学者还是希望提升技能,这些实践任务都将引导您探索事务管理的各个方面,包括传播、隔离级别、嵌套事务等。 + +## 实验任务的目标 + +这个实验任务的主要目标是为您提供在Spring环境中管理事务的实践经验和熟练度。通过这些任务,您将深入了解配置事务、处理不同的传播行为、实现嵌套事务,并确保应用程序中的数据完整性。 + +## 练习任务 + +1. [事务设置](practice/configuration.md) +2. [第一部分:创建实体和存储库](practice/lessons/entities-and-repositories.md) +3. [第二部分:实现基本的事务操作](practice/lessons/basic-transactional-operations.md) +4. [第三部分:使用详细日志增强事务方法](practice/lessons/transactional-logging.md) +5. [第四部分:实现嵌套事务和非事务操作](practice/lessons/nested-and-non-transactional-operations.md) + +## 实验任务 + +![img.png](../../srcs/transactions/task-chart.png) + +- **为事件注册用户** + - **任务:** 实现一个方法来为事件注册用户。确保该操作完全隔离,以保持数据一致性。无论主事务成功与否,都要单独记录此操作。 + - **传播:** REQUIRED + - **隔离级别:** SERIALIZABLE + - **日志传播:** REQUIRES_NEW + +- **从事件中移除用户的注册** + - **任务:** 实现一个方法来从事件中移除用户的注册。确保此方法始终在现有事务中执行。 + - **传播:** MANDATORY + +- **获取某个事件的注册用户** + - **任务:** 实现一个方法来获取特定事件的所有注册用户。确保该方法要么加入现有事务,要么创建一个新事务,只读取已提交的数据。 + - **传播:** REQUIRED + - **隔离级别:** READ_COMMITTED + +- **添加新事件** + - **任务:** 实现一个方法来添加新事件。此操作应该没有事务保证,以避免不必要的事务开销。 + - **传播:** NOT_SUPPORTED + +- **使用嵌套事务更新事件详情和注册** + - **任务:** 实现一个方法来更新事件详情以及相关的注册信息。确保在嵌套事务中保持一致性。 + - **传播:** REQUIRED + - **隔离级别:** REPEATABLE_READ + - **嵌套任务:** 在嵌套事务中更新注册信息。 + +- **更新注册信息** + - **任务:** 实现一个方法来更新注册记录。确保这些操作属于嵌套事务。 + - **传播:** NESTED + - **隔离级别:** REPEATABLE_READ + +- **执行非事务操作** + - **任务:** 实现一个方法用于执行不需要事务上下文的操作,如非关键任务或日志记录。 + - **传播:** None \ No newline at end of file diff --git a/docs/cn/transactions/practice/configuration.md b/docs/cn/transactions/practice/configuration.md new file mode 100644 index 0000000..104e814 --- /dev/null +++ b/docs/cn/transactions/practice/configuration.md @@ -0,0 +1,85 @@ +# 事务设置 + +## 简介 + +本指南专注于在Spring Boot项目中设置事务管理。它提供了启用事务管理和配置事务属性的逐步说明。 + +## 目标 + +本指南的目标是演示如何在Spring Boot应用程序中配置事务管理,从而实现对数据库事务的管理。 + +## 事务管理设置 + +要在Spring Boot项目中启用事务管理,请按照以下步骤操作: + +1. 在您的 `pom.xml` 或 `build.gradle` 文件中添加必要的依赖项。确保您具有Spring Boot、Spring Data JPA以及您正在使用的任何数据库驱动程序的依赖项(例如,H2、MySQL、PostgreSQL)。 + +2. 在您的Spring Boot应用程序中配置事务管理。您可以通过在主应用程序类上注释 `@EnableTransactionManagement` 来实现这一点。 + +### 示例(Java配置): + +```java +package com.example.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@SpringBootApplication +@EnableTransactionManagement +public class DemoApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + +} +``` + +3. 如果您使用的是Spring Web MVC,则需要将以下内容添加到您的配置文件中以设置事务管理器: + +### 示例(XML配置): + +```xml + + + +``` + +### 示例(Java配置): + +```java +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.transaction.PlatformTransactionManager; + +import javax.persistence.EntityManagerFactory; + +@Configuration +public class TransactionConfig { + + /** + * Spring事务管理器的Bean定义。 + * + *

+ * 此方法使用配置的实体管理器工厂设置JPA的事务管理器。 + *

+ * + * @param entityManagerFactory 实体管理器工厂bean + * @return 事务管理器bean + */ + @Bean + public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { + JpaTransactionManager txManager = new JpaTransactionManager(); + txManager.setEntityManagerFactory(entityManagerFactory); + return txManager; + } +} +``` + +通过按照这些步骤操作,您将在Spring Boot应用程序中启用事务管理,从而有效地管理数据库事务。 + +--- + +# [下一步:创建实体和存储库](lessons/entities-and-repositories.md) \ No newline at end of file diff --git a/docs/cn/transactions/practice/lessons/basic-transactional-operations.md b/docs/cn/transactions/practice/lessons/basic-transactional-operations.md new file mode 100644 index 0000000..909ae7f --- /dev/null +++ b/docs/cn/transactions/practice/lessons/basic-transactional-operations.md @@ -0,0 +1,50 @@ +# 第二课:实现基本事务操作 + +## 目标 + +本部分旨在为在Spring Boot应用程序中注册学生和管理课程引入简单但重要的事务方法。 + +## 步骤 + +1. **将学生注册到课程中** + + **场景**:作为大学管理员,您需要将学生注册到课程中。此操作应顺利进行,并确保即使同时进行多个注册或存在任何数据库问题,数据完整性仍然保持完好。 + + **实现 `enrollStudentInCourse` 方法**:创建一个方法来将学生注册到课程中。确保此过程是事务性的,意味着它就像一个整体交易一样,保证所有事情都正确地一起发生。我们使用 `Propagation.REQUIRED` 确保此方法参与任何现有事务或在不存在事务时创建新事务。另外,我们设置 `Isolation.SERIALIZABLE` 以确保即使有并发事务,它们也不会相互干扰,从而保持数据的完整性。 + + ```java + @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.SERIALIZABLE) + public void enrollStudentInCourse(UUID studentId, UUID courseId) { + // 实现代码在此处 + } + ``` + +2. **检索课程的学生** + + **场景**:为了创建课程的班级名单,您需要检索已注册的学生列表。此操作应确保您始终获得数据库的准确视图,即使同时发生其他活动。 + + **实现 `getStudentsForCourse` 方法**:开发一个方法来检索特定课程的学生。它应确保无论有没有正在进行的事务,您检索的数据都是一致的。我们使用 `Propagation.REQUIRED` 确保此方法参与任何现有事务或在不存在事务时创建新事务。我们设置 `Isolation.READ_COMMITTED` 确保我们检索的数据已提交并对其他事务可见,保持一致性。 + + ```java + @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED) + public List getStudentsForCourse(UUID courseId) { + // 实现代码在此处 + } + ``` + +3. **添加新课程** + + **场景**:新课程即将纳入课程表。在将其添加到系统时,您希望此操作不会干扰其他正在进行的事务,保持其独立性。 + + **实现 `addNewCourse` 方法**:创建一个方法来将新课程添加到系统中。确保此过程不会与任何其他正在进行的事务纠缠在一起。我们使用 `Propagation.NOT_SUPPORTED` 确保此方法不参与任何现有事务,使其具有自主性,并避免与其他操作发生潜在冲突。 + + ```java + @Transactional(propagation = Propagation.NOT_SUPPORTED) + public Course addNewCourse(String title) { + // 实现代码在此处 + } + ``` + +--- + +# [下一步:通过详细日志增强事务方法](transactional-logging.md) \ No newline at end of file diff --git a/docs/cn/transactions/practice/lessons/entities-and-repositories.md b/docs/cn/transactions/practice/lessons/entities-and-repositories.md new file mode 100644 index 0000000..a09abb1 --- /dev/null +++ b/docs/cn/transactions/practice/lessons/entities-and-repositories.md @@ -0,0 +1,38 @@ +# 第一课:创建实体和存储库 + +## 目标 + +本任务的目标是在使用Spring Data JPA的Spring Boot项目中定义核心实体(Student、Course、Enrollment、Log)并设置相应的存储库。 + +## 步骤 + +1. **参考提供的ER图来定义实体类。** + ![er-diagram.png](../../../../srcs/transactions/er-diagram.png) + 如果您已根据提供的ER图有实体类,请继续执行步骤2。否则,请分析ER图并创建以下实体类: + + - Student(学生) + - Course(课程) + - Enrollment(注册) + - Log(日志) + + 确保每个实体类包含ER图中所示的必要属性。 + +2. **为实体创建存储库。** + + 例如,让我们为 `Student` 实体创建存储库: + + ```java + package com.example.demo.repository; + + import com.example.demo.entity.Student; + import org.springframework.data.jpa.repository.JpaRepository; + + public interface StudentRepository extends JpaRepository { + } + ``` + + 如果您已经有了实体存储库,请继续下一步。否则,重复上述步骤为其他实体(Course、Enrollment、Log)创建存储库。 + +--- + +# [下一步:实现基本事务操作](basic-transactional-operations.md) \ No newline at end of file diff --git a/docs/cn/transactions/practice/lessons/nested-and-non-transactional-operations.md b/docs/cn/transactions/practice/lessons/nested-and-non-transactional-operations.md new file mode 100644 index 0000000..4462e2e --- /dev/null +++ b/docs/cn/transactions/practice/lessons/nested-and-non-transactional-operations.md @@ -0,0 +1,66 @@ +# 第四课:实现嵌套事务和非事务操作 + +## 目标 + +本部分旨在探讨在服务层中使用嵌套事务和非事务操作,为学生提供管理复杂事务场景的见解。 + +## 步骤 + +1. **更新课程详情和注册** + + **场景**:作为大学管理员,您经常需要同时更新课程详情和与该课程相关的注册。此操作应确保数据一致性和完整性,即使同时执行多个更新也是如此。 + + **实现 `updateCourseAndEnrollments` 方法**:定义一个方法来使用所需的事务行为更新课程详情和注册。我们使用 `Propagation.REQUIRED` 确保此方法参与任何现有事务或在不存在事务时创建新事务。设置 `Isolation.REPEATABLE_READ` 确保此方法读取的数据在整个事务中保持一致。在此方法内部,我们通过调用 `updateEnrollments` 方法执行嵌套事务来更新注册,确保此操作是原子的,并与外部事务隔离。 + + ```java + @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ) + public void updateCourseAndEnrollments(UUID courseId, String newTitle) { + // 记录更新过程的开始 + logAction("Update Course and Enrollments", "Start"); + + try { + // 更新课程详情的实现 + // ... + + // 嵌套事务更新注册 + updateEnrollments(courseId); + + // 记录成功的更新 + logAction("Update Course and Enrollments", "Success"); + } catch (Exception e) { + // 记录失败 + logAction("Update Course and Enrollments", "Failure: " + e.getMessage()); + throw e; + } + } + ``` + +2. **独立更新注册** + + **场景**:某些管理任务可能需要独立于课程更新来更新注册。此操作应在维护数据一致性的同时,允许单独的事务控制。 + + **实现 `updateEnrollments` 方法**:定义一个方法来使用嵌套事务行为更新课程的注册。我们使用 `Propagation.NESTED` 表示此方法在外部事务范围内执行,但如果需要,可以独立回滚。设置 `Isolation.REPEATABLE_READ` 确保此方法读取的数据在整个事务中保持一致。 + + ```java + @Transactional(propagation = Propagation.NESTED, isolation = Isolation.REPEATABLE_READ) + public void updateEnrollments(UUID courseId) { + // 记录更新注册的开始 + logAction("Update Enrollments", "Start"); + + try { + // 更新注册的实现 + // ... + + // 记录成功的更新 + logAction("Update Enrollments", "Success"); + } catch (Exception e) { + // 记录失败 + logAction("Update Enrollments", "Failure: " + e.getMessage()); + throw e; + } + } + ``` + +--- + +# [下一步:任务](../../lab-work.md) \ No newline at end of file diff --git a/docs/cn/transactions/practice/lessons/transactional-logging.md b/docs/cn/transactions/practice/lessons/transactional-logging.md new file mode 100644 index 0000000..f4ca60d --- /dev/null +++ b/docs/cn/transactions/practice/lessons/transactional-logging.md @@ -0,0 +1,105 @@ +# 第三课:通过详细日志增强事务方法 + +## 目标 + +本部分旨在为每个事务操作集成详细的日志记录,确保操作及其结果被记录。 + +## 步骤 + +1. **实现日志记录方法** + + **场景**:在增强事务方法的日志记录之前,我们需要实现一个方法来独立处理日志记录,以确保无论主事务的结果如何,日志都能可靠地记录。 + + **实现 `logAction` 方法**:创建一个方法来独立记录操作,确保准确跟踪事务结果。我们使用 `Propagation.REQUIRES_NEW` 在单独的事务中执行日志记录操作,使其独立于任何正在进行的事务,并确保即使主事务失败,也能完成日志记录。 + + ```java + @Transactional(propagation = Propagation.REQUIRES_NEW) + public void logAction(String action, String outcome) { + Log log = new Log(action, outcome, LocalDateTime.now()); + logRepository.save(log); + } + ``` + +2. **记录学生注册课程** + + **场景**:作为大学管理员,您需要记录学生注册课程的情况,以便跟踪成功的注册和任何潜在的失败。 + + **增强 `enrollStudentInCourse` 方法**:修改方法以记录操作的成功或失败。 + + ```java + @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.SERIALIZABLE) + public void enrollStudentInCourse(UUID studentId, UUID courseId) { + // 记录注册过程的开始 + logAction("Enroll Student", "Start"); + + try { + // 注册学生到课程的实现 + // ... + + // 记录成功的注册 + logAction("Enroll Student", "Success"); + } catch (Exception e) { + // 记录失败 + logAction("Enroll Student", "Failure: " + e.getMessage()); + throw e; + } + } + ``` + +3. **记录检索课程的学生** + + **场景**:为了维护与课程相关的活动的审计轨迹,您需要记录检索课程的学生,并确保即使发生异常,日志记录也会发生。 + + **增强 `getStudentsForCourse` 方法**:修改方法以记录操作的成功或失败。 + + ```java + @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED) + public List getStudentsForCourse(UUID courseId) { + // 记录检索课程学生的开始 + logAction("Retrieve Students for Course", "Start"); + + try { + // 检索课程学生的实现 + // ... + + // 记录成功的检索 + logAction("Retrieve Students for Course", "Success"); + return students; + } catch (Exception e) { + // 记录失败 + logAction("Retrieve Students for Course", "Failure: " + e.getMessage()); + throw e; + } + } + ``` + +4. **记录添加新课程** + + **场景**:当添加新课程时,记录操作的结果是至关重要的,以跟踪添加的成功或失败。 + + **增强 `addNewCourse` 方法**:修改方法以记录操作的成功或失败。 + + ```java + @Transactional(propagation = Propagation.NOT_SUPPORTED) + public Course addNewCourse(String title) { + // 记录添加新课程的开始 + logAction("Add New Course", "Start"); + + try { + // 添加新课程的实现 + // ... + + // 记录成功的添加 + logAction("Add New Course", "Success"); + return savedCourse; + } catch (Exception e) { + // 记录失败 + logAction("Add New Course", "Failure: " + e.getMessage()); + throw e; + } + } + ``` + +--- + +# [下一步:实现嵌套事务和非事务操作](nested-and-non-transactional-operations.md) \ No newline at end of file diff --git a/docs/en/jmeter/lab-work.md b/docs/en/jmeter/lab-work.md new file mode 100644 index 0000000..df0e63a --- /dev/null +++ b/docs/en/jmeter/lab-work.md @@ -0,0 +1,28 @@ +English | [中文](../../cn/jmeter/lab-work.md) | [Русский](../../ru/jmeter/lab-work.md) + + +# JMeter Lab Work + +Welcome to the JMeter Lab Work! The goal of this series of tasks is to help you practice and master JMeter, a powerful tool for performance testing and measuring the performance of web applications. Whether you're a beginner or looking to enhance your skills, these hands-on tasks will guide you through various aspects of using JMeter for load testing, recording, and analyzing HTTP requests. + +## Goal of the Lab Work + +The primary goal of this lab work is to provide you with practical experience and proficiency in using JMeter for performance testing. JMeter is widely utilized for testing the performance of web applications and services, and through these tasks, you will gain valuable insights into its configuration, scripting, recording, and analysis features. + +## Practice Tasks + +- [Lesson 1: Introduction to JMeter and Basic Setup](lessons/introduction-to-jmeter-and-basic-setup.md) +- [Lesson 2: Setting Up HTTP(S) Test Script Recorder](lessons/setting-up-http-test-script-recorder.md) +- [Lesson 3: Configuring and Using the Proxy Server](lessons/configuring-and-using-the-proxy-server.md) +- [Lesson 4: Configuring Browser to Use the Proxy Server](lessons/configuring-browser-to-use-the-proxy-server.md) +- [Lesson 5: Recording and Managing HTTP Requests](lessons/recording-and-managing-http-requests.md) +- [Lesson 6: Organizing Recorded Requests](lessons/organizing-recorded-requests.md) +- [Lesson 7: Creating a Test Scenario](lessons/creating-a-test-scenario.md) +- [Lesson 8: Parameterizing HTTP Requests](lessons/parameterizing-http-requests.md) +- [Lesson 9: Adding Listeners and Running Tests](lessons/adding-listeners-and-running-tests.md) +- [Lesson 10: Executing Load Testing](lessons/executing-load-testing.md) +- [Lesson 11: Analyzing Test Results](lessons/analyzing-test-results.md) + +## Lab Work Tasks + +idk :D diff --git a/docs/en/jmeter/lessons/adding-listeners-and-running-tests.md b/docs/en/jmeter/lessons/adding-listeners-and-running-tests.md new file mode 100644 index 0000000..de68c1a --- /dev/null +++ b/docs/en/jmeter/lessons/adding-listeners-and-running-tests.md @@ -0,0 +1,28 @@ +# Lesson 9: Adding Listeners and Running Tests + +## Goal +The goal of this lesson is to add listeners to view test results and to run the test scenarios in JMeter. + +## Steps + +### 9.1. Adding a Listener +1. **View Results Tree** + - Right-click on the **Thread Group**. + - Select **Add > Listener > View Results Tree**. + +### 9.2. Saving the Test Plan +1. **Saving** + - Click on the **Test Plan** node. + - Go to **File > Save Test Plan as**. + - Choose a location, enter a filename, and save the test plan. + +### 9.3. Running the Test Scenario +1. **Execution** + - Click **Run > Start** to begin the test. +
![run-test-scenraio-button.png](../../../srcs/jmeter/run-test-scenraio-button.png) + - View the results in the **View Results Tree** listener. + - Ensure there are no errors in the test results. + +--- + +# [Next: Executing Load Testing](executing-load-testing.md) diff --git a/docs/en/jmeter/lessons/analyzing-test-results.md b/docs/en/jmeter/lessons/analyzing-test-results.md new file mode 100644 index 0000000..17ce637 --- /dev/null +++ b/docs/en/jmeter/lessons/analyzing-test-results.md @@ -0,0 +1,19 @@ +# Lesson 11: Analyzing Test Results + +## Goal +The goal of this lesson is to analyze test results using electronic spreadsheets and to prepare for subsequent test runs in JMeter. + +## Steps + +### 11.1. Utilizing Electronic Spreadsheets +1. **Exporting and Analyzing Data** + - Export the results from the **Aggregate Report** listener to a CSV file. + - Use a spreadsheet application (e.g., Excel) to analyze the average response times and other metrics. + +### 11.2. Clearing Statistics for Subsequent Runs +1. **Clearing Data** + - Before running a new test, clear the previous results by selecting **Run > Clear All**. + +--- + +# [Next: Tasks](../lab-work.md) \ No newline at end of file diff --git a/docs/en/jmeter/lessons/configuring-and-using-the-proxy-server.md b/docs/en/jmeter/lessons/configuring-and-using-the-proxy-server.md new file mode 100644 index 0000000..00f6a33 --- /dev/null +++ b/docs/en/jmeter/lessons/configuring-and-using-the-proxy-server.md @@ -0,0 +1,19 @@ +# Lesson 3: Configuring and Using the Proxy Server + +## Goal +The goal of this lesson is to configure the Proxy Server in JMeter and demonstrate how to use it for recording HTTP(S) requests. + +## Steps + +### 3.1. Configuring the Proxy Server +1. **Setting Port and URL Patterns** + - In the **HTTP(S) Test Script Recorder** window, set the **Port** field to `9090`. + - In the **URL Patterns to Exclude** section, click **Add** and enter patterns such as `.*\.gif`, `.*\.js`, and `.*\.css`. +
![setting-port-and-url-pattern.png](../../../srcs/jmeter/setting-port-and-url-pattern.png) +### 3.2. Starting the Proxy Server +1. **Starting Recording** + - Click the **Start** button at the bottom of the **HTTP(S) Test Script Recorder** window. +
![start-recording-button.png](../../../srcs/jmeter/start-recording-button.png) +--- + +# [Next: Recording and Managing HTTP Requests](recording-and-managing-http-requests.md) diff --git a/docs/en/jmeter/lessons/configuring-browser-to-use-the-proxy-server.md b/docs/en/jmeter/lessons/configuring-browser-to-use-the-proxy-server.md new file mode 100644 index 0000000..977b400 --- /dev/null +++ b/docs/en/jmeter/lessons/configuring-browser-to-use-the-proxy-server.md @@ -0,0 +1,17 @@ +# Lesson 4: Configuring Browser to Use the Proxy Server + +## Goal +The goal of this lesson is to configure your browser to use the Proxy Server set up in JMeter for recording HTTP(S) requests. + +## Steps + +### 4.1. Configuring Browser Settings +1. **Setting Up Proxy in Browser** + - Open your browser settings and navigate to the proxy settings. + - Set the proxy server address to `localhost` and the port to `9090`. + - Save the settings and restart the browser if necessary. + +--- + +# [Next: Organizing Recorded Requests](organizing-recorded-requests.md) + diff --git a/docs/en/jmeter/lessons/creating-a-test-scenario.md b/docs/en/jmeter/lessons/creating-a-test-scenario.md new file mode 100644 index 0000000..0ec5dfd --- /dev/null +++ b/docs/en/jmeter/lessons/creating-a-test-scenario.md @@ -0,0 +1,30 @@ +# Lesson 7: Creating a Test Scenario + +## Goal +The goal of this lesson is to create a test scenario by organizing recorded requests and adding dynamic value extraction in JMeter. + +## Steps + +### 7.1. Adding a Simple Controller +1. **Organizing Requests** + - Right-click on the **Thread Group**. +
![thread-group-icon.png](../../../srcs/jmeter/thread-group-icon.png) + - Select **Add > Logic Controller > Simple Controller**. +
![new-simple-controller-button.png](../../../srcs/jmeter/new-simple-controller-button.png) + - Rename the Simple Controller to match the function you are testing. + - Drag and drop all recorded HTTP requests from the **Recording Controller** to the **Simple Controller**. + +### 7.2. Adding a Regular Expression Extractor +1. **Dynamic Value Extraction** + - Right-click on the HTTP request that requires a dynamic value (e.g., `javax.faces.ViewState`). + - Select **Add > Post Processors > Regular Expression Extractor**. +
![new-regular-expression-button.png](../../../srcs/jmeter/new-regular-expression-button.png) + - Configure the extractor: + - **Reference Name:** `jsfViewState` + - **Regular Expression:** `![regular-expression-extractor-fields.png](../../../srcs/jmeter/regular-expression-extractor-fields.png) +--- + +# [Next: Parameterizing HTTP Requests](parameterizing-http-requests.md) diff --git a/docs/en/jmeter/lessons/executing-load-testing.md b/docs/en/jmeter/lessons/executing-load-testing.md new file mode 100644 index 0000000..165d7e3 --- /dev/null +++ b/docs/en/jmeter/lessons/executing-load-testing.md @@ -0,0 +1,26 @@ +# Lesson 10: Executing Load Testing + +## Goal +The goal of this lesson is to configure and execute load testing in JMeter. + +## Steps + +### 10.1. Adjusting Thread Settings +1. **Load Testing Configuration** + - Click on the **Thread Group**. + - Set the **Number of Threads** (users), **Ramp-Up Period** (seconds), and **Loop Count** as needed for your load test. + +### 10.2. Adding an Aggregate Report Listener +1. **Summary Report** + - Right-click on the **Simple Controller**. + - Select **Add > Listener > Aggregate Report**. + - Disable the **View Results Tree** listener to improve performance during load testing. + +### 10.3. Running the Load Test +1. **Execution** + - Click **Run > Start** to begin the load test. + - View the summarized results in the **Aggregate Report** listener. + +--- + +# [Next: Analyzing Test Results](analyzing-test-results.md) \ No newline at end of file diff --git a/docs/en/jmeter/lessons/first.md b/docs/en/jmeter/lessons/first.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/en/jmeter/lessons/introduction-to-jmeter-and-basic-setup.md b/docs/en/jmeter/lessons/introduction-to-jmeter-and-basic-setup.md new file mode 100644 index 0000000..241ab1e --- /dev/null +++ b/docs/en/jmeter/lessons/introduction-to-jmeter-and-basic-setup.md @@ -0,0 +1,27 @@ +# Lesson 1: Introduction to JMeter and Basic Setup + +## Goal +The goal of this lesson is to introduce JMeter and guide you through the basic setup process, including starting JMeter and adding a Thread Group to your Test Plan. + +## Steps + +### 1.1. Starting JMeter + +![jmeter-site.png](../../../srcs/jmeter/site.png) +1. **Download and Install JMeter** + - Visit the [official JMeter website](https://jmeter.apache.org/download_jmeter.cgi) and download the latest version. + - Extract the downloaded archive. + - Navigate to the `bin` directory and start JMeter by running the `jmeter.bat` file (Windows) or `jmeter.sh` (macOS/Linux). + +### 1.2. Adding a Thread Group +![interface.png](../../../srcs/jmeter/interface.png) +1. **Creating a Test Plan** + - Open JMeter. + - Right-click on the **Test Plan** node. +
![test-plan.png](../../../srcs/jmeter/test-plan.png) + + - Select **Add > Threads (Users) > Thread Group**. +
![test-plan.png](../../../srcs/jmeter/thread-group.png) + +--- +# [Next: Setting Up HTTP Test Script Recorder](setting-up-http-test-script-recorder.md) diff --git a/docs/en/jmeter/lessons/organizing-recorded-requests.md b/docs/en/jmeter/lessons/organizing-recorded-requests.md new file mode 100644 index 0000000..a914890 --- /dev/null +++ b/docs/en/jmeter/lessons/organizing-recorded-requests.md @@ -0,0 +1,22 @@ +# Lesson 6: Organizing Recorded Requests + +## Goal +The goal of this lesson is to organize the recorded HTTP requests in JMeter for better management and test execution. + +## Steps + +### 6.1. Disabling the Recording Controller +1. **Disabling** + - Right-click on the **Recording Controller** in JMeter. +
![recording-controller-button.png](../../../srcs/jmeter/recording-controller-button.png) + - Select **Disable** to stop capturing further requests. +
![disable-element.png](../../../srcs/jmeter/disable-element.png) +### 6.2. Adding an HTTP Cookie Manager +1. **Session Management** + - Right-click on the **Thread Group**. +
![thread-group-icon.png](../../../srcs/jmeter/thread-group-icon.png) + - Select **Add > Config Element > HTTP Cookie Manager**. +
![new-http-cookie-manager-button.png](../../../srcs/jmeter/new-http-cookie-manager-button.png) +--- + +# [Next: Creating a Test Scenario](creating-a-test-scenario.md) diff --git a/docs/en/jmeter/lessons/parameterizing-http-requests.md b/docs/en/jmeter/lessons/parameterizing-http-requests.md new file mode 100644 index 0000000..a2daa62 --- /dev/null +++ b/docs/en/jmeter/lessons/parameterizing-http-requests.md @@ -0,0 +1,15 @@ +# Lesson 8: Parameterizing HTTP Requests + +## Goal +The goal of this lesson is to parameterize HTTP requests in JMeter using extracted dynamic values. + +## Steps + +### 8.1. Modifying HTTP Requests +1. **Using Extracted Values** + - In each HTTP request that uses the parameter `javax.faces.ViewState`, replace the value with `${jsfViewState}`. + - Ensure the **Encode** checkbox is selected if needed. + +--- + +# [Next: Adding Listeners and Running Tests](adding-listeners-and-running-tests.md) diff --git a/docs/en/jmeter/lessons/recording-and-managing-http-requests.md b/docs/en/jmeter/lessons/recording-and-managing-http-requests.md new file mode 100644 index 0000000..d67bc0a --- /dev/null +++ b/docs/en/jmeter/lessons/recording-and-managing-http-requests.md @@ -0,0 +1,21 @@ +# Lesson 5: Recording and Managing HTTP Requests + +## Goal +The goal of this lesson is to record HTTP requests made by navigating through a web application and manage the recorded requests in JMeter. + +## Steps + +### 5.1. Recording HTTP Requests +1. **Navigating Through the Application** + - Navigate through your web application as you normally would. The HTTP requests will be recorded by JMeter. + +### 5.2. Stopping the Recording +1. **Stopping Proxy Server** + - Return to JMeter and click the **Stop** button in the **HTTP(S) Test Script Recorder** window. +
![stop-recording-button.png](../../../srcs/jmeter/stop-recording-button.png) + - Disable the proxy settings in your browser to revert to direct internet access. + +--- + +# [Next: Organizing Recorded Requests](organizing-recorded-requests.md) + diff --git a/docs/en/jmeter/lessons/second.md b/docs/en/jmeter/lessons/second.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/en/jmeter/lessons/setting-up-http-test-script-recorder.md b/docs/en/jmeter/lessons/setting-up-http-test-script-recorder.md new file mode 100644 index 0000000..008f569 --- /dev/null +++ b/docs/en/jmeter/lessons/setting-up-http-test-script-recorder.md @@ -0,0 +1,24 @@ +# Lesson 2: Setting Up HTTP(S) Test Script Recorder + +## Goal +The goal of this lesson is to guide you through setting up the HTTP(S) Test Script Recorder in JMeter, including adding a Recording Controller and configuring a Proxy Server. + +## Steps + +### 2.1. Adding a Recording Controller +1. **Adding to Thread Group** + - Right-click on the **Thread Group**. +
![thread-group-icon.png](../../../srcs/jmeter/thread-group-icon.png) + + - Select **Add > Logic Controller > Recording Controller**. +
![recording-controller-button.png](../../../srcs/jmeter/recording-controller-button.png) + +### 2.2. Adding a Proxy Server +1. **Configuring Proxy** + - Right-click on the **Workbench** node. +
![test-plan.png](../../../srcs/jmeter/test-plan.png) + - Select **Add > Non-Test Elements > HTTP(S) Test Script Recorder**. +
![test-script-recorder.png](../../../srcs/jmeter/test-script-recorder.png) +--- + +# [Next: Configuring and Using the Proxy Server](configuring-and-using-the-proxy-server.md) diff --git a/docs/en/jmeter/lessons/third.md b/docs/en/jmeter/lessons/third.md new file mode 100644 index 0000000..945c9b4 --- /dev/null +++ b/docs/en/jmeter/lessons/third.md @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/docs/en/jpa/lab-work.md b/docs/en/jpa/lab-work.md new file mode 100644 index 0000000..22c8282 --- /dev/null +++ b/docs/en/jpa/lab-work.md @@ -0,0 +1,58 @@ +English | [中文](../../cn/jpa/lab-work.md) | [Русский](../../ru/jpa/lab-work.md) + + +# Lab Work: JPA (Java Persistence API) + +Welcome to the Spring Boot with JPA Lab Work! In this lab work, you will practice various tasks related to setting up a Spring Boot project with JPA (Java Persistence API). + +## Goal of the Lab Work + +The goal of this lab work is to provide hands-on experience with key concepts and tasks involved in working with Spring Boot and JPA. By completing the practice tasks, you will gain proficiency in setting up dependencies, defining entity characteristics, managing relationships between entities, and interacting with the database using JpaRepository. + +## Practice Tasks + +1. **Database Dependencies Setup** + - [Database Driver Setup](practice/dependencies/driver.md) + - [Spring Boot and JPA Dependencies](practice/dependencies/jpa.md) + +2. **Entity Creation, Characteristics, Relationships and Fetching Strategies** + - [Entity Creation](practice/creation/create-entity.md) + - [Entity Characteristics Definition](practice/creation/characteristics.md) + - [Managing Relationships](practice/creation/relationships.md) + - [Fetching Strategies](practice/creation/fetching.md) + +3. **Interacting with Custom Repository** + - [Create Record](practice/interacting/repository/create.md) + - [Read Record](practice/interacting/repository/read.md) + - [Update Record](practice/interacting/repository/update.md) + - [Delete Record](practice/interacting/repository/delete.md) + - [Custom Queries](practice/interacting/repository/query.md) + +4. **Interacting with JPA Repository** + - [Create Record](practice/interacting/jpa-repository/create.md) + - [Read Record](practice/interacting/jpa-repository/read.md) + - [Delete Record](practice/interacting/jpa-repository/delete.md) + - [Custom Queries](practice/interacting/jpa-repository/query.md) + + +## Lab Work Tasks + +1. Set up database dependencies for PostgreSQL, MySQL, Oracle, MongoDB, and Microsoft SQL Server. + +2. Implement the next Entity-Relationships Diagram: +![img.png](../../srcs/jpa/task-er-diagram.png) + + 1. Define entity characteristics for Student, Enrollment, and Course entities based on the Entity Relationships diagram. + + 2. Create entity classes for Student, Enrollment, and Course according to the defined characteristics. + + 3. Implement fetching strategies for efficient data retrieval to optimize database interactions. + + 4. Manage relationships between entities such as Student, Enrollment, and Course by establishing appropriate associations and mappings. + + 5. Interact with the database by creating methods for CRUD operations using the Repository layer and EntityManager in at least two repositories. + + 6. Interact with the database by creating methods for CRUD operations using JpaRepository in at least two repositories. + + 7. Implement custom queries to perform advanced data retrieval and manipulation operations as required by the application's business logic. + diff --git a/docs/en/jpa/practice/creation/characteristics.md b/docs/en/jpa/practice/creation/characteristics.md new file mode 100644 index 0000000..0297f7a --- /dev/null +++ b/docs/en/jpa/practice/creation/characteristics.md @@ -0,0 +1,111 @@ +# Defining Entity Characteristics + +## Introduction + +This guide focuses on defining entity columns or characteristics in a Spring Boot project using JPA (Java Persistence API). + +## Goal +The goal of this guide is to provide clear instructions for defining the characteristics of entities in a Spring Boot project with JPA, utilizing annotations to enforce constraints and behaviors for each attribute. + + +## Entity Characteristics + +### Student Entity Characteristics: +- `id` (UUID): Primary key for the entity. +- `name` (String): Name of the student (must not be blank). +- `email` (String): Email address of the student (must be a valid email address). +- `major` (String): Major or field of study of the student (must not be blank). +- `year` (int): Year of study for the student (must not be null). +- `international` (boolean): Indicates if the student is international (must not be null). + +### Define `id` Attribute + +Add the `id` attribute to the `Student` class. This attribute will serve as the primary key for the entity. + +```java +@Id +@GeneratedValue(strategy = GenerationType.AUTO) +private UUID id; +``` + +- `@Id`: Indicates that this field is the primary key for the entity. +- `@GeneratedValue`: Specifies the strategy for generating primary key values automatically. + +### Define `name` Attribute + +Add the `name` attribute to the `Student` class. This attribute represents the name of the student and must not be blank. + +```java +@NotBlank +private String name; +``` + +- `@NotBlank`: Ensures that the value of `name` is not null and contains at least one non-whitespace character. + +### Define `email` Attribute + +Add the `email` attribute to the `Student` class. This attribute represents the email address of the student and must be a valid email address. + +```java +@NotBlank +@Email +private String email; +``` + +- `@Email`: Validates that the value of `email` is a valid email address. + +### Define `major` Attribute + +Add the `major` attribute to the `Student` class. This attribute represents the major or field of study of the student and must not be blank. + +```java +@NotBlank +private String major; +``` + +- `@NotBlank`: Ensures that the value of `major` is not null and contains at least one non-whitespace character. + +### Define `year` Attribute + +Add the `year` attribute to the `Student` class. This attribute represents the year of study for the student and must not be null. + +```java +@NotNull +private int year; +``` + +- `@NotNull`: Ensures that the value of `year` is not null. + +### Define `international` Attribute + +Add the `international` attribute to the `Student` class. This attribute indicates whether the student is international and must not be null. + +```java +@NotNull +private boolean international; +``` + +- `@NotNull`: Ensures that the value of `international` is not null. + + +You can repeat the previous steps to create entity characteristics for the `Course` and `Enrollment` entities, ensuring appropriate annotations are applied to each attribute. + +### Enrollment Entity Characteristics: + +- `id` (UUID): Primary key for the entity. +- `enrollmentDate` (Date): Date of enrollment. +- `grade` (int): Grade achieved in the course. + +### Course Entity Characteristics: + +- `id` (UUID): Primary key for the entity. +- `name` (String): Name of the course. +- `instructor` (String): Name of the course instructor. +- `schedule` (String): Schedule details of the course. +- `capacity` (int): Maximum capacity of the course. +- `online` (boolean): Indicates if the course is online. +- `startDate` (Date): Start date of the course. + +--- + +# [Next: Managing Relationships](relationships.md) \ No newline at end of file diff --git a/docs/en/jpa/practice/creation/create-entity.md b/docs/en/jpa/practice/creation/create-entity.md new file mode 100644 index 0000000..851531f --- /dev/null +++ b/docs/en/jpa/practice/creation/create-entity.md @@ -0,0 +1,60 @@ +# Creating Entities + +## Introduction + +This guide focuses on creating entities in a Spring Boot project using JPA (Java Persistence API). It provides step-by-step instructions for setting up the folder structure and creating entity classes. + +## Goal + +The goal of this guide is to demonstrate how to create entity classes in a Spring Boot project, following best practices and utilizing JPA for data persistence. + +## Folder Structure + +To ensure a well-organized project, it's essential to establish a proper folder structure. Follow these guidelines: + +``` +src/ +└── main/ + └── java/ + └── com/ + └── example/ + └── demo/ + └── entity/ + ├── Student.java + ├── Enrollment.java + └── Course.java + +``` + +In this structure: +- The `src/main/java` directory contains your Java source files. +- The `com/example/demo/entity` directory is where you'll create your entity classes. + +## Creating Entity Classes + +To create entity classes, follow these steps: + +1. Navigate to the `com/example/demo/entity` directory in your project. +2. Create a new Java class file for each entity. You can repeat the following steps for each entity (e.g., Student, Enrollment, Course). +3. Define your entity class with the `@Entity` annotation. + +### Example: + +```java +package com.example.demo.entity; + +import javax.persistence.Entity; + +@Entity +public class Student { + +} +``` + +The `@Entity` annotation indicates that this class is a JPA entity. + +Repeat the above steps to create `Enrollment` and `Course` entity classes. + +--- + +# [Next: Entity Characteristics Definition](characteristics.md) \ No newline at end of file diff --git a/docs/en/jpa/practice/creation/fetching.md b/docs/en/jpa/practice/creation/fetching.md new file mode 100644 index 0000000..de11305 --- /dev/null +++ b/docs/en/jpa/practice/creation/fetching.md @@ -0,0 +1,49 @@ +Understood. Here's the revised document with the code combined with the scenario: + +--- + +# Fetching Strategies in Spring Boot with JPA: Understanding Lazy and Eager Loading + +## Introduction + +This guide explores the fetching strategies in a Spring Boot project with JPA (Java Persistence API). Specifically, we will delve into the concepts of Lazy and Eager loading and how they are applied in entity relationships. + +## Goal + +The goal of this guide is to provide a comprehensive understanding of fetching strategies in JPA. By the end of this guide, you will comprehend when to use Lazy and Eager loading and how to implement them in your application. + +## Fetching Strategies + +### Scenario + +In our entity relationships, we have a One-to-Many relationship between the `Student` entity and the `Enrollment` entity. Similarly, there is a One-to-Many relationship between the `Course` entity and the `Enrollment` entity. + +#### Student Entity + +In the `Student` entity, we have a One-to-Many relationship with the `Enrollment` entity. Each student can have multiple enrollments. + +To represent this relationship, we use the `@OneToMany` annotation with `mappedBy = "student"` in the `Student` entity. Here, we have a choice between Lazy and Eager loading strategies for fetching the associated enrollments. + +```java +@OneToMany(mappedBy = "student", fetch = FetchType.EAGER, cascade = CascadeType.ALL) +private List enrollments; +``` + +We opt for Eager loading (`FetchType.EAGER`) in this scenario. Since we typically expect to access all enrollments of a student together, Eager loading ensures that all enrollments are fetched immediately when loading the student. + +#### Course Entity + +Similarly, in the `Course` entity, we also have a One-to-Many relationship with the `Enrollment` entity. Each course can have multiple enrollments. + +To represent this relationship, we use the `@OneToMany` annotation with `mappedBy = "course"` in the `Course` entity. Here, we have another choice between Lazy and Eager loading strategies for fetching the associated enrollments. + +```java +@OneToMany(mappedBy = "course", fetch = FetchType.LAZY, cascade = CascadeType.ALL) +private List enrollments; +``` + +We opt for Lazy loading (`FetchType.LAZY`) in this scenario. Since we may not always need to access all enrollments of a course, Lazy loading ensures that enrollments are fetched only when explicitly requested. + +--- + +# [Next: Create Repository](../interacting/repository.md) \ No newline at end of file diff --git a/docs/en/jpa/practice/creation/relationships.md b/docs/en/jpa/practice/creation/relationships.md new file mode 100644 index 0000000..e7cdd1b --- /dev/null +++ b/docs/en/jpa/practice/creation/relationships.md @@ -0,0 +1,44 @@ +# Defining Entity Relationships + +## Introduction + +This guide delves into understanding and implementing relationships between entities in a Spring Boot project using JPA (Java Persistence API). Specifically, we will explore the relationship between the `Enrollment` entity and its associated entities `Student` and `Course`. + +## Goal + +The goal of this guide is to provide clear instructions for defining and understanding entity relationships in a Spring Boot project with JPA. By the end of this guide, you will comprehend how to establish associations between entities and implement them in your application. + +## Entity Associations + +![img.png](../../../../srcs/jpa/er-diagram.png) +### Enrollment Entity Characteristics: + +- `id` (UUID): Primary key for the entity. +- `student` (Student): Student associated with the enrollment. +- `course` (Course): Course associated with the enrollment. +- `enrollmentDate` (Date): Date of enrollment. +- `grade` (int): Grade achieved in the course. + +#### Student Relationship + +The relationship between the `Enrollment` entity and the `Student` entity represents a scenario where a student enrolls in a course. This is a Many-to-One relationship, where many enrollments can be associated with one student. To establish this relationship, annotate the `student` attribute in the `Enrollment` entity with `@ManyToOne`. + +```java +@ManyToOne +@JoinColumn(name = "student_id") +private Student student; +``` + +#### Course Relationship + +Similarly, the relationship between the `Enrollment` entity and the `Course` entity signifies a scenario where a course is enrolled by multiple students. This is also a Many-to-One relationship, where many enrollments can be associated with one course. Annotate the `course` attribute in the `Enrollment` entity with `@ManyToOne`. + +```java +@ManyToOne +@JoinColumn(name = "course_id") +private Course course; +``` + +--- + +# [Next: Fetching Strategies](fetching.md) diff --git a/docs/en/jpa/practice/dependencies/driver.md b/docs/en/jpa/practice/dependencies/driver.md new file mode 100644 index 0000000..928b2ab --- /dev/null +++ b/docs/en/jpa/practice/dependencies/driver.md @@ -0,0 +1,100 @@ +# JPA: Setup Dependencies + +## Introduction + +This guide focuses on setting up dependencies for a Spring Boot project with JPA (Java Persistence API). It covers the necessary steps to include database drivers for various databases such as PostgreSQL, MySQL, Oracle, MongoDB, and Microsoft SQL Server. By following this guide, you will configure all the required dependencies to establish connections with these databases in your Spring Boot application. + +## Goal +The goal of this guide is to provide clear instructions for setting up the necessary dependencies for Spring Boot and JPA, specifically focusing on database drivers for different databases. + +## Setup Dependencies + +### Database Drivers + +To connect to different databases in your Spring Boot application, include the appropriate database drivers. + +#### PostgreSQL + +**For Gradle:** +```groovy +implementation "org.postgresql:postgresql" +``` + +**For Maven:** +```xml + + org.postgresql + postgresql + INSERT_VERSION_HERE + +``` + +#### MySQL + +**For Gradle:** +```groovy +implementation "mysql:mysql-connector-java" +``` + +**For Maven:** +```xml + + mysql + mysql-connector-java + INSERT_VERSION_HERE + +``` + +#### Oracle Database Driver + +**For Gradle:** +```groovy +implementation 'com.oracle.database.jdbc:ojdbc8' +``` + +**For Maven:** +```xml + + com.oracle.database.jdbc + ojdbc8 + +``` + +#### MongoDB Driver (MongoDB Java Driver) + +**For Gradle:** +```groovy +implementation 'org.mongodb:mongodb-driver-sync:4.4.3' +``` + +**For Maven:** +```xml + + org.mongodb + mongodb-driver-sync + 4.4.3 + +``` + +#### Microsoft SQL Server JDBC Driver + +**For Gradle:** +```groovy +implementation 'com.microsoft.sqlserver:mssql-jdbc:9.4.0.jre11' +``` + +**For Maven:** +```xml + + com.microsoft.sqlserver + mssql-jdbc + 9.4.0.jre11 + +``` + +These dependencies facilitate database connectivity. + +--- + +# [Next: Spring Boot and JPA Dependencies](jpa.md) + diff --git a/docs/en/jpa/practice/dependencies/jpa.md b/docs/en/jpa/practice/dependencies/jpa.md new file mode 100644 index 0000000..6a63d36 --- /dev/null +++ b/docs/en/jpa/practice/dependencies/jpa.md @@ -0,0 +1,181 @@ +# JPA: Setup Dependencies + +## Introduction + +This guide focuses on setting up dependencies for a Spring Boot project with JPA (Java Persistence API). It covers the necessary steps to include Spring Boot Starter JDBC and Spring Boot Starter Data JPA dependencies. + +## Goal + +The goal of this guide is to provide clear instructions for setting up the necessary dependencies for Spring Boot and JPA, specifically focusing on Spring Boot Starter JDBC and Spring Boot Starter Data JPA dependencies. + +## Setup Dependencies + +### Spring Boot Starter JDBC + +To enable JDBC support in your Spring Boot application: + +#### Gradle + +```groovy +implementation "org.springframework.boot:spring-boot-starter-jdbc" +``` + +#### Maven + +```xml + + org.springframework.boot + spring-boot-starter-jdbc + +``` + +This dependency provides auto-configuration for JDBC-based data access. + +### Spring Boot Starter Data JPA + +To include support for JPA (Java Persistence API) in your Spring Boot application: + +#### Gradle + +```groovy +implementation "org.springframework.boot:spring-boot-starter-data-jpa" +``` + +#### Maven + +```xml + + org.springframework.boot + spring-boot-starter-data-jpa + +``` + +This dependency simplifies the setup of JPA-based repositories and provides default configurations for Hibernate. + +### Additional Configuration for Spring WebMVC + +If you are using Spring WebMVC, you need to add additional configuration to set up persistence-related beans and properties. + +#### Create a Persistence Configuration Class + +Create a new class named `PersistenceConfig` in the `com.example.config` package: + +```java +package com.example.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.persistence.EntityManagerFactory; +import javax.sql.DataSource; + +/** + * Configuration class for setting up persistence-related beans and properties. + * + *

+ * This class configures the data source, entity manager factory, and transaction manager for JPA. + * It reads database connection properties from an external properties file. + *

+ */ +@Configuration +@EnableTransactionManagement +@EnableJpaRepositories(basePackages = "com.example.repository") +@PropertySource({"classpath:application.properties"}) +public class PersistenceConfig { + + @Value("${spring.datasource.driver}") + private String dbDriver; + + @Value("${spring.datasource.url}") + private String dbUrl; + + @Value("${spring.datasource.username}") + private String dbUsername; + + @Value("${spring.datasource.password}") + private String dbPassword; + + @Value("${spring.jpa.properties.hibernate.dialect}") + private String hibernateDialect; + + @Value("${spring.jpa.properties.hibernate.show_sql}") + private boolean hibernateShowSql; + + @Value("${spring.jpa.hibernate.ddl-auto}") + private String hibernateHbm2ddlAuto; + + /** + * Bean definition for the DataSource. + * + *

+ * This method sets up the data source using the properties defined in the application.properties file. + *

+ * + * @return DataSource bean + */ + @Bean + public DataSource dataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName(dbDriver); + dataSource.setUrl(dbUrl); + dataSource.setUsername(dbUsername); + dataSource.setPassword(dbPassword); + return dataSource; + } + + /** + * Bean definition for the EntityManagerFactory. + * + *

+ * This method sets up the entity manager factory using the configured data source and Hibernate properties. + *

+ * + * @param dataSource the data source bean + * @return EntityManagerFactory bean + */ + @Bean + public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) { + LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); + em.setDataSource(dataSource); + em.setPackagesToScan("com.example.entity"); + + HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); + vendorAdapter.setDatabasePlatform(hibernateDialect); + vendorAdapter.setShowSql(hibernateShowSql); + vendorAdapter.setGenerateDdl("update".equalsIgnoreCase(hibernateHbm2ddlAuto)); + em.setJpaVendorAdapter(vendorAdapter); + + return em; + } + + /** + * Bean definition for the Spring Transaction Manager. + * + *

+ * This method sets up the transaction manager for JPA using the configured entity manager factory. + *

+ * + * @param entityManagerFactory the entity manager factory bean + * @return TransactionManager bean + */ + @Bean + public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { + JpaTransactionManager txManager = new JpaTransactionManager(); + txManager.setEntityManagerFactory(entityManagerFactory); + return txManager; + } +} +``` + +--- + +# [Next: Entity Creation](../creation/create-entity.md) \ No newline at end of file diff --git a/docs/en/jpa/practice/interacting/jpa-repository.md b/docs/en/jpa/practice/interacting/jpa-repository.md new file mode 100644 index 0000000..e81961e --- /dev/null +++ b/docs/en/jpa/practice/interacting/jpa-repository.md @@ -0,0 +1,54 @@ +# Creating JpaRepository + +## Introduction + +This guide demonstrates how to create repository for entity management in a Spring Boot project with JPA (Java Persistence API) using JpaRepository. + +## Goal + +The goal of this guide is to provide clear instructions for setting up repository for managing entities in a Spring Boot application. By the end of this guide, you will be able to create repository and service classes for the `Course` entity. + +## Folder Structure + +``` +src/ +└── main/ + └── java/ + └── com/ + └── example/ + └── demo/ + ├── data/ + │ └── entities/ + │ ├── Student.java + │ ├── Enrollment.java + │ └── Course.java + └── repository/ + ├── StudentRepository.java + └── CourseRepository.java + +``` +## Repository Class + +### CourseRepository.java + +```java +package com.yourcompany.yourproject.repository; + +import com.yourcompany.yourproject.model.Course; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface CourseRepository extends JpaRepository { + // Add repository methods for course entity +} +``` + + +The `@Repository` annotation is a Spring stereotype annotation used to indicate that the decorated class is a repository component in the data access layer. It serves as a marker for any class that fulfills the role of a repository, facilitating the translation of exceptions into Spring's unified exception hierarchy. + + +--- + +# [Next: Create Record](jpa-repository/create.md) + diff --git a/docs/en/jpa/practice/interacting/jpa-repository/create.md b/docs/en/jpa/practice/interacting/jpa-repository/create.md new file mode 100644 index 0000000..9bcf784 --- /dev/null +++ b/docs/en/jpa/practice/interacting/jpa-repository/create.md @@ -0,0 +1,38 @@ +# Creating Records in a Table Using JpaRepository + +## Introduction + +This guide demonstrates how to create records in a table using the repository layer in a Spring Boot application with JPA (Java Persistence API) and JpaRepository. + +## Goal + +The goal of this guide is to illustrate the process of creating records in a table by implementing a method within the `CourseRepository` interface using JpaRepository. + +## Repository Method + +### CourseRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Course; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.UUID; + +@Repository +public interface CourseRepository extends JpaRepository { + + Course save(Course course); +} +``` + +### Explanation + +The `save(Course course)` method provided by JpaRepository allows us to persist a new record in the `Course` table. + +By invoking this method and passing a `Course` object as a parameter, JpaRepository automatically handles the process of persisting the entity to the database. + +--- + +# [Next: Read Record](read.md) \ No newline at end of file diff --git a/docs/en/jpa/practice/interacting/jpa-repository/delete.md b/docs/en/jpa/practice/interacting/jpa-repository/delete.md new file mode 100644 index 0000000..b24cfcf --- /dev/null +++ b/docs/en/jpa/practice/interacting/jpa-repository/delete.md @@ -0,0 +1,41 @@ +# Deleting Records from a Table Using JpaRepository + +## Introduction + +This guide demonstrates how to delete records from a table using the repository layer in a Spring Boot application with JPA (Java Persistence API) and JpaRepository. + +## Goal + +The goal of this guide is to illustrate the process of deleting records from a table by implementing a method within the `CourseRepository` interface using JpaRepository. + +## Repository Method + +### CourseRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Course; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.UUID; + +@Repository +public interface CourseRepository extends JpaRepository { + + void deleteById(UUID id); +} +``` + +## Explanation + +The `deleteById(UUID id)` method signature follows a convention recognized by JpaRepository for deleting records based on their unique identifier. + +- The `delete` keyword indicates that this method is used for deleting data. +- `ById` specifies the criteria for identifying the record to be deleted. In this case, we are targeting a record with a specific ID. + +By adhering to this naming convention, JpaRepository automatically generates the appropriate SQL query behind the scenes to delete the desired record from the database. This simplifies the development process by eliminating the need to write explicit SQL delete statements, allowing developers to focus on defining method signatures that reflect the intended data deletion operations. + +--- + +# [Next: Custom Query](query.md) diff --git a/docs/en/jpa/practice/interacting/jpa-repository/query.md b/docs/en/jpa/practice/interacting/jpa-repository/query.md new file mode 100644 index 0000000..0804429 --- /dev/null +++ b/docs/en/jpa/practice/interacting/jpa-repository/query.md @@ -0,0 +1,43 @@ +# Custom Query Using JpaRepository + +## Introduction + +This guide demonstrates how to implement custom query methods using the `@Query` annotation in the repository layer of a Spring Boot application with JPA (Java Persistence API) and JpaRepository. + +## Goal + +The goal of this guide is to illustrate the process of creating custom query methods in the repository interface to perform specific database operations tailored to application requirements. + +## Repository Method + +### CourseRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Course; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; +import java.util.List; + +@Repository +public interface CourseRepository extends JpaRepository { + + @Query("SELECT c FROM Course c WHERE c.instructor = :instructor") + List findCoursesByInstructor(@Param("instructor") String instructor); +} +``` + +### Explanation + +The `@Query` annotation allows us to define custom JPQL (Java Persistence Query Language) queries directly within the repository interface. + +- `"SELECT c FROM Course c WHERE c.instructor = :instructor"` is a JPQL query that selects all courses where the instructor matches the provided value. +- `@Param("instructor")` annotation binds the method parameter `instructor` to the named parameter `:instructor` in the JPQL query. + +By using `@Query`, we can create complex queries tailored to specific data retrieval needs, providing flexibility and control over the database operations. + +--- + +# [Next: Tasks](../../../lab-work.md) diff --git a/docs/en/jpa/practice/interacting/jpa-repository/read.md b/docs/en/jpa/practice/interacting/jpa-repository/read.md new file mode 100644 index 0000000..ce7a6b2 --- /dev/null +++ b/docs/en/jpa/practice/interacting/jpa-repository/read.md @@ -0,0 +1,42 @@ +# Reading Records from a Table Using JpaRepository + +## Introduction + +This guide demonstrates how to retrieve data from a table using the repository layer in a Spring Boot application with JPA (Java Persistence API) and JpaRepository. + +## Goal + +The goal of this guide is to illustrate the process of reading data from a table by implementing a method within the `CourseRepository` interface using JpaRepository. + +## Repository Method + +### CourseRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Course; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.List; + +@Repository +public interface CourseRepository extends JpaRepository { + + List findCoursesByInstructor(String instructor); +} +``` + +### Explanation + +The `findCoursesByInstructor(String instructor)` method signature follows a specific naming convention recognized by Spring Data JPA. + +- The `find` keyword indicates that this method is used for retrieving data. +- `Courses` represents the entity type we want to retrieve. +- `ByInstructor` specifies the criteria for filtering the results. In this case, we are querying for courses based on the `instructor` attribute. + +By adhering to this naming convention, Spring Data JPA automatically generates the appropriate SQL query behind the scenes to fetch the required data from the database. This simplifies the development process by eliminating the need to write explicit SQL queries, allowing developers to focus on defining method signatures that reflect the desired data retrieval operations. + +--- + +# [Next: Delete Record](delete.md) \ No newline at end of file diff --git a/docs/en/jpa/practice/interacting/repository.md b/docs/en/jpa/practice/interacting/repository.md new file mode 100644 index 0000000..42cd863 --- /dev/null +++ b/docs/en/jpa/practice/interacting/repository.md @@ -0,0 +1,51 @@ +# Creating Repository + +## Introduction + +This guide demonstrates how to create repository for entity management in a Spring Boot project with JPA (Java Persistence API). + +## Goal + +The goal of this guide is to provide clear instructions for setting up repository for managing entities in a Spring Boot application. By the end of this guide, you will be able to create repository for the `Student` entity. + +## Folder Structure + +``` +src/ +└── main/ + └── java/ + └── com/ + └── example/ + └── demo/ + ├── data/ + │ └── entites/ + │ ├── Student.java + │ ├── Enrollment.java + │ └── Course.java + └── repository/ + └── StudentRepository.java + +``` +## Repository Class + +### StudentRepository.java + +```java +package com.yourcompany.yourproject.repository; + +import com.yourcompany.yourproject.model.Student; +import org.springframework.stereotype.Repository; + +@Repository +public class StudentRepository { + // Add repository methods for student entity +} +``` + + +The `@Repository` annotation is a Spring stereotype annotation used to indicate that the decorated class is a repository component in the data access layer. It serves as a marker for any class that fulfills the role of a repository, facilitating the translation of exceptions into Spring's unified exception hierarchy. + + +--- + +# [Next: Create Record](repository/create.md) diff --git a/docs/en/jpa/practice/interacting/repository/create.md b/docs/en/jpa/practice/interacting/repository/create.md new file mode 100644 index 0000000..34e92de --- /dev/null +++ b/docs/en/jpa/practice/interacting/repository/create.md @@ -0,0 +1,46 @@ +# Creating New Records in a Table Using Repository Layer + +## Introduction + +This guide illustrates how to create new records in a table using the repository layer in a Spring Boot application with JPA (Java Persistence API). + +## Goal + +The goal of this guide is to demonstrate the process of creating new records in a table by utilizing the repository layer. We will achieve this by implementing a method within the `StudentRepository` interface using the `EntityManager` instead of `JpaRepository`. + +## Repository Method + +### StudentRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Student; +import org.springframework.stereotype.Repository; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.transaction.Transactional; + +@Repository +public class StudentRepository { + + @PersistenceContext + private EntityManager entityManager; + + public void saveStudent(Student student) { + entityManager.persist(student); + } +} +``` + +### Explanation + +- `@Repository`: This annotation marks the class as a repository component in the data access layer. + +- `@PersistenceContext`: This annotation is used to inject an EntityManager instance into the repository class. + +- `entityManager.persist(student)`: This line of code persists the new `Student` entity to the database. + +--- + +# [Next: Read Record](read.md) \ No newline at end of file diff --git a/docs/en/jpa/practice/interacting/repository/delete.md b/docs/en/jpa/practice/interacting/repository/delete.md new file mode 100644 index 0000000..25fa2de --- /dev/null +++ b/docs/en/jpa/practice/interacting/repository/delete.md @@ -0,0 +1,47 @@ +# Deleting Records from a Table Using Repository Layer + +## Introduction + +This guide demonstrates how to delete records from a table using the repository layer in a Spring Boot application with JPA (Java Persistence API). + +## Goal + +The goal of this guide is to illustrate the process of deleting records from a table by implementing a method within the `StudentRepository` interface using the `EntityManager`. + +## Repository Method + +### StudentRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Student; +import org.springframework.stereotype.Repository; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.transaction.Transactional; + +@Repository +public class StudentRepository { + + @PersistenceContext + private EntityManager entityManager; + + public void deleteStudent(UUID id) { + Student studentToDelete = entityManager.find(Student.class, id); + entityManager.remove(studentToDelete); + } +} +``` + +### Explanation + +- `@Repository`: This annotation marks the class as a repository component in the data access layer. + +- `@PersistenceContext`: This annotation is used to inject an EntityManager instance into the repository class. + +- `entityManager.remove(studentToDelete)`: This line of code deletes the `Student` entity from the database. + +--- + +# [Next: Custom Query](query.md) diff --git a/docs/en/jpa/practice/interacting/repository/query.md b/docs/en/jpa/practice/interacting/repository/query.md new file mode 100644 index 0000000..d8c2129 --- /dev/null +++ b/docs/en/jpa/practice/interacting/repository/query.md @@ -0,0 +1,49 @@ +# Creating Custom Queries in a Table Using Repository Layer + +## Introduction + +This guide demonstrates how to create custom queries to fetch records from a table using the repository layer in a Spring Boot application with JPA (Java Persistence API). + +## Goal + +The goal of this guide is to illustrate the process of creating custom queries to fetch records from a table by implementing a method within the `StudentRepository` interface using the `EntityManager`. + +## Repository Method + +### StudentRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Student; +import org.springframework.stereotype.Repository; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.transaction.Transactional; +import java.util.List; + +@Repository +public class StudentRepository { + + @PersistenceContext + private EntityManager entityManager; + + public List findStudentsByMajor(String major) { + return entityManager.createQuery("SELECT s FROM Student s WHERE s.major = :major", Student.class) + .setParameter("major", major) + .getResultList(); + } +} +``` + +### Explanation + +- `@Repository`: This annotation marks the class as a repository component in the data access layer. + +- `@PersistenceContext`: This annotation is used to inject an EntityManager instance into the repository class. + +- `entityManager.createQuery(...)`: This line of code creates a custom JPQL (Java Persistence Query Language) query to fetch records based on the provided criteria (`major` in this example). + +--- + +# [Next: Create JpaRepository](../jpa-repository.md) \ No newline at end of file diff --git a/docs/en/jpa/practice/interacting/repository/read.md b/docs/en/jpa/practice/interacting/repository/read.md new file mode 100644 index 0000000..cd32262 --- /dev/null +++ b/docs/en/jpa/practice/interacting/repository/read.md @@ -0,0 +1,46 @@ +# Reading Records from a Table Using Repository Layer + +## Introduction + +This guide demonstrates how to read records from a table using the repository layer in a Spring Boot application with JPA (Java Persistence API). + +## Goal + +The goal of this guide is to illustrate the process of reading records from a table by implementing a method within the `StudentRepository` interface using the `EntityManager`. + +## Repository Method + +### StudentRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Student; +import org.springframework.stereotype.Repository; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.transaction.Transactional; + +@Repository +public class StudentRepository { + + @PersistenceContext + private EntityManager entityManager; + + public Student findStudentById(UUID id) { + return entityManager.find(Student.class, id); + } +} +``` + +### Explanation + +- `@Repository`: This annotation marks the class as a repository component in the data access layer. + +- `@PersistenceContext`: This annotation is used to inject an EntityManager instance into the repository class. + +- `entityManager.find(Student.class, id)`: This line of code retrieves the `Student` entity from the database based on the provided `id`. + +--- + +# [Next: Update Record](update.md) diff --git a/docs/en/jpa/practice/interacting/repository/update.md b/docs/en/jpa/practice/interacting/repository/update.md new file mode 100644 index 0000000..ba2b0bc --- /dev/null +++ b/docs/en/jpa/practice/interacting/repository/update.md @@ -0,0 +1,46 @@ +# Updating Records in a Table Using Repository Layer + +## Introduction + +This guide illustrates how to update records in a table using the repository layer in a Spring Boot application with JPA (Java Persistence API). + +## Goal + +The goal of this guide is to demonstrate the process of updating records in a table by implementing a method within the `StudentRepository` interface using the `EntityManager`. + +## Repository Method + +### StudentRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Student; +import org.springframework.stereotype.Repository; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.transaction.Transactional; + +@Repository +public class StudentRepository { + + @PersistenceContext + private EntityManager entityManager; + + public Student updateStudent(Student student) { + return entityManager.merge(student); + } +} +``` + +### Explanation + +- `@Repository`: This annotation marks the class as a repository component in the data access layer. + +- `@PersistenceContext`: This annotation is used to inject an EntityManager instance into the repository class. + +- `entityManager.merge(student)`: This line of code updates the `Student` entity in the database. + +--- + +# [Next: Delete Record](delete.md) \ No newline at end of file diff --git a/docs/en/springsecurity/lab-work.md b/docs/en/springsecurity/lab-work.md new file mode 100644 index 0000000..5c795fd --- /dev/null +++ b/docs/en/springsecurity/lab-work.md @@ -0,0 +1,64 @@ +English | [中文](../../cn/springsecurity/lab-work.md) | [Русский](../../ru/springsecurity/lab-work.md) + + +# Spring Security Lab Work + +Welcome to the Spring Security Lab Work! The goal of this series of tasks is to help you practice and get know to Spring Security, and make an enough startup project. Whether you're a beginner or looking to enhance your skills, these hands-on tasks will guide you through various aspects of security integration in a Spring application. + +## Goal of the Lab Work + +The primary goal of this lab work is to provide you with practical experience and proficiency in using security within a Spring environment. Spring Security is widely utilized for authentication, authorization and securing your project, and through these tasks, you will gain valuable insights into its configuration, authentication, authorization, and more. + +## Practice Tasks + +1. [Task 1: Configure Spring Security](practice/configure-spring-security.md) +2. [Task 2: Create a Base Implementation for User](practice/base-implementation-user.md) +3. [Task 3: Password Encryption](practice/password-encryption.md) +4. [Task 4: Add a Dummy Users](practice/add-dummy-users.md) +5. [Task 5: Create Identity to Users](practice/create-identity-to-users.md) +6. [Task 6: Create a Base for Authorization in Server](practice/setup-server-authorization.md) +7. [Task 7: Authorize Authenticated Users](practice/authorize-server-authenticated.md) +8. [Task 8: Authorize by Role](practice/authorize-server-role.md) +9. [Task 9: Authorize by Authority](practice/authorize-server-authority.md) +10. [Task 10: Configure Thymeleaf Security](practice/configure-thymeleaf-security.md) +11. [Task 11: Authorize Authenticated Users](practice/authorize-client-authenticated.md) +12. [Task 12: Authorize by Role](practice/authorize-client-role.md) +13. [Task 13: Authorize by Authority](practice/authorize-client-authority.md) +14. [Task 14: Custom Login Form](practice/custom-login-form.md) + +## Lab Work Tasks + +![img.png](../../srcs/springsecurity/task.png) + +### Task 1: Setup Spring Security +Initialize Spring Security in your project. + +### Task 2: Define User Roles and Authorities +Define different user roles (Manager, Teacher, Student) and their respective authorities. + +### Task 3: Configure Security in Controllers +Protect endpoints using role-based access control. + +#### Implementation Details +**Manager Role**: +- Add New Teacher (`/teachers/new`) +- Modify Teacher Profile (`/teachers/{id}/edit`) +- Modify Student Profile (`/students/{id}/edit`) +- Modify Student Marks (`/students/{id}/marks/edit`) + +**Teacher Role**: +- Modify Student Marks (`/students/{id}/marks/edit`) +- Add New Subject (`/subjects/new`) +- Add New Test (`/tests/new`) + +**Student Role**: +- Pass Test (`/tests/{id}/take`) +- Read Marks (`/students/{id}/marks`) + +### Task 4: Implement Authorization in Thymeleaf Templates + +Restrict access to UI elements based on user roles. + + +### Task 5: Test Role-Based Access Control +Ensure that endpoints and UI elements are correctly protected. diff --git a/docs/en/springsecurity/practice/add-dummy-users.md b/docs/en/springsecurity/practice/add-dummy-users.md new file mode 100644 index 0000000..de6300e --- /dev/null +++ b/docs/en/springsecurity/practice/add-dummy-users.md @@ -0,0 +1,64 @@ +# Add Dummy Users + +This task outlines the process of updating the `CustomUserDetailsService` class to include a method for adding dummy users to the in-memory storage to serving as a simple demonstration of user creation. + +## Goal + +Update the `CustomUserDetailsService` class to include a method for adding dummy users, allowing for the initialization of user data in the in-memory storage. + +## Steps + +1. **Update CustomUserDetailsService Class:** + + First, we need to update the `CustomUserDetailsService` class to include a method for adding dummy users. We'll leverage this method during bean initialization to populate the in-memory storage with dummy user data. + + ```java + @Service + public class CustomUserDetailsService implements UserDetailsService { + + private final UsersRepository usersRepository; + private final PasswordEncoder passwordEncoder; + + @Autowired + public CustomUserDetailsService(UsersRepository usersRepository, PasswordEncoder passwordEncoder) { + this.usersRepository = usersRepository; + this.passwordEncoder = passwordEncoder; + + // Call the addDummyUsers method to add dummy users during bean initialization + addDummyUsers(); + } + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + // Retrieve user details from the repository + CustomUserDetails userDetails = usersRepository.findByUsername(username); + if (userDetails == null) { + throw new UsernameNotFoundException("User not found with username: " + username); + } + return userDetails; + } + + // Method to add dummy users + private void addDummyUsers() { + // Create dummy users + CustomUserDetails admin = new CustomUserDetails("admin", passwordEncoder.encode("admin"), true, true, true, true); + CustomUserDetails moderator = new CustomUserDetails("moderator", passwordEncoder.encode("moderator"), true, true, true, true); + CustomUserDetails user = new CustomUserDetails("user", passwordEncoder.encode("user"), true, true, true, true); + + // Add users to the repository + usersRepository.save(admin); + usersRepository.save(moderator); + usersRepository.save(user); + } + } + ``` + + In this updated class: + - We've added a constructor that accepts `UsersRepository` and `PasswordEncoder` as dependencies. + - During bean initialization, the constructor calls the `addDummyUsers` method to populate the in-memory storage with dummy users. + - The `addDummyUsers` method creates dummy users with hardcoded usernames and passwords. + - Finally, the dummy users are saved to the repository using the `save` method. + +--- + +# [NEXT TASK: Create Identity to Users](create-identity-to-users.md) diff --git a/docs/en/springsecurity/practice/authorize-client-authenticated.md b/docs/en/springsecurity/practice/authorize-client-authenticated.md new file mode 100644 index 0000000..5905399 --- /dev/null +++ b/docs/en/springsecurity/practice/authorize-client-authenticated.md @@ -0,0 +1,54 @@ +# Authorize Authenticated Users (Client Side) + +This task outlines the process of authorizing users based on their authentication status in the client-side view using Thymeleaf. By displaying or hiding elements based on whether the user is authenticated, you can control the visibility of specific functionalities or actions. + +## Goal + +Control the visibility of elements related to adding and removing students based on whether the user is authenticated in the Thymeleaf views. + +## Steps + +1. **Update Thymeleaf Templates:** + + Modify the Thymeleaf templates to conditionally display elements based on the user's authentication status. + + ```html + + + + Student Management + + +

Student Management

+ + + + + + + + +
+

Welcome to the student management system. Here you can manage student records.

+
+ + + ``` + + In this template: + - The `th:if="${#authorization.expression('isAuthenticated()')}"` statement is used to conditionally display the "Add Student" and "Remove Student" buttons only if the user is authenticated. + +## Explanation + +- **Thymeleaf Security Dialect**: The `#authorization` object is part of the Thymeleaf Security Dialect, which integrates Spring Security with Thymeleaf. +- **Conditional Display**: The `th:if` attribute is used to conditionally display or hide elements based on the user's authentication status. + +By following these steps, you can control the visibility of elements in your Thymeleaf views based on whether the user is authenticated, ensuring that only authenticated users can see and interact with specific functionalities. + +--- + +# [NEXT TASK: Authorize by Role](authorize-client-role.md) diff --git a/docs/en/springsecurity/practice/authorize-client-authority.md b/docs/en/springsecurity/practice/authorize-client-authority.md new file mode 100644 index 0000000..cf24bc7 --- /dev/null +++ b/docs/en/springsecurity/practice/authorize-client-authority.md @@ -0,0 +1,55 @@ +# Authorize by Authority (Client Side) + +This task outlines the process of authorizing users based on their authorities in the client-side view using Thymeleaf. By displaying or hiding elements based on user authorities, you can control the visibility of specific functionalities or actions. + +## Goal + +Control the visibility of elements related to adding and removing students based on the user's authorities in the Thymeleaf views. + +## Steps + +1. **Update Thymeleaf Templates:** + + Modify the Thymeleaf templates to conditionally display elements based on the user's authorities. + + ```html + + + + Student Management + + +

Student Management

+ + + + + + + + +
+

Welcome to the student management system. Here you can manage student records.

+
+ + + ``` + + In this template: + - The `th:if="${#authorization.expression('hasAuthority(''WRITE'')')}"` statement is used to conditionally display the "Add Student" button only if the user has the `WRITE` authority. + - Similarly, the `th:if="${#authorization.expression('hasAuthority(''DELETE'')')}"` statement is used to conditionally display the "Remove Student" button only if the user has the `DELETE` authority. + +## Explanation + +- **Thymeleaf Security Dialect**: The `#authorization` object is part of the Thymeleaf Security Dialect, which integrates Spring Security with Thymeleaf. +- **Conditional Display**: The `th:if` attribute is used to conditionally display or hide elements based on the user's authorities. + +By following these steps, you can control the visibility of elements in your Thymeleaf views based on user authorities, ensuring that only authorized users can see and interact with specific functionalities. + +--- + +# [NEXT TASK: Custom Login Form](custom-login-form.md) diff --git a/docs/en/springsecurity/practice/authorize-client-role.md b/docs/en/springsecurity/practice/authorize-client-role.md new file mode 100644 index 0000000..639933a --- /dev/null +++ b/docs/en/springsecurity/practice/authorize-client-role.md @@ -0,0 +1,55 @@ +# Authorize by Role (Client Side) + +This task outlines the process of authorizing users based on their roles in the client-side view using Thymeleaf. By displaying or hiding elements based on user roles, you can control the visibility of specific functionalities or actions. + +## Goal + +Control the visibility of elements related to adding and removing students based on the user's roles in the Thymeleaf views. + +## Steps + +1. **Update Thymeleaf Templates:** + + Modify the Thymeleaf templates to conditionally display elements based on the user's roles. + + ```html + + + + Student Management + + +

Student Management

+ + + + + + + + +
+

Welcome to the student management system. Here you can manage student records.

+
+ + + ``` + + In this template: + - The `th:if="${#authorization.expression('hasRole(''ROLE_ADMIN'')')}"` statement is used to conditionally display the "Add Student" button only if the user has the `ROLE_ADMIN` role. + - Similarly, the `th:if="${#authorization.expression('hasRole(''ROLE_MANAGER'')')}"` statement is used to conditionally display the "Remove Student" button only if the user has the `ROLE_MANAGER` role. + +## Explanation + +- **Thymeleaf Security Dialect**: The `#authorization` object is part of the Thymeleaf Security Dialect, which integrates Spring Security with Thymeleaf. +- **Conditional Display**: The `th:if` attribute is used to conditionally display or hide elements based on the user's roles. + +By following these steps, you can control the visibility of elements in your Thymeleaf views based on user roles, ensuring that only authorized users can see and interact with specific functionalities. + +--- + +# [NEXT TASK: Authorize by Authority](authorize-client-authority.md) diff --git a/docs/en/springsecurity/practice/authorize-server-authenticated.md b/docs/en/springsecurity/practice/authorize-server-authenticated.md new file mode 100644 index 0000000..5b9cd1b --- /dev/null +++ b/docs/en/springsecurity/practice/authorize-server-authenticated.md @@ -0,0 +1,38 @@ +# Authorize Authenticated User + +This task outlines the process of authorizing authenticated users in your application. By requiring authentication for specific paths or endpoints, you can ensure that only logged-in users can access certain resources. + +## Goal + +Authorize access to the `/second` path only for authenticated users while allowing public access to other paths. + +## Steps + +1. **Update Security Configuration:** + + In the `WebSecurityConfig` class, modify the `configure(HttpSecurity http)` method to specify that access to the `/second` path should be restricted to authenticated users. + + ```java + @Configuration + @EnableWebSecurity + public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests((requests) -> requests + // Other endpoints... + .requestMatchers("/second").authenticated() + // Other endpoints... + ); + } + } + ``` + + In this configuration: + - We use `.authorizeHttpRequests()` to define authorization rules. + - The `.requestMatchers("/second").authenticated()` statement specifies that access to the `/second` path should be restricted to authenticated users. + +--- + +# [NEXT TASK: Authorize by Role](authorize-server-role.md) diff --git a/docs/en/springsecurity/practice/authorize-server-authority.md b/docs/en/springsecurity/practice/authorize-server-authority.md new file mode 100644 index 0000000..8484252 --- /dev/null +++ b/docs/en/springsecurity/practice/authorize-server-authority.md @@ -0,0 +1,39 @@ +# Authorize by Authority + +This task outlines the process of authorizing users based on their authorities in your application. By assigning different authorities to users, you can control access to specific functionalities or actions. + +## Goal + +Authorize access to the `/addStudent` path for users with the `WRITE` authority and the `/removeStudent` path for users with the `DELETE` authority. + +## Steps + +1. **Update Security Configuration:** + + In the `WebSecurityConfig` class, modify the `configure(HttpSecurity http)` method to specify authority-based access control for the `/addStudent` and `/removeStudent` paths. + + ```java + @Configuration + @EnableWebSecurity + public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests((requests) -> requests + // Other Endpoints... + .requestMatchers("/addStudent").hasAuthority("WRITE") + .requestMatchers("/removeStudent").hasAuthority("DELETE") + // Other Endpoints... + ); + } + } + ``` + + In this configuration: + - The `.requestMatchers("/addStudent").hasAuthority("WRITE")` statement specifies that access to the `/addStudent` path should be restricted to users with the `WRITE` authority. + - Similarly, `.requestMatchers("/removeStudent").hasAuthority("DELETE")` restricts access to the `/removeStudent` path to users with the `DELETE` authority. + +--- + +# [NEXT TASK: Configure Thymeleaf Security](configure-thymeleaf-security.md) \ No newline at end of file diff --git a/docs/en/springsecurity/practice/authorize-server-role.md b/docs/en/springsecurity/practice/authorize-server-role.md new file mode 100644 index 0000000..3b1ab77 --- /dev/null +++ b/docs/en/springsecurity/practice/authorize-server-role.md @@ -0,0 +1,39 @@ +# Authorize by Role + +This task outlines the process of authorizing users based on their roles in your application. By assigning different roles to users, you can control access to specific resources or functionalities. + +## Goal + +Authorize access to the `/third` path for users with the `ROLE_MODERATOR` role and the `/fourth` path for users with the `ROLE_ADMIN` role. + +## Steps + +1. **Update Security Configuration:** + + In the `WebSecurityConfig` class, modify the `configure(HttpSecurity http)` method to specify role-based access control for the `/third` and `/fourth` paths. + + ```java + @Configuration + @EnableWebSecurity + public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests((requests) -> requests + // Other Endpoints... + .requestMatchers("/third").hasAuthority("ROLE_MODERATOR") + .requestMatchers("/fourth").hasAuthority("ROLE_ADMIN") + // Other Endpoints... + ); + } + } + ``` + + In this configuration: + - The `.requestMatchers("/third").hasAuthority("ROLE_MODERATOR")` statement specifies that access to the `/third` path should be restricted to users with the `ROLE_MODERATOR` authority. + - Similarly, `.requestMatchers("/fourth").hasAuthority("ROLE_ADMIN")` restricts access to the `/fourth` path to users with the `ROLE_ADMIN` authority. + +--- + +# [NEXT TASK: Authorize by Authority](authorize-server-authority.md) \ No newline at end of file diff --git a/docs/en/springsecurity/practice/base-implementation-user.md b/docs/en/springsecurity/practice/base-implementation-user.md new file mode 100644 index 0000000..c77596f --- /dev/null +++ b/docs/en/springsecurity/practice/base-implementation-user.md @@ -0,0 +1,184 @@ +# Create Base Implementation for User + +In this task, we will focus on creating a base implementation for managing users in your application. This includes defining the UserDetails entity, creating a repository to manage user data, and implementing a UserDetailsService to load user details during authentication. + +## Goal + +The goal of this task is to establish a solid foundation for managing users within your application. By implementing UserDetails, UsersRepository, and UserDetailsService, you will be able to authenticate users, manage their details, and perform user-related operations efficiently. + +## Steps + +1. **Define UserDetails Entity** + + Start by defining a UserDetails entity that represents the user details in your application. This entity should implement the UserDetails interface provided by Spring Security. + + ```java + package edu.labs.yourproject.model; + + import org.springframework.security.core.GrantedAuthority; + import org.springframework.security.core.userdetails.UserDetails; + + import java.util.Collection; + + public class CustomUserDetails implements UserDetails { + + // Implement UserDetails methods here + + } + ``` + + Implement the methods required by the UserDetails interface to provide user details such as username, password, authorities, etc. + +2. **Create UsersRepository Class** + + Since we are using in-memory storage for now, we'll create a simple UsersRepository class to manage user data. + + a. **Create UsersRepository Class** + + Create a new Java class named `UsersRepository` inside the `edu.labs.yourproject.repository` package. + + ```java + package edu.labs.yourproject.repository; + + import org.springframework.stereotype.Repository; + import edu.labs.yourproject.model.CustomUserDetails; + + @Repository + public class UsersRepository { + + private List users = new ArrayList<>(); + + // Add methods for managing users as needed + } + ``` + + This class will serve as the repository for managing user data. We'll add methods to retrieve, add, update, and delete users in subsequent steps. + + b. **Add findByUsername Method** + + Add a method named `findByUsername` to the `UsersRepository` class. This method will retrieve user details by username from the repository. + + ```java + public CustomUserDetails findByUsername(String username) { + for (CustomUserDetails user : users) { + if (user.getUsername().equals(username)) { + return user; + } + } + return null; // User not found + } + ``` + + The `findByUsername` method is used to retrieve user details by username from the repository. In this placeholder implementation, it returns `null`, but you'll replace it with the actual logic to fetch user details from the database or any other data source. + +3. **Implement UserDetailsService** + + In this step, we will implement a UserDetailsService to load user details during authentication. This service will retrieve user information from the UsersRepository. + + a. **Create CustomUserDetailsService Class** + + Start by creating a new class named `CustomUserDetailsService` within your project's service package. This class will implement the UserDetailsService interface provided by Spring Security. + + ```java + package edu.labs.yourproject.service; + + import org.springframework.beans.factory.annotation.Autowired; + import org.springframework.security.core.userdetails.UserDetails; + import org.springframework.security.core.userdetails.UserDetailsService; + import org.springframework.security.core.userdetails.UsernameNotFoundException; + import org.springframework.stereotype.Service; + import com.yourcompany.yourproject.model.CustomUserDetails; + import com.yourcompany.yourproject.repository.UsersRepository; + + @Service + public class CustomUserDetailsService implements UserDetailsService { + + private final UsersRepository usersRepository; + + @Autowired + public CustomUserDetailsService(UsersRepository usersRepository) { + this.usersRepository = usersRepository; + } + + // Implement methods here + } + ``` + + We create the `CustomUserDetailsService` class and autowire the `UsersRepository` dependency using constructor injection. + + b. **Override loadUserByUsername Method** + + Override the `loadUserByUsername` method defined in the UserDetailsService interface. This method will retrieve user details from the UsersRepository based on the provided username. + + ```java + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + // Retrieve user details from the in-memory repository + CustomUserDetails userDetails = usersRepository.findByUsername(username); + if (userDetails == null) { + throw new UsernameNotFoundException("User not found with username: " + username); + } + return userDetails; + } + ``` + + Inside the `loadUserByUsername` method, we call the `findByUsername` method of the UsersRepository to retrieve user details by username. If the user is not found, we throw a UsernameNotFoundException. + +4. **Configure Beans in WebSecurityConfig** + + Open the WebSecurityConfig class located in your project's configuration package (`edu.labs.yourproject.config`). Inside this class, define beans for CustomUserDetails and UserDetailsRepository. + + ```java + package edu.labs.yourproject.config; + + import edu.labs.yourproject.model.CustomUserDetails; + import edu.labs.yourproject.repository.UserDetailsRepository; + import org.springframework.context.annotation.Bean; + import org.springframework.context.annotation.Configuration; + + @Configuration + @EnableWebSecurity + public class WebSecurityConfig { + + // The rest of code is here... + + @Bean + public CustomUserDetailsService customUserDetailsService() { + // Instantiate and configure CustomUserDetails bean + return new CustomUserDetailsService(); + } + + @Bean + public UserDetailsRepository userDetailsRepository() { + // Instantiate and configure UserDetailsRepository bean + return new UserDetailsRepository(); + } + } + ``` + + Define two bean methods: `CustomUserDetailsService()` and `userDetailsRepository()`. These methods instantiate and configure CustomUserDetailsService and UserDetailsRepository beans, respectively. + +## Folder Structure + +Your project's folder structure should resemble the following: + +``` +src +└── main + └── java + └── edu + └── labs + └── yourproject + ├── model + │ └── CustomUserDetails.java + ├── repository + │ └── UsersRepository.java + └── service + └── CustomUserDetailsService.java +``` + +This folder structure indicates where to create the `CustomUserDetailsService` class and the `UsersRepository` interface within your project. Organizing your classes in this manner helps maintain a clear and structured codebase. + +--- + +# [NEXT TASK: Password Encryption](password-encryption.md) \ No newline at end of file diff --git a/docs/en/springsecurity/practice/configure-spring-security.md b/docs/en/springsecurity/practice/configure-spring-security.md new file mode 100644 index 0000000..29a4e40 --- /dev/null +++ b/docs/en/springsecurity/practice/configure-spring-security.md @@ -0,0 +1,80 @@ +# Configure Spring Security + +In this task, we will focus on configuring Spring Security in your project. Spring Security provides comprehensive security features for Java applications, including authentication, authorization, and protection against common security threats. + +## Goal + +The goal of this task is to integrate Spring Security into your existing project, ensuring that your application is secure and protected against unauthorized access. + +## Steps + +1. **Add Spring Security Dependency** + + - For Maven Projects: + + Add the following dependency to your project's `pom.xml` file: + + ```xml + + org.springframework.boot + spring-boot-starter-security + + ``` + + - For Gradle Projects: + + Add the following dependency to your project's `build.gradle` file: + + ```groovy + implementation 'org.springframework.boot:spring-boot-starter-security' + ``` + + Ensure that you include the appropriate version of Spring Security for your project. + +2. **Create Security Configuration Class** + + Create a new Java class named `WebSecurityConfig` within your project's source folder structure. Typically, this class resides in the `config` package. The file should be named `WebSecurityConfig.java`. + + Your project's folder structure should resemble the following: + + ``` + src + └── main + └── java + └── edu + └── labs + └── yourproject + ├── config + │ └── WebMvcConfig.java + │ └── WebSecurityConfig.java + └── controller + └── PracticeController.java + ``` + +3. **Configure Security Configuration Class** + + Inside the `WebSecurityConfig` class, annotate it with `@Configuration` and `@EnableWebSecurity` to indicate that it is a configuration class for Spring Security. also will annotate `configure` method with `@Bean` + + ```java + package edu.labs.yourproject.config; + + import org.springframework.context.annotation.Configuration; + import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; + import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + + @Configuration + @EnableWebSecurity + public class WebSecurityConfig { + + @Bean + public SecurityFilterChain configure(HttpSecurity http) throws Exception { + http + // Security configuration here + return http.build(); + } + } + ``` + +--- + +# [Next Task: Authorize Authenticated Users](authorize-client-authenticated.md) diff --git a/docs/en/springsecurity/practice/configure-thymeleaf-security.md b/docs/en/springsecurity/practice/configure-thymeleaf-security.md new file mode 100644 index 0000000..efb4cd7 --- /dev/null +++ b/docs/en/springsecurity/practice/configure-thymeleaf-security.md @@ -0,0 +1,30 @@ +# Configure Thymeleaf with Spring Security + +## Goal +The goal of this task is to integrate Thymeleaf with Spring Security, enabling the use of additional Thymeleaf dialects and utilities provided by the `thymeleaf-extras-springsecurity6` library. + +## Steps + +1. **Gradle (Groovy):** + + Add the `thymeleaf-extras-springsecurity6` dependency to your `build.gradle` file: + + ```groovy + implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6:3.0.4.RELEASE' + ``` + +2. **Maven:** + + Add the following dependency to your `pom.xml` file: + + ```xml + + org.thymeleaf.extras + thymeleaf-extras-springsecurity6 + 3.0.4.RELEASE + + ``` + +--- + +# [NEXT TASK: Create a Base Implementation for User](base-implementation-user.md) diff --git a/docs/en/springsecurity/practice/create-identity-to-users.md b/docs/en/springsecurity/practice/create-identity-to-users.md new file mode 100644 index 0000000..c839716 --- /dev/null +++ b/docs/en/springsecurity/practice/create-identity-to-users.md @@ -0,0 +1,61 @@ +# Create Identity for Users + +This task outlines the process of adding authorities and roles to the users created in the previous step, "Add Dummy Users." By assigning roles and authorities to users, we establish their identity within the application and control their access to various resources and functionalities. + +## Goal + +Enhance the user profiles created in the previous step by assigning roles and authorities, thereby defining their identities and access permissions within the application. + +## Steps + +1. **Update User Profiles with Roles and Authorities:** + + We'll update the dummy user profiles created in the `CustomUserDetailsService` class to include roles and authorities. This involves assigning specific roles to each user, such as `ADMIN`, `MODERATOR`, or `USER`, and granting corresponding authorities based on their roles. + + ```java + // Inside addDummyUsers() method + + // Define roles + String adminRole = "ROLE_ADMIN"; + String moderatorRole = "ROLE_MODERATOR"; + String userRole = "ROLE_USER"; + + // Define authorities + List adminAuthorities = Arrays.asList( + new SimpleGrantedAuthority(adminRole), + new SimpleGrantedAuthority("READ"), + new SimpleGrantedAuthority("WRITE") + ); + + List moderatorAuthorities = Arrays.asList( + new SimpleGrantedAuthority(moderatorRole), + new SimpleGrantedAuthority("READ") + ); + + List userAuthorities = Collections.singletonList( + new SimpleGrantedAuthority(userRole) + ); + + // Create dummy users with roles and authorities + CustomUserDetails admin = new CustomUserDetails("admin", passwordEncoder.encode("admin"), true, true, true, true); + admin.setAuthorities(adminAuthorities); + admin.setRole(adminRole); + + CustomUserDetails moderator = new CustomUserDetails("moderator", passwordEncoder.encode("moderator"), true, true, true, true); + moderator.setAuthorities(moderatorAuthorities); + moderator.setRole(moderatorRole); + + CustomUserDetails user = new CustomUserDetails("user", passwordEncoder.encode("user"), true, true, true, true); + user.setAuthorities(userAuthorities); + user.setRole(userRole); + ``` + + In this updated code: + - We define roles and authorities as variables for clarity and ease of maintenance. + - Each user profile now includes a list of authorities based on their assigned roles. + - Authorities are represented as `SimpleGrantedAuthority` objects and added to the user profiles accordingly. + - Additionally, we set the role for each user to enable role-based access control in subsequent steps. + +--- + +# [NEXT TASK: Create a Base for Authorization in Server](setup-server-authorization.md) \ No newline at end of file diff --git a/docs/en/springsecurity/practice/custom-login-form.md b/docs/en/springsecurity/practice/custom-login-form.md new file mode 100644 index 0000000..fb8132c --- /dev/null +++ b/docs/en/springsecurity/practice/custom-login-form.md @@ -0,0 +1,40 @@ +# Custom Login Form + +This task guides you through the process of enabling a custom login form for authentication using Spring Security. By implementing a custom login form, users can securely authenticate into your application. + +## Goal + +Activate the custom login form page that has already been created in specific path. + +## Steps + +1. **Update Security Configuration:** + + In the `WebSecurityConfig` class, modify the `configure(HttpSecurity http)` method to specify the custom login page. + + ```java + @Configuration + @EnableWebSecurity + public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests((requests) -> requests + // Add other authorization configurations here + ) + .formLogin((login) -> login + .loginPage("/custom-login-page") // Specify the custom login page URL + // Add other form login configurations here + ); + } + } + ``` + + In this configuration: + - The `.loginPage("/custom-login-page")` statement specifies the URL of the custom login page. + - You can add additional configurations to customize the form login behavior, such as setting login success or failure URLs, defining form field names, etc. + +--- + +# [NEXT: TASKS](../lab-work.md) diff --git a/docs/en/springsecurity/practice/password-encryption.md b/docs/en/springsecurity/practice/password-encryption.md new file mode 100644 index 0000000..2cd1a21 --- /dev/null +++ b/docs/en/springsecurity/practice/password-encryption.md @@ -0,0 +1,81 @@ +# Password Encryption + +In this task, we will configure password encryption for user authentication in a Spring Security-enabled application. Encrypting passwords enhances security by storing them securely in the database. + +## Goal + +The goal of this setup is to configure password encryption using the BCryptPasswordEncoder provided by Spring Security. This ensures that passwords are securely hashed before being stored in the database. + +## Steps + +1. **Add BCryptPasswordEncoder Bean** + + Open the WebSecurityConfig class located in your project's configuration package (`edu.labs.yourproject.config`). Inside this class, define a bean for BCryptPasswordEncoder. + + ```java + package edu.labs.yourproject.config; + + import org.springframework.context.annotation.Bean; + import org.springframework.context.annotation.Configuration; + import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + + @Configuration + public class WebSecurityConfig { + + @Bean + public BCryptPasswordEncoder passwordEncoder() { + // Instantiate and configure BCryptPasswordEncoder bean + return new BCryptPasswordEncoder(); + } + } + ``` + + Define a bean method `passwordEncoder()` that instantiates and configures a BCryptPasswordEncoder bean. This bean will be used to encode passwords before storing them in the database. + +2. **Encrypt Passwords** + + a. **Update CustomUserDetailsService Class** + + Open the CustomUserDetailsService class located in your project's service package (`edu.labs.yourproject.service`). Inject the BCryptPasswordEncoder bean into this class. + + ```java + package edu.labs.yourproject.service; + + import org.springframework.beans.factory.annotation.Autowired; + import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + import org.springframework.stereotype.Service; + import edu.labs.yourproject.model.CustomUserDetails; + import edu.labs.yourproject.repository.UsersRepository; + + @Service + public class CustomUserDetailsService implements UserDetailsService { + + private final UsersRepository usersRepository; + + @Autowired + private BCryptPasswordEncoder passwordEncoder; + + @Autowired + public CustomUserDetailsService(UsersRepository usersRepository) { + this.usersRepository = usersRepository; + } + } + ``` + + b. **Implement Registration Method** + + Define a method in the CustomUserDetailsService class to handle user registration. In this method, encrypt the user's password before saving it to the database. + + ```java + public void registerUser(CustomUserDetails user) { + // Encrypt password before saving user + String encodedPassword = passwordEncoder.encode(user.getPassword()); + user.setPassword(encodedPassword); + usersRepository.save(user); + } + ``` + + This method takes a CustomUserDetails object representing the user to be registered. It encrypts the user's password using the BCryptPasswordEncoder bean and then saves the user to the database. + +--- +# [NEXT TASK: Add a Dummy Users](add-dummy-users.md) \ No newline at end of file diff --git a/docs/en/springsecurity/practice/setup-server-authorization.md b/docs/en/springsecurity/practice/setup-server-authorization.md new file mode 100644 index 0000000..5c23912 --- /dev/null +++ b/docs/en/springsecurity/practice/setup-server-authorization.md @@ -0,0 +1,41 @@ +# Setup Server Authorization + +This task you through setting up authorization in your application by configuring security rules using Spring Security. By defining authorization rules, you can control access to specific paths and endpoints within your application. + +## Goal + +Configure authorization rules to restrict or allow access to various paths and endpoints in the application. + +## Steps + +1. **Add Security Configuration:** + + In the `WebSecurityConfig` class, add the `configure(HttpSecurity http)` method to define security rules for the application. We'll use the paths and endpoints defined in the previous lab work. + + ```java + @Configuration + @EnableWebSecurity + public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests((requests) -> requests + .requestMatchers("/first").permitAll() + .requestMatchers("/second").permitAll() + .requestMatchers("/third").permitAll() + .requestMatchers("/fourth").permitAll() + .requestMatchers("/addStudent").permitAll() + .requestMatchers("/removeStudent").permitAll() + ); + } + } + ``` + + In this configuration: + - We use `.authorizeHttpRequests()` to define authorization rules. + - Inside the lambda expression, we specify which requests should be permitted. + +--- + +# [NEXT TASK: Authorize Authenticated Users](authorize-server-authenticated.md) diff --git a/docs/en/thymeleaf/lab-work.md b/docs/en/thymeleaf/lab-work.md index 8872e1b..f548e74 100644 --- a/docs/en/thymeleaf/lab-work.md +++ b/docs/en/thymeleaf/lab-work.md @@ -1,3 +1,6 @@ +English | [中文](../../cn/thymeleaf/lab-work.md) | [Русский](../../ru/thymeleaf/lab-work.md) + + # Thymeleaf Lab Work Welcome to the Thymeleaf Lab Work! The goal of this series of tasks is to help you practice and master Thymeleaf, a powerful template engine for Java applications. Whether you're a beginner or looking to enhance your skills, these hands-on tasks will guide you through various aspects of Thymeleaf integration in a Spring application. @@ -46,7 +49,7 @@ The primary goal of this lab work is to provide you with practical experience an ![login-page.png](../../srcs/thymeleaf/login-page.png) - ![signup-page.png](../../srcs/thymeleaf/signup-page.png) + ![signup.png](../../srcs/thymeleaf/signup.png) 4. **Task 4: Validate Login and Register Actions** @@ -68,6 +71,4 @@ The primary goal of this lab work is to provide you with practical experience an ![modify-user-page.png](../../srcs/thymeleaf/modify-user-page.png) -Feel free to explore and complete these tasks at your own pace. Each task is designed to further enhance your skills in Thymeleaf and web development. If you have any questions or need assistance, feel free to reach out. -Happy coding! diff --git a/docs/en/thymeleaf/practice/configure-thymeleaf.md b/docs/en/thymeleaf/practice/configure-thymeleaf.md index 2c016c4..0bb9809 100644 --- a/docs/en/thymeleaf/practice/configure-thymeleaf.md +++ b/docs/en/thymeleaf/practice/configure-thymeleaf.md @@ -112,8 +112,6 @@ This task involves setting up Thymeleaf within a Spring application, enabling se --- -**Conclusion:** - -Congratulations! You have successfully configured Thymeleaf in your Spring application. This setup allows for seamless integration of Thymeleaf templates, providing a powerful tool for dynamic web content. If you want to delve deeper into Thymeleaf configuration or explore advanced features, feel free to refer to the [Thymeleaf Documentation](https://www.thymeleaf.org/documentation.html). +--- # [NEXT TASK: *Create First View*](create-first-view.md) \ No newline at end of file diff --git a/docs/en/thymeleaf/practice/create-first-view.md b/docs/en/thymeleaf/practice/create-first-view.md index 30577eb..710d029 100644 --- a/docs/en/thymeleaf/practice/create-first-view.md +++ b/docs/en/thymeleaf/practice/create-first-view.md @@ -56,8 +56,4 @@ In this task, we'll create the first Thymeleaf view for your Spring application. --- -**Conclusion:** - -You have successfully created and registered your first Thymeleaf view. Ensure you follow the correct file path as defined in the Thymeleaf configuration. - # [NEXT TASK: *Working With Variables*](working-with-variables.md) \ No newline at end of file diff --git a/docs/en/thymeleaf/practice/form-handling.md b/docs/en/thymeleaf/practice/form-handling.md index c7b6b7b..c9ff294 100644 --- a/docs/en/thymeleaf/practice/form-handling.md +++ b/docs/en/thymeleaf/practice/form-handling.md @@ -67,8 +67,6 @@ In this continuation, we will focus on handling form submissions and rendering t - The logic inside this method adds the student to the `students` list. In a real-world scenario, you would typically save the student to a database or perform other necessary actions. - `return "redirect:/third";`: This line redirects the user back to the form view (`/third`). -**Conclusion:** - -You have successfully implemented form handling in Thymeleaf, including showing the form view and handling form submissions in the `PracticeController`. Users can navigate to the form, submit student details. +--- # [NEXT TASK: *Query Parameter and Validation*](validation.md) \ No newline at end of file diff --git a/docs/en/thymeleaf/practice/forms.md b/docs/en/thymeleaf/practice/forms.md index 3876c1d..10d76be 100644 --- a/docs/en/thymeleaf/practice/forms.md +++ b/docs/en/thymeleaf/practice/forms.md @@ -113,8 +113,6 @@ Your view should look like that: ![third-view.png](../../../srcs/thymeleaf/third-view.png) -**Conclusion:** - -You have successfully set up the form in `third.html` and passed each field to the `PracticeController` using Thymeleaf's form binding. +--- # [NEXT TASK: *Form Handling*](form-handling.md) \ No newline at end of file diff --git a/docs/en/thymeleaf/practice/fragments-and-layouts.md b/docs/en/thymeleaf/practice/fragments-and-layouts.md index b3e2f8e..16651f7 100644 --- a/docs/en/thymeleaf/practice/fragments-and-layouts.md +++ b/docs/en/thymeleaf/practice/fragments-and-layouts.md @@ -123,8 +123,6 @@ Your view should look like that: ![fourth-view.png](../../../srcs/thymeleaf/fourth-view.png) -**Conclusion:** - -You have successfully implemented Thymeleaf fragments and layouts. The fragments are now correctly marked with `th:fragment` attributes inside the respective views, enabling their usage in the `fourth.html` layout. +--- # Congratulations ! you completed all tasks. now let's move to **[Lab work tasks](../lab-work.md#lab-work-tasks)** \ No newline at end of file diff --git a/docs/en/thymeleaf/practice/iteration.md b/docs/en/thymeleaf/practice/iteration.md index 9f8cc3a..8d37079 100644 --- a/docs/en/thymeleaf/practice/iteration.md +++ b/docs/en/thymeleaf/practice/iteration.md @@ -100,8 +100,6 @@ Your page should look like that: ![second-view.png](../../../srcs/thymeleaf/second-view.png) -**Conclusion:** - -You have successfully implemented iteration in Thymeleaf by creating a list of `StudentModel` objects, passing it to the `secondView`, and rendering a table of students in the `second.html` view. This approach allows you to dynamically display data in tables based on the provided model. +--- # [NEXT TASK: *Literals*](literals.md) \ No newline at end of file diff --git a/docs/en/thymeleaf/practice/literals.md b/docs/en/thymeleaf/practice/literals.md index f77ca7b..0841931 100644 --- a/docs/en/thymeleaf/practice/literals.md +++ b/docs/en/thymeleaf/practice/literals.md @@ -48,8 +48,6 @@ Your view should look like that: ![second-view-enhanced.png](../../../srcs/thymeleaf/second-view-enhanced.png) -**Conclusion:** - -You have successfully enhanced the `second.html` Thymeleaf view by incorporating literals to modify the displayed values based on certain conditions. This approach allows you to provide more descriptive and dynamic content in your views. +--- # [NEXT TASK: *Forms*](forms.md) \ No newline at end of file diff --git a/docs/en/thymeleaf/practice/validation.md b/docs/en/thymeleaf/practice/validation.md index 283fba4..00de7cb 100644 --- a/docs/en/thymeleaf/practice/validation.md +++ b/docs/en/thymeleaf/practice/validation.md @@ -78,8 +78,6 @@ Your view should look like that: ![third-view-error.png](../../../srcs/thymeleaf/third-view-error.png) -**Conclusion:** - -You have successfully adapted the `third` to display both success and error messages based on query parameters. This provides a more comprehensive feedback mechanism for users interacting with the form. +--- # [NEXT TASK: *Fragments and Layouts*](fragments-and-layouts.md) \ No newline at end of file diff --git a/docs/en/thymeleaf/practice/variables-and-controller.md b/docs/en/thymeleaf/practice/variables-and-controller.md index ca4ad12..1c2c04b 100644 --- a/docs/en/thymeleaf/practice/variables-and-controller.md +++ b/docs/en/thymeleaf/practice/variables-and-controller.md @@ -60,8 +60,6 @@ In this task, you will create a new Thymeleaf view named `second.html` and explo The `th:text="${title}"` expression retrieves the value of the `title` variable passed from the controller. -**Conclusion:** - -You have successfully created a new Thymeleaf view (`second.html`) and explored the process of passing variables from the controller to the view. This approach allows for dynamic content generation based on controller logic. Feel free to extend this concept to pass more variables and customize your views further. Now let's continue to the task +--- # [NEXT TASK: *Iteration*](iteration.md) \ No newline at end of file diff --git a/docs/en/thymeleaf/practice/working-with-variables.md b/docs/en/thymeleaf/practice/working-with-variables.md index 43ea184..21cbacd 100644 --- a/docs/en/thymeleaf/practice/working-with-variables.md +++ b/docs/en/thymeleaf/practice/working-with-variables.md @@ -83,10 +83,6 @@ now your page should look like that: ![first-view.png](../../../srcs/thymeleaf/first-view.png) -**Conclusion:** - -You have successfully explored and implemented various types of local variables in Thymeleaf. Experiment with different scenarios and understand how these variables contribute to dynamic and localized content in your Spring application. - -Feel free to refer to the [Thymeleaf Documentation](https://www.thymeleaf.org/documentation.html) for more details and advanced features. +--- # [NEXT TASK: *Variables And Controller*](variables-and-controller.md) \ No newline at end of file diff --git a/docs/en/transactions/lab-work.md b/docs/en/transactions/lab-work.md new file mode 100644 index 0000000..82457d6 --- /dev/null +++ b/docs/en/transactions/lab-work.md @@ -0,0 +1,58 @@ +English | [中文](../../cn/transactions/lab-work.md) | [Русский](../../ru/transactions/lab-work.md) + + +# Transactions Lab Work + +Welcome to the Transactions Lab Work! The goal of this series of tasks is to help you practice and master transaction management in a Spring application. Whether you're a beginner or looking to enhance your skills, these hands-on tasks will guide you through various aspects of transaction management, including propagation, isolation levels, nested transactions, and more. + +## Goal of the Lab Work + +The primary goal of this lab work is to provide you with practical experience and proficiency in managing transactions within a Spring environment. Through these tasks, you will gain valuable insights into configuring transactions, handling different propagation behaviors, implementing nested transactions, and ensuring data integrity in your applications. + +## Practice Tasks + +1. [Transaction Setup](practice/configuration.md) +2. [Part 1: Create the Entities and Repositories](practice/lessons/entities-and-repositories.md) +3. [Part 2: Implementing Basic Transactional Operations](practice/lessons/basic-transactional-operations.md) +4. [Part 3: Enhancing Transactional Methods with Detailed Logging](practice/lessons/transactional-logging.md) +5. [Part 4: Implementing Nested Transactions and Non-Transactional Operations](practice/lessons/nested-and-non-transactional-operations.md) + +## Lab Work Tasks + +![img.png](../../srcs/transactions/task-chart.png) + +- **Registering a User for an Event** + - **Task:** Implement a method to register a user for an event. Ensure the operation is completely isolated to maintain data consistency. Log this operation separately, regardless of whether the main transaction succeeds or fails. + - **Propagation:** REQUIRED + - **Isolation:** SERIALIZABLE + - **Logging Propagation:** REQUIRES_NEW + +- **Removing a User's Registration from an Event** + - **Task:** Implement a method to remove a user's registration from an event. Ensure this method is always executed within an existing transaction. + - **Propagation:** MANDATORY + +- **Fetching Registered Users for an Event** + - **Task:** Implement a method to fetch all users registered for a specific event. Ensure the method either joins an existing transaction or creates a new one, reading only committed data. + - **Propagation:** REQUIRED + - **Isolation:** READ_COMMITTED + +- **Adding a New Event** + - **Task:** Implement a method to add a new event. This operation should run without transactional guarantees to avoid unnecessary transactional overhead. + - **Propagation:** NOT_SUPPORTED + +- **Updating Event Details and Registrations with Nested Transactions** + - **Task:** Implement a method to update event details along with related registrations. Ensure consistency within nested transactions. + - **Propagation:** REQUIRED + - **Isolation:** REPEATABLE_READ + - **Nested Task:** Update registrations within a nested transaction. + +- **Updating Registrations** + - **Task:** Implement a method to update registration records. Ensure these operations are part of a nested transaction. + - **Propagation:** NESTED + - **Isolation:** REPEATABLE_READ + +- **Performing Non-Transactional Operation** + - **Task:** Implement a method for operations that do not require a transactional context, such as non-critical tasks or logging. + - **Propagation:** None + +--- \ No newline at end of file diff --git a/docs/en/transactions/practice/configuration.md b/docs/en/transactions/practice/configuration.md new file mode 100644 index 0000000..3bcf85a --- /dev/null +++ b/docs/en/transactions/practice/configuration.md @@ -0,0 +1,85 @@ +# Transaction Setup + +## Introduction + +This guide focuses on setting up transaction management in a Spring Boot project. It provides step-by-step instructions for enabling transaction management and configuring transaction attributes. + +## Goal + +The goal of this guide is to demonstrate how to configure transaction management in a Spring Boot application, allowing for the management of database transactions. + +## Transaction Management Setup + +To enable transaction management in your Spring Boot project, follow these steps: + +1. Add the necessary dependencies to your `pom.xml` or `build.gradle` file. Ensure that you have dependencies for Spring Boot, Spring Data JPA, and any database driver you are using (e.g., H2, MySQL, PostgreSQL). + +2. Configure transaction management in your Spring Boot application. You can do this by annotating your main application class with `@EnableTransactionManagement`. + +### Example (Java Config): + +```java +package com.example.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@SpringBootApplication +@EnableTransactionManagement +public class DemoApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + +} +``` + +3. If you are using Spring Web MVC, you need to add the following to your configuration files to set up the transaction manager: + +### Example (XML Config): + +```xml + + + +``` + +### Example (Java Config): + +```java +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.transaction.PlatformTransactionManager; + +import javax.persistence.EntityManagerFactory; + +@Configuration +public class TransactionConfig { + + /** + * Bean definition for the Spring Transaction Manager. + * + *

+ * This method sets up the transaction manager for JPA using the configured entity manager factory. + *

+ * + * @param entityManagerFactory the entity manager factory bean + * @return TransactionManager bean + */ + @Bean + public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { + JpaTransactionManager txManager = new JpaTransactionManager(); + txManager.setEntityManagerFactory(entityManagerFactory); + return txManager; + } +} +``` + +By following these steps, you will have transaction management enabled in your Spring Boot application, allowing you to manage database transactions effectively. + +--- + +# [Next: Create the Entities and Repositories](lessons/entities-and-repositories.md) \ No newline at end of file diff --git a/docs/en/transactions/practice/lessons/basic-transactional-operations.md b/docs/en/transactions/practice/lessons/basic-transactional-operations.md new file mode 100644 index 0000000..63d6589 --- /dev/null +++ b/docs/en/transactions/practice/lessons/basic-transactional-operations.md @@ -0,0 +1,50 @@ +# Lesson 2: Implementing Basic Transactional Operations + +## Goal + +This part aims to introduce simple yet important transactional methods for enrolling students and managing courses in a Spring Boot application. + +## Steps + +1. **Enrolling a Student in a Course** + + **Scenario**: As a university administrator, you need to enroll a student in a course. This action should be smooth and ensure that even if multiple enrollments happen at the same time or if there are any database issues, data integrity remains intact. + + **Implement `enrollStudentInCourse` Method**: Create a method to enroll a student in a course. Ensure that this process is transactional, meaning it's like a single package deal that guarantees everything happens correctly together. We use `Propagation.REQUIRED` to ensure that this method participates in any existing transaction or creates a new one if none exists. Additionally, we set `Isolation.SERIALIZABLE` to ensure that even if there are concurrent transactions, they don't interfere with each other, maintaining the integrity of the data. + + ```java + @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.SERIALIZABLE) + public void enrollStudentInCourse(UUID studentId, UUID courseId) { + // Your implementation here + } + ``` + +2. **Fetching Students for a Course** + + **Scenario**: To create a class roster for a course, you need to fetch a list of students who have enrolled. This operation should make sure that you always get an accurate view of the database, even if other activities are happening simultaneously. + + **Implement `getStudentsForCourse` Method**: Develop a method to retrieve students for a particular course. It should ensure that the data you fetch is consistent, regardless of any ongoing transactions. We use `Propagation.REQUIRED` to make sure this method participates in any existing transaction or creates a new one if none exists. We set `Isolation.READ_COMMITTED` to ensure that the data we fetch is committed and visible to other transactions, maintaining consistency. + + ```java + @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED) + public List getStudentsForCourse(UUID courseId) { + // Your implementation here + } + ``` + +3. **Adding a New Course** + + **Scenario**: A new course is about to be introduced to the curriculum. When adding it to the system, you want to make sure this operation doesn't interfere with anything else going on, maintaining its independence. + + **Implement `addNewCourse` Method**: Create a method to add a new course to the system. Make sure this process doesn't get tangled up with any other ongoing transactions. We use `Propagation.NOT_SUPPORTED` to ensure that this method doesn't participate in any existing transaction, giving it autonomy and avoiding any potential conflicts with other operations. + + ```java + @Transactional(propagation = Propagation.NOT_SUPPORTED) + public Course addNewCourse(String title) { + // Your implementation here + } + ``` + +--- + +# [NEXT: Enhancing Transactional Methods with Detailed Logging](transactional-logging.md) diff --git a/docs/en/transactions/practice/lessons/entities-and-repositories.md b/docs/en/transactions/practice/lessons/entities-and-repositories.md new file mode 100644 index 0000000..783f47f --- /dev/null +++ b/docs/en/transactions/practice/lessons/entities-and-repositories.md @@ -0,0 +1,38 @@ +# Lesson 1: Create the Entities and Repositories + +## Goal + +The goal of this task is to define the core entities (Student, Course, Enrollment, Log) and set up the corresponding repositories in a Spring Boot project using Spring Data JPA. + +## Steps + +1. **Refer to the provided ER diagram to define the entity classes.** + ![er-diagram.png](../../../../srcs/transactions/er-diagram.png) + If you already have the entity classes based on the provided ER diagram, proceed to step 2. Otherwise, analyze the ER diagram and create the following entity classes: + + - Student + - Course + - Enrollment + - Log + + Ensure that each entity class includes the necessary attributes as depicted in the ER diagram. + +2. **Create the repositories for the entities.** + + For example, let's create the repository for the `Student` entity: + + ```java + package com.example.demo.repository; + + import com.example.demo.entity.Student; + import org.springframework.data.jpa.repository.JpaRepository; + + public interface StudentRepository extends JpaRepository { + } + ``` + + If you already have the entity repositories, proceed to next step. Else, repeat the above step for the repositories of the remaining entities (Course, Enrollment, Log). + +--- + +# [СЛЕДУЮЩЕЕ: Реализация базовых транзакционных операций](basic-transactional-operations.md) \ No newline at end of file diff --git a/docs/en/transactions/practice/lessons/nested-and-non-transactional-operations.md b/docs/en/transactions/practice/lessons/nested-and-non-transactional-operations.md new file mode 100644 index 0000000..5ec8ec5 --- /dev/null +++ b/docs/en/transactions/practice/lessons/nested-and-non-transactional-operations.md @@ -0,0 +1,66 @@ +# Lesson 4: Implementing Nested Transactions and Non-Transactional Operations + +## Goal + +This part aims to explore the use of nested transactions and non-transactional operations within the service layer, providing students with insights into managing complex transactional scenarios. + +## Steps + +1. **Updating Course Details and Enrollments** + + **Scenario**: As a university administrator, you often need to update both the course details and the enrollments associated with that course. This operation should ensure data consistency and integrity, even if multiple updates are performed simultaneously. + + **Implement `updateCourseAndEnrollments` Method**: Define a method to update the course details and enrollments with the required transactional behavior. We use `Propagation.REQUIRED` to ensure that this method participates in any existing transaction or creates a new one if none exists. Setting `Isolation.REPEATABLE_READ` ensures that the data read by this method remains consistent throughout the transaction. Inside this method, we perform a nested transaction by calling the `updateEnrollments` method to update enrollments, ensuring that this operation is atomic and isolated from the outer transaction. + + ```java + @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ) + public void updateCourseAndEnrollments(UUID courseId, String newTitle) { + // Log the start of the update process + logAction("Update Course and Enrollments", "Start"); + + try { + // Implementation to update course details + // ... + + // Nested transaction to update enrollments + updateEnrollments(courseId); + + // Log successful update + logAction("Update Course and Enrollments", "Success"); + } catch (Exception e) { + // Log failure + logAction("Update Course and Enrollments", "Failure: " + e.getMessage()); + throw e; + } + } + ``` + +2. **Updating Enrollments Independently** + + **Scenario**: Certain administrative tasks may require updating enrollments independently of course updates. This operation should maintain data consistency while allowing for separate transactional control. + + **Implement `updateEnrollments` Method**: Define a method to update enrollments for a course with nested transactional behavior. We use `Propagation.NESTED` to indicate that this method is executed within the scope of the outer transaction but can be rolled back independently if needed. Setting `Isolation.REPEATABLE_READ` ensures that the data read by this method remains consistent throughout the transaction. + + ```java + @Transactional(propagation = Propagation.NESTED, isolation = Isolation.REPEATABLE_READ) + public void updateEnrollments(UUID courseId) { + // Log the start of the enrollment update process + logAction("Update Enrollments", "Start"); + + try { + // Implementation to update enrollments + // ... + + // Log successful update + logAction("Update Enrollments", "Success"); + } catch (Exception e) { + // Log failure + logAction("Update Enrollments", "Failure: " + e.getMessage()); + throw e; + } + } + ``` + +--- + +# [NEXT: Tasks](../../lab-work.md) \ No newline at end of file diff --git a/docs/en/transactions/practice/lessons/transactional-logging.md b/docs/en/transactions/practice/lessons/transactional-logging.md new file mode 100644 index 0000000..31c3719 --- /dev/null +++ b/docs/en/transactions/practice/lessons/transactional-logging.md @@ -0,0 +1,105 @@ +# Lesson 3: Enhancing Transactional Methods with Detailed Logging + +## Goal + +This part aims to integrate detailed logging for each transactional operation, ensuring actions are logged with their outcomes. + +## Steps + +1. **Implementing the Logging Method** + + **Scenario**: Before enhancing transactional methods with logging, we need to implement a method to handle logging independently of the main transaction. This ensures that logging occurs reliably, regardless of the outcome of the main transaction. + + **Implement `logAction` Method**: Create a method to log actions independently, ensuring accurate tracking of transaction outcomes. We use `Propagation.REQUIRES_NEW` to execute the logging operation in a separate transaction, making it independent of any ongoing transactions and guaranteeing its completion even if the main transaction fails. + + ```java + @Transactional(propagation = Propagation.REQUIRES_NEW) + public void logAction(String action, String outcome) { + Log log = new Log(action, outcome, LocalDateTime.now()); + logRepository.save(log); + } + ``` + +2. **Logging Enrollment of a Student in a Course** + + **Scenario**: As a university administrator, you need to log the enrollment of a student in a course to keep track of successful enrollments and any potential failures. + + **Enhance `enrollStudentInCourse` Method**: Modify the method to log the action's success or failure. + + ```java + @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.SERIALIZABLE) + public void enrollStudentInCourse(UUID studentId, UUID courseId) { + // Log the start of the enrollment process + logAction("Enroll Student", "Start"); + + try { + // Implementation to enroll the student in the course + // ... + + // Log successful enrollment + logAction("Enroll Student", "Success"); + } catch (Exception e) { + // Log failure + logAction("Enroll Student", "Failure: " + e.getMessage()); + throw e; + } + } + ``` + +3. **Logging Retrieval of Students for a Course** + + **Scenario**: To maintain an audit trail of course-related activities, you need to log the retrieval of students for a course and ensure that the logging occurs even in case of exceptions. + + **Enhance `getStudentsForCourse` Method**: Modify the method to log the action's success or failure. + + ```java + @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED) + public List getStudentsForCourse(UUID courseId) { + // Log the start of retrieving students for the course + logAction("Retrieve Students for Course", "Start"); + + try { + // Implementation to retrieve students for the course + // ... + + // Log successful retrieval + logAction("Retrieve Students for Course", "Success"); + return students; + } catch (Exception e) { + // Log failure + logAction("Retrieve Students for Course", "Failure: " + e.getMessage()); + throw e; + } + } + ``` + +4. **Logging Addition of a New Course** + + **Scenario**: When adding a new course, it's essential to log the outcome of the operation to track the success or failure of the addition. + + **Enhance `addNewCourse` Method**: Modify the method to log the action's success or failure. + + ```java + @Transactional(propagation = Propagation.NOT_SUPPORTED) + public Course addNewCourse(String title) { + // Log the start of adding a new course + logAction("Add New Course", "Start"); + + try { + // Implementation to add a new course + // ... + + // Log successful addition + logAction("Add New Course", "Success"); + return savedCourse; + } catch (Exception e) { + // Log failure + logAction("Add New Course", "Failure: " + e.getMessage()); + throw e; + } + } + ``` + +--- + +# [NEXT: Implementing Nested Transactions and Non-Transactional Operations](nested-and-non-transactional-operations.md) diff --git a/docs/ru/jmeter/lab-work.md b/docs/ru/jmeter/lab-work.md new file mode 100644 index 0000000..ebc73c5 --- /dev/null +++ b/docs/ru/jmeter/lab-work.md @@ -0,0 +1,28 @@ +[English](../../en/jmeter/lab-work.md) | [中文](../../cn/jmeter/lab-work.md) | Русский + + +# Практические задания лабораторной работы по JMeter + +Добро пожаловать в лабораторную работу по JMeter! Цель этой серии задач - помочь вам практиковаться и освоить JMeter, полезный инструмент для тестирования и измерения производительности веб-приложений. Независимо от того, являетесь ли вы начинающим или хотите улучшить свои навыки, эти практические задания помогут вам ознакомиться с различными аспектами использования JMeter для нагрузочного тестирования, записи и анализа HTTP-запросов. + +## Цель лабораторной работы + +Основная цель этой лабораторной работы - предоставить вам практический опыт и мастерство в использовании JMeter для тестирования производительности. JMeter широко используется для теста веб-приложений и сервисов, и благодаря этим задачам вы получите ценные знания о его настройке, написании сценариев, записи и анализе функций. + +## Практические задания + +- [Урок 1: Введение в JMeter и базовая настройка](lessons/introduction-to-jmeter-and-basic-setup.md) +- [Урок 2: Настройка записи тестовых сценариев HTTP(S)](lessons/setting-up-http-test-script-recorder.md) +- [Урок 3: Настройка и использование прокси-сервера](lessons/configuring-and-using-the-proxy-server.md) +- [Урок 4: Настройка браузера для использования прокси-сервера](lessons/configuring-browser-to-use-the-proxy-server.md) +- [Урок 5: Запись и управление HTTP-запросами](lessons/recording-and-managing-http-requests.md) +- [Урок 6: Организация записанных запросов](lessons/organizing-recorded-requests.md) +- [Урок 7: Создание тестового сценария](lessons/creating-a-test-scenario.md) +- [Урок 8: Параметризация HTTP-запросов](lessons/parameterizing-http-requests.md) +- [Урок 9: Добавление слушателей и запуск тестов](lessons/adding-listeners-and-running-tests.md) +- [Урок 10: Выполнение нагрузочного тестирования](lessons/executing-load-testing.md) +- [Урок 11: Анализ результатов тестирования](lessons/analyzing-test-results.md) + +## Задания лабораторной работы + +idk :D \ No newline at end of file diff --git a/docs/ru/jmeter/lessons/adding-listeners-and-running-tests.md b/docs/ru/jmeter/lessons/adding-listeners-and-running-tests.md new file mode 100644 index 0000000..47a3283 --- /dev/null +++ b/docs/ru/jmeter/lessons/adding-listeners-and-running-tests.md @@ -0,0 +1,28 @@ +## Урок 9: Добавление слушателей и запуск тестов + +### Цель +Цель этого урока - добавить слушателей для просмотра результатов теста и запустить сценарии тестирования в JMeter. + +### Шаги + +#### 9.1. Добавление слушателя +1. **Дерево результатов просмотра** + - Щелкните правой кнопкой мыши на **Группе потоков**. + - Выберите **Добавить > Слушатель > Дерево результатов просмотра**. + +#### 9.2. Сохранение плана тестирования +1. **Сохранение** + - Щелкните на узле **План тестирования**. + - Перейдите в **Файл > Сохранить план тестирования как**. + - Выберите местоположение, введите имя файла и сохраните план тестирования. + +#### 9.3. Запуск сценария тестирования +1. **Выполнение** + - Нажмите **Запуск > Старт**, чтобы начать тест. +
![run-test-scenraio-button.png](../../../srcs/jmeter/run-test-scenraio-button.png) + - Просматривайте результаты в слушателе **Дерево результатов просмотра**. + - Убедитесь, что в результатах теста нет ошибок. + +--- + +# [Далее: Выполнение нагрузочного тестирования](executing-load-testing.md) \ No newline at end of file diff --git a/docs/ru/jmeter/lessons/analyzing-test-results.md b/docs/ru/jmeter/lessons/analyzing-test-results.md new file mode 100644 index 0000000..70957d5 --- /dev/null +++ b/docs/ru/jmeter/lessons/analyzing-test-results.md @@ -0,0 +1,19 @@ +## Урок 11: Анализ результатов тестирования + +### Цель +Цель этого урока - проанализировать результаты тестирования с использованием электронных таблиц и подготовиться к последующим запускам тестов в JMeter. + +### Шаги + +#### 11.1. Использование электронных таблиц +1. **Экспорт и анализ данных** + - Экспортируйте результаты из слушателя **Сводный отчет** в файл CSV. + - Используйте приложение для электронных таблиц (например, Excel) для анализа средних времен ответа и других метрик. + +#### 11.2. Очистка статистики перед последующими запусками +1. **Очистка данных** + - Перед запуском нового теста очистите предыдущие результаты, выбрав **Запуск > Очистить все**. + +--- + +# [Далее: Задания](../lab-work.md) \ No newline at end of file diff --git a/docs/ru/jmeter/lessons/configuring-and-using-the-proxy-server.md b/docs/ru/jmeter/lessons/configuring-and-using-the-proxy-server.md new file mode 100644 index 0000000..87d96a8 --- /dev/null +++ b/docs/ru/jmeter/lessons/configuring-and-using-the-proxy-server.md @@ -0,0 +1,21 @@ +## Урок 3: Настройка и использование прокси-сервера + +### Цель +Цель этого урока - настроить прокси-сервер в JMeter и продемонстрировать, как его использовать для записи HTTP(S) запросов. + +### Шаги + +#### 3.1. Настройка прокси-сервера +1. **Настройка порта и шаблонов URL** + - В окне **HTTP(S) Test Script Recorder** установите значение поля **Порт** на `9090`. + - В разделе **Шаблоны URL для исключения** нажмите **Добавить** и введите шаблоны, такие как `.*\.gif`, `.*\.js` и `.*\.css`. +
![setting-port-and-url-pattern.png](../../../srcs/jmeter/setting-port-and-url-pattern.png) + +#### 3.2. Запуск прокси-сервера +1. **Начало записи** + - Нажмите кнопку **Старт** в нижней части окна **HTTP(S) Test Script Recorder**. +
![start-recording-button.png](../../../srcs/jmeter/start-recording-button.png) + +--- + +# [Далее: Настройка браузера для использования прокси-сервера](configuring-browser-to-use-the-proxy-server.md) \ No newline at end of file diff --git a/docs/ru/jmeter/lessons/configuring-browser-to-use-the-proxy-server.md b/docs/ru/jmeter/lessons/configuring-browser-to-use-the-proxy-server.md new file mode 100644 index 0000000..979ff73 --- /dev/null +++ b/docs/ru/jmeter/lessons/configuring-browser-to-use-the-proxy-server.md @@ -0,0 +1,16 @@ +## Урок 4: Настройка браузера для использования прокси-сервера + +### Цель +Цель этого урока - настроить ваш браузер для использования настроенного в JMeter прокси-сервера для записи HTTP(S) запросов. + +### Шаги + +#### 4.1. Настройка параметров браузера +1. **Настройка прокси в браузере** + - Откройте настройки вашего браузера и перейдите к настройкам прокси. + - Установите адрес прокси-сервера на `localhost`, а порт на `9090`. + - Сохраните настройки и, при необходимости, перезапустите браузер. + +--- + +# [Далее: Запись и управление HTTP-запросами](recording-and-managing-http-requests.md) \ No newline at end of file diff --git a/docs/ru/jmeter/lessons/creating-a-test-scenario.md b/docs/ru/jmeter/lessons/creating-a-test-scenario.md new file mode 100644 index 0000000..91cb5f8 --- /dev/null +++ b/docs/ru/jmeter/lessons/creating-a-test-scenario.md @@ -0,0 +1,31 @@ +## Урок 7: Создание тестового сценария + +### Цель +Цель этого урока - создать тестовый сценарий, организовав записанные запросы и добавив извлечение динамических значений в JMeter. + +### Шаги + +#### 7.1. Добавление простого контроллера +1. **Организация запросов** + - Щелкните правой кнопкой мыши по **Группе потоков**. +
![thread-group-icon.png](../../../srcs/jmeter/thread-group-icon.png) + - Выберите **Добавить > Логический контроллер > Простой контроллер**. +
![new-simple-controller-button.png](../../../srcs/jmeter/new-simple-controller-button.png) + - Переименуйте Простой контроллер в соответствии с функцией, которую вы тестируете. + - Перетащите все записанные HTTP-запросы из **Контроллера записи** в **Простой контроллер**. + +#### 7.2. Добавление извлекателя регулярного выражения +1. **Извлечение динамического значения** + - Щелкните правой кнопкой мыши на HTTP-запросе, который требует динамического значения (например, `javax.faces.ViewState`). + - Выберите **Добавить > Постпроцессоры > Извлечение регулярного выражения**. +
![new-regular-expression-button.png](../../../srcs/jmeter/new-regular-expression-button.png) + - Настройте извлекатель: + - **Имя ссылки:** `jsfViewState` + - **Регулярное выражение:** ` + - **Шаблон:** `$1$` + - **Номер совпадения:** `0` +
![regular-expression-extractor-fields.png](../../../srcs/jmeter/regular-expression-extractor-fields.png) + +--- + +# [Далее: Параметризация HTTP-запросов](parameterizing-http-requests.md) \ No newline at end of file diff --git a/docs/ru/jmeter/lessons/executing-load-testing.md b/docs/ru/jmeter/lessons/executing-load-testing.md new file mode 100644 index 0000000..9714257 --- /dev/null +++ b/docs/ru/jmeter/lessons/executing-load-testing.md @@ -0,0 +1,26 @@ +## Урок 10: Выполнение нагрузочного тестирования + +### Цель +Цель этого урока - настроить и выполнить нагрузочное тестирование в JMeter. + +### Шаги + +#### 10.1. Настройка параметров потока +1. **Настройка нагрузочного тестирования** + - Щелкните на **Группе потоков**. + - Установите **Количество потоков** (пользователей), **Период нарастания** (в секундах) и **Количество повторов** по необходимости для вашего нагрузочного теста. + +#### 10.2. Добавление слушателя агрегированного отчета +1. **Сводный отчет** + - Щелкните правой кнопкой мыши на **Простом контроллере**. + - Выберите **Добавить > Слушатель > Агрегированный отчет**. + - Отключите слушателя **Дерево результатов просмотра**, чтобы улучшить производительность во время нагрузочного тестирования. + +#### 10.3. Запуск нагрузочного теста +1. **Выполнение** + - Нажмите **Запуск > Старт**, чтобы начать нагрузочное тестирование. + - Просматривайте сводные результаты в слушателе **Агрегированный отчет**. + +--- + +# [Далее: Анализ результатов тестирования](analyzing-test-results.md) \ No newline at end of file diff --git a/docs/ru/jmeter/lessons/introduction-to-jmeter-and-basic-setup.md b/docs/ru/jmeter/lessons/introduction-to-jmeter-and-basic-setup.md new file mode 100644 index 0000000..969a924 --- /dev/null +++ b/docs/ru/jmeter/lessons/introduction-to-jmeter-and-basic-setup.md @@ -0,0 +1,24 @@ +## Урок 1: Введение в JMeter и базовая настройка + +### Цель +Цель этого урока - познакомить вас с JMeter и провести через процесс базовой настройки, включая запуск JMeter и добавление группы потоков в ваш план тестирования. + +### Шаги + +#### 1.1. Запуск JMeter +![jmeter-site.png](../../../srcs/jmeter/site.png) +1. **Загрузка и установка JMeter** + - Посетите [официальный веб-сайт JMeter](https://jmeter.apache.org/download_jmeter.cgi) и загрузите последнюю версию. + - Распакуйте скачанный архив. + - Перейдите в каталог `bin` и запустите JMeter, запустив файл `jmeter.bat` (Windows) или `jmeter.sh` (macOS/Linux). + +#### 1.2. Добавление группы потоков +![interface.png](../../../srcs/jmeter/interface.png) +1. **Создание плана тестирования** + - Откройте JMeter. + - Щелкните правой кнопкой мыши на узле **План тестирования**. +
![test-plan.png](../../../srcs/jmeter/test-plan.png) + - Выберите **Добавить > Потоки (Пользователи) > Группа потоков**. +
![test-plan.png](../../../srcs/jmeter/thread-group.png) +--- +# [Далее: Настройка HTTP Test Script Recorder](setting-up-http-test-script-recorder.md) \ No newline at end of file diff --git a/docs/ru/jmeter/lessons/organizing-recorded-requests.md b/docs/ru/jmeter/lessons/organizing-recorded-requests.md new file mode 100644 index 0000000..2885a3e --- /dev/null +++ b/docs/ru/jmeter/lessons/organizing-recorded-requests.md @@ -0,0 +1,22 @@ +## Урок 6: Организация записанных запросов + +### Цель +Цель этого урока - организовать записанные HTTP-запросы в JMeter для лучшего управления и выполнения тестов. + +### Шаги + +#### 6.1. Отключение Контроллера записи +1. **Отключение** + - Щелкните правой кнопкой мыши на **Контроллере записи** в JMeter. +
![recording-controller-button.png](../../../srcs/jmeter/recording-controller-button.png) + - Выберите **Отключить**, чтобы прекратить захват дальнейших запросов. +
![disable-element.png](../../../srcs/jmeter/disable-element.png) +#### 6.2. Добавление Менеджера HTTP Cookie +1. **Управление сессией** + - Щелкните правой кнопкой мыши на **Группе потоков**. +
![thread-group-icon.png](../../../srcs/jmeter/thread-group-icon.png) + - Выберите **Добавить > Элемент конфигурации > Менеджер HTTP Cookie**. +
![new-http-cookie-manager-button.png](../../../srcs/jmeter/new-http-cookie-manager-button.png) +--- + +# [Далее: Создание тестового сценария](creating-a-test-scenario.md) \ No newline at end of file diff --git a/docs/ru/jmeter/lessons/parameterizing-http-requests.md b/docs/ru/jmeter/lessons/parameterizing-http-requests.md new file mode 100644 index 0000000..96898dc --- /dev/null +++ b/docs/ru/jmeter/lessons/parameterizing-http-requests.md @@ -0,0 +1,15 @@ +## Урок 8: Параметризация HTTP-запросов + +### Цель +Цель этого урока - параметризовать HTTP-запросы в JMeter с использованием извлеченных динамических значений. + +### Шаги + +#### 8.1. Изменение HTTP-запросов +1. **Использование извлеченных значений** + - В каждом HTTP-запросе, который использует параметр `javax.faces.ViewState`, замените значение на `${jsfViewState}`. + - Убедитесь, что флажок **Кодировать** выбран при необходимости. + +--- + +# [Далее: Добавление слушателей и запуск тестов](adding-listeners-and-running-tests.md) \ No newline at end of file diff --git a/docs/ru/jmeter/lessons/recording-and-managing-http-requests.md b/docs/ru/jmeter/lessons/recording-and-managing-http-requests.md new file mode 100644 index 0000000..533146c --- /dev/null +++ b/docs/ru/jmeter/lessons/recording-and-managing-http-requests.md @@ -0,0 +1,20 @@ +## Урок 5: Запись и управление HTTP-запросами + +### Цель +Цель этого урока - записать HTTP-запросы, сделанные при навигации по веб-приложению, и управлять записанными запросами в JMeter. + +### Шаги + +#### 5.1. Запись HTTP-запросов +1. **Навигация по приложению** + - Перейдите по вашему веб-приложению так, как вы это обычно делаете. JMeter будет записывать HTTP-запросы. + +#### 5.2. Остановка записи +1. **Остановка прокси-сервера** + - Вернитесь в JMeter и нажмите кнопку **Стоп** в окне **HTTP(S) Test Script Recorder**. +
![stop-recording-button.png](../../../srcs/jmeter/stop-recording-button.png) + - Отключите настройки прокси в вашем браузере, чтобы вернуться к прямому доступу в Интернет. + +--- + +# [Далее: Организация записанных запросов](organizing-recorded-requests.md) \ No newline at end of file diff --git a/docs/ru/jmeter/lessons/setting-up-http-test-script-recorder.md b/docs/ru/jmeter/lessons/setting-up-http-test-script-recorder.md new file mode 100644 index 0000000..52f5718 --- /dev/null +++ b/docs/ru/jmeter/lessons/setting-up-http-test-script-recorder.md @@ -0,0 +1,26 @@ +## Урок 2: Настройка HTTP(S) Test Script Recorder + +### Цель +Цель этого урока - рассказать вам, как настроить HTTP(S) Test Script Recorder в JMeter, включая добавление Контроллера записи и настройку Прокси-сервера. + +### Шаги + +#### 2.1. Добавление Контроллера записи +1. **Добавление в Группу потоков** + - Щелкните правой кнопкой мыши на **Группе потоков**. +
![thread-group-icon.png](../../../srcs/jmeter/thread-group-icon.png) + + - Выберите **Добавить > Логический контроллер > Контроллер записи**. +
![recording-controller-button.png](../../../srcs/jmeter/recording-controller-button.png) + +#### 2.2. Добавление Прокси-сервера +1. **Настройка прокси** + - Щелкните правой кнопкой мыши на узле **Рабочая область**. +
![test-plan.png](../../../srcs/jmeter/test-plan.png) + + - Выберите **Добавить > Элементы, не относящиеся к тестированию > HTTP(S) Test Script Recorder**. +
![test-script-recorder.png](../../../srcs/jmeter/test-script-recorder.png) + +--- + +# [Далее: Настройка и использование прокси-сервера](configuring-and-using-the-proxy-server.md) diff --git a/docs/ru/jpa/lab-work.md b/docs/ru/jpa/lab-work.md new file mode 100644 index 0000000..14ec71b --- /dev/null +++ b/docs/ru/jpa/lab-work.md @@ -0,0 +1,56 @@ +[English](../../en/jmeter/lab-work.md) | [中文](../../cn/jmeter/lab-work.md) | Русский + +# Лабораторная работа: JPA (Java Persistence API) + +Добро пожаловать на лабораторную работу по Spring Boot с JPA! В этой лабораторной работе вы попрактикуетесь в различных задачах, связанных с настройкой проекта Spring Boot с JPA (Java Persistence API). + +## Цель лабораторной работы + +Цель этой лабораторной работы - предоставить практический опыт работы с основными концепциями и задачами, связанными с работой с Spring Boot и JPA. Завершив практические задачи, вы приобретете навыки настройки зависимостей, определения характеристик сущностей, управления отношениями между сущностями и взаимодействия с базой данных с использованием JpaRepository. + +## Задачи практики + +1. **Настройка зависимостей базы данных** + - [Настройка драйвера базы данных](practice/dependencies/driver.md) + - [Зависимости Spring Boot и JPA](practice/dependencies/jpa.md) + +2. **Создание сущностей, определение характеристик, отношений и стратегий извлечения данных** + - [Создание сущности](practice/creation/create-entity.md) + - [Определение характеристик сущности](practice/creation/characteristics.md) + - [Управление отношениями](practice/creation/relationships.md) + - [Стратегии извлечения](practice/creation/fetching.md) + +3. **Взаимодействие с пользовательским репозиторием** + - [Создание записи](practice/interacting/repository/create.md) + - [Чтение записи](practice/interacting/repository/read.md) + - [Обновление записи](practice/interacting/repository/update.md) + - [Удаление записи](practice/interacting/repository/delete.md) + - [Пользовательские запросы](practice/interacting/repository/query.md) + +4. **Взаимодействие с репозиторием JPA** + - [Создание записи](practice/interacting/jpa-repository/create.md) + - [Чтение записи](practice/interacting/jpa-repository/read.md) + - [Удаление записи](practice/interacting/jpa-repository/delete.md) + - [Пользовательские запросы](practice/interacting/jpa-repository/query.md) + + +## Задачи лабораторной работы + +1. Настройте зависимости базы данных для PostgreSQL, MySQL, Oracle и Microsoft SQL Server. + +2. Реализуйте следующую схему сущностей и отношений: + ![img.png](../../srcs/jpa/task-er-diagram.png) + + 1. Определите характеристики сущностей для сущностей Student, Enrollment и Course на основе диаграммы сущностей и отношений. + + 2. Создайте классы сущностей для Student, Enrollment и Course в соответствии с определенными характеристиками. + + 3. Реализуйте стратегии извлечения для эффективного извлечения данных для оптимизации взаимодействия с базой данных. + + 4. Управляйте отношениями между сущностями, такими как Student, Enrollment и Course, установив соответствующие ассоциации и отображения. + + 5. Взаимодействуйте с базой данных, создав методы для операций CRUD с использованием слоя Repository и EntityManager как минимум в двух репозиториях. + + 6. Взаимодействуйте с базой данных, создав методы для операций CRUD с использованием JpaRepository как минимум в двух репозиториях. + + 7. Реализуйте пользовательские запросы для выполнения расширенных операций извлечения и манипулирования данными, необходимых для бизнес-логики приложения. diff --git a/docs/ru/jpa/practice/creation/characteristics.md b/docs/ru/jpa/practice/creation/characteristics.md new file mode 100644 index 0000000..0410195 --- /dev/null +++ b/docs/ru/jpa/practice/creation/characteristics.md @@ -0,0 +1,109 @@ +# Определение Характеристик Сущностей + +## Введение + +Это руководство фокусируется на определении колонок или характеристик сущностей в проекте Spring Boot с использованием JPA (Java Persistence API). + +## Цель + +Цель этого руководства - предоставить четкие инструкции по определению характеристик сущностей в проекте Spring Boot с JPA, используя аннотации для обеспечения ограничений и поведения для каждого атрибута. + +## Характеристики Сущностей + +### Характеристики Сущности Student: +- `id` (UUID): Первичный ключ для сущности. +- `name` (String): Имя студента (не должно быть пустым). +- `email` (String): Адрес электронной почты студента (должен быть действительным адресом электронной почты). +- `major` (String): Специализация или направление обучения студента (не должно быть пустым). +- `year` (int): Год обучения студента (не должен быть null). +- `international` (boolean): Указывает, является ли студент международным (не должен быть null). + +### Определение Атрибута `id` + +Добавьте атрибут `id` в класс `Student`. Этот атрибут будет служить первичным ключом для сущности. + +```java +@Id +@GeneratedValue(strategy = GenerationType.AUTO) +private UUID id; +``` + +- `@Id`: Указывает, что это поле является первичным ключом для сущности. +- `@GeneratedValue`: Указывает стратегию автоматической генерации значений первичного ключа. + +### Определение Атрибута `name` + +Добавьте атрибут `name` в класс `Student`. Этот атрибут представляет имя студента и не должен быть пустым. + +```java +@NotBlank +private String name; +``` + +- `@NotBlank`: Обеспечивает, что значение `name` не является null и содержит хотя бы один непробельный символ. + +### Определение Атрибута `email` + +Добавьте атрибут `email` в класс `Student`. Этот атрибут представляет адрес электронной почты студента и должен быть действительным адресом электронной почты. + +```java +@NotBlank +@Email +private String email; +``` + +- `@Email`: Проверяет, что значение `email` является действительным адресом электронной почты. + +### Определение Атрибута `major` + +Добавьте атрибут `major` в класс `Student`. Этот атрибут представляет специализацию или направление обучения студента и не должен быть пустым. + +```java +@NotBlank +private String major; +``` + +- `@NotBlank`: Обеспечивает, что значение `major` не является null и содержит хотя бы один непробельный символ. + +### Определение Атрибута `year` + +Добавьте атрибут `year` в класс `Student`. Этот атрибут представляет год обучения студента и не должен быть null. + +```java +@NotNull +private int year; +``` + +- `@NotNull`: Обеспечивает, что значение `year` не является null. + +### Определение Атрибута `international` + +Добавьте атрибут `international` в класс `Student`. Этот атрибут указывает, является ли студент международным, и не должен быть null. + +```java +@NotNull +private boolean international; +``` + +- `@NotNull`: Обеспечивает, что значение `international` не является null. + + +Вы можете повторить предыдущие шаги для создания характеристик сущностей для сущностей `Course` и `Enrollment`, обеспечив правильное применение аннотаций для каждого атрибута. + +### Характеристики Сущности Enrollment: + +- `id` (UUID): Первичный ключ для сущности. +- `enrollmentDate` (Date): Дата записи на курс. +- `grade` (int): Оценка, полученная за курс. + +### Характеристики Сущности Course: + +- `id` (UUID): Первичный ключ для сущности. +- `name` (String): Название курса. +- `instructor` (String): Имя преподавателя курса. +- `schedule` (String): Детали расписания курса. +- `capacity` (int): Максимальная вместимость курса. +- `online` (boolean): Указывает, является ли курс онлайн. +- `startDate` (Date): Дата начала курса. + +--- diff --git a/docs/ru/jpa/practice/creation/create-entity.md b/docs/ru/jpa/practice/creation/create-entity.md new file mode 100644 index 0000000..5183fd3 --- /dev/null +++ b/docs/ru/jpa/practice/creation/create-entity.md @@ -0,0 +1,60 @@ +# Создание Сущностей + +## Введение + +Это руководство сосредотачивается на создании сущностей в проекте Spring Boot с использованием JPA (Java Persistence API). Оно предоставляет пошаговые инструкции по настройке структуры каталогов и созданию классов сущностей. + +## Цель + +Цель этого руководства - продемонстрировать, как создавать классы сущностей в проекте Spring Boot, следуя bewt-практикам и используя JPA для сохранения данных. + +## Структура Каталогов + +Для обеспечения хорошо организованного проекта важно установить правильную структуру каталогов. Следуйте этим рекомендациям: + +``` +src/ +└── main/ + └── java/ + └── com/ + └── example/ + └── demo/ + └── entity/ + ├── Student.java + ├── Enrollment.java + └── Course.java + +``` + +В этой структуре: +- Каталог `src/main/java` содержит ваши исходные файлы Java. +- Каталог `com/example/demo/entity` - это место, где вы создадите ваши классы сущностей. + +## Создание Классов Сущностей + +Для создания классов сущностей следуйте этим шагам: + +1. Перейдите в каталог `com/example/demo/entity` в вашем проекте. +2. Создайте новый файл Java-класса для каждой сущности. Вы можете повторить следующие шаги для каждой сущности (например, Student, Enrollment, Course). +3. Определите ваш класс сущности с аннотацией `@Entity`. + +### Пример: + +```java +package com.example.demo.entity; + +import javax.persistence.Entity; + +@Entity +public class Student { + +} +``` + +Аннотация `@Entity` указывает, что этот класс является сущностью JPA. + +Повторите вышеуказанные шаги для создания классов сущностей `Enrollment` и `Course`. + +--- + +# [Далее: Определение Характеристик Сущностей](characteristics.md) diff --git a/docs/ru/jpa/practice/creation/fetching.md b/docs/ru/jpa/practice/creation/fetching.md new file mode 100644 index 0000000..8c83af7 --- /dev/null +++ b/docs/ru/jpa/practice/creation/fetching.md @@ -0,0 +1,45 @@ +# Стратегии Извлечения в Spring Boot с JPA: Понимание Ленивой и Агрессивной Загрузки + +## Введение + +Это руководство исследует стратегии извлечения в проекте Spring Boot с использованием JPA (Java Persistence API). Конкретно мы погрузимся в понятия ленивой и агрессивной загрузки и как они применяются в отношениях между сущностями. + +## Цель + +Цель этого руководства - предоставить полное понимание стратегий извлечения в JPA. К концу этого руководства вы поймете, когда использовать ленивую и агрессивную загрузку и как их реализовать в вашем приложении. + +## Стратегии Извлечения + +### Сценарий + +В наших отношениях между сущностями у нас есть отношение Один-ко-Многим между сущностью `Student` и сущностью `Enrollment`. Точно так же, существует отношение Один-ко-Многим между сущностью `Course` и сущностью `Enrollment`. + +#### Сущность Student + +В сущности `Student` у нас есть отношение Один-ко-Многим с сущностью `Enrollment`. У каждого студента может быть несколько записей на курсы. + +Для представления этого отношения мы используем аннотацию `@OneToMany` с `mappedBy = "student"` в сущности `Student`. Здесь у нас есть выбор между стратегиями ленивой и агрессивной загрузки для извлечения связанных записей. + +```java +@OneToMany(mappedBy = "student", fetch = FetchType.EAGER, cascade = CascadeType.ALL) +private List enrollments; +``` + +В этом сценарии мы выбираем агрессивную загрузку (`FetchType.EAGER`). Поскольку мы обычно ожидаем получить доступ ко всем записям студента вместе, агрессивная загрузка гарантирует, что все записи будут извлечены немедленно при загрузке студента. + +#### Сущность Course + +Аналогично, в сущности `Course` у нас также есть отношение Один-ко-Многим с сущностью `Enrollment`. У каждого курса может быть несколько записей на курсы. + +Для представления этого отношения мы используем аннотацию `@OneToMany` с `mappedBy = "course"` в сущности `Course`. Здесь у нас также есть выбор между стратегиями ленивой и агрессивной загрузки для извлечения связанных записей. + +```java +@OneToMany(mappedBy = "course", fetch = FetchType.LAZY, cascade = CascadeType.ALL) +private List enrollments; +``` + +В этом сценарии мы выбираем ленивую загрузку (`FetchType.LAZY`). Поскольку нам не всегда нужно получать доступ ко всем записям курса, ленивая загрузка гарантирует, что записи будут извлечены только при явном запросе. + +--- + +# [Далее: Создание Репозитория](../interacting/repository.md) diff --git a/docs/ru/jpa/practice/creation/relationships.md b/docs/ru/jpa/practice/creation/relationships.md new file mode 100644 index 0000000..9040aab --- /dev/null +++ b/docs/ru/jpa/practice/creation/relationships.md @@ -0,0 +1,44 @@ +# Определение Связей Между Сущностями + +## Введение + +Это руководство посвящено пониманию и реализации связей между сущностями в проекте Spring Boot с использованием JPA (Java Persistence API). Конкретно мы рассмотрим отношение между сущностью `Enrollment` и ее связанными сущностями `Student` и `Course`. + +## Цель + +Цель этого руководства - предоставить четкие инструкции по определению и пониманию связей сущностей в проекте Spring Boot с JPA. К концу этого руководства вы поймете, как установить ассоциации между сущностями и реализовать их в вашем приложении. + +## Связи Между Сущностями + +![img.png](../../../../srcs/jpa/er-diagram.png) +### Характеристики Сущности Enrollment: + +- `id` (UUID): Первичный ключ для сущности. +- `student` (Student): Студент, связанный с записью на курс. +- `course` (Course): Курс, связанный с записью на курс. +- `enrollmentDate` (Date): Дата записи на курс. +- `grade` (int): Оценка, полученная за курс. + +#### Отношение со Студентом + +Отношение между сущностью `Enrollment` и сущностью `Student` представляет собой сценарий, когда студент записывается на курс. Это отношение Многие-к-Одному, где много записей на курс может быть связано с одним студентом. Чтобы установить это отношение, аннотируйте атрибут `student` в сущности `Enrollment` аннотацией `@ManyToOne`. + +```java +@ManyToOne +@JoinColumn(name = "student_id") +private Student student; +``` + +#### Отношение с Курсом + +Аналогично отношение между сущностью `Enrollment` и сущностью `Course` означает сценарий, когда на курс записывается несколько студентов. Это также отношение Многие-к-Одному, где много записей на курс может быть связано с одним курсом. Аннотируйте атрибут `course` в сущности `Enrollment` аннотацией `@ManyToOne`. + +```java +@ManyToOne +@JoinColumn(name = "course_id") +private Course course; +``` + +--- + +# [Далее: Стратегии Извлечения](fetching.md) diff --git a/docs/ru/jpa/practice/dependencies/driver.md b/docs/ru/jpa/practice/dependencies/driver.md new file mode 100644 index 0000000..5867be1 --- /dev/null +++ b/docs/ru/jpa/practice/dependencies/driver.md @@ -0,0 +1,100 @@ +# JPA: Настройка зависимостей + +## Введение + +Это руководство сосредотачивается на настройке зависимостей для проекта Spring Boot с использованием JPA (Java Persistence API). Оно охватывает необходимые шаги по включению драйверов базы данных для различных баз данных, таких как PostgreSQL, MySQL, Oracle, MongoDB и Microsoft SQL Server. Следуя этому руководству, вы настроите все необходимые зависимости для установления соединений с этими базами данных в вашем приложении Spring Boot. + +## Цель + +Цель этого руководства - предоставить четкие инструкции по настройке необходимых зависимостей для Spring Boot и JPA, с особенным акцентом на драйверах баз данных для различных баз данных. + +## Настройка зависимостей + +### Драйверы баз данных + +Для подключения к различным базам данных в вашем приложении Spring Boot включите соответствующие драйверы баз данных. + +#### PostgreSQL + +**Для Gradle:** +```groovy +implementation "org.postgresql:postgresql" +``` + +**Для Maven:** +```xml + + org.postgresql + postgresql + INSERT_VERSION_HERE + +``` + +#### MySQL + +**Для Gradle:** +```groovy +implementation "mysql:mysql-connector-java" +``` + +**Для Maven:** +```xml + + mysql + mysql-connector-java + INSERT_VERSION_HERE + +``` + +#### Драйвер Oracle Database + +**Для Gradle:** +```groovy +implementation 'com.oracle.database.jdbc:ojdbc8' +``` + +**Для Maven:** +```xml + + com.oracle.database.jdbc + ojdbc8 + +``` + +#### Драйвер MongoDB (MongoDB Java Driver) + +**Для Gradle:** +```groovy +implementation 'org.mongodb:mongodb-driver-sync:4.4.3' +``` + +**Для Maven:** +```xml + + org.mongodb + mongodb-driver-sync + 4.4.3 + +``` + +#### Драйвер Microsoft SQL Server JDBC + +**Для Gradle:** +```groovy +implementation 'com.microsoft.sqlserver:mssql-jdbc:9.4.0.jre11' +``` + +**Для Maven:** +```xml + + com.microsoft.sqlserver + mssql-jdbc + 9.4.0.jre11 + +``` + +Эти зависимости облегчают подключение к базам данных. + +--- + +# [Далее: JPA Настройка зависимостей](jpa.md) \ No newline at end of file diff --git a/docs/ru/jpa/practice/dependencies/jpa.md b/docs/ru/jpa/practice/dependencies/jpa.md new file mode 100644 index 0000000..4f68d7a --- /dev/null +++ b/docs/ru/jpa/practice/dependencies/jpa.md @@ -0,0 +1,183 @@ +# Настройка зависимостей JPA + +## Введение + +Это руководство сосредоточено на настройке зависимостей для проекта Spring Boot с использованием JPA (Java Persistence API). Оно охватывает необходимые шаги для включения зависимостей Spring Boot Starter JDBC и Spring Boot Starter Data JPA. + +## Цель + +Цель этого руководства - предоставить четкие инструкции по настройке необходимых зависимостей для Spring Boot и JPA, с акцентом на зависимостях Spring Boot Starter JDBC и Spring Boot Starter Data JPA. + +## Настройка зависимостей + +### Spring Boot Starter JDBC + +Для включения поддержки JDBC в вашем приложении Spring Boot: + +#### Gradle + +```groovy +implementation "org.springframework.boot:spring-boot-starter-jdbc" +``` + +#### Maven + +```xml + + org.springframework.boot + spring-boot-starter-jdbc + +``` + +Эта зависимость обеспечивает автоконфигурацию для доступа к данным на основе JDBC. + +### Spring Boot Starter Data JPA + +Для включения поддержки JPA (Java Persistence API) в вашем приложении Spring Boot: + +#### Gradle + +```groovy +implementation "org.springframework.boot:spring-boot-starter-data-jpa" +``` + +#### Maven + +```xml + + org.springframework.boot + spring-boot-starter-data-jpa + +``` + +Эта зависимость упрощает настройку репозиториев на основе JPA и предоставляет конфигурации по умолчанию для Hibernate. + +### Дополнительная конфигурация для Spring WebMVC + +Если вы используете Spring WebMVC, вам необходимо добавить дополнительную конфигурацию для настройки бинов и свойств, связанных с сохранением состояния. + +#### Создание класса конфигурации Persistence + +Создайте новый класс с именем `PersistenceConfig` в пакете `com.example.config`: + +```java +package com.example.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.persistence.EntityManagerFactory; +import javax.sql.DataSource; + +/** + * Класс конфигурации для настройки бинов и свойств, связанных с сохранением состояния. + * + *

+ * Этот класс настраивает источник данных, фабрику менеджеров сущностей и менеджер транзакций для JPA. + * Он считывает свойства подключения к базе данных из внешнего файла свойств. + *

+ */ +@Configuration +@EnableTransactionManagement +@EnableJpaRepositories(basePackages = "com.example.repository") +@PropertySource({"classpath:application.properties"}) +public class PersistenceConfig { + + @Value("${spring.datasource.driver}") + private String dbDriver; + + @Value("${spring.datasource.url}") + private String dbUrl; + + @Value("${spring.datasource.username}") + private String dbUsername; + + @Value("${spring.datasource.password}") + private String dbPassword; + + @Value("${spring.jpa.properties.hibernate.dialect}") + private String hibernateDialect; + + @Value("${spring.jpa.properties.hibernate.show_sql}") + private boolean hibernateShowSql; + + @Value("${spring.jpa.hibernate.ddl-auto}") + private String hibernateHbm2ddlAuto; + + /** + * Определение бина DataSource. + * + *

+ * Этот метод настраивает источник данных, используя свойства, определенные в файле application.properties. + *

+ * + * @return Бин DataSource + */ + @Bean + public DataSource dataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName(dbDriver); + dataSource.setUrl(dbUrl); + dataSource.setUsername(dbUsername); + dataSource.setPassword(dbPassword); + return dataSource; + } + + /** + * Определение бина EntityManagerFactory. + * + *

+ * Этот метод настраивает фабрику менеджеров сущност + +ей с использованием настроенного источника данных и свойств Hibernate. + *

+ * + * @param dataSource бин источника данных + * @return Бин EntityManagerFactory + */ + @Bean + public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) { + LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); + em.setDataSource(dataSource); + em.setPackagesToScan("com.example.entity"); + + HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); + vendorAdapter.setDatabasePlatform(hibernateDialect); + vendorAdapter.setShowSql(hibernateShowSql); + vendorAdapter.setGenerateDdl("update".equalsIgnoreCase(hibernateHbm2ddlAuto)); + em.setJpaVendorAdapter(vendorAdapter); + + return em; + } + + /** + * Определение бина TransactionManager Spring. + * + *

+ * Этот метод настраивает менеджер транзакций для JPA с использованием настроенной фабрики менеджеров сущностей. + *

+ * + * @param entityManagerFactory бин фабрики менеджеров сущностей + * @return Бин TransactionManager + */ + @Bean + public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { + JpaTransactionManager txManager = new JpaTransactionManager(); + txManager.setEntityManagerFactory(entityManagerFactory); + return txManager; + } +} +``` + +--- + +# [Следующий: Создание сущностей](../creation/create-entity.md) \ No newline at end of file diff --git a/docs/ru/jpa/practice/interacting/jpa-repository.md b/docs/ru/jpa/practice/interacting/jpa-repository.md new file mode 100644 index 0000000..fd57f6f --- /dev/null +++ b/docs/ru/jpa/practice/interacting/jpa-repository.md @@ -0,0 +1,52 @@ +# Создание JpaRepository + +## Введение + +Это руководство демонстрирует, как создать репозиторий для управления сущностями в проекте Spring Boot с использованием JPA (Java Persistence API) с помощью JpaRepository. + +## Цель + +Цель этого руководства - предоставить четкие инструкции по настройке репозитория для управления сущностями в приложении Spring Boot. По окончании этого руководства вы сможете создать классы репозитория и сервиса для сущности `Course`. + +## Структура каталогов + +``` +src/ +└── main/ + └── java/ + └── com/ + └── example/ + └── demo/ + ├── data/ + │ └── entities/ + │ ├── Student.java + │ ├── Enrollment.java + │ └── Course.java + └── repository/ + ├── StudentRepository.java + └── CourseRepository.java + +``` + +## Класс репозитория + +### CourseRepository.java + +```java +package com.yourcompany.yourproject.repository; + +import com.yourcompany.yourproject.model.Course; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface CourseRepository extends JpaRepository { + // Добавьте методы репозитория для сущности курса +} +``` + +Аннотация `@Repository` является аннотацией стереотипа Spring, используемой для указания того, что декорированный класс является компонентом репозитория в слое доступа к данным. Она служит маркером для любого класса, который выполняет роль репозитория, облегчая перевод исключений в едиерное иерархия исключений Spring. + +--- + +# [Далее: Создание записи](jpa-repository/create.md) diff --git a/docs/ru/jpa/practice/interacting/jpa-repository/create.md b/docs/ru/jpa/practice/interacting/jpa-repository/create.md new file mode 100644 index 0000000..eda726e --- /dev/null +++ b/docs/ru/jpa/practice/interacting/jpa-repository/create.md @@ -0,0 +1,38 @@ +# Создание записей в таблице с использованием JpaRepository + +## Введение + +Это руководство демонстрирует, как создавать записи в таблице, используя слой репозитория в приложении Spring Boot с JPA (Java Persistence API) и JpaRepository. + +## Цель + +Цель этого руководства - проиллюстрировать процесс создания записей в таблице путем реализации метода в интерфейсе `CourseRepository` с использованием JpaRepository. + +## Метод репозитория + +### CourseRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Course; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.UUID; + +@Repository +public interface CourseRepository extends JpaRepository { + + Course save(Course course); +} +``` + +### Объяснение + +Метод `save(Course course)`, предоставленный JpaRepository, позволяет нам сохранить новую запись в таблице `Course`. + +Вызывая этот метод и передавая объект `Course` в качестве параметра, JpaRepository автоматически обрабатывает процесс сохранения сущности в базе данных. + +--- + +# [Далее: Чтение записи](read.md) diff --git a/docs/ru/jpa/practice/interacting/jpa-repository/delete.md b/docs/ru/jpa/practice/interacting/jpa-repository/delete.md new file mode 100644 index 0000000..adea12c --- /dev/null +++ b/docs/ru/jpa/practice/interacting/jpa-repository/delete.md @@ -0,0 +1,41 @@ +# Удаление записей из таблицы с использованием JpaRepository + +## Введение + +В этом руководстве показано, как удалять записи из таблицы, используя слой репозитория в приложении Spring Boot с JPA (Java Persistence API) и JpaRepository. + +## Цель + +Цель этого руководства - проиллюстрировать процесс удаления записей из таблицы путем реализации метода в интерфейсе `CourseRepository` с использованием JpaRepository. + +## Метод репозитория + +### CourseRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Course; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.UUID; + +@Repository +public interface CourseRepository extends JpaRepository { + + void deleteById(UUID id); +} +``` + +## Объяснение + +Метод `deleteById(UUID id)` следует соглашению, распознаваемому JpaRepository, для удаления записей на основе их уникального идентификатора. + +- Ключевое слово `delete` указывает, что этот метод используется для удаления данных. +- `ById` указывает критерий для идентификации записи, которую нужно удалить. В данном случае мы нацелены на запись с определенным идентификатором. + +Следуя этому соглашению по именованию, JpaRepository автоматически генерирует соответствующий SQL-запрос для удаления желаемой записи из базы данных. Это упрощает процесс разработки, устраняя необходимость писать явные SQL-запросы на удаление, что позволяет разработчикам сосредоточиться на определении сигнатур методов, отражающих предполагаемые операции удаления данных. + +--- + +# [Далее: Пользовательский запрос](query.md) diff --git a/docs/ru/jpa/practice/interacting/jpa-repository/query.md b/docs/ru/jpa/practice/interacting/jpa-repository/query.md new file mode 100644 index 0000000..5d2c4b5 --- /dev/null +++ b/docs/ru/jpa/practice/interacting/jpa-repository/query.md @@ -0,0 +1,43 @@ +# Пользовательский запрос с использованием JpaRepository + +## Введение + +Это руководство демонстрирует, как реализовать методы пользовательского запроса, используя аннотацию `@Query` в слое репозитория приложения Spring Boot с JPA (Java Persistence API) и JpaRepository. + +## Цель + +Цель этого руководства - проиллюстрировать процесс создания методов пользовательского запроса в интерфейсе репозитория для выполнения определенных операций с базой данных, адаптированных к требованиям приложения. + +## Метод репозитория + +### CourseRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Course; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; +import java.util.List; + +@Repository +public interface CourseRepository extends JpaRepository { + + @Query("SELECT c FROM Course c WHERE c.instructor = :instructor") + List findCoursesByInstructor(@Param("instructor") String instructor); +} +``` + +### Объяснение + +Аннотация `@Query` позволяет нам определять пользовательские запросы JPQL (Java Persistence Query Language) непосредственно в интерфейсе репозитория. + +- `"SELECT c FROM Course c WHERE c.instructor = :instructor"` - это запрос JPQL, который выбирает все курсы, где имя инструктора соответствует предоставленному значению. +- Аннотация `@Param("instructor")` привязывает параметр метода `instructor` к именованному параметру `:instructor` в запросе JPQL. + +Используя `@Query`, мы можем создавать сложные запросы, адаптированные к конкретным потребностям извлечения данных, обеспечивая гибкость и контроль над операциями с базой данных. + +--- + +# [Next: Tasks](../../../lab-work.md) \ No newline at end of file diff --git a/docs/ru/jpa/practice/interacting/jpa-repository/read.md b/docs/ru/jpa/practice/interacting/jpa-repository/read.md new file mode 100644 index 0000000..7cd66e0 --- /dev/null +++ b/docs/ru/jpa/practice/interacting/jpa-repository/read.md @@ -0,0 +1,42 @@ +# Чтение записей из таблицы с использованием JpaRepository + +## Введение + +Это руководство демонстрирует, как извлекать данные из таблицы, используя слой репозитория в приложении Spring Boot с JPA (Java Persistence API) и JpaRepository. + +## Цель + +Цель этого руководства - проиллюстрировать процесс чтения данных из таблицы путем реализации метода в интерфейсе `CourseRepository` с использованием JpaRepository. + +## Метод репозитория + +### CourseRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Course; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.List; + +@Repository +public interface CourseRepository extends JpaRepository { + + List findCoursesByInstructor(String instructor); +} +``` + +### Объяснение + +Сигнатура метода `findCoursesByInstructor(String instructor)` следует определенному соглашению по именованию, распознаваемому Spring Data JPA. + +- Ключевое слово `find` указывает, что этот метод используется для извлечения данных. +- `Courses` представляет тип сущности, который мы хотим извлечь. +- `ByInstructor` указывает критерий для фильтрации результатов. В данном случае мы запрашиваем курсы на основе атрибута `instructor`. + +Следуя этому соглашению по именованию, Spring Data JPA автоматически генерирует соответствующий SQL-запрос за кулисами, чтобы извлечь необходимые данные из базы данных. Это упрощает процесс разработки, устраняя необходимость писать явные SQL-запросы, что позволяет разработчикам сосредоточиться на определении сигнатур методов, отражающих желаемые операции извлечения данных. + +--- + +# [Далее: Удаление записи](delete.md) diff --git a/docs/ru/jpa/practice/interacting/repository.md b/docs/ru/jpa/practice/interacting/repository.md new file mode 100644 index 0000000..16e82e1 --- /dev/null +++ b/docs/ru/jpa/practice/interacting/repository.md @@ -0,0 +1,50 @@ +# Создание репозитория + +## Введение + +Это руководство демонстрирует, как создать репозиторий для управления сущностями в проекте Spring Boot с использованием JPA (Java Persistence API). + +## Цель + +Цель этого руководства - предоставить четкие инструкции по настройке репозитория для управления сущностями в приложении Spring Boot. По окончании этого руководства вы сможете создать репозиторий для сущности `Student`. + +## Структура каталогов + +``` +src/ +└── main/ + └── java/ + └── com/ + └── example/ + └── demo/ + ├── data/ + │ └── entites/ + │ ├── Student.java + │ ├── Enrollment.java + │ └── Course.java + └── repository/ + └── StudentRepository.java + +``` + +## Класс репозитория + +### StudentRepository.java + +```java +package com.yourcompany.yourproject.repository; + +import com.yourcompany.yourproject.model.Student; +import org.springframework.stereotype.Repository; + +@Repository +public class StudentRepository { + // Добавьте методы репозитория для сущности студента +} +``` + +Аннотация `@Repository` является аннотацией стереотипа Spring, используемой для указания того, что декорированный класс является компонентом репозитория в слое доступа к данным. Она служит маркером для любого класса, который выполняет роль репозитория, облегчая перевод исключений в едиерное иерархия исключений Spring. + +--- + +# [Далее: Создание записи](repository/create.md) diff --git a/docs/ru/jpa/practice/interacting/repository/create.md b/docs/ru/jpa/practice/interacting/repository/create.md new file mode 100644 index 0000000..8fbbbf9 --- /dev/null +++ b/docs/ru/jpa/practice/interacting/repository/create.md @@ -0,0 +1,46 @@ +# Создание новых записей в таблице с использованием слоя репозитория + +## Введение + +Это руководство иллюстрирует, как создавать новые записи в таблице, используя слой репозитория в приложении Spring Boot с JPA (Java Persistence API). + +## Цель + +Цель этого руководства - продемонстрировать процесс создания новых записей в таблице с использованием слоя репозитория. Мы достигнем этого, реализовав метод в интерфейсе `StudentRepository`, используя `EntityManager` вместо `JpaRepository`. + +## Метод репозитория + +### StudentRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Student; +import org.springframework.stereotype.Repository; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.transaction.Transactional; + +@Repository +public class StudentRepository { + + @PersistenceContext + private EntityManager entityManager; + + public void saveStudent(Student student) { + entityManager.persist(student); + } +} +``` + +### Объяснение + +- `@Repository`: Эта аннотация помечает класс как компонент репозитория в слое доступа к данным. + +- `@PersistenceContext`: Эта аннотация используется для внедрения экземпляра EntityManager в класс репозитория. + +- `entityManager.persist(student)`: Этот код сохраняет новую сущность `Student` в базе данных. + +--- + +# [Далее: Чтение записи](read.md) diff --git a/docs/ru/jpa/practice/interacting/repository/delete.md b/docs/ru/jpa/practice/interacting/repository/delete.md new file mode 100644 index 0000000..c6ade0d --- /dev/null +++ b/docs/ru/jpa/practice/interacting/repository/delete.md @@ -0,0 +1,47 @@ +# Удаление записей из таблицы с использованием слоя репозитория + +## Введение + +В этом руководстве показано, как удалять записи из таблицы, используя слой репозитория в приложении Spring Boot с JPA (Java Persistence API). + +## Цель + +Цель этого руководства - продемонстрировать процесс удаления записей из таблицы, реализовав метод в интерфейсе `StudentRepository` с использованием `EntityManager`. + +## Метод репозитория + +### StudentRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Student; +import org.springframework.stereotype.Repository; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.transaction.Transactional; + +@Repository +public class StudentRepository { + + @PersistenceContext + private EntityManager entityManager; + + public void deleteStudent(UUID id) { + Student studentToDelete = entityManager.find(Student.class, id); + entityManager.remove(studentToDelete); + } +} +``` + +### Объяснение + +- `@Repository`: Эта аннотация помечает класс как компонент репозитория в слое доступа к данным. + +- `@PersistenceContext`: Эта аннотация используется для внедрения экземпляра EntityManager в класс репозитория. + +- `entityManager.remove(studentToDelete)`: Этот код удаляет сущность `Student` из базы данных. + +--- + +# [Далее: Пользовательский запрос](query.md) diff --git a/docs/ru/jpa/practice/interacting/repository/query.md b/docs/ru/jpa/practice/interacting/repository/query.md new file mode 100644 index 0000000..b25f84d --- /dev/null +++ b/docs/ru/jpa/practice/interacting/repository/query.md @@ -0,0 +1,48 @@ +# Создание пользовательских запросов в таблице с использованием слоя репозитория + +## Введение + +В этом руководстве показано, как создавать пользовательские запросы для извлечения записей из таблицы, используя слой репозитория в приложении Spring Boot с JPA (Java Persistence API). + +## Цель + +Цель этого руководства - проиллюстрировать процесс создания пользовательских запросов для извлечения записей из таблицы, реализовав метод в интерфейсе `StudentRepository` с использованием `EntityManager`. + +## Метод репозитория + +### StudentRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Student; +import org.springframework.stereotype.Repository; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import java.util.List; + +@Repository +public class StudentRepository { + + @PersistenceContext + private EntityManager entityManager; + + public List findStudentsByMajor(String major) { + return entityManager.createQuery("SELECT s FROM Student s WHERE s.major = :major", Student.class) + .setParameter("major", major) + .getResultList(); + } +} +``` + +### Объяснение + +- `@Repository`: Эта аннотация помечает класс как компонент репозитория в слое доступа к данным. + +- `@PersistenceContext`: Эта аннотация используется для внедрения экземпляра EntityManager в класс репозитория. + +- `entityManager.createQuery(...)`: Этот код создает пользовательский запрос на JPQL (Java Persistence Query Language) для извлечения записей на основе предоставленного критерия (`major` в этом примере). + +--- + +# [Далее: Создание JpaRepository](../jpa-repository.md) diff --git a/docs/ru/jpa/practice/interacting/repository/read.md b/docs/ru/jpa/practice/interacting/repository/read.md new file mode 100644 index 0000000..36e6af3 --- /dev/null +++ b/docs/ru/jpa/practice/interacting/repository/read.md @@ -0,0 +1,46 @@ +# Чтение записей из таблицы с использованием слоя репозитория + +## Введение + +В этом руководстве показано, как читать записи из таблицы, используя слой репозитория в приложении Spring Boot с JPA (Java Persistence API). + +## Цель + +Цель этого руководства - проиллюстрировать процесс чтения записей из таблицы, реализовав метод в интерфейсе `StudentRepository` с использованием `EntityManager`. + +## Метод репозитория + +### StudentRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Student; +import org.springframework.stereotype.Repository; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import java.util.UUID; + +@Repository +public class StudentRepository { + + @PersistenceContext + private EntityManager entityManager; + + public Student findStudentById(UUID id) { + return entityManager.find(Student.class, id); + } +} +``` + +### Объяснение + +- `@Repository`: Эта аннотация помечает класс как компонент репозитория в слое доступа к данным. + +- `@PersistenceContext`: Эта аннотация используется для внедрения экземпляра EntityManager в класс репозитория. + +- `entityManager.find(Student.class, id)`: Этот код извлекает сущность `Student` из базы данных на основе предоставленного `id`. + +--- + +# [Далее: Обновление записи](update.md) diff --git a/docs/ru/jpa/practice/interacting/repository/update.md b/docs/ru/jpa/practice/interacting/repository/update.md new file mode 100644 index 0000000..2fe9b31 --- /dev/null +++ b/docs/ru/jpa/practice/interacting/repository/update.md @@ -0,0 +1,46 @@ +# Обновление записей в таблице с использованием слоя репозитория + +## Введение + +Это руководство иллюстрирует, как обновлять записи в таблице с использованием слоя репозитория в приложении Spring Boot с JPA (Java Persistence API). + +## Цель + +Цель этого руководства - продемонстрировать процесс обновления записей в таблице, реализовав метод в интерфейсе `StudentRepository` с использованием `EntityManager`. + +## Метод репозитория + +### StudentRepository.java + +```java +package com.example.demo.repository; + +import com.example.demo.data.entities.Student; +import org.springframework.stereotype.Repository; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.transaction.Transactional; + +@Repository +public class StudentRepository { + + @PersistenceContext + private EntityManager entityManager; + + public Student updateStudent(Student student) { + return entityManager.merge(student); + } +} +``` + +### Объяснение + +- `@Repository`: Эта аннотация помечает класс как компонент репозитория в слое доступа к данным. + +- `@PersistenceContext`: Эта аннотация используется для внедрения экземпляра EntityManager в класс репозитория. + +- `entityManager.merge(student)`: Этот код обновляет сущность `Student` в базе данных. + +--- + +# [Далее: Удаление записи](delete.md) diff --git a/docs/ru/springsecurity/lab-work.md b/docs/ru/springsecurity/lab-work.md new file mode 100644 index 0000000..2166b50 --- /dev/null +++ b/docs/ru/springsecurity/lab-work.md @@ -0,0 +1,62 @@ +[English](../../en/springsecurity/lab-work.md) | [中文](../../cn/springsecurity/lab-work.md) | Русский + +# Лабораторные работы по Spring Security + +Добро пожаловать в лабораторные работы по Spring Security! Цель этой серии задач - помочь вам на практике познакомиться с Spring Security, а также создать почти полноценный проект. Если вы начинающий или просто стремитесь улучшить свои навыки, эти практические задачи помогут вам разобраться в различных аспектах интеграции безопасности в приложение на Spring. + +## Цель лабораторных работ + +Основная цель этих лабораторных работ - предоставить вам практический опыт и уверенность в использовании безопасности в среде Spring. Spring Security широко используется для аутентификации, авторизации и обеспечения безопасности вашего приложения, и через эти задачи вы получите полезные знания о конфигурации, аутентификации, авторизации и многом другом. + +## Задачи практики + +1. [Задача 1: Настройка Spring Security](practice/configure-spring-security.md) +2. [Задача 2: Создание базовой реализации для пользователя](practice/base-implementation-user.md) +3. [Задача 3: Шифрование пароля](practice/password-encryption.md) +4. [Задача 4: Добавление фиктивных пользователей](practice/add-dummy-users.md) +5. [Задача 5: Создание идентификации для пользователей](practice/create-identity-to-users.md) +6. [Задача 6: Создание базы для авторизации на сервере](practice/setup-server-authorization.md) +7. [Задача 7: Авторизация аутентифицированных пользователей](practice/authorize-server-authenticated.md) +8. [Задача 8: Авторизация по ролям](practice/authorize-server-role.md) +9. [Задача 9: Авторизация по полномочиям](practice/authorize-server-authority.md) +10. [Задача 10: Настройка Thymeleaf Security](practice/configure-thymeleaf-security.md) +11. [Задача 11: Авторизация аутентифицированных пользователей](practice/authorize-client-authenticated.md) +12. [Задача 12: Авторизация по ролям](practice/authorize-client-role.md) +13. [Задача 13: Авторизация по полномочиям](practice/authorize-client-authority.md) +14. [Задача 14: Пользовательская форма входа](practice/custom-login-form.md) + +## Задачи лабораторной работы + +![img.png](../../srcs/springsecurity/task.png) + +### Задача 1: Настройка Spring Security +Инициализация Spring Security в вашем проекте. + +### Задача 2: Определение Ролей и Полномочий Пользователей +Определение различных пользовательских ролей (Менеджер, Учитель, Студент) и их соответствующих полномочий. + +### Задача 3: Настройка Безопасности в Контроллерах +Защита путей приложения (endpoins) с использованием контроля доступа на основе ролей. + +#### Детали реализации +**Роль Менеджера**: +- Добавление Нового Учителя (`/teachers/new`) +- Изменение Профиля Учителя (`/teachers/{id}/edit`) +- Изменение Профиля Студента (`/students/{id}/edit`) +- Изменение Оценок Студента (`/students/{id}/marks/edit`) + +**Роль Учителя**: +- Изменение Оценок Студента (`/students/{id}/marks/edit`) +- Добавление Нового Предмета (`/subjects/new`) +- Добавление Нового Теста (`/tests/new`) + +**Роль Студента**: +- Прохождение Теста (`/tests/{id}/take`) +- Просмотр Оценок (`/students/{id}/marks`) + +### Задача 4: Реализация Авторизации в Шаблонах Thymeleaf + +Ограничение доступа к элементам пользовательского интерфейса на основе ролей пользователей. + +### Задача 5: Тестирование Контроля Доступа на Основе Ролей +Убедитесь, что enpoints и элементы пользовательского интерфейса правильно защищены. diff --git a/docs/ru/springsecurity/practice/add-dummy-users.md b/docs/ru/springsecurity/practice/add-dummy-users.md new file mode 100644 index 0000000..d439254 --- /dev/null +++ b/docs/ru/springsecurity/practice/add-dummy-users.md @@ -0,0 +1,68 @@ +# Добавление фиктивных пользователей + +В этом задании описан процесс обновления класса `CustomUserDetailsService` для включения метода добавления фиктивных пользователей в хранилище в памяти, чтобы использовать его в качестве простого демонстрационного примера создания пользователей. + +## Цель + +Обновить класс `CustomUserDetailsService`, чтобы включить метод добавления фиктивных пользователей, позволяющий инициализировать данные пользователей в хранилище в памяти. + +## Шаги + +1. **Обновление класса CustomUserDetailsService:** + + Сначала нам нужно обновить класс `CustomUserDetailsService`, чтобы добавить метод добавления фиктивных пользователей. Мы будем использовать этот метод во время инициализации бина для заполнения хранилища в памяти данными о фиктивных пользователях. + + ```java + @Service + public class CustomUserDetailsService implements UserDetailsService { + + private final UsersRepository usersRepository; + private final PasswordEncoder passwordEncoder; + + @Autowired + public CustomUserDetailsService(UsersRepository usersRepository, PasswordEncoder passwordEncoder) { + this.usersRepository = usersRepository; + this.passwordEncoder = passwordEncoder; + + // Вызываем метод addDummyUsers для добавления фиктивных пользователей во время инициализации бина + addDummyUsers(); + } + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + // Получаем данные пользователя из репозитория + CustomUserDetails userDetails = usersRepository.findByUsername(username); + if (userDetails == null) { + throw new UsernameNotFoundException("Пользователь с именем пользователя не найден: " + username); + } + return userDetails; + } + + // Метод для добавления фиктивных пользователей + private void addDummyUsers() { + // Создаем фиктивных пользователей + CustomUserDetails admin = new CustomUserDetails("admin", passwordEncoder.encode("admin"), true, true, true, true); + CustomUserDetails moderator = new CustomUserDetails("moderator", passwordEncoder.encode("moderator"), true, true, true, true); + CustomUserDetails user = new CustomUserDetails("user", passwordEncoder.encode("user"), true, true, true, true); + + // Добавляем пользователей в репозиторий + usersRepository.save(admin); + usersRepository.save(moderator); + usersRepository.save(user); + } + } + ``` + + В этом обновленном классе: + - Мы добавили конструктор, который принимает `UsersRepository` и `PasswordEncoder` в качестве зависимостей. + - Во время инициализации бина конструктор вызывает метод `addDummyUsers` для заполнения хранилища в памяти фиктивными пользователями. + - Метод `addDummyUsers` создает фиктивных пользователей с захардкоженными именами пользователей и паролями. + - Наконец, фиктивные пользователи сохраняются в репозитории с помощью метода `save`. + +## Заключение + +Поздравляем! Вы успешно добавили фиктивных пользователей для имитации базы данных в вашем приложении с использованием Spring Security. Путем инициализации списка фиктивных пользователей в классе UserRepositoryImpl и заполнения его во время запуска приложения вы теперь можете аутентифицировать и авторизовывать пользователей в вашем приложении. + +--- + +# [СЛЕДУЮЩЕЕ ЗАДАНИЕ: Создание идентификации для пользователей](create-identity-to-users.md) diff --git a/docs/ru/springsecurity/practice/authorize-client-authenticated.md b/docs/ru/springsecurity/practice/authorize-client-authenticated.md new file mode 100644 index 0000000..2fb7c91 --- /dev/null +++ b/docs/ru/springsecurity/practice/authorize-client-authenticated.md @@ -0,0 +1,54 @@ +# Авторизация аутентифицированных пользователей (на клиентской стороне) + +Этот файл описывает процесс авторизации пользователей на основе их статуса аутентификации на клиентской стороне с использованием Thymeleaf. Путем отображения или скрытия элементов в представлении в зависимости от статуса аутентификации пользователя можно контролировать видимость определенных функциональностей или действий. + +## Цель + +Контролировать видимость элементов, связанных с добавлением и удалением студентов, в зависимости от статуса аутентификации пользователя в представлениях Thymeleaf. + +## Шаги + +1. **Обновление шаблонов Thymeleaf:** + + Измените шаблоны Thymeleaf для условного отображения элементов в зависимости от статуса аутентификации пользователя. + + ```html + + + + Управление студентами + + +

Управление студентами

+ + + + + + + + +
+

Добро пожаловать в систему управления студентами. Здесь вы можете управлять записями студентов.

+
+ + + ``` + + В этом шаблоне: + - Используется выражение `th:if="${#authorization.expression('isAuthenticated()')}"`, чтобы условно отображать кнопки "Добавить студента" и "Удалить студента" только если пользователь аутентифицирован. + +## Объяснение + +- **Диалект безопасности Thymeleaf**: Объект `#authorization` является частью диалекта безопасности Thymeleaf, который интегрирует Spring Security с Thymeleaf. +- **Условное отображение**: Атрибут `th:if` используется для условного отображения или скрытия элементов в зависимости от статуса аутентификации пользователя. + +Следуя этим шагам, вы можете контролировать видимость элементов в ваших представлениях Thymeleaf в зависимости от статуса аутентификации пользователя, обеспечивая, что только аутентифицированные пользователи могут видеть и взаимодействовать с определенными функциональностями. + +--- + +# [СЛЕДУЮЩАЯ ЗАДАЧА: Авторизация по ролям](authorize-client-role.md) \ No newline at end of file diff --git a/docs/ru/springsecurity/practice/authorize-client-authority.md b/docs/ru/springsecurity/practice/authorize-client-authority.md new file mode 100644 index 0000000..f4a6842 --- /dev/null +++ b/docs/ru/springsecurity/practice/authorize-client-authority.md @@ -0,0 +1,55 @@ +# Авторизация по авторитету (клиентская сторона) + +Это задание описывает процесс авторизации пользователей на клиентской стороне веб-интерфейса с использованием Thymeleaf. Путем отображения или скрытия элементов на основе авторитетов пользователя вы можете контролировать видимость определенных функций или действий. + +## Цель + +Контроль видимости элементов, связанных с добавлением и удалением студентов, в зависимости от авторитетов пользователя в представлениях Thymeleaf. + +## Шаги + +1. **Обновление шаблонов Thymeleaf:** + + Измените шаблоны Thymeleaf, чтобы условно отображать элементы в зависимости от авторитетов пользователя. + + ```html + + + + Управление студентами + + +

Управление студентами

+ + + + + + + + +
+

Добро пожаловать в систему управления студентами. Здесь вы можете управлять записями студентов.

+
+ + + ``` + + В этом шаблоне: + - Используется оператор `th:if="${#authorization.expression('hasAuthority(''WRITE'')')}"`, чтобы условно отображать кнопку "Добавить студента" только в том случае, если у пользователя есть авторитет `WRITE`. + - Аналогично, оператор `th:if="${#authorization.expression('hasAuthority(''DELETE'')')}"` используется для условного отображения кнопки "Удалить студента" только в том случае, если у пользователя есть авторитет `DELETE`. + +## Объяснение + +- **Диалект безопасности Thymeleaf**: Объект `#authorization` является частью диалекта безопасности Thymeleaf, который интегрирует Spring Security с Thymeleaf. +- **Условное отображение**: Атрибут `th:if` используется для условного отображения или скрытия элементов на основе авторитетов пользователя. + +Следуя этим шагам, вы можете контролировать видимость элементов в ваших представлениях Thymeleaf в зависимости от авторитетов пользователей, гарантируя, что только авторизованные пользователи могут видеть и взаимодействовать с определенными функциями. + +--- + +# [СЛЕДУЮЩЕЕ ЗАДАНИЕ: Пользовательская форма входа](custom-login-form.md) \ No newline at end of file diff --git a/docs/ru/springsecurity/practice/authorize-client-role.md b/docs/ru/springsecurity/practice/authorize-client-role.md new file mode 100644 index 0000000..ca031bb --- /dev/null +++ b/docs/ru/springsecurity/practice/authorize-client-role.md @@ -0,0 +1,55 @@ +# Авторизация по ролям (клиентская сторона) + +Это задание описывает процесс авторизации пользователей на клиентской стороне веб-интерфейса с использованием Thymeleaf. Путем отображения или скрытия элементов на основе ролей пользователя можно контролировать видимость определенных функций или действий. + +## Цель + +Контроль видимости элементов, связанных с добавлением и удалением студентов, в зависимости от ролей пользователя в представлениях Thymeleaf. + +## Шаги + +1. **Обновление шаблонов Thymeleaf:** + + Измените шаблоны Thymeleaf, чтобы условно отображать элементы в зависимости от ролей пользователя. + + ```html + + + + Управление студентами + + +

Управление студентами

+ + + + + + + + +
+

Добро пожаловать в систему управления студентами. Здесь вы можете управлять записями студентов.

+
+ + + ``` + + В этом шаблоне: + - Используется оператор `th:if="${#authorization.expression('hasRole(''ROLE_ADMIN'')')}"`, чтобы условно отображать кнопку "Добавить студента" только в том случае, если у пользователя есть роль `ROLE_ADMIN`. + - Аналогично, оператор `th:if="${#authorization.expression('hasRole(''ROLE_MANAGER'')')}"` используется для условного отображения кнопки "Удалить студента" только в том случае, если у пользователя есть роль `ROLE_MANAGER`. + +## Объяснение + +- **Диалект безопасности Thymeleaf**: Объект `#authorization` является частью диалекта безопасности Thymeleaf, который интегрирует Spring Security с Thymeleaf. +- **Условное отображение**: Атрибут `th:if` используется для условного отображения или скрытия элементов на основе ролей пользователя. + +Следуя этим шагам, вы можете контролировать видимость элементов в ваших представлениях Thymeleaf в зависимости от ролей пользователей, гарантируя, что только авторизованные пользователи могут видеть и взаимодействовать с определенными функциями. + +--- + +# [СЛЕДУЮЩЕЕ ЗАДАНИЕ: Авторизация по авторитету](authorize-client-authority.md) \ No newline at end of file diff --git a/docs/ru/springsecurity/practice/authorize-server-authenticated.md b/docs/ru/springsecurity/practice/authorize-server-authenticated.md new file mode 100644 index 0000000..61c8b67 --- /dev/null +++ b/docs/ru/springsecurity/practice/authorize-server-authenticated.md @@ -0,0 +1,38 @@ +# Авторизация аутентифицированного пользователя + +Это задание описывает процесс авторизации аутентифицированных пользователей в вашем приложении. Путем требования аутентификации для определенных путей или конечных точек вы можете гарантировать, что только вошедшие в систему пользователи могут получить доступ к определенным ресурсам. + +## Цель + +Авторизовать доступ к пути `/second` только для аутентифицированных пользователей, разрешив публичный доступ к другим путям. + +## Шаги + +1. **Обновление конфигурации безопасности:** + + В классе `WebSecurityConfig` измените метод `configure(HttpSecurity http)` так, чтобы доступ к пути `/second` был ограничен только для аутентифицированных пользователей. + + ```java + @Configuration + @EnableWebSecurity + public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests((requests) -> requests + // Другие конечные точки... + .requestMatchers("/second").authenticated() + // Другие конечные точки... + ); + } + } + ``` + + В этой конфигурации: + - Мы используем `.authorizeHttpRequests()`, чтобы определить правила авторизации. + - Заявление `.requestMatchers("/second").authenticated()` указывает, что доступ к пути `/second` должен быть ограничен только для аутентифицированных пользователей. + +--- + +# [СЛЕДУЮЩЕЕ ЗАДАНИЕ: Авторизация по роли](authorize-server-role.md) diff --git a/docs/ru/springsecurity/practice/authorize-server-authority.md b/docs/ru/springsecurity/practice/authorize-server-authority.md new file mode 100644 index 0000000..2040e86 --- /dev/null +++ b/docs/ru/springsecurity/practice/authorize-server-authority.md @@ -0,0 +1,39 @@ +# Авторизация по правам + +В этом задании описывается процесс авторизации пользователей на основе их прав в вашем приложении. Присваивая различные права пользователям, вы можете контролировать доступ к определенным функциональностям или действиям. + +## Цель + +Авторизовать доступ к пути `/addStudent` для пользователей с правами `WRITE` и к пути `/removeStudent` для пользователей с правами `DELETE`. + +## Шаги + +1. **Обновление конфигурации безопасности:** + + В классе `WebSecurityConfig` измените метод `configure(HttpSecurity http)` для определения контроля доступа на основе прав для путей `/addStudent` и `/removeStudent`. + + ```java + @Configuration + @EnableWebSecurity + public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests((requests) -> requests + // Другие конечные точки... + .requestMatchers("/addStudent").hasAuthority("WRITE") + .requestMatchers("/removeStudent").hasAuthority("DELETE") + // Другие конечные точки... + ); + } + } + ``` + + В этой конфигурации: + - Заявление `.requestMatchers("/addStudent").hasAuthority("WRITE")` указывает, что доступ к пути `/addStudent` должен быть ограничен для пользователей с правами `WRITE`. + - Аналогично, `.requestMatchers("/removeStudent").hasAuthority("DELETE")` ограничивает доступ к пути `/removeStudent` для пользователей с правами `DELETE`. + +--- + +# [СЛЕДУЮЩЕЕ ЗАДАНИЕ: Настройка безопасности Thymeleaf](configure-thymeleaf-security.md) diff --git a/docs/ru/springsecurity/practice/authorize-server-role.md b/docs/ru/springsecurity/practice/authorize-server-role.md new file mode 100644 index 0000000..ce374bc --- /dev/null +++ b/docs/ru/springsecurity/practice/authorize-server-role.md @@ -0,0 +1,39 @@ +# Авторизация по ролям + +Это задание описывает процесс авторизации пользователей на основе их ролей в вашем приложении. Присваивая различные роли пользователям, вы можете контролировать доступ к определенным ресурсам или функциональностям. + +## Цель + +Авторизовать доступ к пути `/third` для пользователей с ролью `ROLE_MODERATOR` и к пути `/fourth` для пользователей с ролью `ROLE_ADMIN`. + +## Шаги + +1. **Обновление конфигурации безопасности:** + + В классе `WebSecurityConfig` измените метод `configure(HttpSecurity http)` для определения контроля доступа на основе ролей для путей `/third` и `/fourth`. + + ```java + @Configuration + @EnableWebSecurity + public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests((requests) -> requests + // Другие конечные точки... + .requestMatchers("/third").hasAuthority("ROLE_MODERATOR") + .requestMatchers("/fourth").hasAuthority("ROLE_ADMIN") + // Другие конечные точки... + ); + } + } + ``` + + В этой конфигурации: + - Заявление `.requestMatchers("/third").hasAuthority("ROLE_MODERATOR")` указывает, что доступ к пути `/third` должен быть ограничен для пользователей с авторитетом `ROLE_MODERATOR`. + - Аналогично, `.requestMatchers("/fourth").hasAuthority("ROLE_ADMIN")` ограничивает доступ к пути `/fourth` для пользователей с авторитетом `ROLE_ADMIN`. + +--- + +# [СЛЕДУЮЩЕЕ ЗАДАНИЕ: Авторизация по полномочию](authorize-server-authority.md) \ No newline at end of file diff --git a/docs/ru/springsecurity/practice/base-implementation-user.md b/docs/ru/springsecurity/practice/base-implementation-user.md new file mode 100644 index 0000000..694a173 --- /dev/null +++ b/docs/ru/springsecurity/practice/base-implementation-user.md @@ -0,0 +1,186 @@ +# Создание базовой реализации для управления пользователями + +В этом задании мы сосредоточимся на создании базовой реализации для управления пользователями в вашем приложении. Это включает в себя определение сущности UserDetails, создание репозитория для управления данными пользователей и реализацию UserDetailsService для загрузки деталей пользователей во время аутентификации. + +## Цель + +Цель этого задания - установить надежное основание для управления пользователями в вашем приложении. Реализовав UserDetails, UsersRepository и UserDetailsService, вы сможете аутентифицировать пользователей, управлять их данными и эффективно выполнять операции, связанные с пользователями. + +## Шаги + +1. **Определение сущности UserDetails** + + Начните с определения сущности UserDetails, которая представляет детали пользователя в вашем приложении. Эта сущность должна реализовывать интерфейс UserDetails, предоставляемый Spring Security. + + ```java + package edu.labs.yourproject.model; + + import org.springframework.security.core.GrantedAuthority; + import org.springframework.security.core.userdetails.UserDetails; + + import java.util.Collection; + + public class CustomUserDetails implements UserDetails { + + // Реализуйте методы UserDetails здесь + + } + ``` + + Реализуйте методы, необходимые интерфейсом UserDetails, для предоставления деталей пользователя, таких как имя пользователя, пароль, права доступа и т. д. + +2. **Создание класса UsersRepository** + + Поскольку мы используем хранилище в памяти на данный момент, создадим простой класс UsersRepository для управления данными пользователей. + + a. **Создание класса UsersRepository** + + Создайте новый класс Java с именем `UsersRepository` внутри пакета `edu.labs.yourproject.repository`. + + ```java + package edu.labs.yourproject.repository; + + import org.springframework.stereotype.Repository; + import edu.labs.yourproject.model.CustomUserDetails; + + @Repository + public class UsersRepository { + + private List users = new ArrayList<>(); + + // Добавьте методы для управления пользователями по мере необходимости + } + ``` + + Этот класс будет служить репозиторием для управления данными пользователей. Мы добавим методы для извлечения, добавления, обновления и удаления пользователей в последующих шагах. + + b. **Добавление метода findByUsername** + + Добавьте метод с именем `findByUsername` в класс `UsersRepository`. Этот метод будет извлекать детали пользователя по имени пользователя из репозитория. + + ```java + public CustomUserDetails findByUsername(String username) { + for (CustomUserDetails user : users) { + if (user.getUsername().equals(username)) { + return user; + } + } + return null; // Пользователь не найден + } + ``` + + Метод `findByUsername` используется для извлечения деталей пользователя по имени пользователя из репозитория. В этой заполнительной реализации он возвращает `null`, но вы замените его фактической логикой извлечения деталей пользователя из базы данных или любого другого источника данных. + +3. **Реализация UserDetailsService** + + На этом шаге мы реализуем UserDetailsService для загрузки деталей пользователя во время аутентификации. Этот сервис будет извлекать информацию о пользователе из UsersRepository. + + a. **Создание класса CustomUserDetailsService** + + Начните с создания нового класса с именем `CustomUserDetailsService` в пакете сервиса вашего проекта. Этот класс будет реализовывать интерфейс UserDetailsService, предоставляемый Spring Security. + + ```java + package edu.labs.yourproject.service; + + import org.springframework.beans.factory.annotation.Autowired; + import org.springframework.security.core.userdetails.UserDetails; + import org.springframework.security.core.userdetails.UserDetailsService; + import org.springframework.security.core.userdetails.UsernameNotFoundException; + import org.springframework.stereotype.Service; + import com.yourcompany.yourproject.model.CustomUserDetails; + import com.yourcompany.yourproject.repository.UsersRepository; + + @Service + public class CustomUserDetailsService implements UserDetailsService { + + private final UsersRepository usersRepository; + + @Autowired + public CustomUserDetailsService(UsersRepository usersRepository) { + this.usersRepository = usersRepository; + } + + // Здесь реализуются методы + } + ``` + + Мы создаем класс `CustomUserDetailsService` и проводим инъекцию зависимости `UsersRepository` с помощ + +ью конструктора. + + b. **Переопределение метода loadUserByUsername** + + Переопределите метод `loadUserByUsername`, определенный в интерфейсе UserDetailsService. Этот метод будет извлекать детали пользователя из UsersRepository на основе предоставленного имени пользователя. + + ```java + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + // Извлечение деталей пользователя из репозитория в памяти + CustomUserDetails userDetails = usersRepository.findByUsername(username); + if (userDetails == null) { + throw new UsernameNotFoundException("Пользователь с именем пользователя не найден: " + username); + } + return userDetails; + } + ``` + + Внутри метода `loadUserByUsername` мы вызываем метод `findByUsername` у UsersRepository для извлечения деталей пользователя по имени пользователя. Если пользователь не найден, мы генерируем исключение UsernameNotFoundException. + +4. **Настройка бинов в WebSecurityConfig** + + Откройте класс WebSecurityConfig, расположенный в пакете конфигурации вашего проекта (`edu.labs.yourproject.config`). Внутри этого класса определите бины для CustomUserDetails и UserDetailsRepository. + + ```java + package edu.labs.yourproject.config; + + import edu.labs.yourproject.model.CustomUserDetails; + import edu.labs.yourproject.repository.UserDetailsRepository; + import org.springframework.context.annotation.Bean; + import org.springframework.context.annotation.Configuration; + + @Configuration + @EnableWebSecurity + public class WebSecurityConfig { + + // Весь остальной код здесь... + + @Bean + public CustomUserDetailsService customUserDetailsService() { + // Создание и настройка бина CustomUserDetails + return new CustomUserDetailsService(); + } + + @Bean + public UserDetailsRepository userDetailsRepository() { + // Создание и настройка бина UserDetailsRepository + return new UserDetailsRepository(); + } + } + ``` + + Определите два метода бина: `CustomUserDetailsService()` и `userDetailsRepository()`. Эти методы создают и настраивают бины CustomUserDetailsService и UserDetailsRepository соответственно. + +## Структура папок + +Структура папок вашего проекта должна выглядеть примерно так: + +``` +src +└── main + └── java + └── edu + └── labs + └── yourproject + ├── model + │ └── CustomUserDetails.java + ├── repository + │ └── UsersRepository.java + └── service + └── CustomUserDetailsService.java +``` + +Эта структура папок показывает, где создать класс `CustomUserDetailsService` и интерфейс `UsersRepository` в вашем проекте. Организация ваших классов таким образом помогает поддерживать чистый и структурированный код. + +--- + +# [СЛЕДУЮЩЕЕ ЗАДАНИЕ: Шифрование паролей](password-encryption.md) \ No newline at end of file diff --git a/docs/ru/springsecurity/practice/configure-spring-security.md b/docs/ru/springsecurity/practice/configure-spring-security.md new file mode 100644 index 0000000..4ef55f5 --- /dev/null +++ b/docs/ru/springsecurity/practice/configure-spring-security.md @@ -0,0 +1,79 @@ +# Настройка Spring Security + +В этом задании мы сосредоточимся на настройке Spring Security в вашем проекте. Spring Security предоставляет обширные средства безопасности для Java-приложений, включая аутентификацию, авторизацию и защиту от распространенных угроз безопасности. + +## Цель + +Цель этого задания - интегрировать Spring Security в ваш существующий проект, гарантируя, что ваше приложение защищено от несанкционированного доступа. + +## Шаги + +1. **Добавление зависимости Spring Security** + + - Для проектов Maven: + + Добавьте следующую зависимость в файл `pom.xml` вашего проекта: + + ```xml + + org.springframework.boot + spring-boot-starter-security + + ``` + + - Для проектов Gradle: + + Добавьте следующую зависимость в файл `build.gradle` вашего проекта: + + ```groovy + implementation 'org.springframework.boot:spring-boot-starter-security' + ``` + + Убедитесь, что вы используете соответствующую версию Spring Security для вашего проекта. + +2. **Создание класса конфигурации безопасности** + + Создайте новый Java класс с именем `WebSecurityConfig` в структуре вашего проекта. Обычно этот класс располагается в пакете `config`. Файл должен называться `WebSecurityConfig.java`. + + Структура папок вашего проекта должна выглядеть примерно так: + + ``` + src + └── main + └── java + └── edu + └── labs + └── yourproject + ├── config + │ └── WebMvcConfig.java + │ └── WebSecurityConfig.java + └── controller + └── PracticeController.java + ``` + +3. **Настройка класса конфигурации безопасности** + + Внутри класса `WebSecurityConfig` отметьте его аннотациями `@Configuration` и `@EnableWebSecurity`, чтобы указать, что это класс конфигурации для Spring Security. + + ```java + package edu.labs.yourproject.config; + + import org.springframework.context.annotation.Configuration; + import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; + import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + + @Configuration + @EnableWebSecurity + public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + // Конфигурация безопасности здесь + } + } + ``` + +--- + +# [СЛЕДУЮЩЕЕ ЗАДАНИЕ: Шифрование паролей](password-encryption.md) diff --git a/docs/ru/springsecurity/practice/configure-thymeleaf-security.md b/docs/ru/springsecurity/practice/configure-thymeleaf-security.md new file mode 100644 index 0000000..0e0cc51 --- /dev/null +++ b/docs/ru/springsecurity/practice/configure-thymeleaf-security.md @@ -0,0 +1,30 @@ +# Настройка Thymeleaf с Spring Security + +## Цель +Цель этого задания - интегрировать Thymeleaf с Spring Security, обеспечивая использование дополнительных диалектов и утилит, предоставляемых библиотекой `thymeleaf-extras-springsecurity6`. + +## Шаги + +1. **Gradle (Groovy):** + + Добавьте зависимость `thymeleaf-extras-springsecurity6` в ваш файл `build.gradle`: + + ```groovy + implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6:3.0.4.RELEASE' + ``` + +2. **Maven:** + + Добавьте следующую зависимость в ваш файл `pom.xml`: + + ```xml + + org.thymeleaf.extras + thymeleaf-extras-springsecurity6 + 3.0.4.RELEASE + + ``` + +--- + +# [СЛЕДУЮЩЕЕ ЗАДАНИЕ: Создать базовую реализацию для пользователя](base-implementation-user.md) diff --git a/docs/ru/springsecurity/practice/create-identity-to-users.md b/docs/ru/springsecurity/practice/create-identity-to-users.md new file mode 100644 index 0000000..fc0880a --- /dev/null +++ b/docs/ru/springsecurity/practice/create-identity-to-users.md @@ -0,0 +1,61 @@ +# Создание идентификации пользователей + +Это задание описывает процесс добавления ролей и полномочий пользователям, созданным на предыдущем этапе, "Добавление фиктивных пользователей". Присваивая роли и полномочия пользователям, мы устанавливаем их идентификацию в приложении и контролируем доступ к различным ресурсам и функционалу. + +## Цель + +Расширить профили пользователей, созданные на предыдущем этапе, присвоив им роли и полномочия, тем самым определив их идентификацию и разрешения на доступ в приложении. + +## Шаги + +1. **Обновление профилей пользователей с ролями и полномочиями:** + + Мы обновим фиктивные профили пользователей, созданные в классе `CustomUserDetailsService`, чтобы добавить роли и полномочия. Это включает в себя назначение конкретных ролей каждому пользователю, таких как `ADMIN`, `MODERATOR` или `USER`, и предоставление соответствующих полномочий на основе их ролей. + + ```java + // Внутри метода addDummyUsers() + + // Определение ролей + String adminRole = "ROLE_ADMIN"; + String moderatorRole = "ROLE_MODERATOR"; + String userRole = "ROLE_USER"; + + // Определение полномочий + List adminAuthorities = Arrays.asList( + new SimpleGrantedAuthority(adminRole), + new SimpleGrantedAuthority("READ"), + new SimpleGrantedAuthority("WRITE") + ); + + List moderatorAuthorities = Arrays.asList( + new SimpleGrantedAuthority(moderatorRole), + new SimpleGrantedAuthority("READ") + ); + + List userAuthorities = Collections.singletonList( + new SimpleGrantedAuthority(userRole) + ); + + // Создание фиктивных пользователей с ролями и полномочиями + CustomUserDetails admin = new CustomUserDetails("admin", passwordEncoder.encode("admin"), true, true, true, true); + admin.setAuthorities(adminAuthorities); + admin.setRole(adminRole); + + CustomUserDetails moderator = new CustomUserDetails("moderator", passwordEncoder.encode("moderator"), true, true, true, true); + moderator.setAuthorities(moderatorAuthorities); + moderator.setRole(moderatorRole); + + CustomUserDetails user = new CustomUserDetails("user", passwordEncoder.encode("user"), true, true, true, true); + user.setAuthorities(userAuthorities); + user.setRole(userRole); + ``` + + В этом обновленном коде: + - Мы определяем роли и полномочия в виде переменных для ясности и удобства обслуживания. + - Теперь каждый профиль пользователя включает список полномочий на основе назначенных им ролей. + - Полномочия представлены объектами `SimpleGrantedAuthority` и добавляются в профили пользователей соответственно. + - Кроме того, мы устанавливаем роль для каждого пользователя, чтобы в дальнейшем использовать контроль доступа на основе ролей. + +--- + +# [СЛЕДУЮЩЕЕ ЗАДАНИЕ: Создать базу для авторизации на сервере](setup-server-authorization.md) diff --git a/docs/ru/springsecurity/practice/custom-login-form.md b/docs/ru/springsecurity/practice/custom-login-form.md new file mode 100644 index 0000000..e7e6d64 --- /dev/null +++ b/docs/ru/springsecurity/practice/custom-login-form.md @@ -0,0 +1,40 @@ +# Пользовательский формуляр входа + +Это задание руководит вас через процесс активации пользовательской страницы формы входа для аутентификации с использованием Spring Security. Реализуя пользовательскую страницу входа, пользователи могут безопасно аутентифицироваться в вашем приложении. + +## Цель + +Активировать пользовательскую страницу формы входа, которая уже была создана по определенному пути. + +## Шаги + +1. **Обновить конфигурацию безопасности:** + + В классе `WebSecurityConfig` измените метод `configure(HttpSecurity http)` для указания пользовательской страницы входа. + + ```java + @Configuration + @EnableWebSecurity + public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests((requests) -> requests + // Добавьте другие конфигурации авторизации здесь + ) + .formLogin((login) -> login + .loginPage("/custom-login-page") // Укажите URL пользовательской страницы входа + // Добавьте другие конфигурации формы входа здесь + ); + } + } + ``` + + В этой конфигурации: + - Оператор `.loginPage("/custom-login-page")` указывает URL пользовательской страницы входа. + - Вы можете добавить дополнительные конфигурации для настройки поведения формы входа, такие как установка URL для успешного или неудачного входа, определение имен полей формы и т. д. + +--- + +# [СЛЕДУЮЩЕЕ: ЗАДАНИЯ](../lab-work.md) \ No newline at end of file diff --git a/docs/ru/springsecurity/practice/password-encryption.md b/docs/ru/springsecurity/practice/password-encryption.md new file mode 100644 index 0000000..97a78d4 --- /dev/null +++ b/docs/ru/springsecurity/practice/password-encryption.md @@ -0,0 +1,82 @@ +# Шифрование паролей + +В этой задаче мы настроим шифрование паролей для аутентификации пользователей в приложении, использующем Spring Security. Шифрование паролей повышает безопасность, сохраняя их в базе данных в зашифрованном виде. + +## Цель + +Цель этой настройки - настроить шифрование паролей с использованием BCryptPasswordEncoder, предоставляемого Spring Security. Это обеспечит защиту паролей путем их безопасного хеширования перед сохранением в базе данных. + +## Шаги + +1. **Добавление бина BCryptPasswordEncoder** + + Откройте класс WebSecurityConfig, находящийся в пакете конфигурации вашего проекта (`edu.labs.yourproject.config`). Внутри этого класса определите бин для BCryptPasswordEncoder. + + ```java + package edu.labs.yourproject.config; + + import org.springframework.context.annotation.Bean; + import org.springframework.context.annotation.Configuration; + import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + + @Configuration + public class WebSecurityConfig { + + @Bean + public BCryptPasswordEncoder passwordEncoder() { + // Создание и настройка бина BCryptPasswordEncoder + return new BCryptPasswordEncoder(); + } + } + ``` + + Определите метод бина `passwordEncoder()`, который создает и настраивает бин BCryptPasswordEncoder. Этот бин будет использоваться для шифрования паролей перед их сохранением в базе данных. + +2. **Шифрование паролей** + + a. **Обновление класса CustomUserDetailsService** + + Откройте класс CustomUserDetailsService, находящийся в вашем пакете сервисов (`edu.labs.yourproject.service`). Внедрите бин BCryptPasswordEncoder в этот класс. + + ```java + package edu.labs.yourproject.service; + + import org.springframework.beans.factory.annotation.Autowired; + import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + import org.springframework.stereotype.Service; + import edu.labs.yourproject.model.CustomUserDetails; + import edu.labs.yourproject.repository.UsersRepository; + + @Service + public class CustomUserDetailsService implements UserDetailsService { + + private final UsersRepository usersRepository; + + @Autowired + private BCryptPasswordEncoder passwordEncoder; + + @Autowired + public CustomUserDetailsService(UsersRepository usersRepository) { + this.usersRepository = usersRepository; + } + } + ``` + + b. **Реализация метода регистрации** + + Определите метод в классе CustomUserDetailsService для обработки регистрации пользователя. В этом методе зашифруйте пароль пользователя перед сохранением его в базе данных. + + ```java + public void registerUser(CustomUserDetails user) { + // Шифрование пароля перед сохранением пользователя + String encodedPassword = passwordEncoder.encode(user.getPassword()); + user.setPassword(encodedPassword); + usersRepository.save(user); + } + ``` + + Этот метод принимает объект CustomUserDetails, представляющий пользователя для регистрации. Он шифрует пароль пользователя с использованием бина BCryptPasswordEncoder, а затем сохраняет пользователя в базе данных. + +--- + +# [СЛЕДУЮЩЕЕ ЗАДАНИЕ: Добавить тестовых пользователей](add-dummy-users.md) diff --git a/docs/ru/springsecurity/practice/setup-server-authorization.md b/docs/ru/springsecurity/practice/setup-server-authorization.md new file mode 100644 index 0000000..28672bc --- /dev/null +++ b/docs/ru/springsecurity/practice/setup-server-authorization.md @@ -0,0 +1,45 @@ +# Настройка авторизации на сервере + +В этой задаче мы настроим авторизацию в вашем приложении, определив правила безопасности с использованием Spring Security. Определяя правила авторизации, вы можете контролировать доступ к определенным путям и конечным точкам в вашем приложении. + +## Цель + +Настроить правила авторизации для ограничения или разрешения доступа к различным путям и конечным точкам в приложении. + +## Шаги + +1. **Добавление конфигурации безопасности:** + + В классе `WebSecurityConfig` добавьте метод `configure(HttpSecurity http)`, чтобы определить правила безопасности для приложения. Мы будем использовать пути и конечные точки, определенные в предыдущей лабораторной работе. + + ```java + @Configuration + @EnableWebSecurity + public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests((requests) -> requests + .requestMatchers("/first").permitAll() + .requestMatchers("/second").permitAll() + .requestMatchers("/third").permitAll() + .requestMatchers("/fourth").permitAll() + .requestMatchers("/addStudent").permitAll() + .requestMatchers("/removeStudent").permitAll() + ); + } + } + ``` + + В этой конфигурации: + - Мы используем `.authorizeHttpRequests()`, чтобы определить правила авторизации. + - Внутри лямбда-выражения мы указываем, какие запросы следует разрешить. + +## Вывод + +Вы успешно настроили правила авторизации в вашем приложении для управления доступом к различным путям и конечным точкам. Определяя конкретные разрешения для каждого пути, вы можете гарантировать, что пользователи смогут получить доступ только к ресурсам, к которым у них есть соответствующие разрешения. + +--- + +# [СЛЕДУЮЩАЯ ЗАДАЧА: Авторизация аутентифицированных пользователей](authorize-server-authenticated.md) diff --git a/docs/ru/thymeleaf/lab-work.md b/docs/ru/thymeleaf/lab-work.md index e531959..dd9bd8e 100644 --- a/docs/ru/thymeleaf/lab-work.md +++ b/docs/ru/thymeleaf/lab-work.md @@ -1,10 +1,13 @@ +[English](../../en/thymeleaf/lab-work.md) | [中文](../../cn/thymeleaf/lab-work.md) | Русский + + # Лабораторная работа по Thymeleaf -Добро пожаловать в лабораторную работу по Thymeleaf! Цель этой серии задач - помочь вам практиковаться и освоить Thymeleaf, мощный шаблонизатор для Java-приложений. Независимо от того, являетесь ли вы начинающим или стремитесь улучшить свои навыки, эти практические задачи научат вас различным аспектам интеграции Thymeleaf в приложение Spring. +Добро пожаловать в лабораторную работу по Thymeleaf! Цель этой серии задач - помочь вам практиковаться и освоить Thymeleaf - шаблонизатор для Java-приложений. Независимо от того, являетесь ли вы начинающим или стремитесь улучшить свои навыки, эти практические задачи научат вас различным аспектам интеграции Thymeleaf в приложении Spring. ## Цель лабораторной работы -Основная цель этой лабораторной работы - предоставить вам практический опыт и мастерство использования Thymeleaf в среде Spring. Thymeleaf широко используется для серверного рендеринга в веб-разработке, и через эти задачи вы получите ценные знания о его конфигурации, использовании переменных, контроллерах, обработке форм и многом другом. +Цель этой лабораторной работы - помочь вам изучить Thymeleaf в среде Spring на практике. Thymeleaf широко используется для серверного рендеринга в веб-разработке. Прорешав эти задания, вы получите полезные знания о его конфигурации, использовании переменных, контроллерах, обработке форм и многом другом. ## Практические задачи @@ -24,8 +27,8 @@ 1. **Задача 1: Создание HTML-макета с фрагментами** - - Создайте отдельные фрагменты для различных частей HTML-страницы, таких как навигационная панель, заголовок, head и подвал. - - Соберите эти фрагменты в один HTML-файл, чтобы создать полный макет. + - Создайте отдельные фрагменты для различных частей HTML-страницы, таких как навигационная панель, заголовок, header и подвал. + - Соберите эти фрагменты в один HTML-файл, чтобы создать полноценный макет веб страницы. - Например: ![layout.png](../../srcs/thymeleaf/layout.png) @@ -41,13 +44,13 @@ 3. **Задача 3: Создание форм входа и регистрации** - - Разработайте и реализуйте формы входа и регистрации для аутентификации пользователей. + - Создайте формы входа и регистрации для аутентификации пользователей. - Используйте привязку модели Thymeleaf для обработки данных формы. - Например: ![login-page.png](../../srcs/thymeleaf/login-page.png) - ![signup-page.png](../../srcs/thymeleaf/signup-page.png) + ![signup.png](../../srcs/thymeleaf/signup.png) 4. **Задача 4: Валидация действий входа и регистрации** @@ -62,13 +65,10 @@ - Разработайте страницу "Пользователи", отображающую таблицу пользователей. - Реализуйте итерацию для динамического заполнения таблицы данными пользователей. - - Предоставьте функциональность удаления или изменения записей пользователя со страницы. + - Реализуйте функциональность для удаления или изменения записей пользователя на странице. - Например: ![users-page.png](../../srcs/thymeleaf/users-page.png) ![modify-user-page.png](../../srcs/thymeleaf/modify-user-page.png) -Не стесняйтесь исследовать и выполнять эти задачи в своем собственном темпе. Каждая задача разработана для дополнительного развития ваших навыков в Thymeleaf и веб-разработке. Если у вас есть вопросы или вам нужна помощь, не стесняйтесь обращаться. - -Счастливого кодирования! \ No newline at end of file diff --git a/docs/ru/thymeleaf/practice/configure-thymeleaf.md b/docs/ru/thymeleaf/practice/configure-thymeleaf.md index f767e45..1031ed8 100644 --- a/docs/ru/thymeleaf/practice/configure-thymeleaf.md +++ b/docs/ru/thymeleaf/practice/configure-thymeleaf.md @@ -2,7 +2,7 @@ **Описание:** -Это задание включает в себя настройку Thymeleaf в приложении Spring для обеспечения беспроблемной интеграции шаблонного движка для веб-разработки. +Это задание включает в себя настройку Thymeleaf в приложении Spring для обеспечения легкой интеграции шаблонного движка для веб-разработки. ## **Шаги:** @@ -24,10 +24,10 @@ } ``` - Размещение класса конфигурации в пакете `config` повышает организованность и обеспечивает четкую структуру в вашем проекте. Скорректируйте имя пакета в зависимости от структуры вашего проекта. + Размещение класса конфигурации в пакете `config` помогает правильно структурировать ваш код. Скорректируйте имя пэкеджа в зависимости от структуры вашего проекта. 2. **Настройте Разрешитель Шаблонов Thymeleaf:** - - Определите метод, аннотированный `@Bean`, для конфигурации разрешителя шаблонов Thymeleaf. + - Создайте метод с аннотацией `@Bean` для конфигурации шаблонизатора Thymeleaf. - Используйте `ClassLoaderTemplateResolver` и установите префикс, суффикс, режим шаблона и кодировку символов. ```java @@ -72,7 +72,7 @@ ``` 4. **Настройте Разрешитель Представлений Thymeleaf:** - - Создайте метод, аннотированный `@Bean`, для настройки разрешителя представлений Thymeleaf. + - Создайте метод, аннотированный `@Bean`, для настройки Thymeleaf. - Установите шаблонный движок. ```java @@ -112,8 +112,4 @@ --- -**Заключение:** - -Поздравляю! Вы успешно настроили Thymeleaf в вашем приложении Spring. Эта настройка позволяет интегрировать шаблоны Thymeleaf без заметных усилий, предоставляя мощный инструмент для создания динамичного веб-контента. Если вы хотите более глубоко изучить конфигурацию Thymeleaf или изучить продвинутые функции, не стесняйтесь обращаться к [Документации Thymeleaf](https://www.thymeleaf.org/documentation.html). - -# [СЛЕДУЮЩЕЕ ЗАДАНИЕ: *Создание Первого Представления*](create-first-view.md) \ No newline at end of file +# [СЛЕДУЮЩЕЕ ЗАДАНИЕ: *Создание Первого Представления*](create-first-view.md) diff --git a/docs/ru/thymeleaf/practice/create-first-view.md b/docs/ru/thymeleaf/practice/create-first-view.md index a2ed7b7..c9527d3 100644 --- a/docs/ru/thymeleaf/practice/create-first-view.md +++ b/docs/ru/thymeleaf/practice/create-first-view.md @@ -56,8 +56,4 @@ --- -**Вывод:** - -Вы успешно создали и зарегистрировали ваше первое представление Thymeleaf. Убедитесь, что вы следуете правильному пути к файлам, как определено в конфигурации Thymeleaf. - # [СЛЕДУЮЩЕЕ ЗАДАНИЕ: *Работа с Переменными*](working-with-variables.md) \ No newline at end of file diff --git a/docs/ru/thymeleaf/practice/form-handling.md b/docs/ru/thymeleaf/practice/form-handling.md index 607eba6..a9eec58 100644 --- a/docs/ru/thymeleaf/practice/form-handling.md +++ b/docs/ru/thymeleaf/practice/form-handling.md @@ -67,8 +67,6 @@ - Логика внутри этого метода добавляет студента в список `students`. В реальном сценарии вы обычно бы сохраняли студента в базу данных или выполняли другие необходимые действия. - `return "redirect:/third";`: Эта строка перенаправляет пользователя обратно к представлению формы (`/third`). -**Заключение:** - -Вы успешно реализовали обработку формы в Thymeleaf, включая отображение представления формы и обработку отправки формы в `PracticeController`. Пользователи могут переходить к форме, отправлять данные студента. +--- # [СЛЕДУЮЩЕЕ ЗАДАНИЕ: *Параметры Запроса и Валидация*](validation.md) \ No newline at end of file diff --git a/docs/ru/thymeleaf/practice/forms.md b/docs/ru/thymeleaf/practice/forms.md index 0d185da..3ace17c 100644 --- a/docs/ru/thymeleaf/practice/forms.md +++ b/docs/ru/thymeleaf/practice/forms.md @@ -113,8 +113,6 @@ ![third-view.png](../../../srcs/thymeleaf/third-view.png) -**Заключение:** - -Вы успешно настроили форму в `third.html` и передали каждое поле в `PracticeController`, используя привязку формы Thymeleaf. +--- # [СЛЕДУЮЩЕЕ ЗАДАНИЕ: *Обработка Форм*](form-handling.md) \ No newline at end of file diff --git a/docs/ru/thymeleaf/practice/fragments-and-layouts.md b/docs/ru/thymeleaf/practice/fragments-and-layouts.md index dc9f2ef..ff464c4 100644 --- a/docs/ru/thymeleaf/practice/fragments-and-layouts.md +++ b/docs/ru/thymeleaf/practice/fragments-and-layouts.md @@ -123,8 +123,6 @@ ![fourth-view.png](../../../srcs/thymeleaf/fourth-view.png) -**Заключение:** - -Вы успешно реализовали фрагменты и макеты Thymeleaf. Фрагменты теперь правильно помечены атрибутами `th:fragment` в соответствующих представлениях, что позволяет их использовать в макете `fourth.html`. +--- # Поздравляю! Вы выполнили все задания. Теперь давайте перейдем к **[Заданиям лабораторной работы](../lab-work.md#задания-лабораторной-работы)** diff --git a/docs/ru/thymeleaf/practice/iteration.md b/docs/ru/thymeleaf/practice/iteration.md index 9f7803b..847c1d2 100644 --- a/docs/ru/thymeleaf/practice/iteration.md +++ b/docs/ru/thymeleaf/practice/iteration.md @@ -100,8 +100,6 @@ ![second-view.png](../../../srcs/thymeleaf/second-view.png) -**Заключение:** - -Вы успешно реализовали итерацию в Thymeleaf, создав список объектов `StudentModel`, передав его в `secondView` и отображая таблицу студентов в представлении `second.html`. Этот подход позволяет динамически отображать данные в таблицах на основе предоставленной модели. +--- # [СЛЕДУЮЩЕЕ ЗАДАНИЕ: *Литералы*](literals.md) diff --git a/docs/ru/thymeleaf/practice/literals.md b/docs/ru/thymeleaf/practice/literals.md index ee0af4c..b78b317 100644 --- a/docs/ru/thymeleaf/practice/literals.md +++ b/docs/ru/thymeleaf/practice/literals.md @@ -48,8 +48,6 @@ ![second-view-enhanced.png](../../../srcs/thymeleaf/second-view-enhanced.png) -**Заключение:** - -Вы успешно улучшили представление Thymeleaf `second.html`, внедрив литералы для изменения отображаемых значений в зависимости от определенных условий. Этот подход позволяет предоставлять более описательное и динамичное содержание в ваших представлениях. +--- # [СЛЕДУЮЩЕЕ ЗАДАНИЕ: *Формы*](forms.md) diff --git a/docs/ru/thymeleaf/practice/validation.md b/docs/ru/thymeleaf/practice/validation.md index 43f2e41..4ba6276 100644 --- a/docs/ru/thymeleaf/practice/validation.md +++ b/docs/ru/thymeleaf/practice/validation.md @@ -78,8 +78,6 @@ ![third-view-error.png](../../../srcs/thymeleaf/third-view-error.png) -**Заключение:** - -Вы успешно адаптировали `third` для отображения сообщений об успехе и сообщений об ошибках на основе параметров запроса. Это предоставляет более полный механизм обратной связи для пользователей, взаимодействующих с формой. +--- # [СЛЕДУЮЩЕЕ ЗАДАНИЕ: *Фрагменты и макеты*](fragments-and-layouts.md) diff --git a/docs/ru/thymeleaf/practice/variables-and-controller.md b/docs/ru/thymeleaf/practice/variables-and-controller.md index b4a2d9f..a8902d8 100644 --- a/docs/ru/thymeleaf/practice/variables-and-controller.md +++ b/docs/ru/thymeleaf/practice/variables-and-controller.md @@ -60,8 +60,6 @@ Выражение `th:text="${title}"` извлекает значение переменной `title`, переданной из контроллера. -**Заключение:** - -Вы успешно создали новое представление Thymeleaf (`second.html`) и изучили процесс передачи переменных из контроллера в представление. Этот подход позволяет генерировать динамический контент на основе логики контроллера. Не стесняйтесь расширять этот концепт для передачи большего количества переменных и дополнительной настройки ваших представлений. Теперь давайте продолжим к следующему заданию +--- # [СЛЕДУЮЩЕЕ ЗАДАНИЕ: *Итерация*](iteration.md) diff --git a/docs/ru/thymeleaf/practice/working-with-variables.md b/docs/ru/thymeleaf/practice/working-with-variables.md index 47a0281..715422c 100644 --- a/docs/ru/thymeleaf/practice/working-with-variables.md +++ b/docs/ru/thymeleaf/practice/working-with-variables.md @@ -83,10 +83,6 @@ ![first-view.png](../../../srcs/thymeleaf/first-view.png) -**Заключение:** - -Вы успешно изучили и реализовали различные типы локальных переменных в Thymeleaf. Экспериментируйте с различными сценариями и понимайте, как эти переменные способствуют созданию динамичного и локализованного контента в вашем приложении Spring. - -Не стесняйтесь обращаться к [документации по Thymeleaf](https://www.thymeleaf.org/documentation.html) для получения дополнительной информации и продвинутых функций. +--- # [СЛЕДУЮЩЕЕ ЗАДАНИЕ: *Переменные и контроллер*](variables-and-controller.md) diff --git a/docs/ru/transactions/lab-work.md b/docs/ru/transactions/lab-work.md new file mode 100644 index 0000000..78a97ec --- /dev/null +++ b/docs/ru/transactions/lab-work.md @@ -0,0 +1,56 @@ +[English](../../en/transactions/lab-work.md) | [中文](../../cn/transactions/lab-work.md) | Русский + + +# Лабораторная работа по Транзакциям + +Добро пожаловать в лабораторную работу по транзакциям! Цель этих задач - помочь вам овладеть управлением транзакциями в приложении на Spring. Независимо от вашего уровня - будь то начинающий или опытный разработчик, эти практические задачи помогут вам освоить различные аспекты управления транзакциями, включая распространение, уровни изоляции, вложенные транзакции и многое другое. + +## Цель лабораторной работы + +Основная цель этой лабораторной работы - предоставить вам практический опыт и навыки в управлении транзакциями. Через эти задачи вы получите ценные знания о настройке транзакций, обработке различных типов распространения, реализации вложенных транзакций и обеспечении целостности данных в ваших приложениях. + +## Задачи практики + +1. [Настройка транзакции](practice/configuration.md) +2. [Часть 1: Создание сущностей и репозиториев](practice/lessons/entities-and-repositories.md) +3. [Часть 2: Реализация основных транзакционных операций](practice/lessons/basic-transactional-operations.md) +4. [Часть 3: Улучшение транзакционных методов с подробным журналированием](practice/lessons/transactional-logging.md) +5. [Часть 4: Реализация вложенных транзакций и операций без транзакции](practice/lessons/nested-and-non-transactional-operations.md) + +## Задачи лабораторной работы + +![img.png](../../srcs/transactions/task-chart.png) + +- **Регистрация пользователя на мероприятие** + - **Задача:** Реализуйте метод для регистрации пользователя на мероприятие. Обеспечьте полную изоляцию операции для поддержания целостности данных. Запишите эту операцию отдельно, независимо от успешного или неудачного выполнения основной транзакции. + - **Распространение:** REQUIRED + - **Изоляция:** SERIALIZABLE + - **Распространение журналирования:** REQUIRES_NEW + +- **Удаление регистрации пользователя с мероприятия** + - **Задача:** Реализуйте метод для удаления регистрации пользователя с мероприятия. Обеспечьте выполнение этого метода в рамках существующей транзакции. + - **Распространение:** MANDATORY + +- **Получение зарегистрированных пользователей на мероприятие** + - **Задача:** Реализуйте метод для получения всех пользователей, зарегистрированных на конкретное мероприятие. Обеспечьте, чтобы метод либо присоединялся к существующей транзакции, либо создавал новую, читая только подтвержденные данные. + - **Распространение:** REQUIRED + - **Изоляция:** READ_COMMITTED + +- **Добавление нового мероприятия** + - **Задача:** Реализуйте метод для добавления нового мероприятия. Эта операция должна выполняться без транзакционных гарантий, чтобы избежать ненужных затрат на транзакции. + - **Распространение:** NOT_SUPPORTED + +- **Обновление деталей мероприятия и регистраций с вложенными транзакциями** + - **Задача:** Реализуйте метод для обновления деталей мероприятия вместе с соответствующими регистрациями. Обеспечьте согласованность в рамках вложенных транзакций. + - **Распространение:** REQUIRED + - **Изоляция:** REPEATABLE_READ + - **Вложенная задача:** Обновление регистраций в рамках вложенной транзакции. + +- **Обновление регистраций** + - **Задача:** Реализуйте метод для обновления записей регистрации. Обеспечьте, чтобы эти операции были частью вложенной транзакции. + - **Распространение:** NESTED + - **Изоляция:** REPEATABLE_READ + +- **Выполнение операции без транзакции** + - **Задача:** Реализуйте метод для операций, не требующих транзакционного контекста, например обычные операции или логгирование. + - **Распространение:** Нет diff --git a/docs/ru/transactions/practice/configuration.md b/docs/ru/transactions/practice/configuration.md new file mode 100644 index 0000000..d511378 --- /dev/null +++ b/docs/ru/transactions/practice/configuration.md @@ -0,0 +1,85 @@ +# Настройка транзакций + +## Введение + +Это руководство посвящено настройке управления транзакциями в проекте Spring Boot. Он предоставляет пошаговые инструкции по включению управления транзакциями и настройке атрибутов транзакций. + +## Цель + +Цель этого руководства - продемонстрировать, как настроить управление транзакциями в приложении Spring Boot, позволяя управлять транзакциями базы данных. + +## Настройка управления транзакциями + +Чтобы включить управление транзакциями в вашем проекте Spring Boot, выполните следующие шаги: + +1. Добавьте необходимые зависимости в ваш файл `pom.xml` или `build.gradle`. Убедитесь, что у вас есть зависимости для Spring Boot, Spring Data JPA и любого драйвера базы данных, который вы используете (например, H2, MySQL, PostgreSQL). + +2. Настройте управление транзакциями в вашем приложении Spring Boot. Вы можете сделать это, аннотировав ваш класс основного приложения аннотацией `@EnableTransactionManagement`. + +### Пример (Java Config): + +```java +package com.example.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@SpringBootApplication +@EnableTransactionManagement +public class DemoApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + +} +``` + +3. Если вы используете Spring Web MVC, вам необходимо добавить следующее в ваши файлы конфигурации для настройки менеджера транзакций: + +### Пример (XML Config): + +```xml + + + +``` + +### Пример (Java Config): + +```java +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.transaction.PlatformTransactionManager; + +import javax.persistence.EntityManagerFactory; + +@Configuration +public class TransactionConfig { + + /** + * Определение бина для Spring Transaction Manager. + * + *

+ * Этот метод настраивает менеджер транзакций для JPA с использованием настроенной фабрики сущностей. + *

+ * + * @param entityManagerFactory бин фабрики сущностей + * @return бин TransactionManager + */ + @Bean + public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { + JpaTransactionManager txManager = new JpaTransactionManager(); + txManager.setEntityManagerFactory(entityManagerFactory); + return txManager; + } +} +``` + +Следуя этим шагам, вы сможете включить управление транзакциями в вашем приложении Spring Boot, что позволит вам эффективно управлять транзакциями базы данных. + +--- + +# [Далее: Создание сущностей и репозиториев](lessons/entities-and-repositories.md) \ No newline at end of file diff --git a/docs/ru/transactions/practice/lessons/basic-transactional-operations.md b/docs/ru/transactions/practice/lessons/basic-transactional-operations.md new file mode 100644 index 0000000..5439b83 --- /dev/null +++ b/docs/ru/transactions/practice/lessons/basic-transactional-operations.md @@ -0,0 +1,50 @@ +## Урок 2: Внедрение основных транзакционных операций + +## Цель + +Этот раздел направлен на введение простых, но важных транзакционных методов для зачисления студентов и управления курсами в приложении Spring Boot. + +## Шаги + +1. **Зачисление студента на курс** + + **Сценарий**: В качестве администратора университета вам необходимо зачислить студента на курс. Это действие должно быть не должно вызвать проблем и гарантировать целостность данных, даже если происходит несколько зачислений одновременно или возникают проблемы с базой данных. + + **Реализация метода `enrollStudentInCourse`**: Создайте метод для зачисления студента на курс. Обеспечьте, чтобы этот процесс был транзакционным, что означает, что это как единый пакетный процесс, гарантирующий, что весь процесс единый. Мы используем `Propagation.REQUIRED`, чтобы убедиться, что этот метод участвует в любой существующей транзакции или создает новую, если таковой не существует. Кроме того, мы устанавливаем `Isolation.SERIALIZABLE`, чтобы гарантировать, что даже если есть параллельные транзакции, они не мешают друг другу, сохраняя целостность данных. + + ```java + @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.SERIALIZABLE) + public void enrollStudentInCourse(UUID studentId, UUID courseId) { + // Ваша реализация здесь + } + ``` + +2. **Получение списка студентов для курса** + + **Сценарий**: Чтобы создать список группы для курса, вам необходимо получить список студентов, которые зачислены на него. Эта операция должна гарантировать, что вы всегда получаете точные данные базы данных, даже если происходят другие действия одновременно. + + **Реализация метода `getStudentsForCourse`**: Разработайте метод для извлечения студентов для определенного курса. Он должен гарантировать, что данные, которые вы извлекаете, согласованы, независимо от любых текущих транзакций. Мы используем `Propagation.REQUIRED`, чтобы убедиться, что этот метод участвует в любой существующей транзакции или создает новую, если таковая не существует. Мы устанавливаем `Isolation.READ_COMMITTED`, чтобы гарантировать, что данные, которые мы извлекаем, зафиксированы и видны другим транзакциям, поддерживая последовательность. + + ```java + @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED) + public List getStudentsForCourse(UUID courseId) { + // Ваша реализация здесь + } + ``` + +3. **Добавление нового курса** + + **Сценарий**: Новый курс готовится к новому учебному году. При добавлении нового курса в систему вы хотите убедиться, что это действие не мешает ничему другому, происходящему в системе, сохраняя свою независимость. + + **Реализация метода `addNewCourse`**: Создайте метод для добавления нового курса в систему. Убедитесь, что этот процесс не запутывается с другими текущими транзакциями. Мы используем `Propagation.NOT_SUPPORTED`, чтобы убедиться, что этот метод не участвует в какой-либо текущей транзакции, обеспечивая его автономность и избегая потенциальных конфликтов с другими операциями. + + ```java + @Transactional(propagation = Propagation.NOT_SUPPORTED) + public Course addNewCourse(String title) { + // Ваша реализация здесь + } + ``` + +--- + +# [СЛЕДУЮЩЕЕ: Улучшение транзакционных методов с подробным логированием](transactional-logging.md) diff --git a/docs/ru/transactions/practice/lessons/entities-and-repositories.md b/docs/ru/transactions/practice/lessons/entities-and-repositories.md new file mode 100644 index 0000000..9c2e951 --- /dev/null +++ b/docs/ru/transactions/practice/lessons/entities-and-repositories.md @@ -0,0 +1,39 @@ +## Урок 1: Создание сущностей и репозиториев + +## Цель + +Цель этой задачи - определить основные сущности (Студент, Курс, Зачисление, Лог) и настроить соответствующие репозитории в проекте Spring Boot с использованием Spring Data JPA. + +## Шаги + +1. **Обратитесь к предоставленной ER-диаграмме, чтобы определить классы сущностей.** + ![er-diagram.png](../../../../srcs/transactions/er-diagram.png) + Если у вас уже есть классы сущностей на основе предоставленной ER-диаграммы, перейдите к шагу 2. В противном случае проанализируйте ER-диаграмму и создайте следующие классы сущностей: + + - Student (Студент) + - Course (Курс) + - Enrollment (Зачисление) + - Log (Лог) + + Обеспечьте наличие необходимых атрибутов в каждом классе, как показано на ER-диаграмме. + +2. **Создайте репозитории для сущностей.** + + Например, давайте создадим репозиторий для сущности `Student`: + + ```java + package com.example.demo.repository; + + import com.example.demo.entity.Student; + import org.springframework.data.jpa.repository.JpaRepository; + + public interface StudentRepository extends JpaRepository { + } + ``` + + Если у вас уже есть репозитории, перейдите к следующему шагу. В противном случае повторите описанный выше шаг для репозиториев оставшихся сущностей (Course, Enrollment, Log). + +--- + +# [СЛЕДУЮЩЕЕ: Реализация базовых транзакционных операций](basic-transactional-operations.md) + diff --git a/docs/ru/transactions/practice/lessons/nested-and-non-transactional-operations.md b/docs/ru/transactions/practice/lessons/nested-and-non-transactional-operations.md new file mode 100644 index 0000000..c6473e0 --- /dev/null +++ b/docs/ru/transactions/practice/lessons/nested-and-non-transactional-operations.md @@ -0,0 +1,66 @@ +## Урок 4: Реализация вложенных транзакций и операций без транзакции + +## Цель + +Этот раздел направлен на изучение использования вложенных транзакций и операций без транзакции в слое сервиса, обеспечивая студентам понимание управления сложными транзакционными сценариями. + +## Шаги + +1. **Обновление деталей курса и зачислений** + + **Сценарий**: В качестве администратора университета вам часто приходится обновлять как детали курса, так и зачисления, связанные с этим курсом. Эта операция должна обеспечивать целостность и непрерывность данных, даже если происходит несколько обновлений одновременно. + + **Реализация метода `updateCourseAndEnrollments`**: Определите метод для обновления деталей курса и зачислений с необходимым транзакционным поведением. Мы используем `Propagation.REQUIRED`, чтобы убедиться, что этот метод участвует в любой существующей транзакции или создает новую, если таковой не существует. Установка `Isolation.REPEATABLE_READ` гарантирует, что данные, считываемые этим методом, остаются согласованными на протяжении всей транзакции. Внутри этого метода мы выполняем вложенную транзакцию, вызывая метод `updateEnrollments` для обновления зачислений, обеспечивая атомарность и изоляцию этой операции от внешней транзакции. + + ```java + @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ) + public void updateCourseAndEnrollments(UUID courseId, String newTitle) { + // Запись начала процесса обновления + logAction("Update Course and Enrollments", "Start"); + + try { + // Реализация обновления деталей курса + // ... + + // Вложенная транзакция для обновления зачислений + updateEnrollments(courseId); + + // Запись успешного обновления + logAction("Update Course and Enrollments", "Success"); + } catch (Exception e) { + // Запись неудачи + logAction("Update Course and Enrollments", "Failure: " + e.getMessage()); + throw e; + } + } + ``` + +2. **Независимое обновление зачислений** + + **Сценарий**: Некоторые административные задачи могут потребовать обновления зачислений независимо от обновлений курса. Эта операция должна поддерживать целостность данных, позволяя при этом отдельное транзакционное управление. + + **Реализация метода `updateEnrollments`**: Определите метод для обновления зачислений для курса с вложенным транзакционным поведением. Мы используем `Propagation.NESTED`, чтобы указать, что этот метод выполняется в рамках внешней транзакции, но может быть отменен независимо при необходимости. Установка `Isolation.REPEATABLE_READ` гарантирует, что данные, считываемые этим методом, остаются согласованными на протяжении всей транзакции. + + ```java + @Transactional(propagation = Propagation.NESTED, isolation = Isolation.REPEATABLE_READ) + public void updateEnrollments(UUID courseId) { + // Запись начала процесса обновления зачислений + logAction("Update Enrollments", "Start"); + + try { + // Реализация обновления зачислений + // ... + + // Запись успешного обновления + logAction("Update Enrollments", "Success"); + } catch (Exception e) { + // Запись неудачи + logAction("Update Enrollments", "Failure: " + e.getMessage()); + throw e; + } + } + ``` + +--- + +# [ДАЛЕЕ: Задания](../../lab-work.md) diff --git a/docs/ru/transactions/practice/lessons/transactional-logging.md b/docs/ru/transactions/practice/lessons/transactional-logging.md new file mode 100644 index 0000000..c55423b --- /dev/null +++ b/docs/ru/transactions/practice/lessons/transactional-logging.md @@ -0,0 +1,105 @@ +## Урок 3: Дополнение транзакционных методов логгированием + +## Цель + +Этот раздел направлен на интеграцию логгирования для каждой транзакционной операции, обеспечивая запись действий с их результатами. + +## Шаги + +1. **Реализация метода журналирования(логгирования)** + + **Сценарий**: Прежде чем улучшать транзакционные методы с помощью журналирования, нам нужно реализовать метод для обработки журналирования независимо от основной транзакции. Это гарантирует, что логгирование происходит надежно, независимо от результата основной транзакции. + + **Реализация метода `logAction`**: Создайте метод для независимого записывания действий, обеспечивая точное отслеживание результатов транзакции. Мы используем `Propagation.REQUIRES_NEW`, чтобы выполнить операцию логгирования в отдельной транзакции, делая ее независимой от любых текущих транзакций и гарантируя ее завершение даже в случае сбоя основной транзакции. + + ```java + @Transactional(propagation = Propagation.REQUIRES_NEW) + public void logAction(String action, String outcome) { + Log log = new Log(action, outcome, LocalDateTime.now()); + logRepository.save(log); + } + ``` + +2. **Логгирование зачисления студента на курс** + + **Сценарий**: В качестве администратора университета вам необходимо зарегистрировать зачисление студента на курс для отслеживания успешных зачислений и возможных ошибок. + + **Улучшение метода `enrollStudentInCourse`**: Измените метод для журналирования успешного или неудачного действия. + + ```java + @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.SERIALIZABLE) + public void enrollStudentInCourse(UUID studentId, UUID courseId) { + // Запись начала процесса зачисления + logAction("Enroll Student", "Start"); + + try { + // Реализация зачисления студента на курс + // ... + + // Журналирование успешного зачисления + logAction("Enroll Student", "Success"); + } catch (Exception e) { + // Журналирование ошибки + logAction("Enroll Student", "Failure: " + e.getMessage()); + throw e; + } + } + ``` + +3. **Запись получения списка студентов для курса** + + **Сценарий**: Для поддержания аудита активностей, связанных с курсом, вам необходимо зарегистрировать получение списка студентов для курса и гарантировать, что журналирование происходит даже в случае исключений. + + **Улучшение метода `getStudentsForCourse`**: Измените метод для журналирования успешного или неудачного действия. + + ```java + @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED) + public List getStudentsForCourse(UUID courseId) { + // Запись начала получения списка студентов для курса + logAction("Retrieve Students for Course", "Start"); + + try { + // Реализация получения списка студентов для курса + // ... + + // Журналирование успешного получения + logAction("Retrieve Students for Course", "Success"); + return students; + } catch (Exception e) { + // Журналирование ошибки + logAction("Retrieve Students for Course", "Failure: " + e.getMessage()); + throw e; + } + } + ``` + +4. **Запись добавления нового курса** + + **Сценарий**: При добавлении нового курса важно зарегистрировать результат операции для отслеживания успешного или неудачного добавления. + + **Улучшение метода `addNewCourse`**: Измените метод для журналирования успешного или неудачного действия. + + ```java + @Transactional(propagation = Propagation.NOT_SUPPORTED) + public Course addNewCourse(String title) { + // Запись начала добавления нового курса + logAction("Add New Course", "Start"); + + try { + // Реализация добавления нового курса + // ... + + // Журналирование успешного добавления + logAction("Add New Course", "Success"); + return savedCourse; + } catch (Exception e) { + // Журналирование ошибки + logAction("Add New Course", "Failure: " + e.getMessage()); + throw e; + } + } + ``` + +--- + +# [ДАЛЕЕ: Реализация вложенных транзакций и непривязанных к транзакции операций](nested-and-non-transactional-operations.md) \ No newline at end of file diff --git a/docs/srcs/jmeter/disable-element.png b/docs/srcs/jmeter/disable-element.png new file mode 100644 index 0000000..2ecf91e Binary files /dev/null and b/docs/srcs/jmeter/disable-element.png differ diff --git a/docs/srcs/jmeter/interface.png b/docs/srcs/jmeter/interface.png new file mode 100644 index 0000000..1e18560 Binary files /dev/null and b/docs/srcs/jmeter/interface.png differ diff --git a/docs/srcs/jmeter/new-http-cookie-manager-button.png b/docs/srcs/jmeter/new-http-cookie-manager-button.png new file mode 100644 index 0000000..efa9a6f Binary files /dev/null and b/docs/srcs/jmeter/new-http-cookie-manager-button.png differ diff --git a/docs/srcs/jmeter/new-recording-controller-button.png b/docs/srcs/jmeter/new-recording-controller-button.png new file mode 100644 index 0000000..b86d960 Binary files /dev/null and b/docs/srcs/jmeter/new-recording-controller-button.png differ diff --git a/docs/srcs/jmeter/new-regular-expression-button.png b/docs/srcs/jmeter/new-regular-expression-button.png new file mode 100644 index 0000000..dbe8971 Binary files /dev/null and b/docs/srcs/jmeter/new-regular-expression-button.png differ diff --git a/docs/srcs/jmeter/new-simple-controller-button.png b/docs/srcs/jmeter/new-simple-controller-button.png new file mode 100644 index 0000000..3458971 Binary files /dev/null and b/docs/srcs/jmeter/new-simple-controller-button.png differ diff --git a/docs/srcs/jmeter/recording-controller-button.png b/docs/srcs/jmeter/recording-controller-button.png new file mode 100644 index 0000000..2b0faf2 Binary files /dev/null and b/docs/srcs/jmeter/recording-controller-button.png differ diff --git a/docs/srcs/jmeter/regular-expression-extractor-fields.png b/docs/srcs/jmeter/regular-expression-extractor-fields.png new file mode 100644 index 0000000..ffacef5 Binary files /dev/null and b/docs/srcs/jmeter/regular-expression-extractor-fields.png differ diff --git a/docs/srcs/jmeter/run-test-scenraio-button.png b/docs/srcs/jmeter/run-test-scenraio-button.png new file mode 100644 index 0000000..67466c7 Binary files /dev/null and b/docs/srcs/jmeter/run-test-scenraio-button.png differ diff --git a/docs/srcs/jmeter/setting-port-and-url-pattern.png b/docs/srcs/jmeter/setting-port-and-url-pattern.png new file mode 100644 index 0000000..a29229b Binary files /dev/null and b/docs/srcs/jmeter/setting-port-and-url-pattern.png differ diff --git a/docs/srcs/jmeter/site.png b/docs/srcs/jmeter/site.png new file mode 100644 index 0000000..9c84e82 Binary files /dev/null and b/docs/srcs/jmeter/site.png differ diff --git a/docs/srcs/jmeter/start-recording-button.png b/docs/srcs/jmeter/start-recording-button.png new file mode 100644 index 0000000..94be557 Binary files /dev/null and b/docs/srcs/jmeter/start-recording-button.png differ diff --git a/docs/srcs/jmeter/stop-recording-button.png b/docs/srcs/jmeter/stop-recording-button.png new file mode 100644 index 0000000..e539997 Binary files /dev/null and b/docs/srcs/jmeter/stop-recording-button.png differ diff --git a/docs/srcs/jmeter/test-plan.png b/docs/srcs/jmeter/test-plan.png new file mode 100644 index 0000000..b4f1660 Binary files /dev/null and b/docs/srcs/jmeter/test-plan.png differ diff --git a/docs/srcs/jmeter/test-script-recorder.png b/docs/srcs/jmeter/test-script-recorder.png new file mode 100644 index 0000000..3cb9278 Binary files /dev/null and b/docs/srcs/jmeter/test-script-recorder.png differ diff --git a/docs/srcs/jmeter/thread-group-icon.png b/docs/srcs/jmeter/thread-group-icon.png new file mode 100644 index 0000000..9c7cd2e Binary files /dev/null and b/docs/srcs/jmeter/thread-group-icon.png differ diff --git a/docs/srcs/jmeter/thread-group.png b/docs/srcs/jmeter/thread-group.png new file mode 100644 index 0000000..8769c76 Binary files /dev/null and b/docs/srcs/jmeter/thread-group.png differ diff --git a/docs/srcs/jpa/er-diagram.png b/docs/srcs/jpa/er-diagram.png new file mode 100644 index 0000000..3d47dc4 Binary files /dev/null and b/docs/srcs/jpa/er-diagram.png differ diff --git a/docs/srcs/jpa/task-er-diagram.png b/docs/srcs/jpa/task-er-diagram.png new file mode 100644 index 0000000..aa3dbcc Binary files /dev/null and b/docs/srcs/jpa/task-er-diagram.png differ diff --git a/docs/srcs/springsecurity/task.png b/docs/srcs/springsecurity/task.png new file mode 100644 index 0000000..7b8e717 Binary files /dev/null and b/docs/srcs/springsecurity/task.png differ diff --git a/docs/srcs/thymeleaf/signup.png b/docs/srcs/thymeleaf/signup.png new file mode 100644 index 0000000..5c0c764 Binary files /dev/null and b/docs/srcs/thymeleaf/signup.png differ diff --git a/docs/srcs/transactions/er-diagram.png b/docs/srcs/transactions/er-diagram.png new file mode 100644 index 0000000..92809d0 Binary files /dev/null and b/docs/srcs/transactions/er-diagram.png differ diff --git a/docs/srcs/transactions/task-chart.png b/docs/srcs/transactions/task-chart.png new file mode 100644 index 0000000..a92af23 Binary files /dev/null and b/docs/srcs/transactions/task-chart.png differ diff --git a/settings.gradle b/settings.gradle index 256101f..b73e5d5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,3 @@ rootProject.name = 'java-web-dev-tutorial' + +include 'a-thymeleaf' \ No newline at end of file