realizados cambios en el docker

This commit is contained in:
Jaime Jiménez
2025-06-13 11:56:51 +02:00
parent ff586804bf
commit b7ef46b8cb
18 changed files with 556 additions and 0 deletions

8
.env Normal file
View File

@ -0,0 +1,8 @@
# Base de datos MySQL
MYSQL_DATABASE=printhub
MYSQL_ROOT_PASSWORD=8FOc7XQrUWEtwgiDKppfcv2LWo
# Spring Boot datasource
SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/miappdb?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
SPRING_DATASOURCE_USERNAME=printhub
SPRING_DATASOURCE_PASSWORD=DsomyTF4NjTtwzGTTWaxoUEvIt

8
Dockerfile.dev Normal file
View File

@ -0,0 +1,8 @@
FROM eclipse-temurin:24-jdk
# Instala Maven si lo necesitas (si usas ./mvnw, esto es opcional)
RUN apt-get update && apt-get install -y maven
WORKDIR /app
EXPOSE 8080

34
docker-compose.yml Normal file
View File

@ -0,0 +1,34 @@
services:
mysql:
image: mysql:8.0
container_name: mysql
command: --default-authentication-plugin=mysql_native_password
environment:
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_USER: ${SPRING_DATASOURCE_USERNAME}
MYSQL_PASSWORD: ${SPRING_DATASOURCE_PASSWORD}
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
app:
build:
context: .
dockerfile: Dockerfile.dev
container_name: springboot-dev
command: ./mvnw spring-boot:run
volumes:
- ./:/app
ports:
- "8080:8080"
depends_on:
- mysql
environment:
SPRING_DATASOURCE_URL: ${SPRING_DATASOURCE_URL}
SPRING_DATASOURCE_USERNAME: ${SPRING_DATASOURCE_USERNAME}
SPRING_DATASOURCE_PASSWORD: ${SPRING_DATASOURCE_PASSWORD}
volumes:
mysql-data:

View File

@ -0,0 +1,13 @@
package com.printhub.printhub;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class PrintHubApplication {
public static void main(String[] args) {
SpringApplication.run(PrintHubApplication.class, args);
}
}

View File

@ -0,0 +1,40 @@
package com.printhub.printhub.config;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.LinkedHashSet;
import java.util.Set;
@Component
public class I18nBaseNameProvider {
public String[] getBaseNames() {
Set<String> baseNames = new LinkedHashSet<>();
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
// Busca todos los .properties bajo i18n/*/*.properties
var resources = resolver.getResources("classpath*:/i18n/*/*.properties");
for (var res : resources) {
String uri = res.getURI().toString();
// Extraer ruta base sin extensión .properties ni sufijos como _en
String base = uri
.replaceAll(".*?/i18n/", "i18n/")
.replaceAll("(_[a-zA-Z]+)?\\.properties$", "")
.replace(".jar!", ""); // por si viene de un jar
// Eliminar duplicados con un Set
baseNames.add("classpath:" + base);
}
} catch (IOException e) {
e.printStackTrace(); // o usa logger
}
return baseNames.toArray(new String[0]);
}
}

View File

@ -0,0 +1,58 @@
package com.printhub.printhub.config;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import java.util.Locale;
@Configuration
public class I18nConfig {
private final I18nBaseNameProvider baseNameProvider;
public I18nConfig(I18nBaseNameProvider baseNameProvider) {
this.baseNameProvider = baseNameProvider;
}
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
String[] baseNames = baseNameProvider.getBaseNames();
messageSource.setBasenames(baseNames);
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver resolver = new SessionLocaleResolver();
resolver.setDefaultLocale(Locale.forLanguageTag("es"));
return resolver;
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
interceptor.setParamName("lang");
return interceptor;
}
@Bean
public WebMvcConfigurer webMvcConfigurer(LocaleChangeInterceptor interceptor) {
return new WebMvcConfigurer() {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor);
}
};
}
}

View File

@ -0,0 +1,21 @@
package com.printhub.printhub.controller.config;
import com.printhub.printhub.service.I18nService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
@RequestMapping("/api/lang")
public class I18nController {
@Autowired
private I18nService i18nService;
@GetMapping
public Map<String, String> getLanguage(@RequestParam(defaultValue = "es") String lang) {
return i18nService.getTranslations(lang);
}
}

View File

@ -0,0 +1,23 @@
package com.printhub.printhub.controller.home;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.Locale;
@Controller
public class HomeController {
@Autowired
private MessageSource messageSource;
@GetMapping("/")
public String index(Model model, Locale locale) {
model.addAttribute("title", messageSource.getMessage("t-home", null, locale));
return "printhub/home";
}
}

View File

@ -0,0 +1,36 @@
package com.printhub.printhub.service;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.*;
@Service
public class I18nService {
public Map<String, String> getTranslations(String lang) {
Map<String, String> translations = new HashMap<>();
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
var resources = resolver.getResources("classpath:i18n/" + lang + "/*.properties");
for (var resource : resources) {
Properties props = new Properties();
try (var reader = new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8)) {
props.load(reader);
for (String key : props.stringPropertyNames()) {
translations.put(key, props.getProperty(key));
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return translations;
}
}

View File

@ -0,0 +1,24 @@
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{printhub/layout}">
<th:block layout:fragment="pagetitle">
<!--page title-->
<div th:replace="~{printhub/partials/title-meta :: title-meta(${title})}"></div>
</th:block>
<head>
</head>
<body>
<div layout:fragment="content">
<!-- start page title -->
<div th:replace="~{printhub/partials/page-title :: page-title(${title},'Pages')}"></div>
</div>
<th:block layout:fragment="pagejs">
</th:block>
</body>
</html>

View File

@ -0,0 +1,37 @@
<html lang="en" data-layout="semibox" data-sidebar-visibility="show" data-topbar="light" data-sidebar="light" data-sidebar-size="lg" data-sidebar-image="none" data-preloader="disable" xmlns="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<th:block layout:fragment="pagetitle" />
<!-- Page CSS -->
<div th:replace="~{theme/partials/head-css :: head-css}"></div>
</head>
<body data-sidebar="dark" data-layout-mode="light">
<div id="layout-wrapper">
<div th:replace="~{printhub/partials/topbar :: topbar}"></div>
<div th:replace="~{printhub/partials/sidebar :: sidebar}"></div>
<div class="main-content">
<div class="page-content">
<div class="container-fluid">
<section layout:fragment="content" th:remove="tag">
</section>
</div>
</div>
<div th:replace="~{printhub/partials/footer :: footer}"></div>
</div>
</div>
<th:block layout:fragment="modal" />
<div th:replace="~{theme/partials/vendor-scripts :: scripts}"></div>
<th:block layout:fragment="pagejs" />
<!-- App js -->
<script th:src="@{/assets/js/app.js}"></script>
</body>
</html>

View File

@ -0,0 +1,22 @@
<html>
<body>
<div th:fragment="footer" th:remove="tag">
<footer class="footer">
<div class="container-fluid">
<div class="row">
<div class="col-sm-6">
<script>document.write(new Date().getFullYear())</script> © PrintHub.
</div>
<div class="col-sm-6">
<div class="text-sm-end d-none d-sm-block">
Design & Develop by IMN & JJO
</div>
</div>
</div>
</div>
</footer>
</div>
</body>
</html>

View File

@ -0,0 +1,25 @@
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div th:fragment="page-title(title,pagetitle)" th:remove="tag">
<!-- start page title -->
<div class="row">
<div class="col-12">
<div class="page-title-box d-sm-flex align-items-center justify-content-between">
<h4 data-key="t-home" class="mb-sm-0" th:text="${title}"></h4>
<div class="page-title-right">
<ol class="breadcrumb m-0">
<li class="breadcrumb-item"><a href="javascript: void(0);" th:text="${pagetitle}"></a></li>
<li class="breadcrumb-item active" data-key="t-home" th:text="${title}"></li>
</ol>
</div>
</div>
</div>
</div>
<!-- end page title -->
</div>
</body>
</html>

View File

@ -0,0 +1,53 @@
<html >
<body>
<div th:fragment="sidebar" th:remove="tag">
<!-- ========== App Menu ========== -->
<div class="app-menu navbar-menu">
<!-- LOGO -->
<div class="navbar-brand-box">
<!-- Dark Logo-->
<a href="/" class="logo logo-dark">
<span class="logo-sm">
<img src="/assets/images/logo-sm.png" alt="" height="22">
</span>
<span class="logo-lg">
<img src="/assets/images/logo-dark.png" alt="" height="17">
</span>
</a>
<!-- Light Logo-->
<a href="/" class="logo logo-light">
<span class="logo-sm">
<img src="/assets/images/logo-sm.png" alt="" height="22">
</span>
<span class="logo-lg">
<img src="/assets/images/logo-light.png" alt="" height="17">
</span>
</a>
<button type="button" class="btn btn-sm p-0 fs-20 header-item float-end btn-vertical-sm-hover"
id="vertical-hover">
<i class="ri-record-circle-line"></i>
</button>
</div>
<div id="scrollbar">
<div class="container-fluid">
<div id="two-column-menu">
</div>
<ul class="navbar-nav" id="navbar-nav">
<div th:replace="~{printhub/partials/sidebarMenus/configurationMenu :: configuration}"></div>
</ul>
</div>
<!-- Sidebar -->
</div>
<div class="sidebar-background"></div>
</div>
<!-- Left Sidebar End -->
<!-- Vertical Overlay-->
<div class="vertical-overlay"></div>
</div>
</body>
</html>

View File

@ -0,0 +1,17 @@
<div th:fragment="configuration" th:remove="tag">
<li class="menu-title"><span data-key="t-menu">Menu</span></li>
<li class="nav-item">
<a class="nav-link menu-link" href="#configurationMenu" data-bs-toggle="collapse" role="button"
aria-expanded="false" aria-controls="configurationMenu">
<i class="ri-tools-line"></i> <span data-key="t-menu-config">Configuración</span>
</a>
<div class="collapse menu-dropdown" id="configurationMenu">
<ul class="nav nav-sm flex-column">
<li class="nav-item">
<a href="/configuration/printers" class="nav-link" data-key="t-menu-config-impresioras">
Impresoras </a>
</li>
</ul>
</div>
</li> <!-- end Dashboard Menu -->
</div>

View File

@ -0,0 +1,14 @@
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<body>
<div th:fragment="title-meta(title)" th:remove="tag">
<meta charset="utf-8" />
<title th:text="${title} + ' | PrintHub'"></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta content="Servicion de impresión personal" name="description" />
<!-- App favicon -->
<link rel="shortcut icon" href="/assets/images/favicon.ico">
</div>
</body>
</html>

View File

@ -0,0 +1,110 @@
<html>
<body>
<div th:fragment="topbar" th:remove="tag">
<header id="page-topbar">
<div class="layout-width">
<div class="navbar-header">
<div class="d-flex">
<!-- LOGO -->
<div class="navbar-brand-box horizontal-logo">
<a href="/" class="logo logo-dark">
<span class="logo-sm">
<img src="/assets/images/logo-sm.png" alt="" height="22">
</span>
<span class="logo-lg">
<img src="/assets/images/logo-dark.png" alt="" height="17">
</span>
</a>
<a href="/" class="logo logo-light">
<span class="logo-sm">
<img src="/assets/images/logo-sm.png" alt="" height="22">
</span>
<span class="logo-lg">
<img src="/assets/images/logo-light.png" alt="" height="17">
</span>
</a>
</div>
<button type="button" class="btn btn-sm px-3 fs-16 header-item vertical-menu-btn topnav-hamburger" id="topnav-hamburger-icon">
<span class="hamburger-icon">
<span></span>
<span></span>
<span></span>
</span>
</button>
</div>
<div class="d-flex align-items-center">
<div class="dropdown ms-1 topbar-head-dropdown header-item">
<button type="button" class="btn btn-icon btn-topbar btn-ghost-secondary rounded-circle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<img id="header-lang-img" src="/assets/images/flags/us.svg" alt="Header Language" height="20" class="rounded">
</button>
<div class="dropdown-menu dropdown-menu-end">
<!-- item-->
<a href="javascript:void(0);" class="dropdown-item notify-item language" data-lang="es" title="Spanish">
<img src="/assets/images/flags/spain.svg" alt="user-image" class="me-2 rounded" height="18">
<span class="align-middle">Español</span>
</a>
<!-- item-->
<a href="javascript:void(0);" class="dropdown-item notify-item language py-2" data-lang="en" title="English">
<img src="/assets/images/flags/gb.svg" alt="user-image" class="me-2 rounded" height="18">
<span class="align-middle">English</span>
</a>
</div>
</div>
<div class="ms-1 header-item d-none d-sm-flex">
<button type="button" class="btn btn-icon btn-topbar btn-ghost-secondary rounded-circle" data-toggle="fullscreen">
<i class='bx bx-fullscreen fs-22'></i>
</button>
</div>
<div class="ms-1 header-item d-none d-sm-flex">
<button type="button" class="btn btn-icon btn-topbar btn-ghost-secondary rounded-circle light-dark-mode">
<i class='bx bx-moon fs-22'></i>
</button>
</div>
<div class="dropdown ms-sm-3 header-item topbar-user">
<button type="button" class="btn" id="page-header-user-dropdown" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="d-flex align-items-center">
<img class="rounded-circle header-profile-user" src="/assets/images/users/avatar-1.jpg" alt="Header Avatar">
<span class="text-start ms-xl-2">
<span class="d-none d-xl-inline-block ms-1 fw-medium user-name-text">Anna Adame</span>
<span class="d-none d-xl-block ms-1 fs-12 text-muted user-name-sub-text">Founder</span>
</span>
</span>
</button>
<div class="dropdown-menu dropdown-menu-end">
<!-- item-->
<h6 class="dropdown-header">Welcome Anna!</h6>
<a class="dropdown-item" href="/pages-profile"><i class="mdi mdi-account-circle text-muted fs-16 align-middle me-1"></i> <span class="align-middle">Profile</span></a>
<a class="dropdown-item" href="/apps-chat"><i class="mdi mdi-message-text-outline text-muted fs-16 align-middle me-1"></i> <span class="align-middle">Messages</span></a>
<a class="dropdown-item" href="/apps-tasks-kanban"><i class="mdi mdi-calendar-check-outline text-muted fs-16 align-middle me-1"></i> <span class="align-middle">Taskboard</span></a>
<a class="dropdown-item" href="/pages-faqs"><i class="mdi mdi-lifebuoy text-muted fs-16 align-middle me-1"></i> <span class="align-middle">Help</span></a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="/pages-profile"><i class="mdi mdi-wallet text-muted fs-16 align-middle me-1"></i> <span class="align-middle">Balance : <b>$5971.67</b></span></a>
<a class="dropdown-item" href="/pages-profile-settings"><span class="badge bg-soft-success text-success mt-1 float-end">New</span><i class="mdi mdi-cog-outline text-muted fs-16 align-middle me-1"></i> <span class="align-middle">Settings</span></a>
<a class="dropdown-item" href="auth-lockscreen-basic"><i class="mdi mdi-lock text-muted fs-16 align-middle me-1"></i> <span class="align-middle">Lock screen</span></a>
<a class="dropdown-item" href="auth-logout-basic"><i class="mdi mdi-logout text-muted fs-16 align-middle me-1"></i> <span class="align-middle" data-key="t-logout">Logout</span></a>
</div>
</div>
</div>
</div>
</div>
</header>
</div>
</body>
</html>

View File

@ -0,0 +1,13 @@
package com.printhub.printhub;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class PrinthubApplicationTests {
@Test
void contextLoads() {
}
}