В первой части статьи с помощью инструмента 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 для управления учащимися, курсами и связанными объектами.

Пошаговое решение

  1. Создание сервисного уровня:

    • Сервисы будут обрабатывать бизнес логику и взаимодействовать с базой данных с помощью DataManager.

  2. Создание контроллеров 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.

Пошаговое решение

  1. Откройте Jmix Studio:

    • Запустите свой проект Jmix в IntelliJ IDEA с установленной Jmix Studio.

  2. Перейдите к сущности:

    • В окне инструмента Jmix найдите сущность, для которой вы хотите создать CRUD-экраны.

  3. Воспользуйтесь мастером создания представлений (View):

    • Щелкните правой кнопкой мыши на сущности и выберите New -> View.

    • В качестве альтернативы вы можете выбрать сущность и нажать Viewsна верхней панели конструктора сущностей.

  4. Выберите шаблон:

    • Мастер представит список шаблонов. Выберите подходящий шаблон для просмотра в режиме CRUD.

  5. Настройте View:

    • Вы можете изменить автоматически созданные свойства View.

    • В пунктах меню Entity list view fetch plan и Entity detail view fetch выберите данные, которые будут отображаться в представлениях. Вы можете использовать встроенные планы выборки или создать свои собственные.

  6. Завершите работу Мастера:

    • Нажмите кнопку Finish, чтобы сгенерировать XML-дескриптор представления и контроллер представления.

    • Файл пакета сообщений будет обновлен, и в главное меню будет добавлен новый пункт меню, если вы создаете list view.

  7. Настройка представлений:

    • Используйте конструктор представлений для дальнейшей настройки ваших представлений по мере необходимости.

Пример сгенерированного кода

Вот пример того, как может выглядеть сгенерированное представление списка для сущности 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. Он сможет по простым запросам создавать сущности, экраны и добавлять компоненты: «Сделай экраны для этой сущности», «Добавь слушатели для кнопки». Возможно, добавим голосовой ввод команд. 

Комментарии (0)