still under construction

This commit is contained in:
2021-08-20 23:40:43 +09:00
parent 2ee272598a
commit 14af7dfe4e
37 changed files with 185 additions and 349 deletions

View File

@@ -41,8 +41,8 @@ tasks.asciidoctor {
dependencies {
implementation(project(":sitemap"))
implementation(project(":linkback"))
implementation(project(":web-app"))
implementation(project(":address-finder"))
implementation("com.vladsch.flexmark:flexmark-all:0.62.2")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")

View File

@@ -31,4 +31,5 @@ public class Application {
}
}
}

View File

@@ -0,0 +1,24 @@
/*
* Project Asgard
*
* Copyright (c) 2021. Elex. All Rights Reserved.
* https://www.elex-project.com/
*/
package com.elex_project.asgard.config;
import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizer;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component
public class AsgardCacheCustomizer implements CacheManagerCustomizer<ConcurrentMapCacheManager> {
@Override
public void customize(ConcurrentMapCacheManager cacheManager) {
cacheManager.setCacheNames(Arrays
.asList("sitemap", "syndication/rss", "syndication/atom"));
}
}

View File

@@ -9,6 +9,8 @@ package com.elex_project.asgard.config;
import com.elex_project.asgard.supplements.Markdown;
import com.elex_project.asgard.view.AsgardLocaleResolver;
import org.springframework.cache.CacheManager;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
@@ -16,32 +18,14 @@ import org.springframework.web.servlet.LocaleResolver;
@Configuration
public class Config {
/*@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
*/
/*@Bean
public HttpTraceRepository httpTraceRepository() {
return new InMemoryHttpTraceRepository();
}*/
/**
* Locale resolver, 디폴트 로캐일을 지정한다.
*/
@Bean
public LocaleResolver localeResolver() {
/*SessionLocaleResolver localeResolver = new SessionLocaleResolver();
localeResolver.setDefaultLocale(Locale.ENGLISH);
localeResolver.setLocaleAttributeName("lc");
localeResolver.setTimeZoneAttributeName("tz");
return localeResolver;*/
return new AsgardLocaleResolver();
}
/**
* Markdown parser
*

View File

@@ -1,8 +0,0 @@
/*
* Project Asgard
*
* Copyright (c) 2021. Elex. All Rights Reserved.
* https://www.elex-project.com/
*/
package com.elex_project.asgard.config;

View File

@@ -1,105 +0,0 @@
/*
* Project Asgard
*
* Copyright (c) 2021. Elex. All Rights Reserved.
* https://www.elex-project.com/
*/
package com.elex_project.asgard.controller;
import org.jetbrains.annotations.NotNull;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
abstract class BaseController {
/*@NotNull
protected Map<String, Object> map() {
final HashMap<String, Object> map = new HashMap<>();
map.put("html_lang", lang());
return map;
}
@NotNull
private String lang() {
return getHttpRequest()
.map(request -> request.getLocale().toLanguageTag())
.orElse("en");
}
@NotNull
protected URI getRequestURI() {
return getHttpRequest()
.map(request -> URI.create(request.getRequestURI()))
.orElse(URI.create("/"));
}
private Optional<ServletRequestAttributes> getRequestAttributes() {
return Optional
.ofNullable((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
}
protected Optional<HttpServletRequest> getHttpRequest() {
return getRequestAttributes()
.map(ServletRequestAttributes::getRequest);
}
protected Optional<HttpServletResponse> getHttpResponse() {
return getRequestAttributes()
.map(ServletRequestAttributes::getResponse);
}
@NotNull
protected String[] getAttributeNames() {
return getRequestAttributes()
.map(attr -> attr.getAttributeNames(RequestAttributes.SCOPE_REQUEST))
.orElse(new String[0]);
}
@NotNull
protected String[] getSessionAttributeNames() {
return getRequestAttributes()
.map(attr -> attr.getAttributeNames(RequestAttributes.SCOPE_SESSION))
.orElse(new String[0]);
}
@NotNull
protected Optional<Object> getAttribute(@NotNull final String key) {
return getRequestAttributes()
.map(attr -> attr.getAttribute(key, RequestAttributes.SCOPE_REQUEST));
}
@NotNull
protected Optional<Object> getSessionAttribute(@NotNull final String key) {
return getRequestAttributes()
.map(attr -> attr.getAttribute(key, RequestAttributes.SCOPE_SESSION));
}
protected void setAttribute(@NotNull final String key, final Object value) {
getRequestAttributes()
.ifPresent(attr -> attr.setAttribute(key, value, RequestAttributes.SCOPE_REQUEST));
}
protected void setSessionAttribute(@NotNull final String key, final Object value) {
getRequestAttributes()
.ifPresent(attr -> attr.setAttribute(key, value, RequestAttributes.SCOPE_SESSION));
}
protected void removeAttribute(@NotNull final String key) {
getRequestAttributes()
.ifPresent(attr -> attr.removeAttribute(key, RequestAttributes.SCOPE_REQUEST));
}
protected void removeSessionAttribute(@NotNull final String key) {
getRequestAttributes()
.ifPresent(attr -> attr.removeAttribute(key, RequestAttributes.SCOPE_SESSION));
}*/
}

View File

@@ -7,27 +7,25 @@
package com.elex_project.asgard.controller;
import com.elex_project.asgard.service.NoteService;
import com.elex_project.asgard.service.DocumentService;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
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.net.URI;
import java.util.List;
@Slf4j
@Controller
public class NoteController extends BaseController {
public class DocumentController {
@Autowired
private NoteService noteService;
private DocumentService documentService;
/*@GetMapping(path = "/*")
public ModelAndView reader(){
@@ -35,7 +33,7 @@ public class NoteController extends BaseController {
return new ModelAndView("document", map());
}*/
@GetMapping(path = "/*")
public ModelAndView editor(@RequestParam boolean edit, ModelAndView model) {
public ModelAndView editor(@RequestParam(required = false) boolean edit, ModelAndView model) {
if (edit) {
model.setViewName("edit");
} else {

View File

@@ -9,6 +9,7 @@ package com.elex_project.asgard.controller;
import com.elex_project.asgard.service.SitemapService;
import com.elex_project.asgard.service.SyndicationService;
import com.elex_project.asgard.syndication.SyndicationType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
@@ -19,15 +20,13 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.ModelAndView;
import java.util.Map;
/**
* @link http://www.robotstxt.org/robotstxt.html
* @link http://humanstxt.org/
*/
@Slf4j
@Controller
public class HomeController extends BaseController {
public class HomeController {
@Autowired
private SyndicationService syndicationService;
@Autowired
@@ -73,8 +72,7 @@ public class HomeController extends BaseController {
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public String rss() {
return syndicationService.getRssSyndication();
//return "syndication/rss2";
return syndicationService.getSyndication(SyndicationType.RSS_2);
}
/**
@@ -86,7 +84,7 @@ public class HomeController extends BaseController {
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public String atom() {
return syndicationService.getAtomSyndication();
return syndicationService.getSyndication(SyndicationType.ATOM);
}
@PostMapping(path = "/trackback/{id}",

View File

@@ -1,8 +0,0 @@
/*
* Project Asgard
*
* Copyright (c) 2021. Elex. All Rights Reserved.
* https://www.elex-project.com/
*/
package com.elex_project.asgard.controller;

View File

@@ -8,8 +8,7 @@
package com.elex_project.asgard.model;
import com.elex_project.asgard.supplements.StringArrayConverter;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
@@ -18,11 +17,14 @@ import javax.persistence.*;
import java.time.LocalDateTime;
@Slf4j
@Data
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
@Entity
@Table(name = "notes")
public class Note {
@Table(name = "documents")
public class Document {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@@ -48,7 +50,7 @@ public class Note {
@LastModifiedDate
private LocalDateTime modifiedOn;
public static Note of(){
public static Document of() {
return null;
}
}

View File

@@ -1,84 +0,0 @@
/*
* Project Asgard
*
* Copyright (c) 2021. Elex. All Rights Reserved.
* https://www.elex-project.com/
*/
package com.elex_project.asgard.model;
import com.elex_project.asgard.supplements.InetAddressConverter;
import com.elex_project.asgard.supplements.StringArrayConverter;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import javax.persistence.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.Duration;
import java.time.LocalDateTime;
import static com.elex_project.asgard.supplements.RequestLogInterceptor.REQUEST_TIME;
@Slf4j
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "http_trace")
public class HttpTraceModel {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Column
private LocalDateTime requestTime;
@Column
private Long elapsed;
@Column
private String requestUrl;
@Column
private String requestMethod;
@Column
private String userAgent;
@Column
private String referer;
@Column
@Convert(converter = StringArrayConverter.class)
private String[] acceptLang;
@Column
@Convert(converter = InetAddressConverter.class)
private InetAddress ipAddress;
public static HttpTraceModel of(final HttpServletRequest request, final HttpServletResponse response) {
final HttpTraceModel model = new HttpTraceModel();
model.requestUrl = request.getRequestURI();
model.requestMethod = request.getMethod();
model.userAgent = request.getHeader("User-Agent");
model.referer = request.getHeader("Referer");
final String acceptLang = request.getHeader("Accept-Language");
if (null != acceptLang) {
model.acceptLang = acceptLang.replaceAll(";q=[0-9.]*", "").split(",");
} else {
model.acceptLang = new String[0];
}
model.requestTime = (LocalDateTime) request.getAttribute(REQUEST_TIME);
if (null != model.requestTime) {
model.elapsed = Duration.between(model.requestTime, LocalDateTime.now()).toMillis();
}
String ip = request.getHeader("X-Forwarded-For");
if (null == ip) ip = request.getHeader("X-Real-Ip");
if (null == ip) ip = request.getRemoteAddr();
try {
model.ipAddress = InetAddress.getByName(ip);
} catch (UnknownHostException ignore) {
}
return model;
}
}

View File

@@ -1,8 +0,0 @@
/*
* Project Asgard
*
* Copyright (c) 2021. Elex. All Rights Reserved.
* https://www.elex-project.com/
*/
package com.elex_project.asgard.model;

View File

@@ -12,5 +12,5 @@ import org.springframework.stereotype.Service;
@Slf4j
@Service
public class NoteService {
public class DocumentService {
}

View File

@@ -13,8 +13,11 @@ import com.elex_project.asgard.sitemap.Sitemap;
import com.elex_project.asgard.sitemap.SitemapItem;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Slf4j
@@ -25,6 +28,11 @@ public class SitemapService extends BaseSitemapService {
@Override
protected Sitemap sitemap() {
final Sitemap sitemap = new Sitemap();
sitemap.addItem(SitemapItem.builder()
.loc("https://www.elex-project.com/address-finder/")
.lastMod(LocalDate.of(2021,8,19).atStartOfDay())
.changeFreq(Frequency.NEVER)
.build());
sitemap.addItem(SitemapItem.builder()
.loc("https://aaa.com/1")
.lastMod(LocalDateTime.now())
@@ -37,7 +45,13 @@ public class SitemapService extends BaseSitemapService {
return sitemap;
}
//@CacheEvict(allEntries = true)
@Cacheable
@Override
public String getSitemap() {
return super.getSitemap();
}
@CacheEvict(allEntries = true)
public void clearCaches() {
}

View File

@@ -10,7 +10,11 @@ package com.elex_project.asgard.service;
import com.elex_project.asgard.syndication.BaseSyndicationService;
import com.elex_project.asgard.syndication.Syndication;
import com.elex_project.asgard.syndication.SyndicationItem;
import com.elex_project.asgard.syndication.SyndicationType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
@@ -19,12 +23,16 @@ import java.util.List;
import java.util.Locale;
@Slf4j
@CacheConfig(cacheNames = "syndication")
@Service
//@CacheConfig(cacheNames = "templates/syndication")
public class SyndicationService extends BaseSyndicationService {
@Cacheable
@Override
public String getSyndication(SyndicationType type) {
return super.getSyndication(type);
}
//@CacheEvict(allEntries = true)
@CacheEvict(allEntries = true)
public void clearCaches() {
}
@@ -60,7 +68,7 @@ public class SyndicationService extends BaseSyndicationService {
.url("https://something.com/2")
.build())
.build();
final List<SyndicationItem> items = new ArrayList<>();// todo
final List<SyndicationItem> items = new ArrayList<>();// todo read from db
items.forEach(syndication::addItem);
return syndication;
}

View File

@@ -1,8 +0,0 @@
/*
* Project Asgard
*
* Copyright (c) 2021. Elex. All Rights Reserved.
* https://www.elex-project.com/
*/
package com.elex_project.asgard.service;

View File

@@ -7,7 +7,6 @@
package com.elex_project.asgard.supplements;
import com.elex_project.asgard.model.HttpTraceModel;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.web.servlet.HandlerInterceptor;
@@ -15,11 +14,12 @@ import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.Duration;
import java.time.LocalDateTime;
@Slf4j
public class RequestLogInterceptor implements HandlerInterceptor {
public static final String REQUEST_TIME = "elex.request.time";
private static final String REQUEST_TIME = "elex.request.time";
@Override
public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler)
@@ -37,8 +37,8 @@ public class RequestLogInterceptor implements HandlerInterceptor {
@Override
public void afterCompletion(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler, Exception ex)
throws Exception {
final HttpTraceModel traceModel = HttpTraceModel.of(request, response);
log.info("Http Trace: {}", traceModel);
Duration elapsed = Duration
.between((LocalDateTime) request.getAttribute(REQUEST_TIME), LocalDateTime.now());
log.info("Http Trace: {}", elapsed);
}
}

View File

@@ -1,8 +0,0 @@
/*
* Project Asgard
*
* Copyright (c) 2021. Elex. All Rights Reserved.
* https://www.elex-project.com/
*/
package com.elex_project.asgard.supplements;

View File

@@ -14,10 +14,13 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ViewModelInterceptor implements HandlerInterceptor {
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
if (null != modelAndView) {
modelAndView.addObject("title", "Title~!!!");
}
}
}

View File

@@ -1,8 +0,0 @@
/*
* Project Asgard
*
* Copyright (c) 2021. Elex. All Rights Reserved.
* https://www.elex-project.com/
*/
package com.elex_project.asgard.view;

View File

@@ -8,5 +8,5 @@ Name:
/* SITE */
Front-end: HTML5, CSS3, Javascript, Material Design Components, Node-js(yarn, webpack, babel), Scss
Back-end: Spring-boot, Mustache, Hibernate
Back-end: Spring-boot, Mustache, Thymeleaf, Hibernate
Server: Docker, MariaDB, Tomcat, Nginx, Linux

View File

@@ -1,14 +1,14 @@
<!DOCTYPE html>
<html lang="{{html_lang}}">
<html xmlns:th="http://www.thymeleaf.org" th:lang="${#locale.language}">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
{{> fragments/meta}}
<th:block th:replace="~{fragments :: meta}"></th:block>
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet" />
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
<link rel="author" href="/humans.txt" />
<link rel="stylesheet" href="/bundle.css" />
<title>{{title}}</title>
<title th:text="${title}">{{title}}</title>
<script src="/bundle.js"></script>
</head>
<body>
@@ -158,7 +158,7 @@
</p>
</article>
</main>
<footer class="mdc-layout-grid">
<footer class="mdc-layout-grid" th:include="~{fragments :: footer}">
<p>Copyright &copy; 2021</p>
</footer>
</div>

View File

@@ -1,7 +1,7 @@
<!doctype html>
<html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>{{status}} - {{message}}</title>
<title th:text="|${status} - ${message}|">{{status}} - {{message}}</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="preconnect" href="https://fonts.gstatic.com">
@@ -16,13 +16,13 @@
<body>
<p class="inline">
<span class="green">www-user@elex-project.com</span><span>:</span>
<span class="blue">{{path}}</span><span>$&nbsp;</span><span>http get {{path}}</span>
<span class="blue" th:text="${path}">{{path}}</span><span>$&nbsp;</span><span th:text="|http get ${path}|">http get {{path}}</span>
</p>
<p>{{status}} - {{message}}</p>
<p>Trace:<br /> {{trace}}</p>
<p th:text="|${status} - ${message}|">{{status}} - {{message}}</p>
<p th:utext="|Trace:<br/> ${trace}|">Trace:<br /> {{trace}}</p>
<p class="inline">
<span class="green">www-user@elex-project.com</span><span>:</span>
<span class="blue">{{path}}</span><span>$&nbsp;</span><input type="text"/>
<span class="blue" th:text="${path}">{{path}}</span><span>$&nbsp;</span><input type="text"/>
</p>
</body>
</html>

View File

@@ -1,13 +1,13 @@
<!doctype html>
<html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>{{status}} - {{message}}</title>
<title th:text="|${status} - ${message}|">{{status}} - {{message}}</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p>Oops-404!</p>
<h1>{{status}}</h1>
<p>{{message}}</p>
<h1 th:text="${status}">{{status}}</h1>
<p th:text="${message}">{{message}}</p>
</body>
</html>

View File

@@ -0,0 +1,52 @@
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title th:text="${title}">{{title}}</title>
<th:block th:fragment="meta">
<meta property="og:title" content="{{title}}" />
<meta property="og:url" content="{{url}}" />
<meta name="description" property="og:description" content="{{description}}" />
<meta property="og:locale" content="{{html_lang}}" />
<meta property="og:site_name" content="Elex Project" />
<meta property="og:image" content="{{image}}" />
<meta property="og:type" content="article" />
<meta property="og:article:section" content="{{section}}" />
<meta name="keyword" property="og:article:tag" content="{{tag}}" />
<meta property="og:article:published_time" content="{{published_time}}" />
<meta property="og:article:modified_time" content="{{modified_time}}" />
<meta name="author" property="og:article:author" content="{{author}}"/>
</th:block>
<link rel="stylesheet" href="/persona.min.css" />
<script>
let toggle = function () {
const elem = document.querySelector(".layout");
elem.classList.toggle("closed");
};
</script>
</head>
<body>
<div class="layout">
<div class="sidebar">
<nav class="nav">
<ul>
</ul>
</nav>
</div>
<header class="header">
<span class="icon-button material-icons" onclick="toggle();">menu</span>
<h1 class="grow" th:text="${title}">{{title}}</h1>
</header>
<div class="main">
<main>
</main>
<footer th:fragment="footer">
Copyright &copy; 2021. Elex. All Rights Reserved.
</footer>
</div>
</div>
</body>
</html>

View File

@@ -1,3 +0,0 @@
<footer th:fragment="footer">
Copyright &copy;
</footer>

View File

@@ -1,14 +0,0 @@
<head th:fragment="meta">
<meta property="og:title" content="{{title}}" />
<meta property="og:url" content="{{url}}" />
<meta name="description" property="og:description" content="{{description}}" />
<meta property="og:locale" content="{{html_lang}}" />
<meta property="og:site_name" content="Elex Project" />
<meta property="og:image" content="{{image}}" />
<meta property="og:type" content="article" />
<meta property="og:article:section" content="{{section}}" />
<meta name="keyword" property="og:article:tag" content="{{tag}}" />
<meta property="og:article:published_time" content="{{published_time}}" />
<meta property="og:article:modified_time" content="{{modified_time}}" />
<meta name="author" property="og:article:author" content="{{author}}"/>
</head>

View File

@@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title th:text="${title}">{{title}}</title>
<th:block th:include="~{fragments/meta :: meta}"></th:block>
<th:block th:replace="~{fragments :: meta}"></th:block>
<link rel="stylesheet" href="/persona.min.css" />
<script>
let toggle = function () {
@@ -32,7 +32,7 @@
<p>...</p>
</main>
<footer th:replace="~{fragments/footer :: footer}">
<footer th:replace="~{fragments :: footer}">
</footer>
</div>
</div>