2021-08-16

This commit is contained in:
2021-08-16 13:47:25 +09:00
parent 68ea844c69
commit 827351bdf5
22 changed files with 365 additions and 20 deletions

View File

@@ -0,0 +1,27 @@
/*
* Spring-boot Examples
*
* Copyright (c) 2021. Elex. All Rights Reserved.
* https://www.elex-project.com/
*/
plugins {
id("elex-spring-boot")
id("org.springframework.boot") version "2.5.3"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-mustache")
compileOnly("org.projectlombok:lombok")
developmentOnly("org.springframework.boot:spring-boot-devtools")
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
annotationProcessor("org.projectlombok:lombok")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}

View File

@@ -0,0 +1,20 @@
/*
* Spring-boot Examples
*
* Copyright (c) 2021. Elex. All Rights Reserved.
* https://www.elex-project.com/
*/
package kr.pe.elex.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@@ -0,0 +1,81 @@
package kr.pe.elex.examples;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.jni.Local;
import org.jetbrains.annotations.NotNull;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/**
* 로케일 리졸버
* AcceptHeaderLocaleResolver를 기본 정책으로하되, GET 파라미터로 로캐일 변환이 가능하도록 한다.
* @author Elex
*/
@Slf4j
public class CustomLocaleResolver implements LocaleResolver {
/**
* 지원되는 로캐일 목록. 첫 번째 로캐일은 기본 로캐일로 사용된다.
*/
private static final List<Locale> supportedLocales = List
.of(Locale.KOREAN, Locale.ENGLISH);
//private Locale locale = null;
private final AcceptHeaderLocaleResolver acceptHeaderLocaleResolver;
public CustomLocaleResolver() {
super();
acceptHeaderLocaleResolver = new AcceptHeaderLocaleResolver();
acceptHeaderLocaleResolver.setSupportedLocales(supportedLocales);
acceptHeaderLocaleResolver.setDefaultLocale(Locale.ENGLISH);
}
@Override
public @NotNull Locale resolveLocale(@NotNull HttpServletRequest request) {
String lang = request.getParameter("language");
if (null == lang) {
return acceptHeaderLocaleResolver.resolveLocale(request);
} else {
Locale loc = new Locale(lang);
List<Locale.LanguageRange> priorityList = new ArrayList<>();
priorityList.add(new Locale.LanguageRange(loc.toLanguageTag(), 1.0));
priorityList.add(new Locale.LanguageRange(loc.getLanguage(), 0.9));
priorityList.add(new Locale.LanguageRange(Locale.ENGLISH.getLanguage(),0.3));
//priorityList.add(new Locale.LanguageRange(Locale.ROOT.getLanguage(),0.1));
log.debug("PriorityList: {}", priorityList);
Locale pick = Locale.lookup(
priorityList,
supportedLocales);
log.debug("Picked locale: {}", pick);
return pick;
/*for (Locale loc : supportedLocales) {
if (locale.equals(loc)) return loc;
}
for (Locale loc : supportedLocales) {
if (locale.getLanguage().equals(loc.getLanguage())) return loc;
}
return supportedLocales.get(0);*/
}
}
/**
* 세션 등에 저장하고 싶을 때 사용한다.
* @param request
* @param response
* @param locale
*/
@Override
public void setLocale(@NotNull HttpServletRequest request, HttpServletResponse response,
Locale locale) {
//this.locale = locale;
}
}

View File

@@ -1,5 +1,6 @@
package kr.pe.elex.examples; package kr.pe.elex.examples;
//import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Mustache; import com.samskivert.mustache.Mustache;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;

View File

@@ -0,0 +1,36 @@
/*
* Spring-boot Examples
*
* Copyright (c) 2021. Elex. All Rights Reserved.
* https://www.elex-project.com/
*/
package kr.pe.elex.examples;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import java.util.HashMap;
@Slf4j
@Controller
public class MyController {
@GetMapping(path = {"/"})
public String index(ModelAndView modelAndView) throws Exception {
//log.info("Data: {}", modelAndView);
return "main";
}
}

View File

@@ -0,0 +1,60 @@
package kr.pe.elex.examples;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Description;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.context.support.ResourceBundleMessageSource;
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 java.util.Locale;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Value("${spring.messages.basename:i18n}")
String messagesBasename = null;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
/**
* Locale resolver, 디폴트 로캐일을 지정한다.
*/
@Bean
public LocaleResolver localeResolver() {
/*
SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
sessionLocaleResolver.setDefaultLocale(Locale.US);
return sessionLocaleResolver;
*/
return new CustomLocaleResolver();
}
/**
* Locale change interceptor, 요청 파라미터에 따른 로케일 변경
*/
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("language");
return localeChangeInterceptor;
}
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource
= new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:/" + messagesBasename);
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
}

View File

@@ -0,0 +1,8 @@
/*
* Spring-boot Examples
*
* Copyright (c) 2021. Elex. All Rights Reserved.
* https://www.elex-project.com/
*/
package kr.pe.elex.examples;

View File

@@ -0,0 +1,9 @@
spring:
application:
name: My spring-boot project
mustache:
expose-request-attributes: true
messages:
basename: i18n
server:
port: 8080

View File

@@ -0,0 +1,10 @@
('-. ('-. ) (`-.
_( OO) _( OO) ( OO ).
(,------.,--. (,------.(_/. \_)-.
| .---'| |.-') | .---' \ `.' /
| | | | OO ) | | \ /\
(| '--. | |`-' |(| '--. \ \ |
| .--'(| '---.' | .--' .' \_)
| `---.| | | `---. / .'. \
`------'`------' `------''--' '--'
powered by ELEX

View File

@@ -0,0 +1,2 @@
hello.text = Hello
only.text = Root Only

View File

@@ -0,0 +1 @@
hello.text = 안녕

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Spring-boot Examples
~
~ Copyright (c) 2021. Elex. All Rights Reserved.
~ https://www.elex-project.com/
-->
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
<springProperty name="LOG_DIR" source="logging.path"
defaultValue="${user.home}/logs"/>
<property name="LOG_PATH" value="${LOG_DIR}/stephanie.log"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<appender name="ROLLING-FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<charset>UTF-8</charset>
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
<file>${LOG_PATH}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/sebastian_%d{yyyy-MM-dd}_%i.log.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>60</maxHistory>
</rollingPolicy>
</appender>
<logger name="kr.pe.elex" level="debug" additivity="false">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="ROLLING-FILE"/>
</logger>
<root level="info">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="ROLLING-FILE"/>
</root>
</configuration>

View File

@@ -1,2 +1,3 @@
<h1>i18n</h1> <h1>i18n</h1>
<p>{{#i18n}}hello.text{{/i18n}}</p> <p>{{#i18n}}hello.text{{/i18n}}</p>
<p>{{#i18n}}only.text{{/i18n}}</p>

View File

@@ -14,8 +14,8 @@ plugins {
dependencies { dependencies {
implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-mustache") //implementation("org.springframework.boot:spring-boot-starter-mustache")
implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
compileOnly("org.projectlombok:lombok") compileOnly("org.projectlombok:lombok")
developmentOnly("org.springframework.boot:spring-boot-devtools") developmentOnly("org.springframework.boot:spring-boot-devtools")

View File

@@ -1,12 +1,14 @@
package kr.pe.elex.examples; package kr.pe.elex.examples;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.jni.Local;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver; import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@@ -22,9 +24,9 @@ public class CustomLocaleResolver implements LocaleResolver {
* 지원되는 로캐일 목록. 첫 번째 로캐일은 기본 로캐일로 사용된다. * 지원되는 로캐일 목록. 첫 번째 로캐일은 기본 로캐일로 사용된다.
*/ */
private static final List<Locale> supportedLocales = List private static final List<Locale> supportedLocales = List
.of(Locale.ENGLISH, Locale.KOREAN); .of(Locale.KOREAN, Locale.ENGLISH);
private Locale locale = null; //private Locale locale = null;
private final AcceptHeaderLocaleResolver acceptHeaderLocaleResolver; private final AcceptHeaderLocaleResolver acceptHeaderLocaleResolver;
public CustomLocaleResolver() { public CustomLocaleResolver() {
@@ -32,26 +34,40 @@ public class CustomLocaleResolver implements LocaleResolver {
acceptHeaderLocaleResolver = new AcceptHeaderLocaleResolver(); acceptHeaderLocaleResolver = new AcceptHeaderLocaleResolver();
acceptHeaderLocaleResolver.setSupportedLocales(supportedLocales); acceptHeaderLocaleResolver.setSupportedLocales(supportedLocales);
acceptHeaderLocaleResolver.setDefaultLocale(supportedLocales.get(0)); acceptHeaderLocaleResolver.setDefaultLocale(Locale.ENGLISH);
} }
@Override @Override
public @NotNull Locale resolveLocale(@NotNull HttpServletRequest request) { public @NotNull Locale resolveLocale(@NotNull HttpServletRequest request) {
if (null == locale) { String lang = request.getParameter("language");
if (null == lang) {
return acceptHeaderLocaleResolver.resolveLocale(request); return acceptHeaderLocaleResolver.resolveLocale(request);
} else { } else {
for (Locale loc : supportedLocales) { Locale loc = new Locale(lang);
List<Locale.LanguageRange> priorityList = new ArrayList<>();
priorityList.add(new Locale.LanguageRange(loc.toLanguageTag(), 1.0));
priorityList.add(new Locale.LanguageRange(loc.getLanguage(), 0.9));
priorityList.add(new Locale.LanguageRange(Locale.ENGLISH.getLanguage(),0.3));
//priorityList.add(new Locale.LanguageRange(Locale.ROOT.getLanguage(),0.1));
log.debug("PriorityList: {}", priorityList);
Locale pick = Locale.lookup(
priorityList,
supportedLocales);
log.debug("Picked locale: {}", pick);
return pick;
/*for (Locale loc : supportedLocales) {
if (locale.equals(loc)) return loc; if (locale.equals(loc)) return loc;
} }
for (Locale loc : supportedLocales) { for (Locale loc : supportedLocales) {
if (locale.getLanguage().equals(loc.getLanguage())) return loc; if (locale.getLanguage().equals(loc.getLanguage())) return loc;
} }
return supportedLocales.get(0); return supportedLocales.get(0);*/
} }
} }
/** /**
* 안터셉터에서 처리될껄? * 세션 등에 저장하고 싶을 때 사용한다.
* @param request * @param request
* @param response * @param response
* @param locale * @param locale
@@ -59,6 +75,7 @@ public class CustomLocaleResolver implements LocaleResolver {
@Override @Override
public void setLocale(@NotNull HttpServletRequest request, HttpServletResponse response, public void setLocale(@NotNull HttpServletRequest request, HttpServletResponse response,
Locale locale) { Locale locale) {
this.locale = locale; //this.locale = locale;
} }
} }

View File

@@ -18,6 +18,7 @@ import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes; import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import java.util.HashMap; import java.util.HashMap;
@@ -28,8 +29,7 @@ public class MyController {
@GetMapping(path = {"/"}) @GetMapping(path = {"/"})
public String index() throws Exception { public String index() throws Exception {
return "home";
return "main";
} }
} }

View File

@@ -4,12 +4,16 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.MessageSource; import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Description;
import org.springframework.context.support.ReloadableResourceBundleMessageSource; import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import java.util.Locale;
@Configuration @Configuration
public class WebConfig implements WebMvcConfigurer { public class WebConfig implements WebMvcConfigurer {
@Value("${spring.messages.basename:i18n}") @Value("${spring.messages.basename:i18n}")
@@ -44,11 +48,12 @@ public class WebConfig implements WebMvcConfigurer {
} }
@Bean @Bean
public MessageSource messageSource() { public ResourceBundleMessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
= new ReloadableResourceBundleMessageSource(); messageSource.setBasename(messagesBasename);
messageSource.setBasename("classpath:/" + messagesBasename);
messageSource.setDefaultEncoding("UTF-8"); messageSource.setDefaultEncoding("UTF-8");
messageSource.setDefaultLocale(Locale.ENGLISH);
return messageSource; return messageSource;
} }
} }

View File

@@ -1,9 +1,14 @@
spring: spring:
application: application:
name: My spring-boot project name: My spring-boot project
mustache:
expose-request-attributes: true
messages: messages:
basename: i18n basename: i18n
thymeleaf:
enabled: true
cache: false
encoding: UTF-8
mode: HTML
prefix: classpath:/templates/
suffix: .html
server: server:
port: 8080 port: 8080

View File

@@ -0,0 +1,2 @@
hello.text = Hello
only.text = Root Only

View File

@@ -1 +0,0 @@
hello.text = Hello

View File

@@ -0,0 +1,13 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Sample</title>
</head>
<body>
<h1>i18n</h1>
<p th:text="#{hello.text}">HELLO_TEXT</p>
<p th:text="#{only.text}">Mmm... 뭥</p>
</body>
</html>

View File

@@ -9,5 +9,5 @@ rootProject.name = "spring-boot-examples"
include( include(
"file-upload", "security", "security-with-jpa", "validation", "testing", "file-upload", "security", "security-with-jpa", "validation", "testing",
"mqtt", "websocket", "restful", "swing", "rest-doc", "mqtt", "websocket", "restful", "swing", "rest-doc",
"cache", "security-with-jwt", "exception", "i18n", "mvc" "cache", "security-with-jwt", "exception", "i18n", "i18n-mustache","mvc"
) )