¿Cómo añadir un nuevo concepto al core de Plataforma?
Conceptos básicos
Antes de empezar hay que tener claro la función de algunos de los módulos de la Plataforma:
config-model: librería donde se define nuestro modelo, las clases que luego se convierten en tablas en la configDB y sus Repository
config-init: módulo que se ejecuta solo una vez cuando se realiza la instalación o actualización del entorno y que crea todas las tablas en la configDB o las actualiza.
config-service: librería donde se definen los Services del config-model
controlpanel: módulo que contiene los controladores y la parte front, que se despliega y está accesible luego desde el navegador
management-apis: módulo que contiene las APIs de gestión, por cada controlador que existe en el controlpanel existe un controlador REST en este módulo.
cache-server: caché que tiene que levantarse para arrancar el management-apis
Por otro lado, la Plataforma cuenta con dos bases de datos:
ConfigDB: base de datos de configuración en la que se apoya toda la Plataforma y que puede ser un MariaDB o un PostgreSQL, aunque lo normal es que sea un MariaDB.
RealTimeDB: base de datos en tiempo real, aquí se guardan los datos de las entidades dadas de alta en la Plataforma y es un MongoDB
Añadir una opción al menú
Desde el controlpanel se puede modificar el menú de cada rol accediendo a la opción de menú ADMINISTRATION > Menu Management pero cuando se quiere añadir un nuevo concepto a Plataforma con su propia opción de menú lo que hay que hacer es tocar el módulo config-init para añadir esta nueva opción.
Para ello hay que tocar los archivos que se encuentran en src/main/resources/menu, hay un archivo JSON para cada rol y hay que meter la nueva opción de menú/submenu en el apartado correspondiente con sus internacionalizaciones, por ejemplo si se quiere meter un nuevo submenú en el menú APPS habría que añadir algo como esto, indicando también el endpoint al cual tiene que redirigir dicha opción de menú:
{
"id": "intelligence",
"title": {
"EN": "Intelligence",
"ES": "Inteligencia",
"FR": "Intelligence"
},
"icon": "",
"url": "/controlpanel/research/list",
"active": true
}Creación del modelo
Para este ejemplo se va a crear el concepto de Research y lo primero es crear el modelo de datos que se va a convertir en una nueva tabla/tablas en la ConfigDB.
Para crear este nuevo modelo hay que crear en el módulo config-model dentro del paquete com-minsait.onesait.platform.config.model una nueva clase Research que tiene que extender de OPResources. Al extender de OPResources ya están definidos los campos básicos como identification, description, createAt, updateAt… por lo que en la clase Research solo hay que meter los campos específicos de este concepto.
A continuacio se muestra un ejemplo de cómo tendría que definirse la clase Research y qué etiquetas hay que poner para que luego al ejecutar el config-init se cree la tabla en la ConfigDB:
@Configurable
@Entity
@EntityListeners({ AuditingEntityListener.class, VersioningListener.class, AuditEntityListener.class })
@Table(name = "RESEARCH")
public class Research extends OPResource {
private static final long serialVersionUID = 1L;
@Column(name = "FIELD1", length = 50, unique = false, nullable = false)
@NotNull
@Getter
@Setter
private String field1;
@Column(name = "FIELD2", length = 50, unique = false, nullable = false)
@NotNull
@Getter
@Setter
private String field2;
}Para saber si el modelo que hemos creado es válido basta con ejecutar el módulo config-init y verificar que se ha creado la tabla en la configDB.
Creación del Repository
Para poder acceder a los datos de la clase Research que se almacenan en la configDB es necesario crearse la interfaz ResearchRepository.java dentro del módulo config-model en el paquete com.minsait.onesait.platform.config.repository.
Esta interfaz tiene que extender de JpaRepository para que Spring sepa a qué modelo de la tabla tiene que apuntar para ejecutar las queries. En esta interfaz se definen los métodos con las queries que vamos a necesitar para las pantallas del CRUD o para los controladores. Al extender del Repository ya tenemos los métodos básicos y solo tendremos que dar de alta los métodos específicos que necesitemos con la query correspondiente.
A continuación se muestra un ejemplo de cómo podría quedar esta interfaz:
public interface ResearchRepository extends JpaRepository<Research, Long> {
Research findById(String id);
Research findByIdentification(String identification);
@Query("SELECT cp FROM Research cp WHERE cp.identification like %:identification%")
List<Research> findByIdentificationLike(@Param("identification") String identification);
List<Category> findByDescription(String description);
}Creación del Service
Por cada repository hay que crearse un Service, ya que desde los controladores web no debería nunca utilizarse dirctamente un repository, sino que todo tiene que hacerse a través del Service.
Para ello hay que crear un nuevo paquete com.minsait.onesait.platform.config.services.research en el módulo config-services que contenga la interfaz ResearchService y su implementación ResearchServiceImpl. Aquí es donde se van a definir todos los métodos que se van a necesitar desde el controlador para acceder a la configDB.
Si has definido todo bien, desde el service deberías utilizar la clase ResearchRepository para lanzar las consultas y desde el controlador sólo deberías utilizar el ResearchService.
Creación del controlador web
Una vez está definido el modelo lo siguiente sería crearse el controlador web dentro del módulo controlpanel. Para ello hay que crearse un nuevo paquete dentro del controlpanel com.minsait.onesait.platform.controlpanel.controller.research y dentro de dicho módulo la clase ResearchController.java que será el controlador web y donde estarán todos los métodos necesario para mostrar las pantallas y guardar los datos en la configDB.
Los métodos básicos que se suelen necesitar son:
list, para la tabla que liste todos los research
create, para acceder a la pantalla de creación
createResearch, para crear el research y guardarlo en la configDB
update, para acceder a la pantalla de edición
updateResearch, para editar el research y guardarlo en la configDB
delete, para eliminar el research
A continuación se muestra un ejemplo de controlador, recuerda que desde los controladores solo deberías de utilizar los services, nunca los repository.
@Controller
@RequestMapping("/research")
@Slf4j
public class ResearchController {
@Autowired
private ResearchService researchService;
@GetMapping(value = "/list", produces = "text/html")
public String list(Model model, HttpServletRequest request,
@RequestParam(required = false, name = "identification") String identification,
@RequestParam(required = false, name = "description") String description) {
//TODO list
return "categories/list";
}
@GetMapping(value = "/create")
public String create(Model model) {
//TODO create
return "categories/create";
}
@GetMapping(value = "/update/{id}", produces = "text/html")
public String update(Model model, @PathVariable("id") String id) {
//TODO update
return "categories/create";
}
@PostMapping(value = "/create")
public String createResearch(Model model, @Valid Research research, BindingResult bindingResult,
RedirectAttributes redirect, HttpServletRequest request) {
//TODO create
}
@PutMapping(value = "/update/{id}")
public String updateCategory(Model model, @PathVariable("id") String id, @Valid Category category,
BindingResult bindingResult, RedirectAttributes redirect, HttpServletRequest request) {
//TODO update
}
@GetMapping("/show/{id}")
public String show(Model model, @PathVariable("id") String id, RedirectAttributes redirect) {
//TODO show
}
@DeleteMapping("/{id}")
public String delete(Model model, @PathVariable("id") String id, RedirectAttributes redirect) {
//TODO delete
}
}Creación de las pantallas HTML
Es recomendable reutilizar o fijarse en pantallas ya existentes y que tengan una estructura similar a la que necesitamos. Por ejemplo, los listados suelen ser siempre iguales, por lo que ahorramos tiempo y trabajo si directamente copiamos un HTML similar y simplemente cambios los campos por los nuestros.
En Plataforma se utiliza Thymeleaf para la comunicación enter el controlador web y la pantalla HTML, puede consultar cómo funciona aquí.
Para cada concepto en Plataforma existe una carpeta en el controlpanel en src/main/resources/templates por lo que tendríamos que crearnos aquí la carpeta research y dentro los HTMLs que necesitemos (list, create, show..)
A la hora de crear las pantallas hay que tener varias cosas en cuenta:
El uso de thymeleaf para interactuar con los controladores
El uso de internacionalización, en Plataforma trabajamos con los idiomas español, inglés y francés. Para cada idioma hay un fichero .properties en src/main/resources/i18n por lo que todos los literales que metamos en las pantallas tienen que estar definidos en estos ficheros y luego referenciados con las etiquetas correspondientes en el HTML. Es recomendable reutilizar los literales genéricos, por ejemplo para los botones de cancelar, guardar…
Toda la lógica Javascript debería estar externalizada a un fichero .js que se define en src/main/resources/static/js/pages. Este dichero es importado como librería al HTML.
Hay que seguir una misma estética, por lo que es recomendable fijarse en las pantallas ya existentes y seguir el mismo estilo, como por ejemplo, donde poner los botones de guarda y cancelar y cosas similares.
Añadir concepto a las Aplicaciones
Una vez está creado el concepto nuevo y la funcionalidad está funcionando correctamante, hay que añadir este concepto a las Aplicaciones de la Plataforma.
Las Aplicaciónes son entorno colaborativos donde varios usuarios pueden desarrollar soluciones sobre la Plataforma.
Añadir a la clase OPResources un nuevo enumerado, en este caso RESEARCH
Modificar el create.html de projects para añadir este nuevo concepto
Añadir versionado siguiendo esta guía