Дипломная работа: Социальная подкаст-платформа

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

Развертывание программного обеспечения может включать в себя:

- Компиляцию кода, если это требуются;

- Выгрузку кода, или пакетов, в которых он содержится;

- Выгрузку зависимостей проекта, в том случае, если он опирается на сторонние библиотеки;

- Выполнение настроечных операций на сервере, каких-либо сценариев, которые необходимо выполнять каждый раз для конкретного проекта.

На сегодняшний день развертывание программного обеспечения принято производить максимально автоматизированным способом - то есть писать некоторые сценарии или использовать готовые инструменты, которые автоматизируют:

- Перенос кода проекта на сервер;

- Адаптацию проекта, например, установку базы данных или настройку проксирования;

- Непосредственно запуск на сервере. [10]

Созданный в ходе данной работы программный продукт может быть развернут на любом современном сервере, который поддерживает Java 8.

Перечислим общие действия для ручного развертывания разработанного приложения на сервере:

- Через файлы конфигураций проекта и сервера настраивается работа с базой данных. При этом предполагается, что необходимая база данных уже находится на сервере;

- С помощью инструмента для сборки, а именно Maven, проект собирается в JAR-пакет. Для этого используется консольная команда «mvn clean install»;

- Полученный в результате сборки пакет с приложением передается на удаленный сервер и запускается стандартной консольной командой «java -jar discasst.jar».

В итоге мы получаем полностью работоспособное приложение, доступ к которому можно получить через сеть интернет.

Заключение

Целью выпускной квалификационной работы стала разработка социальной подкаст-платформы. Для достижения цели был проведен аналитический обзор, в ходе которого были поставлены задачи, которые будет решать данный продукт, проведен анализ существующих аналогов разрабатываемой системы, определены типы пользователей и бизнес-правила. В ходе проектирования была создана use-case диаграмма, выбраны средства разработки, спроектирована схема базы данных, а также произведено проектирование пользовательского интерфейса.

Разработка платформы состояла из двух частей. Первой из них была разработка серверной части, в которой содержится бизнес-логика приложения и работа с базой данных. Вторым этапом стала разработка клиентской части, представляющей из себя веб-страницу.

Тестирование программного продукта состояло из нескольких этапов: модульного и нагрузочного тестирования. Также было оценено удобство использования пользовательского интерфейса приложения.

В результате проделанной работы программный продукт выполняет все возложенные на него задачи. Платформа сочетает в себе как функции, необходимые для удобного поиска и прослушивания подкастов, такие как поиск по жанрам, подписки и рейтинги, так и социальные функции, выраженные полнофункциональным комментированием выпусков и отдельными микроблогами подкастов.

Список использованных источников

1. iTunes Store: [Электронный ресурс]. URL: https://ru.wikipedia.org/wiki/ITunes_Store.

2. Spring Boot: [Электронный ресурс]. URL: http://spring-projects.ru/projects/spring-boot.

3. Spring Security: [Электронный ресурс]. URL: https://ru.wikipedia.org/wiki/Spring_Security.

4. Шпаргалки Java программиста 10: Lombok: [Электронный ресурс]. URL: https://projectlombok.org.

5. React, или как перестать беспокоиться и начать жить: [Электронный ресурс]. URL: https://getinstance.info/articles/react/react-basics/.

6. Bootstrap (фреймворк): [Электронный ресурс]. URL: https://ru.wikipedia.org/wiki/Bootstrap_(фреймворк).

7. Интерфейс пользователя: [Электронный ресурс]. URL: https://ru.bmstu.wiki/Интерфейс_пользователя.

8. JSON: [Электронный ресурс]. URL: https://ru.wikipedia.org/wiki/JSON.

9. Модульное тестирование: [Электронный ресурс]. URL: https://qalight.com.ua/baza-znaniy/modulnoe-testirovanie/.

10. Деплой -- что это в программировании (deploy): [Электронный ресурс]. URL: http://fkn.ktu10.com/?q=node/9501.

Приложение

Исходный код проекта

Исходный код серверной части проекта:

Файл: Discasst\src\main\resources\config\application.properties

server.port=3005

spring.data.rest.base-path=/service

logging.level.org.springframework.security=ERROR

Файл: Discasst\src\main\java\discasst\Application.java

package discasst;

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);

}

}

Файл: Discasst\src\main\java\discasst\config\SecurityConfig.java

package discasst.config;

import discasst.service.UserService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;

import org.springframework.security.config.annotation.web.builders.HttpSecurity;

import org.springframework.security.config.annotation.web.builders.WebSecurity;

import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import org.springframework.security.crypto.password.PasswordEncoder;

import org.springframework.security.web.csrf.CookieCsrfTokenRepository;

import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import static org.springframework.http.HttpMethod.POST;

@Configuration

@EnableWebSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired

private UserService userService;

@Bean

public PasswordEncoder passwordEncoder(){

return new BCryptPasswordEncoder();

}

@Autowired

public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

auth.userDetailsService(userService).passwordEncoder(passwordEncoder());

}

@Override

public void configure(WebSecurity webSecurity) throws Exception {

webSecurity.ignoring().antMatchers(POST, "/getCoauthorsByIdList", "/getPodcastsInPage");

}

@Override

protected void configure(HttpSecurity http) throws Exception {

http

.authorizeRequests()

.antMatchers("/podcast/**",

"/getCoauthors",

"/getPodcastById",

"/getEpisodesByPodcastIdInPage",

"/getEpisodesInFeedByUserIdInPage",

"/getPodcastsByUserIdInCoauthors",

"/user/**",

"/getAllGenres",

"/",

"/css/**",

"/generated/**",

"/images/**",

"/favicon.ico",

"/error",

"/register",

"/addUser",

"/getAllPodcasts",

"/getAllEpisodesByPodcastId",

"/getEpisodesCountToday",

"/getEpisodesCountThisMounth",

"/getPodcastsCountThisMounth",

"/getPodcastsCountToday",

"/getPodcastsByUserId/**",

"/getUsersCountThisMounth",

"/getUsersCountToday",

"/statistics",

"/getUserInfo",

"/getAllTwitsByPodcastId"

).permitAll()

.anyRequest().authenticated()

.and()

.formLogin()

.loginPage("/signin")

.usernameParameter("username")

.passwordParameter("password")

.loginProcessingUrl("/perform_login")

.defaultSuccessUrl("/", true)

.failureUrl("/signin?error")

.permitAll()

.and()

.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).permitAll()

.and().csrf()

.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());

}

}

Файл: Discasst\src\main\java\discasst\da\CoauthorsRepository.java

package discasst.da;

import discasst.entity.CoauthorsEntity;

import org.springframework.data.jpa.repository.Query;

import org.springframework.data.repository.CrudRepository;

import org.springframework.data.repository.query.Param;

import java.util.List;

public interface CoauthorsRepository extends CrudRepository<CoauthorsEntity, Long> {

List<CoauthorsEntity> findAllByPodcastId(long id);

@Query("SELECT a.podcastId FROM CoauthorsEntity a WHERE a.userId like:userId")

long[] findAllByUserId(@Param("userId") long userId);

void deleteAllByPodcastId(long id);

}

Файл: Discasst\src\main\java\discasst\da\EpisodeRepository.java

package discasst.da;

import discasst.entity.Episode;

import org.springframework.data.domain.Page;

import org.springframework.data.domain.Pageable;

import org.springframework.data.jpa.repository.Query;

import org.springframework.data.repository.CrudRepository;

import org.springframework.data.repository.query.Param;

import java.util.List;

public interface EpisodeRepository extends CrudRepository<Episode, Long> {

Page<Episode> findAllByPodcastIdOrderByIdDesc(long id, Pageable pageable);

Page<Episode> findAllByPodcastIdInOrderByIdDesc(long[] podcastIds, Pageable pageable);

List<Episode> findAllByDate(String date);

void deleteAllByPodcastId(long id);

@Query("select a from Episode a where a.date like:monthAndYear")

List<Episode> findAllInThisMonth(

@Param("monthAndYear") String monthAndYear);

}

Файл: Discasst\src\main\java\discasst\da\ExposeEntityIdRest.java

package discasst.da;

import discasst.entity.*;

import org.springframework.data.rest.core.config.RepositoryRestConfiguration;

import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;

import org.springframework.stereotype.Component;

@Component

public class ExposeEntityIdRest extends RepositoryRestConfigurerAdapter {

/**

* Сохраняет айдишники в объектах

*/

@Override

public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {

config.exposeIdsFor(User.class);

config.exposeIdsFor(Podcast.class);

config.exposeIdsFor(Genre.class);

config.exposeIdsFor(Episode.class);

config.exposeIdsFor(CoauthorsEntity.class);

config.exposeIdsFor(RatingEntity.class);

config.exposeIdsFor(Tweet.class);

}

}

Файл: Discasst\src\main\java\discasst\da\GenreRepository.java

package discasst.da;

import discasst.entity.Genre;

import org.springframework.data.repository.CrudRepository;

import java.util.List;

public interface GenreRepository extends CrudRepository<Genre, Long> {

List<Genre> findAll();

}

Файл: Discasst\src\main\java\discasst\da\PodcastRepository.java

package discasst.da;

import discasst.entity.Podcast;

import org.springframework.data.domain.Page;

import org.springframework.data.domain.Pageable;

import org.springframework.data.jpa.repository.Query;

import org.springframework.data.repository.PagingAndSortingRepository;

import org.springframework.data.repository.query.Param;

import java.util.List;

public interface PodcastRepository extends PagingAndSortingRepository<Podcast, Long> {

Podcast findById(long id);

List<Podcast> findAll();

Page<Podcast> findByNameContainsIgnoreCaseAndGenreIdNotInOrderByRatingDesc(String name, long[] genres, Pageable pageable);

Page<Podcast> findByNameContainsIgnoreCaseAndGenreIdNotInOrderByIdDesc(String name, long[] genres, Pageable pageable);

List<Podcast> findAllByAuthorId(long id);

List<Podcast> findAllByIdIn(long[] ids);

List<Podcast> findAllByCreationDate(String date);

@Query("select a from Podcast a where a.creationDate like:monthAndYear")

List<Podcast> findAllInThisMonth(@Param("monthAndYear") String monthAndYear);

}

Файл: Discasst\src\main\java\discasst\da\RatingRepository.java

package discasst.da;

import discasst.entity.RatingEntity;

import org.springframework.data.repository.CrudRepository;

public interface RatingRepository extends CrudRepository<RatingEntity, Long> {

RatingEntity findByPodcastIdAndUserId(long podcastId, long userId);

void deleteAllByPodcastId(long id);

}

Файл: Discasst\src\main\java\discasst\da\SubscribeRepository.java

package discasst.da;

import discasst.entity.SubscribeEntity;

import org.springframework.data.jpa.repository.Query;

import org.springframework.data.repository.CrudRepository;

import org.springframework.data.repository.query.Param;

public interface SubscribeRepository extends CrudRepository<SubscribeEntity, Long> {

SubscribeEntity findByPodcastIdAndUserId(long podcastId, long userId);

void deleteAllByPodcastId(long id);

@Query("SELECT a.podcastId FROM SubscribeEntity a WHERE a.userId like:userId AND a.isSubscribed LIKE true")

long[] findAllByUserId(@Param("userId") long userId);

}

Файл: Discasst\src\main\java\discasst\da\TweetRepository.java

package discasst.da;

import discasst.entity.Tweet;

import org.springframework.data.domain.Page;

import org.springframework.data.domain.Pageable;

import org.springframework.data.repository.PagingAndSortingRepository;

public interface TweetRepository extends PagingAndSortingRepository<Tweet, Long> {

Page<Tweet> findAllByPodcastIdOrderByIdDesc(long id, Pageable pageable);

Page<Tweet> findAllByPodcastIdInOrderByIdDesc(long[] podcastIds, Pageable pageable);

void deleteAllByPodcastId(long id);

}

Файл: Discasst\src\main\java\discasst\da\UserRepository.java

package discasst.da;

import discasst.entity.User;

import org.springframework.data.jpa.repository.Query;

import org.springframework.data.repository.CrudRepository;

import org.springframework.data.repository.query.Param;

import java.util.List;

public interface UserRepository extends CrudRepository<User, Long> {

User findByUsername(String username);

List<User> findAllByIdIn(long[] list);

List<User> findAllByCreationDate(String date);

@Query("select a from User a where a.creationDate like:monthAndYear")

List<User> findAllInThisMonth(@Param("monthAndYear") String monthAndYear);

}

Файл: Discasst\src\main\java\discasst\entity\CoauthorsEntity.java

package discasst.entity;

import lombok.Data;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.Id;

@Entity

@Data

public class CoauthorsEntity {

@Id

@GeneratedValue

private long id;

private long podcastId;

private long userId;

public CoauthorsEntity(long podcastId, long userId) {

this.podcastId = podcastId;

this.userId = userId;

}

}

Файл: Discasst\src\main\java\discasst\entity\Episode.java

package discasst.entity;

import lombok.Data;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.Id;

import java.text.SimpleDateFormat;

import java.util.Date;

@Entity

@Data

public class Episode {

@Id

@GeneratedValue

private long id;

private long podcastId;

private String name;

@Column(columnDefinition = "TEXT")

private String description;

private String podsterLink;

private String date;

public long getPodcastId() {

return podcastId;

}

public Episode(long podcastId, String name,

String description, String podsterLink, Date date) {

this.podcastId = podcastId;

this.name = name;

this.description = description;

this.podsterLink = podsterLink;

this.date = new SimpleDateFormat("dd.MM.yy").format(date);

}

public void setDate(Date date) {

this.date = new SimpleDateFormat("dd.MM.yy").format(date);

}

}

Файл: Discasst\src\main\java\discasst\entity\Genre.java

package discasst.entity;

import lombok.Data;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.Id;

@Entity

@Data

public class Genre {

@Id

@GeneratedValue

private long id;

@Column(unique = true)

private String name;

public Genre(String name) {

this.name = name;

}

}

Файл: Discasst\src\main\java\discasst\entity\Podcast.java

package discasst.entity;

import lombok.Data;

import javax.persistence.*;

import java.text.SimpleDateFormat;

import java.util.Date;

@Entity

@Data

@Table(name = "podcast")

public class Podcast {

@Id

@GeneratedValue

private long id;

@Column(unique = true)

private String name;

private long authorId;

@Column(columnDefinition="TEXT")

private String description;

private String itunesLink = "";

private String vkLink = "";

private String twitterLink = "";

private String facebookLink = "";

private Integer episodeCount = 0;

private Integer subscribersCount = 0;

private long genreId;

private Integer rating = 0;

private String creationDate;

public Podcast(String name, String description, Integer rating, Integer genreId, int episodeCount) {

this.name = name;

this.description = description;

this.rating = rating;

this.genreId = genreId;

this.episodeCount = episodeCount;

}

public Podcast(String name, String description, String itunesLink, String vkLink, String twitterLink,

String facebookLink, Integer episodeCount, long genreId, Integer rating, Integer subscribersCount, long authorId) {

this.name = name;

this.description = description;

this.itunesLink = itunesLink;

this.vkLink = vkLink;

this.twitterLink = twitterLink;

this.facebookLink = facebookLink;

this.episodeCount = episodeCount;

this.genreId = genreId;

this.rating = rating;

this.subscribersCount = subscribersCount;

this.authorId = authorId;

}

public Integer getEpisodeCount() {

return episodeCount;

}

public void setEpisodeCount(Integer episodeCount) {

this.episodeCount = episodeCount;

}

public void setCreationDate(Date date) {

this.creationDate = new SimpleDateFormat("dd.MM.yy").format(date);

}

public long getAuthorId() {

return authorId;

}

public void ratingInc() {

this.rating++;

}

public void ratingDec() {

this.rating--;

}

public void subscribersCountDec() {