Академический Документы
Профессиональный Документы
Культура Документы
Дипломная работа
„Создание системы управление веб-сайтом”
Специальность Информатика
Руководитель, преподаватель
Департамента Информатики
Анатолий Гладей
Кишинэу – 2021
Оглавление
Оглавление 2
Введение 5
Глава I 6
История развития и текущее состояние CMS 6
Определение CMS 6
История развития CMS 7
Первые веб-сайты 7
Динамическое изменение контента 7
Системы управления контентом 7
Классификация CMS 8
Популярные системы 8
Глава II 9
Задача дипломной работы и инструменты 9
Функционал системы 9
Выбор языка программирования 10
Выбор базы данных и СУБД 14
Выбор инструментов языка 18
Используемый софт 19
Глава III 20
Проект системы 20
Структура базы данных: 21
Веб сервер 22
Структура пользовательского интерфейса 23
Области применения 24
Преимущества и недостатки проекта 25
Преимущества 25
Недостатки 25
Глава IV 26
Реализация системы 26
Основные модули сервера 26
Пользовательский интерфейс 35
Заключение 37
Литература и ссылки 38
Приложения 39
АННОТАЦИЯ
На дипломную работу
Ключевые слова: Система управления контентом, CMS, Веб, веб движок, графический
интерфейс, язык программирования Java, Spring, Hibernate, Thyeamleaf.
Определение CMS
CMS (Content Management System) — программное обеспечение, позволяющее управлять
контентом на сайта. Создавать новые записи, редактировать существующие, добавлять
пользователей, новые разделы. Редактировать дизайн сайта, добавлять или убирать некоторый
функционал.
Назначение CMS — основной целью CMS, является упрощение работы с сайтом, для
администратора и модератора. Он полностью избавляет владельца сайта от необходимости
писать какой-либо код. Весь функционал реализован с помощью пользовательского интерфейса
и является интуитивно понятным.
По итогу, все что формируется на сайте, так или иначе создается и редактируется с помощью
движка CMS. Это позволяет создавать веб сайты очень быстро, а самое главное качественно.
Ведь CMS пишутся долго и тщательно тестируются временем, что нельзя сказать о сайте
написанным программистом, вероятность встретить там ошибку во много раз выше, чем на
сайте, который использует CMS.
История развития CMS
Первые веб-сайты
На заре интернета, веб сайты представляли собой набор текста или картинок. Сайты писались
только с использованием HTML тегов, без динамической отрисовки на сервере, стилей и
Javascript.
Сайты были полностью статичные, не было возможности что-либо менять на страницах без их
ручного изменения.
● Personal Home;
● Page (PHP);
● Active Server, Pages (ASP);
● JavaServer Pages (JSP).
В это же время появились CSS, каскадные таблицы стилей и FrontPage, инструмент от MicroSoft
для создания и управления сайтами. Изначально он присутствовал в Office 2007, и обладал
широким спектром возможностей: мог автоматически отправлять изменения, внесенные
разработчиком сайта в исходные тексты в режиме реального времени.
Популярные системы
● WordPress
Бесплатный движок и самый популярный на сегодняшний день CMS движок. Изначально
позволял создавать только блоги, однако с учетом своей модульной архитектуры и
открытого исходного кода, был быстро дополнен всевозможными модулями, для
создания сайтов под любой спектр задач. Блоги, интернет-магазины, корпоративные
сайты, информационные порталы.
● «1С-Битрикс»
Коммерческий , платный движок. В сравнении с Wordpress проигрывает, по спектру
применения, однако выигрывает в коммерческих задачах, под которые и был создан.
Использование является платным.
● Joomla
Близкий аналог WordPress. Бесплатная, простая и легкая CMS.
Глава II
Функционал системы
Система должна обладать следующими функционалом:
● Регистрации и авторизации пользователей
● Возможность динамически создавать контент
● Редактировать существующий контент
● Управление персональными данными пользователей
● Пользователи имеют возможность комментировать контент
● Редактировать основные детали страниц сайта
● Система ролей доступа к содержимому
● Панель управления администратора
● Администратор имеет полный контроль над пользователями сайта
● Администратор имеет возможность редактировать любые посты пользователей.
● Система пользовательских компонентов
● Система визуального создания страниц
● API - инструментарий для взаимодействия с внешними программами
Выбор языка программирования
Для реализации данного функционала я изучил существующие CMS на сегодняшний день и
выявил для себя их основные достоинства и недостатки.
Основной недостаток большинства современных CMS - они медленные.
При этом для многих языков существует различие в производительности между компилируемой
и интерпретируемой реализацией.
Большое количество языков, включая BASIC, C, Lisp, Pascal и Python, имеют обе реализации. В
Java используется JIT-компиляция для генерации машинного кода, хотя изначально он
переводится в интерпретируемую форму. Языки Microsoft .NET Framework компилируются в
Common Intermediate Language (CIL), который во время выполнения компилируется в нативный
код. Большинство реализаций Lisp позволяют смешивать оба вида кода.
Кроме того, существуют реализации языков, которые компилируют исходный текст программы
в байт-код, который затем либо интерпретируется, либо выполняется JIT-компилятором (или
виртуальной машиной).
PHP - (Personal Home Page) скриптовый язык общего назначения, интенсивно применяемый для
разработки веб-приложений. В настоящее время поддерживается подавляющим большинством
хостинг-провайдеров и является одним из лидеров среди языков, применяющихся для создания
динамических веб-сайтов.
Исходя из этого, я решил остановить свой выбор на языке программирования Java, так как он
обладает JIT компиляцией.
Так как JIT-компиляция является, по сути, одной из форм динамической компиляции, она
позволяет применять такие технологии, как адаптивная оптимизация и динамическая
рекомпиляция. Благодаря этому JIT-компиляция может показывать лучшие результаты в плане
производительности, чем статическая компиляция. Интерпретация и JIT-компиляция особенно
хорошо подходят для динамических языков программирования, при этом среда исполнения
справляется с поздним связыванием типов и гарантирует безопасность исполнения.
JIT компиляция работает быстрее интерпретированных языков, но синтаксис и инструменты
Java является проще в освоение чем, полностью компилированный C или C++.
Выбор базы данных и СУБД
Следующим шагом моей работы стал выбор базы данных и СУБД.
База данных - это хранение информации в упорядоченном виде, по заранее известным
стандартам.
● иерархические;
● сетевые;
● реляционные;
Данный метод представления, легок в исполнении программами, вся файловая система как
правило, построена на иерархическом принципе.
Интернет ресурсы, языки программирования, языки разметки, часто используют иерархическую
структуру, ввиду ее простоты и надежности.
Третья нормальная форма - представляет собой, что каждый столбец таблицы, зависит только
от столбца, который является ключом.
СУБД
Существует две модели СУБД - реляционная и бессистемная. Без Схемные СУБД основанные
на принципах не структурированного подхода, что позволяет программисту, не заботиться о
правильном проектировании реляционной базы данных, однако минусами такой системы
является низкая производительность и трудное расширяемость базы данных в будущем.
Одним из примеров не структурированных баз данных является NoSQL.
● SQLite;
● MySQL;
● PostgreSQL.
Принцип работы таких систем заключается в слежении за строгой структурой данных, которая
представлена в виде комплекса таблиц. В свою очередь внутри таблицы есть ячейки и поля,
которыми также управляет MySQL.
Может решать любой спектр задач, основан на технологии JavaBeans, что лучше всего
реализуется в веб приложениях.
Hibernate — библиотека для языка программирования Java, основной задачей которой является
представление Java объектов в виде объектов реляционной базы данных. Является самой
популярной реализации JPA.
Данный подход позволяет сократить число низкоуровневых операции работы с базой данных,
что увеличивает скорость разработки и уменьшает число ошибок.
Thymeleaf — серверный механизм для создания Java шаблонах, для создания веб страниц.
Способен обрабатывать HTML, XML, JavaScript, CSS на стороне Java приложения.
Thymeleaf разработан с учетом стандартов Web, и технологии HTML5, что позволяет создавать
полностью соответствующие стандарту шаблоны.
Bootstrap - свободный набор инструментов для создания веб сайтов. Имеет готовые и
стилизованные HTML и CSS шаблоны для оформления страниц, кнопок, веб-форм, меню,
блоков навигации. Также имеет встроенные JavaScript расширения.
Используемый софт
Для сборки проекта была выбрана система сборки проектов Apache Maven.
Apache Maven — система для автоматизации сборки Java проектов. Имеет строгую структуру,
основанную на XML. Позволяет разработчикам легко подключать новые библиотеки и собирать
проект в jar или war пакет.
Git - Система управления версиями. Позволяет хранить все версии файлов на определенном
моменте их жизненного цикла. Позволяет легко отслеживать изменения файлов и при
необходимости, возвращаться к предыдущим версиям.
Имеет систему веток, что позволяет развивать проект независимо от других версии, что
востребовано в корпоративных решениях.
Глава III
Проект системы
Для необходимой структуры проект был разделен на три части:
● База данных - в которой хранятся пользователи, роли, посты, комментарии и т.д.
● Веб сервер - ядро проекта, отвечающее за обработку действий пользователей сайта,
редактирования контента, переход по ссылкам, отрисовку страниц, взаимодействие с
базой данных.
● Пользовательский интерфейс - все страницы сайта, компоненты страницы, стили,
скрипты и библиотеки JavaScript.
● REST API - инструментарий для доступа внешних программ.
В данном проекте архитектура REST была реализована, для предоставления API, для сторонних
программ. Что позволило бы расширять функционала основной системы.
Структура базы данных:
База данных состоит из следующих таблиц:
● User - таблица хранящая все данные о пользователях. Их данные для аутентификации,
персональные данные и ссылки на другие таблицы
● Post - таблица хранящая все посты всех пользователей сайта, дату и время публикации.
● Roles - таблица ролей пользователей, разграничивающая из полномочия.
● Post_comments - таблица хранящая комментарии для каждого поста
● Api_data - таблица для дополнительной информации.
Схема проекта
Структура пользовательского интерфейса
● Common - вспомогательный файлы
● Js - библиотеки и файлы скриптов Javascript.
● View - содержит все страницы и компоненты страницы
● adminPanel - содержит страницы и компоненты панели управления сайта
● Site - содержит страницы и компоненты основного сайта
Области применения
Данная система управления контентом построена, на модульном (компонентном) подходе, что
позволяет ее легко расширять для любых нужд.
Данная система управления контентом изначально нацелена, на использования для создания и
управления блогом.
Однако есть возможность создавать пользовательские компоненты, что позволит
переквалифицировать систему под интернет магазин, новостной портал, сайт визитку.
Также есть возможность взаимодействовать с системой посредством REST API, что позволяет
как добавлять в систему новый функционал, так и интегрировать ее в другое приложение.
Список ролей позволяет разграничивать полномочия пользователей, благодаря этому можно
построить иерархию пользователей и разграничить их возможности.
Преимущества и недостатки проекта
Преимущества
Недостатки
Реализация системы
Папка Controller :
AdminPanelController - класс отвечающий за управление контентом сайта со страницы
AdminPanel.Отвечает за навигацию по панели администратора, и все основные функции.Это
основная страница управления контентом сайта, доступная только администратору.
Его основные функции это роутинг по панели администратора и получения данных для каждой
из страниц панели.
@GetMapping("")
public String adminPage(Principal principal, Model model) {
if (!isAdmin(principal)) {
return "redirect: /403";
}
model.addAttribute("links",
menuItemManger.getMenuItemDtoList(Constants.MENU_TYPE.ADMIN));
model.addAttribute("title", "Latte Dashboard");
model.addAttribute("posts",postManager.getAll());
return "/view/adminPanel/main";
}
@GetMapping("/pageList")
public String getPages(Model model, Principal principal) {
if (!isAdmin(principal)) {
return "redirect: /403";
}
File componentsDir = FileUtil.readFile(Constants.SITE_VIEW_PATH + "/elements");
File templatesDir = FileUtil.readFile(Constants.SITE_VIEW_PATH + "/templates");
List<String> components = new LinkedList<>();
List<String> templates = new LinkedList<>();
if (componentsDir.isDirectory()) {
Arrays.stream(componentsDir.listFiles())
.forEach(f -> components.add(f.getName()));
}
if (templatesDir.isDirectory()) {
Arrays.stream(templatesDir.listFiles())
.forEach(f -> templates.add(f.getName()));
}
model.addAttribute("components", components);
model.addAttribute("templates", templates);
return "/view/adminPanel/templates/pageList";
}
Папка Model:
Хранит в себе все модели POJO, классы, для работы приложения.
Папка Repository :
Хранит в себе классы, которые предоставляют методы для работы с базой данных.Такие
методы, как : получения объектов, по id, имени, удаление, обновление и создание нового
объекта.
● CategoryCrudRepository - клас, для извлечения объектов модели Category.
● PostCommentsRepository - класс для извлечения комментариев. Из нестандартных
методов, имеет поиск всех комментариев по id поста.
● PostCrudRepository - класс для извлечения постов. Из нестандартных методов, имеет
метод для получения постов по id пользователя и поиск постов по категории.
● RoleCrudRepository - класс для извлечения ролей.
● UserCrudRepository - класс для извлечения пользователей.
Папка Service:
Хранит в себе классы, отвечающие за логику выполнения операций с базой данных и являются
связующим звеном контроллеров и репозитория.
Каждый класс имеет интерфейс и одну реализацию, которая находится в каталоге impl, таковы
требования фреймворка Spring.
● CategoryManager - позволяет работать с категориями. Имеет методы для получения
списка категорий, получения категории по имени или id. Методы для добавления и
удаления категории по id.
public void addCategory(String name, Long roleId) {
try {
Role role = roleCrudRepository.findById(roleId).get();
Category category = new Category();
category.setName(name);
if (role != null) {
category.setRole(role);
repository.save(category);}
} catch (Exception e) {
System.err.println("Cant add category!");
e.printStackTrace();}}
public void deleteCategory(Long categoryId) {
if (repository.findById(categoryId).isPresent()) {
repository.delete(repository.findById(categoryId).get());
}else{
System.err.println("No category with such ID !");}
}
● MenuItemManager - считывает список ссылок и оборачивает их в DTO, для передачи в
Router.js
public List<MenuItemDto> getMenuItemDtoList(int menuType) {
switch (menuType) {
case Constants.MENU_TYPE.SITE:
return getSiteMenuLinkList();
case Constants.MENU_TYPE.ADMIN:
return getAdminMenuLinkList();
default:
System.err.println("MenuItemManger(2) -> No such option ");
return null;}}
Папка Utils:
● Constants - хранит все константы проекта.
● FileUtil - хранит в себе статические методы для удобной работы с файлами.
● StringUtils - хранит в себе методы для удобной работы со строками.
Папка Common:
Menu.json - файл хранящий в себе все ссылки сайта, и их названия.
AdminMenu.json - файл храня в себе все ссылки панели администратора , и их названия
Пользовательский интерфейс
Модуль js - содержит все скрипты используемые на сайте.
Папка Core:
● Router.js - скрипт перехватывающий все переходы по ссылкам и подгружающий из в
виде AJAX запросов.
function ajaxLoad(link) {
fetch(link)
.then(response => response.text())
.then(data => {
console.log(data);
var doc = parser.parseFromString(data, 'text/html');
console.log(doc);
document.getElementById('content').innerHTML = doc.body.innerHTML;
});
}
● App.js - содержит набор функций используемых на всех страницах сайта. Функции для
ajaxLogin, loadComments, addComment, ajaxSubmit.
Папка View:
Данный каталог имеет два подкаталога : aminPanel и site. Каждый из них имеет одинаковую
структуру, но хранят в себе данные для панели администратора и для основного сайта.
Пример main.html :
Для того чтобы компоненты не были статичными html частями страниц, каждый компонент
имеет набор инструментов для работы с данными.
В контекст каждого компонента добавлены все существующие менеджеры. Это позволяет
пользователям обращаться к публичным методам данных менеджеров, для извлечения и
фильтрации требуемых им данных.
После того как компонент был создан, он должен быть загружен на сайт, на странице Page
editor.
После этого компонент будет доступен в конструкторе страниц.
Заключение
В результате выполнения данной дипломной работы, я изучил техническое устройство и
архитектуру систем управления контентом, что позволило мне создать свою систему
управления контентом.
Мною были изучены технологии обработки страниц, динамической от рисовки страниц, основы
роутинга по страницам и ORM модель базы данных.
Я попытался избежать в ней недостатков, которые допустили авторы других операционных
система, и создать свою, максимально расширяемую систему управления контентом.
Литература и ссылки
https://club.cnews.ru/blogs/entry/istoriya_razvitiya_cms_evolyutsiya_ili_revolyutsiya_
https://ru.wikipedia.org/wiki/
https://dic.academic.ru/dic.nsf/ruwiki/522058
https://blog.ingate.ru/seo-wikipedia/cms/
https://webshake.ru/post/bazy-dannyh
https://opensource.com/article/20/7/history-content-management-system
https://docs.oracle.com/en/java/
https://spring.io/projects/spring-boot
https://www.thymeleaf.org/
https://jquery.com/
https://hibernate.org/
Приложения
Примеры пользовательского интерфейса :
Форма логина
Форма регистрации
Основная страница сайта
Страница профиля
Страница редактирования проста:
Страница категорий:
Форма добавления категорий
Router.js
let mainDivId;
let ajaxLinks = [];
$(document).ready(()=>{
fetch("/utils/ajaxLinks").then(response => response.json()).then(data => {
data.forEach(link => ajaxLinks.push(link));
console.log(ajaxLinks);
});
setListener();
})
//Link listener
function setListener() {
$('a').on('click',function (e){
e.preventDefault();
const origin = e.target.closest("a");
let link = origin.getAttribute('href');
let flag = false;
ajaxLinks.forEach(ajaxLink => {
if (link.includes(ajaxLink)) {
ajaxLoad(link);
flag = true;
}
})
if (!flag) {
window.location.href = link;
}
});
function ajaxLoad(link) {
fetch(link)
.then(response => response.text())
.then(data => {
console.log(data);
var doc = parser.parseFromString(data, 'text/html');
document.getElementById('content').innerHTML = doc.body.innerHTML;
});
}
app.js
let devMode = true;
function ajaxLogin(data) {
$.ajax({
type: "POST",
url: "/login",
data: data,
success: function (data) {
// console.log(data);
},
error: function (err) {
console.log(err);
alert("Err");
}
});
}
function addComment(commForm) {
$.ajax({
type: "GET",
url: $(commForm).attr('action'),
data: $(commForm).serialize(),
success: function (data) {
console.log();
let updatePost = $(commForm).attr('action').split("/")[3];
loadComments(updatePost, false);
setListener();
},
error: function (err) {
console.log(err);
}
})
}
AdminPanelController
package com.latte.demolatte.controller;
import com.latte.demolatte.model.Role;
import com.latte.demolatte.model.User;
import com.latte.demolatte.service.MenuItemManger;
import com.latte.demolatte.service.PostManager;
import com.latte.demolatte.service.UserManager;
import com.latte.demolatte.utils.Constants;
import com.latte.demolatte.utils.FileUtil;
import com.latte.demolatte.utils.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import java.io.File;
import java.io.FileWriter;
import java.security.Principal;
import java.util.*;
@Controller
@RequestMapping("adminPanel")
public class AdminPanelController {
@GetMapping("")
public String adminPage(Principal principal, Model model) {
if (!isAdmin(principal)) {
return "redirect: /403";
}
model.addAttribute("links",
menuItemManger.getMenuItemDtoList(Constants.MENU_TYPE.ADMIN));
model.addAttribute("title", "Latte Dashboard");
model.addAttribute("posts",postManager.getAll());
return "/view/adminPanel/main";
}
@GetMapping("/pageList")
public String getPages(Model model, Principal principal) {
if (!isAdmin(principal)) {
return "redirect: /403";
}
File componentsDir = FileUtil.readFile(Constants.SITE_VIEW_PATH +
"/elements");
File templatesDir = FileUtil.readFile(Constants.SITE_VIEW_PATH +
"/templates");
List<String> components = new LinkedList<>();
List<String> templates = new LinkedList<>();
if (componentsDir.isDirectory()) {
Arrays.stream(componentsDir.listFiles())
.forEach(f -> components.add(f.getName()));
}
if (templatesDir.isDirectory()) {
Arrays.stream(templatesDir.listFiles())
.forEach(f -> templates.add(f.getName()));
}
model.addAttribute("components", components);
model.addAttribute("templates", templates);
return "/view/adminPanel/templates/pageList";
}
@GetMapping("/editComponent/{type}/{name}")
public String getComponent(Model model,
Principal principal,
@PathVariable String type,
@PathVariable String name) {
if (!isAdmin(principal)) {
return "redirect: /403";
}
try {
String fileContent = FileUtil.readFileByTypeAndName(type, name);
if (fileContent == null) {
throw new Exception("Can't read file");
}
model.addAttribute("code", type.equalsIgnoreCase("component"));
model.addAttribute("editPostContent", fileContent);
model.addAttribute("saveAction", "/adminPanel/editComponent/" + type +
"/" + name);
return "/view/adminPanel/templates/codeEditor";
} catch (Exception e) {
e.printStackTrace();
}
return "redirect: /feed";
}
@PostMapping("/editComponent/{type}/{name}")
public String saveComponent(@PathVariable String type,
Principal principal,
@PathVariable String name,
@RequestParam("content") String content) {
if (!isAdmin(principal)) {
return "redirect: /403";
}
try {
@GetMapping("/userList")
public String userList(Model model) {
model.addAttribute("columns", User.columnsNames());
model.addAttribute("userList", userManager.getAll());
return "/view/adminPanel/components/userList";
}
@PostMapping("/update/user/")
@ResponseStatus(value = HttpStatus.OK)
public void updateUser(Principal principal,
@RequestParam Map<String, String> editedUser) {
if (!isAdmin(principal)) {
return;
}
if (editedUser.get("action").equals("delete")) {
userManager.deleteUser(editedUser.get("username"));
return;
}
User user = userManager.getUserByUsername(editedUser.get("username"));
user.setUsername(editedUser.get("username"));
user.setFirstName(editedUser.get("firstName"));
user.setLastName(editedUser.get("lastName"));
userManager.updateUser(user);
}
ApiController
package com.latte.demolatte.controller;
import com.latte.demolatte.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/api")
public class ApiController {
private CategoryManager categoryManager;
private MenuItemManger menuItemManger;
private PostManager postManager;
private RoleManager roleManager;
private UserManager userManager;
@Autowired
public ApiController(CategoryManager categoryManager,
MenuItemManger menuItemManger,
PostManager postManager,
RoleManager roleManager,
UserManager userManager) {
this.categoryManager = categoryManager;
this.menuItemManger = menuItemManger;
this.postManager = postManager;
this.roleManager = roleManager;
this.userManager = userManager;
}
@RequestMapping("{pageName}")
public String linkResolver(Model model,
@PathVariable("pageName") String pageName){
System.out.println("Page name = "+pageName);
userManager.getAll().forEach(System.out::println);
model.addAttribute("userManager",userManager);
model.addAttribute("postManager",postManager);
model.addAttribute("roleManager",roleManager);
model.addAttribute("menuItemManager",menuItemManger);
model.addAttribute("categoryManager",categoryManager);
return "/view/site/components/"+pageName;
}
}
CategoryController
package com.latte.demolatte.controller;
import com.latte.demolatte.model.Post;
import com.latte.demolatte.service.CategoryManager;
import com.latte.demolatte.service.PostManager;
import com.latte.demolatte.service.RoleManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RequestMapping
@Controller
public class CategoryController {
private CategoryManager categoryManager;
private PostManager postManager;
private RoleManager roleManager;
@Autowired
public void setCategoryManager(CategoryManager categoryManager) {
this.categoryManager = categoryManager;
}
@Autowired
public void setPostManager(PostManager postManager) {
this.postManager = postManager;
}
@Autowired
public void setRoleManager(RoleManager roleManager) {
this.roleManager = roleManager;
}
@PostMapping("/adminPanel/category/add")
@ResponseStatus(value = HttpStatus.OK)
public void addCategory(@RequestParam("name") String name,
@RequestParam("role_id") Long roleId) {
categoryManager.addCategory(name, roleId);
}
@GetMapping("/adminPanel/category/{id}")
public void deleteCategory(@PathVariable(name = "id") Long categoryId){
List<Post> posts = postManager.getPostsByCategory(categoryId);
postManager.deletePosts(posts);
categoryManager.deleteCategory(categoryId);
}
@GetMapping("/adminPanel/categories")
public String categoryList(Model model){
model.addAttribute("categoryList",categoryManager.getCategoryList());
model.addAttribute("roleList",roleManager.getAllRoles());
return "/view/adminPanel/components/categoryList";
}
}
PageConstructController
package com.latte.demolatte.controller;
import com.latte.demolatte.service.ComponentService;
import com.latte.demolatte.service.PageCreator;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("/adminPanel/pageConstructor")
public class PageConstructorController {
@GetMapping("")
public String page(Model model){
ComponentService componentService = new ComponentService();
model.addAttribute("components",componentService.getComponents());
return "/view/adminPanel/templates/pageConstructor";
}
@PostMapping("/save")
public String savePage(@RequestParam Map<String,String> params) {
JSONObject jsonObject = new JSONObject((String) params.keySet().toArray()
[0]);
String title = jsonObject.getString("title");
Map<String, List<String>> data =new HashMap<>();
data.put("page_body",jsonArrayToList(jsonObject.getJSONArray("page_body")));
data.put("side_bar",jsonArrayToList(jsonObject.getJSONArray("side_bar")));
data.put("page_footer",jsonArrayToList(jsonObject.getJSONArray("page_footer")));
data.put("page_header",jsonArrayToList(jsonObject.getJSONArray("page_header")));
PageCreator pageCreator = new PageCreator(title,data);
pageCreator.createPage();
return "/view/adminPanel/main";
}
PostCommentsController
package com.latte.demolatte.controller;
import com.latte.demolatte.model.PostComment;
import com.latte.demolatte.model.User;
import com.latte.demolatte.service.PostCommentsManager;
import com.latte.demolatte.service.PostManager;
import com.latte.demolatte.service.UserManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import java.security.Principal;
import java.util.Date;
@Controller
@RequestMapping("/comments")
public class PostCommentsController {
@Autowired
public void setPostManager(PostCommentsManager postCommentsManager) {
this.postCommentsManager = postCommentsManager;
}
@Autowired
public void setUserManager(UserManager userManager) {
this.userManager = userManager;
}
@Autowired
public void setPostManager(PostManager postManager) {
this.postManager = postManager;
}
@GetMapping("{id}")
public String postComments(@PathVariable Long id, Model model) {
model.addAttribute("comments", postCommentsManager.getPostComments(id));
model.addAttribute("postId",id);
return "/view/site/elements/comments";
}
@GetMapping("/add/{id}")
@ResponseStatus(value = HttpStatus.OK)
public void addComment(Principal principal,
@PathVariable Long id,
@RequestParam String text){
User user = userManager.getUserByUsername(principal.getName());
PostComment postComment = new PostComment();
postComment.setCommentPost(postManager.getPostById(id));
postComment.setText(text);
postComment.setCreateUser(user);
postComment.setUpdateUser(user);
postComment.setDate(new Date());
postCommentsManager.addComment(postComment);
}
}
PostController
package com.latte.demolatte.controller;
import com.latte.demolatte.model.Category;
import com.latte.demolatte.model.Post;
import com.latte.demolatte.model.User;
import com.latte.demolatte.service.CategoryManager;
import com.latte.demolatte.service.MenuItemManger;
import com.latte.demolatte.service.PostManager;
import com.latte.demolatte.service.UserManager;
import com.latte.demolatte.utils.Constants;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import java.security.Principal;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@Controller
@RequestMapping("/feed")
public class PostController {
@GetMapping()
public String lastPosts(Model model,
@RequestParam(value = "category", required = false)
Long categoryId) {
List<Post> postList = null;
if (categoryId != null) {
postList = postManager.getPostsByCategory(categoryId);
}else{
postList = postManager.getNewPosts();
}
if (postList.size() > 1) {
model.addAttribute("lastPost", postList.get(0));
}
model.addAttribute("links",
menuItemManger.getMenuItemDtoList(Constants.MENU_TYPE.SITE));
model.addAttribute(Constants.CONTEXT_VARIABLES.SITE_TITLE, "Test title");
model.addAttribute("categories",categoryManager.getCategoryList());
model.addAttribute("posts", postList);
return "/view/site/main";
}
@GetMapping("add")
public String addPost(Model model) {
model.addAttribute("saveAction", "/feed/save");
model.addAttribute("categoryList", categoryManager.getCategoryList());
return "/view/site/templates/editorPage";
}
@GetMapping("edit/{id}")
public String editPost(Model model, @PathVariable Long id) {
Post post = postManager.getPostById(id);
model.addAttribute("saveAction", "/feed/save/" + id);
model.addAttribute("editPostContent", (post != null ? post.getContent() :
""));
model.addAttribute("postTitle", post != null ? post.getTitle() : "");
model.addAttribute("categoryList", categoryManager.getCategoryList());
return "/view/site/templates/editorPage";
}
@GetMapping("delete/{id}")
public String deletePost(@PathVariable Long id) {
postManager.deletePostById(id);
return "redirect:/feed";
}
}
RegistrationController
package com.latte.demolatte.controller;
import com.latte.demolatte.model.User;
import com.latte.demolatte.service.UserManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class RegistrationController {
@GetMapping("/registration")
public String registration(Model model) {
model.addAttribute("userForm", new User());
return "/view/site/templates/registration";
}
@PostMapping("/registration")
public String addUser(@ModelAttribute("userForm") User userForm, BindingResult
bindingResult, Model model) {
if (bindingResult.hasErrors()) {
return "/view/site/templates/registration";
}
if (!userManager.saveUser(userForm)){
model.addAttribute("usernameError", "Пользователь с таким именем уже
существует");
return "/view/site/templates/registration";
}
return "redirect:/feed";
}
@GetMapping("/login")
public String loginPage(){
return "/view/login";
}
}
UserProfileController
package com.latte.demolatte.controller;
import com.latte.demolatte.model.User;
import com.latte.demolatte.service.PostManager;
import com.latte.demolatte.service.UserManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import java.security.Principal;
import java.util.Map;
@Controller
@RequestMapping("/profile")
public class UserProfileController {
private UserManager userManager;
private PostManager postManager;
@Autowired
public void setUserManager(UserManager userManager) {
this.userManager = userManager;
}
@Autowired
public void setPostManager(PostManager postManager) {
this.postManager = postManager;
}
@GetMapping
public String userProfile(Principal principal, Model model) {
User user = userManager.getUserByUsername(principal.getName());
model.addAttribute("user",user);
model.addAttribute("currUser",true);
model.addAttribute("userPosts",postManager.getUserPosts(user.getId()));
return "/view/site/elements/userCard";
}
@GetMapping("/{id}")
public String anotherUserInfo(@PathVariable Long id,
Model model){
User user = userManager.getUserById(id);
model.addAttribute("user",user);
model.addAttribute("currUser",false);
model.addAttribute("userPosts",postManager.getUserPosts(user.getId()));
return "/view/site/elements/userCard";
}
@PostMapping("/save")
public String saveUser(Principal principal,
@RequestParam Map<String,String> editedUser){
User user = userManager.getUserByUsername(principal.getName());
user.setInfo(editedUser.get("info"));
user.setLastName(editedUser.get("lastName"));
user.setFirstName(editedUser.get("firstName"));
userManager.updateUserInfo(user);
return "redirect:/feed";
}
}
CategoryManagerImpl
package com.latte.demolatte.service.impl;
import com.latte.demolatte.model.Category;
import com.latte.demolatte.model.Role;
import com.latte.demolatte.repository.CategoryCrudRepository;
import com.latte.demolatte.repository.RoleCrudRepository;
import com.latte.demolatte.service.CategoryManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class CategoryManagerImpl implements CategoryManager {
@Autowired
public void setRepository(CategoryCrudRepository repository) {
this.repository = repository;
}
@Autowired
public void setRoleCrudRepository(RoleCrudRepository roleCrudRepository) {
this.roleCrudRepository = roleCrudRepository;
}
@Override
public List<Category> getCategoryList() {
return repository.findAll();
}
@Override
public Category getCategoryByName(String name) {
return repository.findByName(name);
}
@Override
public Category getCategoryById(Long id) {
return repository.findById(id).get();
}
@Override
public void addCategory(String name, Long roleId) {
try {
Role role = roleCrudRepository.findById(roleId).get();
Category category = new Category();
category.setName(name);
if (role != null) {
category.setRole(role);
repository.save(category);
}
} catch (Exception e) {
System.err.println("Cant add category!");
e.printStackTrace();
}
}
@Override
public void deleteCategory(Long categoryId) {
if (repository.findById(categoryId).isPresent()) {
repository.delete(repository.findById(categoryId).get());
}else{
System.err.println("No category with such ID !");
}
}
}
MenuItemManagerImpl
package com.latte.demolatte.service.impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.latte.demolatte.model.dto.MenuItemDto;
import com.latte.demolatte.service.MenuItemManger;
import com.latte.demolatte.utils.Constants;
import com.latte.demolatte.utils.FileUtil;
import org.springframework.stereotype.Component;
import java.io.FileNotFoundException;
import java.util.LinkedList;
import java.util.List;
@Component
public class MenuItemManagerImpl implements MenuItemManger {
private List<MenuItemDto> adminMenuLinkList;
private List<MenuItemDto> siteMenuLinkList;
@Override
public List<MenuItemDto> getMenuItemDtoList(int menuType) {
switch (menuType) {
case Constants.MENU_TYPE.SITE:
return getSiteMenuLinkList();
case Constants.MENU_TYPE.ADMIN:
return getAdminMenuLinkList();
default:
System.err.println("MenuItemManger(2) -> No such option ");
return null;
}
}
@Override
public List<String> getMenuLinks(int menuType) {
List<String> res = new LinkedList<>();
getMenuItemDtoList(menuType).forEach(el -> res.add(el.getUrl()));
return res;
}
UserManagerImpl
package com.latte.demolatte.service.impl;
import com.latte.demolatte.model.Role;
import com.latte.demolatte.model.User;
import com.latte.demolatte.repository.RoleCrudRepository;
import com.latte.demolatte.repository.UserCrudRepository;
import com.latte.demolatte.service.UserManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class UserManagerImpl implements UserManager {
private UserCrudRepository userCrudRepository;
private RoleCrudRepository roleCrudRepository;
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Override
public User getUserById(Long id) {
Optional<User> user = userCrudRepository.findById(id);
if (user.isPresent()) {
return user.get();
}
return new User();
}
@Override
public User getUserByUsername(String username) {
return userCrudRepository.findByUsername(username);
}
@Override
public boolean saveUser(User user) {
User userFromDb = userCrudRepository.findByUsername(user.getUsername());
if (userFromDb != null) {
return false;
}
Role defaultRole = roleCrudRepository.findById(1L).get();
user.setRole(Collections.singleton(defaultRole));
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
user.setFirstName(user.getFirstName() == null ? "anonymous" :
user.getFirstName());
user.setLastName(user.getLastName() == null ? "anonymous" :
user.getLastName());
user.setInfo(user.getInfo() == null ? "" : user.getInfo());
userCrudRepository.save(user);
return true;
}
@Override
public UserDetails loadUserByUsername(String username) throws
UsernameNotFoundException {
User user = userCrudRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User '" + username + "' not
found");
}
return user;
}
@Override
public void createUser(UserDetails userDetails) {
@Override
public void updateUser(UserDetails userDetails) {
if (userDetails instanceof User) {
User user = (User) userDetails;
userCrudRepository.save(user);
}
}
@Override
public void deleteUser(String username) {
User user = userCrudRepository.findByUsername(username);
if(user != null){
userCrudRepository.delete(user);
}
}
@Override
public void changePassword(String s, String s1) {
@Override
public boolean userExists(String s) {
return false;
}
@Override
public List<User> getUsersByRole(String roleName) {
Role role = roleCrudRepository.findByName(roleName);
if (role != null) {
return userCrudRepository.getAllUsersByRoleId(role.getId());
}
return new LinkedList<>();
}
}