docs: detailed comments; fix: var declarations, no DROP, text inputs

This commit is contained in:
2026-07-20 08:13:26 +04:00
parent 53e12ecddd
commit d0fb4df1cb
2 changed files with 169 additions and 23 deletions
+112 -16
View File
@@ -1,67 +1,163 @@
<!---
Application.cfc — конфигурация Lucee CRUD-приложения
Жизненный цикл:
1. OnApplicationStart — вызывается ОДИН раз при старте приложения
- читает TABLE_NAME из env vars (json_env в Terraform)
- создаёт таблицу CREATE TABLE IF NOT EXISTS
- сохраняет имя таблицы в application.tableName
2. OnRequestStart — вызывается ПЕРЕД каждым запросом
- копирует application.tableName → request.tableName
3. OnRequest — вызывает index.cfm с CRUD-логикой
Datasource: testds, конфигурируется из env vars с префиксом testds_
(testds_class, testds_connectionString, testds_username, testds_password, ...)
Terraform json_env должен содержать:
- TABLE_NAME — имя таблицы (по умолчанию check_point)
- testds_class — JDBC-драйвер
- testds_connectionString — строка подключения к PostgreSQL
- testds_username — имя пользователя БД
- testds_password — пароль пользователя БД
--->
<cfcomponent displayname="Application" output="true">
<!--- Идентификатор приложения для Lucee --->
<cfset this.Name = "tfluceecrud" />
<!--- Таймаут приложения: 3 часа бездействия → перезапуск (вызовет OnApplicationStart заново) --->
<cfset this.applicationTimeout = createTimeSpan(0, 0, 3, 0) />
<!--- Включаем сессии для защиты от CSRF (Lucee автоматически добавляет токены) --->
<cfset this.sessionmanagement = "Yes" />
<!--- Сессия живёт 2 часа неактивности --->
<cfset this.sessiontimeout = CreateTimeSpan(0, 0, 120, 0) />
<!--- Имя datasource по умолчанию — используется в cfquery без атрибута datasource --->
<cfset this.datasource = "testds" />
<!--- Конфигурируем datasource из env vars с префиксом testds_ --->
<cfset getDS(this.datasource, this.datasource) />
<!--- Отключаем отладку на проде, таймаут запроса 20 секунд --->
<cfsetting requesttimeout="20" showdebugoutput="false" />
<cffunction name="OnApplicationStart" access="public" returntype="boolean">
<cfreturn true />
</cffunction>
<cffunction name="OnRequestStart" access="public" returntype="boolean">
<cfset request.tableName = createObject("java", "java.lang.System").getEnv().get("TABLE_NAME") />
<cfif NOT isDefined("request.tableName") OR NOT len(request.tableName)>
<cfset request.tableName = "check_point" />
<!---
OnApplicationStart — выполняется ОДИН раз при старте приложения.
Здесь: создаём таблицу если её нет, сохраняем имя в application scope.
application scope — живёт пока приложение не перезапустится (таймаут 3 часа).
Используем application а не request потому что request умирает после каждого запроса.
--->
<cffunction name="OnApplicationStart" access="public" returntype="boolean">
<!--- 1. Читаем имя таблицы из переменной окружения TABLE_NAME --->
<cfset var tableName = createObject("java", "java.lang.System").getEnv().get("TABLE_NAME") />
<!--- 2. Если переменная не задана в json_env — используем значение по умолчанию --->
<cfif NOT isDefined("tableName") OR NOT len(tableName)>
<cfset tableName = "check_point" />
</cfif>
<!--- 3. Сохраняем в application scope — доступно всем запросам этого приложения --->
<cfset application.tableName = tableName />
<!--- 4. Создаём таблицу если она ещё не существует (IF NOT EXISTS) --->
<!--- id: автоинкрементный первичный ключ --->
<!--- value: текстовое поле для CRUD-значений --->
<cftry>
<cfquery>
DROP TABLE IF EXISTS #request.tableName#
</cfquery>
<cfquery>
CREATE TABLE #request.tableName# (
CREATE TABLE IF NOT EXISTS #tableName# (
id SERIAL PRIMARY KEY,
value TEXT NOT NULL DEFAULT ''
)
</cfquery>
<!--- Игнорируем ошибки: нет прав, таблица уже есть, БД недоступна --->
<cfcatch type="database"></cfcatch>
</cftry>
<cfreturn true />
</cffunction>
<!---
OnRequestStart — выполняется ПЕРЕД каждым HTTP-запросом.
Здесь: копируем имя таблицы из application в request scope.
request scope — живёт только в течение одного запроса.
Каждая страница (index.cfm) читает request.tableName.
--->
<cffunction name="OnRequestStart" access="public" returntype="boolean">
<!--- Если приложение уже стартовало — берём имя из application --->
<cfif isDefined("application.tableName")>
<cfset request.tableName = application.tableName />
<!--- Иначе (первый запрос до OnApplicationStart) — fallback --->
<cfelse>
<cfset request.tableName = "check_point" />
</cfif>
<cfreturn true />
</cffunction>
<!---
OnRequest — обработчик каждого запроса.
Включает целевой шаблон (index.cfm) с установленной кодировкой.
--->
<cffunction name="OnRequest" access="public" returntype="void">
<cfargument name="template" type="string" required="true" />
<!--- UTF-8 для форм и URL-параметров --->
<cfset setEncoding("FORM", "UTF-8") />
<cfset setEncoding("URL", "UTF-8") />
<!--- Вычисляем web-корень для ссылок --->
<cfset local.basePath = getDirectoryFromPath(getCurrentTemplatePath()) />
<cfset request.webRoot = "../" />
<cfset request.thisPage = Replace(ReplaceNoCase(expandPath(arguments.template), local.basePath, ""), "\", "/") />
<!--- Выполняем запрошенный шаблон (index.cfm) --->
<cfinclude template="#arguments.template#" />
</cffunction>
<cffunction name="getDS" access="private" returntype="void">
<cfargument name="dsname" type="string" required="true" />
<cfargument name="prefix" type="string" default="#dsname#" />
<cfset system = createObject("java", "java.lang.System") />
<!---
getDS — конфигурирует datasource Lucee из переменных окружения.
Соглашение об именах env vars:
{prefix}_{field} → параметр datasource
Пример для testds:
testds_class → JDBC-драйвер
testds_connectionString → jdbc:postgresql://host:5432/db
testds_username → пользователь
testds_password → пароль
Все параметры передаются через json_env в Terraform.
--->
<cffunction name="getDS" access="private" returntype="void">
<cfargument name="dsname" type="string" required="true" hint="Имя datasource (testds)" />
<cfargument name="prefix" type="string" default="#dsname#" hint="Префикс env vars" />
<!--- Java-объект для чтения переменных окружения --->
<cfset var system = createObject("java", "java.lang.System") />
<!--- Словарь параметров datasource --->
<cfset var ds = {} />
<!--- Перебираем все возможные поля datasource --->
<cfloop list="class,connectionString,username,password,bundleName,bundleVersion,connectionLimit,liveTimeout,validate" item="field">
<!--- Читаем env var: {prefix}_{field}, например testds_username --->
<cfset var value = system.getEnv("#arguments.prefix#_#field#") />
<!--- Если переменная задана и не пуста — добавляем в datasource --->
<cfif isDefined("value") AND len(value)>
<cfset structInsert(ds, field, value) />
</cfif>
</cfloop>
<!--- Регистрируем datasource в Lucee --->
<cfset THIS.datasources[dsname] = ds />
</cffunction>