В первой части статьи с помощью инструмента Jmix AI Assistant начато создание системы для проведения онлайн курсов.
Были сгенерированы сценарии использования (use cases), разработана UML-диаграмма в формате PlantUML для этих use cases, разработана доменная модель для системы и ее реализация на JMIX. Далее все классы разбиты по пакетам.
Продолжим эксперименты по разработке кода с помощью Jmix AI Assistant, включая следующие:
Генерация класса, заполняющего доменную модель тестовыми данными
Генерация REST API для модели домена, включая создание контроллеров и REST сервисов
Генерация CRUD-экранов пользовательского интерфейса
Генерация класса, заполняющего доменную модель тестовыми данными
Пишем очередной запрос для Jmix AI Assistant:
Сгенерируй класс, заполняющий доменную модель тестовыми данными.
Создай 2-3 студентов, добавь 2 курса и несколько материалов,
2 теста с 2-3 вопросами, запиши студентов на курс.
Выведи информацию о всех курсах.
Для каждого курса выводи список студентов (имя, фамилия, email), список материалов и список тестов.
Ответ должен содержать только код.
В качестве пакета используй ru.rsa.mcc.eduplatform.
Получаем ответ от Jmix AI Assistant:
package ru.rsa.mcc.eduplatform;
import ru.rsa.mcc.eduplatform.model.user.Student;
import ru.rsa.mcc.eduplatform.model.course.Course;
import ru.rsa.mcc.eduplatform.model.course.Module;
import ru.rsa.mcc.eduplatform.model.content.Material;
import ru.rsa.mcc.eduplatform.model.assessment.Test;
import ru.rsa.mcc.eduplatform.model.assessment.Question;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
public class TestDataGenerator {
public static void main(String[] args) {
// Create students
Student student1 = new Student();
student1.setUsername("john_doe");
student1.setPassword("password123");
student1.setEmail("john.doe@example.com");
student1.setStudentId("S001");
student1.setEnrollmentDate(LocalDate.now());
Student student2 = new Student();
student2.setUsername("jane_smith");
student2.setPassword("password123");
student2.setEmail("jane.smith@example.com");
student2.setStudentId("S002");
student2.setEnrollmentDate(LocalDate.now());
Student student3 = new Student();
student3.setUsername("alice_jones");
student3.setPassword("password123");
student3.setEmail("alice.jones@example.com");
student3.setStudentId("S003");
student3.setEnrollmentDate(LocalDate.now());
// Create courses
Course course1 = new Course();
course1.setTitle("Introduction to Programming");
course1.setDescription("Learn the basics of programming.");
Course course2 = new Course();
course2.setTitle("Advanced Java");
course2.setDescription("Deep dive into Java programming.");
// Create materials
Material material1 = new Material();
material1.setTitle("Java Basics");
material1.setType("Video");
material1.setData("URL to Java Basics Video");
material1.setDuration(60);
Material material2 = new Material();
material2.setTitle("OOP Concepts");
material2.setType("Document");
material2.setData("URL to OOP Concepts Document");
material2.setDuration(45);
// Create tests
Test test1 = new Test();
test1.setTitle("Java Basics Test");
test1.setDate(LocalDate.now());
test1.setDuration(30);
Question question1 = new Question();
question1.setText("What is Java?");
question1.setOptions(List.of("Programming Language", "Coffee", "Animal"));
question1.setCorrectAnswer("Programming Language");
Question question2 = new Question();
question2.setText("What is OOP?");
question2.setOptions(List.of("Object-Oriented Programming", "Open Office Protocol", "Online Order Processing"));
question2.setCorrectAnswer("Object-Oriented Programming");
test1.setQuestions(List.of(question1, question2));
Test test2 = new Test();
test2.setTitle("Advanced Java Test");
test2.setDate(LocalDate.now());
test2.setDuration(45);
Question question3 = new Question();
question3.setText("What is polymorphism?");
question3.setOptions(List.of("Many forms", "Single form", "No form"));
question3.setCorrectAnswer("Many forms");
test2.setQuestions(List.of(question3));
// Assign students to courses
List<Student> studentsCourse1 = new ArrayList<>();
studentsCourse1.add(student1);
studentsCourse1.add(student2);
List<Student> studentsCourse2 = new ArrayList<>();
studentsCourse2.add(student3);
// Assign materials and tests to modules
Module module1 = new Module();
module1.setTitle("Module 1");
module1.setDescription("Basic Module");
module1.setMaterials(List.of(material1, material2));
module1.setTests(List.of(test1));
Module module2 = new Module();
module2.setTitle("Module 2");
module2.setDescription("Advanced Module");
module2.setMaterials(List.of(material2));
module2.setTests(List.of(test2));
// Assign modules to courses
course1.setModules(List.of(module1));
course2.setModules(List.of(module2));
// Print course information
printCourseInfo(course1, studentsCourse1);
printCourseInfo(course2, studentsCourse2);
}
private static void printCourseInfo(Course course, List<Student> students) {
System.out.println("Course: " + course.getTitle());
System.out.println("Description: " + course.getDescription());
System.out.println("Students Enrolled:");
for (Student student : students) {
System.out.println(" - " + student.getUsername() + " (" + student.getEmail() + ")");
}
System.out.println("Modules:");
for (Module module : course.getModules()) {
System.out.println(" Module: " + module.getTitle());
System.out.println(" Materials:");
for (Material material : module.getMaterials()) {
System.out.println(" - " + material.getTitle() + " (" + material.getType() + ")");
}
System.out.println(" Tests:");
for (Test test : module.getTests()) {
System.out.println(" - " + test.getTitle());
}
}
System.out.println();
}
}
Этот код настраивает простой генератор тестовых данных для нашей образовательной платформы. Он создает студентов, курсы, модули, материалы и тесты, а затем распечатывает информацию о курсе, включая зарегистрированных студентов, материалы и тесты.
Генерация REST API для модели домена, включая создание контроллеров и REST сервисов
Пишем очередной запрос Jmix AI Assistant:
Сгенерировать REST-запросы, контроллеры и сервисы
Получаем следующий ответ от Jmix AI Assistant:
Чтобы в приложении Jmix предоставить доступ к нашей модели домена через REST API, необходимо создать REST контроллеры и сервисы. Ниже приведено пошаговое решение по настройке конечных точек REST для управления учащимися, курсами и связанными объектами.
Пошаговое решение
-
Создание сервисного уровня:
Сервисы будут обрабатывать бизнес логику и взаимодействовать с базой данных с помощью
DataManager
.
-
Создание контроллеров REST:
Контроллеры будут предоставлять доступ к конечным точкам REST и использовать сервисный уровень для выполнения REST-запросов.
Уровень сервиса
StudentService.java
package ru.rsa.mcc.eduplatform.service;
import io.jmix.core.DataManager;
import io.jmix.core.SaveContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import ru.rsa.mcc.eduplatform.model.user.Student;
import java.util.List;
@Service
public class StudentService {
@Autowired
private DataManager dataManager;
public List<Student> getAllStudents() {
return dataManager.load(Student.class).all().list();
}
public Student saveStudent(Student student) {
return dataManager.save(student);
}
public void deleteStudent(Student student) {
dataManager.remove(student);
}
}
CourseService.java
package ru.rsa.mcc.eduplatform.service;
import io.jmix.core.DataManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import ru.rsa.mcc.eduplatform.model.course.Course;
import java.util.List;
@Service
public class CourseService {
@Autowired
private DataManager dataManager;
public List<Course> getAllCourses() {
return dataManager.load(Course.class).all().list();
}
public Course saveCourse(Course course) {
return dataManager.save(course);
}
public void deleteCourse(Course course) {
dataManager.remove(course);
}
}
REST контроллеры
StudentController.java
package ru.rsa.mcc.eduplatform.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import ru.rsa.mcc.eduplatform.model.user.Student;
import ru.rsa.mcc.eduplatform.service.StudentService;
import java.util.List;
@RestController
@RequestMapping("/api/students")
public class StudentController {
@Autowired
private StudentService studentService;
@GetMapping
public List<Student> getAllStudents() {
return studentService.getAllStudents();
}
@PostMapping
public Student createStudent(@RequestBody Student student) {
return studentService.saveStudent(student);
}
@DeleteMapping("/{id}")
public void deleteStudent(@PathVariable String id) {
Student student = studentService.getAllStudents().stream()
.filter(s -> s.getId().toString().equals(id))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Student not found"));
studentService.deleteStudent(student);
}
}
CourseController.java
package ru.rsa.mcc.eduplatform.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import ru.rsa.mcc.eduplatform.model.course.Course;
import ru.rsa.mcc.eduplatform.service.CourseService;
import java.util.List;
@RestController
@RequestMapping("/api/courses")
public class CourseController {
@Autowired
private CourseService courseService;
@GetMapping
public List<Course> getAllCourses() {
return courseService.getAllCourses();
}
@PostMapping
public Course createCourse(@RequestBody Course course) {
return courseService.saveCourse(course);
}
@DeleteMapping("/{id}")
public void deleteCourse(@PathVariable String id) {
Course course = courseService.getAllCourses().stream()
.filter(c -> c.getId().toString().equals(id))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Course not found"));
courseService.deleteCourse(course);
}
}
Объяснение:
Сервисный уровень: обрабатывает бизнес логику и взаимодействия с базой данных с помощью
DataManager
.Контроллеры REST: предоставляют конечные точки для операций CRUD с объектами Student и Course.
-
Конечные точки:
GET /api/students
: Извлечь всех студентов.POST /api/students
: Создать нового студента.DELETE /api/students/{id}
: Удалить студента по идентификатору.GET /api/courses
: Извлечь все курсы.POST /api/courses
: Создать новый курс.DELETE /api/courses/{id}
: Удалить курс по идентификатору.
Эти классы предоставляют базовый REST API для управления учащимися и курсами в вашем приложении Jmix. Вы можете расширить его, добавив дополнительные конечные точки и службы для других объектов по мере необходимости.
Генерация CRUD-экранов для сущностей
Пишем следующий запрос Jmix AI Assistant:
Сгенерировать CRUD-экраны для всех сущностей
Получаем такой ответ от Jmix AI Assistant:
Чтобы создать CRUD-экраны для всех объектов в Jmix, вы можете использовать Jmix Studio, которая предоставляет мастер создания представлений из шаблонов. Ниже приведено пошаговое руководство по созданию этих экранов с помощью Jmix Studio.
Пошаговое решение
-
Откройте Jmix Studio:
Запустите свой проект Jmix в IntelliJ IDEA с установленной Jmix Studio.
-
Перейдите к сущности:
В окне инструмента Jmix найдите сущность, для которой вы хотите создать CRUD-экраны.
-
Воспользуйтесь мастером создания представлений (View):
Щелкните правой кнопкой мыши на сущности и выберите
New
->View
.В качестве альтернативы вы можете выбрать сущность и нажать
Views
на верхней панели конструктора сущностей.
-
Выберите шаблон:
Мастер представит список шаблонов. Выберите подходящий шаблон для просмотра в режиме CRUD.
-
Настройте View:
Вы можете изменить автоматически созданные свойства View.
В пунктах меню
Entity list view fetch plan
иEntity detail view fetch
выберите данные, которые будут отображаться в представлениях. Вы можете использовать встроенные планы выборки или создать свои собственные.
-
Завершите работу Мастера:
Нажмите кнопку
Finish
, чтобы сгенерировать XML-дескриптор представления и контроллер представления.Файл пакета сообщений будет обновлен, и в главное меню будет добавлен новый пункт меню, если вы создаете list view.
-
Настройка представлений:
Используйте конструктор представлений для дальнейшей настройки ваших представлений по мере необходимости.
Пример сгенерированного кода
Вот пример того, как может выглядеть сгенерированное представление списка для сущности Student
:
student-list-view.xml
<view xmlns="http://jmix.io/schema/flowui/view">
<data>
<collection id="studentsDc"
class="ru.rsa.mcc.eduplatform.model.user.Student"
fetchPlan="_base">
<loader id="studentsDl">
<query>
<![CDATA[select e from Student e]]>
</query>
</loader>
</collection>
</data>
<facets>
<dataLoadCoordinator auto="true"/>
</facets>
<layout>
<hbox id="buttonsPanel" classNames="buttons-panel">
<button id="createBtn" action="studentsDataGrid.create"/>
<button id="editBtn" action="studentsDataGrid.edit"/>
<button id="removeBtn" action="studentsDataGrid.remove"/>
</hbox>
<dataGrid id="studentsDataGrid"
width="100%"
minHeight="20em"
dataContainer="studentsDc">
<actions>
<action id="create" type="list_create"/>
<action id="edit" type="list_edit"/>
<action id="remove" type="list_remove"/>
</actions>
<columns>
<column property="username"/>
<column property="email"/>
<column property="studentId"/>
<column property="enrollmentDate"/>
</columns>
</dataGrid>
</layout>
</view>
StudentListView.java
package ru.rsa.mcc.eduplatform.view.student;
import io.jmix.flowui.view.*;
import ru.rsa.mcc.eduplatform.model.user.Student;
@ViewController("student-list-view")
@ViewDescriptor("student-list-view.xml")
@Route("students")
public class StudentListView extends StandardListView<Student> {
}
Объяснение:
Мастер создания представлений: Мастер Jmix Studio упрощает создание экранов CRUD, предоставляя шаблоны и параметры конфигурации.
Настройка: После создания экранов вы можете настроить их с помощью конструктора представлений.
Сгенерированный код: Сгенерированный код: В примере показано представление list view для сущности
Student
, включая табличное представление данных с действиями по созданию, редактированию и удалению сущностей.
Такой подход позволяет вам быстро создавать и настраивать CRUD-экраны для всех ваших объектов в приложении Jmix.
Источники:
Заключение
В рамках этой заметки описаны эксперименты по разработке кода с помощью Jmix AI Assistant, включая следующие:
Генерация класса, заполняющего доменную модель тестовыми данными
Реализация REST API для модели домена, включая создание контроллеров и REST сервисов
Генерация CRUD-экранов пользовательского интерфейса
Код, сгенерированный Jmix AI Assistant, вполне работоспособный. Естественно хотелось бы чтобы Jmix AI Assistant был интегрирован в Jmix Studio.
В статье Jmix AI Assistant — ваш помощник в освоении Jmix озвучены планы разработчиков:
Далее мы планируем интегрировать ассистента в Jmix Studio. Он сможет по простым запросам создавать сущности, экраны и добавлять компоненты: «Сделай экраны для этой сущности», «Добавь слушатели для кнопки». Возможно, добавим голосовой ввод команд.