K-Duck-Core
Структура фреймворка
K-Duck — это открытый и бесплатный фреймворк для разработки на основе Spring MVC, Spring и Spring JdbcTemplate. Он позволяет быстро создавать функциональные модули в соответствии с требованиями проекта. В отличие от других фреймворков, K-Duck инкапсулирует данные таблиц в виде объектов и полностью берёт на себя управление доступом к данным. Разработчикам не нужно писать код для DAO-слоя, а также создавать SQL-запросы в текстовом виде. Это снижает требования к навыкам написания SQL и уменьшает вероятность ошибок.
В бизнес-слое предоставляется гибкий набор реализаций по умолчанию для сервисов, что позволяет избежать дублирования кода и абстрагировать конкретные бизнес-объекты на более высокий уровень. Это обеспечивает универсальность и расширяемость бизнес-объектов для различных сценариев использования. Абстрактный дизайн также предоставляет возможности для управления аспектами и контроля.
Технологии нижнего уровня
Архитектура фреймворка
Хотя фреймворк следует традиционной многоуровневой структуре (пользовательский интерфейс, бизнес-логика и доступ к данным), он инкапсулирует некоторые общие и повторяющиеся логики. Разработчики могут сосредоточиться на написании кода для конкретной бизнес-логики.
Рисунок слева: Фреймворк инкапсулирует информацию о таблицах в объекты. Определяются конкретные классы объектов: определение сущности данных. В будущем планируется расширить функциональность, включая поддержку JSON-данных и отдельных функций обслуживания. Благодаря объектной модели для таблиц, обеспечивается поддержка на уровне полей и возможность создания унифицированных объектов доступа к данным.
Рисунок в центре: Изменения в структуре не влияют на разделение уровней. Однако параметры интерфейса и все бизнес-объекты были абстрагированы на более высокий уровень, чтобы обеспечить универсальность. Все переданные параметры и возвращённые объекты являются объектами ValueMap или ValueMapList (исключая объекты слоя данных, которые являются ValueBean). Это позволяет использовать их в качестве универсальных бизнес-объектов во всех сценариях. Однако это может усложнить контроль над разработкой. Поэтому фреймворк обеспечивает целостность данных и поддерживает проверку существования свойств. Также поддерживается форма Bean для объектов Map, которая сохраняет все характеристики Map и позволяет разработчикам работать с ними как с традиционными бизнес-Bean.
Рисунок справа: Доступ к данным управляется фреймворком (JdbcDao). Разработчики обычно не используют этот объект напрямую, а обращаются к реализации по умолчанию (DefaultService) для доступа к данным. Этот объект содержит общие операции доступа к данным, такие как добавление данных, пакетное добавление, удаление по первичному ключу, удаление по внешнему ключу, обновление по первичному ключу и обновление по внешнему ключу. Для запросов с условиями предоставляется специальный интерфейс QueryCreator. Если реализация по умолчанию не удовлетворяет требованиям бизнеса, необходимо наследовать этот интерфейс и расширять методы. Независимо от метода, разработчики должны вызывать только методы реализации по умолчанию.
Таким образом, при отсутствии сложных бизнес-сценариев разработчикам не требуется писать код для доступа к данным и бизнес-логике, что сокращает объём работы и позволяет сосредоточиться на логическом программировании.
Использование фреймворка
Настройка среды
Сначала создайте новый проект Maven с помощью IDE. Добавьте зависимость kduck-core в файл pom.xml:
<dependency>
<groupId>cn.kduck</groupId>
<artifactId>kduck-core</artifactId>
<version>1.1.0</version>
</dependency>
Создание проекта может занять некоторое время из-за загрузки зависимостей.
Затем создайте пакет com.goldgov и внутри него файл Java для запуска основной программы. Например, создайте файл Application.java (если основной класс находится в другом пакете, Spring должен сканировать пакет cn.kduck):
package cn.kduck;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Этот код аналогичен стандартному классу запуска Spring Boot.
Создайте файл конфигурации application.yml для проекта. Обратите внимание, что это стандартное имя файла конфигурации, которое не следует изменять. Настройте информацию о источнике данных (поскольку фреймворк автоматически сканирует таблицы для получения информации об объектах):
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/kduck_demo?useSSL=false&nullCatalogMeansCurrent=true&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
username: liuhg
password: liuhg317
Если вы хотите отключить сканирование таблиц при запуске, вы можете сделать это, но в этом примере мы будем использовать сканирование.
Для MySQL рекомендуется добавить параметры соединения: nullCatalogMeansCurrent = true & useInformationSchema = true. Первый параметр гарантирует получение точных данных пользователя, а второй — получение комментариев определения таблицы. Если при запуске возникают проблемы, попробуйте удалить второй параметр.
Это стандартная конфигурация Spring Boot, и вы можете обратиться к официальной документации Spring для дополнительной настройки.
Запустите программу, запустив Application. Вы увидите следующий экран, указывающий на успешный запуск:

Поскольку в базе данных нет таблиц данных, информация о сканировании таблиц не отображается в выводе запуска. В следующем разделе мы создадим демонстрационный модуль на основе этого пустого проекта.
Разработка модуля
Далее мы покажем, как использовать фреймворк для создания модуля на примере. Предположим, нам нужно создать модуль для студентов класса, который включает две таблицы: класс и ученик. Структура данных таблиц следующая:

Выполните следующие шаги для создания модуля:

Теперь мы можем заполнить каждый класс соответствующим кодом. Во фреймворке используются объекты ValueMap для инкапсуляции бизнес-данных. Однако для более сложных модулей использование ValueMap может привести к путанице. Чтобы решить эту проблему, фреймворк также поддерживает объекты Bean, сохраняя при этом характеристики ValueMap. Таким образом, наши классы ClassInfo и StudentInfo будут выглядеть следующим образом: createQuery: создать объект QuerySupport, который может получить используемый в реальности объект Query.
Обычно используется SelectBuilder для создания. В следующих разделах будет подробно описано использование SelectBuilder.
Пример кода означает, что нужно выполнить запрос к сущности CLASS_INFO и поддерживать возможность выполнения неточного запроса по className (название класса).
Необходимо объявить как Spring Bean.
В заголовке класса необходимо добавить аннотацию @Component.
Причина, по которой объект запроса был выделен в отдельный компонент, заключается в том, что логика запроса имеет определённую ценность повторного использования, и её можно применять в различных местах.
Затем необходимо написать класс реализации интерфейса:
@Service
public class DemoServiceImpl extends DefaultService implements DemoService {
@Override
public void addClass(ClassInfo classInfo) {
super.add(CODE_CLASS,classInfo);
}
@Override
public void addStudent(Long classId, StudentInfo studentInfo) {
Assert.notNull(classId,"班级ID不能为null");
studentInfo.setClassId(classId);
super.add(CODE_STUDENT,studentInfo);
}
@Override
public void updateStudent(StudentInfo studentInfo) {
super.update(CODE_STUDENT,studentInfo);
}
@Override
public void deleteStudent(String[] studentId) {
super.delete(CODE_STUDENT,studentId);
}
@Override
public StudentInfo getStudent(String studentId) {
return super.getForBean(CODE_STUDENT,studentId,StudentInfo::new);
}
@Override
public List<StudentInfo> listStudent(String studentName, Page page) {
Map<String, Object> paramMap = ParamMap.create("studentName", studentName).toMap();
QuerySupport query = super.getQuery(DemoQuery.class, paramMap);
return super.listForBean(query,page,StudentInfo::new);
}
}
Здесь мы видим некоторые отличия от обычного написания классов реализации Service. Во-первых, класс наследуется от класса DefaultService, который предоставляет инкапсуляцию операций доступа к данным Dao и охватывает большинство общих операций доступа к данным. Поэтому мы можем видеть, что при выполнении операций добавления, удаления, изменения и запроса нам не нужно писать слишком много логики кода и внедрять конкретные Dao.
Во всех методах интерфейса используются методы, предоставляемые классом DefaultService. В интерфейсе определены значения кодирования, которые почти всегда используются во всех методах для представления объектов данных перед операциями.
Для метода запроса, поскольку используется объект ValueMap в форме Bean, результаты могут быть преобразованы с помощью метода xxxForBean. Для получения дополнительной информации о других интерфейсах и методах использования вы можете обратиться к документации по другим методам в классе DefaultService.
Наконец, необходимо написать код DemoController. В контроллере необходимо внедрить интерфейс DemoService и напрямую использовать конечный код, подобный следующему:
@RestController
@RequestMapping("/example")
@Api(tags="示例模块")
public class DemoController {
private DemoService demoService;
@Autowired
public DemoController(DemoService demoService){
this.demoService = demoService;
}
@PostMapping("/class/add")
@ApiOperation("添加班级")
@ApiParamRequest({
@ApiField(name="className",value="班级名称"),
@ApiField(name="classNo",value="班号")
})
public JsonObject addClass(ClassInfo classInfo) {
demoService.addClass(classInfo);
return JsonObject.SUCCESS;
}
@PostMapping("/student/add")
@ApiOperation("添加学生信息")
@ApiParamRequest({
@ApiField(name="classId",value="班级ID"),
@ApiField(name="name",value="学生姓名"),
@ApiField(name="gender",value="学生性别(1男,2女)",allowableValues = "1,2"),
@ApiField(name="studentNo",value="学号")
})
public JsonObject addStudent(Long classId,StudentInfo studentInfo) {
demoService.addStudent(classId,studentInfo);
return JsonObject.SUCCESS;
}
@PutMapping("/student/update")
@ApiOperation("更新学生信息")
@ApiParamRequest({
@ApiField(name="studentId",value="学生ID"),
@ApiField(name="name",value="学生姓名"),
@ApiField(name="gender",value="学生性别(1男,2女)",allowableValues = "1,2"),
@ApiField(name="studentNo",value="学号")
})
public JsonObject updateStudent(StudentInfo studentInfo) {
demoService.updateStudent(studentInfo);
return JsonObject.SUCCESS;
}
@PutMapping("/student/delete")
@ApiOperation("删除学生信息")
@ApiParamRequest({
@ApiField(name="ids",value="学生ID",allowMultiple = true)
})
public JsonObject deleteStudent(@RequestParam("ids") String[] ids) {
demoService.deleteStudent(ids);
return JsonObject.SUCCESS;
}
@PutMapping("/student/get")
@ApiOperation("查看学生信息")
@ApiParamRequest({
@ApiField(name="studentId",value="学生ID")
})
@ApiJsonResponse({
@ApiField(name="studentId",value="学生ID"),
@ApiField(name="name",value="学生姓名"),
@ApiField(name="gender",value="学生性别(1男,2女)",allowableValues = "1,2"),
@ApiField(name="studentNo",value="学号")
})
public JsonObject
``` Вот перевод текста на русский язык:
Это стандартный способ написания контроллера с добавлением аннотаций Swagger. С точки зрения кода, в нём практически нет ничего особенного. Аннотации @ApiJsonResponse и @ApiField являются расширениями фреймворка. Поскольку объект JsonObject содержит только стандартные структуры свойств, он не может правильно и точно отражать структуру возвращаемых данных JSON. Эти две аннотации позволяют отобразить структуру JSON в интерфейсе Swagger.
После создания таблицы данных и повторного запуска приложения, можно увидеть информацию о сканировании таблицы данных в журнале запуска:
>Поскольку здесь представлен только бэкэнд-интерфейсный сервис и отсутствует интегрированная страница, вы можете протестировать интерфейс через Swagger (http://localhost:8080/swagger-ui.html):
**О конструкторе запросов**
SelectBuilder — это конструктор для построения запросов. Он позволяет инкапсулировать часть SQL-запросов в конструктор, что способствует оптимизации логики SQL-инъекций. SelectBuilder часто используется в реализации интерфейса QueryCreator. Интерфейс предоставляет метод, который принимает объект репозитория сущностей для удобства получения объекта определения сущности. Это необходимо, поскольку конструктор требует предоставления объекта сущности при построении запроса. Затем вызывается метод where() для начала условий и, наконец, метод build() возвращает объект QuerySupport.
Ниже представлена диаграмма последовательности вызовов методов SelectBuilder, которая включает основные методы SQL-сборки:
Далее следует базовый пример использования SelectBuilder:
```java
// Подготавливаем карту значений параметров запроса
Map<String, Object> paramMap = ParamMap.create("userName", "刚").set("age","20").toMap();
// Создаём конструктор запросов
SelectBuilder sqlBuiler = new SelectBuilder(paramMap);
// Связываем два поля запроса, которые должны быть возвращены (все поля из a-псевдонима таблицы и все поля из b-псевдонима, кроме поля userId)
sqlBuiler.bindFields("a",userEntityDef.getFieldList())
.bindFields("b", BeanDefUtils.excludeField(orgUserEntityDef.getFieldList(),"userId"));
// Сначала строим запрос к таблице и связываем их (первый параметр — псевдоним, второй — объект сущности, соответствующей таблице), затем строим условие запроса
sqlBuiler.from("a",userEntityDef).innerJoin("b",orgUserEntityDef)
.where()
.and("a.USER_NAME", ConditionType.BEGIN_WITH,"userName")
.or("a.AGE", ConditionType.IS_NOT_EMPTY);
// Этот запрос требует подсчёта количества полей
sqlBuiler.bindAggregate("a.USER_NAME", AggregateType.COUNT);
QuerySupport querySupport = sqlBuiler.build();
Окончательный сформированный SQL-запрос выглядит следующим образом:
SELECT a.USER_ID,a.USER_NAME,a.GENDER,a.BIRTHDAY,COUNT(a.AGE) AS AGE,a.ENABLE,b.ORG_USER_ID,b.ORG_ID FROM DEMO_USER a INNER JOIN DEMO_ORG_USER b ON a.USER_ID=b.USER_ID WHERE a.USER_NAME LIKE ? OR (a.AGE IS NOT NULL AND a.AGE !='')
Параметр: «刚%».
Мы будем постепенно улучшать этот проект. Если у вас есть какие-либо вопросы о K-Duck Framework, пожалуйста, напишите нам по адресу lhg_0317@163.com.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )