From 5efcaa1a3ca9281178566468bc65eddf8bc4c772 Mon Sep 17 00:00:00 2001 From: Anton Romanov Date: Wed, 9 Mar 2022 00:10:50 +0400 Subject: [PATCH] #1 -- add some business logic --- build.gradle | 7 +- data/db.mv.db | Bin 20480 -> 24576 bytes .../ulstu/configuration/MvcConfiguration.java | 3 +- .../ru/ulstu/controller/IndexController.java | 24 ++--- .../ru/ulstu/controller/NewsController.java | 37 ++++++++ src/main/java/ru/ulstu/model/BaseEntity.java | 83 ++++++++++++++++++ src/main/java/ru/ulstu/model/News.java | 32 +++++-- .../ru/ulstu/repository/NewsRepository.java | 7 ++ .../java/ru/ulstu/service/NewsService.java | 45 ++++++++++ src/main/resources/static/favicon.ico | Bin 305822 -> 15406 bytes src/main/resources/templates/default.html | 8 +- src/main/resources/templates/editNews.html | 26 ++++++ src/main/resources/templates/index.html | 4 - 13 files changed, 243 insertions(+), 33 deletions(-) create mode 100644 src/main/java/ru/ulstu/controller/NewsController.java create mode 100644 src/main/java/ru/ulstu/model/BaseEntity.java create mode 100644 src/main/java/ru/ulstu/repository/NewsRepository.java create mode 100644 src/main/java/ru/ulstu/service/NewsService.java create mode 100644 src/main/resources/templates/editNews.html diff --git a/build.gradle b/build.gradle index f103d3e..d5286fb 100644 --- a/build.gradle +++ b/build.gradle @@ -32,10 +32,11 @@ dependencies { versionSwagger = '2.5.0' } - implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web' - implementation group: 'org.springframework.boot', name: 'spring-boot-starter-jetty' + implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web' + implementation group: 'org.springframework.boot', name: 'spring-boot-starter-jetty' implementation group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf' - implementation group: 'org.slf4j', name: 'slf4j-api', version: versionSLF4J + implementation group: 'org.springframework.boot', name: 'spring-boot-starter-validation' + implementation group: 'org.slf4j', name: 'slf4j-api', version: versionSLF4J implementation group: 'nz.net.ultraq.thymeleaf', name: 'thymeleaf-layout-dialect' implementation group: 'org.springframework.boot', name:'spring-boot-starter-data-jpa' implementation group: 'com.h2database', name:'h2' diff --git a/data/db.mv.db b/data/db.mv.db index 9e8355995daf126bb0ce886b8decd179ae7cc0e3..2867556fbde610335892a5c43e5dd6d0feb53af0 100644 GIT binary patch literal 24576 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 JgC6Vue*?VDS(X3* diff --git a/src/main/java/ru/ulstu/configuration/MvcConfiguration.java b/src/main/java/ru/ulstu/configuration/MvcConfiguration.java index 9716493..502e5b1 100644 --- a/src/main/java/ru/ulstu/configuration/MvcConfiguration.java +++ b/src/main/java/ru/ulstu/configuration/MvcConfiguration.java @@ -20,7 +20,8 @@ import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; public class MvcConfiguration implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { - registry.addViewController("/{articlename:\\w+}"); + registry.addViewController("/index"); + registry.addViewController("/editNews"); } @Override diff --git a/src/main/java/ru/ulstu/controller/IndexController.java b/src/main/java/ru/ulstu/controller/IndexController.java index d70ef2f..d6f2fc0 100644 --- a/src/main/java/ru/ulstu/controller/IndexController.java +++ b/src/main/java/ru/ulstu/controller/IndexController.java @@ -9,28 +9,20 @@ package ru.ulstu.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; -import ru.ulstu.model.News; - -import java.util.GregorianCalendar; -import java.util.List; +import ru.ulstu.service.NewsService; @Controller public class IndexController { + private final NewsService newsService; + + public IndexController(NewsService newsService) { + this.newsService = newsService; + } + @GetMapping("/") public String index(Model model) { - model.addAttribute("news", List.of(new News("Открытие семинара", new GregorianCalendar(2022, 4, 1).getTime(), - "На кафере \"Информационные системы\" Ульяновского государственного технического университета состоится открытие постоянно действующего семинара \"Анализ данных и процессов\". Семинар планируется проводить ежемесячно."), - new News("Открытие семинара", new GregorianCalendar(2022, 4, 1).getTime(), - "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec laoreet enim dolor, vitae imperdiet mi consectetur et. Etiam posuere massa sed arcu pulvinar, eu tincidunt nunc vehicula. Integer interdum magna et orci eleifend convallis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam interdum nulla eget lacus ultricies sagittis. Duis a lacus lacinia, pulvinar augue ultrices, vulputate arcu. Etiam facilisis justo nec ex tincidunt, sit amet tempus ante iaculis. Praesent non accumsan odio. Nunc faucibus mattis elit elementum lacinia. Sed orci augue, iaculis sed efficitur ac, faucibus nec orci. Vivamus sed tempor lectus. Mauris non nisi lobortis, varius tortor id, cursus orci. Sed gravida, est nec placerat ornare, mi metus mattis eros, vitae finibus lectus turpis ut felis. Mauris faucibus lorem orci, tempor bibendum leo varius et.\n" + - "\n" + - "Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Suspendisse ut vulputate enim, nec rutrum magna. Ut finibus dignissim arcu, gravida gravida eros vulputate a. Nulla dapibus eleifend egestas. Pellentesque malesuada venenatis fermentum. Proin suscipit mi enim, eu cursus neque luctus id. Sed nec sodales libero, vel finibus sem. Maecenas tincidunt sagittis risus a posuere. Donec quis velit lorem. Curabitur viverra libero quis nibh molestie, id suscipit lorem ultrices. Donec egestas lectus at justo tempus, et pulvinar magna dignissim. Donec eleifend pretium ante in maximus. Maecenas in malesuada ante. Donec euismod tincidunt tempus.\n" + - "\n" + - "Integer convallis euismod nibh non ornare. Sed sed sagittis enim, id tempus libero. Sed interdum dui ut orci ultrices efficitur. Aenean a tristique odio. Duis nec lacus sit amet metus fringilla posuere. Donec nisi felis, congue ut lorem in, efficitur dapibus leo. Sed vel urna porta, mollis nunc in, aliquam quam. Sed rhoncus justo nisi, vitae volutpat nibh feugiat at. Phasellus laoreet justo et elit aliquet, non tincidunt mauris sagittis. Nunc in quam velit. Aliquam lobortis turpis elit, ut aliquam dolor sagittis sed. Duis pellentesque eu turpis quis ullamcorper. Nullam in ullamcorper metus. Vestibulum sit amet tellus at nulla pretium commodo. Nulla eleifend lacus ex, ac sodales odio pellentesque in. Cras nec metus elit.\n" + - "\n" + - "Cras feugiat gravida magna, nec faucibus eros eleifend nec. Donec sodales ligula ut ante lacinia eleifend. Pellentesque bibendum nunc vel nulla luctus, ut vulputate turpis semper. Aenean quis massa bibendum, vehicula lorem et, fringilla arcu. Morbi nisi elit, pellentesque ac tincidunt quis, volutpat et felis. Duis ullamcorper velit mauris, sit amet egestas sem euismod ac. Proin sodales urna in libero scelerisque mollis.\n" + - "\n" + - "Curabitur sed massa tempus, ullamcorper nisl non, posuere mi. Integer nisl quam, venenatis ut dapibus vehicula, tempor nec metus. Suspendisse ultrices maximus lorem quis accumsan. Donec ac orci et dolor tincidunt pellentesque. In at tempor ligula. Nulla mi risus, malesuada tincidunt ante vel, rhoncus posuere massa. Pellentesque feugiat urna id arcu gravida euismod. Maecenas vulputate et lorem vitae molestie. Maecenas et nibh nec nisl facilisis faucibus. Vestibulum sed lacus elementum, interdum erat non, euismod odio. Proin ac lorem vel nibh efficitur egestas ac et nibh. Integer at enim."))); + model.addAttribute("news", newsService.getAll()); return "index"; } } diff --git a/src/main/java/ru/ulstu/controller/NewsController.java b/src/main/java/ru/ulstu/controller/NewsController.java new file mode 100644 index 0000000..d76fe1f --- /dev/null +++ b/src/main/java/ru/ulstu/controller/NewsController.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 Anton Romanov - All Rights Reserved + * You may use, distribute and modify this code, please write to: romanov73@gmail.com. + * + */ + +package ru.ulstu.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import ru.ulstu.model.News; +import ru.ulstu.service.NewsService; + +@Controller +public class NewsController { + private final NewsService newsService; + + public NewsController(NewsService newsService) { + this.newsService = newsService; + } + + @GetMapping("/editNews/{newsId}") + public String editNews(@PathVariable(value = "newsId") Integer id, Model model) { + model.addAttribute("news", (id != null && id != 0) ? newsService.getById(id) : new News()); + return "editNews"; + } + + @PostMapping("saveNews") + public String saveNews(@ModelAttribute News news) { + newsService.save(news); + return "redirect:/"; + } +} diff --git a/src/main/java/ru/ulstu/model/BaseEntity.java b/src/main/java/ru/ulstu/model/BaseEntity.java new file mode 100644 index 0000000..7946ec0 --- /dev/null +++ b/src/main/java/ru/ulstu/model/BaseEntity.java @@ -0,0 +1,83 @@ +package ru.ulstu.model; + +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; +import javax.persistence.Version; +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +@MappedSuperclass +public abstract class BaseEntity implements Serializable, Comparable { + @Id + @GeneratedValue(strategy = GenerationType.TABLE) + private Integer id; + + @Version + private Integer version; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!getClass().isAssignableFrom(obj.getClass())) { + return false; + } + BaseEntity other = (BaseEntity) obj; + if (id == null) { + if (other.id != null) { + return false; + } + } else if (!id.equals(other.id)) { + return false; + } + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (id == null ? 0 : id.hashCode()); + return result; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{" + + "id=" + id + + ", version=" + version + + '}'; + } + + @Override + public int compareTo(@NotNull BaseEntity o) { + return id != null ? id.compareTo(o.getId()) : -1; + } + + public void reset() { + this.id = null; + this.version = null; + } +} \ No newline at end of file diff --git a/src/main/java/ru/ulstu/model/News.java b/src/main/java/ru/ulstu/model/News.java index 9050698..7efb6dc 100644 --- a/src/main/java/ru/ulstu/model/News.java +++ b/src/main/java/ru/ulstu/model/News.java @@ -1,12 +1,22 @@ package ru.ulstu.model; +import javax.persistence.Entity; +import javax.persistence.Lob; import java.util.Date; -public class News { +@Entity +public class News extends BaseEntity { private final static int MAX_NEWS_TEXT_PREVIEW_LENGTH = 800; - private final String title; - private final Date date; - private final String text; + + private String title; + + private Date date; + + @Lob + private String text; + + public News() { + } public News(String title, Date date, String text) { this.title = title; @@ -22,12 +32,24 @@ public class News { return date; } + public void setDate(Date date) { + this.date = date; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setText(String text) { + this.text = text; + } + public String getText() { return text; } public String getPreview() { - return text.length() > MAX_NEWS_TEXT_PREVIEW_LENGTH + return text != null && text.length() > MAX_NEWS_TEXT_PREVIEW_LENGTH ? text.substring(0, MAX_NEWS_TEXT_PREVIEW_LENGTH) + "..." : text; } diff --git a/src/main/java/ru/ulstu/repository/NewsRepository.java b/src/main/java/ru/ulstu/repository/NewsRepository.java new file mode 100644 index 0000000..3aaf6bf --- /dev/null +++ b/src/main/java/ru/ulstu/repository/NewsRepository.java @@ -0,0 +1,7 @@ +package ru.ulstu.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import ru.ulstu.model.News; + +public interface NewsRepository extends JpaRepository { +} diff --git a/src/main/java/ru/ulstu/service/NewsService.java b/src/main/java/ru/ulstu/service/NewsService.java new file mode 100644 index 0000000..a4bcae3 --- /dev/null +++ b/src/main/java/ru/ulstu/service/NewsService.java @@ -0,0 +1,45 @@ +package ru.ulstu.service; + +import org.springframework.stereotype.Service; +import ru.ulstu.model.News; +import ru.ulstu.repository.NewsRepository; + +import javax.validation.constraints.NotNull; +import java.util.Date; +import java.util.List; + +@Service +public class NewsService { + private final NewsRepository newsRepository; + + public NewsService(NewsRepository newsRepository) { + this.newsRepository = newsRepository; + } + + public void create(String title, String text) { + newsRepository.save(new News(title, new Date(), text)); + } + + public void create(News news) { + news.setDate(new Date()); + newsRepository.save(news); + } + + public void save(News news) { + if (news.getId() != null && (news.getId() != 0)) { + newsRepository.save(news); + } else { + create(news); + } + } + + public News getById(@NotNull Integer id) { + return newsRepository + .findById(id) + .orElseThrow(() -> new RuntimeException("Новость не найдена")); + } + + public List getAll() { + return newsRepository.findAll(); + } +} diff --git a/src/main/resources/static/favicon.ico b/src/main/resources/static/favicon.ico index 4d4f220f9c4fbcc966f1bf92c84c60b0ab1ffb6f..dca8f8d67ea05ee0a483ce70dbc899e5084aeea1 100644 GIT binary patch literal 15406 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 literal 305822 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 diff --git a/src/main/resources/templates/default.html b/src/main/resources/templates/default.html index ab97906..01de6c5 100644 --- a/src/main/resources/templates/default.html +++ b/src/main/resources/templates/default.html @@ -22,7 +22,7 @@